r1006: configure: Use libx264_pic instead of libx264 if available.
[cinelerra_cv/mob.git] / cinelerra / track.C
blob00e893fe83f8d468cd71ecfa47cbb34ad4bc66cf
1 #include "asset.h"
2 #include "autoconf.h"
3 #include "automation.h"
4 #include "bcsignals.h"
5 #include "clip.h"
6 #include "edit.h"
7 #include "edits.h"
8 #include "edl.h"
9 #include "edlsession.h"
10 #include "filexml.h"
11 #include "floatauto.h"
12 #include "floatautos.h"
13 #include "keyframe.h"
14 #include "localsession.h"
15 #include "module.h"
16 #include "patch.h"
17 #include "patchbay.h"
18 #include "plugin.h"
19 #include "pluginset.h"
20 #include "mainsession.h"
21 #include "theme.h"
22 #include "intautos.h"
23 #include "track.h"
24 #include "trackcanvas.h"
25 #include "tracks.h"
26 #include "transition.h"
27 #include "transportque.inc"
28 #include "vedit.h"
29 #include "vframe.h"
30 #include <string.h>
33 Track::Track(EDL *edl, Tracks *tracks) : ListItem<Track>()
35         this->edl = edl;
36         this->tracks = tracks;
37         y_pixel = 0;
38         expand_view = 0;
39         draw = 1;
40         gang = 1;
41         title[0] = 0;
42         record = 1;
43         play = 1;
44         nudge = 0;
45         track_w = edl->session->output_w;
46         track_h = edl->session->output_h;
47         id = EDL::next_id();
50 Track::~Track()
52         delete automation;
53         delete edits;
54         plugin_set.remove_all_objects();
57 int Track::create_objects()
59         return 0;
63 int Track::copy_settings(Track *track)
65         this->expand_view = track->expand_view;
66         this->draw = track->draw;
67         this->gang = track->gang;
68         this->record = track->record;
69         this->nudge = track->nudge;
70         this->play = track->play;
71         this->track_w = track->track_w;
72         this->track_h = track->track_h;
73         strcpy(this->title, track->title);
74         return 0;
77 int Track::get_id()
79         return id;
83 int Track::load_defaults(BC_Hash *defaults)
85         return 0;
88 void Track::equivalent_output(Track *track, double *result)
90         if(data_type != track->data_type ||
91                 track_w != track->track_w ||
92                 track_h != track->track_h ||
93                 play != track->play ||
94                 nudge != track->nudge)
95                 *result = 0;
97 // Convert result to track units
98         int64_t result2 = -1;
99         automation->equivalent_output(track->automation, &result2);
100         edits->equivalent_output(track->edits, &result2);
102         int plugin_sets = MIN(plugin_set.total, track->plugin_set.total);
103 // Test existing plugin sets
104         for(int i = 0; i < plugin_sets; i++)
105         {
106                 plugin_set.values[i]->equivalent_output(
107                         track->plugin_set.values[i], 
108                         &result2);
109         }
111 // New EDL has more plugin sets.  Get starting plugin in new plugin sets
112         for(int i = plugin_sets; i < plugin_set.total; i++)
113         {
114                 Plugin *current = plugin_set.values[i]->get_first_plugin();
115                 if(current)
116                 {
117                         if(result2 < 0 || current->startproject < result2)
118                                 result2 = current->startproject;
119                 }
120         }
122 // New EDL has fewer plugin sets.  Get starting plugin in old plugin set
123         for(int i = plugin_sets; i < track->plugin_set.total; i++)
124         {
125                 Plugin *current = track->plugin_set.values[i]->get_first_plugin();
126                 if(current)
127                 {
128                         if(result2 < 0 || current->startproject < result2)
129                                 result2 = current->startproject;
130                 }
131         }
133 // Number of plugin sets differs but somehow we didn't find the start of the
134 // change.  Assume 0
135         if(track->plugin_set.total != plugin_set.total && result2 < 0)
136                 result2 = 0;
138         if(result2 >= 0 && 
139                 (*result < 0 || from_units(result2) < *result))
140                 *result = from_units(result2);
144 int Track::is_synthesis(RenderEngine *renderengine, 
145         int64_t position, 
146         int direction)
148         int is_synthesis = 0;
149         for(int i = 0; i < plugin_set.total; i++)
150         {
151                 Plugin *plugin = get_current_plugin(position,
152                         i,
153                         direction,
154                         0,
155                         0);
156                 if(plugin)
157                 {
158 // Assume data from a shared track is synthesized
159                         if(plugin->plugin_type == PLUGIN_SHAREDMODULE) 
160                                 is_synthesis = 1;
161                         else
162                                 is_synthesis = plugin->is_synthesis(renderengine, 
163                                         position, 
164                                         direction);
165                         if(is_synthesis) break;
166                 }
167         }
168         return is_synthesis;
171 void Track::copy_from(Track *track)
173         copy_settings(track);
174         edits->copy_from(track->edits);
175         for(int i = 0; i < this->plugin_set.total; i++)
176                 delete this->plugin_set.values[i];
177         this->plugin_set.remove_all_objects();
179         for(int i = 0; i < track->plugin_set.total; i++)
180         {
181                 PluginSet *new_plugin_set = plugin_set.append(new PluginSet(edl, this));
182                 new_plugin_set->copy_from(track->plugin_set.values[i]);
183         }
184         automation->copy_from(track->automation);
185         this->track_w = track->track_w;
186         this->track_h = track->track_h;
189 Track& Track::operator=(Track& track)
191 printf("Track::operator= 1\n");
192         copy_from(&track);
193         return *this;
196 int Track::vertical_span(Theme *theme)
198         int result = 0;
199         if(expand_view)
200                 result = edl->local_session->zoom_track + 
201                         plugin_set.total * 
202                         theme->get_image("plugin_bg_data")->get_h();
203         else
204                 result = edl->local_session->zoom_track;
206         if(edl->session->show_titles)
207                 result += theme->get_image("title_bg_data")->get_h();
209         return result;
212 double Track::get_length()
214         double total_length = 0;
215         double length = 0;
217 // Test edits
218         int64_t unit_end;
219         unit_end = edits->last->startproject;
220         if (edits->last->transition)
221                 unit_end += edits->last->transition->length + 1; // add one so transition is finished...
222         length = from_units(unit_end);
223         if(length > total_length) total_length = length;
225 // Test plugins
226         for(int i = 0; i < plugin_set.total; i++)
227         {
228                 length = from_units(plugin_set.values[i]->last->startproject);
229                 if(length > total_length) total_length = length;
230         }
232 // Test keyframes
233         length = from_units(automation->get_length());
234         if(length > total_length) total_length = length;
235         
237         return total_length;
242 void Track::get_source_dimensions(double position, int &w, int &h)
244         int64_t native_position = to_units(position, 0);
245         for(Edit *current = edits->first; current; current = NEXT)
246         {
247                 if(current->startproject <= native_position &&
248                         current->startproject + current->length > native_position &&
249                         current->asset)
250                 {
251                         w = current->asset->width;
252                         h = current->asset->height;
253                         return;
254                 }
255         }
259 int64_t Track::horizontal_span()
261         return (int64_t)(get_length() * 
262                 edl->session->sample_rate / 
263                 edl->local_session->zoom_sample + 
264                 0.5);
268 int Track::load(FileXML *file, int track_offset, uint32_t load_flags)
270         int result = 0;
271         int current_channel = 0;
272         int current_plugin = 0;
275         record = file->tag.get_property("RECORD", record);
276         play = file->tag.get_property("PLAY", play);
277         gang = file->tag.get_property("GANG", gang);
278         draw = file->tag.get_property("DRAW", draw);
279         nudge = file->tag.get_property("NUDGE", nudge);
280         expand_view = file->tag.get_property("EXPAND", expand_view);
281         track_w = file->tag.get_property("TRACK_W", track_w);
282         track_h = file->tag.get_property("TRACK_H", track_h);
284         load_header(file, load_flags);
286         do{
287                 result = file->read_tag();
289                 if(!result)
290                 {
291                         if(file->tag.title_is("/TRACK"))
292                         {
293                                 result = 1;
294                         }
295                         else
296                         if(file->tag.title_is("TITLE"))
297                         {
298                                 file->read_text_until("/TITLE", title, BCTEXTLEN);
299                         }
300                         else
301                         if(load_flags && automation->load(file)
302                         /* strstr(file->tag.get_title(), "AUTOS") */)
303                         {
304                                 ;
305                         }
306                         else
307                         if(file->tag.title_is("EDITS"))
308                         {
309                                 if(load_flags & LOAD_EDITS)
310                                         edits->load(file, track_offset);
311                         }
312                         else
313                         if(file->tag.title_is("PLUGINSET"))
314                         {
315                                 if(load_flags & LOAD_EDITS)
316                                 {
317                                         PluginSet *plugin_set = new PluginSet(edl, this);
318                                         this->plugin_set.append(plugin_set);
319                                         plugin_set->load(file, load_flags);
320                                 }
321                                 else
322                                 if(load_flags & LOAD_AUTOMATION)
323                                 {
324                                         if(current_plugin < this->plugin_set.total)
325                                         {
326                                                 PluginSet *plugin_set = this->plugin_set.values[current_plugin];
327                                                 plugin_set->load(file, load_flags);
328                                                 current_plugin++;
329                                         }
330                                 }
331                         }
332                         else
333                                 load_derived(file, load_flags);
334                 }
335         }while(!result);
339         return 0;
342 void Track::insert_asset(Asset *asset, 
343                 double length, 
344                 double position, 
345                 int track_number)
347 //printf("Track::insert_asset %f\n", length);
348         edits->insert_asset(asset, 
349                 to_units(length, 1), 
350                 to_units(position, 0), 
351                 track_number);
352         edits->loaded_length += to_units(length, 1);
355 // Insert data
357 // Default keyframes: We don't replace default keyframes in pasting but
358 // when inserting the first EDL of a load operation we need to replace
359 // the default keyframes.
361 // Plugins:  This is an arbitrary behavior
363 // 1) No plugin in source track: Paste silence into destination
364 // plugin sets.
365 // 2) Plugin in source track: plugin in source track is inserted into
366 // existing destination track plugin sets, new sets being added when
367 // necessary.
369 void Track::insert_track(Track *track, 
370         double position, 
371         int replace_default,
372         int edit_plugins)
375 // Decide whether to copy settings based on load_mode
376         if(replace_default) copy_settings(track);
378         edits->insert_edits(track->edits, to_units(position, 0));
380         if(edit_plugins)
381                 insert_plugin_set(track, position);
383         automation->insert_track(track->automation, 
384                 to_units(position, 0), 
385                 to_units(track->get_length(), 1),
386                 replace_default);
388         optimize();
392 // Called by insert_track
393 void Track::insert_plugin_set(Track *track, double position)
395 // Extend plugins if no incoming plugins
396         if(!track->plugin_set.total)
397         {
398                 shift_effects(position, 
399                         track->get_length(), 
400                         1);
401         }
402         else
403         for(int i = 0; i < track->plugin_set.total; i++)
404         {
405                 if(i >= plugin_set.total)
406                         plugin_set.append(new PluginSet(edl, this));
408                 plugin_set.values[i]->insert_edits(track->plugin_set.values[i], 
409                         to_units(position, 0));
410         }
414 Plugin* Track::insert_effect(char *title, 
415                 SharedLocation *shared_location, 
416                 KeyFrame *default_keyframe,
417                 PluginSet *plugin_set,
418                 double start,
419                 double length,
420                 int plugin_type)
422         if(!plugin_set)
423         {
424                 plugin_set = new PluginSet(edl, this);
425                 this->plugin_set.append(plugin_set);
426         }
428         Plugin *plugin = 0;
430 // Position is identical to source plugin
431         if(plugin_type == PLUGIN_SHAREDPLUGIN)
432         {
433                 Track *source_track = tracks->get_item_number(shared_location->module);
434                 if(source_track)
435                 {
436                         Plugin *source_plugin = source_track->get_current_plugin(
437                                 edl->local_session->get_selectionstart(), 
438                                 shared_location->plugin, 
439                                 PLAY_FORWARD, 
440                                 1,
441                                 0);
443 // From an attach operation
444                         if(source_plugin)
445                         {
446                                 plugin = plugin_set->insert_plugin(title, 
447                                         source_plugin->startproject, 
448                                         source_plugin->length,
449                                         plugin_type, 
450                                         shared_location,
451                                         default_keyframe,
452                                         1);
453                         }
454                         else
455 // From a drag operation
456                         {
457                                 plugin = plugin_set->insert_plugin(title, 
458                                         to_units(start, 0), 
459                                         to_units(length, 1),
460                                         plugin_type, 
461                                         shared_location,
462                                         default_keyframe,
463                                         1);
464                         }
465                 }
466         }
467         else
468         {
469 // This should be done in the caller
470                 if(EQUIV(length, 0))
471                 {
472                         if(edl->local_session->get_selectionend() > 
473                                 edl->local_session->get_selectionstart())
474                         {
475                                 start = edl->local_session->get_selectionstart();
476                                 length = edl->local_session->get_selectionend() - start;
477                         }
478                         else
479                         {
480                                 start = 0;
481                                 length = get_length();
482                         }
483                 }
484 //printf("Track::insert_effect %f %f %d %d\n", start, length, to_units(start, 0), 
485 //                      to_units(length, 0));
487                 plugin = plugin_set->insert_plugin(title, 
488                         to_units(start, 0), 
489                         to_units(length, 1),
490                         plugin_type, 
491                         shared_location,
492                         default_keyframe,
493                         1);
494         }
495 //printf("Track::insert_effect 2 %f %f\n", start, length);
497         expand_view = 1;
498         return plugin;
501 void Track::move_plugins_up(PluginSet *plugin_set)
503         for(int i = 0; i < this->plugin_set.total; i++)
504         {
505                 if(this->plugin_set.values[i] == plugin_set)
506                 {
507                         if(i == 0) break;
509                         PluginSet *temp = this->plugin_set.values[i - 1];
510                         this->plugin_set.values[i - 1] = this->plugin_set.values[i];
511                         this->plugin_set.values[i] = temp;
513                         SharedLocation old_location, new_location;
514                         new_location.module = old_location.module = tracks->number_of(this);
515                         old_location.plugin = i;
516                         new_location.plugin = i - 1;
517                         tracks->change_plugins(old_location, new_location, 1);
518                         break;
519                 }
520         }
523 void Track::move_plugins_down(PluginSet *plugin_set)
525         for(int i = 0; i < this->plugin_set.total; i++)
526         {
527                 if(this->plugin_set.values[i] == plugin_set)
528                 {
529                         if(i == this->plugin_set.total - 1) break;
531                         PluginSet *temp = this->plugin_set.values[i + 1];
532                         this->plugin_set.values[i + 1] = this->plugin_set.values[i];
533                         this->plugin_set.values[i] = temp;
535                         SharedLocation old_location, new_location;
536                         new_location.module = old_location.module = tracks->number_of(this);
537                         old_location.plugin = i;
538                         new_location.plugin = i + 1;
539                         tracks->change_plugins(old_location, new_location, 1);
540                         break;
541                 }
542         }
546 void Track::remove_asset(Asset *asset)
548         for(Edit *edit = edits->first; edit; edit = edit->next)
549         {
550                 if(edit->asset && edit->asset == asset)
551                 {
552                         edit->asset = 0;
553                 }
554         }
555         optimize();
558 void Track::remove_pluginset(PluginSet *plugin_set)
560         int i;
561         for(i = 0; i < this->plugin_set.total; i++)
562                 if(plugin_set == this->plugin_set.values[i]) break;
564         this->plugin_set.remove_object(plugin_set);
565         for(i++ ; i < this->plugin_set.total; i++)
566         {
567                 SharedLocation old_location, new_location;
568                 new_location.module = old_location.module = tracks->number_of(this);
569                 old_location.plugin = i;
570                 new_location.plugin = i - 1;
571                 tracks->change_plugins(old_location, new_location, 0);
572         }
575 void Track::shift_keyframes(double position, double length, int convert_units)
577         if(convert_units)
578         {
579                 position = to_units(position, 0);
580                 length = to_units(length, 1);
581         }
583         automation->paste_silence(Units::to_int64(position), 
584                 Units::to_int64(position + length));
585 // Effect keyframes are shifted in shift_effects
588 void Track::shift_effects(double position, double length, int convert_units)
590         if(convert_units)
591         {
592                 position = to_units(position, 0);
593                 length = to_units(length, 1);
594         }
596         for(int i = 0; i < plugin_set.total; i++)
597         {
598                 plugin_set.values[i]->shift_effects(Units::to_int64(position), Units::to_int64(length));
599         }
602 void Track::detach_effect(Plugin *plugin)
604 //printf("Track::detach_effect 1\n");           
605         for(int i = 0; i < plugin_set.total; i++)
606         {
607                 PluginSet *plugin_set = this->plugin_set.values[i];
608                 for(Plugin *dest = (Plugin*)plugin_set->first; 
609                         dest; 
610                         dest = (Plugin*)dest->next)
611                 {
612                         if(dest == plugin)
613                         {
614                                 int64_t start = plugin->startproject;
615                                 int64_t end = plugin->startproject + plugin->length;
617                                 plugin_set->clear(start, end);
618                                 plugin_set->paste_silence(start, end);
620 // Delete 0 length pluginsets   
621                                 plugin_set->optimize();
622 //printf("Track::detach_effect 2 %d\n", plugin_set->length());
623                                 if(plugin_set->last == plugin_set->first && plugin_set->last->silence())
624                                         remove_pluginset(plugin_set);
625                                 return;
626                         }
627                 }
628         }
631 void Track::resample(double old_rate, double new_rate)
633         edits->resample(old_rate, new_rate);
634         automation->resample(old_rate, new_rate);
635         for(int i = 0; i < plugin_set.total; i++)
636                 plugin_set.values[i]->resample(old_rate, new_rate);
637         nudge = (int64_t)(nudge * new_rate / old_rate);
640 void Track::detach_shared_effects(int module)
642         for(int i = 0; i < plugin_set.total; i++)
643         {
644                 PluginSet *plugin_set = this->plugin_set.values[i];
645                 for(Plugin *dest = (Plugin*)plugin_set->first; 
646                         dest; 
647                         dest = (Plugin*)dest->next)
648                 {
649                         if ((dest->plugin_type == PLUGIN_SHAREDPLUGIN ||
650                                 dest->plugin_type == PLUGIN_SHAREDMODULE)
651                             &&
652                                 dest->shared_location.module == module)
653                         {
654                                 int64_t start = dest->startproject;
655                                 int64_t end = dest->startproject + dest->length;
657                                 plugin_set->clear(start, end);
658                                 plugin_set->paste_silence(start, end);
660 // Delete 0 length pluginsets   
661                                 plugin_set->optimize();
662                                 if(plugin_set->last == plugin_set->first && plugin_set->last->silence())
663                                 {
664                                         this->plugin_set.remove_object_number(i);
665                                         --i;
666                                 }
667                         }
668                 }
669         }
673 void Track::optimize()
675         edits->optimize();
676         for(int i = 0; i < plugin_set.total; i++)
677         {
678                 PluginSet *plugin_set = this->plugin_set.values[i];
679                 plugin_set->optimize();
680 //printf("Track::optimize %d\n", plugin_set.values[i]->total());
681 // new definition of empty track...
682                 if(plugin_set->last == plugin_set->first && plugin_set->last->silence())
683                 {
684                         remove_pluginset(plugin_set);
685                         i--;
686                 }
687         }
690 Plugin* Track::get_current_plugin(double position, 
691         int plugin_set, 
692         int direction, 
693         int convert_units,
694         int use_nudge)
696         Plugin *current;
697         if(convert_units) position = to_units(position, 0);
698         if(use_nudge) position += nudge;
699         
700         if(plugin_set >= this->plugin_set.total || plugin_set < 0) return 0;
702 //printf("Track::get_current_plugin 1 %d %d %d\n", position, this->plugin_set.total, direction);
703         if(direction == PLAY_FORWARD)
704         {
705                 for(current = (Plugin*)this->plugin_set.values[plugin_set]->last; 
706                         current; 
707                         current = (Plugin*)PREVIOUS)
708                 {
709 // printf("Track::get_current_plugin 2 %d %ld %ld\n", 
710 // current->startproject, 
711 // current->startproject + current->length, 
712 // position);
713                         if(current->startproject <= position && 
714                                 current->startproject + current->length > position)
715                         {
716                                 return current;
717                         }
718                 }
719         }
720         else
721         if(direction == PLAY_REVERSE)
722         {
723                 for(current = (Plugin*)this->plugin_set.values[plugin_set]->first; 
724                         current; 
725                         current = (Plugin*)NEXT)
726                 {
727                         if(current->startproject < position && 
728                                 current->startproject + current->length >= position)
729                         {
730                                 return current;
731                         }
732                 }
733         }
735         return 0;
738 Plugin* Track::get_current_transition(double position, 
739         int direction, 
740         int convert_units,
741         int use_nudge)
743         Edit *current;
744         Plugin *result = 0;
745         if(convert_units) position = to_units(position, 0);
746         if(use_nudge) position += nudge;
748         if(direction == PLAY_FORWARD)
749         {
750                 for(current = edits->last; current; current = PREVIOUS)
751                 {
752                         if(current->startproject <= position && current->startproject + current->length > position)
753                         {
754 //printf("Track::get_current_transition %p\n", current->transition);
755                                 if(current->transition && position < current->startproject + current->transition->length)
756                                 {
757                                         result = current->transition;
758                                         break;
759                                 }
760                         }
761                 }
762         }
763         else
764         if(direction == PLAY_REVERSE)
765         {
766                 for(current = edits->first; current; current = NEXT)
767                 {
768                         if(current->startproject < position && current->startproject + current->length >= position)
769                         {
770                                 if(current->transition && position <= current->startproject + current->transition->length)
771                                 {
772                                         result = current->transition;
773                                         break;
774                                 }
775                         }
776                 }
777         }
779         return result;
782 void Track::synchronize_params(Track *track)
784         for(Edit *this_edit = edits->first, *that_edit = track->edits->first;
785                 this_edit && that_edit;
786                 this_edit = this_edit->next, that_edit = that_edit->next)
787         {
788                 this_edit->synchronize_params(that_edit);
789         }
791         for(int i = 0; i < plugin_set.total && i < track->plugin_set.total; i++)
792                 plugin_set.values[i]->synchronize_params(track->plugin_set.values[i]);
794         automation->copy_from(track->automation);
795         this->nudge = track->nudge;
802 int Track::dump()
804         printf("   Data type %d\n", data_type);
805         printf("   Title %s\n", title);
806         printf("   Edits:\n");
807         for(Edit* current = edits->first; current; current = NEXT)
808         {
809                 current->dump();
810         }
811         automation->dump();
812         printf("   Plugin Sets: %d\n", plugin_set.total);
814         for(int i = 0; i < plugin_set.total; i++)
815                 plugin_set.values[i]->dump();
816 //printf("Track::dump 2\n");
817         return 0;
840 Track::Track() : ListItem<Track>()
842         y_pixel = 0;
845 // ======================================== accounting
847 int Track::number_of() 
849         return tracks->number_of(this); 
856         
857         
864 // ================================================= editing
866 int Track::select_auto(AutoConf *auto_conf, int cursor_x, int cursor_y)
868         return 0;
871 int Track::move_auto(AutoConf *auto_conf, int cursor_x, int cursor_y, int shift_down)
873         return 0;
876 int Track::release_auto()
878         return 0;
881 // used for copying automation alone
882 int Track::copy_automation(double selectionstart, 
883         double selectionend, 
884         FileXML *file,
885         int default_only,
886         int autos_only)
888         int64_t start = to_units(selectionstart, 0);
889         int64_t end = to_units(selectionend, 1);
891         file->tag.set_title("TRACK");
892 // Video or audio
893     save_header(file);
894         file->append_tag();
895         file->append_newline();
897         automation->copy(start, end, file, default_only, autos_only);
899         if(edl->session->auto_conf->plugins)
900         {
901                 file->tag.set_title("PLUGINSETS");
902                 file->append_tag();
903                 file->append_newline();
904                 for(int i = 0; i < plugin_set.total; i++)
905                 {
906                 
907                         plugin_set.values[i]->copy_keyframes(start, 
908                                 end, 
909                                 file, 
910                                 default_only,
911                                 autos_only);
912                 }
913                 file->tag.set_title("/PLUGINSETS");
914                 file->append_tag();
915                 file->append_newline();
916         }
918         file->tag.set_title("/TRACK");
919         file->append_tag();
920         file->append_newline();
921         file->append_newline();
922         file->append_newline();
923         file->append_newline();
925         return 0;
928 int Track::paste_automation(double selectionstart, 
929         double total_length, 
930         double frame_rate,
931         int64_t sample_rate,
932         FileXML *file,
933         int default_only)
935 // Only used for pasting automation alone.
936         int64_t start;
937         int64_t length;
938         int result;
939         double scale;
941         if(data_type == TRACK_AUDIO)
942                 scale = edl->session->sample_rate / sample_rate;
943         else
944                 scale = edl->session->frame_rate / frame_rate;
946         total_length *= scale;
947         start = to_units(selectionstart, 0);
948         length = to_units(total_length, 1);
949         result = 0;
950 //printf("Track::paste_automation 1\n");
952         while(!result)
953         {
954                 result = file->read_tag();
956                 if(!result)
957                 {
958                         if(file->tag.title_is("/TRACK"))
959                                 result = 1;
960                         else
961                         if(automation->paste(start, 
962                                         length, 
963                                         scale,
964                                         file,
965                                         default_only,
966                                         0))
967                         /* strstr(file->tag.get_title(), "AUTOS")) */
968                         {
969                                 ;
970                         }
971                         else
972                         if(file->tag.title_is("PLUGINSETS"))
973                         {
974 //printf("Track::paste_automation 2 %d\n", current_pluginset);
975                                 PluginSet::paste_keyframes(start, 
976                                         length, 
977                                         file,
978                                         default_only,
979                                         this);
980                         }
981                 }
982         }
983 //printf("Track::paste_automation 3\n");
984         
986         return 0;
989 void Track::clear_automation(double selectionstart, 
990         double selectionend, 
991         int shift_autos,
992         int default_only)
994         int64_t start = to_units(selectionstart, 0);
995         int64_t end = to_units(selectionend, 1);
997         automation->clear(start, end, edl->session->auto_conf, 0);
999         if(edl->session->auto_conf->plugins)
1000         {
1001                 for(int i = 0; i < plugin_set.total; i++)
1002                 {
1003                         plugin_set.values[i]->clear_keyframes(start, end);
1004                 }
1005         }
1009 void Track::straighten_automation(double selectionstart, 
1010         double selectionend)
1012         int64_t start = to_units(selectionstart, 0);
1013         int64_t end = to_units(selectionend, 1);
1015         automation->straighten(start, end, edl->session->auto_conf);
1021 int Track::copy(double start, 
1022         double end, 
1023         FileXML *file, 
1024         char *output_path)
1026 // Use a copy of the selection in converted units
1027 // So copy_automation doesn't reconvert.
1028         int64_t start_unit = to_units(start, 0);
1029         int64_t end_unit = to_units(end, 1);
1034         file->tag.set_title("TRACK");
1035         file->tag.set_property("RECORD", record);
1036         file->tag.set_property("NUDGE", nudge);
1037         file->tag.set_property("PLAY", play);
1038         file->tag.set_property("GANG", gang);
1039         file->tag.set_property("DRAW", draw);
1040         file->tag.set_property("EXPAND", expand_view);
1041         file->tag.set_property("TRACK_W", track_w);
1042         file->tag.set_property("TRACK_H", track_h);
1043         save_header(file);
1044         file->append_tag();
1045         file->append_newline();
1046         save_derived(file);
1048         file->tag.set_title("TITLE");
1049         file->append_tag();
1050         file->append_text(title);
1051         file->tag.set_title("/TITLE");
1052         file->append_tag();
1053         file->append_newline();
1055 //      if(data_type == TRACK_AUDIO)
1056 //              file->tag.set_property("TYPE", "AUDIO");
1057 //      else
1058 //              file->tag.set_property("TYPE", "VIDEO");
1059 // 
1060 //      file->append_tag();
1061 //      file->append_newline();
1063         edits->copy(start_unit, end_unit, file, output_path);
1065         AutoConf auto_conf;
1066         auto_conf.set_all(1);
1067         automation->copy(start_unit, end_unit, file, 0, 0);
1070         for(int i = 0; i < plugin_set.total; i++)
1071         {
1072                 plugin_set.values[i]->copy(start_unit, end_unit, file);
1073         }
1075         copy_derived(start_unit, end_unit, file);
1077         file->tag.set_title("/TRACK");
1078         file->append_tag();
1079         file->append_newline();
1080         file->append_newline();
1081         file->append_newline();
1082         file->append_newline();
1084         return 0;
1087 int Track::copy_assets(double start, 
1088         double end, 
1089         ArrayList<Asset*> *asset_list)
1091         int i, result = 0;
1093         start = to_units(start, 0);
1094         end = to_units(end, 1);
1096         Edit *current = edits->editof((int64_t)start, PLAY_FORWARD, 0);
1098 // Search all edits
1099         while(current && current->startproject < end)
1100         {
1101 // Check for duplicate assets
1102                 if(current->asset)
1103                 {
1104                         for(i = 0, result = 0; i < asset_list->total; i++)
1105                         {
1106                                 if(asset_list->values[i] == current->asset) result = 1;
1107                         }
1108 // append pointer to new asset
1109                         if(!result) asset_list->append(current->asset);
1110                 }
1112                 current = NEXT;
1113         }
1115         return 0;
1122 int Track::clear(double start, 
1123         double end, 
1124         int edit_edits,
1125         int edit_labels,
1126         int edit_plugins,
1127         int convert_units,
1128         Edits *trim_edits)
1130 // Edits::move_auto calls this routine after the units are converted to the track
1131 // format.
1132 //printf("Track::clear 1 %d %d %d\n", edit_edits, edit_labels, edit_plugins);
1133         if(convert_units)
1134         {
1135                 start = to_units(start, 0);
1136                 end = to_units(end, 1);
1137         }
1139         if(edit_edits)
1140                 automation->clear((int64_t)start, (int64_t)end, 0, 1);
1142         if(edit_plugins)
1143                 for(int i = 0; i < plugin_set.total; i++)
1144                 {
1145                         if(!trim_edits || trim_edits == (Edits*)plugin_set.values[i])
1146                                 plugin_set.values[i]->clear((int64_t)start, (int64_t)end);
1147                 }
1149         if(edit_edits)
1150                 edits->clear((int64_t)start, (int64_t)end);
1151         return 0;
1154 int Track::clear_handle(double start, 
1155         double end, 
1156         int clear_labels,
1157         int clear_plugins, 
1158         double &distance)
1160         edits->clear_handle(start, end, clear_plugins, distance);
1163 int Track::popup_transition(int cursor_x, int cursor_y)
1165         return 0;
1170 int Track::modify_edithandles(double oldposition, 
1171         double newposition, 
1172         int currentend, 
1173         int handle_mode,
1174         int edit_labels,
1175         int edit_plugins)
1177         edits->modify_handles(oldposition, 
1178                 newposition, 
1179                 currentend,
1180                 handle_mode,
1181                 1,
1182                 edit_labels,
1183                 edit_plugins,
1184                 0);
1187         return 0;
1190 int Track::modify_pluginhandles(double oldposition, 
1191         double newposition, 
1192         int currentend, 
1193         int handle_mode,
1194         int edit_labels,
1195         Edits *trim_edits)
1197         for(int i = 0; i < plugin_set.total; i++)
1198         {
1199                 if(!trim_edits || trim_edits == (Edits*)plugin_set.values[i])
1200                         plugin_set.values[i]->modify_handles(oldposition, 
1201                                 newposition, 
1202                                 currentend, 
1203                                 handle_mode,
1204 // Don't allow plugin tweeks to affect edits.
1205                                 0,
1206                                 edit_labels,
1207                                 1,
1208                                 trim_edits);
1209         }
1210         return 0;
1214 int Track::paste_silence(double start, double end, int edit_plugins)
1216         start = to_units(start, 0);
1217         end = to_units(end, 1);
1219         edits->paste_silence((int64_t)start, (int64_t)end);
1220         shift_keyframes(start, end - start, 0);
1221         if(edit_plugins) shift_effects(start, end - start, 0);
1223         edits->optimize();
1224         return 0;
1227 int Track::select_edit(int cursor_x, 
1228         int cursor_y, 
1229         double &new_start, 
1230         double &new_end)
1232         return 0;
1235 int Track::scale_time(float rate_scale, int scale_edits, int scale_autos, int64_t start, int64_t end)
1237         return 0;
1240 void Track::change_plugins(SharedLocation &old_location, SharedLocation &new_location, int do_swap)
1242         for(int i = 0; i < plugin_set.total; i++)
1243         {
1244                 for(Plugin *plugin = (Plugin*)plugin_set.values[i]->first; 
1245                         plugin; 
1246                         plugin = (Plugin*)plugin->next)
1247                 {
1248                         if(plugin->plugin_type == PLUGIN_SHAREDPLUGIN)
1249                         {
1250                                 if(plugin->shared_location == old_location)
1251                                         plugin->shared_location = new_location;
1252                                 else
1253                                 if(do_swap && plugin->shared_location == new_location)
1254                                         plugin->shared_location = old_location;
1255                         }
1256                 }
1257         }
1260 void Track::change_modules(int old_location, int new_location, int do_swap)
1262         for(int i = 0; i < plugin_set.total; i++)
1263         {
1264                 for(Plugin *plugin = (Plugin*)plugin_set.values[i]->first; 
1265                         plugin; 
1266                         plugin = (Plugin*)plugin->next)
1267                 {
1268                         if(plugin->plugin_type == PLUGIN_SHAREDPLUGIN ||
1269                                 plugin->plugin_type == PLUGIN_SHAREDMODULE)
1270                         {
1271                                 if(plugin->shared_location.module == old_location)
1272                                         plugin->shared_location.module = new_location;
1273                                 else
1274                                 if(do_swap && plugin->shared_location.module == new_location)
1275                                         plugin->shared_location.module = old_location;
1276                         }
1277                 }
1278         }
1282 int Track::playable_edit(int64_t position, int direction)
1284         int result = 0;
1285         if(direction == PLAY_REVERSE) position--;
1286         for(Edit *current = edits->first; current && !result; current = NEXT)
1287         {
1288                 if(current->startproject <= position && 
1289                         current->startproject + current->length > position)
1290                 {
1291 //printf("Track::playable_edit %p %p\n", current->transition, current->asset);
1292                         if(current->transition || current->asset) result = 1;
1293                 }
1294         }
1295         return result;
1299 int Track::need_edit(Edit *current, int test_transitions)
1301         return ((test_transitions && current->transition) ||
1302                 (!test_transitions && current->asset));
1305 int64_t Track::plugin_change_duration(int64_t input_position,
1306         int64_t input_length,
1307         int reverse,
1308         int use_nudge)
1310         if(use_nudge) input_position += nudge;
1311         for(int i = 0; i < plugin_set.total; i++)
1312         {
1313                 int64_t new_duration = plugin_set.values[i]->plugin_change_duration(
1314                         input_position, 
1315                         input_length, 
1316                         reverse);
1317                 if(new_duration < input_length) input_length = new_duration;
1318         }
1319         return input_length;
1322 int64_t Track::edit_change_duration(int64_t input_position, 
1323         int64_t input_length, 
1324         int reverse, 
1325         int test_transitions,
1326         int use_nudge)
1328         Edit *current;
1329         int64_t edit_length = input_length;
1330         if(use_nudge) input_position += nudge;
1332         if(reverse)
1333         {
1334 // ================================= Reverse playback
1335 // Get first edit on or after position
1336                 for(current = edits->first; 
1337                         current && current->startproject + current->length <= input_position;
1338                         current = NEXT)
1339                         ;
1341                 if(current)
1342                 {
1343                         if(current->startproject > input_position)
1344                         {
1345 // Before first edit
1346                                 ;
1347                         }
1348                         else
1349                         if(need_edit(current, test_transitions))
1350                         {
1351 // Over an edit of interest.
1352                                 if(input_position - current->startproject < input_length)
1353                                         edit_length = input_position - current->startproject + 1;
1354                         }
1355                         else
1356                         {
1357 // Over an edit that isn't of interest.
1358 // Search for next edit of interest.
1359                                 for(current = PREVIOUS ; 
1360                                         current && 
1361                                         current->startproject + current->length > input_position - input_length &&
1362                                         !need_edit(current, test_transitions);
1363                                         current = PREVIOUS)
1364                                         ;
1366                                         if(current && 
1367                                                 need_edit(current, test_transitions) &&
1368                                                 current->startproject + current->length > input_position - input_length)
1369                         edit_length = input_position - current->startproject - current->length + 1;
1370                         }
1371                 }
1372                 else
1373                 {
1374 // Not over an edit.  Try the last edit.
1375                         current = edits->last;
1376                         if(current && 
1377                                 ((test_transitions && current->transition) ||
1378                                 (!test_transitions && current->asset)))
1379                                 edit_length = input_position - edits->length() + 1;
1380                 }
1381         }
1382         else
1383         {
1384 // =================================== forward playback
1385 // Get first edit on or before position
1386                 for(current = edits->last; 
1387                         current && current->startproject > input_position;
1388                         current = PREVIOUS)
1389                         ;
1391                 if(current)
1392                 {
1393                         if(current->startproject + current->length <= input_position)
1394                         {
1395 // Beyond last edit.
1396                                 ;
1397                         }
1398                         else
1399                         if(need_edit(current, test_transitions))
1400                         {
1401 // Over an edit of interest.
1402 // Next edit is going to require a change.
1403                                 if(current->length + current->startproject - input_position < input_length)
1404                                         edit_length = current->startproject + current->length - input_position;
1405                         }
1406                         else
1407                         {
1408 // Over an edit that isn't of interest.
1409 // Search for next edit of interest.
1410                                 for(current = NEXT ; 
1411                                         current && 
1412                                         current->startproject < input_position + input_length &&
1413                                         !need_edit(current, test_transitions);
1414                                         current = NEXT)
1415                                         ;
1417                                         if(current && 
1418                                                 need_edit(current, test_transitions) &&
1419                                                 current->startproject < input_position + input_length) 
1420                                                 edit_length = current->startproject - input_position;
1421                         }
1422                 }
1423                 else
1424                 {
1425 // Not over an edit.  Try the first edit.
1426                         current = edits->first;
1427                         if(current && 
1428                                 ((test_transitions && current->transition) ||
1429                                 (!test_transitions && current->asset)))
1430                                 edit_length = edits->first->startproject - input_position;
1431                 }
1432         }
1434         if(edit_length < input_length)
1435                 return edit_length;
1436         else
1437                 return input_length;
1440 int Track::purge_asset(Asset *asset)
1442         return 0;
1445 int Track::asset_used(Asset *asset)
1447         Edit* current_edit;
1448         int result = 0;
1450         for(current_edit = edits->first; current_edit; current_edit = current_edit->next)
1451         {
1452                 if(current_edit->asset == asset)
1453                 {
1454                         result++;
1455                 }
1456         }
1457         return result;
1460 int Track::is_playable(int64_t position, int direction)
1462         return 1;
1466 int Track::plugin_used(int64_t position, int64_t direction)
1468 //printf("Track::plugin_used 1 %d\n", this->plugin_set.total);
1469         for(int i = 0; i < this->plugin_set.total; i++)
1470         {
1471                 Plugin *current_plugin = get_current_plugin(position, 
1472                         i, 
1473                         direction, 
1474                         0,
1475                         0);
1477 //printf("Track::plugin_used 2 %p\n", current_plugin);
1478                 if(current_plugin && 
1479                         (current_plugin->on && 
1480                         current_plugin->plugin_type != PLUGIN_NONE))
1481                 {
1482                         return 1;
1483                 }
1484         }
1485 //printf("Track::plugin_used 3 %p\n", current_plugin);
1486         return 0;
1489 // Audio is always rendered through VConsole
1490 int Track::direct_copy_possible(int64_t start, int direction, int use_nudge)
1492         return 1;
1495 int64_t Track::to_units(double position, int round)
1497         return (int64_t)position;
1500 double Track::to_doubleunits(double position)
1502         return position;
1505 double Track::from_units(int64_t position)
1507         return (double)position;