asset drag/drop to viewers, bluebanana bug, listbox fontlist highlight
[goodguy/history.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 }
70
71 Track::~Track()
72 {
73         delete automation;
74         delete edits;
75         plugin_set.remove_all_objects();
76 }
77
78 void Track::create_objects()
79 {
80 }
81
82
83 int Track::copy_settings(Track *track)
84 {
85         this->expand_view = track->expand_view;
86         this->draw = track->draw;
87         this->gang = track->gang;
88         this->record = track->record;
89         this->nudge = track->nudge;
90         this->play = track->play;
91         this->track_w = track->track_w;
92         this->track_h = track->track_h;
93         strcpy(this->title, track->title);
94         return 0;
95 }
96
97 int Track::get_id()
98 {
99         return id;
100 }
101
102
103 int Track::load_defaults(BC_Hash *defaults)
104 {
105         return 0;
106 }
107
108 void Track::equivalent_output(Track *track, double *result)
109 {
110         if(data_type != track->data_type ||
111                 track_w != track->track_w ||
112                 track_h != track->track_h ||
113                 play != track->play ||
114                 nudge != track->nudge)
115                 *result = 0;
116
117 // Convert result to track units
118         int64_t result2 = -1;
119         automation->equivalent_output(track->automation, &result2);
120         edits->equivalent_output(track->edits, &result2);
121
122         int plugin_sets = MIN(plugin_set.total, track->plugin_set.total);
123 // Test existing plugin sets
124         for(int i = 0; i < plugin_sets; i++)
125         {
126                 plugin_set.values[i]->equivalent_output(
127                         track->plugin_set.values[i],
128                         &result2);
129         }
130
131 // New EDL has more plugin sets.  Get starting plugin in new plugin sets
132         for(int i = plugin_sets; i < plugin_set.total; i++)
133         {
134                 Plugin *current = plugin_set.values[i]->get_first_plugin();
135                 if(current)
136                 {
137                         if(result2 < 0 || current->startproject < result2)
138                                 result2 = current->startproject;
139                 }
140         }
141
142 // New EDL has fewer plugin sets.  Get starting plugin in old plugin set
143         for(int i = plugin_sets; i < track->plugin_set.total; i++)
144         {
145                 Plugin *current = track->plugin_set.values[i]->get_first_plugin();
146                 if(current)
147                 {
148                         if(result2 < 0 || current->startproject < result2)
149                                 result2 = current->startproject;
150                 }
151         }
152
153 // Number of plugin sets differs but somehow we didn't find the start of the
154 // change.  Assume 0
155         if(track->plugin_set.total != plugin_set.total && result2 < 0)
156                 result2 = 0;
157
158         if(result2 >= 0 &&
159                 (*result < 0 || from_units(result2) < *result))
160                 *result = from_units(result2);
161 }
162
163
164 int Track::is_synthesis(int64_t position,
165         int direction)
166 {
167         int is_synthesis = 0;
168         for(int i = 0; i < plugin_set.total; i++)
169         {
170                 Plugin *plugin = get_current_plugin(position,
171                         i,
172                         direction,
173                         0,
174                         0);
175                 if(plugin)
176                 {
177 // Assume data from a shared track is synthesized
178                         if(plugin->plugin_type == PLUGIN_SHAREDMODULE)
179                                 is_synthesis = 1;
180                         else
181                                 is_synthesis = plugin->is_synthesis(position,
182                                         direction);
183
184 //printf("Track::is_synthesis %d %d\n", __LINE__, is_synthesis);
185                         if(is_synthesis) break;
186                 }
187         }
188         return is_synthesis;
189 }
190
191 void Track::copy_from(Track *track)
192 {
193         copy_settings(track);
194         edits->copy_from(track->edits);
195         for(int i = 0; i < this->plugin_set.total; i++)
196                 delete this->plugin_set.values[i];
197         this->plugin_set.remove_all_objects();
198
199         for(int i = 0; i < track->plugin_set.total; i++)
200         {
201                 PluginSet *new_plugin_set = plugin_set.append(new PluginSet(edl, this));
202                 new_plugin_set->copy_from(track->plugin_set.values[i]);
203         }
204         automation->copy_from(track->automation);
205         this->track_w = track->track_w;
206         this->track_h = track->track_h;
207 }
208
209 Track& Track::operator=(Track& track)
210 {
211 printf("Track::operator= 1\n");
212         copy_from(&track);
213         return *this;
214 }
215
216 int Track::vertical_span(Theme *theme)
217 {
218         int result = 0;
219         if(expand_view)
220                 result = edl->local_session->zoom_track +
221                         plugin_set.total *
222                         theme->get_image("plugin_bg_data")->get_h();
223         else
224                 result = edl->local_session->zoom_track;
225
226         if(edl->session->show_titles)
227                 result += theme->get_image("title_bg_data")->get_h();
228
229         return result;
230 }
231
232 double Track::get_length()
233 {
234         double total_length = 0;
235         double length = 0;
236
237 // Test edits
238         if(edits->last)
239         {
240                 length = from_units(edits->last->startproject + edits->last->length);
241                 if(length > total_length) total_length = length;
242         }
243
244 // Test plugins
245         for(int i = 0; i < plugin_set.total; i++)
246         {
247                 if( !plugin_set.values[i]->last ) continue;
248                 length = from_units(plugin_set.values[i]->last->startproject +
249                         plugin_set.values[i]->last->length);
250                 if(length > total_length) total_length = length;
251         }
252
253 // Test keyframes
254         length = from_units(automation->get_length());
255         if(length > total_length) total_length = length;
256
257
258         return total_length;
259 }
260
261 int Track::has_speed()
262 {
263         FloatAutos *autos = (FloatAutos*)automation->autos[AUTOMATION_SPEED];
264         if(autos)
265         {
266                 if(autos->first)
267                 {
268                         for(FloatAuto *current = (FloatAuto*)autos->first;
269                                 current;
270                                 current = (FloatAuto*)current->next)
271                         {
272                                 if(!EQUIV(current->get_value(), 1.0) ||
273                                         !EQUIV(current->get_control_in_value(), 0.0) ||
274                                         !EQUIV(current->get_control_out_value(), 0.0))
275                                 {
276                                         return 1;
277                                 }
278                         }
279                 }
280         }
281
282         return 0;
283 }
284
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         expand_view = file->tag.get_property("EXPAND", expand_view);
325         track_w = file->tag.get_property("TRACK_W", track_w);
326         track_h = file->tag.get_property("TRACK_H", track_h);
327
328         load_header(file, load_flags);
329
330         do{
331                 result = file->read_tag();
332
333                 if(!result)
334                 {
335                         if(file->tag.title_is("/TRACK"))
336                         {
337                                 result = 1;
338                         }
339                         else
340                         if(file->tag.title_is("TITLE"))
341                         {
342                                 file->read_text_until("/TITLE", title, BCTEXTLEN);
343                         }
344                         else
345                         if(load_flags && automation->load(file)
346                         /* strstr(file->tag.get_title(), "AUTOS") */)
347                         {
348                                 ;
349                         }
350                         else
351                         if(file->tag.title_is("EDITS"))
352                         {
353                                 if(load_flags & LOAD_EDITS)
354                                         edits->load(file, track_offset);
355                                 else
356                                         result = file->skip_tag();
357                         }
358                         else
359                         if(file->tag.title_is("PLUGINSET"))
360                         {
361                                 if(load_flags & LOAD_EDITS)
362                                 {
363                                         PluginSet *plugin_set = new PluginSet(edl, this);
364                                         this->plugin_set.append(plugin_set);
365                                         plugin_set->load(file, load_flags);
366                                 }
367                                 else
368                                 if(load_flags & LOAD_AUTOMATION)
369                                 {
370                                         if(current_plugin < this->plugin_set.total)
371                                         {
372                                                 PluginSet *plugin_set = this->plugin_set.values[current_plugin];
373                                                 plugin_set->load(file, load_flags);
374                                                 current_plugin++;
375                                         }
376                                 }
377                                 else
378                                         result = file->skip_tag();
379                         }
380                         else
381                                 load_derived(file, load_flags);
382                 }
383         }while(!result);
384
385
386
387         return 0;
388 }
389
390 void Track::insert_asset(Asset *asset,
391         EDL *nested_edl,
392         double length,
393         double position,
394         int track_number)
395 {
396         edits->insert_asset(asset,
397                 nested_edl,
398                 to_units(length, 1),
399                 to_units(position, 0),
400                 track_number);
401 }
402
403 // Insert data
404
405 // Default keyframes: We don't replace default keyframes in pasting but
406 // when inserting the first EDL of a load operation we need to replace
407 // the default keyframes.
408
409 // Plugins:  This is an arbitrary behavior
410 //
411 // 1) No plugin in source track: Paste silence into destination
412 // plugin sets.
413 // 2) Plugin in source track: plugin in source track is inserted into
414 // existing destination track plugin sets, new sets being added when
415 // necessary.
416
417 void Track::insert_track(Track *track,
418         double position,
419         int replace_default,
420         int edit_plugins,
421         int edit_autos,
422         double edl_length)
423 {
424 // Calculate minimum length of data to pad.
425         int64_t min_length = to_units(
426                 MAX(edl_length, track->get_length()),
427                 1);
428 //printf("Track::insert_track %d %s %jd\n", __LINE__, title, min_length);
429
430 // Decide whether to copy settings based on load_mode
431         if(replace_default) copy_settings(track);
432
433         edits->insert_edits(track->edits,
434                 to_units(position, 0),
435                 min_length,
436                 edit_autos);
437
438         if(edit_plugins)
439                 insert_plugin_set(track,
440                         to_units(position, 0),
441                         min_length,
442                         edit_autos);
443
444         if(edit_autos)
445                 automation->insert_track(track->automation,
446                         to_units(position, 0),
447                         min_length,
448                         replace_default);
449
450         optimize();
451
452 }
453
454 // Called by insert_track
455 void Track::insert_plugin_set(Track *track,
456         int64_t position,
457         int64_t min_length,
458         int edit_autos)
459 {
460 // Extend plugins if no incoming plugins
461         if(!track->plugin_set.total)
462         {
463                 shift_effects(position,
464                         min_length,
465                         edit_autos);
466         }
467         else
468         for(int i = 0; i < track->plugin_set.total; i++)
469         {
470                 if(i >= plugin_set.total)
471                         plugin_set.append(new PluginSet(edl, this));
472
473                 plugin_set.values[i]->insert_edits(track->plugin_set.values[i],
474                         position,
475                         min_length,
476                         edit_autos);
477         }
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(),
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)
658 {
659         for(int i = 0; i < plugin_set.total; i++)
660         {
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
847
848
849 int Track::dump(FILE *fp)
850 {
851         fprintf(fp,"   Data type %d\n", data_type);
852         fprintf(fp,"   Title %s\n", title);
853         fprintf(fp,"   Edits:\n");
854         for(Edit* current = edits->first; current; current = NEXT)
855         {
856                 current->dump(fp);
857         }
858         automation->dump(fp);
859         fprintf(fp,"   Plugin Sets: %d\n", plugin_set.total);
860
861         for(int i = 0; i < plugin_set.total; i++)
862                 plugin_set.values[i]->dump(fp);
863 //printf("Track::dump 2\n");
864         return 0;
865 }
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887 Track::Track() : ListItem<Track>()
888 {
889         y_pixel = 0;
890 }
891
892 // ======================================== accounting
893
894 int Track::number_of()
895 {
896         return tracks->number_of(this);
897 }
898
899
900
901
902
903
904
905
906
907
908
909
910
911 // ================================================= editing
912
913 int Track::select_auto(AutoConf *auto_conf, int cursor_x, int cursor_y)
914 {
915         return 0;
916 }
917
918 int Track::move_auto(AutoConf *auto_conf, int cursor_x, int cursor_y, int shift_down)
919 {
920         return 0;
921 }
922
923 int Track::release_auto()
924 {
925         return 0;
926 }
927
928 // used for copying automation alone
929 int Track::copy_automation(double selectionstart,
930         double selectionend,
931         FileXML *file,
932         int default_only,
933         int active_only)
934 {
935         int64_t start = to_units(selectionstart, 0);
936         int64_t end = to_units(selectionend, 1);
937
938         file->tag.set_title("TRACK");
939 // Video or audio
940     save_header(file);
941         file->append_tag();
942         file->append_newline();
943
944         automation->copy(start, end, file, default_only, active_only);
945
946         if(edl->session->auto_conf->plugins)
947         {
948                 for(int i = 0; i < plugin_set.total; i++)
949                 {
950
951                         plugin_set.values[i]->copy_keyframes(start,
952                                 end,
953                                 file,
954                                 default_only,
955                                 active_only);
956                 }
957         }
958
959         file->tag.set_title("/TRACK");
960         file->append_tag();
961         file->append_newline();
962         file->append_newline();
963         file->append_newline();
964         file->append_newline();
965
966         return 0;
967 }
968
969 int Track::paste_automation(double selectionstart,
970         double total_length,
971         double frame_rate,
972         int64_t sample_rate,
973         FileXML *file,
974         int default_only,
975         int active_only)
976 {
977 // Only used for pasting automation alone.
978         int64_t start;
979         int64_t length;
980         int result;
981         double scale;
982         int current_pluginset;
983
984         if(data_type == TRACK_AUDIO)
985                 scale = edl->session->sample_rate / sample_rate;
986         else
987                 scale = edl->session->frame_rate / frame_rate;
988
989         total_length *= scale;
990         start = to_units(selectionstart, 0);
991         length = to_units(total_length, 1);
992         result = 0;
993         current_pluginset = 0;
994 //printf("Track::paste_automation 1\n");
995
996         while(!result)
997         {
998                 result = file->read_tag();
999
1000                 if(!result)
1001                 {
1002                         if(file->tag.title_is("/TRACK"))
1003                                 result = 1;
1004                         else
1005                         if(automation->paste(start, length, scale, file,
1006                                         default_only, active_only, 0)) {}
1007                         else if(file->tag.title_is("PLUGINSET")) {
1008                                 if(current_pluginset < plugin_set.total) {
1009                                         plugin_set.values[current_pluginset]->
1010                                                 paste_keyframes(start, length, file,
1011                                                 default_only, active_only);
1012                                         current_pluginset++;
1013                                 }
1014                         }
1015                 }
1016         }
1017
1018
1019         return 0;
1020 }
1021
1022 void Track::clear_automation(double selectionstart,
1023         double selectionend,
1024         int shift_autos,
1025         int default_only)
1026 {
1027         int64_t start = to_units(selectionstart, 0);
1028         int64_t end = to_units(selectionend, 1);
1029
1030         automation->clear(start, end, edl->session->auto_conf, 0);
1031
1032         if(edl->session->auto_conf->plugins)
1033         {
1034                 for(int i = 0; i < plugin_set.total; i++)
1035                 {
1036                         plugin_set.values[i]->clear_keyframes(start, end);
1037                 }
1038         }
1039
1040 }
1041
1042 void Track::set_automation_mode(double selectionstart,
1043         double selectionend,
1044         int mode)
1045 {
1046         int64_t start = to_units(selectionstart, 0);
1047         int64_t end = to_units(selectionend, 1);
1048
1049         automation->set_automation_mode(start, end, mode, edl->session->auto_conf);
1050 }
1051
1052
1053
1054
1055 int Track::copy(double start,
1056         double end,
1057         FileXML *file,
1058         const char *output_path)
1059 {
1060 // Use a copy of the selection in converted units
1061 // So copy_automation doesn't reconvert.
1062         int64_t start_unit = to_units(start, 0);
1063         int64_t end_unit = to_units(end, 1);
1064
1065
1066
1067
1068         file->tag.set_title("TRACK");
1069         file->tag.set_property("RECORD", record);
1070         file->tag.set_property("NUDGE", nudge);
1071         file->tag.set_property("PLAY", play);
1072         file->tag.set_property("GANG", gang);
1073         file->tag.set_property("DRAW", draw);
1074         file->tag.set_property("EXPAND", expand_view);
1075         file->tag.set_property("TRACK_W", track_w);
1076         file->tag.set_property("TRACK_H", track_h);
1077         save_header(file);
1078         file->append_tag();
1079         file->append_newline();
1080         save_derived(file);
1081
1082         file->tag.set_title("TITLE");
1083         file->append_tag();
1084         file->append_text(title);
1085         file->tag.set_title("/TITLE");
1086         file->append_tag();
1087         file->append_newline();
1088
1089 //      if(data_type == TRACK_AUDIO)
1090 //              file->tag.set_property("TYPE", "AUDIO");
1091 //      else
1092 //              file->tag.set_property("TYPE", "VIDEO");
1093 //
1094 //      file->append_tag();
1095 //      file->append_newline();
1096
1097         edits->copy(start_unit, end_unit, file, output_path);
1098
1099         AutoConf auto_conf;
1100         auto_conf.set_all(1);
1101         automation->copy(start_unit, end_unit, file, 0, 0);
1102
1103
1104         for(int i = 0; i < plugin_set.total; i++)
1105         {
1106                 plugin_set.values[i]->copy(start_unit, end_unit, file);
1107         }
1108
1109         copy_derived(start_unit, end_unit, file);
1110
1111         file->tag.set_title("/TRACK");
1112         file->append_tag();
1113         file->append_newline();
1114         file->append_newline();
1115         file->append_newline();
1116         file->append_newline();
1117
1118         return 0;
1119 }
1120
1121 int Track::copy_assets(double start,
1122         double end,
1123         ArrayList<Asset*> *asset_list)
1124 {
1125         int i, result = 0;
1126
1127         start = to_units(start, 0);
1128         end = to_units(end, 1);
1129
1130         Edit *current = edits->editof((int64_t)start, PLAY_FORWARD, 0);
1131
1132 // Search all edits
1133         while(current && current->startproject < end)
1134         {
1135 // Check for duplicate assets
1136                 if(current->asset)
1137                 {
1138                         for(i = 0, result = 0; i < asset_list->total; i++)
1139                         {
1140                                 if(asset_list->values[i] == current->asset) result = 1;
1141                         }
1142 // append pointer to new asset
1143                         if(!result) asset_list->append(current->asset);
1144                 }
1145
1146                 current = NEXT;
1147         }
1148
1149         return 0;
1150 }
1151
1152
1153
1154
1155
1156 int Track::clear(double start,
1157         double end,
1158         int edit_edits,
1159         int edit_labels,
1160         int edit_plugins,
1161         int edit_autos,
1162         int convert_units,
1163         Edits *trim_edits)
1164 {
1165 // Edits::move_auto calls this routine after the units are converted to the track
1166 // format.
1167 //printf("Track::clear 1 %d %d %d\n", edit_edits, edit_labels, edit_plugins);
1168         if(convert_units)
1169         {
1170                 start = to_units(start, 0);
1171                 end = to_units(end, 1);
1172         }
1173
1174
1175         if(edit_autos)
1176                 automation->clear((int64_t)start, (int64_t)end, 0, 1);
1177
1178         if(edit_plugins)
1179         {
1180                 for(int i = 0; i < plugin_set.total; i++)
1181                 {
1182                         if(!trim_edits || trim_edits == (Edits*)plugin_set.values[i])
1183                                 plugin_set.values[i]->clear((int64_t)start, (int64_t)end, edit_autos);
1184                 }
1185         }
1186
1187         if(edit_edits)
1188                 edits->clear((int64_t)start, (int64_t)end);
1189         return 0;
1190 }
1191
1192 int Track::clear_handle(double start,
1193         double end,
1194         int clear_labels,
1195         int clear_plugins,
1196         int edit_autos,
1197         double &distance)
1198 {
1199         edits->clear_handle(start, end, clear_plugins, edit_autos, distance);
1200         return 0;
1201 }
1202
1203 int Track::popup_transition(int cursor_x, int cursor_y)
1204 {
1205         return 0;
1206 }
1207
1208
1209
1210 int Track::modify_edithandles(double oldposition,
1211         double newposition,
1212         int currentend,
1213         int handle_mode,
1214         int edit_labels,
1215         int edit_plugins,
1216         int edit_autos)
1217 {
1218         edits->modify_handles(oldposition,
1219                 newposition,
1220                 currentend,
1221                 handle_mode,
1222                 1,
1223                 edit_labels,
1224                 edit_plugins,
1225                 edit_autos,
1226                 0);
1227
1228
1229         return 0;
1230 }
1231
1232 int Track::modify_pluginhandles(double oldposition,
1233         double newposition,
1234         int currentend,
1235         int handle_mode,
1236         int edit_labels,
1237         int edit_autos,
1238         Edits *trim_edits)
1239 {
1240         for(int i = 0; i < plugin_set.total; i++)
1241         {
1242                 if(!trim_edits || trim_edits == (Edits*)plugin_set.values[i])
1243                         plugin_set.values[i]->modify_handles(oldposition,
1244                                 newposition,
1245                                 currentend,
1246                                 handle_mode,
1247 // Don't allow plugin tweeks to affect edits.
1248                                 0,
1249                                 edit_labels,
1250                                 1,
1251                                 edit_autos,
1252                                 trim_edits);
1253         }
1254         return 0;
1255 }
1256
1257
1258 int Track::paste_silence(double start, double end, int edit_plugins, int edit_autos)
1259 {
1260         int64_t start_i = to_units(start, 0);
1261         int64_t end_i = to_units(end, 1);
1262
1263         edits->paste_silence(start_i, end_i);
1264         if(edit_autos) shift_keyframes(start_i, end_i - start_i);
1265         if(edit_plugins) shift_effects(start_i, end_i - start_i, edit_autos);
1266
1267         edits->optimize();
1268         return 0;
1269 }
1270
1271 int Track::select_edit(int cursor_x,
1272         int cursor_y,
1273         double &new_start,
1274         double &new_end)
1275 {
1276         return 0;
1277 }
1278
1279 int Track::scale_time(float rate_scale, int scale_edits, int scale_autos, int64_t start, int64_t end)
1280 {
1281         return 0;
1282 }
1283
1284 void Track::change_plugins(SharedLocation &old_location, SharedLocation &new_location, int do_swap)
1285 {
1286         for(int i = 0; i < plugin_set.total; i++)
1287         {
1288                 for(Plugin *plugin = (Plugin*)plugin_set.values[i]->first;
1289                         plugin;
1290                         plugin = (Plugin*)plugin->next)
1291                 {
1292                         if(plugin->plugin_type == PLUGIN_SHAREDPLUGIN)
1293                         {
1294                                 if(plugin->shared_location == old_location)
1295                                         plugin->shared_location = new_location;
1296                                 else
1297                                 if(do_swap && plugin->shared_location == new_location)
1298                                         plugin->shared_location = old_location;
1299                         }
1300                 }
1301         }
1302 }
1303
1304 void Track::change_modules(int old_location, int new_location, int do_swap)
1305 {
1306         for(int i = 0; i < plugin_set.total; i++)
1307         {
1308                 for(Plugin *plugin = (Plugin*)plugin_set.values[i]->first;
1309                         plugin;
1310                         plugin = (Plugin*)plugin->next)
1311                 {
1312                         if(plugin->plugin_type == PLUGIN_SHAREDPLUGIN ||
1313                                 plugin->plugin_type == PLUGIN_SHAREDMODULE)
1314                         {
1315                                 if(plugin->shared_location.module == old_location)
1316                                         plugin->shared_location.module = new_location;
1317                                 else
1318                                 if(do_swap && plugin->shared_location.module == new_location)
1319                                         plugin->shared_location.module = old_location;
1320                         }
1321                 }
1322         }
1323 }
1324
1325
1326 int Track::playable_edit(int64_t position, int direction)
1327 {
1328         int result = 0;
1329         if(direction == PLAY_REVERSE) position--;
1330         for(Edit *current = edits->first; current && !result; current = NEXT)
1331         {
1332                 if(current->startproject <= position &&
1333                         current->startproject + current->length > position)
1334                 {
1335 //printf("Track::playable_edit %p %p\n", current->transition, current->asset);
1336                         if(current->transition ||
1337                                 current->asset ||
1338                                 current->nested_edl) result = 1;
1339                 }
1340         }
1341         return result;
1342 }
1343
1344
1345 int Track::need_edit(Edit *current, int test_transitions)
1346 {
1347         return ((test_transitions && current->transition) ||
1348                 (!test_transitions && current->asset));
1349 }
1350
1351 int64_t Track::plugin_change_duration(int64_t input_position,
1352         int64_t input_length,
1353         int reverse,
1354         int use_nudge)
1355 {
1356         if(use_nudge) input_position += nudge;
1357         for(int i = 0; i < plugin_set.total; i++)
1358         {
1359                 int64_t new_duration = plugin_set.values[i]->plugin_change_duration(
1360                         input_position,
1361                         input_length,
1362                         reverse);
1363                 if(new_duration < input_length) input_length = new_duration;
1364         }
1365         return input_length;
1366 }
1367
1368 int64_t Track::edit_change_duration(int64_t input_position,
1369         int64_t input_length,
1370         int reverse,
1371         int test_transitions,
1372         int use_nudge)
1373 {
1374         Edit *current;
1375         int64_t edit_length = input_length;
1376         if(use_nudge) input_position += nudge;
1377
1378         if(reverse)
1379         {
1380 // ================================= Reverse playback
1381 // Get first edit on or after position
1382                 for(current = edits->first;
1383                         current && current->startproject + current->length <= input_position;
1384                         current = NEXT)
1385                         ;
1386
1387                 if(current)
1388                 {
1389                         if(current->startproject > input_position)
1390                         {
1391 // Before first edit
1392                                 ;
1393                         }
1394                         else
1395                         if(need_edit(current, test_transitions))
1396                         {
1397 // Over an edit of interest.
1398                                 if(input_position - current->startproject < input_length)
1399                                         edit_length = input_position - current->startproject + 1;
1400                         }
1401                         else
1402                         {
1403 // Over an edit that isn't of interest.
1404 // Search for next edit of interest.
1405                                 for(current = PREVIOUS ;
1406                                         current &&
1407                                         current->startproject + current->length > input_position - input_length &&
1408                                         !need_edit(current, test_transitions);
1409                                         current = PREVIOUS)
1410                                         ;
1411
1412                                         if(current &&
1413                                                 need_edit(current, test_transitions) &&
1414                                                 current->startproject + current->length > input_position - input_length)
1415                         edit_length = input_position - current->startproject - current->length + 1;
1416                         }
1417                 }
1418                 else
1419                 {
1420 // Not over an edit.  Try the last edit.
1421                         current = edits->last;
1422                         if(current &&
1423                                 ((test_transitions && current->transition) ||
1424                                 (!test_transitions && current->asset)))
1425                                 edit_length = input_position - edits->length() + 1;
1426                 }
1427         }
1428         else
1429         {
1430 // =================================== forward playback
1431 // Get first edit on or before position
1432                 for(current = edits->last;
1433                         current && current->startproject > input_position;
1434                         current = PREVIOUS)
1435                         ;
1436
1437                 if(current)
1438                 {
1439                         if(current->startproject + current->length <= input_position)
1440                         {
1441 // Beyond last edit.
1442                                 ;
1443                         }
1444                         else
1445                         if(need_edit(current, test_transitions))
1446                         {
1447 // Over an edit of interest.
1448 // Next edit is going to require a change.
1449                                 if(current->length + current->startproject - input_position < input_length)
1450                                         edit_length = current->startproject + current->length - input_position;
1451                         }
1452                         else
1453                         {
1454 // Over an edit that isn't of interest.
1455 // Search for next edit of interest.
1456                                 for(current = NEXT ;
1457                                         current &&
1458                                         current->startproject < input_position + input_length &&
1459                                         !need_edit(current, test_transitions);
1460                                         current = NEXT)
1461                                         ;
1462
1463                                         if(current &&
1464                                                 need_edit(current, test_transitions) &&
1465                                                 current->startproject < input_position + input_length)
1466                                                 edit_length = current->startproject - input_position;
1467                         }
1468                 }
1469                 else
1470                 {
1471 // Not over an edit.  Try the first edit.
1472                         current = edits->first;
1473                         if(current &&
1474                                 ((test_transitions && current->transition) ||
1475                                 (!test_transitions && current->asset)))
1476                                 edit_length = edits->first->startproject - input_position;
1477                 }
1478         }
1479
1480         if(edit_length < input_length)
1481                 return edit_length;
1482         else
1483                 return input_length;
1484 }
1485
1486 void Track::shuffle_edits(double start, double end, int first_track)
1487 {
1488         ArrayList<Edit*> new_edits;
1489         ArrayList<Label*> new_labels;
1490         int64_t start_units = to_units(start, 0);
1491         int64_t end_units = to_units(end, 0);
1492 // Sample range of all edits selected
1493         //int64_t total_start_units = 0;
1494         //int64_t total_end_units = 0;
1495 // Edit before range
1496         Edit *start_edit = 0;
1497         int have_start_edit = 0;
1498
1499 // Move all edit pointers to list
1500         for(Edit *current = edits->first;
1501                 current; )
1502         {
1503                 if(current->startproject >= start_units &&
1504                         current->startproject + current->length <= end_units)
1505                 {
1506                         if(!have_start_edit) start_edit = current->previous;
1507                         have_start_edit = 1;
1508                         //total_start_units = current->startproject;
1509                         //total_end_units = current->startproject + current->length;
1510                         new_edits.append(current);
1511
1512 // Move label pointers
1513                         if(first_track && edl->session->labels_follow_edits)
1514                         {
1515                                 double start_seconds = from_units(current->startproject);
1516                                 double end_seconds = from_units(current->startproject +
1517                                         current->length);
1518                                 for(Label *label = edl->labels->first;
1519                                         label;
1520                                         label = label->next)
1521                                 {
1522                                         if(label->position >= start_seconds &&
1523                                                 label->position < end_seconds)
1524                                         {
1525                                                 new_labels.append(label);
1526                                                 edl->labels->remove_pointer(label);
1527                                         }
1528                                 }
1529                         }
1530
1531 // Remove edit pointer
1532                         Edit *previous = current;
1533                         current = NEXT;
1534                         edits->remove_pointer(previous);
1535                 }
1536                 else
1537                 {
1538                         current = NEXT;
1539                 }
1540         }
1541
1542 // Insert pointers in random order
1543         while(new_edits.size())
1544         {
1545                 int index = rand() % new_edits.size();
1546                 Edit *edit = new_edits.get(index);
1547                 new_edits.remove_number(index);
1548                 if( !start_edit )
1549                         edits->insert_before(edits->first, edit);
1550                 else
1551                         edits->insert_after(start_edit, edit);
1552                 start_edit = edit;
1553
1554 // Recalculate start position
1555 // Save old position for moving labels
1556                 int64_t startproject1 = edit->startproject;
1557                 int64_t startproject2 = 0;
1558                 if(edit->previous)
1559                 {
1560                         edit->startproject =
1561                                 startproject2 =
1562                                 edit->previous->startproject + edit->previous->length;
1563                 }
1564                 else
1565                 {
1566                         edit->startproject = startproject2 = 0;
1567                 }
1568
1569
1570 // Insert label pointers
1571                 if(first_track && edl->session->labels_follow_edits)
1572                 {
1573                         double start_seconds1 = from_units(startproject1);
1574                         double end_seconds1 = from_units(startproject1 + edit->length);
1575                         double start_seconds2 = from_units(startproject2);
1576                         for(int i = new_labels.size() - 1; i >= 0; i--)
1577                         {
1578                                 Label *label = new_labels.get(i);
1579 // Was in old edit position
1580                                 if(label->position >= start_seconds1 &&
1581                                         label->position < end_seconds1)
1582                                 {
1583 // Move to new edit position
1584                                         double position = label->position -
1585                                                 start_seconds1 + start_seconds2;
1586                                         edl->labels->insert_label(position);
1587                                         new_labels.remove_object_number(i);
1588                                 }
1589                         }
1590                 }
1591
1592
1593         }
1594
1595         optimize();
1596
1597         if(first_track && edl->session->labels_follow_edits)
1598         {
1599                 edl->labels->optimize();
1600         }
1601 }
1602
1603 // exactly the same as shuffle_edits except for 1 line
1604 void Track::reverse_edits(double start, double end, int first_track)
1605 {
1606         ArrayList<Edit*> new_edits;
1607         ArrayList<Label*> new_labels;
1608         int64_t start_units = to_units(start, 0);
1609         int64_t end_units = to_units(end, 0);
1610 // Sample range of all edits selected
1611         //int64_t total_start_units = 0;
1612         //int64_t total_end_units = 0;
1613 // Edit before range
1614         Edit *start_edit = 0;
1615         int have_start_edit = 0;
1616
1617 // Move all edit pointers to list
1618         for(Edit *current = edits->first; current; )
1619         {
1620                 if(current->startproject >= start_units &&
1621                         current->startproject + current->length <= end_units)
1622                 {
1623                         if(!have_start_edit) start_edit = current->previous;
1624                         have_start_edit = 1;
1625                         //total_start_units = current->startproject;
1626                         //total_end_units = current->startproject + current->length;
1627                         new_edits.append(current);
1628
1629 // Move label pointers
1630                         if(first_track && edl->session->labels_follow_edits)
1631                         {
1632                                 double start_seconds = from_units(current->startproject);
1633                                 double end_seconds = from_units(current->startproject +
1634                                         current->length);
1635                                 for(Label *label = edl->labels->first;
1636                                         label;
1637                                         label = label->next)
1638                                 {
1639                                         if(label->position >= start_seconds &&
1640                                                 label->position < end_seconds)
1641                                         {
1642                                                 new_labels.append(label);
1643                                                 edl->labels->remove_pointer(label);
1644                                         }
1645                                 }
1646                         }
1647
1648 // Remove edit pointer
1649                         Edit *previous = current;
1650                         current = NEXT;
1651                         edits->remove_pointer(previous);
1652                 }
1653                 else
1654                 {
1655                         current = NEXT;
1656                 }
1657         }
1658
1659 // Insert pointers in reverse order
1660         while(new_edits.size())
1661         {
1662                 int index = new_edits.size() - 1;
1663                 Edit *edit = new_edits.get(index);
1664                 new_edits.remove_number(index);
1665                 if( !start_edit )
1666                         edits->insert_before(edits->first, edit);
1667                 else
1668                         edits->insert_after(start_edit, edit);
1669                 start_edit = edit;
1670
1671 // Recalculate start position
1672 // Save old position for moving labels
1673                 int64_t startproject1 = edit->startproject;
1674                 int64_t startproject2 = 0;
1675                 if(edit->previous)
1676                 {
1677                         edit->startproject =
1678                                 startproject2 =
1679                                 edit->previous->startproject + edit->previous->length;
1680                 }
1681                 else
1682                 {
1683                         edit->startproject = startproject2 = 0;
1684                 }
1685
1686
1687 // Insert label pointers
1688                 if(first_track && edl->session->labels_follow_edits)
1689                 {
1690                         double start_seconds1 = from_units(startproject1);
1691                         double end_seconds1 = from_units(startproject1 + edit->length);
1692                         double start_seconds2 = from_units(startproject2);
1693                         for(int i = new_labels.size() - 1; i >= 0; i--)
1694                         {
1695                                 Label *label = new_labels.get(i);
1696 // Was in old edit position
1697                                 if(label->position >= start_seconds1 &&
1698                                         label->position < end_seconds1)
1699                                 {
1700 // Move to new edit position
1701                                         double position = label->position -
1702                                                 start_seconds1 + start_seconds2;
1703                                         edl->labels->insert_label(position);
1704                                         new_labels.remove_object_number(i);
1705                                 }
1706                         }
1707                 }
1708
1709
1710         }
1711
1712         optimize();
1713
1714         if(first_track && edl->session->labels_follow_edits)
1715         {
1716                 edl->labels->optimize();
1717         }
1718 }
1719
1720 void Track::align_edits(double start,
1721         double end,
1722         ArrayList<double> *times)
1723 {
1724         int64_t start_units = to_units(start, 0);
1725         int64_t end_units = to_units(end, 0);
1726
1727 // If 1st track with data, times is empty & we need to collect the edit times.
1728         if(!times->size())
1729         {
1730                 for(Edit *current = edits->first; current; current = NEXT)
1731                 {
1732                         if(current->startproject >= start_units &&
1733                                 current->startproject + current->length <= end_units)
1734                         {
1735                                 times->append(from_units(current->startproject));
1736                         }
1737                 }
1738         }
1739         else
1740 // All other tracks get silence or cut to align the edits on the times.
1741         {
1742                 int current_time = 0;
1743                 for(Edit *current = edits->first;
1744                         current && current_time < times->size(); )
1745                 {
1746                         if(current->startproject >= start_units &&
1747                                 current->startproject + current->length <= end_units)
1748                         {
1749                                 int64_t desired_startunits = to_units(times->get(current_time), 0);
1750                                 int64_t current_startunits = current->startproject;
1751                                 current = NEXT;
1752
1753
1754                                 if(current_startunits < desired_startunits)
1755                                 {
1756 //printf("Track::align_edits %d\n", __LINE__);
1757                                         edits->paste_silence(current_startunits,
1758                                                 desired_startunits);
1759                                         shift_keyframes(current_startunits,
1760                                                 desired_startunits - current_startunits);
1761                                 }
1762                                 else
1763                                 if(current_startunits > desired_startunits)
1764                                 {
1765                                         edits->clear(desired_startunits,
1766                                                 current_startunits);
1767                                         if(edl->session->autos_follow_edits)
1768                                                 shift_keyframes(desired_startunits,
1769                                                         current_startunits - desired_startunits);
1770                                 }
1771
1772                                 current_time++;
1773                         }
1774                         else
1775                         {
1776                                 current = NEXT;
1777                         }
1778                 }
1779         }
1780
1781         optimize();
1782 }
1783
1784 int Track::purge_asset(Asset *asset)
1785 {
1786         return 0;
1787 }
1788
1789 int Track::asset_used(Asset *asset)
1790 {
1791         Edit* current_edit;
1792         int result = 0;
1793
1794         for(current_edit = edits->first; current_edit; current_edit = current_edit->next)
1795         {
1796                 if(current_edit->asset == asset)
1797                 {
1798                         result++;
1799                 }
1800         }
1801         return result;
1802 }
1803
1804 int Track::is_playable(int64_t position, int direction)
1805 {
1806         return 1;
1807 }
1808
1809
1810 int Track::plugin_used(int64_t position, int64_t direction)
1811 {
1812 //printf("Track::plugin_used 1 %d\n", this->plugin_set.total);
1813         for(int i = 0; i < this->plugin_set.total; i++)
1814         {
1815                 Plugin *current_plugin = get_current_plugin(position,
1816                         i,
1817                         direction,
1818                         0,
1819                         0);
1820
1821 //printf("Track::plugin_used 2 %p %d %d\n", current_plugin, current_plugin->on, current_plugin->plugin_type);
1822                 if(current_plugin &&
1823                         current_plugin->on &&
1824                         current_plugin->plugin_type != PLUGIN_NONE)
1825                 {
1826                         return 1;
1827                 }
1828         }
1829 //printf("Track::plugin_used 3 %p\n", current_plugin);
1830         return 0;
1831 }
1832
1833 // Audio is always rendered through VConsole
1834 int Track::direct_copy_possible(int64_t start, int direction, int use_nudge)
1835 {
1836         return 1;
1837 }
1838
1839 int64_t Track::to_units(double position, int round)
1840 {
1841         return (int64_t)position;
1842 }
1843
1844 double Track::to_doubleunits(double position)
1845 {
1846         return position;
1847 }
1848
1849 double Track::from_units(int64_t position)
1850 {
1851         return (double)position;
1852 }
1853
1854 int Track::plugin_exists(Plugin *plugin)
1855 {
1856         for(int number = 0; number < plugin_set.size(); number++)
1857         {
1858                 PluginSet *ptr = plugin_set.get(number);
1859                 for(Plugin *current_plugin = (Plugin*)ptr->first;
1860                         current_plugin;
1861                         current_plugin = (Plugin*)current_plugin->next)
1862                 {
1863                         if(current_plugin == plugin) return 1;
1864                 }
1865         }
1866
1867         for(Edit *current = edits->first; current; current = NEXT)
1868         {
1869                 if(current->transition &&
1870                         (Plugin*)current->transition == plugin) return 1;
1871         }
1872
1873
1874         return 0;
1875 }
1876