18 new shapewipe transitions from rafa, rework savefile/confirm for nested edl edits
[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         this->track = track;
44         this->plugin_set = 0;
45         strcpy(this->title, title);
46         plugin_type = PLUGIN_NONE;
47         in = 1;
48         out = 1;
49         show = 0;
50         on = 1;
51         gui_id = -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         this->track = plugin_set->track;
61         this->plugin_set = plugin_set;
62         strcpy(this->title, title);
63         plugin_type = PLUGIN_NONE;
64         in = 1;
65         out = 1;
66         show = 0;
67         on = 1;
68         gui_id = -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::init(const char *title,
113         int64_t unit_position, int64_t unit_length, int plugin_type,
114         SharedLocation *shared_location, KeyFrame *default_keyframe)
115 {
116         if( title ) strcpy(this->title, title);
117         if( shared_location ) this->shared_location = *shared_location;
118         this->plugin_type = plugin_type;
119         if( default_keyframe )
120                 *this->keyframes->default_auto = *default_keyframe;
121         this->keyframes->default_auto->position = unit_position;
122         this->startproject = unit_position;
123         this->length = unit_length;
124 }
125
126 void Plugin::copy_base(Edit *edit)
127 {
128         Plugin *plugin = (Plugin*)edit;
129
130         this->startsource = edit->startsource;
131         this->startproject = edit->startproject;
132         this->length = edit->length;
133         this->orig_id = edit->orig_id;
134
135         this->plugin_type = plugin->plugin_type;
136         this->in = plugin->in;
137         this->out = plugin->out;
138         this->show = plugin->show;
139         this->on = plugin->on;
140 // dont copy gui_id, it will be a duplicate ref
141 // Should reconfigure this based on where the first track is now.
142         this->shared_location = plugin->shared_location;
143         strcpy(this->title, plugin->title);
144 }
145
146 void Plugin::copy_from(Edit *edit)
147 {
148         copy_base(edit);
149         copy_keyframes((Plugin*)edit);
150 }
151
152 void Plugin::copy_keyframes(Plugin *plugin)
153 {
154
155         keyframes->copy_from(plugin->keyframes);
156 }
157
158 void Plugin::copy_keyframes(int64_t start,
159         int64_t end,
160         FileXML *file,
161         int default_only,
162         int active_only)
163 {
164 // Only 1 default is copied from where the start position is
165         int64_t endproject = startproject + length;
166         if(!default_only ||
167                 (default_only &&
168                         start < endproject &&
169                         start >= startproject))
170                 keyframes->copy(start, end, file, default_only, active_only);
171 }
172
173 void Plugin::synchronize_params(Edit *edit)
174 {
175         Plugin *plugin = (Plugin*)edit;
176         this->in = plugin->in;
177         this->out = plugin->out;
178         this->show = plugin->show;
179         this->gui_id = plugin->gui_id;
180         this->on = plugin->on;
181         strcpy(this->title, plugin->title);
182         copy_keyframes(plugin);
183 }
184
185 void Plugin::shift_keyframes(int64_t position)
186 {
187         for(KeyFrame *keyframe = (KeyFrame*)keyframes->first;
188                 keyframe;
189                 keyframe = (KeyFrame*)keyframe->next)
190         {
191                 keyframe->position += position;
192         }
193 }
194
195
196 void Plugin::equivalent_output(Edit *edit, int64_t *result)
197 {
198         Plugin *plugin = (Plugin*)edit;
199 // End of plugin changed
200         if(startproject + length != plugin->startproject + plugin->length)
201         {
202                 if(*result < 0 || startproject + length < *result)
203                         *result = startproject + length;
204         }
205
206 // Start of plugin changed
207         if( startproject != plugin->startproject || plugin_type != plugin->plugin_type ||
208             on != plugin->on || !(shared_location == plugin->shared_location) ||
209                 strcmp(title, plugin->title) ) {
210                 if( *result < 0 || startproject < *result )
211                         *result = startproject;
212         }
213
214 // Test keyframes
215         keyframes->equivalent_output(plugin->keyframes, startproject, result);
216 }
217
218 const char* Plugin::type_to_text(int type)
219 {
220         switch( type ) {
221         case PLUGIN_STANDALONE:    return _("standalone");
222         case PLUGIN_SHAREDPLUGIN:  return _("shared plugin");
223         case PLUGIN_SHAREDMODULE:  return _("shared module");
224         }
225         return _("none");
226 }
227
228 int Plugin::is_synthesis(int64_t position, int direction, int depth)
229 {
230         if( depth > 255 ) {
231                 printf("Plugin::is_synthesis %d: depth range limit, type=%s, title=%s\n",
232                         __LINE__, type_to_text(plugin_type), title);
233                 return 0;
234         }
235         switch( plugin_type ) {
236         case PLUGIN_STANDALONE: {
237                 if( !track ) {
238                         printf("Plugin::is_synthesis track not defined\n");
239                         return 0;
240                 }
241                 PluginServer *plugin_server = MWindow::scan_plugindb(title, track->data_type);
242                 return plugin_server->get_synthesis(); }
243
244 // Dereference real plugin and descend another level
245         case PLUGIN_SHAREDPLUGIN: {
246                 int real_module_number = shared_location.module;
247                 int real_plugin_number = shared_location.plugin;
248                 Track *track = edl->tracks->number(real_module_number);
249 // Get shared plugin from master track
250                 Plugin *plugin = track->get_current_plugin(position,
251                         real_plugin_number, direction, 0, 0);
252
253                 if(plugin)
254                         return plugin->is_synthesis(position, direction, depth+1);
255                 break; }
256
257 // Dereference the real track and descend
258         case PLUGIN_SHAREDMODULE: {
259                 int real_module_number = shared_location.module;
260                 Track *track = edl->tracks->number(real_module_number);
261                 return track->is_synthesis(position, direction, depth+1); }
262         }
263         return 0;
264 }
265
266
267
268 int Plugin::identical(Plugin *that)
269 {
270 // Test type
271         if(plugin_type != that->plugin_type) return 0;
272
273 // Test title or location
274         switch(plugin_type)
275         {
276                 case PLUGIN_STANDALONE:
277                         if(strcmp(title, that->title)) return 0;
278                         break;
279                 case PLUGIN_SHAREDPLUGIN:
280                         if(shared_location.module != that->shared_location.module ||
281                                 shared_location.plugin != that->shared_location.plugin) return 0;
282                         break;
283                 case PLUGIN_SHAREDMODULE:
284                         if(shared_location.module != that->shared_location.module) return 0;
285                         break;
286         }
287
288 // Test remaining fields
289         return (this->on == that->on &&
290                 ((KeyFrame*)keyframes->default_auto)->identical(
291                         ((KeyFrame*)that->keyframes->default_auto)));
292 }
293
294 int Plugin::keyframe_exists(KeyFrame *ptr)
295 {
296         for(KeyFrame *current = (KeyFrame*)keyframes->first;
297                 current;
298                 current = (KeyFrame*)NEXT)
299         {
300                 if(current == ptr) return 1;
301         }
302         return 0;
303 }
304
305
306 void Plugin::change_plugin(char *title,
307                 SharedLocation *shared_location,
308                 int plugin_type)
309 {
310         strcpy(this->title, title);
311         this->shared_location = *shared_location;
312         this->plugin_type = plugin_type;
313 }
314
315
316
317 KeyFrame* Plugin::get_prev_keyframe(int64_t position,
318         int direction)
319 {
320         return keyframes->get_prev_keyframe(position, direction);
321 }
322
323 KeyFrame* Plugin::get_next_keyframe(int64_t position,
324         int direction)
325 {
326         KeyFrame *current;
327
328 // This doesn't work for playback because edl->selectionstart doesn't
329 // change during playback at the same rate as PluginClient::source_position.
330         if(position < 0)
331         {
332 //printf("Plugin::get_next_keyframe position < 0\n");
333                 position = track->to_units(edl->local_session->get_selectionstart(1), 0);
334         }
335
336 // Get keyframe after current position
337         for(current = (KeyFrame*)keyframes->first;
338                 current;
339                 current = (KeyFrame*)NEXT)
340         {
341                 if(direction == PLAY_FORWARD && current->position > position) break;
342                 else
343                 if(direction == PLAY_REVERSE && current->position >= position) break;
344         }
345
346 // Nothing after current position
347         if(!current && keyframes->last)
348         {
349                 current =  (KeyFrame*)keyframes->last;
350         }
351         else
352 // No keyframes
353         if(!current)
354         {
355                 current = (KeyFrame*)keyframes->default_auto;
356         }
357
358         return current;
359 }
360
361 KeyFrame* Plugin::get_keyframe()
362 {
363         return keyframes->get_keyframe();
364 }
365
366 void Plugin::copy(int64_t start, int64_t end, FileXML *file)
367 {
368         int64_t endproject = startproject + length;
369
370         if((startproject >= start && startproject <= end) ||  // startproject in range
371                  (endproject <= end && endproject >= start) ||     // endproject in range
372                  (startproject <= start && endproject >= end))    // range in project
373         {
374 // edit is in range
375                 int64_t startproject_in_selection = startproject; // start of edit in selection in project
376                 int64_t startsource_in_selection = startsource; // start of source in selection in source
377                 //int64_t endsource_in_selection = startsource + length; // end of source in selection
378                 int64_t length_in_selection = length;             // length of edit in selection
379
380                 if(startproject < start)
381                 {         // start is after start of edit in project
382                         int64_t length_difference = start - startproject;
383
384                         startsource_in_selection += length_difference;
385                         startproject_in_selection += length_difference;
386                         length_in_selection -= length_difference;
387                 }
388
389 // end is before end of edit in project
390                 if(endproject > end)
391                 {
392                         length_in_selection = end - startproject_in_selection;
393                 }
394
395 // Plugins don't store silence
396                 file->tag.set_title("PLUGIN");
397 //              file->tag.set_property("STARTPROJECT", startproject_in_selection - start);
398                 file->tag.set_property("LENGTH", length_in_selection);
399                 file->tag.set_property("TYPE", plugin_type);
400                 file->tag.set_property("TITLE", title);
401                 file->append_tag();
402                 file->append_newline();
403
404
405                 if(plugin_type == PLUGIN_SHAREDPLUGIN ||
406                         plugin_type == PLUGIN_SHAREDMODULE)
407                 {
408                         shared_location.save(file);
409                 }
410
411
412
413                 if(in)
414                 {
415                         file->tag.set_title("IN");
416                         file->append_tag();
417                         file->tag.set_title("/IN");
418                         file->append_tag();
419                 }
420                 if(out)
421                 {
422                         file->tag.set_title("OUT");
423                         file->append_tag();
424                         file->tag.set_title("/OUT");
425                         file->append_tag();
426                 }
427                 if(show)
428                 {
429                         file->tag.set_title("SHOW");
430                         file->append_tag();
431                         file->tag.set_title("/SHOW");
432                         file->append_tag();
433                 }
434                 if(on)
435                 {
436                         file->tag.set_title("ON");
437                         file->append_tag();
438                         file->tag.set_title("/ON");
439                         file->append_tag();
440                 }
441                 file->append_newline();
442
443 // Keyframes
444                 keyframes->copy(start, end, file, 0, 0);
445
446                 file->tag.set_title("/PLUGIN");
447                 file->append_tag();
448                 file->append_newline();
449         }
450 }
451
452 void Plugin::load(FileXML *file)
453 {
454         int result = 0;
455         int first_keyframe = 1;
456         in = 0;
457         out = 0;
458 // Currently show is ignored when loading
459         show = 0;
460         on = 0;
461         while(keyframes->last) delete keyframes->last;
462
463         do{
464                 result = file->read_tag();
465
466 //printf("Plugin::load 1 %s\n", file->tag.get_title());
467                 if(!result)
468                 {
469                         if(file->tag.title_is("/PLUGIN"))
470                         {
471                                 result = 1;
472                         }
473                         else
474                         if(file->tag.title_is("SHARED_LOCATION"))
475                         {
476                                 shared_location.load(file);
477                         }
478                         else
479                         if(file->tag.title_is("IN"))
480                         {
481                                 in = 1;
482                         }
483                         else
484                         if(file->tag.title_is("OUT"))
485                         {
486                                 out = 1;
487                         }
488                         else
489                         if(file->tag.title_is("SHOW"))
490                         {
491                                 show = 1;
492                         }
493                         else
494                         if(file->tag.title_is("ON"))
495                         {
496                                 on = 1;
497                         }
498                         else
499                         if(file->tag.title_is("KEYFRAME"))
500                         {
501 // Default keyframe
502                                 if(first_keyframe)
503                                 {
504                                         keyframes->default_auto->load(file);
505                                         first_keyframe = 0;
506                                 }
507                                 else
508 // Override default keyframe
509                                 {
510                                         KeyFrame *keyframe = (KeyFrame*)keyframes->append(new KeyFrame(edl, keyframes));
511                                         keyframe->position = file->tag.get_property("POSITION", (int64_t)0);
512                                         keyframe->load(file);
513                                 }
514                         }
515                 }
516         }while(!result);
517 }
518
519 void Plugin::get_shared_location(SharedLocation *result)
520 {
521         if(plugin_type == PLUGIN_STANDALONE && plugin_set)
522         {
523                 result->module = edl->tracks->number_of(track);
524                 result->plugin = track->plugin_set.number_of(plugin_set);
525         }
526         else
527         {
528                 *result = this->shared_location;
529         }
530 }
531
532 Track* Plugin::get_shared_track()
533 {
534         return edl->tracks->get_item_number(shared_location.module);
535 }
536
537
538 void Plugin::calculate_title(char *string, int use_nudge)
539 {
540         switch( plugin_type ) {
541         case PLUGIN_STANDALONE:
542         case PLUGIN_NONE:
543                 strcpy(string, _(title));
544                 break;
545         case PLUGIN_SHAREDPLUGIN:
546         case PLUGIN_SHAREDMODULE:
547                 shared_location.calculate_title(string, edl,
548                         startproject, 0, plugin_type, use_nudge);
549                 break;
550         }
551 }
552
553 void Plugin::fix_plugin_title(char *title)
554 {
555         MWindow::fix_plugin_title(title);
556 }
557
558
559 void Plugin::paste(FileXML *file)
560 {
561         length = file->tag.get_property("LENGTH", (int64_t)0);
562 }
563
564 void Plugin::resample(double old_rate, double new_rate)
565 {
566 // Resample keyframes in here
567         keyframes->resample(old_rate, new_rate);
568 }
569
570 void Plugin::shift(int64_t difference)
571 {
572         Edit::shift(difference);
573
574         if(edl->session->autos_follow_edits)
575                 shift_keyframes(difference);
576 }
577
578 void Plugin::dump(FILE *fp)
579 {
580         fprintf(fp,"    PLUGIN: type=%d, id %d, orig_id %d, title=\"%s\" on=%d track=%d plugin=%d gui_id=%d\n",
581                 plugin_type, id, orig_id, title, on, shared_location.module, shared_location.plugin, gui_id);
582         fprintf(fp,"    startproject %jd length %jd\n", startproject, length);
583
584         keyframes->dump(fp);
585 }
586
587