3 * Copyright (C) 2010 Adam Williams <broadcast at earthling dot net>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include "automation.h"
24 #include "bcsignals.h"
29 #include "edlsession.h"
31 #include "floatauto.h"
32 #include "floatautos.h"
35 #include "localsession.h"
41 #include "pluginset.h"
42 #include "mainsession.h"
46 #include "trackcanvas.h"
48 #include "transition.h"
49 #include "transportque.inc"
55 Track::Track(EDL *edl, Tracks *tracks) : ListItem<Track>()
58 this->tracks = tracks;
68 track_w = edl->session->output_w;
69 track_h = edl->session->output_h;
72 masks = (1<<SUBMASKS)-1;
79 plugin_set.remove_all_objects();
82 void Track::create_objects()
87 int Track::copy_settings(Track *track)
89 this->expand_view = track->expand_view;
90 this->draw = track->draw;
91 this->gang = track->gang;
92 this->record = track->record;
93 this->nudge = track->nudge;
94 this->mixer_id = track->mixer_id;
95 this->play = track->play;
96 this->data_h = track->data_h;
97 this->track_w = track->track_w;
98 this->track_h = track->track_h;
99 this->masks = track->masks;
100 strcpy(this->title, track->title);
110 int Track::load_defaults(BC_Hash *defaults)
115 void Track::equivalent_output(Track *track, double *result)
117 if(data_type != track->data_type ||
118 track_w != track->track_w ||
119 track_h != track->track_h ||
120 play != track->play ||
121 nudge != track->nudge)
124 // Convert result to track units
125 int64_t result2 = -1;
126 automation->equivalent_output(track->automation, &result2);
127 edits->equivalent_output(track->edits, &result2);
129 int plugin_sets = MIN(plugin_set.total, track->plugin_set.total);
130 // Test existing plugin sets
131 for(int i = 0; i < plugin_sets; i++)
133 plugin_set.values[i]->equivalent_output(
134 track->plugin_set.values[i],
138 // New EDL has more plugin sets. Get starting plugin in new plugin sets
139 for(int i = plugin_sets; i < plugin_set.total; i++)
141 Plugin *current = plugin_set.values[i]->get_first_plugin();
144 if(result2 < 0 || current->startproject < result2)
145 result2 = current->startproject;
149 // New EDL has fewer plugin sets. Get starting plugin in old plugin set
150 for(int i = plugin_sets; i < track->plugin_set.total; i++)
152 Plugin *current = track->plugin_set.values[i]->get_first_plugin();
155 if(result2 < 0 || current->startproject < result2)
156 result2 = current->startproject;
160 // Number of plugin sets differs but somehow we didn't find the start of the
162 if(track->plugin_set.total != plugin_set.total && result2 < 0)
166 (*result < 0 || from_units(result2) < *result))
167 *result = from_units(result2);
171 int Track::is_synthesis(int64_t position, int direction, int depth)
174 for( int i = 0; !result && i<plugin_set.total; ++i ) {
175 Plugin *plugin = get_current_plugin(position, i, direction, 0, 0);
176 if( !plugin ) continue;
177 // Assume data from a shared track is synthesized
178 result = plugin->plugin_type == PLUGIN_SHAREDMODULE ? 1 :
179 plugin->is_synthesis(position, direction, depth);
184 void Track::copy_from(Track *track)
186 copy_settings(track);
187 edits->copy_from(track->edits);
188 this->plugin_set.remove_all_objects();
190 for( int i=0; i<track->plugin_set.total; ++i ) {
191 PluginSet *new_plugin_set = plugin_set.append(new PluginSet(edl, this));
192 new_plugin_set->copy_from(track->plugin_set.values[i]);
194 automation->copy_from(track->automation);
195 this->track_w = track->track_w;
196 this->track_h = track->track_h;
199 Track& Track::operator=(Track& track)
201 printf("Track::operator= 1\n");
206 int Track::vertical_span(Theme *theme)
210 result += theme->get_image("title_bg_data")->get_h();
214 result += plugin_set.total * theme->get_image("plugin_bg_data")->get_h();
215 result = MAX(result, theme->title_h);
219 double Track::get_length()
221 double total_length = 0;
227 length = from_units(edits->last->startproject + edits->last->length);
228 if(length > total_length) total_length = length;
232 for(int i = 0; i < plugin_set.total; i++)
234 if( !plugin_set.values[i]->last ) continue;
235 length = from_units(plugin_set.values[i]->last->startproject +
236 plugin_set.values[i]->last->length);
237 if(length > total_length) total_length = length;
241 length = from_units(automation->get_length());
242 if(length > total_length) total_length = length;
248 int Track::has_speed()
250 FloatAutos *autos = (FloatAutos*)automation->autos[AUTOMATION_SPEED];
255 for(FloatAuto *current = (FloatAuto*)autos->first;
257 current = (FloatAuto*)current->next)
259 if(!EQUIV(current->get_value(), 1.0) ||
260 !EQUIV(current->get_control_in_value(), 0.0) ||
261 !EQUIV(current->get_control_out_value(), 0.0))
272 int Track::show_assets()
274 return expand_view || edl->session->show_assets ? 1 : 0;
277 int Track::show_titles()
279 return expand_view || edl->session->show_titles ? 1 : 0;
282 int Track::show_transitions()
284 return expand_view || edl->session->auto_conf->transitions ? 1 : 0;
287 void Track::get_source_dimensions(double position, int &w, int &h)
289 int64_t native_position = to_units(position, 0);
290 for(Edit *current = edits->first; current; current = NEXT)
292 if(current->startproject <= native_position &&
293 current->startproject + current->length > native_position &&
296 w = current->asset->width;
297 h = current->asset->height;
304 int64_t Track::horizontal_span()
306 return (int64_t)(get_length() *
307 edl->session->sample_rate /
308 edl->local_session->zoom_sample +
313 int Track::load(FileXML *file, int track_offset, uint32_t load_flags)
316 int current_plugin = 0;
319 record = file->tag.get_property("RECORD", record);
320 play = file->tag.get_property("PLAY", play);
321 gang = file->tag.get_property("GANG", gang);
322 draw = file->tag.get_property("DRAW", draw);
323 nudge = file->tag.get_property("NUDGE", nudge);
324 mixer_id = file->tag.get_property("MIXER_ID", mixer_id);
325 expand_view = file->tag.get_property("EXPAND", expand_view);
326 data_h = file->tag.get_property("DATA_H", data_h);
327 track_w = file->tag.get_property("TRACK_W", track_w);
328 track_h = file->tag.get_property("TRACK_H", track_h);
329 masks = file->tag.get_property("MASKS", masks);
331 load_header(file, load_flags);
334 result = file->read_tag();
338 if(file->tag.title_is("/TRACK"))
343 if(file->tag.title_is("TITLE"))
346 file->read_text_until("/TITLE", &data);
347 memset(title, 0, sizeof(title));
348 strncpy(title, data.cstr(), sizeof(title)-1);
351 if(load_flags && automation->load(file)
352 /* strstr(file->tag.get_title(), "AUTOS") */)
357 if(file->tag.title_is("EDITS"))
359 if(load_flags & LOAD_EDITS)
360 edits->load(file, track_offset);
362 result = file->skip_tag();
365 if(file->tag.title_is("PLUGINSET"))
367 if(load_flags & LOAD_EDITS)
369 PluginSet *plugin_set = new PluginSet(edl, this);
370 this->plugin_set.append(plugin_set);
371 plugin_set->load(file, load_flags);
374 if(load_flags & LOAD_AUTOMATION)
376 if(current_plugin < this->plugin_set.total)
378 PluginSet *plugin_set = this->plugin_set.values[current_plugin];
379 plugin_set->load(file, load_flags);
384 result = file->skip_tag();
387 load_derived(file, load_flags);
396 void Track::insert_asset(Asset *asset,
402 edits->insert_asset(asset,
405 to_units(position, 0),
411 // Default keyframes: We don't replace default keyframes in pasting but
412 // when inserting the first EDL of a load operation we need to replace
413 // the default keyframes.
415 // Plugins: This is an arbitrary behavior
417 // 1) No plugin in source track: Paste silence into destination
419 // 2) Plugin in source track: plugin in source track is inserted into
420 // existing destination track plugin sets, new sets being added when
423 void Track::insert_track(Track *track,
430 // Calculate minimum length of data to pad.
431 int64_t min_length = to_units(
432 MAX(edl_length, track->get_length()),
434 //printf("Track::insert_track %d %s %jd\n", __LINE__, title, min_length);
436 // Decide whether to copy settings based on load_mode
437 if(replace_default) copy_settings(track);
439 edits->insert_edits(track->edits,
440 to_units(position, 0),
445 insert_plugin_set(track,
446 to_units(position, 0),
451 automation->insert_track(track->automation,
452 to_units(position, 0),
460 // Called by insert_track
461 void Track::insert_plugin_set(Track *track,
466 // Extend plugins if no incoming plugins
467 if( track->plugin_set.total ) {
468 for(int i = 0; i < track->plugin_set.total; i++) {
469 if(i >= plugin_set.total)
470 plugin_set.append(new PluginSet(edl, this));
472 plugin_set.values[i]->insert_edits(track->plugin_set.values[i],
473 position, min_length, edit_autos);
477 shift_effects(position, min_length, edit_autos, 0);
481 Plugin* Track::insert_effect(const char *title,
482 SharedLocation *shared_location,
483 KeyFrame *default_keyframe,
484 PluginSet *plugin_set,
491 plugin_set = new PluginSet(edl, this);
492 this->plugin_set.append(plugin_set);
497 // Position is identical to source plugin
498 if(plugin_type == PLUGIN_SHAREDPLUGIN)
500 Track *source_track = tracks->get_item_number(shared_location->module);
503 Plugin *source_plugin = source_track->get_current_plugin(
504 edl->local_session->get_selectionstart(1),
505 shared_location->plugin,
510 // From an attach operation
513 plugin = plugin_set->insert_plugin(title,
514 source_plugin->startproject,
515 source_plugin->length,
522 // From a drag operation
524 plugin = plugin_set->insert_plugin(title,
536 // This should be done in the caller
539 if(edl->local_session->get_selectionend() >
540 edl->local_session->get_selectionstart())
542 start = edl->local_session->get_selectionstart();
543 length = edl->local_session->get_selectionend() - start;
548 length = get_length();
551 //printf("Track::insert_effect %f %f %d %d\n", start, length, to_units(start, 0),
552 // to_units(length, 0));
554 plugin = plugin_set->insert_plugin(title,
562 //printf("Track::insert_effect 2 %f %f\n", start, length);
568 void Track::move_plugins_up(PluginSet *plugin_set)
570 for(int i = 0; i < this->plugin_set.total; i++)
572 if(this->plugin_set.values[i] == plugin_set)
576 PluginSet *temp = this->plugin_set.values[i - 1];
577 this->plugin_set.values[i - 1] = this->plugin_set.values[i];
578 this->plugin_set.values[i] = temp;
580 SharedLocation old_location, new_location;
581 new_location.module = old_location.module = tracks->number_of(this);
582 old_location.plugin = i;
583 new_location.plugin = i - 1;
584 tracks->change_plugins(old_location, new_location, 1);
590 void Track::move_plugins_down(PluginSet *plugin_set)
592 for(int i = 0; i < this->plugin_set.total; i++)
594 if(this->plugin_set.values[i] == plugin_set)
596 if(i == this->plugin_set.total - 1) break;
598 PluginSet *temp = this->plugin_set.values[i + 1];
599 this->plugin_set.values[i + 1] = this->plugin_set.values[i];
600 this->plugin_set.values[i] = temp;
602 SharedLocation old_location, new_location;
603 new_location.module = old_location.module = tracks->number_of(this);
604 old_location.plugin = i;
605 new_location.plugin = i + 1;
606 tracks->change_plugins(old_location, new_location, 1);
613 void Track::remove_asset(Indexable *asset)
615 for(Edit *edit = edits->first; edit; edit = edit->next)
617 if(asset->is_asset &&
619 edit->asset == (Asset*)asset)
624 if(!asset->is_asset &&
626 edit->nested_edl == (EDL*)asset)
628 edit->nested_edl = 0;
634 void Track::remove_pluginset(PluginSet *plugin_set)
637 for(i = 0; i < this->plugin_set.total; i++)
638 if(plugin_set == this->plugin_set.values[i]) break;
640 this->plugin_set.remove_object(plugin_set);
641 for(i++ ; i < this->plugin_set.total; i++)
643 SharedLocation old_location, new_location;
644 new_location.module = old_location.module = tracks->number_of(this);
645 old_location.plugin = i;
646 new_location.plugin = i - 1;
647 tracks->change_plugins(old_location, new_location, 0);
651 void Track::shift_keyframes(int64_t position, int64_t length)
653 automation->paste_silence(position, position + length);
654 // Effect keyframes are shifted in shift_effects
657 void Track::shift_effects(int64_t position, int64_t length, int edit_autos, Edits *trim_edits)
659 for( int i=0; i<plugin_set.total; ++i ) {
660 if( !trim_edits || trim_edits == (Edits*)plugin_set.values[i] )
661 plugin_set.values[i]->shift_effects(position, length, edit_autos);
665 void Track::detach_effect(Plugin *plugin)
667 //printf("Track::detach_effect 1\n");
668 for(int i = 0; i < plugin_set.total; i++)
670 PluginSet *plugin_set = this->plugin_set.values[i];
671 for(Plugin *dest = (Plugin*)plugin_set->first;
673 dest = (Plugin*)dest->next)
677 int64_t start = plugin->startproject;
678 int64_t end = plugin->startproject + plugin->length;
680 plugin_set->clear(start, end, 1);
682 //printf("Track::detach_effect 2 %d\n", plugin_set->length());
683 // Delete 0 length pluginsets
690 void Track::resample(double old_rate, double new_rate)
692 edits->resample(old_rate, new_rate);
693 automation->resample(old_rate, new_rate);
694 for(int i = 0; i < plugin_set.total; i++)
695 plugin_set.values[i]->resample(old_rate, new_rate);
696 nudge = (int64_t)(nudge * new_rate / old_rate);
699 void Track::detach_shared_effects(int module)
701 for(int i = 0; i < plugin_set.size(); i++) {
702 PluginSet *plugin_set = this->plugin_set.get(i);
703 for(Plugin *dest = (Plugin*)plugin_set->first; dest; ) {
704 if( (dest->plugin_type == PLUGIN_SHAREDPLUGIN ||
705 dest->plugin_type == PLUGIN_SHAREDMODULE) &&
706 dest->shared_location.module == module ) {
707 int64_t start = dest->startproject;
708 int64_t end = dest->startproject + dest->length;
709 plugin_set->clear(start, end, 1);
712 if(dest) dest = (Plugin*)dest->next;
719 void Track::optimize()
722 for(int i = 0; i < plugin_set.total; ) {
723 PluginSet *plugin_set = this->plugin_set.values[i];
724 plugin_set->optimize();
725 //printf("Track::optimize %d\n", plugin_set.values[i]->total());
726 // new definition of empty track...
727 if( !plugin_set->last ||
728 (plugin_set->last == plugin_set->first &&
729 plugin_set->last->silence()) ) {
730 remove_pluginset(plugin_set);
737 Plugin* Track::get_current_plugin(double position,
744 if(convert_units) position = to_units(position, 0);
745 if(use_nudge) position += nudge;
747 if(plugin_set >= this->plugin_set.total || plugin_set < 0) return 0;
749 //printf("Track::get_current_plugin 1 %d %d %d\n", position, this->plugin_set.total, direction);
750 if(direction == PLAY_FORWARD)
752 for(current = (Plugin*)this->plugin_set.values[plugin_set]->last;
754 current = (Plugin*)PREVIOUS)
756 // printf("Track::get_current_plugin 2 %d %ld %ld\n",
757 // current->startproject,
758 // current->startproject + current->length,
760 if(current->startproject <= position &&
761 current->startproject + current->length > position)
768 if(direction == PLAY_REVERSE)
770 for(current = (Plugin*)this->plugin_set.values[plugin_set]->first;
772 current = (Plugin*)NEXT)
774 if(current->startproject < position &&
775 current->startproject + current->length >= position)
785 Plugin* Track::get_current_transition(double position,
792 if(convert_units) position = to_units(position, 0);
793 if(use_nudge) position += nudge;
795 if(direction == PLAY_FORWARD)
797 for(current = edits->last; current; current = PREVIOUS)
799 if(current->startproject <= position && current->startproject + current->length > position)
801 //printf("Track::get_current_transition %p\n", current->transition);
802 if(current->transition && position < current->startproject + current->transition->length)
804 result = current->transition;
811 if(direction == PLAY_REVERSE)
813 for(current = edits->first; current; current = NEXT)
815 if(current->startproject < position && current->startproject + current->length >= position)
817 if(current->transition && position <= current->startproject + current->transition->length)
819 result = current->transition;
829 void Track::synchronize_params(Track *track)
831 for(Edit *this_edit = edits->first, *that_edit = track->edits->first;
832 this_edit && that_edit;
833 this_edit = this_edit->next, that_edit = that_edit->next)
835 this_edit->synchronize_params(that_edit);
838 for(int i = 0; i < plugin_set.total && i < track->plugin_set.total; i++)
839 plugin_set.values[i]->synchronize_params(track->plugin_set.values[i]);
841 automation->copy_from(track->automation);
842 this->nudge = track->nudge;
846 int Track::dump(FILE *fp)
848 fprintf(fp," Data type %d, draw %d, gang %d, play %d, record %d, nudge %jd, masks 0x%04x\n",
849 data_type, draw, gang, play, record, nudge, masks);
850 fprintf(fp," Title %s\n", title);
851 fprintf(fp," Edits:\n");
852 for(Edit* current = edits->first; current; current = NEXT)
854 automation->dump(fp);
855 fprintf(fp," Plugin Sets: %d\n", plugin_set.total);
857 for( int i=0; i<plugin_set.total; ++i )
858 plugin_set[i]->dump(fp);
862 // ======================================== accounting
864 int Track::number_of()
866 return tracks->number_of(this);
871 // ================================================= editing
873 int Track::select_auto(AutoConf *auto_conf, int cursor_x, int cursor_y)
878 int Track::move_auto(AutoConf *auto_conf, int cursor_x, int cursor_y, int shift_down)
883 int Track::release_auto()
888 // used for copying automation alone
889 int Track::copy_automation(double selectionstart,
895 int64_t start = to_units(selectionstart, 0);
896 int64_t end = to_units(selectionend, 1);
898 file->tag.set_title("TRACK");
902 file->append_newline();
904 automation->copy(start, end, file, default_only, active_only);
906 if(edl->session->auto_conf->plugins)
908 for(int i = 0; i < plugin_set.total; i++)
911 plugin_set.values[i]->copy_keyframes(start,
919 file->tag.set_title("/TRACK");
921 file->append_newline();
922 file->append_newline();
923 file->append_newline();
924 file->append_newline();
929 int Track::paste_automation(double selectionstart, double total_length,
930 double frame_rate, int64_t sample_rate,
931 FileXML *file, int default_only, int active_only)
933 // Only used for pasting automation alone.
934 double scale = data_type == TRACK_AUDIO ?
935 edl->session->sample_rate / sample_rate :
936 edl->session->frame_rate / frame_rate ;
938 total_length *= scale;
939 int64_t start = to_units(selectionstart, 0);
940 int64_t length = to_units(total_length, 1);
942 int current_pluginset = 0;
943 //printf("Track::paste_automation 1\n");
945 while( !(result = file->read_tag()) ) {
946 if( file->tag.title_is("/TRACK") ) break;
947 if( automation->paste(start, length, scale, file,
948 default_only, active_only, 0) )
950 if( file->tag.title_is("PLUGINSET") ) {
951 if( current_pluginset < plugin_set.total ) {
952 plugin_set.values[current_pluginset]->
953 paste_keyframes(start, length, file,
954 default_only, active_only);
963 void Track::clear_automation(double selectionstart,
968 int64_t start = to_units(selectionstart, 0);
969 int64_t end = to_units(selectionend, 1);
971 automation->clear(start, end, edl->session->auto_conf, 0);
973 if(edl->session->auto_conf->plugins)
975 for(int i = 0; i < plugin_set.total; i++)
977 plugin_set.values[i]->clear_keyframes(start, end);
983 void Track::set_automation_mode(double selectionstart,
987 int64_t start = to_units(selectionstart, 0);
988 int64_t end = to_units(selectionend, 1);
990 automation->set_automation_mode(start, end, mode, edl->session->auto_conf);
996 int Track::copy(int copy_flags, double start, double end,
997 FileXML *file, const char *output_path)
999 // Use a copy of the selection in converted units
1000 // So copy_automation doesn't reconvert.
1001 int64_t start_unit = to_units(start, 0);
1002 int64_t end_unit = to_units(end, 1);
1007 file->tag.set_title("TRACK");
1008 file->tag.set_property("RECORD", record);
1009 file->tag.set_property("NUDGE", nudge);
1010 file->tag.set_property("MIXER_ID", mixer_id);
1011 file->tag.set_property("PLAY", play);
1012 file->tag.set_property("GANG", gang);
1013 file->tag.set_property("DRAW", draw);
1014 file->tag.set_property("EXPAND", expand_view);
1015 file->tag.set_property("DATA_H", data_h);
1016 file->tag.set_property("TRACK_W", track_w);
1017 file->tag.set_property("TRACK_H", track_h);
1018 file->tag.set_property("MASKS", masks);
1021 file->append_newline();
1024 file->tag.set_title("TITLE");
1026 file->append_text(title);
1027 file->tag.set_title("/TITLE");
1029 file->append_newline();
1031 // if(data_type == TRACK_AUDIO)
1032 // file->tag.set_property("TYPE", "AUDIO");
1034 // file->tag.set_property("TYPE", "VIDEO");
1036 // file->append_tag();
1037 // file->append_newline();
1039 if( (copy_flags & COPY_EDITS) )
1040 edits->copy(start_unit, end_unit, file, output_path);
1042 if( (copy_flags & COPY_AUTOS) ) {
1044 auto_conf.set_all(1);
1045 automation->copy(start_unit, end_unit, file, 0, 0);
1048 if( (copy_flags & COPY_PLUGINS) ) {
1049 for( int i=0; i<plugin_set.total; ++i )
1050 plugin_set.values[i]->copy(start_unit, end_unit, file);
1053 copy_derived(start_unit, end_unit, file);
1055 file->tag.set_title("/TRACK");
1057 file->append_newline();
1058 file->append_newline();
1059 file->append_newline();
1060 file->append_newline();
1065 int Track::copy_assets(double start,
1067 ArrayList<Asset*> *asset_list)
1071 start = to_units(start, 0);
1072 end = to_units(end, 1);
1074 Edit *current = edits->editof((int64_t)start, PLAY_FORWARD, 0);
1077 while(current && current->startproject < end)
1079 // Check for duplicate assets
1082 for(i = 0, result = 0; i < asset_list->total; i++)
1084 if(asset_list->values[i] == current->asset) result = 1;
1086 // append pointer to new asset
1087 if(!result) asset_list->append(current->asset);
1096 int Track::blade(double position)
1098 int64_t start = to_units(position, 0);
1099 Edit *edit = edits->split_edit(start);
1100 if( !edit || edit->silence() ) return 1;
1101 edit->hard_left = 1;
1102 if( edit->previous ) edit->previous->hard_right = 1;
1106 int Track::clear(double start, double end,
1107 int edit_edits, int edit_labels, int edit_plugins,
1108 int edit_autos, Edits *trim_edits)
1110 return clear(to_units(start, 0), to_units(end, 1),
1111 edit_edits, edit_labels, edit_plugins, edit_autos, trim_edits);
1114 int Track::clear(int64_t start, int64_t end,
1115 int edit_edits, int edit_labels, int edit_plugins,
1116 int edit_autos, Edits *trim_edits)
1118 //printf("Track::clear 1 %d %d %d\n", edit_edits, edit_labels, edit_plugins);
1120 automation->clear(start, end, 0, 1);
1121 if( edit_plugins ) {
1122 int edit_keyframes = edit_plugins < 0 ? 1 : edit_autos;
1123 for(int i = 0; i < plugin_set.total; i++) {
1124 if(!trim_edits || trim_edits == (Edits*)plugin_set.values[i])
1125 plugin_set.values[i]->clear(start, end, edit_keyframes);
1129 edits->clear(start, end);
1133 int Track::clear_handle(double start,
1140 edits->clear_handle(start, end, clear_plugins, edit_autos, distance);
1144 int Track::popup_transition(int cursor_x, int cursor_y)
1151 int Track::modify_edithandles(double oldposition, double newposition,
1152 int currentend, int handle_mode, int edit_labels,
1153 int edit_plugins, int edit_autos, int group_id)
1155 edits->modify_handles(oldposition, newposition,
1156 currentend, handle_mode, 1, edit_labels, edit_plugins,
1157 edit_autos, 0, group_id);
1161 int Track::modify_pluginhandles(double oldposition,
1169 for(int i = 0; i < plugin_set.total; i++)
1171 if(!trim_edits || trim_edits == (Edits*)plugin_set.values[i])
1172 plugin_set.values[i]->modify_handles(oldposition, newposition,
1173 // Don't allow plugin tweeks to affect edits.
1174 currentend, handle_mode, 0, 0, 0, 0, 0, 0);
1180 int Track::paste_silence(double start, double end, int edit_plugins, int edit_autos)
1182 return paste_silence(to_units(start, 0), to_units(end, 1),
1183 edit_plugins, edit_autos);
1186 int Track::paste_silence(int64_t start, int64_t end, int edit_plugins, int edit_autos)
1188 edits->paste_silence(start, end);
1190 shift_keyframes(start, end - start);
1192 shift_effects(start, end - start, edit_autos, 0);
1197 int Track::select_edit(int cursor_x,
1205 int Track::scale_time(float rate_scale, int scale_edits, int scale_autos, int64_t start, int64_t end)
1210 void Track::change_plugins(SharedLocation &old_location, SharedLocation &new_location, int do_swap)
1212 for(int i = 0; i < plugin_set.total; i++)
1214 for(Plugin *plugin = (Plugin*)plugin_set.values[i]->first;
1216 plugin = (Plugin*)plugin->next)
1218 if(plugin->plugin_type == PLUGIN_SHAREDPLUGIN)
1220 if(plugin->shared_location == old_location)
1221 plugin->shared_location = new_location;
1223 if(do_swap && plugin->shared_location == new_location)
1224 plugin->shared_location = old_location;
1230 void Track::change_modules(int old_location, int new_location, int do_swap)
1232 for(int i = 0; i < plugin_set.total; i++)
1234 for(Plugin *plugin = (Plugin*)plugin_set.values[i]->first;
1236 plugin = (Plugin*)plugin->next)
1238 if(plugin->plugin_type == PLUGIN_SHAREDPLUGIN ||
1239 plugin->plugin_type == PLUGIN_SHAREDMODULE)
1241 if(plugin->shared_location.module == old_location)
1242 plugin->shared_location.module = new_location;
1244 if(do_swap && plugin->shared_location.module == new_location)
1245 plugin->shared_location.module = old_location;
1252 int Track::playable_edit(int64_t position, int direction)
1255 if(direction == PLAY_REVERSE) position--;
1256 for(Edit *current = edits->first; current && !result; current = NEXT)
1258 if(current->startproject <= position &&
1259 current->startproject + current->length > position)
1261 //printf("Track::playable_edit %p %p\n", current->transition, current->asset);
1262 if(current->transition ||
1264 current->nested_edl) result = 1;
1271 int Track::need_edit(Edit *current, int test_transitions)
1273 return ((test_transitions && current->transition) ||
1274 (!test_transitions && current->asset));
1277 int64_t Track::plugin_change_duration(int64_t input_position,
1278 int64_t input_length,
1282 if(use_nudge) input_position += nudge;
1283 for(int i = 0; i < plugin_set.total; i++)
1285 int64_t new_duration = plugin_set.values[i]->plugin_change_duration(
1289 if(new_duration < input_length) input_length = new_duration;
1291 return input_length;
1294 int64_t Track::edit_change_duration(int64_t input_position,
1295 int64_t input_length,
1297 int test_transitions,
1301 int64_t edit_length = input_length;
1302 if(use_nudge) input_position += nudge;
1306 // ================================= Reverse playback
1307 // Get first edit on or after position
1308 for(current = edits->first;
1309 current && current->startproject + current->length <= input_position;
1315 if(current->startproject > input_position)
1317 // Before first edit
1321 if(need_edit(current, test_transitions))
1323 // Over an edit of interest.
1324 if(input_position - current->startproject < input_length)
1325 edit_length = input_position - current->startproject + 1;
1329 // Over an edit that isn't of interest.
1330 // Search for next edit of interest.
1331 for(current = PREVIOUS ;
1333 current->startproject + current->length > input_position - input_length &&
1334 !need_edit(current, test_transitions);
1339 need_edit(current, test_transitions) &&
1340 current->startproject + current->length > input_position - input_length)
1341 edit_length = input_position - current->startproject - current->length + 1;
1346 // Not over an edit. Try the last edit.
1347 current = edits->last;
1349 ((test_transitions && current->transition) ||
1350 (!test_transitions && current->asset)))
1351 edit_length = input_position - edits->length() + 1;
1356 // =================================== forward playback
1357 // Get first edit on or before position
1358 for(current = edits->last;
1359 current && current->startproject > input_position;
1365 if(current->startproject + current->length <= input_position)
1367 // Beyond last edit.
1371 if(need_edit(current, test_transitions))
1373 // Over an edit of interest.
1374 // Next edit is going to require a change.
1375 if(current->length + current->startproject - input_position < input_length)
1376 edit_length = current->startproject + current->length - input_position;
1380 // Over an edit that isn't of interest.
1381 // Search for next edit of interest.
1382 for(current = NEXT ;
1384 current->startproject < input_position + input_length &&
1385 !need_edit(current, test_transitions);
1390 need_edit(current, test_transitions) &&
1391 current->startproject < input_position + input_length)
1392 edit_length = current->startproject - input_position;
1397 // Not over an edit. Try the first edit.
1398 current = edits->first;
1400 ((test_transitions && current->transition) ||
1401 (!test_transitions && current->asset)))
1402 edit_length = edits->first->startproject - input_position;
1406 if(edit_length < input_length)
1409 return input_length;
1412 void Track::shuffle_edits(double start, double end, int first_track)
1414 ArrayList<Edit*> new_edits;
1415 ArrayList<Label*> new_labels;
1416 int64_t start_units = to_units(start, 0);
1417 int64_t end_units = to_units(end, 0);
1418 // Sample range of all edits selected
1419 //int64_t total_start_units = 0;
1420 //int64_t total_end_units = 0;
1421 // Edit before range
1422 Edit *start_edit = 0;
1423 int have_start_edit = 0;
1425 // Move all edit pointers to list
1426 for(Edit *current = edits->first;
1429 if(current->startproject >= start_units &&
1430 current->startproject + current->length <= end_units)
1432 if(!have_start_edit) start_edit = current->previous;
1433 have_start_edit = 1;
1434 //total_start_units = current->startproject;
1435 //total_end_units = current->startproject + current->length;
1436 new_edits.append(current);
1438 // Move label pointers
1439 if(first_track && edl->session->labels_follow_edits)
1441 double start_seconds = from_units(current->startproject);
1442 double end_seconds = from_units(current->startproject +
1444 for(Label *label = edl->labels->first;
1446 label = label->next)
1448 if(label->position >= start_seconds &&
1449 label->position < end_seconds)
1451 new_labels.append(label);
1452 edl->labels->remove_pointer(label);
1457 // Remove edit pointer
1458 Edit *previous = current;
1460 edits->remove_pointer(previous);
1468 // Insert pointers in random order
1469 while(new_edits.size())
1471 int index = rand() % new_edits.size();
1472 Edit *edit = new_edits.get(index);
1473 new_edits.remove_number(index);
1475 edits->insert_before(edits->first, edit);
1477 edits->insert_after(start_edit, edit);
1480 // Recalculate start position
1481 // Save old position for moving labels
1482 int64_t startproject1 = edit->startproject;
1483 int64_t startproject2 = 0;
1486 edit->startproject =
1488 edit->previous->startproject + edit->previous->length;
1492 edit->startproject = startproject2 = 0;
1496 // Insert label pointers
1497 if(first_track && edl->session->labels_follow_edits)
1499 double start_seconds1 = from_units(startproject1);
1500 double end_seconds1 = from_units(startproject1 + edit->length);
1501 double start_seconds2 = from_units(startproject2);
1502 for(int i = new_labels.size() - 1; i >= 0; i--)
1504 Label *label = new_labels.get(i);
1505 // Was in old edit position
1506 if(label->position >= start_seconds1 &&
1507 label->position < end_seconds1)
1509 // Move to new edit position
1510 double position = label->position -
1511 start_seconds1 + start_seconds2;
1512 edl->labels->insert_label(position);
1513 new_labels.remove_object_number(i);
1523 if(first_track && edl->session->labels_follow_edits)
1525 edl->labels->optimize();
1529 // exactly the same as shuffle_edits except for 1 line
1530 void Track::reverse_edits(double start, double end, int first_track)
1532 ArrayList<Edit*> new_edits;
1533 ArrayList<Label*> new_labels;
1534 int64_t start_units = to_units(start, 0);
1535 int64_t end_units = to_units(end, 0);
1536 // Sample range of all edits selected
1537 //int64_t total_start_units = 0;
1538 //int64_t total_end_units = 0;
1539 // Edit before range
1540 Edit *start_edit = 0;
1541 int have_start_edit = 0;
1543 // Move all edit pointers to list
1544 for(Edit *current = edits->first; current; )
1546 if(current->startproject >= start_units &&
1547 current->startproject + current->length <= end_units)
1549 if(!have_start_edit) start_edit = current->previous;
1550 have_start_edit = 1;
1551 //total_start_units = current->startproject;
1552 //total_end_units = current->startproject + current->length;
1553 new_edits.append(current);
1555 // Move label pointers
1556 if(first_track && edl->session->labels_follow_edits)
1558 double start_seconds = from_units(current->startproject);
1559 double end_seconds = from_units(current->startproject +
1561 for(Label *label = edl->labels->first;
1563 label = label->next)
1565 if(label->position >= start_seconds &&
1566 label->position < end_seconds)
1568 new_labels.append(label);
1569 edl->labels->remove_pointer(label);
1574 // Remove edit pointer
1575 Edit *previous = current;
1577 edits->remove_pointer(previous);
1585 // Insert pointers in reverse order
1586 while(new_edits.size())
1588 int index = new_edits.size() - 1;
1589 Edit *edit = new_edits.get(index);
1590 new_edits.remove_number(index);
1592 edits->insert_before(edits->first, edit);
1594 edits->insert_after(start_edit, edit);
1597 // Recalculate start position
1598 // Save old position for moving labels
1599 int64_t startproject1 = edit->startproject;
1600 int64_t startproject2 = 0;
1603 edit->startproject =
1605 edit->previous->startproject + edit->previous->length;
1609 edit->startproject = startproject2 = 0;
1613 // Insert label pointers
1614 if(first_track && edl->session->labels_follow_edits)
1616 double start_seconds1 = from_units(startproject1);
1617 double end_seconds1 = from_units(startproject1 + edit->length);
1618 double start_seconds2 = from_units(startproject2);
1619 for(int i = new_labels.size() - 1; i >= 0; i--)
1621 Label *label = new_labels.get(i);
1622 // Was in old edit position
1623 if(label->position >= start_seconds1 &&
1624 label->position < end_seconds1)
1626 // Move to new edit position
1627 double position = label->position -
1628 start_seconds1 + start_seconds2;
1629 edl->labels->insert_label(position);
1630 new_labels.remove_object_number(i);
1640 if(first_track && edl->session->labels_follow_edits)
1642 edl->labels->optimize();
1646 void Track::align_edits(double start, double end, Track *master_track)
1648 int64_t start_units = to_units(start, 0);
1649 int64_t end_units = to_units(end, 0);
1651 // All other tracks get silence or cut to align the edits on the times.
1652 Edit *master = master_track->edits->first;
1653 for(Edit *current = edits->first; current && master; ) {
1654 if( current->startproject >= start_units &&
1655 current->startproject + current->length <= end_units ) {
1656 // edit is in highlighted region
1657 int64_t master_length_units = to_units(master_track->from_units(master->length), 0);
1658 // starting time of master edit
1659 int64_t master_start_units = to_units(master_track->from_units(master->startproject), 0);
1660 // starting time of current edit
1661 int64_t current_startunits = current->startproject;
1663 // the following occur if multiple aligns are performed
1664 // master edit is not silence but current edit is silence
1665 if( !master->silence() && current->silence() ) {
1666 // try again with next edit
1670 if( master->silence() && !current->silence() ) {
1671 // master edit is silence but current edit is not silence
1672 master = master->next;
1675 if( current->length < master_length_units / 2 ) {
1676 // current edit is a glitch edit between 2 required edits
1682 // current edit starts before master edit
1683 if( current_startunits < master_start_units ) {
1684 //printf("Track::align_edits %d\n", __LINE__);
1685 edits->paste_silence(current_startunits, master_start_units);
1686 shift_keyframes(current_startunits,
1687 master_start_units - current_startunits);
1689 else if( current_startunits > master_start_units ) {
1690 // current edit starts after master edit
1691 edits->clear(master_start_units,
1692 current_startunits);
1693 if(edl->session->autos_follow_edits)
1694 shift_keyframes(master_start_units,
1695 current_startunits - master_start_units);
1698 master = master->next;
1702 master = master->next;
1709 int Track::purge_asset(Asset *asset)
1714 int Track::asset_used(Asset *asset)
1719 for(current_edit = edits->first; current_edit; current_edit = current_edit->next)
1721 if(current_edit->asset == asset)
1729 int Track::is_playable(int64_t position, int direction)
1735 int Track::plugin_used(int64_t position, int64_t direction)
1737 //printf("Track::plugin_used 1 %d\n", this->plugin_set.total);
1738 for(int i = 0; i < this->plugin_set.total; i++)
1740 Plugin *current_plugin = get_current_plugin(position,
1746 //printf("Track::plugin_used 2 %p %d %d\n", current_plugin, current_plugin->on, current_plugin->plugin_type);
1747 if(current_plugin &&
1748 current_plugin->on &&
1749 current_plugin->plugin_type != PLUGIN_NONE)
1754 //printf("Track::plugin_used 3 %p\n", current_plugin);
1758 // Audio is always rendered through VConsole
1759 int Track::direct_copy_possible(int64_t start, int direction, int use_nudge)
1764 int64_t Track::to_units(double position, int round)
1766 return (int64_t)position;
1769 double Track::to_doubleunits(double position)
1774 double Track::from_units(int64_t position)
1776 return (double)position;
1779 int64_t Track::frame_align(int64_t position, int round)
1781 if( data_type != TRACK_VIDEO && edl->session->cursor_on_frames )
1782 position = to_units(edl->align_to_frame(from_units(position), round), round);
1786 Plugin *Track::plugin_exists(int plugin_id)
1788 for( int i=0; i<plugin_set.size(); ++i ) {
1789 PluginSet *set = plugin_set.get(i);
1790 Plugin *plugin = (Plugin*)set->first;
1791 for( ; plugin; plugin=(Plugin*)plugin->next ) {
1792 if( plugin->orig_id == plugin_id )
1796 for( Edit *current=edits->first; current; current=NEXT ) {
1797 Plugin *plugin = (Plugin *)current->transition;
1798 if( plugin && plugin->orig_id == plugin_id )
1804 int Track::get_mixer_id()
1806 if( mixer_id < 0 ) {
1808 for( Track *track=tracks->first; track!=0; track=track->next )
1809 if( track->mixer_id > v ) v = track->mixer_id;
1815 void Track::get_fauto_xyz(int fauto, float &x, float &y, float &z)
1817 FloatAutos **fautos = (FloatAutos **)&automation->autos;
1818 FloatAuto *xauto = (FloatAuto *)fautos[fauto+0]->get_auto_for_editing(-1, 1);
1819 if( xauto ) x = xauto->get_value();
1820 FloatAuto *yauto = (FloatAuto *)fautos[fauto+1]->get_auto_for_editing(-1, 1);
1821 if( yauto ) y = yauto->get_value();
1822 FloatAuto *zauto = (FloatAuto *)fautos[fauto+2]->get_auto_for_editing(-1, 1);
1823 if( zauto ) z = zauto->get_value();
1825 void Track::set_fauto_xyz(int fauto, float x, float y, float z)
1827 FloatAutos **fautos = (FloatAutos **)&automation->autos;
1828 FloatAuto *xauto = (FloatAuto *)fautos[fauto+0]->get_auto_for_editing(-1, 1);
1829 if( xauto ) xauto->set_value(x);
1830 FloatAuto *yauto = (FloatAuto *)fautos[fauto+1]->get_auto_for_editing(-1, 1);
1831 if( yauto ) yauto->set_value(y);
1832 FloatAuto *zauto = (FloatAuto *)fautos[fauto+2]->get_auto_for_editing(-1, 1);
1833 if( zauto ) zauto->set_value(z);
1836 void Track::get_projector(float &x, float &y, float &z)
1838 get_fauto_xyz(AUTOMATION_PROJECTOR_X, x, y, z);
1840 void Track::set_projector(float x, float y, float z)
1842 set_fauto_xyz(AUTOMATION_PROJECTOR_X, x, y, z);
1845 void Track::get_camera(float &x, float &y, float &z)
1847 get_fauto_xyz(AUTOMATION_CAMERA_X, x, y, z);
1849 void Track::set_camera(float x, float y, float z)
1851 set_fauto_xyz(AUTOMATION_CAMERA_X, x, y, z);