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