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