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