r550: References to a shared plugin that is moved up or down must be updated.
[cinelerra_cv.git] / cinelerra / track.C
blob1f99150ce29df3a343a984e5eb5a3a0f884ae63b
1 #include "asset.h"
2 #include "autoconf.h"
3 #include "automation.h"
4 #include "clip.h"
5 #include "edit.h"
6 #include "edits.h"
7 #include "edl.h"
8 #include "edlsession.h"
9 #include "filexml.h"
10 #include "floatauto.h"
11 #include "floatautos.h"
12 #include "keyframe.h"
13 #include "localsession.h"
14 #include "module.h"
15 #include "patch.h"
16 #include "patchbay.h"
17 #include "plugin.h"
18 #include "pluginset.h"
19 #include "mainsession.h"
20 #include "theme.h"
21 #include "intautos.h"
22 #include "track.h"
23 #include "trackcanvas.h"
24 #include "tracks.h"
25 #include "transition.h"
26 #include "transportque.inc"
27 #include "vedit.h"
28 #include "vframe.h"
29 #include <string.h>
32 Track::Track(EDL *edl, Tracks *tracks) : ListItem<Track>()
34         this->edl = edl;
35         this->tracks = tracks;
36         y_pixel = 0;
37         expand_view = 0;
38         draw = 1;
39         gang = 1;
40         title[0] = 0;
41         record = 1;
42         play = 1;
43         nudge = 0;
44         track_w = edl->session->output_w;
45         track_h = edl->session->output_h;
46         id = EDL::next_id();
49 Track::~Track()
51         delete automation;
52         delete edits;
53         plugin_set.remove_all_objects();
56 int Track::create_objects()
58         return 0;
62 int Track::copy_settings(Track *track)
64         this->expand_view = track->expand_view;
65         this->draw = track->draw;
66         this->gang = track->gang;
67         this->record = track->record;
68         this->nudge = track->nudge;
69         this->play = track->play;
70         this->track_w = track->track_w;
71         this->track_h = track->track_h;
72         strcpy(this->title, track->title);
73         return 0;
76 int Track::get_id()
78         return id;
82 int Track::load_defaults(Defaults *defaults)
84         return 0;
87 void Track::equivalent_output(Track *track, double *result)
89         if(data_type != track->data_type ||
90                 track_w != track->track_w ||
91                 track_h != track->track_h ||
92                 play != track->play ||
93                 nudge != track->nudge)
94                 *result = 0;
96 // Convert result to track units
97         int64_t result2 = -1;
98         automation->equivalent_output(track->automation, &result2);
99         edits->equivalent_output(track->edits, &result2);
101         int plugin_sets = MIN(plugin_set.total, track->plugin_set.total);
102 // Test existing plugin sets
103         for(int i = 0; i < plugin_sets; i++)
104         {
105                 plugin_set.values[i]->equivalent_output(
106                         track->plugin_set.values[i], 
107                         &result2);
108         }
110 // New EDL has more plugin sets.  Get starting plugin in new plugin sets
111         for(int i = plugin_sets; i < plugin_set.total; i++)
112         {
113                 Plugin *current = plugin_set.values[i]->get_first_plugin();
114                 if(current)
115                 {
116                         if(result2 < 0 || current->startproject < result2)
117                                 result2 = current->startproject;
118                 }
119         }
121 // New EDL has fewer plugin sets.  Get starting plugin in old plugin set
122         for(int i = plugin_sets; i < track->plugin_set.total; i++)
123         {
124                 Plugin *current = track->plugin_set.values[i]->get_first_plugin();
125                 if(current)
126                 {
127                         if(result2 < 0 || current->startproject < result2)
128                                 result2 = current->startproject;
129                 }
130         }
132 // Number of plugin sets differs but somehow we didn't find the start of the
133 // change.  Assume 0
134         if(track->plugin_set.total != plugin_set.total && result2 < 0)
135                 result2 = 0;
137         if(result2 >= 0 && 
138                 (*result < 0 || from_units(result2) < *result))
139                 *result = from_units(result2);
143 int Track::is_synthesis(RenderEngine *renderengine, 
144         int64_t position, 
145         int direction)
147         int is_synthesis = 0;
148         for(int i = 0; i < plugin_set.total; i++)
149         {
150                 Plugin *plugin = get_current_plugin(position,
151                         i,
152                         direction,
153                         0,
154                         0);
155                 if(plugin)
156                 {
157                         is_synthesis = plugin->is_synthesis(renderengine, 
158                                 position, 
159                                 direction);
160                         if(is_synthesis) break;
161                 }
162         }
163         return is_synthesis;
166 void Track::copy_from(Track *track)
168         copy_settings(track);
169         edits->copy_from(track->edits);
170         for(int i = 0; i < this->plugin_set.total; i++)
171                 delete this->plugin_set.values[i];
172         this->plugin_set.remove_all_objects();
174         for(int i = 0; i < track->plugin_set.total; i++)
175         {
176                 PluginSet *new_plugin_set = plugin_set.append(new PluginSet(edl, this));
177                 new_plugin_set->copy_from(track->plugin_set.values[i]);
178         }
179         automation->copy_from(track->automation);
180         this->track_w = track->track_w;
181         this->track_h = track->track_h;
184 Track& Track::operator=(Track& track)
186 printf("Track::operator= 1\n");
187         copy_from(&track);
188         return *this;
191 int Track::vertical_span(Theme *theme)
193         int result = 0;
194         if(expand_view)
195                 result = edl->local_session->zoom_track + 
196                         plugin_set.total * 
197                         theme->plugin_bg_data->get_h();
198         else
199                 result = edl->local_session->zoom_track;
201         if(edl->session->show_titles)
202                 result += theme->title_bg_data->get_h();
204         return result;
207 double Track::get_length()
209         double total_length = 0;
210         double length = 0;
212 // Test edits
213         if(edits->last)
214         {
215                 length = from_units(edits->last->startproject + edits->last->length);
216                 if(length > total_length) total_length = length;
217         }
219 // Test plugins
220         for(int i = 0; i < plugin_set.total; i++)
221         {
222                 if(plugin_set.values[i]->last)
223                 {
224                         length = from_units(plugin_set.values[i]->last->startproject + 
225                                 plugin_set.values[i]->last->length);
226                         if(length > total_length) total_length = length;
227                 }
228         }
230 // Test keyframes
231         length = from_units(automation->get_length());
232         if(length > total_length) total_length = length;
233         
235         return total_length;
240 void Track::get_source_dimensions(double position, int &w, int &h)
242         int64_t native_position = to_units(position, 0);
243         for(Edit *current = edits->first; current; current = NEXT)
244         {
245                 if(current->startproject <= native_position &&
246                         current->startproject + current->length > native_position &&
247                         current->asset)
248                 {
249                         w = current->asset->width;
250                         h = current->asset->height;
251                         return;
252                 }
253         }
257 int64_t Track::horizontal_span()
259         return (int64_t)(get_length() * 
260                 edl->session->sample_rate / 
261                 edl->local_session->zoom_sample + 
262                 0.5);
266 int Track::load(FileXML *file, int track_offset, uint32_t load_flags)
268         int result = 0;
269         int current_channel = 0;
270         int current_plugin = 0;
273         record = file->tag.get_property("RECORD", record);
274         play = file->tag.get_property("PLAY", play);
275         gang = file->tag.get_property("GANG", gang);
276         draw = file->tag.get_property("DRAW", draw);
277         nudge = file->tag.get_property("NUDGE", nudge);
278         expand_view = file->tag.get_property("EXPAND", expand_view);
279         track_w = file->tag.get_property("TRACK_W", track_w);
280         track_h = file->tag.get_property("TRACK_H", track_h);
282         load_header(file, load_flags);
284         do{
285                 result = file->read_tag();
287                 if(!result)
288                 {
289                         if(file->tag.title_is("/TRACK"))
290                         {
291                                 result = 1;
292                         }
293                         else
294                         if(file->tag.title_is("TITLE"))
295                         {
296                                 file->read_text_until("/TITLE", title);
297                         }
298                         else
299                         if(strstr(file->tag.get_title(), "AUTOS"))
300                         {
301                                 if(load_flags)
302                                 {
303                                         automation->load(file);
304                                 }
305                         }
306                         else
307                         if(file->tag.title_is("EDITS"))
308                         {
309                                 if(load_flags & LOAD_EDITS)
310                                         edits->load(file, track_offset);
311                         }
312                         else
313                         if(file->tag.title_is("PLUGINSET"))
314                         {
315                                 if(load_flags & LOAD_EDITS)
316                                 {
317                                         PluginSet *plugin_set = new PluginSet(edl, this);
318                                         this->plugin_set.append(plugin_set);
319                                         plugin_set->load(file, load_flags);
320                                 }
321                                 else
322                                 if(load_flags & LOAD_AUTOMATION)
323                                 {
324                                         if(current_plugin < this->plugin_set.total)
325                                         {
326                                                 PluginSet *plugin_set = this->plugin_set.values[current_plugin];
327                                                 plugin_set->load(file, load_flags);
328                                                 current_plugin++;
329                                         }
330                                 }
331                         }
332                         else
333                                 load_derived(file, load_flags);
334                 }
335         }while(!result);
339         return 0;
342 void Track::insert_asset(Asset *asset, 
343                 double length, 
344                 double position, 
345                 int track_number)
347 //printf("Track::insert_asset %f\n", length);
348         edits->insert_asset(asset, 
349                 to_units(length, 1), 
350                 to_units(position, 0), 
351                 track_number);
354 // Insert data
356 // Default keyframes: We don't replace default keyframes in pasting but
357 // when inserting the first EDL of a load operation we need to replace
358 // the default keyframes.
360 // Plugins:  This is an arbitrary behavior
362 // 1) No plugin in source track: Paste silence into destination
363 // plugin sets.
364 // 2) Plugin in source track: plugin in source track is inserted into
365 // existing destination track plugin sets, new sets being added when
366 // necessary.
368 void Track::insert_track(Track *track, 
369         double position, 
370         int replace_default,
371         int edit_plugins)
373 // Decide whether to copy settings based on load_mode
374         if(replace_default) copy_settings(track);
376         edits->insert_edits(track->edits, to_units(position, 0));
378         if(edit_plugins)
379                 insert_plugin_set(track, position);
381         automation->insert_track(track->automation, 
382                 to_units(position, 0), 
383                 to_units(track->get_length(), 1),
384                 replace_default);
386         optimize();
389 // Called by insert_track
390 void Track::insert_plugin_set(Track *track, double position)
392 // Extend plugins if no incoming plugins
393         if(!track->plugin_set.total)
394         {
395                 shift_effects(position, 
396                         track->get_length(), 
397                         1);
398         }
399         else
400         for(int i = 0; i < track->plugin_set.total; i++)
401         {
402                 if(i >= plugin_set.total)
403                         plugin_set.append(new PluginSet(edl, this));
405                 plugin_set.values[i]->insert_edits(track->plugin_set.values[i], 
406                         to_units(position, 0));
407         }
411 Plugin* Track::insert_effect(char *title, 
412                 SharedLocation *shared_location, 
413                 KeyFrame *default_keyframe,
414                 PluginSet *plugin_set,
415                 double start,
416                 double length,
417                 int plugin_type)
419         if(!plugin_set)
420         {
421                 plugin_set = new PluginSet(edl, this);
422                 this->plugin_set.append(plugin_set);
423         }
425         Plugin *plugin = 0;
427 // Position is identical to source plugin
428         if(plugin_type == PLUGIN_SHAREDPLUGIN)
429         {
430                 Track *source_track = tracks->get_item_number(shared_location->module);
431                 if(source_track)
432                 {
433                         Plugin *source_plugin = source_track->get_current_plugin(
434                                 edl->local_session->get_selectionstart(), 
435                                 shared_location->plugin, 
436                                 PLAY_FORWARD, 
437                                 1,
438                                 0);
440 // From an attach operation
441                         if(source_plugin)
442                         {
443                                 plugin = plugin_set->insert_plugin(title, 
444                                         source_plugin->startproject, 
445                                         source_plugin->length,
446                                         plugin_type, 
447                                         shared_location,
448                                         default_keyframe,
449                                         1);
450                         }
451                         else
452 // From a drag operation
453                         {
454                                 plugin = plugin_set->insert_plugin(title, 
455                                         to_units(start, 0), 
456                                         to_units(length, 0),
457                                         plugin_type, 
458                                         shared_location,
459                                         default_keyframe,
460                                         1);
461                         }
462                 }
463         }
464         else
465         {
466 // This should be done in the caller
467                 if(EQUIV(length, 0))
468                 {
469                         if(edl->local_session->get_selectionend() > 
470                                 edl->local_session->get_selectionstart())
471                         {
472                                 start = edl->local_session->get_selectionstart();
473                                 length = edl->local_session->get_selectionend() - start;
474                         }
475                         else
476                         {
477                                 start = 0;
478                                 length = get_length();
479                         }
480                 }
481 //printf("Track::insert_effect %f %f %d %d\n", start, length, to_units(start, 0), 
482 //                      to_units(length, 0));
484                 plugin = plugin_set->insert_plugin(title, 
485                         to_units(start, 0), 
486                         to_units(length, 0),
487                         plugin_type, 
488                         shared_location,
489                         default_keyframe,
490                         1);
491         }
492 //printf("Track::insert_effect 2 %f %f\n", start, length);
494         expand_view = 1;
495         return plugin;
498 void Track::move_plugins_up(PluginSet *plugin_set)
500         for(int i = 0; i < this->plugin_set.total; i++)
501         {
502                 if(this->plugin_set.values[i] == plugin_set)
503                 {
504                         if(i == 0) break;
506                         PluginSet *temp = this->plugin_set.values[i - 1];
507                         this->plugin_set.values[i - 1] = this->plugin_set.values[i];
508                         this->plugin_set.values[i] = temp;
510                         SharedLocation old_location, new_location;
511                         new_location.module = old_location.module = tracks->number_of(this);
512                         old_location.plugin = i;
513                         new_location.plugin = i - 1;
514                         tracks->change_plugins(old_location, new_location, 1);
515                         break;
516                 }
517         }
520 void Track::move_plugins_down(PluginSet *plugin_set)
522         for(int i = 0; i < this->plugin_set.total; i++)
523         {
524                 if(this->plugin_set.values[i] == plugin_set)
525                 {
526                         if(i == this->plugin_set.total - 1) break;
528                         PluginSet *temp = this->plugin_set.values[i + 1];
529                         this->plugin_set.values[i + 1] = this->plugin_set.values[i];
530                         this->plugin_set.values[i] = temp;
532                         SharedLocation old_location, new_location;
533                         new_location.module = old_location.module = tracks->number_of(this);
534                         old_location.plugin = i;
535                         new_location.plugin = i + 1;
536                         tracks->change_plugins(old_location, new_location, 1);
537                         break;
538                 }
539         }
543 void Track::remove_asset(Asset *asset)
545         for(Edit *edit = edits->first; edit; edit = edit->next)
546         {
547                 if(edit->asset && edit->asset == asset)
548                 {
549                         edit->asset = 0;
550                 }
551         }
552         optimize();
555 void Track::remove_pluginset(PluginSet *plugin_set)
557         int i;
558         for(i = 0; i < this->plugin_set.total; i++)
559                 if(plugin_set == this->plugin_set.values[i]) break;
561         this->plugin_set.remove_object(plugin_set);
562         for(i++ ; i < this->plugin_set.total; i++)
563         {
564                 SharedLocation old_location, new_location;
565                 new_location.module = old_location.module = tracks->number_of(this);
566                 old_location.plugin = i;
567                 new_location.plugin = i - 1;
568                 tracks->change_plugins(old_location, new_location, 0);
569         }
572 void Track::shift_keyframes(double position, double length, int convert_units)
574         if(convert_units)
575         {
576                 position = to_units(position, 0);
577                 length = to_units(length, 0);
578         }
580         automation->paste_silence(Units::to_int64(position), 
581                 Units::to_int64(position + length));
582 // Effect keyframes are shifted in shift_effects
585 void Track::shift_effects(double position, double length, int convert_units)
587         if(convert_units)
588         {
589                 position = to_units(position, 0);
590                 length = to_units(length, 0);
591         }
593         for(int i = 0; i < plugin_set.total; i++)
594         {
595                 plugin_set.values[i]->shift_effects(Units::to_int64(position), Units::to_int64(length));
596         }
599 void Track::detach_effect(Plugin *plugin)
601 //printf("Track::detach_effect 1\n");           
602         for(int i = 0; i < plugin_set.total; i++)
603         {
604                 PluginSet *plugin_set = this->plugin_set.values[i];
605                 for(Plugin *dest = (Plugin*)plugin_set->first; 
606                         dest; 
607                         dest = (Plugin*)dest->next)
608                 {
609                         if(dest == plugin)
610                         {
611                                 int64_t start = plugin->startproject;
612                                 int64_t end = plugin->startproject + plugin->length;
614                                 plugin_set->clear(start, end);
615                                 plugin_set->paste_silence(start, end);
617 // Delete 0 length pluginsets   
618                                 plugin_set->optimize();
619 //printf("Track::detach_effect 2 %d\n", plugin_set->length());
620                                 if(!plugin_set->length()) 
621                                         this->plugin_set.remove_object(plugin_set);
623                                 return;
624                         }
625                 }
626         }
629 void Track::resample(double old_rate, double new_rate)
631         edits->resample(old_rate, new_rate);
632         automation->resample(old_rate, new_rate);
633         for(int i = 0; i < plugin_set.total; i++)
634                 plugin_set.values[i]->resample(old_rate, new_rate);
635         nudge = (int64_t)(nudge * new_rate / old_rate);
640 void Track::optimize()
642         edits->optimize();
643         for(int i = 0; i < plugin_set.total; i++)
644         {
645                 plugin_set.values[i]->optimize();
646 //printf("Track::optimize %d\n", plugin_set.values[i]->total());
647                 if(plugin_set.values[i]->total() <= 0)
648                 {
649                         remove_pluginset(plugin_set.values[i]);
650                         i--;
651                 }
652         }
655 Plugin* Track::get_current_plugin(double position, 
656         int plugin_set, 
657         int direction, 
658         int convert_units,
659         int use_nudge)
661         Plugin *current;
662         if(convert_units) position = to_units(position, 0);
663         if(use_nudge) position += nudge;
664         
665         if(plugin_set >= this->plugin_set.total || plugin_set < 0) return 0;
667 //printf("Track::get_current_plugin 1 %d %d %d\n", position, this->plugin_set.total, direction);
668         if(direction == PLAY_FORWARD)
669         {
670                 for(current = (Plugin*)this->plugin_set.values[plugin_set]->last; 
671                         current; 
672                         current = (Plugin*)PREVIOUS)
673                 {
674 // printf("Track::get_current_plugin 2 %d %ld %ld\n", 
675 // current->startproject, 
676 // current->startproject + current->length, 
677 // position);
678                         if(current->startproject <= position && 
679                                 current->startproject + current->length > position)
680                         {
681                                 return current;
682                         }
683                 }
684         }
685         else
686         if(direction == PLAY_REVERSE)
687         {
688                 for(current = (Plugin*)this->plugin_set.values[plugin_set]->first; 
689                         current; 
690                         current = (Plugin*)NEXT)
691                 {
692                         if(current->startproject < position && 
693                                 current->startproject + current->length >= position)
694                         {
695                                 return current;
696                         }
697                 }
698         }
700         return 0;
703 Plugin* Track::get_current_transition(double position, 
704         int direction, 
705         int convert_units,
706         int use_nudge)
708         Edit *current;
709         Plugin *result = 0;
710         if(convert_units) position = to_units(position, 0);
711         if(use_nudge) position += nudge;
713         if(direction == PLAY_FORWARD)
714         {
715                 for(current = edits->last; current; current = PREVIOUS)
716                 {
717                         if(current->startproject <= position && current->startproject + current->length > position)
718                         {
719 //printf("Track::get_current_transition %p\n", current->transition);
720                                 if(current->transition && position < current->startproject + current->transition->length)
721                                 {
722                                         result = current->transition;
723                                         break;
724                                 }
725                         }
726                 }
727         }
728         else
729         if(direction == PLAY_REVERSE)
730         {
731                 for(current = edits->first; current; current = NEXT)
732                 {
733                         if(current->startproject < position && current->startproject + current->length >= position)
734                         {
735                                 if(current->transition && position <= current->startproject + current->transition->length)
736                                 {
737                                         result = current->transition;
738                                         break;
739                                 }
740                         }
741                 }
742         }
744         return result;
747 void Track::synchronize_params(Track *track)
749         for(Edit *this_edit = edits->first, *that_edit = track->edits->first;
750                 this_edit && that_edit;
751                 this_edit = this_edit->next, that_edit = that_edit->next)
752         {
753                 this_edit->synchronize_params(that_edit);
754         }
756         for(int i = 0; i < plugin_set.total && i < track->plugin_set.total; i++)
757                 plugin_set.values[i]->synchronize_params(track->plugin_set.values[i]);
759         automation->copy_from(track->automation);
760         this->nudge = track->nudge;
767 int Track::dump()
769         printf("   Data type %d\n", data_type);
770         printf("   Title %s\n", title);
771         printf("   Edits:\n");
772         for(Edit* current = edits->first; current; current = NEXT)
773         {
774                 current->dump();
775         }
776         automation->dump();
777         printf("   Plugin Sets: %d\n", plugin_set.total);
779         for(int i = 0; i < plugin_set.total; i++)
780                 plugin_set.values[i]->dump();
781 //printf("Track::dump 2\n");
782         return 0;
805 Track::Track() : ListItem<Track>()
807         y_pixel = 0;
810 // ======================================== accounting
812 int Track::number_of() 
814         return tracks->number_of(this); 
821         
822         
829 // ================================================= editing
831 int Track::select_auto(AutoConf *auto_conf, int cursor_x, int cursor_y)
833         return 0;
836 int Track::move_auto(AutoConf *auto_conf, int cursor_x, int cursor_y, int shift_down)
838         return 0;
841 int Track::release_auto()
843         return 0;
846 // used for copying automation alone
847 int Track::copy_automation(double selectionstart, 
848         double selectionend, 
849         FileXML *file,
850         int default_only,
851         int autos_only)
853         int64_t start = to_units(selectionstart, 0);
854         int64_t end = to_units(selectionend, 0);
856         file->tag.set_title("TRACK");
857 // Video or audio
858     save_header(file);
859         file->append_tag();
860         file->append_newline();
862         automation->copy(start, end, file, default_only, autos_only);
864         if(edl->session->auto_conf->plugins)
865         {
866                 file->tag.set_title("PLUGINSETS");
867                 file->append_tag();
868                 file->append_newline();
869                 for(int i = 0; i < plugin_set.total; i++)
870                 {
871                 
872                         plugin_set.values[i]->copy_keyframes(start, 
873                                 end, 
874                                 file, 
875                                 default_only,
876                                 autos_only);
877                 }
878                 file->tag.set_title("/PLUGINSETS");
879                 file->append_tag();
880                 file->append_newline();
881         }
883         file->tag.set_title("/TRACK");
884         file->append_tag();
885         file->append_newline();
886         file->append_newline();
887         file->append_newline();
888         file->append_newline();
890         return 0;
893 int Track::paste_automation(double selectionstart, 
894         double total_length, 
895         double frame_rate,
896         int64_t sample_rate,
897         FileXML *file,
898         int default_only)
900 // Only used for pasting automation alone.
901         int64_t start;
902         int64_t length;
903         int result;
904         double scale;
906         if(data_type == TRACK_AUDIO)
907                 scale = edl->session->sample_rate / sample_rate;
908         else
909                 scale = edl->session->frame_rate / frame_rate;
911         total_length *= scale;
912         start = to_units(selectionstart, 0);
913         length = to_units(total_length, 0);
914         result = 0;
915 //printf("Track::paste_automation 1\n");
917         while(!result)
918         {
919                 result = file->read_tag();
921                 if(!result)
922                 {
923                         if(file->tag.title_is("/TRACK"))
924                                 result = 1;
925                         else
926                         if(strstr(file->tag.get_title(), "AUTOS"))
927                         {
928                                 automation->paste(start, 
929                                         length, 
930                                         scale,
931                                         file,
932                                         default_only,
933                                         0);
934                         }
935                         else
936                         if(file->tag.title_is("PLUGINSETS"))
937                         {
938 //printf("Track::paste_automation 2 %d\n", current_pluginset);
939                                 PluginSet::paste_keyframes(start, 
940                                         length, 
941                                         file,
942                                         default_only,
943                                         this);
944                         }
945                 }
946         }
947 //printf("Track::paste_automation 3\n");
948         
950         return 0;
953 void Track::clear_automation(double selectionstart, 
954         double selectionend, 
955         int shift_autos,
956         int default_only)
958         int64_t start = to_units(selectionstart, 0);
959         int64_t end = to_units(selectionend, 0);
961         automation->clear(start, end, edl->session->auto_conf, 0);
963         if(edl->session->auto_conf->plugins)
964         {
965                 for(int i = 0; i < plugin_set.total; i++)
966                 {
967                         plugin_set.values[i]->clear_keyframes(start, end);
968                 }
969         }
974 int Track::copy(double start, 
975         double end, 
976         FileXML *file, 
977         char *output_path)
979 // Use a copy of the selection in converted units
980 // So copy_automation doesn't reconvert.
981         int64_t start_unit = to_units(start, 0);
982         int64_t end_unit = to_units(end, 1);
987         file->tag.set_title("TRACK");
988         file->tag.set_property("RECORD", record);
989         file->tag.set_property("NUDGE", nudge);
990         file->tag.set_property("PLAY", play);
991         file->tag.set_property("GANG", gang);
992         file->tag.set_property("DRAW", draw);
993         file->tag.set_property("EXPAND", expand_view);
994         file->tag.set_property("TRACK_W", track_w);
995         file->tag.set_property("TRACK_H", track_h);
996         save_header(file);
997         file->append_tag();
998         file->append_newline();
999         save_derived(file);
1001         file->tag.set_title("TITLE");
1002         file->append_tag();
1003         file->append_text(title);
1004         file->tag.set_title("/TITLE");
1005         file->append_tag();
1006         file->append_newline();
1010         edits->copy(start_unit, end_unit, file, output_path);
1012         AutoConf auto_conf;
1013         auto_conf.set_all();
1014         automation->copy(start_unit, end_unit, file, 0, 0);
1017         for(int i = 0; i < plugin_set.total; i++)
1018         {
1019                 plugin_set.values[i]->copy(start_unit, end_unit, file);
1020         }
1022         copy_derived(start_unit, end_unit, file);
1024         file->tag.set_title("/TRACK");
1025         file->append_tag();
1026         file->append_newline();
1027         file->append_newline();
1028         file->append_newline();
1029         file->append_newline();
1031         return 0;
1034 int Track::copy_assets(double start, 
1035         double end, 
1036         ArrayList<Asset*> *asset_list)
1038         int i, result = 0;
1040         start = to_units(start, 0);
1041         end = to_units(end, 0);
1043         Edit *current = edits->editof((int64_t)start, PLAY_FORWARD, 0);
1045 // Search all edits
1046         while(current && current->startproject < end)
1047         {
1048 // Check for duplicate assets
1049                 if(current->asset)
1050                 {
1051                         for(i = 0, result = 0; i < asset_list->total; i++)
1052                         {
1053                                 if(asset_list->values[i] == current->asset) result = 1;
1054                         }
1055 // append pointer to new asset
1056                         if(!result) asset_list->append(current->asset);
1057                 }
1059                 current = NEXT;
1060         }
1062         return 0;
1069 int Track::clear(double start, 
1070         double end, 
1071         int edit_edits,
1072         int edit_labels,
1073         int edit_plugins,
1074         int convert_units,
1075         Edits *trim_edits)
1077 // Edits::move_auto calls this routine after the units are converted to the track
1078 // format.
1079 //printf("Track::clear 1 %d %d %d\n", edit_edits, edit_labels, edit_plugins);
1080         if(convert_units)
1081         {
1082                 start = to_units(start, 0);
1083                 end = to_units(end, 0);
1084         }
1086         if(edit_edits)
1087                 automation->clear((int64_t)start, (int64_t)end, 0, 1);
1089         if(edit_plugins)
1090                 for(int i = 0; i < plugin_set.total; i++)
1091                 {
1092                         if(!trim_edits || trim_edits == (Edits*)plugin_set.values[i])
1093                                 plugin_set.values[i]->clear((int64_t)start, (int64_t)end);
1094                 }
1096         if(edit_edits)
1097                 edits->clear((int64_t)start, (int64_t)end);
1098         return 0;
1101 int Track::clear_handle(double start, 
1102         double end, 
1103         int clear_labels,
1104         int clear_plugins, 
1105         double &distance)
1107         edits->clear_handle(start, end, clear_plugins, distance);
1110 int Track::popup_transition(int cursor_x, int cursor_y)
1112         return 0;
1117 int Track::modify_edithandles(double oldposition, 
1118         double newposition, 
1119         int currentend, 
1120         int handle_mode,
1121         int edit_labels,
1122         int edit_plugins)
1124         edits->modify_handles(oldposition, 
1125                 newposition, 
1126                 currentend,
1127                 handle_mode,
1128                 1,
1129                 edit_labels,
1130                 edit_plugins,
1131                 0);
1134         return 0;
1137 int Track::modify_pluginhandles(double oldposition, 
1138         double newposition, 
1139         int currentend, 
1140         int handle_mode,
1141         int edit_labels,
1142         Edits *trim_edits)
1144         for(int i = 0; i < plugin_set.total; i++)
1145         {
1146                 if(!trim_edits || trim_edits == (Edits*)plugin_set.values[i])
1147                         plugin_set.values[i]->modify_handles(oldposition, 
1148                                 newposition, 
1149                                 currentend, 
1150                                 handle_mode,
1151 // Don't allow plugin tweeks to affect edits.
1152                                 0,
1153                                 edit_labels,
1154                                 1,
1155                                 trim_edits);
1156         }
1157         return 0;
1161 int Track::paste_silence(double start, double end, int edit_plugins)
1163         start = to_units(start, 0);
1164         end = to_units(end, 1);
1166         edits->paste_silence((int64_t)start, (int64_t)end);
1167         shift_keyframes(start, end - start, 0);
1168         if(edit_plugins) shift_effects(start, end - start, 0);
1170         edits->optimize();
1171         return 0;
1174 int Track::select_edit(int cursor_x, 
1175         int cursor_y, 
1176         double &new_start, 
1177         double &new_end)
1179         return 0;
1182 int Track::scale_time(float rate_scale, int scale_edits, int scale_autos, int64_t start, int64_t end)
1184         return 0;
1187 void Track::change_plugins(SharedLocation &old_location, SharedLocation &new_location, int do_swap)
1189         for(int i = 0; i < plugin_set.total; i++)
1190         {
1191                 for(Plugin *plugin = (Plugin*)plugin_set.values[i]->first; 
1192                         plugin; 
1193                         plugin = (Plugin*)plugin->next)
1194                 {
1195                         if(plugin->plugin_type == PLUGIN_SHAREDPLUGIN)
1196                         {
1197                                 if(plugin->shared_location == old_location)
1198                                         plugin->shared_location = new_location;
1199                                 else
1200                                 if(do_swap && plugin->shared_location == new_location)
1201                                         plugin->shared_location = old_location;
1202                         }
1203                 }
1204         }
1207 void Track::change_modules(int old_location, int new_location, int do_swap)
1209         for(int i = 0; i < plugin_set.total; i++)
1210         {
1211                 for(Plugin *plugin = (Plugin*)plugin_set.values[i]->first; 
1212                         plugin; 
1213                         plugin = (Plugin*)plugin->next)
1214                 {
1215                         if(plugin->plugin_type == PLUGIN_SHAREDPLUGIN ||
1216                                 plugin->plugin_type == PLUGIN_SHAREDMODULE)
1217                         {
1218                                 if(plugin->shared_location.module == old_location)
1219                                         plugin->shared_location.module = new_location;
1220                                 else
1221                                 if(do_swap && plugin->shared_location.module == new_location)
1222                                         plugin->shared_location.module = old_location;
1223                         }
1224                 }
1225         }
1229 int Track::delete_module_pointers(int deleted_track)
1231         for(int i = 0; i < plugin_set.total; i++)
1232         {
1233                 for(Plugin *plugin = (Plugin*)plugin_set.values[i]->first; 
1234                         plugin; 
1235                         plugin = (Plugin*)plugin->next)
1236                 {
1237                         if(plugin->plugin_type == PLUGIN_SHAREDPLUGIN ||
1238                                 plugin->plugin_type == PLUGIN_SHAREDMODULE)
1239                         {
1240                                 if(plugin->shared_location.module == deleted_track)
1241                                 {
1242                                         plugin->on = 0;
1243                                 }
1244                                 else
1245                                 {
1246                                         plugin->shared_location.module--;
1247                                 }
1248                         }
1249                 }
1250         }
1252         return 0;
1255 int Track::playable_edit(int64_t position, int direction)
1257         int result = 0;
1258         if(direction == PLAY_REVERSE) position--;
1259         for(Edit *current = edits->first; current && !result; current = NEXT)
1260         {
1261                 if(current->startproject <= position && 
1262                         current->startproject + current->length > position)
1263                 {
1264 //printf("Track::playable_edit %p %p\n", current->transition, current->asset);
1265                         if(current->transition || current->asset) result = 1;
1266                 }
1267         }
1268         return result;
1272 int Track::need_edit(Edit *current, int test_transitions)
1274         return ((test_transitions && current->transition) ||
1275                 (!test_transitions && current->asset));
1278 int64_t Track::plugin_change_duration(int64_t input_position,
1279         int64_t input_length,
1280         int reverse,
1281         int use_nudge)
1283         if(use_nudge) input_position += nudge;
1284         for(int i = 0; i < plugin_set.total; i++)
1285         {
1286                 int64_t new_duration = plugin_set.values[i]->plugin_change_duration(
1287                         input_position, 
1288                         input_length, 
1289                         reverse);
1290                 if(new_duration < input_length) input_length = new_duration;
1291         }
1292         return input_length;
1295 int64_t Track::edit_change_duration(int64_t input_position, 
1296         int64_t input_length, 
1297         int reverse, 
1298         int test_transitions,
1299         int use_nudge)
1301         Edit *current;
1302         int64_t edit_length = input_length;
1303         if(use_nudge) input_position += nudge;
1305         if(reverse)
1306         {
1307 // ================================= Reverse playback
1308 // Get first edit on or after position
1309                 for(current = edits->first; 
1310                         current && current->startproject + current->length <= input_position;
1311                         current = NEXT)
1312                         ;
1314                 if(current)
1315                 {
1316                         if(current->startproject > input_position)
1317                         {
1318 // Before first edit
1319                                 ;
1320                         }
1321                         else
1322                         if(need_edit(current, test_transitions))
1323                         {
1324 // Over an edit of interest.
1325                                 if(input_position - current->startproject < input_length)
1326                                         edit_length = input_position - current->startproject + 1;
1327                         }
1328                         else
1329                         {
1330 // Over an edit that isn't of interest.
1331 // Search for next edit of interest.
1332                                 for(current = PREVIOUS ; 
1333                                         current && 
1334                                         current->startproject + current->length > input_position - input_length &&
1335                                         !need_edit(current, test_transitions);
1336                                         current = PREVIOUS)
1337                                         ;
1339                                         if(current && 
1340                                                 need_edit(current, test_transitions) &&
1341                                                 current->startproject + current->length > input_position - input_length)
1342                         edit_length = input_position - current->startproject - current->length + 1;
1343                         }
1344                 }
1345                 else
1346                 {
1347 // Not over an edit.  Try the last edit.
1348                         current = edits->last;
1349                         if(current && 
1350                                 ((test_transitions && current->transition) ||
1351                                 (!test_transitions && current->asset)))
1352                                 edit_length = input_position - edits->last->startproject - edits->last->length + 1;
1353                 }
1354         }
1355         else
1356         {
1357 // =================================== forward playback
1358 // Get first edit on or before position
1359                 for(current = edits->last; 
1360                         current && current->startproject > input_position;
1361                         current = PREVIOUS)
1362                         ;
1364                 if(current)
1365                 {
1366                         if(current->startproject + current->length <= input_position)
1367                         {
1368 // Beyond last edit.
1369                                 ;
1370                         }
1371                         else
1372                         if(need_edit(current, test_transitions))
1373                         {
1374 // Over an edit of interest.
1375 // Next edit is going to require a change.
1376                                 if(current->length + current->startproject - input_position < input_length)
1377                                         edit_length = current->startproject + current->length - input_position;
1378                         }
1379                         else
1380                         {
1381 // Over an edit that isn't of interest.
1382 // Search for next edit of interest.
1383                                 for(current = NEXT ; 
1384                                         current && 
1385                                         current->startproject < input_position + input_length &&
1386                                         !need_edit(current, test_transitions);
1387                                         current = NEXT)
1388                                         ;
1390                                         if(current && 
1391                                                 need_edit(current, test_transitions) &&
1392                                                 current->startproject < input_position + input_length) 
1393                                                 edit_length = current->startproject - input_position;
1394                         }
1395                 }
1396                 else
1397                 {
1398 // Not over an edit.  Try the first edit.
1399                         current = edits->first;
1400                         if(current && 
1401                                 ((test_transitions && current->transition) ||
1402                                 (!test_transitions && current->asset)))
1403                                 edit_length = edits->first->startproject - input_position;
1404                 }
1405         }
1407         if(edit_length < input_length)
1408                 return edit_length;
1409         else
1410                 return input_length;
1413 int Track::purge_asset(Asset *asset)
1415         return 0;
1418 int Track::asset_used(Asset *asset)
1420         Edit* current_edit;
1421         int result = 0;
1423         for(current_edit = edits->first; current_edit; current_edit = current_edit->next)
1424         {
1425                 if(current_edit->asset == asset)
1426                 {
1427                         result++;
1428                 }
1429         }
1430         return result;
1433 int Track::channel_is_playable(int64_t position, int direction, int *do_channel)
1435         return 1;
1439 int Track::plugin_used(int64_t position, int64_t direction)
1441 //printf("Track::plugin_used 1 %d\n", this->plugin_set.total);
1442         for(int i = 0; i < this->plugin_set.total; i++)
1443         {
1444                 Plugin *current_plugin = get_current_plugin(position, 
1445                         i, 
1446                         direction, 
1447                         0,
1448                         0);
1450 //printf("Track::plugin_used 2 %p\n", current_plugin);
1451                 if(current_plugin && 
1452                         (current_plugin->on && 
1453                         current_plugin->plugin_type != PLUGIN_NONE))
1454                 {
1455                         return 1;
1456                 }
1457         }
1458 //printf("Track::plugin_used 3 %p\n", current_plugin);
1459         return 0;
1462 // Audio is always rendered through VConsole
1463 int Track::direct_copy_possible(int64_t start, int direction, int use_nudge)
1465         return 1;
1468 int64_t Track::to_units(double position, int round)
1470         return (int64_t)position;
1473 double Track::to_doubleunits(double position)
1475         return position;
1478 double Track::from_units(int64_t position)
1480         return (double)position;