rework/fixes for paste edits, cinermt suspend uses acpitool
[goodguy/cinelerra.git] / cinelerra-5.1 / cinelerra / plugin.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  */
21
22 #include "bcsignals.h"
23 #include "edl.h"
24 #include "edlsession.h"
25 #include "filexml.h"
26 #include "keyframe.h"
27 #include "keyframes.h"
28 #include "localsession.h"
29 #include "mwindow.h"
30 #include "messages.h"
31 #include "plugin.h"
32 #include "pluginpopup.h"
33 #include "pluginset.h"
34 #include "pluginserver.h"
35 #include "track.h"
36 #include "tracks.h"
37 #include "virtualnode.h"
38
39
40 Plugin::Plugin(EDL *edl, Track *track, const char *title)
41  : Edit(edl, track)
42 {
43         is_plugin = 1;
44         this->track = track;
45         this->plugin_set = 0;
46         strcpy(this->title, title);
47         plugin_type = PLUGIN_NONE;
48         in = 1;
49         out = 1;
50         show = 0;
51         on = 1;
52         keyframes = new KeyFrames(edl, track);
53         keyframes->create_objects();
54 }
55
56
57 Plugin::Plugin(EDL *edl, PluginSet *plugin_set, const char *title)
58  : Edit(edl, plugin_set)
59 {
60         is_plugin = 1;
61         this->track = plugin_set->track;
62         this->plugin_set = plugin_set;
63         strcpy(this->title, title);
64         plugin_type = PLUGIN_NONE;
65         in = 1;
66         out = 1;
67         show = 0;
68         on = 1;
69         keyframes = new KeyFrames(edl, track);
70         keyframes->create_objects();
71 }
72
73 Plugin::~Plugin()
74 {
75         while(keyframes->last) delete keyframes->last;
76         delete keyframes;
77 }
78
79 Edit& Plugin::operator=(Edit& edit)
80 {
81         copy_from(&edit);
82         return *this;
83 }
84
85 Plugin& Plugin::operator=(Plugin& edit)
86 {
87         copy_from(&edit);
88         return *this;
89 }
90
91 int Plugin::operator==(Plugin& that)
92 {
93         return identical(&that);
94 }
95
96 int Plugin::operator==(Edit& that)
97 {
98         return identical((Plugin*)&that);
99 }
100
101 int Plugin::silence()
102 {
103         return plugin_type == PLUGIN_NONE ? 1 : 0;
104 }
105
106 void Plugin::clear_keyframes(int64_t start, int64_t end)
107 {
108         keyframes->clear(start, end, 0);
109 }
110
111
112 void Plugin::copy_base(Edit *edit)
113 {
114         Plugin *plugin = (Plugin*)edit;
115
116         this->startsource = edit->startsource;
117         this->startproject = edit->startproject;
118         this->length = edit->length;
119
120
121         this->plugin_type = plugin->plugin_type;
122         this->in = plugin->in;
123         this->out = plugin->out;
124         this->show = plugin->show;
125         this->on = plugin->on;
126 // Should reconfigure this based on where the first track is now.
127         this->shared_location = plugin->shared_location;
128         strcpy(this->title, plugin->title);
129 }
130
131 void Plugin::copy_from(Edit *edit)
132 {
133         copy_base(edit);
134         copy_keyframes((Plugin*)edit);
135 }
136
137 void Plugin::copy_keyframes(Plugin *plugin)
138 {
139
140         keyframes->copy_from(plugin->keyframes);
141 }
142
143 void Plugin::copy_keyframes(int64_t start,
144         int64_t end,
145         FileXML *file,
146         int default_only,
147         int active_only)
148 {
149 // Only 1 default is copied from where the start position is
150         int64_t endproject = startproject + length;
151         if(!default_only ||
152                 (default_only &&
153                         start < endproject &&
154                         start >= startproject))
155                 keyframes->copy(start, end, file, default_only, active_only);
156 }
157
158 void Plugin::synchronize_params(Edit *edit)
159 {
160         Plugin *plugin = (Plugin*)edit;
161         this->in = plugin->in;
162         this->out = plugin->out;
163         this->show = plugin->show;
164         this->on = plugin->on;
165         strcpy(this->title, plugin->title);
166         copy_keyframes(plugin);
167 }
168
169 void Plugin::shift_keyframes(int64_t position)
170 {
171         for(KeyFrame *keyframe = (KeyFrame*)keyframes->first;
172                 keyframe;
173                 keyframe = (KeyFrame*)keyframe->next)
174         {
175                 keyframe->position += position;
176         }
177 }
178
179
180 void Plugin::equivalent_output(Edit *edit, int64_t *result)
181 {
182         Plugin *plugin = (Plugin*)edit;
183 // End of plugin changed
184         if(startproject + length != plugin->startproject + plugin->length)
185         {
186                 if(*result < 0 || startproject + length < *result)
187                         *result = startproject + length;
188         }
189
190 // Start of plugin changed
191         if( startproject != plugin->startproject || plugin_type != plugin->plugin_type ||
192             on != plugin->on || !(shared_location == plugin->shared_location) ||
193                 strcmp(title, plugin->title) ) {
194                 if( *result < 0 || startproject < *result )
195                         *result = startproject;
196         }
197
198 // Test keyframes
199         keyframes->equivalent_output(plugin->keyframes, startproject, result);
200 }
201
202
203
204 int Plugin::is_synthesis(int64_t position,
205                 int direction)
206 {
207         switch(plugin_type)
208         {
209                 case PLUGIN_STANDALONE:
210                 {
211                         if(!track)
212                         {
213                                 printf("Plugin::is_synthesis track not defined\n");
214                                 return 0;
215                         }
216
217
218                         PluginServer *plugin_server = MWindow::scan_plugindb(title,
219                                 track->data_type);
220 //printf("Plugin::is_synthesis %d %p %d\n", __LINE__, plugin_server, plugin_server->get_synthesis());
221 //plugin_server->dump();
222                         return plugin_server->get_synthesis();
223                         break;
224                 }
225
226 // Dereference real plugin and descend another level
227                 case PLUGIN_SHAREDPLUGIN:
228                 {
229                         int real_module_number = shared_location.module;
230                         int real_plugin_number = shared_location.plugin;
231                         Track *track = edl->tracks->number(real_module_number);
232 // Get shared plugin from master track
233                         Plugin *plugin = track->get_current_plugin(position,
234                                 real_plugin_number,
235                                 direction,
236                                 0,
237                                 0);
238
239                         if(plugin)
240                                 return plugin->is_synthesis(position, direction);
241                         break;
242                 }
243
244 // Dereference the real track and descend
245                 case PLUGIN_SHAREDMODULE:
246                 {
247                         int real_module_number = shared_location.module;
248                         Track *track = edl->tracks->number(real_module_number);
249                         return track->is_synthesis(position, direction);
250                         break;
251                 }
252         }
253         return 0;
254 }
255
256
257
258 int Plugin::identical(Plugin *that)
259 {
260 // Test type
261         if(plugin_type != that->plugin_type) return 0;
262
263 // Test title or location
264         switch(plugin_type)
265         {
266                 case PLUGIN_STANDALONE:
267                         if(strcmp(title, that->title)) return 0;
268                         break;
269                 case PLUGIN_SHAREDPLUGIN:
270                         if(shared_location.module != that->shared_location.module ||
271                                 shared_location.plugin != that->shared_location.plugin) return 0;
272                         break;
273                 case PLUGIN_SHAREDMODULE:
274                         if(shared_location.module != that->shared_location.module) return 0;
275                         break;
276         }
277
278 // Test remaining fields
279         return (this->on == that->on &&
280                 ((KeyFrame*)keyframes->default_auto)->identical(
281                         ((KeyFrame*)that->keyframes->default_auto)));
282 }
283
284 int Plugin::identical_location(Plugin *that)
285 {
286         if(!plugin_set || !plugin_set->track) return 0;
287         if(!that->plugin_set || !that->plugin_set->track) return 0;
288
289         if(plugin_set->track->number_of() == that->plugin_set->track->number_of() &&
290                 plugin_set->get_number() == that->plugin_set->get_number() &&
291                 startproject == that->startproject) return 1;
292
293         return 0;
294
295 }
296
297 int Plugin::keyframe_exists(KeyFrame *ptr)
298 {
299         for(KeyFrame *current = (KeyFrame*)keyframes->first;
300                 current;
301                 current = (KeyFrame*)NEXT)
302         {
303                 if(current == ptr) return 1;
304         }
305         return 0;
306 }
307
308
309 void Plugin::change_plugin(char *title,
310                 SharedLocation *shared_location,
311                 int plugin_type)
312 {
313         strcpy(this->title, title);
314         this->shared_location = *shared_location;
315         this->plugin_type = plugin_type;
316 }
317
318
319
320 KeyFrame* Plugin::get_prev_keyframe(int64_t position,
321         int direction)
322 {
323         return keyframes->get_prev_keyframe(position, direction);
324 }
325
326 KeyFrame* Plugin::get_next_keyframe(int64_t position,
327         int direction)
328 {
329         KeyFrame *current;
330
331 // This doesn't work for playback because edl->selectionstart doesn't
332 // change during playback at the same rate as PluginClient::source_position.
333         if(position < 0)
334         {
335 //printf("Plugin::get_next_keyframe position < 0\n");
336                 position = track->to_units(edl->local_session->get_selectionstart(1), 0);
337         }
338
339 // Get keyframe after current position
340         for(current = (KeyFrame*)keyframes->first;
341                 current;
342                 current = (KeyFrame*)NEXT)
343         {
344                 if(direction == PLAY_FORWARD && current->position > position) break;
345                 else
346                 if(direction == PLAY_REVERSE && current->position >= position) break;
347         }
348
349 // Nothing after current position
350         if(!current && keyframes->last)
351         {
352                 current =  (KeyFrame*)keyframes->last;
353         }
354         else
355 // No keyframes
356         if(!current)
357         {
358                 current = (KeyFrame*)keyframes->default_auto;
359         }
360
361         return current;
362 }
363
364 KeyFrame* Plugin::get_keyframe()
365 {
366         return keyframes->get_keyframe();
367 }
368
369 void Plugin::copy(int64_t start, int64_t end, FileXML *file)
370 {
371         int64_t endproject = startproject + length;
372
373         if((startproject >= start && startproject <= end) ||  // startproject in range
374                  (endproject <= end && endproject >= start) ||     // endproject in range
375                  (startproject <= start && endproject >= end))    // range in project
376         {
377 // edit is in range
378                 int64_t startproject_in_selection = startproject; // start of edit in selection in project
379                 int64_t startsource_in_selection = startsource; // start of source in selection in source
380                 //int64_t endsource_in_selection = startsource + length; // end of source in selection
381                 int64_t length_in_selection = length;             // length of edit in selection
382
383                 if(startproject < start)
384                 {         // start is after start of edit in project
385                         int64_t length_difference = start - startproject;
386
387                         startsource_in_selection += length_difference;
388                         startproject_in_selection += length_difference;
389                         length_in_selection -= length_difference;
390                 }
391
392 // end is before end of edit in project
393                 if(endproject > end)
394                 {
395                         length_in_selection = end - startproject_in_selection;
396                 }
397
398 // Plugins don't store silence
399                 file->tag.set_title("PLUGIN");
400 //              file->tag.set_property("STARTPROJECT", startproject_in_selection - start);
401                 file->tag.set_property("LENGTH", length_in_selection);
402                 file->tag.set_property("TYPE", plugin_type);
403                 file->tag.set_property("TITLE", title);
404                 file->append_tag();
405                 file->append_newline();
406
407
408                 if(plugin_type == PLUGIN_SHAREDPLUGIN ||
409                         plugin_type == PLUGIN_SHAREDMODULE)
410                 {
411                         shared_location.save(file);
412                 }
413
414
415
416                 if(in)
417                 {
418                         file->tag.set_title("IN");
419                         file->append_tag();
420                         file->tag.set_title("/IN");
421                         file->append_tag();
422                 }
423                 if(out)
424                 {
425                         file->tag.set_title("OUT");
426                         file->append_tag();
427                         file->tag.set_title("/OUT");
428                         file->append_tag();
429                 }
430                 if(show)
431                 {
432                         file->tag.set_title("SHOW");
433                         file->append_tag();
434                         file->tag.set_title("/SHOW");
435                         file->append_tag();
436                 }
437                 if(on)
438                 {
439                         file->tag.set_title("ON");
440                         file->append_tag();
441                         file->tag.set_title("/ON");
442                         file->append_tag();
443                 }
444                 file->append_newline();
445
446 // Keyframes
447                 keyframes->copy(start, end, file, 0, 0);
448
449                 file->tag.set_title("/PLUGIN");
450                 file->append_tag();
451                 file->append_newline();
452         }
453 }
454
455 void Plugin::load(FileXML *file)
456 {
457         int result = 0;
458         int first_keyframe = 1;
459         in = 0;
460         out = 0;
461 // Currently show is ignored when loading
462         show = 0;
463         on = 0;
464         while(keyframes->last) delete keyframes->last;
465
466         do{
467                 result = file->read_tag();
468
469 //printf("Plugin::load 1 %s\n", file->tag.get_title());
470                 if(!result)
471                 {
472                         if(file->tag.title_is("/PLUGIN"))
473                         {
474                                 result = 1;
475                         }
476                         else
477                         if(file->tag.title_is("SHARED_LOCATION"))
478                         {
479                                 shared_location.load(file);
480                         }
481                         else
482                         if(file->tag.title_is("IN"))
483                         {
484                                 in = 1;
485                         }
486                         else
487                         if(file->tag.title_is("OUT"))
488                         {
489                                 out = 1;
490                         }
491                         else
492                         if(file->tag.title_is("SHOW"))
493                         {
494                                 show = 1;
495                         }
496                         else
497                         if(file->tag.title_is("ON"))
498                         {
499                                 on = 1;
500                         }
501                         else
502                         if(file->tag.title_is("KEYFRAME"))
503                         {
504 // Default keyframe
505                                 if(first_keyframe)
506                                 {
507                                         keyframes->default_auto->load(file);
508                                         first_keyframe = 0;
509                                 }
510                                 else
511 // Override default keyframe
512                                 {
513                                         KeyFrame *keyframe = (KeyFrame*)keyframes->append(new KeyFrame(edl, keyframes));
514                                         keyframe->position = file->tag.get_property("POSITION", (int64_t)0);
515                                         keyframe->load(file);
516                                 }
517                         }
518                 }
519         }while(!result);
520 }
521
522 void Plugin::get_shared_location(SharedLocation *result)
523 {
524         if(plugin_type == PLUGIN_STANDALONE && plugin_set)
525         {
526                 result->module = edl->tracks->number_of(track);
527                 result->plugin = track->plugin_set.number_of(plugin_set);
528         }
529         else
530         {
531                 *result = this->shared_location;
532         }
533 }
534
535 Track* Plugin::get_shared_track()
536 {
537         return edl->tracks->get_item_number(shared_location.module);
538 }
539
540
541 void Plugin::calculate_title(char *string, int use_nudge)
542 {
543         switch( plugin_type ) {
544         case PLUGIN_STANDALONE:
545         case PLUGIN_NONE:
546                 strcpy(string, _(title));
547                 break;
548         case PLUGIN_SHAREDPLUGIN:
549         case PLUGIN_SHAREDMODULE:
550                 shared_location.calculate_title(string, edl,
551                         startproject, 0, plugin_type, use_nudge);
552                 break;
553         }
554 }
555
556 void Plugin::fix_plugin_title(char *title)
557 {
558         MWindow::fix_plugin_title(title);
559 }
560
561
562 void Plugin::paste(FileXML *file)
563 {
564         length = file->tag.get_property("LENGTH", (int64_t)0);
565 }
566
567 void Plugin::resample(double old_rate, double new_rate)
568 {
569 // Resample keyframes in here
570         keyframes->resample(old_rate, new_rate);
571 }
572
573 void Plugin::shift(int64_t difference)
574 {
575         Edit::shift(difference);
576
577         if(edl->session->autos_follow_edits)
578                 shift_keyframes(difference);
579 }
580
581 void Plugin::dump(FILE *fp)
582 {
583         fprintf(fp,"    PLUGIN: type=%d title=\"%s\" on=%d track=%d plugin=%d\n",
584                 plugin_type, title, on, shared_location.module, shared_location.plugin);
585         fprintf(fp,"    startproject %jd length %jd\n", startproject, length);
586
587         keyframes->dump(fp);
588 }
589
590