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