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