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