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