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