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