9e86481c8df919e4d01f441b2a60ce8ff292368f
[goodguy/cinelerra.git] / cinelerra-5.1 / cinelerra / track.C
1 /*
2  * CINELERRA
3  * Copyright (C) 2010 Adam Williams <broadcast at earthling dot net>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  *
19  */
20
21 #include "asset.h"
22 #include "autoconf.h"
23 #include "automation.h"
24 #include "bcsignals.h"
25 #include "clip.h"
26 #include "edit.h"
27 #include "edits.h"
28 #include "edl.h"
29 #include "edlsession.h"
30 #include "filexml.h"
31 #include "floatauto.h"
32 #include "floatautos.h"
33 #include "keyframe.h"
34 #include "labels.h"
35 #include "localsession.h"
36 #include "maskauto.h"
37 #include "module.h"
38 #include "patch.h"
39 #include "patchbay.h"
40 #include "plugin.h"
41 #include "pluginset.h"
42 #include "mainsession.h"
43 #include "theme.h"
44 #include "intautos.h"
45 #include "track.h"
46 #include "trackcanvas.h"
47 #include "tracks.h"
48 #include "transition.h"
49 #include "transportque.inc"
50 #include "vedit.h"
51 #include "vframe.h"
52 #include <string.h>
53
54
55 Track::Track(EDL *edl, Tracks *tracks) : ListItem<Track>()
56 {
57         this->edl = edl;
58         this->tracks = tracks;
59         y_pixel = 0;
60         data_h = 64;
61         expand_view = 0;
62         draw = 1;
63         ganged = 1;
64         master = 0;
65         title[0] = 0;
66         armed = 1;
67         play = 1;
68         nudge = 0;
69         track_w = edl->session->output_w;
70         track_h = edl->session->output_h;
71         id = EDL::next_id();
72         mixer_id = -1;
73         masks = (1<<SUBMASKS)-1;
74 }
75
76 Track::~Track()
77 {
78         delete automation;
79         delete edits;
80         plugin_set.remove_all_objects();
81 }
82
83 void Track::create_objects()
84 {
85 }
86
87
88 int Track::copy_settings(Track *track)
89 {
90         this->expand_view = track->expand_view;
91         this->draw = track->draw;
92         this->ganged = track->ganged;
93         this->master = track->master;
94         this->armed = track->armed;
95         this->nudge = track->nudge;
96         this->mixer_id = track->mixer_id;
97         this->play = track->play;
98         this->data_h = track->data_h;
99         this->track_w = track->track_w;
100         this->track_h = track->track_h;
101         this->masks = track->masks;
102         strcpy(this->title, track->title);
103         return 0;
104 }
105
106 int Track::get_id()
107 {
108         return id;
109 }
110
111
112 int Track::load_defaults(BC_Hash *defaults)
113 {
114         return 0;
115 }
116
117 void Track::equivalent_output(Track *track, double *result)
118 {
119         if(data_type != track->data_type ||
120                 track_w != track->track_w ||
121                 track_h != track->track_h ||
122                 play != track->play ||
123                 nudge != track->nudge)
124                 *result = 0;
125
126 // Convert result to track units
127         int64_t result2 = -1;
128         automation->equivalent_output(track->automation, &result2);
129         edits->equivalent_output(track->edits, &result2);
130
131         int plugin_sets = MIN(plugin_set.total, track->plugin_set.total);
132 // Test existing plugin sets
133         for(int i = 0; i < plugin_sets; i++)
134         {
135                 plugin_set.values[i]->equivalent_output(
136                         track->plugin_set.values[i],
137                         &result2);
138         }
139
140 // New EDL has more plugin sets.  Get starting plugin in new plugin sets
141         for(int i = plugin_sets; i < plugin_set.total; i++)
142         {
143                 Plugin *current = plugin_set.values[i]->get_first_plugin();
144                 if(current)
145                 {
146                         if(result2 < 0 || current->startproject < result2)
147                                 result2 = current->startproject;
148                 }
149         }
150
151 // New EDL has fewer plugin sets.  Get starting plugin in old plugin set
152         for(int i = plugin_sets; i < track->plugin_set.total; i++)
153         {
154                 Plugin *current = track->plugin_set.values[i]->get_first_plugin();
155                 if(current)
156                 {
157                         if(result2 < 0 || current->startproject < result2)
158                                 result2 = current->startproject;
159                 }
160         }
161
162 // Number of plugin sets differs but somehow we didn't find the start of the
163 // change.  Assume 0
164         if(track->plugin_set.total != plugin_set.total && result2 < 0)
165                 result2 = 0;
166
167         if(result2 >= 0 &&
168                 (*result < 0 || from_units(result2) < *result))
169                 *result = from_units(result2);
170 }
171
172
173 int Track::is_synthesis(int64_t position, int direction, int depth)
174 {
175         int result = 0;
176         for( int i = 0; !result && i<plugin_set.total; ++i ) {
177                 Plugin *plugin = get_current_plugin(position, i, direction, 0, 0);
178                 if( !plugin ) continue;
179 // Assume data from a shared track is synthesized
180                 result = plugin->plugin_type == PLUGIN_SHAREDMODULE ? 1 :
181                         plugin->is_synthesis(position, direction, depth);
182         }
183         return result;
184 }
185
186 void Track::copy_from(Track *track)
187 {
188         copy_settings(track);
189         edits->copy_from(track->edits);
190         this->plugin_set.remove_all_objects();
191
192         for( int i=0; i<track->plugin_set.total; ++i ) {
193                 PluginSet *new_plugin_set = plugin_set.append(new PluginSet(edl, this));
194                 new_plugin_set->copy_from(track->plugin_set.values[i]);
195         }
196         automation->copy_from(track->automation);
197         this->track_w = track->track_w;
198         this->track_h = track->track_h;
199 }
200
201 Track& Track::operator=(Track& track)
202 {
203 printf("Track::operator= 1\n");
204         copy_from(&track);
205         return *this;
206 }
207
208 int Track::vertical_span(Theme *theme)
209 {
210         int result = 0;
211         if( show_titles() )
212                 result += theme->get_image("title_bg_data")->get_h();
213         if( show_assets() )
214                 result += data_h;
215         if( expand_view )
216                 result += plugin_set.total * theme->get_image("plugin_bg_data")->get_h();
217         result = MAX(result, theme->title_h);
218         return result;
219 }
220
221 double Track::get_length()
222 {
223         double total_length = 0;
224         double length = 0;
225
226 // Test edits
227         if(edits->last)
228         {
229                 length = from_units(edits->last->startproject + edits->last->length);
230                 if(length > total_length) total_length = length;
231         }
232
233 // Test plugins
234         for(int i = 0; i < plugin_set.total; i++)
235         {
236                 if( !plugin_set.values[i]->last ) continue;
237                 length = from_units(plugin_set.values[i]->last->startproject +
238                         plugin_set.values[i]->last->length);
239                 if(length > total_length) total_length = length;
240         }
241
242 // Test keyframes
243         length = from_units(automation->get_length());
244         if(length > total_length) total_length = length;
245
246
247         return total_length;
248 }
249
250 int Track::has_speed()
251 {
252         FloatAutos *autos = (FloatAutos*)automation->autos[AUTOMATION_SPEED];
253         if(autos)
254         {
255                 if(autos->first)
256                 {
257                         for(FloatAuto *current = (FloatAuto*)autos->first;
258                                 current;
259                                 current = (FloatAuto*)current->next)
260                         {
261                                 if(!EQUIV(current->get_value(), 1.0) ||
262                                         !EQUIV(current->get_control_in_value(), 0.0) ||
263                                         !EQUIV(current->get_control_out_value(), 0.0))
264                                 {
265                                         return 1;
266                                 }
267                         }
268                 }
269         }
270
271         return 0;
272 }
273
274 int Track::show_assets()
275 {
276         return expand_view || edl->session->show_assets ? 1 : 0;
277 }
278
279 int Track::show_titles()
280 {
281         return expand_view || edl->session->show_titles ? 1 : 0;
282 }
283
284 int Track::show_transitions()
285 {
286         return expand_view || edl->session->auto_conf->transitions ? 1 : 0;
287 }
288
289 void Track::get_source_dimensions(double position, int &w, int &h)
290 {
291         int64_t native_position = to_units(position, 0);
292         for(Edit *current = edits->first; current; current = NEXT)
293         {
294                 if(current->startproject <= native_position &&
295                         current->startproject + current->length > native_position &&
296                         current->asset)
297                 {
298                         w = current->asset->width;
299                         h = current->asset->height;
300                         return;
301                 }
302         }
303 }
304
305
306 int64_t Track::horizontal_span()
307 {
308         return (int64_t)(get_length() *
309                 edl->session->sample_rate /
310                 edl->local_session->zoom_sample +
311                 0.5);
312 }
313
314
315 int Track::load(FileXML *file, int track_offset, uint32_t load_flags)
316 {
317         int result = 0;
318         int current_plugin = 0;
319
320
321         armed = file->tag.get_property("RECORD", armed);
322         play = file->tag.get_property("PLAY", play);
323         ganged = file->tag.get_property("GANG", ganged);
324         master = file->tag.get_property("MASTER", 1);
325         draw = file->tag.get_property("DRAW", draw);
326         nudge = file->tag.get_property("NUDGE", nudge);
327         mixer_id = file->tag.get_property("MIXER_ID", mixer_id);
328         expand_view = file->tag.get_property("EXPAND", expand_view);
329         data_h = file->tag.get_property("DATA_H", data_h);
330         track_w = file->tag.get_property("TRACK_W", track_w);
331         track_h = file->tag.get_property("TRACK_H", track_h);
332         masks = file->tag.get_property("MASKS", masks);
333
334         load_header(file, load_flags);
335
336         do{
337                 result = file->read_tag();
338
339                 if(!result)
340                 {
341                         if(file->tag.title_is("/TRACK"))
342                         {
343                                 result = 1;
344                         }
345                         else
346                         if(file->tag.title_is("TITLE"))
347                         {
348                                 XMLBuffer data;
349                                 file->read_text_until("/TITLE", &data);
350                                 memset(title, 0, sizeof(title));
351                                 strncpy(title, data.cstr(), sizeof(title)-1);
352                         }
353                         else
354                         if(load_flags && automation->load(file)
355                         /* strstr(file->tag.get_title(), "AUTOS") */)
356                         {
357                                 ;
358                         }
359                         else
360                         if(file->tag.title_is("EDITS"))
361                         {
362                                 if(load_flags & LOAD_EDITS)
363                                         edits->load(file, track_offset);
364                                 else
365                                         result = file->skip_tag();
366                         }
367                         else
368                         if(file->tag.title_is("PLUGINSET"))
369                         {
370                                 if(load_flags & LOAD_EDITS)
371                                 {
372                                         PluginSet *plugin_set = new PluginSet(edl, this);
373                                         this->plugin_set.append(plugin_set);
374                                         plugin_set->load(file, load_flags);
375                                 }
376                                 else
377                                 if(load_flags & LOAD_AUTOMATION)
378                                 {
379                                         if(current_plugin < this->plugin_set.total)
380                                         {
381                                                 PluginSet *plugin_set = this->plugin_set.values[current_plugin];
382                                                 plugin_set->load(file, load_flags);
383                                                 current_plugin++;
384                                         }
385                                 }
386                                 else
387                                         result = file->skip_tag();
388                         }
389                         else
390                                 load_derived(file, load_flags);
391                 }
392         }while(!result);
393
394
395
396         return 0;
397 }
398
399 void Track::insert_asset(Asset *asset,
400         EDL *nested_edl,
401         double length,
402         double position,
403         int track_number)
404 {
405         edits->insert_asset(asset,
406                 nested_edl,
407                 to_units(length, 1),
408                 to_units(position, 0),
409                 track_number);
410 }
411
412 // Insert data
413
414 // Default keyframes: We don't replace default keyframes in pasting but
415 // when inserting the first EDL of a load operation we need to replace
416 // the default keyframes.
417
418 // Plugins:  This is an arbitrary behavior
419 //
420 // 1) No plugin in source track: Paste silence into destination
421 // plugin sets.
422 // 2) Plugin in source track: plugin in source track is inserted into
423 // existing destination track plugin sets, new sets being added when
424 // necessary.
425
426 void Track::insert_track(Track *track,
427         double position,
428         int replace_default,
429         int edit_plugins,
430         int edit_autos,
431         double edl_length)
432 {
433 // Calculate minimum length of data to pad.
434         int64_t min_length = to_units(
435                 MAX(edl_length, track->get_length()),
436                 1);
437 //printf("Track::insert_track %d %s %jd\n", __LINE__, title, min_length);
438
439 // Decide whether to copy settings based on load_mode
440         if(replace_default) copy_settings(track);
441
442         edits->insert_edits(track->edits,
443                 to_units(position, 0),
444                 min_length,
445                 edit_autos);
446
447         if(edit_plugins)
448                 insert_plugin_set(track,
449                         to_units(position, 0),
450                         min_length,
451                         edit_autos);
452
453         if(edit_autos)
454                 automation->insert_track(track->automation,
455                         to_units(position, 0),
456                         min_length,
457                         replace_default);
458
459         optimize();
460
461 }
462
463 // Called by insert_track
464 void Track::insert_plugin_set(Track *track,
465         int64_t position,
466         int64_t min_length,
467         int edit_autos)
468 {
469 // Extend plugins if no incoming plugins
470         if( track->plugin_set.total ) {
471                 for(int i = 0; i < track->plugin_set.total; i++) {
472                         if(i >= plugin_set.total)
473                                 plugin_set.append(new PluginSet(edl, this));
474
475                         plugin_set.values[i]->insert_edits(track->plugin_set.values[i],
476                                         position, min_length, edit_autos);
477                 }
478         }
479         else
480                 shift_effects(position, min_length, edit_autos, 0);
481 }
482
483 Plugin* Track::insert_effect(const char *title, SharedLocation *shared_location,
484                 KeyFrame *default_keyframe, PluginSet *plugin_set,
485                 double start, double length, int plugin_type)
486 {
487         if( !plugin_set ) {
488                 plugin_set = new PluginSet(edl, this);
489                 this->plugin_set.append(plugin_set);
490         }
491         Plugin *plugin = plugin_set->insert_plugin(title,
492                         to_units(start, 0), to_units(length, 1), plugin_type,
493                         shared_location, default_keyframe, 1);
494         expand_view = 1;
495         return plugin;
496 }
497
498 void Track::move_plugins_up(PluginSet *plugin_set)
499 {
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;
505
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;
509
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         }
518 }
519
520 void Track::move_plugins_down(PluginSet *plugin_set)
521 {
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;
527
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;
531
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         }
540 }
541
542
543 void Track::remove_asset(Indexable *asset)
544 {
545         for(Edit *edit = edits->first; edit; edit = edit->next)
546         {
547                 if(asset->is_asset &&
548                         edit->asset &&
549                         edit->asset == (Asset*)asset)
550                 {
551                         edit->asset = 0;
552                 }
553                 else
554                 if(!asset->is_asset &&
555                         edit->nested_edl &&
556                         edit->nested_edl == (EDL*)asset)
557                 {
558                         edit->nested_edl = 0;
559                 }
560         }
561         optimize();
562 }
563
564 void Track::remove_pluginset(PluginSet *plugin_set)
565 {
566         int i;
567         for(i = 0; i < this->plugin_set.total; i++)
568                 if(plugin_set == this->plugin_set.values[i]) break;
569
570         this->plugin_set.remove_object(plugin_set);
571         for( ++i ; i<=this->plugin_set.total; ++i ) {
572                 SharedLocation old_location, new_location;
573                 new_location.module = old_location.module = tracks->number_of(this);
574                 old_location.plugin = i;
575                 new_location.plugin = i - 1;
576                 tracks->change_plugins(old_location, new_location, 0);
577         }
578 }
579
580 void Track::shift_keyframes(int64_t position, int64_t length)
581 {
582         automation->paste_silence(position, position + length);
583 // Effect keyframes are shifted in shift_effects
584 }
585
586 void Track::shift_effects(int64_t position, int64_t length, int edit_autos, Edits *trim_edits)
587 {
588         for( int i=0; i<plugin_set.total; ++i ) {
589                 if( !trim_edits || trim_edits == (Edits*)plugin_set.values[i] )
590                         plugin_set.values[i]->shift_effects(position, length, edit_autos);
591         }
592 }
593
594 void Track::detach_effect(Plugin *plugin)
595 {
596 //printf("Track::detach_effect 1\n");
597         for( int i=0; i<plugin_set.size(); ++i ) {
598                 PluginSet *pluginset = plugin_set[i];
599                 Plugin *dest = (Plugin*)pluginset->first;
600                 while( dest && dest != plugin ) dest = (Plugin*)dest->next;
601                 if( !dest ) continue;
602                 tracks->detach_ganged_effects(plugin);
603                 int64_t start = plugin->startproject;
604                 int64_t end = start + plugin->length;
605                 pluginset->clear(start, end, 1);
606                 optimize();
607 //printf("Track::detach_effect 2 %d\n", plugin_set->length());
608 // Delete 0 length pluginsets
609                 return;
610         }
611 }
612
613 void Track::detach_shared_effects(int module)
614 {
615         for( int i=0; i<plugin_set.size(); ++i ) {
616                 PluginSet *pluginset = this->plugin_set[i];
617                 Plugin *dest = (Plugin*)pluginset->first;
618                 for( ; dest; dest=(Plugin*)dest->next ) {
619                         if( (dest->plugin_type != PLUGIN_SHAREDPLUGIN &&
620                              dest->plugin_type != PLUGIN_SHAREDMODULE) ) continue;
621                         if( dest->shared_location.module != module ) continue;
622                         int64_t start = dest->startproject;
623                         int64_t end = start + dest->length;
624                         pluginset->clear(start, end, 1);
625                 }
626         }
627         optimize();
628 }
629
630 void Track::detach_ganged_effects(Plugin *plugin)
631 {
632         for( int i=0; i<plugin_set.size(); ++i ) {
633                 PluginSet *pluginset = this->plugin_set[i];
634                 Plugin *dest = (Plugin*)pluginset->first;
635                 for( ; dest; dest=(Plugin*)dest->next ) {
636                         if( strcmp(dest->title, plugin->title) != 0 ) continue;
637                         if( dest->startproject != plugin->startproject ) continue;
638                         if( dest->length != plugin->length ) continue;
639                         int64_t start = dest->startproject;
640                         int64_t end = start + dest->length;
641                         pluginset->clear(start, end, 1);
642                 }
643         }
644         optimize();
645 }
646
647 void Track::resample(double old_rate, double new_rate)
648 {
649         edits->resample(old_rate, new_rate);
650         automation->resample(old_rate, new_rate);
651         for(int i = 0; i < plugin_set.total; i++)
652                 plugin_set.values[i]->resample(old_rate, new_rate);
653         nudge = (int64_t)(nudge * new_rate / old_rate);
654 }
655
656
657 void Track::optimize()
658 {
659         edits->optimize();
660         for(int i = 0; i < plugin_set.total; ) {
661                 PluginSet *plugin_set = this->plugin_set.values[i];
662                 plugin_set->optimize();
663 //printf("Track::optimize %d\n", plugin_set.values[i]->total());
664 // new definition of empty track...
665                 if( !plugin_set->last ||
666                     (plugin_set->last == plugin_set->first &&
667                      plugin_set->last->silence()) ) {
668                         remove_pluginset(plugin_set);
669                         continue;
670                 }
671                 ++i;
672         }
673 }
674
675 Plugin* Track::get_current_plugin(double position,
676         int plugin_set,
677         int direction,
678         int convert_units,
679         int use_nudge)
680 {
681         Plugin *current;
682         if(convert_units) position = to_units(position, 0);
683         if(use_nudge) position += nudge;
684
685         if(plugin_set >= this->plugin_set.total || plugin_set < 0) return 0;
686
687 //printf("Track::get_current_plugin 1 %d %d %d\n", position, this->plugin_set.total, direction);
688         if(direction == PLAY_FORWARD)
689         {
690                 for(current = (Plugin*)this->plugin_set.values[plugin_set]->last;
691                         current;
692                         current = (Plugin*)PREVIOUS)
693                 {
694 // printf("Track::get_current_plugin 2 %d %ld %ld\n",
695 // current->startproject,
696 // current->startproject + current->length,
697 // position);
698                         if(current->startproject <= position &&
699                                 current->startproject + current->length > position)
700                         {
701                                 return current;
702                         }
703                 }
704         }
705         else
706         if(direction == PLAY_REVERSE)
707         {
708                 for(current = (Plugin*)this->plugin_set.values[plugin_set]->first;
709                         current;
710                         current = (Plugin*)NEXT)
711                 {
712                         if(current->startproject < position &&
713                                 current->startproject + current->length >= position)
714                         {
715                                 return current;
716                         }
717                 }
718         }
719
720         return 0;
721 }
722
723 Plugin* Track::get_current_transition(double position,
724         int direction,
725         int convert_units,
726         int use_nudge)
727 {
728         Edit *current;
729         Plugin *result = 0;
730         if(convert_units) position = to_units(position, 0);
731         if(use_nudge) position += nudge;
732
733         if(direction == PLAY_FORWARD)
734         {
735                 for(current = edits->last; current; current = PREVIOUS)
736                 {
737                         if(current->startproject <= position && current->startproject + current->length > position)
738                         {
739 //printf("Track::get_current_transition %p\n", current->transition);
740                                 if(current->transition && position < current->startproject + current->transition->length)
741                                 {
742                                         result = current->transition;
743                                         break;
744                                 }
745                         }
746                 }
747         }
748         else
749         if(direction == PLAY_REVERSE)
750         {
751                 for(current = edits->first; current; current = NEXT)
752                 {
753                         if(current->startproject < position && current->startproject + current->length >= position)
754                         {
755                                 if(current->transition && position <= current->startproject + current->transition->length)
756                                 {
757                                         result = current->transition;
758                                         break;
759                                 }
760                         }
761                 }
762         }
763
764         return result;
765 }
766
767 void Track::synchronize_params(Track *track)
768 {
769         for(Edit *this_edit = edits->first, *that_edit = track->edits->first;
770                 this_edit && that_edit;
771                 this_edit = this_edit->next, that_edit = that_edit->next)
772         {
773                 this_edit->synchronize_params(that_edit);
774         }
775
776         for(int i = 0; i < plugin_set.total && i < track->plugin_set.total; i++)
777                 plugin_set.values[i]->synchronize_params(track->plugin_set.values[i]);
778
779         automation->copy_from(track->automation);
780         this->nudge = track->nudge;
781 }
782
783
784 int Track::dump(FILE *fp)
785 {
786         fprintf(fp,"   Title %s\n", title);
787         fprintf(fp,"   Data type %d, draw %d, gang %d, master %d, mixer_id %d\n"
788                    "      play %d, armed %d, nudge %jd, masks 0x%04x\n",
789                 data_type, draw, ganged, master, mixer_id, play, armed, nudge, masks);
790         fprintf(fp,"   Edits:\n");
791         for(Edit* current = edits->first; current; current = NEXT)
792                 current->dump(fp);
793         automation->dump(fp);
794         fprintf(fp,"   Plugin Sets: %d\n", plugin_set.total);
795
796         for( int i=0; i<plugin_set.total; ++i )
797                 plugin_set[i]->dump(fp);
798         return 0;
799 }
800
801 // ======================================== accounting
802
803 int Track::number_of()
804 {
805         return tracks->number_of(this);
806 }
807
808
809
810 // ================================================= editing
811
812 int Track::select_auto(AutoConf *auto_conf, int cursor_x, int cursor_y)
813 {
814         return 0;
815 }
816
817 int Track::move_auto(AutoConf *auto_conf, int cursor_x, int cursor_y, int shift_down)
818 {
819         return 0;
820 }
821
822 int Track::release_auto()
823 {
824         return 0;
825 }
826
827 // used for copying automation alone
828 int Track::copy_automation(double selectionstart,
829         double selectionend,
830         FileXML *file,
831         int default_only,
832         int active_only)
833 {
834         int64_t start = to_units(selectionstart, 0);
835         int64_t end = to_units(selectionend, 1);
836
837         file->tag.set_title("TRACK");
838 // Video or audio
839     save_header(file);
840         file->append_tag();
841         file->append_newline();
842
843         automation->copy(start, end, file, default_only, active_only);
844
845         if(edl->session->auto_conf->plugins)
846         {
847                 for(int i = 0; i < plugin_set.total; i++)
848                 {
849
850                         plugin_set.values[i]->copy_keyframes(start,
851                                 end,
852                                 file,
853                                 default_only,
854                                 active_only);
855                 }
856         }
857
858         file->tag.set_title("/TRACK");
859         file->append_tag();
860         file->append_newline();
861         file->append_newline();
862         file->append_newline();
863         file->append_newline();
864
865         return 0;
866 }
867
868 int Track::paste_automation(double selectionstart, double total_length,
869         double frame_rate, int64_t sample_rate,
870         FileXML *file, int default_only, int active_only)
871 {
872 // Only used for pasting automation alone.
873         double scale = data_type == TRACK_AUDIO ?
874                 edl->session->sample_rate / sample_rate :
875                 edl->session->frame_rate / frame_rate ;
876
877         total_length *= scale;
878         int64_t start = to_units(selectionstart, 0);
879         int64_t length = to_units(total_length, 1);
880         int result = 0;
881         int current_pluginset = 0;
882 //printf("Track::paste_automation 1\n");
883
884         while( !(result = file->read_tag()) ) {
885                 if( file->tag.title_is("/TRACK") ) break;
886                 if( automation->paste(start, length, scale, file,
887                                 default_only, active_only, 0) )
888                         continue;
889                 if( file->tag.title_is("PLUGINSET") ) {
890                         if( current_pluginset < plugin_set.total ) {
891                                 plugin_set.values[current_pluginset]->
892                                         paste_keyframes(start, length, file,
893                                                 default_only, active_only);
894                                 ++current_pluginset;
895                         }
896                 }
897         }
898
899         return 0;
900 }
901
902 void Track::clear_automation(double selectionstart,
903         double selectionend,
904         int shift_autos,
905         int default_only)
906 {
907         int64_t start = to_units(selectionstart, 0);
908         int64_t end = to_units(selectionend, 1);
909
910         automation->clear(start, end, edl->session->auto_conf, 0);
911
912         if(edl->session->auto_conf->plugins)
913         {
914                 for(int i = 0; i < plugin_set.total; i++)
915                 {
916                         plugin_set.values[i]->clear_keyframes(start, end);
917                 }
918         }
919
920 }
921
922 void Track::set_automation_mode(double selectionstart,
923         double selectionend,
924         int mode)
925 {
926         int64_t start = to_units(selectionstart, 0);
927         int64_t end = to_units(selectionend, 1);
928
929         automation->set_automation_mode(start, end, mode, edl->session->auto_conf);
930 }
931
932
933
934
935 int Track::copy(int copy_flags, double start, double end,
936                 FileXML *file, const char *output_path)
937 {
938 // Use a copy of the selection in converted units
939 // So copy_automation doesn't reconvert.
940         int64_t start_unit = to_units(start, 0);
941         int64_t end_unit = to_units(end, 1);
942
943
944
945
946         file->tag.set_title("TRACK");
947         file->tag.set_property("RECORD", armed);
948         file->tag.set_property("NUDGE", nudge);
949         file->tag.set_property("MIXER_ID", mixer_id);
950         file->tag.set_property("PLAY", play);
951         file->tag.set_property("GANG", ganged);
952         file->tag.set_property("MASTER", master);
953         file->tag.set_property("DRAW", draw);
954         file->tag.set_property("EXPAND", expand_view);
955         file->tag.set_property("DATA_H", data_h);
956         file->tag.set_property("TRACK_W", track_w);
957         file->tag.set_property("TRACK_H", track_h);
958         file->tag.set_property("MASKS", masks);
959         save_header(file);
960         file->append_tag();
961         file->append_newline();
962         save_derived(file);
963
964         file->tag.set_title("TITLE");
965         file->append_tag();
966         file->append_text(title);
967         file->tag.set_title("/TITLE");
968         file->append_tag();
969         file->append_newline();
970
971 //      if(data_type == TRACK_AUDIO)
972 //              file->tag.set_property("TYPE", "AUDIO");
973 //      else
974 //              file->tag.set_property("TYPE", "VIDEO");
975 //
976 //      file->append_tag();
977 //      file->append_newline();
978
979         if( (copy_flags & COPY_EDITS) )
980                 edits->copy(start_unit, end_unit, file, output_path);
981
982         if( (copy_flags & COPY_AUTOS) ) {
983                 AutoConf auto_conf;
984                 auto_conf.set_all(1);
985                 automation->copy(start_unit, end_unit, file, 0, 0);
986         }
987
988         if( (copy_flags & COPY_PLUGINS) ) {
989                 for( int i=0; i<plugin_set.total; ++i )
990                         plugin_set.values[i]->copy(start_unit, end_unit, file);
991         }
992
993         copy_derived(start_unit, end_unit, file);
994
995         file->tag.set_title("/TRACK");
996         file->append_tag();
997         file->append_newline();
998         file->append_newline();
999         file->append_newline();
1000         file->append_newline();
1001
1002         return 0;
1003 }
1004
1005 int Track::copy_assets(double start,
1006         double end,
1007         ArrayList<Asset*> *asset_list)
1008 {
1009         int i, result = 0;
1010
1011         start = to_units(start, 0);
1012         end = to_units(end, 1);
1013
1014         Edit *current = edits->editof((int64_t)start, PLAY_FORWARD, 0);
1015
1016 // Search all edits
1017         while(current && current->startproject < end)
1018         {
1019 // Check for duplicate assets
1020                 if(current->asset)
1021                 {
1022                         for(i = 0, result = 0; i < asset_list->total; i++)
1023                         {
1024                                 if(asset_list->values[i] == current->asset) result = 1;
1025                         }
1026 // append pointer to new asset
1027                         if(!result) asset_list->append(current->asset);
1028                 }
1029
1030                 current = NEXT;
1031         }
1032
1033         return 0;
1034 }
1035
1036 int Track::blade(double position)
1037 {
1038         int64_t start = to_units(position, 0);
1039         Edit *edit = edits->split_edit(start);
1040         if( !edit || edit->silence() ) return 1;
1041         edit->hard_left = 1;
1042         if( edit->previous ) edit->previous->hard_right = 1;
1043         return 0;
1044 }
1045
1046 int Track::clear(double start, double end,
1047         int edit_edits, int edit_labels, int edit_plugins,
1048         int edit_autos, Edits *trim_edits)
1049 {
1050         return clear(to_units(start, 0), to_units(end, 1),
1051                 edit_edits, edit_labels, edit_plugins, edit_autos, trim_edits);
1052 }
1053
1054 int Track::clear(int64_t start, int64_t end,
1055         int edit_edits, int edit_labels, int edit_plugins,
1056         int edit_autos, Edits *trim_edits)
1057 {
1058 //printf("Track::clear 1 %d %d %d\n", edit_edits, edit_labels, edit_plugins);
1059         if( edit_autos )
1060                 automation->clear(start, end, 0, 1);
1061         if( edit_plugins ) {
1062                 int edit_keyframes = edit_plugins < 0 ? 1 : edit_autos;
1063                 for(int i = 0; i < plugin_set.total; i++) {
1064                         if(!trim_edits || trim_edits == (Edits*)plugin_set.values[i])
1065                                 plugin_set.values[i]->clear(start, end, edit_keyframes);
1066                 }
1067         }
1068         if( edit_edits )
1069                 edits->clear(start, end);
1070         return 0;
1071 }
1072
1073 int Track::clear_handle(double start,
1074         double end,
1075         int clear_labels,
1076         int clear_plugins,
1077         int edit_autos,
1078         double &distance)
1079 {
1080         edits->clear_handle(start, end, clear_plugins, edit_autos, distance);
1081         return 0;
1082 }
1083
1084 int Track::popup_transition(int cursor_x, int cursor_y)
1085 {
1086         return 0;
1087 }
1088
1089
1090
1091 int Track::modify_edithandles(double oldposition, double newposition,
1092         int currentend, int handle_mode, int edit_labels,
1093         int edit_plugins, int edit_autos, int group_id)
1094 {
1095         edits->modify_handles(oldposition, newposition,
1096                 currentend, handle_mode, 1, edit_labels, edit_plugins,
1097                 edit_autos, 0, group_id);
1098         return 0;
1099 }
1100
1101 int Track::modify_pluginhandles(double oldposition,
1102         double newposition,
1103         int currentend,
1104         int handle_mode,
1105         int edit_labels,
1106         int edit_autos,
1107         Edits *trim_edits)
1108 {
1109         for(int i = 0; i < plugin_set.total; i++)
1110         {
1111                 if(!trim_edits || trim_edits == (Edits*)plugin_set.values[i])
1112                         plugin_set.values[i]->modify_handles(oldposition, newposition,
1113 // Don't allow plugin tweeks to affect edits.
1114                                 currentend, handle_mode, 0, 0, 0, 0, 0, 0);
1115         }
1116         return 0;
1117 }
1118
1119
1120 int Track::paste_silence(double start, double end, int edit_plugins, int edit_autos)
1121 {
1122         return paste_silence(to_units(start, 0), to_units(end, 1),
1123                         edit_plugins, edit_autos);
1124 }
1125
1126 int Track::paste_silence(int64_t start, int64_t end, int edit_plugins, int edit_autos)
1127 {
1128         edits->paste_silence(start, end);
1129         if( edit_autos )
1130                 shift_keyframes(start, end - start);
1131         if( edit_plugins )
1132                 shift_effects(start, end - start, edit_autos, 0);
1133         edits->optimize();
1134         return 0;
1135 }
1136
1137 int Track::select_edit(int cursor_x,
1138         int cursor_y,
1139         double &new_start,
1140         double &new_end)
1141 {
1142         return 0;
1143 }
1144
1145 int Track::scale_time(float rate_scale, int scale_edits, int scale_autos, int64_t start, int64_t end)
1146 {
1147         return 0;
1148 }
1149
1150 void Track::change_plugins(SharedLocation &old_location, SharedLocation &new_location, int do_swap)
1151 {
1152         for(int i = 0; i < plugin_set.total; i++)
1153         {
1154                 for(Plugin *plugin = (Plugin*)plugin_set.values[i]->first;
1155                         plugin;
1156                         plugin = (Plugin*)plugin->next)
1157                 {
1158                         if(plugin->plugin_type == PLUGIN_SHAREDPLUGIN)
1159                         {
1160                                 if(plugin->shared_location == old_location)
1161                                         plugin->shared_location = new_location;
1162                                 else
1163                                 if(do_swap && plugin->shared_location == new_location)
1164                                         plugin->shared_location = old_location;
1165                         }
1166                 }
1167         }
1168 }
1169
1170 void Track::change_modules(int old_location, int new_location, int do_swap)
1171 {
1172         for(int i = 0; i < plugin_set.total; i++)
1173         {
1174                 for(Plugin *plugin = (Plugin*)plugin_set.values[i]->first;
1175                         plugin;
1176                         plugin = (Plugin*)plugin->next)
1177                 {
1178                         if(plugin->plugin_type == PLUGIN_SHAREDPLUGIN ||
1179                                 plugin->plugin_type == PLUGIN_SHAREDMODULE)
1180                         {
1181                                 if(plugin->shared_location.module == old_location)
1182                                         plugin->shared_location.module = new_location;
1183                                 else
1184                                 if(do_swap && plugin->shared_location.module == new_location)
1185                                         plugin->shared_location.module = old_location;
1186                         }
1187                 }
1188         }
1189 }
1190
1191
1192 int Track::playable_edit(int64_t position, int direction)
1193 {
1194         int result = 0;
1195         if(direction == PLAY_REVERSE) position--;
1196         for(Edit *current = edits->first; current && !result; current = NEXT)
1197         {
1198                 if(current->startproject <= position &&
1199                         current->startproject + current->length > position)
1200                 {
1201 //printf("Track::playable_edit %p %p\n", current->transition, current->asset);
1202                         if(current->transition ||
1203                                 current->asset ||
1204                                 current->nested_edl) result = 1;
1205                 }
1206         }
1207         return result;
1208 }
1209
1210
1211 int Track::need_edit(Edit *current, int test_transitions)
1212 {
1213         return ((test_transitions && current->transition) ||
1214                 (!test_transitions && current->asset));
1215 }
1216
1217 int64_t Track::plugin_change_duration(int64_t input_position,
1218         int64_t input_length,
1219         int reverse,
1220         int use_nudge)
1221 {
1222         if(use_nudge) input_position += nudge;
1223         for(int i = 0; i < plugin_set.total; i++)
1224         {
1225                 int64_t new_duration = plugin_set.values[i]->plugin_change_duration(
1226                         input_position,
1227                         input_length,
1228                         reverse);
1229                 if(new_duration < input_length) input_length = new_duration;
1230         }
1231         return input_length;
1232 }
1233
1234 int64_t Track::edit_change_duration(int64_t input_position,
1235         int64_t input_length,
1236         int reverse,
1237         int test_transitions,
1238         int use_nudge)
1239 {
1240         Edit *current;
1241         int64_t edit_length = input_length;
1242         if(use_nudge) input_position += nudge;
1243
1244         if(reverse)
1245         {
1246 // ================================= Reverse playback
1247 // Get first edit on or after position
1248                 for(current = edits->first;
1249                         current && current->startproject + current->length <= input_position;
1250                         current = NEXT)
1251                         ;
1252
1253                 if(current)
1254                 {
1255                         if(current->startproject > input_position)
1256                         {
1257 // Before first edit
1258                                 ;
1259                         }
1260                         else
1261                         if(need_edit(current, test_transitions))
1262                         {
1263 // Over an edit of interest.
1264                                 if(input_position - current->startproject < input_length)
1265                                         edit_length = input_position - current->startproject + 1;
1266                         }
1267                         else
1268                         {
1269 // Over an edit that isn't of interest.
1270 // Search for next edit of interest.
1271                                 for(current = PREVIOUS ;
1272                                         current &&
1273                                         current->startproject + current->length > input_position - input_length &&
1274                                         !need_edit(current, test_transitions);
1275                                         current = PREVIOUS)
1276                                         ;
1277
1278                                         if(current &&
1279                                                 need_edit(current, test_transitions) &&
1280                                                 current->startproject + current->length > input_position - input_length)
1281                         edit_length = input_position - current->startproject - current->length + 1;
1282                         }
1283                 }
1284                 else
1285                 {
1286 // Not over an edit.  Try the last edit.
1287                         current = edits->last;
1288                         if(current &&
1289                                 ((test_transitions && current->transition) ||
1290                                 (!test_transitions && current->asset)))
1291                                 edit_length = input_position - edits->length() + 1;
1292                 }
1293         }
1294         else
1295         {
1296 // =================================== forward playback
1297 // Get first edit on or before position
1298                 for(current = edits->last;
1299                         current && current->startproject > input_position;
1300                         current = PREVIOUS)
1301                         ;
1302
1303                 if(current)
1304                 {
1305                         if(current->startproject + current->length <= input_position)
1306                         {
1307 // Beyond last edit.
1308                                 ;
1309                         }
1310                         else
1311                         if(need_edit(current, test_transitions))
1312                         {
1313 // Over an edit of interest.
1314 // Next edit is going to require a change.
1315                                 if(current->length + current->startproject - input_position < input_length)
1316                                         edit_length = current->startproject + current->length - input_position;
1317                         }
1318                         else
1319                         {
1320 // Over an edit that isn't of interest.
1321 // Search for next edit of interest.
1322                                 for(current = NEXT ;
1323                                         current &&
1324                                         current->startproject < input_position + input_length &&
1325                                         !need_edit(current, test_transitions);
1326                                         current = NEXT)
1327                                         ;
1328
1329                                         if(current &&
1330                                                 need_edit(current, test_transitions) &&
1331                                                 current->startproject < input_position + input_length)
1332                                                 edit_length = current->startproject - input_position;
1333                         }
1334                 }
1335                 else
1336                 {
1337 // Not over an edit.  Try the first edit.
1338                         current = edits->first;
1339                         if(current &&
1340                                 ((test_transitions && current->transition) ||
1341                                 (!test_transitions && current->asset)))
1342                                 edit_length = edits->first->startproject - input_position;
1343                 }
1344         }
1345
1346         if(edit_length < input_length)
1347                 return edit_length;
1348         else
1349                 return input_length;
1350 }
1351
1352 void Track::shuffle_edits(double start, double end, int first_track)
1353 {
1354         ArrayList<Edit*> new_edits;
1355         ArrayList<Label*> new_labels;
1356         int64_t start_units = to_units(start, 0);
1357         int64_t end_units = to_units(end, 0);
1358 // Sample range of all edits selected
1359         //int64_t total_start_units = 0;
1360         //int64_t total_end_units = 0;
1361 // Edit before range
1362         Edit *start_edit = 0;
1363         int have_start_edit = 0;
1364
1365 // Move all edit pointers to list
1366         for(Edit *current = edits->first;
1367                 current; )
1368         {
1369                 if(current->startproject >= start_units &&
1370                         current->startproject + current->length <= end_units)
1371                 {
1372                         if(!have_start_edit) start_edit = current->previous;
1373                         have_start_edit = 1;
1374                         //total_start_units = current->startproject;
1375                         //total_end_units = current->startproject + current->length;
1376                         new_edits.append(current);
1377
1378 // Move label pointers
1379                         if(first_track && edl->session->labels_follow_edits)
1380                         {
1381                                 double start_seconds = from_units(current->startproject);
1382                                 double end_seconds = from_units(current->startproject +
1383                                         current->length);
1384                                 for(Label *label = edl->labels->first;
1385                                         label;
1386                                         label = label->next)
1387                                 {
1388                                         if(label->position >= start_seconds &&
1389                                                 label->position < end_seconds)
1390                                         {
1391                                                 new_labels.append(label);
1392                                                 edl->labels->remove_pointer(label);
1393                                         }
1394                                 }
1395                         }
1396
1397 // Remove edit pointer
1398                         Edit *previous = current;
1399                         current = NEXT;
1400                         edits->remove_pointer(previous);
1401                 }
1402                 else
1403                 {
1404                         current = NEXT;
1405                 }
1406         }
1407
1408 // Insert pointers in random order
1409         while(new_edits.size())
1410         {
1411                 int index = rand() % new_edits.size();
1412                 Edit *edit = new_edits.get(index);
1413                 new_edits.remove_number(index);
1414                 if( !start_edit )
1415                         edits->insert_before(edits->first, edit);
1416                 else
1417                         edits->insert_after(start_edit, edit);
1418                 start_edit = edit;
1419
1420 // Recalculate start position
1421 // Save old position for moving labels
1422                 int64_t startproject1 = edit->startproject;
1423                 int64_t startproject2 = 0;
1424                 if(edit->previous)
1425                 {
1426                         edit->startproject =
1427                                 startproject2 =
1428                                 edit->previous->startproject + edit->previous->length;
1429                 }
1430                 else
1431                 {
1432                         edit->startproject = startproject2 = 0;
1433                 }
1434
1435
1436 // Insert label pointers
1437                 if(first_track && edl->session->labels_follow_edits)
1438                 {
1439                         double start_seconds1 = from_units(startproject1);
1440                         double end_seconds1 = from_units(startproject1 + edit->length);
1441                         double start_seconds2 = from_units(startproject2);
1442                         for(int i = new_labels.size() - 1; i >= 0; i--)
1443                         {
1444                                 Label *label = new_labels.get(i);
1445 // Was in old edit position
1446                                 if(label->position >= start_seconds1 &&
1447                                         label->position < end_seconds1)
1448                                 {
1449 // Move to new edit position
1450                                         double position = label->position -
1451                                                 start_seconds1 + start_seconds2;
1452                                         edl->labels->insert_label(position);
1453                                         new_labels.remove_object_number(i);
1454                                 }
1455                         }
1456                 }
1457
1458
1459         }
1460
1461         optimize();
1462
1463         if(first_track && edl->session->labels_follow_edits)
1464         {
1465                 edl->labels->optimize();
1466         }
1467 }
1468
1469 // exactly the same as shuffle_edits except for 1 line
1470 void Track::reverse_edits(double start, double end, int first_track)
1471 {
1472         ArrayList<Edit*> new_edits;
1473         ArrayList<Label*> new_labels;
1474         int64_t start_units = to_units(start, 0);
1475         int64_t end_units = to_units(end, 0);
1476 // Sample range of all edits selected
1477         //int64_t total_start_units = 0;
1478         //int64_t total_end_units = 0;
1479 // Edit before range
1480         Edit *start_edit = 0;
1481         int have_start_edit = 0;
1482
1483 // Move all edit pointers to list
1484         for(Edit *current = edits->first; current; )
1485         {
1486                 if(current->startproject >= start_units &&
1487                         current->startproject + current->length <= end_units)
1488                 {
1489                         if(!have_start_edit) start_edit = current->previous;
1490                         have_start_edit = 1;
1491                         //total_start_units = current->startproject;
1492                         //total_end_units = current->startproject + current->length;
1493                         new_edits.append(current);
1494
1495 // Move label pointers
1496                         if(first_track && edl->session->labels_follow_edits)
1497                         {
1498                                 double start_seconds = from_units(current->startproject);
1499                                 double end_seconds = from_units(current->startproject +
1500                                         current->length);
1501                                 for(Label *label = edl->labels->first;
1502                                         label;
1503                                         label = label->next)
1504                                 {
1505                                         if(label->position >= start_seconds &&
1506                                                 label->position < end_seconds)
1507                                         {
1508                                                 new_labels.append(label);
1509                                                 edl->labels->remove_pointer(label);
1510                                         }
1511                                 }
1512                         }
1513
1514 // Remove edit pointer
1515                         Edit *previous = current;
1516                         current = NEXT;
1517                         edits->remove_pointer(previous);
1518                 }
1519                 else
1520                 {
1521                         current = NEXT;
1522                 }
1523         }
1524
1525 // Insert pointers in reverse order
1526         while(new_edits.size())
1527         {
1528                 int index = new_edits.size() - 1;
1529                 Edit *edit = new_edits.get(index);
1530                 new_edits.remove_number(index);
1531                 if( !start_edit )
1532                         edits->insert_before(edits->first, edit);
1533                 else
1534                         edits->insert_after(start_edit, edit);
1535                 start_edit = edit;
1536
1537 // Recalculate start position
1538 // Save old position for moving labels
1539                 int64_t startproject1 = edit->startproject;
1540                 int64_t startproject2 = 0;
1541                 if(edit->previous)
1542                 {
1543                         edit->startproject =
1544                                 startproject2 =
1545                                 edit->previous->startproject + edit->previous->length;
1546                 }
1547                 else
1548                 {
1549                         edit->startproject = startproject2 = 0;
1550                 }
1551
1552
1553 // Insert label pointers
1554                 if(first_track && edl->session->labels_follow_edits)
1555                 {
1556                         double start_seconds1 = from_units(startproject1);
1557                         double end_seconds1 = from_units(startproject1 + edit->length);
1558                         double start_seconds2 = from_units(startproject2);
1559                         for(int i = new_labels.size() - 1; i >= 0; i--)
1560                         {
1561                                 Label *label = new_labels.get(i);
1562 // Was in old edit position
1563                                 if(label->position >= start_seconds1 &&
1564                                         label->position < end_seconds1)
1565                                 {
1566 // Move to new edit position
1567                                         double position = label->position -
1568                                                 start_seconds1 + start_seconds2;
1569                                         edl->labels->insert_label(position);
1570                                         new_labels.remove_object_number(i);
1571                                 }
1572                         }
1573                 }
1574
1575
1576         }
1577
1578         optimize();
1579
1580         if(first_track && edl->session->labels_follow_edits)
1581         {
1582                 edl->labels->optimize();
1583         }
1584 }
1585
1586 void Track::align_edits(double start, double end, Track *master_track)
1587 {
1588         int64_t start_units = to_units(start, 0);
1589         int64_t end_units = to_units(end, 0);
1590
1591 // All other tracks get silence or cut to align the edits on the times.
1592         Edit *master = master_track->edits->first;
1593         for(Edit *current = edits->first; current && master; ) {
1594                 if( current->startproject >= start_units &&
1595                     current->startproject + current->length <= end_units ) {
1596 // edit is in highlighted region
1597                         int64_t master_length_units = to_units(master_track->from_units(master->length), 0);
1598 // starting time of master edit
1599                         int64_t master_start_units = to_units(master_track->from_units(master->startproject), 0);
1600 // starting time of current edit
1601                         int64_t current_startunits = current->startproject;
1602
1603 // the following occur if multiple aligns are performed
1604 // master edit is not silence but current edit is silence
1605                         if( !master->silence() && current->silence() ) {
1606 // try again with next edit
1607                                 current = NEXT;
1608                                 continue;
1609                         }
1610                         if( master->silence() && !current->silence() ) {
1611 // master edit is silence but current edit is not silence
1612                                 master = master->next;
1613                                 continue;
1614                         }
1615                         if( current->length < master_length_units / 2 ) {
1616 // current edit is a glitch edit between 2 required edits
1617                                 current = NEXT;
1618                                 continue;
1619                         }
1620
1621                         current = NEXT;
1622 // current edit starts before master edit
1623                         if( current_startunits < master_start_units ) {
1624 //printf("Track::align_edits %d\n", __LINE__);
1625                                 edits->paste_silence(current_startunits, master_start_units);
1626                                 shift_keyframes(current_startunits,
1627                                         master_start_units - current_startunits);
1628                         }
1629                         else if( current_startunits > master_start_units ) {
1630 // current edit starts after master edit
1631                                 edits->clear(master_start_units,
1632                                         current_startunits);
1633                                 if(edl->session->autos_follow_edits)
1634                                         shift_keyframes(master_start_units,
1635                                                 current_startunits - master_start_units);
1636                         }
1637
1638                         master = master->next;
1639                 }
1640                 else {
1641                         current = NEXT;
1642                         master = master->next;
1643                 }
1644         }
1645
1646         optimize();
1647 }
1648
1649 int Track::purge_asset(Asset *asset)
1650 {
1651         return 0;
1652 }
1653
1654 int Track::asset_used(Asset *asset)
1655 {
1656         Edit* current_edit;
1657         int result = 0;
1658
1659         for(current_edit = edits->first; current_edit; current_edit = current_edit->next)
1660         {
1661                 if(current_edit->asset == asset)
1662                 {
1663                         result++;
1664                 }
1665         }
1666         return result;
1667 }
1668
1669 int Track::is_playable(int64_t position, int direction)
1670 {
1671         return 1;
1672 }
1673
1674
1675 int Track::plugin_used(int64_t position, int64_t direction)
1676 {
1677 //printf("Track::plugin_used 1 %d\n", this->plugin_set.total);
1678         for(int i = 0; i < this->plugin_set.total; i++)
1679         {
1680                 Plugin *current_plugin = get_current_plugin(position,
1681                         i,
1682                         direction,
1683                         0,
1684                         0);
1685
1686 //printf("Track::plugin_used 2 %p %d %d\n", current_plugin, current_plugin->on, current_plugin->plugin_type);
1687                 if(current_plugin &&
1688                         current_plugin->on &&
1689                         current_plugin->plugin_type != PLUGIN_NONE)
1690                 {
1691                         return 1;
1692                 }
1693         }
1694 //printf("Track::plugin_used 3 %p\n", current_plugin);
1695         return 0;
1696 }
1697
1698 // Audio is always rendered through VConsole
1699 int Track::direct_copy_possible(int64_t start, int direction, int use_nudge)
1700 {
1701         return 1;
1702 }
1703
1704 int64_t Track::to_units(double position, int round)
1705 {
1706         return (int64_t)position;
1707 }
1708
1709 double Track::to_doubleunits(double position)
1710 {
1711         return position;
1712 }
1713
1714 double Track::from_units(int64_t position)
1715 {
1716         return (double)position;
1717 }
1718
1719 int64_t Track::frame_align(int64_t position, int round)
1720 {
1721         if( data_type != TRACK_VIDEO && edl->session->cursor_on_frames )
1722                 position = to_units(edl->align_to_frame(from_units(position), round), round);
1723         return position;
1724 }
1725
1726 Plugin *Track::plugin_exists(int plugin_id)
1727 {
1728         for( int i=0; i<plugin_set.size(); ++i ) {
1729                 PluginSet *set = plugin_set.get(i);
1730                 Plugin *plugin = (Plugin*)set->first;
1731                 for( ; plugin; plugin=(Plugin*)plugin->next ) {
1732                         if( plugin->orig_id == plugin_id )
1733                                 return plugin;
1734                 }
1735         }
1736         for( Edit *current=edits->first; current; current=NEXT ) {
1737                 Plugin *plugin = (Plugin *)current->transition;
1738                 if( plugin && plugin->orig_id == plugin_id )
1739                         return plugin;
1740         }
1741         return 0;
1742 }
1743
1744 int Track::get_mixer_id()
1745 {
1746         if( mixer_id < 0 ) {
1747                 int v = 0;
1748                 for( Track *track=tracks->first; track!=0; track=track->next )
1749                         if( track->mixer_id > v ) v = track->mixer_id;
1750                 mixer_id = v + 1;
1751         }
1752         return mixer_id;
1753 }
1754
1755 void Track::get_fauto_xyz(int fauto, float &x, float &y, float &z)
1756 {
1757         FloatAutos **fautos = (FloatAutos **)&automation->autos;
1758         FloatAuto *xauto = (FloatAuto *)fautos[fauto+0]->get_auto_for_editing(-1, 1);
1759         if( xauto ) x = xauto->get_value();
1760         FloatAuto *yauto = (FloatAuto *)fautos[fauto+1]->get_auto_for_editing(-1, 1);
1761         if( yauto ) y = yauto->get_value();
1762         FloatAuto *zauto = (FloatAuto *)fautos[fauto+2]->get_auto_for_editing(-1, 1);
1763         if( zauto ) z = zauto->get_value();
1764 }
1765 void Track::set_fauto_xyz(int fauto, float x, float y, float z)
1766 {
1767         FloatAutos **fautos = (FloatAutos **)&automation->autos;
1768         FloatAuto *xauto = (FloatAuto *)fautos[fauto+0]->get_auto_for_editing(-1, 1);
1769         if( xauto ) xauto->set_value(x);
1770         FloatAuto *yauto = (FloatAuto *)fautos[fauto+1]->get_auto_for_editing(-1, 1);
1771         if( yauto ) yauto->set_value(y);
1772         FloatAuto *zauto = (FloatAuto *)fautos[fauto+2]->get_auto_for_editing(-1, 1);
1773         if( zauto ) zauto->set_value(z);
1774 }
1775
1776 void Track::get_projector(float &x, float &y, float &z)
1777 {
1778         get_fauto_xyz(AUTOMATION_PROJECTOR_X, x, y, z);
1779 }
1780 void Track::set_projector(float x, float y, float z)
1781 {
1782         set_fauto_xyz(AUTOMATION_PROJECTOR_X, x, y, z);
1783 }
1784
1785 void Track::get_camera(float &x, float &y, float &z)
1786 {
1787         get_fauto_xyz(AUTOMATION_CAMERA_X, x, y, z);
1788 }
1789 void Track::set_camera(float x, float y, float z)
1790 {
1791         set_fauto_xyz(AUTOMATION_CAMERA_X, x, y, z);
1792 }
1793
1794 Track *Track::gang_master()
1795 {
1796         Track *track = this;
1797         switch( edl->session->gang_tracks ) {
1798         case GANG_NONE:
1799                 return track;
1800         case GANG_CHANNELS: {
1801                 Track *current = track;
1802                 int data_type = track->data_type;
1803                 while( current && !track->master ) {
1804                         if( !(current = current->previous) ) break;
1805                         if( current->data_type == data_type ) track = current;
1806                         if( track->master ) break;
1807                 }
1808                 break; }
1809         case GANG_MEDIA: {
1810                 while( track && !track->master ) track = track->previous;
1811                 break; }
1812         }
1813         if( !track ) track = tracks->first;
1814         return track;
1815 }
1816
1817 int Track::is_hidden()
1818 {
1819         if( master ) return 0;
1820         if( edl->session->gang_tracks == GANG_MEDIA ) return 1;
1821         if( edl->session->gang_tracks == GANG_CHANNELS ) {
1822                 for( Track *track=previous; track; track=track->previous ) {
1823                         if( track->data_type == data_type ) return 1;
1824                         if( track->master ) return 0;
1825                 }
1826         }
1827         return 0;
1828 }
1829 int Track::is_armed()
1830 {
1831         return gang_master()->armed;
1832 }
1833
1834 int Track::is_ganged()
1835 {
1836         return gang_master()->ganged;
1837 }
1838
1839 int Track::armed_gang(Track *track)
1840 {
1841         if( edl->session->gang_tracks == GANG_NONE ) return ganged;
1842         Track *current = gang_master();
1843         for(;;) {
1844                 if( track == current ) return 1;
1845                 current = current->next;
1846                 if( !current || current->master ) return 0;
1847         }
1848         return 1;
1849 }
1850
1851
1852 int Track::index_in(Mixer *mixer)
1853 {
1854         if( !mixer || mixer_id < 0 ) return -1;
1855         int k = mixer->mixer_ids.size();
1856         while( --k >= 0 && mixer_id != mixer->mixer_ids[k] );
1857         return k;
1858 }
1859