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