r602: Fix baver's code... don't insert timecode when show_tc is not set
[cinelerra_cv/mob.git] / cinelerra / track.C
blobd92e2fe767f9327c1c1f65331ea8c62b6b4009e4
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::detach_shared_effects(int module)
631 repeat:
632         for(int i = 0; i < plugin_set.total; i++)
633         {
634                 PluginSet *plugin_set = this->plugin_set.values[i];
635                 for(Plugin *dest = (Plugin*)plugin_set->first; 
636                         dest; 
637                         dest = (Plugin*)dest->next)
638                 {
639                         if ((dest->plugin_type == PLUGIN_SHAREDPLUGIN ||
640                                 dest->plugin_type == PLUGIN_SHAREDMODULE)
641                             &&
642                                 dest->shared_location.module == module)
643                         {
644                                 int64_t start = dest->startproject;
645                                 int64_t end = dest->startproject + dest->length;
647                                 plugin_set->clear(start, end);
648                                 plugin_set->paste_silence(start, end);
650 // Delete 0 length pluginsets   
651                                 plugin_set->optimize();
652                                 if(!plugin_set->length())  {
653                                         this->plugin_set.remove_object_number(i);
654                                         --i;
655                                 }
656                         }
657                 }
658         }
661 void Track::resample(double old_rate, double new_rate)
663         edits->resample(old_rate, new_rate);
664         automation->resample(old_rate, new_rate);
665         for(int i = 0; i < plugin_set.total; i++)
666                 plugin_set.values[i]->resample(old_rate, new_rate);
667         nudge = (int64_t)(nudge * new_rate / old_rate);
672 void Track::optimize()
674         edits->optimize();
675         for(int i = 0; i < plugin_set.total; i++)
676         {
677                 plugin_set.values[i]->optimize();
678 //printf("Track::optimize %d\n", plugin_set.values[i]->total());
679                 if(plugin_set.values[i]->total() <= 0)
680                 {
681                         remove_pluginset(plugin_set.values[i]);
682                         i--;
683                 }
684         }
687 Plugin* Track::get_current_plugin(double position, 
688         int plugin_set, 
689         int direction, 
690         int convert_units,
691         int use_nudge)
693         Plugin *current;
694         if(convert_units) position = to_units(position, 0);
695         if(use_nudge) position += nudge;
696         
697         if(plugin_set >= this->plugin_set.total || plugin_set < 0) return 0;
699 //printf("Track::get_current_plugin 1 %d %d %d\n", position, this->plugin_set.total, direction);
700         if(direction == PLAY_FORWARD)
701         {
702                 for(current = (Plugin*)this->plugin_set.values[plugin_set]->last; 
703                         current; 
704                         current = (Plugin*)PREVIOUS)
705                 {
706 // printf("Track::get_current_plugin 2 %d %ld %ld\n", 
707 // current->startproject, 
708 // current->startproject + current->length, 
709 // position);
710                         if(current->startproject <= position && 
711                                 current->startproject + current->length > position)
712                         {
713                                 return current;
714                         }
715                 }
716         }
717         else
718         if(direction == PLAY_REVERSE)
719         {
720                 for(current = (Plugin*)this->plugin_set.values[plugin_set]->first; 
721                         current; 
722                         current = (Plugin*)NEXT)
723                 {
724                         if(current->startproject < position && 
725                                 current->startproject + current->length >= position)
726                         {
727                                 return current;
728                         }
729                 }
730         }
732         return 0;
735 Plugin* Track::get_current_transition(double position, 
736         int direction, 
737         int convert_units,
738         int use_nudge)
740         Edit *current;
741         Plugin *result = 0;
742         if(convert_units) position = to_units(position, 0);
743         if(use_nudge) position += nudge;
745         if(direction == PLAY_FORWARD)
746         {
747                 for(current = edits->last; current; current = PREVIOUS)
748                 {
749                         if(current->startproject <= position && current->startproject + current->length > position)
750                         {
751 //printf("Track::get_current_transition %p\n", current->transition);
752                                 if(current->transition && position < current->startproject + current->transition->length)
753                                 {
754                                         result = current->transition;
755                                         break;
756                                 }
757                         }
758                 }
759         }
760         else
761         if(direction == PLAY_REVERSE)
762         {
763                 for(current = edits->first; current; current = NEXT)
764                 {
765                         if(current->startproject < position && current->startproject + current->length >= position)
766                         {
767                                 if(current->transition && position <= current->startproject + current->transition->length)
768                                 {
769                                         result = current->transition;
770                                         break;
771                                 }
772                         }
773                 }
774         }
776         return result;
779 void Track::synchronize_params(Track *track)
781         for(Edit *this_edit = edits->first, *that_edit = track->edits->first;
782                 this_edit && that_edit;
783                 this_edit = this_edit->next, that_edit = that_edit->next)
784         {
785                 this_edit->synchronize_params(that_edit);
786         }
788         for(int i = 0; i < plugin_set.total && i < track->plugin_set.total; i++)
789                 plugin_set.values[i]->synchronize_params(track->plugin_set.values[i]);
791         automation->copy_from(track->automation);
792         this->nudge = track->nudge;
799 int Track::dump()
801         printf("   Data type %d\n", data_type);
802         printf("   Title %s\n", title);
803         printf("   Edits:\n");
804         for(Edit* current = edits->first; current; current = NEXT)
805         {
806                 current->dump();
807         }
808         automation->dump();
809         printf("   Plugin Sets: %d\n", plugin_set.total);
811         for(int i = 0; i < plugin_set.total; i++)
812                 plugin_set.values[i]->dump();
813 //printf("Track::dump 2\n");
814         return 0;
837 Track::Track() : ListItem<Track>()
839         y_pixel = 0;
842 // ======================================== accounting
844 int Track::number_of() 
846         return tracks->number_of(this); 
853         
854         
861 // ================================================= editing
863 int Track::select_auto(AutoConf *auto_conf, int cursor_x, int cursor_y)
865         return 0;
868 int Track::move_auto(AutoConf *auto_conf, int cursor_x, int cursor_y, int shift_down)
870         return 0;
873 int Track::release_auto()
875         return 0;
878 // used for copying automation alone
879 int Track::copy_automation(double selectionstart, 
880         double selectionend, 
881         FileXML *file,
882         int default_only,
883         int autos_only)
885         int64_t start = to_units(selectionstart, 0);
886         int64_t end = to_units(selectionend, 0);
888         file->tag.set_title("TRACK");
889 // Video or audio
890     save_header(file);
891         file->append_tag();
892         file->append_newline();
894         automation->copy(start, end, file, default_only, autos_only);
896         if(edl->session->auto_conf->plugins)
897         {
898                 file->tag.set_title("PLUGINSETS");
899                 file->append_tag();
900                 file->append_newline();
901                 for(int i = 0; i < plugin_set.total; i++)
902                 {
903                 
904                         plugin_set.values[i]->copy_keyframes(start, 
905                                 end, 
906                                 file, 
907                                 default_only,
908                                 autos_only);
909                 }
910                 file->tag.set_title("/PLUGINSETS");
911                 file->append_tag();
912                 file->append_newline();
913         }
915         file->tag.set_title("/TRACK");
916         file->append_tag();
917         file->append_newline();
918         file->append_newline();
919         file->append_newline();
920         file->append_newline();
922         return 0;
925 int Track::paste_automation(double selectionstart, 
926         double total_length, 
927         double frame_rate,
928         int64_t sample_rate,
929         FileXML *file,
930         int default_only)
932 // Only used for pasting automation alone.
933         int64_t start;
934         int64_t length;
935         int result;
936         double scale;
938         if(data_type == TRACK_AUDIO)
939                 scale = edl->session->sample_rate / sample_rate;
940         else
941                 scale = edl->session->frame_rate / frame_rate;
943         total_length *= scale;
944         start = to_units(selectionstart, 0);
945         length = to_units(total_length, 0);
946         result = 0;
947 //printf("Track::paste_automation 1\n");
949         while(!result)
950         {
951                 result = file->read_tag();
953                 if(!result)
954                 {
955                         if(file->tag.title_is("/TRACK"))
956                                 result = 1;
957                         else
958                         if(strstr(file->tag.get_title(), "AUTOS"))
959                         {
960                                 automation->paste(start, 
961                                         length, 
962                                         scale,
963                                         file,
964                                         default_only,
965                                         0);
966                         }
967                         else
968                         if(file->tag.title_is("PLUGINSETS"))
969                         {
970 //printf("Track::paste_automation 2 %d\n", current_pluginset);
971                                 PluginSet::paste_keyframes(start, 
972                                         length, 
973                                         file,
974                                         default_only,
975                                         this);
976                         }
977                 }
978         }
979 //printf("Track::paste_automation 3\n");
980         
982         return 0;
985 void Track::clear_automation(double selectionstart, 
986         double selectionend, 
987         int shift_autos,
988         int default_only)
990         int64_t start = to_units(selectionstart, 0);
991         int64_t end = to_units(selectionend, 0);
993         automation->clear(start, end, edl->session->auto_conf, 0);
995         if(edl->session->auto_conf->plugins)
996         {
997                 for(int i = 0; i < plugin_set.total; i++)
998                 {
999                         plugin_set.values[i]->clear_keyframes(start, end);
1000                 }
1001         }
1006 int Track::copy(double start, 
1007         double end, 
1008         FileXML *file, 
1009         char *output_path)
1011 // Use a copy of the selection in converted units
1012 // So copy_automation doesn't reconvert.
1013         int64_t start_unit = to_units(start, 0);
1014         int64_t end_unit = to_units(end, 1);
1019         file->tag.set_title("TRACK");
1020         file->tag.set_property("RECORD", record);
1021         file->tag.set_property("NUDGE", nudge);
1022         file->tag.set_property("PLAY", play);
1023         file->tag.set_property("GANG", gang);
1024         file->tag.set_property("DRAW", draw);
1025         file->tag.set_property("EXPAND", expand_view);
1026         file->tag.set_property("TRACK_W", track_w);
1027         file->tag.set_property("TRACK_H", track_h);
1028         save_header(file);
1029         file->append_tag();
1030         file->append_newline();
1031         save_derived(file);
1033         file->tag.set_title("TITLE");
1034         file->append_tag();
1035         file->append_text(title);
1036         file->tag.set_title("/TITLE");
1037         file->append_tag();
1038         file->append_newline();
1042         edits->copy(start_unit, end_unit, file, output_path);
1044         AutoConf auto_conf;
1045         auto_conf.set_all();
1046         automation->copy(start_unit, end_unit, file, 0, 0);
1049         for(int i = 0; i < plugin_set.total; i++)
1050         {
1051                 plugin_set.values[i]->copy(start_unit, end_unit, file);
1052         }
1054         copy_derived(start_unit, end_unit, file);
1056         file->tag.set_title("/TRACK");
1057         file->append_tag();
1058         file->append_newline();
1059         file->append_newline();
1060         file->append_newline();
1061         file->append_newline();
1063         return 0;
1066 int Track::copy_assets(double start, 
1067         double end, 
1068         ArrayList<Asset*> *asset_list)
1070         int i, result = 0;
1072         start = to_units(start, 0);
1073         end = to_units(end, 0);
1075         Edit *current = edits->editof((int64_t)start, PLAY_FORWARD, 0);
1077 // Search all edits
1078         while(current && current->startproject < end)
1079         {
1080 // Check for duplicate assets
1081                 if(current->asset)
1082                 {
1083                         for(i = 0, result = 0; i < asset_list->total; i++)
1084                         {
1085                                 if(asset_list->values[i] == current->asset) result = 1;
1086                         }
1087 // append pointer to new asset
1088                         if(!result) asset_list->append(current->asset);
1089                 }
1091                 current = NEXT;
1092         }
1094         return 0;
1101 int Track::clear(double start, 
1102         double end, 
1103         int edit_edits,
1104         int edit_labels,
1105         int edit_plugins,
1106         int convert_units,
1107         Edits *trim_edits)
1109 // Edits::move_auto calls this routine after the units are converted to the track
1110 // format.
1111 //printf("Track::clear 1 %d %d %d\n", edit_edits, edit_labels, edit_plugins);
1112         if(convert_units)
1113         {
1114                 start = to_units(start, 0);
1115                 end = to_units(end, 0);
1116         }
1118         if(edit_edits)
1119                 automation->clear((int64_t)start, (int64_t)end, 0, 1);
1121         if(edit_plugins)
1122                 for(int i = 0; i < plugin_set.total; i++)
1123                 {
1124                         if(!trim_edits || trim_edits == (Edits*)plugin_set.values[i])
1125                                 plugin_set.values[i]->clear((int64_t)start, (int64_t)end);
1126                 }
1128         if(edit_edits)
1129                 edits->clear((int64_t)start, (int64_t)end);
1130         return 0;
1133 int Track::clear_handle(double start, 
1134         double end, 
1135         int clear_labels,
1136         int clear_plugins, 
1137         double &distance)
1139         edits->clear_handle(start, end, clear_plugins, distance);
1142 int Track::popup_transition(int cursor_x, int cursor_y)
1144         return 0;
1149 int Track::modify_edithandles(double oldposition, 
1150         double newposition, 
1151         int currentend, 
1152         int handle_mode,
1153         int edit_labels,
1154         int edit_plugins)
1156         edits->modify_handles(oldposition, 
1157                 newposition, 
1158                 currentend,
1159                 handle_mode,
1160                 1,
1161                 edit_labels,
1162                 edit_plugins,
1163                 0);
1166         return 0;
1169 int Track::modify_pluginhandles(double oldposition, 
1170         double newposition, 
1171         int currentend, 
1172         int handle_mode,
1173         int edit_labels,
1174         Edits *trim_edits)
1176         for(int i = 0; i < plugin_set.total; i++)
1177         {
1178                 if(!trim_edits || trim_edits == (Edits*)plugin_set.values[i])
1179                         plugin_set.values[i]->modify_handles(oldposition, 
1180                                 newposition, 
1181                                 currentend, 
1182                                 handle_mode,
1183 // Don't allow plugin tweeks to affect edits.
1184                                 0,
1185                                 edit_labels,
1186                                 1,
1187                                 trim_edits);
1188         }
1189         return 0;
1193 int Track::paste_silence(double start, double end, int edit_plugins)
1195         start = to_units(start, 0);
1196         end = to_units(end, 1);
1198         edits->paste_silence((int64_t)start, (int64_t)end);
1199         shift_keyframes(start, end - start, 0);
1200         if(edit_plugins) shift_effects(start, end - start, 0);
1202         edits->optimize();
1203         return 0;
1206 int Track::select_edit(int cursor_x, 
1207         int cursor_y, 
1208         double &new_start, 
1209         double &new_end)
1211         return 0;
1214 int Track::scale_time(float rate_scale, int scale_edits, int scale_autos, int64_t start, int64_t end)
1216         return 0;
1219 void Track::change_plugins(SharedLocation &old_location, SharedLocation &new_location, int do_swap)
1221         for(int i = 0; i < plugin_set.total; i++)
1222         {
1223                 for(Plugin *plugin = (Plugin*)plugin_set.values[i]->first; 
1224                         plugin; 
1225                         plugin = (Plugin*)plugin->next)
1226                 {
1227                         if(plugin->plugin_type == PLUGIN_SHAREDPLUGIN)
1228                         {
1229                                 if(plugin->shared_location == old_location)
1230                                         plugin->shared_location = new_location;
1231                                 else
1232                                 if(do_swap && plugin->shared_location == new_location)
1233                                         plugin->shared_location = old_location;
1234                         }
1235                 }
1236         }
1239 void Track::change_modules(int old_location, int new_location, int do_swap)
1241         for(int i = 0; i < plugin_set.total; i++)
1242         {
1243                 for(Plugin *plugin = (Plugin*)plugin_set.values[i]->first; 
1244                         plugin; 
1245                         plugin = (Plugin*)plugin->next)
1246                 {
1247                         if(plugin->plugin_type == PLUGIN_SHAREDPLUGIN ||
1248                                 plugin->plugin_type == PLUGIN_SHAREDMODULE)
1249                         {
1250                                 if(plugin->shared_location.module == old_location)
1251                                         plugin->shared_location.module = new_location;
1252                                 else
1253                                 if(do_swap && plugin->shared_location.module == new_location)
1254                                         plugin->shared_location.module = old_location;
1255                         }
1256                 }
1257         }
1261 int Track::playable_edit(int64_t position, int direction)
1263         int result = 0;
1264         if(direction == PLAY_REVERSE) position--;
1265         for(Edit *current = edits->first; current && !result; current = NEXT)
1266         {
1267                 if(current->startproject <= position && 
1268                         current->startproject + current->length > position)
1269                 {
1270 //printf("Track::playable_edit %p %p\n", current->transition, current->asset);
1271                         if(current->transition || current->asset) result = 1;
1272                 }
1273         }
1274         return result;
1278 int Track::need_edit(Edit *current, int test_transitions)
1280         return ((test_transitions && current->transition) ||
1281                 (!test_transitions && current->asset));
1284 int64_t Track::plugin_change_duration(int64_t input_position,
1285         int64_t input_length,
1286         int reverse,
1287         int use_nudge)
1289         if(use_nudge) input_position += nudge;
1290         for(int i = 0; i < plugin_set.total; i++)
1291         {
1292                 int64_t new_duration = plugin_set.values[i]->plugin_change_duration(
1293                         input_position, 
1294                         input_length, 
1295                         reverse);
1296                 if(new_duration < input_length) input_length = new_duration;
1297         }
1298         return input_length;
1301 int64_t Track::edit_change_duration(int64_t input_position, 
1302         int64_t input_length, 
1303         int reverse, 
1304         int test_transitions,
1305         int use_nudge)
1307         Edit *current;
1308         int64_t edit_length = input_length;
1309         if(use_nudge) input_position += nudge;
1311         if(reverse)
1312         {
1313 // ================================= Reverse playback
1314 // Get first edit on or after position
1315                 for(current = edits->first; 
1316                         current && current->startproject + current->length <= input_position;
1317                         current = NEXT)
1318                         ;
1320                 if(current)
1321                 {
1322                         if(current->startproject > input_position)
1323                         {
1324 // Before first edit
1325                                 ;
1326                         }
1327                         else
1328                         if(need_edit(current, test_transitions))
1329                         {
1330 // Over an edit of interest.
1331                                 if(input_position - current->startproject < input_length)
1332                                         edit_length = input_position - current->startproject + 1;
1333                         }
1334                         else
1335                         {
1336 // Over an edit that isn't of interest.
1337 // Search for next edit of interest.
1338                                 for(current = PREVIOUS ; 
1339                                         current && 
1340                                         current->startproject + current->length > input_position - input_length &&
1341                                         !need_edit(current, test_transitions);
1342                                         current = PREVIOUS)
1343                                         ;
1345                                         if(current && 
1346                                                 need_edit(current, test_transitions) &&
1347                                                 current->startproject + current->length > input_position - input_length)
1348                         edit_length = input_position - current->startproject - current->length + 1;
1349                         }
1350                 }
1351                 else
1352                 {
1353 // Not over an edit.  Try the last edit.
1354                         current = edits->last;
1355                         if(current && 
1356                                 ((test_transitions && current->transition) ||
1357                                 (!test_transitions && current->asset)))
1358                                 edit_length = input_position - edits->last->startproject - edits->last->length + 1;
1359                 }
1360         }
1361         else
1362         {
1363 // =================================== forward playback
1364 // Get first edit on or before position
1365                 for(current = edits->last; 
1366                         current && current->startproject > input_position;
1367                         current = PREVIOUS)
1368                         ;
1370                 if(current)
1371                 {
1372                         if(current->startproject + current->length <= input_position)
1373                         {
1374 // Beyond last edit.
1375                                 ;
1376                         }
1377                         else
1378                         if(need_edit(current, test_transitions))
1379                         {
1380 // Over an edit of interest.
1381 // Next edit is going to require a change.
1382                                 if(current->length + current->startproject - input_position < input_length)
1383                                         edit_length = current->startproject + current->length - input_position;
1384                         }
1385                         else
1386                         {
1387 // Over an edit that isn't of interest.
1388 // Search for next edit of interest.
1389                                 for(current = NEXT ; 
1390                                         current && 
1391                                         current->startproject < input_position + input_length &&
1392                                         !need_edit(current, test_transitions);
1393                                         current = NEXT)
1394                                         ;
1396                                         if(current && 
1397                                                 need_edit(current, test_transitions) &&
1398                                                 current->startproject < input_position + input_length) 
1399                                                 edit_length = current->startproject - input_position;
1400                         }
1401                 }
1402                 else
1403                 {
1404 // Not over an edit.  Try the first edit.
1405                         current = edits->first;
1406                         if(current && 
1407                                 ((test_transitions && current->transition) ||
1408                                 (!test_transitions && current->asset)))
1409                                 edit_length = edits->first->startproject - input_position;
1410                 }
1411         }
1413         if(edit_length < input_length)
1414                 return edit_length;
1415         else
1416                 return input_length;
1419 int Track::purge_asset(Asset *asset)
1421         return 0;
1424 int Track::asset_used(Asset *asset)
1426         Edit* current_edit;
1427         int result = 0;
1429         for(current_edit = edits->first; current_edit; current_edit = current_edit->next)
1430         {
1431                 if(current_edit->asset == asset)
1432                 {
1433                         result++;
1434                 }
1435         }
1436         return result;
1439 int Track::channel_is_playable(int64_t position, int direction, int *do_channel)
1441         return 1;
1445 int Track::plugin_used(int64_t position, int64_t direction)
1447 //printf("Track::plugin_used 1 %d\n", this->plugin_set.total);
1448         for(int i = 0; i < this->plugin_set.total; i++)
1449         {
1450                 Plugin *current_plugin = get_current_plugin(position, 
1451                         i, 
1452                         direction, 
1453                         0,
1454                         0);
1456 //printf("Track::plugin_used 2 %p\n", current_plugin);
1457                 if(current_plugin && 
1458                         (current_plugin->on && 
1459                         current_plugin->plugin_type != PLUGIN_NONE))
1460                 {
1461                         return 1;
1462                 }
1463         }
1464 //printf("Track::plugin_used 3 %p\n", current_plugin);
1465         return 0;
1468 // Audio is always rendered through VConsole
1469 int Track::direct_copy_possible(int64_t start, int direction, int use_nudge)
1471         return 1;
1474 int64_t Track::to_units(double position, int round)
1476         return (int64_t)position;
1479 double Track::to_doubleunits(double position)
1481         return position;
1484 double Track::from_units(int64_t position)
1486         return (double)position;