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