r105: This commit was manufactured by cvs2svn to create tag
[cinelerra_cv/mob.git] / hvirtual / cinelerra / track.C
blob03359ce4b98f4a30b52ee594c1efc073a05dc618
1 #include "assets.h"
2 #include "autoconf.h"
3 #include "automation.h"
4 #include "clip.h"
5 #include "edit.h"
6 #include "edits.h"
7 #include "edl.h"
8 #include "edlsession.h"
9 #include "filexml.h"
10 #include "floatauto.h"
11 #include "floatautos.h"
12 #include "keyframe.h"
13 #include "localsession.h"
14 #include "module.h"
15 #include "patch.h"
16 #include "patchbay.h"
17 #include "plugin.h"
18 #include "pluginset.h"
19 #include "mainsession.h"
20 #include "theme.h"
21 #include "intautos.h"
22 #include "track.h"
23 #include "trackcanvas.h"
24 #include "tracks.h"
25 #include "transition.h"
26 #include "transportque.inc"
27 #include "vedit.h"
28 #include "vframe.h"
29 #include <string.h>
32 Track::Track(EDL *edl, Tracks *tracks) : ListItem<Track>()
34         this->edl = edl;
35         this->tracks = tracks;
36         y_pixel = 0;
37         expand_view = 0;
38         draw = 1;
39         gang = 1;
40         title[0] = 0;
41         record = 1;
42         play = 1;
43         track_w = edl->session->output_w;
44         track_h = edl->session->output_h;
45         id = EDL::next_id();
48 Track::~Track()
50         delete automation;
51         delete edits;
52 //for(int i = 0; i < plugin_set.total; i++)
53 //      printf("Track::~Track %p %p\n", plugin_set.values[i], plugin_set.values[i]->last);
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->play = track->play;
70         this->track_w = track->track_w;
71         this->track_h = track->track_h;
72         strcpy(this->title, track->title);
73         return 0;
76 int Track::get_id()
78         return id;
82 int Track::load_defaults(Defaults *defaults)
84         return 0;
87 void Track::equivalent_output(Track *track, double *result)
89         if(data_type != track->data_type ||
90                 track_w != track->track_w ||
91                 track_h != track->track_h ||
92                 play != track->play)
93                 *result = 0;
95 // Convert result to track units
96         int64_t result2 = -1;
97         automation->equivalent_output(track->automation, &result2);
98 //printf("Track::equivalent_output 3 %d\n", result2);
99         edits->equivalent_output(track->edits, &result2);
100 //printf("Track::equivalent_output 4 %d\n", 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         }
110 //printf("Track::equivalent_output 5 %d\n", result2);
112 // New EDL has more plugin sets.  Get starting plugin in new plugin sets
113         for(int i = plugin_sets; i < plugin_set.total; i++)
114         {
115                 Plugin *current = plugin_set.values[i]->get_first_plugin();
116                 if(current)
117                 {
118                         if(result2 < 0 || current->startproject < result2)
119                                 result2 = current->startproject;
120                 }
121         }
123 //printf("Track::equivalent_output 6 %f %d\n", *result, result2);
124         if(result2 >= 0 && 
125                 (*result < 0 || from_units(result2) < *result))
126                 *result = from_units(result2);
127 //printf("Track::equivalent_output 7 %f\n", *result);
131 int Track::is_synthesis(RenderEngine *renderengine, 
132         int64_t position, 
133         int direction)
135         int is_synthesis = 0;
136         for(int i = 0; i < plugin_set.total; i++)
137         {
138                 Plugin *plugin = get_current_plugin(position,
139                         i,
140                         direction,
141                         0);
142                 if(plugin)
143                 {
144                         is_synthesis = plugin->is_synthesis(renderengine, 
145                                 position, 
146                                 direction);
147                         if(is_synthesis) break;
148                 }
149         }
150         return is_synthesis;
153 Track& Track::operator=(Track& track)
155 //printf("Track::operator= 1\n");
156         copy_settings(&track);
157 //printf("Track::operator= 1\n");
158         *this->edits = *track.edits;
159 //printf("Track::operator= 1\n");
160         for(int i = 0; i < this->plugin_set.total; i++)
161                 delete this->plugin_set.values[i];
162 //printf("Track::operator= 1\n");
163         this->plugin_set.remove_all_objects();
164 //printf("Track::operator= 1\n");
166         for(int i = 0; i < track.plugin_set.total; i++)
167         {
168                 PluginSet *new_plugin_set = plugin_set.append(new PluginSet(edl, this));
169                 *new_plugin_set = *track.plugin_set.values[i];
170         }
171 //printf("Track::operator= 1\n");
172         *this->automation = *track.automation;
173 //printf("Track::operator= 1\n");
174         this->track_w = track.track_w;
175         this->track_h = track.track_h;
176 //printf("Track::operator= 2\n");
177         return *this;
180 int Track::vertical_span(Theme *theme)
182         int result = 0;
183         if(expand_view)
184                 result = edl->local_session->zoom_track + 
185                         plugin_set.total * 
186                         theme->plugin_bg_data->get_h();
187         else
188                 result = edl->local_session->zoom_track;
190         if(edl->session->show_titles)
191                 result += theme->title_bg_data->get_h();
193         return result;
196 double Track::get_length()
198         double total_length = 0;
199         double length = 0;
201 // Test edits
202         if(edits->last)
203         {
204                 length = from_units(edits->last->startproject + edits->last->length);
205                 if(length > total_length) total_length = length;
206         }
208 // Test plugins
209         for(int i = 0; i < plugin_set.total; i++)
210         {
211                 if(plugin_set.values[i]->last)
212                 {
213                         length = from_units(plugin_set.values[i]->last->startproject + 
214                                 plugin_set.values[i]->last->length);
215                         if(length > total_length) total_length = length;
216                 }
217         }
219 // Test keyframes
220         length = from_units(automation->get_length());
221         if(length > total_length) total_length = length;
222         
224         return total_length;
229 void Track::get_source_dimensions(double position, int &w, int &h)
231         int64_t native_position = to_units(position, 0);
232         for(Edit *current = edits->first; current; current = NEXT)
233         {
234                 if(current->startproject <= native_position &&
235                         current->startproject + current->length > native_position &&
236                         current->asset)
237                 {
238                         w = current->asset->width;
239                         h = current->asset->height;
240                         return;
241                 }
242         }
246 int64_t Track::horizontal_span()
248         return (int64_t)(get_length() * 
249                 edl->session->sample_rate / 
250                 edl->local_session->zoom_sample + 
251                 0.5);
255 int Track::load(FileXML *file, int track_offset, uint32_t load_flags)
257         int result = 0;
258         int current_channel = 0;
259         int current_plugin = 0;
262         record = file->tag.get_property("RECORD", record);
263         play = file->tag.get_property("PLAY", play);
264         gang = file->tag.get_property("GANG", gang);
265         draw = file->tag.get_property("DRAW", draw);
266         expand_view = file->tag.get_property("EXPAND", expand_view);
267         track_w = file->tag.get_property("TRACK_W", track_w);
268         track_h = file->tag.get_property("TRACK_H", track_h);
270         load_header(file, load_flags);
272         do{
273                 result = file->read_tag();
275                 if(!result)
276                 {
277                         if(file->tag.title_is("/TRACK"))
278                         {
279                                 result = 1;
280                         }
281                         else
282                         if(file->tag.title_is("TITLE"))
283                         {
284                                 file->read_text_until("/TITLE", title);
285                         }
286                         else
287                         if(strstr(file->tag.get_title(), "AUTOS"))
288                         {
289                                 if(load_flags)
290                                 {
291                                         automation->load(file);
292                                 }
293                         }
294                         else
295                         if(file->tag.title_is("EDITS"))
296                         {
297                                 if(load_flags & LOAD_EDITS)
298                                         edits->load(file, track_offset);
299                         }
300                         else
301                         if(file->tag.title_is("PLUGINSET"))
302                         {
303                                 if(load_flags & LOAD_EDITS)
304                                 {
305                                         PluginSet *plugin_set = new PluginSet(edl, this);
306                                         this->plugin_set.append(plugin_set);
307                                         plugin_set->load(file, load_flags);
308                                 }
309                                 else
310                                 if(load_flags & LOAD_AUTOMATION)
311                                 {
312                                         if(current_plugin < this->plugin_set.total)
313                                         {
314                                                 PluginSet *plugin_set = this->plugin_set.values[current_plugin];
315                                                 plugin_set->load(file, load_flags);
316                                                 current_plugin++;
317                                         }
318                                 }
319                         }
320                         else
321                                 load_derived(file, load_flags);
322                 }
323         }while(!result);
327         return 0;
330 void Track::insert_asset(Asset *asset, 
331                 double length, 
332                 double position, 
333                 int track_number)
335 //printf("Track::insert_asset %f\n", length);
336         edits->insert_asset(asset, 
337                 to_units(length, 1), 
338                 to_units(position, 0), 
339                 track_number);
342 // Insert data
344 // Default keyframes: We don't replace default keyframes in pasting but
345 // when inserting the first EDL of a load operation we need to replace
346 // the default keyframes.
348 // Plugins:  This is an arbitrary behavior
350 // 1) No plugin in source track: Paste silence into destination
351 // plugin sets.
352 // 2) Plugin in source track: plugin in source track is inserted into
353 // existing destination track plugin sets, new sets being added when
354 // necessary.
356 void Track::insert_track(Track *track, 
357         double position, 
358         int replace_default,
359         int edit_plugins)
361 // Decide whether to copy settings based on load_mode
362         if(replace_default) copy_settings(track);
364         edits->insert_edits(track->edits, to_units(position, 0));
366         if(edit_plugins)
367                 insert_plugin_set(track, position);
369         automation->insert_track(track->automation, 
370                 to_units(position, 0), 
371                 to_units(track->get_length(), 1),
372                 replace_default);
374         optimize();
377 // Called by insert_track
378 void Track::insert_plugin_set(Track *track, double position)
380 // Extend plugins if no incoming plugins
381         if(!track->plugin_set.total)
382         {
383                 shift_effects(position, 
384                         track->get_length(), 
385                         1);
386         }
387         else
388         for(int i = 0; i < track->plugin_set.total; i++)
389         {
390                 if(i >= plugin_set.total)
391                         plugin_set.append(new PluginSet(edl, this));
393                 plugin_set.values[i]->insert_edits(track->plugin_set.values[i], 
394                         to_units(position, 0));
395         }
399 Plugin* Track::insert_effect(char *title, 
400                 SharedLocation *shared_location, 
401                 KeyFrame *default_keyframe,
402                 PluginSet *plugin_set,
403                 double start,
404                 double length,
405                 int plugin_type)
407         if(!plugin_set)
408         {
409                 plugin_set = new PluginSet(edl, this);
410                 this->plugin_set.append(plugin_set);
411         }
413         Plugin *plugin = 0;
415 // Position is identical to source plugin
416         if(plugin_type == PLUGIN_SHAREDPLUGIN)
417         {
418                 Track *source_track = tracks->get_item_number(shared_location->module);
419                 if(source_track)
420                 {
421                         Plugin *source_plugin = source_track->get_current_plugin(
422                                 edl->local_session->get_selectionstart(), 
423                                 shared_location->plugin, 
424                                 PLAY_FORWARD, 
425                                 1);
427 // From an attach operation
428                         if(source_plugin)
429                         {
430                                 plugin = plugin_set->insert_plugin(title, 
431                                         source_plugin->startproject, 
432                                         source_plugin->length,
433                                         plugin_type, 
434                                         shared_location,
435                                         default_keyframe,
436                                         1);
437                         }
438                         else
439 // From a drag operation
440                         {
441                                 plugin = plugin_set->insert_plugin(title, 
442                                         to_units(start, 0), 
443                                         to_units(length, 0),
444                                         plugin_type, 
445                                         shared_location,
446                                         default_keyframe,
447                                         1);
448                         }
449                 }
450         }
451         else
452         {
453 // This should be done in the caller
454                 if(EQUIV(length, 0))
455                 {
456                         if(edl->local_session->get_selectionend() > 
457                                 edl->local_session->get_selectionstart())
458                         {
459                                 start = edl->local_session->get_selectionstart();
460                                 length = edl->local_session->get_selectionend() - start;
461                         }
462                         else
463                         {
464                                 start = 0;
465                                 length = get_length();
466                         }
467                 }
468 //printf("Track::insert_effect %f %f %d %d\n", start, length, to_units(start, 0), 
469 //                      to_units(length, 0));
471                 plugin = plugin_set->insert_plugin(title, 
472                         to_units(start, 0), 
473                         to_units(length, 0),
474                         plugin_type, 
475                         shared_location,
476                         default_keyframe,
477                         1);
478         }
479 //printf("Track::insert_effect 2 %f %f\n", start, length);
481         expand_view = 1;
482         return plugin;
485 void Track::move_plugins_up(PluginSet *plugin_set)
487         for(int i = 0; i < this->plugin_set.total; i++)
488         {
489                 if(this->plugin_set.values[i] == plugin_set)
490                 {
491                         if(i == 0) break;
493                         PluginSet *temp = this->plugin_set.values[i - 1];
494                         this->plugin_set.values[i - 1] = this->plugin_set.values[i];
495                         this->plugin_set.values[i] = temp;
496                         break;
497                 }
498         }
501 void Track::move_plugins_down(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 == this->plugin_set.total - 1) 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;
512                         break;
513                 }
514         }
518 void Track::remove_asset(Asset *asset)
520         for(Edit *edit = edits->first; edit; edit = edit->next)
521         {
522                 if(edit->asset && edit->asset == asset)
523                 {
524                         edit->asset = 0;
525                 }
526         }
527         optimize();
530 void Track::remove_pluginset(PluginSet *plugin_set)
532         int i;
533         for(i = 0; i < this->plugin_set.total; i++)
534                 if(plugin_set == this->plugin_set.values[i]) break;
536         this->plugin_set.remove_object(plugin_set);
537         for(i++ ; i < this->plugin_set.total; i++)
538         {
539                 SharedLocation old_location, new_location;
540                 new_location.module = old_location.module = tracks->number_of(this);
541                 old_location.plugin = i;
542                 new_location.plugin = i - 1;
543                 tracks->change_plugins(old_location, new_location, 0);
544         }
547 void Track::shift_keyframes(double position, double length, int convert_units)
549         if(convert_units)
550         {
551                 position = to_units(position, 0);
552                 length = to_units(length, 0);
553         }
555         automation->paste_silence(Units::to_int64(position), 
556                 Units::to_int64(position + length));
557 // Effect keyframes are shifted in shift_effects
560 void Track::shift_effects(double position, double length, int convert_units)
562         if(convert_units)
563         {
564                 position = to_units(position, 0);
565                 length = to_units(length, 0);
566         }
568         for(int i = 0; i < plugin_set.total; i++)
569         {
570                 plugin_set.values[i]->shift_effects(Units::to_int64(position), Units::to_int64(length));
571         }
574 void Track::detach_effect(Plugin *plugin)
576 //printf("Track::detach_effect 1\n");           
577         for(int i = 0; i < plugin_set.total; i++)
578         {
579                 PluginSet *plugin_set = this->plugin_set.values[i];
580                 for(Plugin *dest = (Plugin*)plugin_set->first; 
581                         dest; 
582                         dest = (Plugin*)dest->next)
583                 {
584                         if(dest == plugin)
585                         {
586                                 int64_t start = plugin->startproject;
587                                 int64_t end = plugin->startproject + plugin->length;
589                                 plugin_set->clear(start, end);
590                                 plugin_set->paste_silence(start, end);
592 // Delete 0 length pluginsets   
593                                 plugin_set->optimize();
594 //printf("Track::detach_effect 2 %d\n", plugin_set->length());
595                                 if(!plugin_set->length()) 
596                                         this->plugin_set.remove_object(plugin_set);
598                                 return;
599                         }
600                 }
601         }
604 void Track::resample(double old_rate, double new_rate)
606         edits->resample(old_rate, new_rate);
607         automation->resample(old_rate, new_rate);
608         for(int i = 0; i < plugin_set.total; i++)
609                 plugin_set.values[i]->resample(old_rate, new_rate);
614 void Track::optimize()
616         edits->optimize();
617         for(int i = 0; i < plugin_set.total; i++)
618         {
619                 plugin_set.values[i]->optimize();
620 //printf("Track::optimize %d\n", plugin_set.values[i]->total());
621                 if(plugin_set.values[i]->total() <= 0)
622                 {
623                         remove_pluginset(plugin_set.values[i]);
624                 }
625         }
628 Plugin* Track::get_current_plugin(double position, 
629         int plugin_set, 
630         int direction, 
631         int convert_units)
633         Plugin *current;
634         if(convert_units) position = to_units(position, 0);
635         
636         
637         if(plugin_set >= this->plugin_set.total || plugin_set < 0) return 0;
639 //printf("Track::get_current_plugin 1 %d %d %d\n", position, this->plugin_set.total, direction);
640         if(direction == PLAY_FORWARD)
641         {
642                 for(current = (Plugin*)this->plugin_set.values[plugin_set]->last; 
643                         current; 
644                         current = (Plugin*)PREVIOUS)
645                 {
646 // printf("Track::get_current_plugin 2 %d %ld %ld\n", 
647 // current->startproject, 
648 // current->startproject + current->length, 
649 // position);
650                         if(current->startproject <= position && 
651                                 current->startproject + current->length > position)
652                         {
653                                 return current;
654                         }
655                 }
656         }
657         else
658         if(direction == PLAY_REVERSE)
659         {
660                 for(current = (Plugin*)this->plugin_set.values[plugin_set]->first; 
661                         current; 
662                         current = (Plugin*)NEXT)
663                 {
664                         if(current->startproject < position && 
665                                 current->startproject + current->length >= position)
666                         {
667                                 return current;
668                         }
669                 }
670         }
672         return 0;
675 Plugin* Track::get_current_transition(double position, int direction, int convert_units)
677         Edit *current;
678         Plugin *result = 0;
679         if(convert_units) position = to_units(position, 0);
681         if(direction == PLAY_FORWARD)
682         {
683                 for(current = edits->last; current; current = PREVIOUS)
684                 {
685                         if(current->startproject <= position && current->startproject + current->length > position)
686                         {
687 //printf("Track::get_current_transition %p\n", current->transition);
688                                 if(current->transition && position < current->startproject + current->transition->length)
689                                 {
690                                         result = current->transition;
691                                         break;
692                                 }
693                         }
694                 }
695         }
696         else
697         if(direction == PLAY_REVERSE)
698         {
699                 for(current = edits->first; current; current = NEXT)
700                 {
701                         if(current->startproject < position && current->startproject + current->length >= position)
702                         {
703                                 if(current->transition && position <= current->startproject + current->transition->length)
704                                 {
705                                         result = current->transition;
706                                         break;
707                                 }
708                         }
709                 }
710         }
712         return result;
715 void Track::synchronize_params(Track *track)
717         for(Edit *this_edit = edits->first, *that_edit = track->edits->first;
718                 this_edit && that_edit;
719                 this_edit = this_edit->next, that_edit = that_edit->next)
720         {
721                 this_edit->synchronize_params(that_edit);
722         }
724         for(int i = 0; i < plugin_set.total && i < track->plugin_set.total; i++)
725                 plugin_set.values[i]->synchronize_params(track->plugin_set.values[i]);
727         automation->copy_from(track->automation);
734 int Track::dump()
736         printf("   Data type %d\n", data_type);
737         printf("   Title %s\n", title);
738         printf("   Edits:\n");
739         for(Edit* current = edits->first; current; current = NEXT)
740         {
741                 current->dump();
742         }
743         automation->dump();
744         printf("   Plugin Sets: %d\n", plugin_set.total);
746         for(int i = 0; i < plugin_set.total; i++)
747                 plugin_set.values[i]->dump();
748 //printf("Track::dump 2\n");
749         return 0;
772 Track::Track() : ListItem<Track>()
774         y_pixel = 0;
777 // ======================================== accounting
779 int Track::number_of() 
781         return tracks->number_of(this); 
788         
789         
796 // ================================================= editing
798 int Track::select_auto(AutoConf *auto_conf, int cursor_x, int cursor_y)
800         return 0;
803 int Track::move_auto(AutoConf *auto_conf, int cursor_x, int cursor_y, int shift_down)
805         return 0;
808 int Track::release_auto()
810         return 0;
813 // used for copying automation alone
814 int Track::copy_automation(double selectionstart, 
815         double selectionend, 
816         FileXML *file,
817         int default_only,
818         int autos_only)
820         int64_t start = to_units(selectionstart, 0);
821         int64_t end = to_units(selectionend, 0);
823         file->tag.set_title("TRACK");
824 // Video or audio
825     save_header(file);
826         file->append_tag();
827         file->append_newline();
829         automation->copy(start, end, file, default_only, autos_only);
831         if(edl->session->auto_conf->plugins)
832         {
833                 for(int i = 0; i < plugin_set.total; i++)
834                 {
835                         plugin_set.values[i]->copy_keyframes(start, 
836                                 end, 
837                                 file, 
838                                 default_only,
839                                 autos_only);
840                 }
841         }
843         file->tag.set_title("/TRACK");
844         file->append_tag();
845         file->append_newline();
846         file->append_newline();
847         file->append_newline();
848         file->append_newline();
850         return 0;
853 int Track::paste_automation(double selectionstart, 
854         double total_length, 
855         double frame_rate,
856         int64_t sample_rate,
857         FileXML *file,
858         int default_only)
860 // Only used for pasting automation alone.
861         int64_t start;
862         int64_t length;
863         int result;
864         int current_pluginset;
865         double scale;
867         if(data_type == TRACK_AUDIO)
868                 scale = edl->session->sample_rate / sample_rate;
869         else
870                 scale = edl->session->frame_rate / frame_rate;
872         total_length *= scale;
873         start = to_units(selectionstart, 0);
874         length = to_units(total_length, 0);
875         result = 0;
876         current_pluginset = 0;
877 //printf("Track::paste_automation 1\n");
879         while(!result)
880         {
881                 result = file->read_tag();
883                 if(!result)
884                 {
885                         if(file->tag.title_is("/TRACK"))
886                                 result = 1;
887                         else
888                         if(strstr(file->tag.get_title(), "AUTOS"))
889                         {
890                                 automation->paste(start, 
891                                         length, 
892                                         scale,
893                                         file,
894                                         default_only,
895                                         0);
896                         }
897                         else
898                         if(file->tag.title_is("PLUGINSET"))
899                         {
900                                 if(current_pluginset < plugin_set.total)
901                                 {
902 //printf("Track::paste_automation 2 %d\n", current_pluginset);
903                                         plugin_set.values[current_pluginset]->paste_keyframes(start, 
904                                                 length, 
905                                                 file,
906                                                 default_only);
907                                         current_pluginset++;
908                                 }
909                         }
910                 }
911         }
912 //printf("Track::paste_automation 3\n");
913         
915         return 0;
918 void Track::clear_automation(double selectionstart, 
919         double selectionend, 
920         int shift_autos,
921         int default_only)
923         int64_t start = to_units(selectionstart, 0);
924         int64_t end = to_units(selectionend, 0);
926         automation->clear(start, end, edl->session->auto_conf, 0);
928         if(edl->session->auto_conf->plugins)
929         {
930                 for(int i = 0; i < plugin_set.total; i++)
931                 {
932                         plugin_set.values[i]->clear_keyframes(start, end);
933                 }
934         }
939 int Track::copy(double start, 
940         double end, 
941         FileXML *file, 
942         char *output_path)
944 //printf("Track::copy 1\n");
945 // Use a copy of the selection in converted units
946 // So copy_automation doesn't reconvert.
947         int64_t start_unit = to_units(start, 0);
948         int64_t end_unit = to_units(end, 1);
953         file->tag.set_title("TRACK");
954 //      file->tag.set_property("PLAY", play);
955         file->tag.set_property("RECORD", record);
956         file->tag.set_property("PLAY", play);
957         file->tag.set_property("GANG", gang);
958 //      file->tag.set_property("MUTE", mute);
959         file->tag.set_property("DRAW", draw);
960         file->tag.set_property("EXPAND", expand_view);
961         file->tag.set_property("TRACK_W", track_w);
962         file->tag.set_property("TRACK_H", track_h);
963         save_header(file);
964         file->append_tag();
965         file->append_newline();
966         save_derived(file);
968         file->tag.set_title("TITLE");
969         file->append_tag();
970         file->append_text(title);
971         file->tag.set_title("/TITLE");
972         file->append_tag();
973         file->append_newline();
975 //printf("Track::copy 1\n");
976         if(data_type == TRACK_AUDIO)
977                 file->tag.set_property("TYPE", "AUDIO");
978         else
979                 file->tag.set_property("TYPE", "VIDEO");
981 //printf("Track::copy 1\n");
982         file->append_tag();
983         file->append_newline();
985 //printf("Track::copy 1\n");
986         edits->copy(start_unit, end_unit, file, output_path);
988 //printf("Track::copy 1\n");
989         AutoConf auto_conf;
990         auto_conf.set_all();
991         automation->copy(start_unit, end_unit, file, 0, 0);
994         for(int i = 0; i < plugin_set.total; i++)
995         {
996                 plugin_set.values[i]->copy(start_unit, end_unit, file);
997         }
999 //printf("Track::copy 1\n");
1000         copy_derived(start_unit, end_unit, file);
1002 //printf("Track::copy 1\n");
1003         file->tag.set_title("/TRACK");
1004         file->append_tag();
1005         file->append_newline();
1006         file->append_newline();
1007         file->append_newline();
1008         file->append_newline();
1009 //printf("Track::copy 2\n");
1010         return 0;
1013 int Track::copy_assets(double start, 
1014         double end, 
1015         ArrayList<Asset*> *asset_list)
1017         int i, result = 0;
1019         start = to_units(start, 0);
1020         end = to_units(end, 0);
1022         Edit *current = edits->editof((int64_t)start, PLAY_FORWARD);
1024 // Search all edits
1025         while(current && current->startproject < end)
1026         {
1027 // Check for duplicate assets
1028                 if(current->asset)
1029                 {
1030                         for(i = 0, result = 0; i < asset_list->total; i++)
1031                         {
1032                                 if(asset_list->values[i] == current->asset) result = 1;
1033                         }
1034 // append pointer to new asset
1035                         if(!result) asset_list->append(current->asset);
1036                 }
1038                 current = NEXT;
1039         }
1041         return 0;
1048 int Track::clear(double start, 
1049         double end, 
1050         int edit_edits,
1051         int edit_labels,
1052         int edit_plugins,
1053         int convert_units)
1055 // Edits::move_auto calls this routine after the units are converted to the track
1056 // format.
1057         if(convert_units)
1058         {
1059                 start = to_units(start, 0);
1060                 end = to_units(end, 0);
1061         }
1063         if(edit_edits)
1064                 automation->clear((int64_t)start, (int64_t)end, 0, 1);
1066         if(edit_plugins)
1067                 for(int i = 0; i < plugin_set.total; i++)
1068                         plugin_set.values[i]->clear((int64_t)start, (int64_t)end);
1070         if(edit_edits)
1071                 edits->clear((int64_t)start, (int64_t)end);
1072         return 0;
1075 int Track::clear_handle(double start, 
1076         double end, 
1077         int clear_labels,
1078         int clear_plugins, 
1079         double &distance)
1081         edits->clear_handle(start, end, clear_plugins, distance);
1084 int Track::popup_transition(int cursor_x, int cursor_y)
1086         return 0;
1091 int Track::modify_edithandles(double oldposition, 
1092         double newposition, 
1093         int currentend, 
1094         int handle_mode,
1095         int edit_labels,
1096         int edit_plugins)
1098         edits->modify_handles(oldposition, 
1099                 newposition, 
1100                 currentend, 
1101                 handle_mode,
1102                 1,
1103                 edit_labels,
1104                 edit_plugins);
1107         return 0;
1110 int Track::modify_pluginhandles(double oldposition, 
1111         double newposition, 
1112         int currentend, 
1113         int handle_mode,
1114         int edit_labels)
1116         for(int i = 0; i < plugin_set.total; i++)
1117         {
1118                 plugin_set.values[i]->modify_handles(oldposition, 
1119                         newposition, 
1120                         currentend, 
1121                         handle_mode,
1122                         0,
1123                         edit_labels,
1124                         1);
1125         }
1126         return 0;
1130 int Track::paste_silence(double start, double end, int edit_plugins)
1132         start = to_units(start, 0);
1133         end = to_units(end, 1);
1135         edits->paste_silence((int64_t)start, (int64_t)end);
1136         shift_keyframes(start, end - start, 0);
1137         if(edit_plugins) shift_effects(start, end - start, 0);
1139         edits->optimize();
1140         return 0;
1143 int Track::select_edit(int cursor_x, 
1144         int cursor_y, 
1145         double &new_start, 
1146         double &new_end)
1148         return 0;
1151 int Track::scale_time(float rate_scale, int scale_edits, int scale_autos, int64_t start, int64_t end)
1153         return 0;
1156 void Track::change_plugins(SharedLocation &old_location, SharedLocation &new_location, int do_swap)
1158         for(int i = 0; i < plugin_set.total; i++)
1159         {
1160                 for(Plugin *plugin = (Plugin*)plugin_set.values[i]->first; 
1161                         plugin; 
1162                         plugin = (Plugin*)plugin->next)
1163                 {
1164                         if(plugin->plugin_type == PLUGIN_SHAREDPLUGIN)
1165                         {
1166                                 if(plugin->shared_location == old_location)
1167                                         plugin->shared_location = new_location;
1168                                 else
1169                                 if(do_swap && plugin->shared_location == new_location)
1170                                         plugin->shared_location = old_location;
1171                         }
1172                 }
1173         }
1176 void Track::change_modules(int old_location, int new_location, int do_swap)
1178         for(int i = 0; i < plugin_set.total; i++)
1179         {
1180                 for(Plugin *plugin = (Plugin*)plugin_set.values[i]->first; 
1181                         plugin; 
1182                         plugin = (Plugin*)plugin->next)
1183                 {
1184                         if(plugin->plugin_type == PLUGIN_SHAREDPLUGIN ||
1185                                 plugin->plugin_type == PLUGIN_SHAREDMODULE)
1186                         {
1187                                 if(plugin->shared_location.module == old_location)
1188                                         plugin->shared_location.module = new_location;
1189                                 else
1190                                 if(do_swap && plugin->shared_location.module == new_location)
1191                                         plugin->shared_location.module = old_location;
1192                         }
1193                 }
1194         }
1198 int Track::delete_module_pointers(int deleted_track)
1200         for(int i = 0; i < plugin_set.total; i++)
1201         {
1202                 for(Plugin *plugin = (Plugin*)plugin_set.values[i]->first; 
1203                         plugin; 
1204                         plugin = (Plugin*)plugin->next)
1205                 {
1206                         if(plugin->plugin_type == PLUGIN_SHAREDPLUGIN ||
1207                                 plugin->plugin_type == PLUGIN_SHAREDMODULE)
1208                         {
1209                                 if(plugin->shared_location.module == deleted_track)
1210                                 {
1211                                         plugin->on = 0;
1212                                 }
1213                                 else
1214                                 {
1215                                         plugin->shared_location.module--;
1216                                 }
1217                         }
1218                 }
1219         }
1221         return 0;
1224 int Track::playable_edit(int64_t position, int direction)
1226         int result = 0;
1227         if(direction == PLAY_REVERSE) position--;
1228         for(Edit *current = edits->first; current && !result; current = NEXT)
1229         {
1230                 if(current->startproject <= position && 
1231                         current->startproject + current->length > position)
1232                 {
1233 //printf("Track::playable_edit %p %p\n", current->transition, current->asset);
1234                         if(current->transition || current->asset) result = 1;
1235                 }
1236         }
1237         return result;
1241 int Track::need_edit(Edit *current, int test_transitions)
1243         return ((test_transitions && current->transition) ||
1244                 (!test_transitions && current->asset));
1247 int64_t Track::plugin_change_duration(int64_t input_position,
1248         int64_t input_length,
1249         int reverse)
1251         for(int i = 0; i < plugin_set.total; i++)
1252         {
1253                 int64_t new_duration = plugin_set.values[i]->plugin_change_duration(
1254                         input_position, 
1255                         input_length, 
1256                         reverse);
1257                 if(new_duration < input_length) input_length = new_duration;
1258         }
1259         return (input_length);
1262 int64_t Track::edit_change_duration(int64_t input_position, 
1263         int64_t input_length, 
1264         int reverse, 
1265         int test_transitions)
1267         Edit *current;
1268         int64_t edit_length = input_length;
1270         if(reverse)
1271         {
1272 // ================================= Reverse playback
1273 // Get first edit on or after position
1274                 for(current = edits->first; 
1275                         current && current->startproject + current->length <= input_position;
1276                         current = NEXT)
1277                         ;
1279                 if(current)
1280                 {
1281                         if(current->startproject > input_position)
1282                         {
1283 // Before first edit
1284                                 ;
1285                         }
1286                         else
1287                         if(need_edit(current, test_transitions))
1288                         {
1289 // Over an edit of interest.
1290                                 if(input_position - current->startproject < input_length)
1291                                         edit_length = input_position - current->startproject + 1;
1292                         }
1293                         else
1294                         {
1295 // Over an edit that isn't of interest.
1296 // Search for next edit of interest.
1297                                 for(current = PREVIOUS ; 
1298                                         current && 
1299                                         current->startproject + current->length > input_position - input_length &&
1300                                         !need_edit(current, test_transitions);
1301                                         current = PREVIOUS)
1302                                         ;
1304                                         if(current && 
1305                                                 need_edit(current, test_transitions) &&
1306                                                 current->startproject + current->length > input_position - input_length)
1307                         edit_length = input_position - current->startproject - current->length + 1;
1308                         }
1309                 }
1310                 else
1311                 {
1312 // Not over an edit.  Try the last edit.
1313                         current = edits->last;
1314                         if(current && 
1315                                 ((test_transitions && current->transition) ||
1316                                 (!test_transitions && current->asset)))
1317                                 edit_length = input_position - edits->last->startproject - edits->last->length + 1;
1318                 }
1319         }
1320         else
1321         {
1322 // =================================== forward playback
1323 // Get first edit on or before position
1324                 for(current = edits->last; 
1325                         current && current->startproject > input_position;
1326                         current = PREVIOUS)
1327                         ;
1329                 if(current)
1330                 {
1331                         if(current->startproject + current->length <= input_position)
1332                         {
1333 // Beyond last edit.
1334                                 ;
1335                         }
1336                         else
1337                         if(need_edit(current, test_transitions))
1338                         {
1339 // Over an edit of interest.
1340 // Next edit is going to require a change.
1341                                 if(current->length + current->startproject - input_position < input_length)
1342                                         edit_length = current->startproject + current->length - input_position;
1343                         }
1344                         else
1345                         {
1346 // Over an edit that isn't of interest.
1347 // Search for next edit of interest.
1348                                 for(current = NEXT ; 
1349                                         current && 
1350                                         current->startproject < input_position + input_length &&
1351                                         !need_edit(current, test_transitions);
1352                                         current = NEXT)
1353                                         ;
1355                                         if(current && 
1356                                                 need_edit(current, test_transitions) &&
1357                                                 current->startproject < input_position + input_length) 
1358                                                 edit_length = current->startproject - input_position;
1359                         }
1360                 }
1361                 else
1362                 {
1363 // Not over an edit.  Try the first edit.
1364                         current = edits->first;
1365                         if(current && 
1366                                 ((test_transitions && current->transition) ||
1367                                 (!test_transitions && current->asset)))
1368                                 edit_length = edits->first->startproject - input_position;
1369                 }
1370         }
1372         if(edit_length < input_length)
1373                 return edit_length;
1374         else
1375                 return input_length;
1378 int Track::purge_asset(Asset *asset)
1380         return 0;
1383 int Track::asset_used(Asset *asset)
1385         Edit* current_edit;
1386         int result = 0;
1388         for(current_edit = edits->first; current_edit; current_edit = current_edit->next)
1389         {
1390                 if(current_edit->asset == asset)
1391                 {
1392                         result++;
1393                 }
1394         }
1395         return result;
1398 int Track::channel_is_playable(int64_t position, int direction, int *do_channel)
1400         return 1;
1404 int Track::plugin_used(int64_t position, int64_t direction)
1406 //printf("Track::plugin_used 1 %d\n", this->plugin_set.total);
1407         for(int i = 0; i < this->plugin_set.total; i++)
1408         {
1409                 Plugin *current_plugin = get_current_plugin(position, i, direction, 0);
1411 //printf("Track::plugin_used 2 %p\n", current_plugin);
1412                 if(current_plugin && 
1413                         (current_plugin->on && 
1414                         current_plugin->plugin_type != PLUGIN_NONE))
1415                 {
1416                         return 1;
1417                 }
1418         }
1419 //printf("Track::plugin_used 3 %p\n", current_plugin);
1420         return 0;
1423 // Audio is always rendered through VConsole
1424 int Track::direct_copy_possible(int64_t start, int direction)
1426         return 1;
1429 int64_t Track::to_units(double position, int round)
1431         return (int64_t)position;
1434 double Track::to_doubleunits(double position)
1436         return position;
1439 double Track::from_units(int64_t position)
1441         return (double)position;