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