e37e930f9342802d3d678bacc63efdd0482cf5c6
[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         this->gui_id = plugin->gui_id;
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->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
220
221 int Plugin::is_synthesis(int64_t position,
222                 int direction)
223 {
224         switch(plugin_type)
225         {
226                 case PLUGIN_STANDALONE:
227                 {
228                         if(!track)
229                         {
230                                 printf("Plugin::is_synthesis track not defined\n");
231                                 return 0;
232                         }
233
234
235                         PluginServer *plugin_server = MWindow::scan_plugindb(title,
236                                 track->data_type);
237 //printf("Plugin::is_synthesis %d %p %d\n", __LINE__, plugin_server, plugin_server->get_synthesis());
238 //plugin_server->dump();
239                         return plugin_server->get_synthesis();
240                         break;
241                 }
242
243 // Dereference real plugin and descend another level
244                 case PLUGIN_SHAREDPLUGIN:
245                 {
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,
252                                 direction,
253                                 0,
254                                 0);
255
256                         if(plugin)
257                                 return plugin->is_synthesis(position, direction);
258                         break;
259                 }
260
261 // Dereference the real track and descend
262                 case PLUGIN_SHAREDMODULE:
263                 {
264                         int real_module_number = shared_location.module;
265                         Track *track = edl->tracks->number(real_module_number);
266                         return track->is_synthesis(position, direction);
267                         break;
268                 }
269         }
270         return 0;
271 }
272
273
274
275 int Plugin::identical(Plugin *that)
276 {
277 // Test type
278         if(plugin_type != that->plugin_type) return 0;
279
280 // Test title or location
281         switch(plugin_type)
282         {
283                 case PLUGIN_STANDALONE:
284                         if(strcmp(title, that->title)) return 0;
285                         break;
286                 case PLUGIN_SHAREDPLUGIN:
287                         if(shared_location.module != that->shared_location.module ||
288                                 shared_location.plugin != that->shared_location.plugin) return 0;
289                         break;
290                 case PLUGIN_SHAREDMODULE:
291                         if(shared_location.module != that->shared_location.module) return 0;
292                         break;
293         }
294
295 // Test remaining fields
296         return (this->on == that->on &&
297                 ((KeyFrame*)keyframes->default_auto)->identical(
298                         ((KeyFrame*)that->keyframes->default_auto)));
299 }
300
301 int Plugin::keyframe_exists(KeyFrame *ptr)
302 {
303         for(KeyFrame *current = (KeyFrame*)keyframes->first;
304                 current;
305                 current = (KeyFrame*)NEXT)
306         {
307                 if(current == ptr) return 1;
308         }
309         return 0;
310 }
311
312
313 void Plugin::change_plugin(char *title,
314                 SharedLocation *shared_location,
315                 int plugin_type)
316 {
317         strcpy(this->title, title);
318         this->shared_location = *shared_location;
319         this->plugin_type = plugin_type;
320 }
321
322
323
324 KeyFrame* Plugin::get_prev_keyframe(int64_t position,
325         int direction)
326 {
327         return keyframes->get_prev_keyframe(position, direction);
328 }
329
330 KeyFrame* Plugin::get_next_keyframe(int64_t position,
331         int direction)
332 {
333         KeyFrame *current;
334
335 // This doesn't work for playback because edl->selectionstart doesn't
336 // change during playback at the same rate as PluginClient::source_position.
337         if(position < 0)
338         {
339 //printf("Plugin::get_next_keyframe position < 0\n");
340                 position = track->to_units(edl->local_session->get_selectionstart(1), 0);
341         }
342
343 // Get keyframe after current position
344         for(current = (KeyFrame*)keyframes->first;
345                 current;
346                 current = (KeyFrame*)NEXT)
347         {
348                 if(direction == PLAY_FORWARD && current->position > position) break;
349                 else
350                 if(direction == PLAY_REVERSE && current->position >= position) break;
351         }
352
353 // Nothing after current position
354         if(!current && keyframes->last)
355         {
356                 current =  (KeyFrame*)keyframes->last;
357         }
358         else
359 // No keyframes
360         if(!current)
361         {
362                 current = (KeyFrame*)keyframes->default_auto;
363         }
364
365         return current;
366 }
367
368 KeyFrame* Plugin::get_keyframe()
369 {
370         return keyframes->get_keyframe();
371 }
372
373 void Plugin::copy(int64_t start, int64_t end, FileXML *file)
374 {
375         int64_t endproject = startproject + length;
376
377         if((startproject >= start && startproject <= end) ||  // startproject in range
378                  (endproject <= end && endproject >= start) ||     // endproject in range
379                  (startproject <= start && endproject >= end))    // range in project
380         {
381 // edit is in range
382                 int64_t startproject_in_selection = startproject; // start of edit in selection in project
383                 int64_t startsource_in_selection = startsource; // start of source in selection in source
384                 //int64_t endsource_in_selection = startsource + length; // end of source in selection
385                 int64_t length_in_selection = length;             // length of edit in selection
386
387                 if(startproject < start)
388                 {         // start is after start of edit in project
389                         int64_t length_difference = start - startproject;
390
391                         startsource_in_selection += length_difference;
392                         startproject_in_selection += length_difference;
393                         length_in_selection -= length_difference;
394                 }
395
396 // end is before end of edit in project
397                 if(endproject > end)
398                 {
399                         length_in_selection = end - startproject_in_selection;
400                 }
401
402 // Plugins don't store silence
403                 file->tag.set_title("PLUGIN");
404 //              file->tag.set_property("STARTPROJECT", startproject_in_selection - start);
405                 file->tag.set_property("LENGTH", length_in_selection);
406                 file->tag.set_property("TYPE", plugin_type);
407                 file->tag.set_property("TITLE", title);
408                 file->append_tag();
409                 file->append_newline();
410
411
412                 if(plugin_type == PLUGIN_SHAREDPLUGIN ||
413                         plugin_type == PLUGIN_SHAREDMODULE)
414                 {
415                         shared_location.save(file);
416                 }
417
418
419
420                 if(in)
421                 {
422                         file->tag.set_title("IN");
423                         file->append_tag();
424                         file->tag.set_title("/IN");
425                         file->append_tag();
426                 }
427                 if(out)
428                 {
429                         file->tag.set_title("OUT");
430                         file->append_tag();
431                         file->tag.set_title("/OUT");
432                         file->append_tag();
433                 }
434                 if(show)
435                 {
436                         file->tag.set_title("SHOW");
437                         file->append_tag();
438                         file->tag.set_title("/SHOW");
439                         file->append_tag();
440                 }
441                 if(on)
442                 {
443                         file->tag.set_title("ON");
444                         file->append_tag();
445                         file->tag.set_title("/ON");
446                         file->append_tag();
447                 }
448                 file->append_newline();
449
450 // Keyframes
451                 keyframes->copy(start, end, file, 0, 0);
452
453                 file->tag.set_title("/PLUGIN");
454                 file->append_tag();
455                 file->append_newline();
456         }
457 }
458
459 void Plugin::load(FileXML *file)
460 {
461         int result = 0;
462         int first_keyframe = 1;
463         in = 0;
464         out = 0;
465 // Currently show is ignored when loading
466         show = 0;
467         on = 0;
468         while(keyframes->last) delete keyframes->last;
469
470         do{
471                 result = file->read_tag();
472
473 //printf("Plugin::load 1 %s\n", file->tag.get_title());
474                 if(!result)
475                 {
476                         if(file->tag.title_is("/PLUGIN"))
477                         {
478                                 result = 1;
479                         }
480                         else
481                         if(file->tag.title_is("SHARED_LOCATION"))
482                         {
483                                 shared_location.load(file);
484                         }
485                         else
486                         if(file->tag.title_is("IN"))
487                         {
488                                 in = 1;
489                         }
490                         else
491                         if(file->tag.title_is("OUT"))
492                         {
493                                 out = 1;
494                         }
495                         else
496                         if(file->tag.title_is("SHOW"))
497                         {
498                                 show = 1;
499                         }
500                         else
501                         if(file->tag.title_is("ON"))
502                         {
503                                 on = 1;
504                         }
505                         else
506                         if(file->tag.title_is("KEYFRAME"))
507                         {
508 // Default keyframe
509                                 if(first_keyframe)
510                                 {
511                                         keyframes->default_auto->load(file);
512                                         first_keyframe = 0;
513                                 }
514                                 else
515 // Override default keyframe
516                                 {
517                                         KeyFrame *keyframe = (KeyFrame*)keyframes->append(new KeyFrame(edl, keyframes));
518                                         keyframe->position = file->tag.get_property("POSITION", (int64_t)0);
519                                         keyframe->load(file);
520                                 }
521                         }
522                 }
523         }while(!result);
524 }
525
526 void Plugin::get_shared_location(SharedLocation *result)
527 {
528         if(plugin_type == PLUGIN_STANDALONE && plugin_set)
529         {
530                 result->module = edl->tracks->number_of(track);
531                 result->plugin = track->plugin_set.number_of(plugin_set);
532         }
533         else
534         {
535                 *result = this->shared_location;
536         }
537 }
538
539 Track* Plugin::get_shared_track()
540 {
541         return edl->tracks->get_item_number(shared_location.module);
542 }
543
544
545 void Plugin::calculate_title(char *string, int use_nudge)
546 {
547         switch( plugin_type ) {
548         case PLUGIN_STANDALONE:
549         case PLUGIN_NONE:
550                 strcpy(string, _(title));
551                 break;
552         case PLUGIN_SHAREDPLUGIN:
553         case PLUGIN_SHAREDMODULE:
554                 shared_location.calculate_title(string, edl,
555                         startproject, 0, plugin_type, use_nudge);
556                 break;
557         }
558 }
559
560 void Plugin::fix_plugin_title(char *title)
561 {
562         MWindow::fix_plugin_title(title);
563 }
564
565
566 void Plugin::paste(FileXML *file)
567 {
568         length = file->tag.get_property("LENGTH", (int64_t)0);
569 }
570
571 void Plugin::resample(double old_rate, double new_rate)
572 {
573 // Resample keyframes in here
574         keyframes->resample(old_rate, new_rate);
575 }
576
577 void Plugin::shift(int64_t difference)
578 {
579         Edit::shift(difference);
580
581         if(edl->session->autos_follow_edits)
582                 shift_keyframes(difference);
583 }
584
585 void Plugin::dump(FILE *fp)
586 {
587         fprintf(fp,"    PLUGIN: type=%d title=\"%s\" on=%d track=%d plugin=%d gui_id=%d\n",
588                 plugin_type, title, on, shared_location.module, shared_location.plugin, gui_id);
589         fprintf(fp,"    startproject %jd length %jd\n", startproject, length);
590
591         keyframes->dump(fp);
592 }
593
594