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"
40 #include "pluginset.h"
41 #include "mainsession.h"
45 #include "trackcanvas.h"
47 #include "transition.h"
48 #include "transportque.inc"
54 Track::Track(EDL *edl, Tracks *tracks) : ListItem<Track>()
57 this->tracks = tracks;
66 track_w = edl->session->output_w;
67 track_h = edl->session->output_h;
75 plugin_set.remove_all_objects();
78 void Track::create_objects()
83 int Track::copy_settings(Track *track)
85 this->expand_view = track->expand_view;
86 this->draw = track->draw;
87 this->gang = track->gang;
88 this->record = track->record;
89 this->nudge = track->nudge;
90 this->play = track->play;
91 this->track_w = track->track_w;
92 this->track_h = track->track_h;
93 strcpy(this->title, track->title);
103 int Track::load_defaults(BC_Hash *defaults)
108 void Track::equivalent_output(Track *track, double *result)
110 if(data_type != track->data_type ||
111 track_w != track->track_w ||
112 track_h != track->track_h ||
113 play != track->play ||
114 nudge != track->nudge)
117 // Convert result to track units
118 int64_t result2 = -1;
119 automation->equivalent_output(track->automation, &result2);
120 edits->equivalent_output(track->edits, &result2);
122 int plugin_sets = MIN(plugin_set.total, track->plugin_set.total);
123 // Test existing plugin sets
124 for(int i = 0; i < plugin_sets; i++)
126 plugin_set.values[i]->equivalent_output(
127 track->plugin_set.values[i],
131 // New EDL has more plugin sets. Get starting plugin in new plugin sets
132 for(int i = plugin_sets; i < plugin_set.total; i++)
134 Plugin *current = plugin_set.values[i]->get_first_plugin();
137 if(result2 < 0 || current->startproject < result2)
138 result2 = current->startproject;
142 // New EDL has fewer plugin sets. Get starting plugin in old plugin set
143 for(int i = plugin_sets; i < track->plugin_set.total; i++)
145 Plugin *current = track->plugin_set.values[i]->get_first_plugin();
148 if(result2 < 0 || current->startproject < result2)
149 result2 = current->startproject;
153 // Number of plugin sets differs but somehow we didn't find the start of the
155 if(track->plugin_set.total != plugin_set.total && result2 < 0)
159 (*result < 0 || from_units(result2) < *result))
160 *result = from_units(result2);
164 int Track::is_synthesis(int64_t position,
167 int is_synthesis = 0;
168 for(int i = 0; i < plugin_set.total; i++)
170 Plugin *plugin = get_current_plugin(position,
177 // Assume data from a shared track is synthesized
178 if(plugin->plugin_type == PLUGIN_SHAREDMODULE)
181 is_synthesis = plugin->is_synthesis(position,
184 //printf("Track::is_synthesis %d %d\n", __LINE__, is_synthesis);
185 if(is_synthesis) break;
191 void Track::copy_from(Track *track)
193 copy_settings(track);
194 edits->copy_from(track->edits);
195 for(int i = 0; i < this->plugin_set.total; i++)
196 delete this->plugin_set.values[i];
197 this->plugin_set.remove_all_objects();
199 for(int i = 0; i < track->plugin_set.total; i++)
201 PluginSet *new_plugin_set = plugin_set.append(new PluginSet(edl, this));
202 new_plugin_set->copy_from(track->plugin_set.values[i]);
204 automation->copy_from(track->automation);
205 this->track_w = track->track_w;
206 this->track_h = track->track_h;
209 Track& Track::operator=(Track& track)
211 printf("Track::operator= 1\n");
216 int Track::vertical_span(Theme *theme)
220 result = edl->local_session->zoom_track +
222 theme->get_image("plugin_bg_data")->get_h();
224 result = edl->local_session->zoom_track;
226 if(edl->session->show_titles)
227 result += theme->get_image("title_bg_data")->get_h();
232 double Track::get_length()
234 double total_length = 0;
240 length = from_units(edits->last->startproject + edits->last->length);
241 if(length > total_length) total_length = length;
245 for(int i = 0; i < plugin_set.total; i++)
247 if( !plugin_set.values[i]->last ) continue;
248 length = from_units(plugin_set.values[i]->last->startproject +
249 plugin_set.values[i]->last->length);
250 if(length > total_length) total_length = length;
254 length = from_units(automation->get_length());
255 if(length > total_length) total_length = length;
261 int Track::has_speed()
263 FloatAutos *autos = (FloatAutos*)automation->autos[AUTOMATION_SPEED];
268 for(FloatAuto *current = (FloatAuto*)autos->first;
270 current = (FloatAuto*)current->next)
272 if(!EQUIV(current->get_value(), 1.0) ||
273 !EQUIV(current->get_control_in_value(), 0.0) ||
274 !EQUIV(current->get_control_out_value(), 0.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 expand_view = file->tag.get_property("EXPAND", expand_view);
325 track_w = file->tag.get_property("TRACK_W", track_w);
326 track_h = file->tag.get_property("TRACK_H", track_h);
328 load_header(file, load_flags);
331 result = file->read_tag();
335 if(file->tag.title_is("/TRACK"))
340 if(file->tag.title_is("TITLE"))
342 file->read_text_until("/TITLE", title, BCTEXTLEN);
345 if(load_flags && automation->load(file)
346 /* strstr(file->tag.get_title(), "AUTOS") */)
351 if(file->tag.title_is("EDITS"))
353 if(load_flags & LOAD_EDITS)
354 edits->load(file, track_offset);
356 result = file->skip_tag();
359 if(file->tag.title_is("PLUGINSET"))
361 if(load_flags & LOAD_EDITS)
363 PluginSet *plugin_set = new PluginSet(edl, this);
364 this->plugin_set.append(plugin_set);
365 plugin_set->load(file, load_flags);
368 if(load_flags & LOAD_AUTOMATION)
370 if(current_plugin < this->plugin_set.total)
372 PluginSet *plugin_set = this->plugin_set.values[current_plugin];
373 plugin_set->load(file, load_flags);
378 result = file->skip_tag();
381 load_derived(file, load_flags);
390 void Track::insert_asset(Asset *asset,
396 edits->insert_asset(asset,
399 to_units(position, 0),
405 // Default keyframes: We don't replace default keyframes in pasting but
406 // when inserting the first EDL of a load operation we need to replace
407 // the default keyframes.
409 // Plugins: This is an arbitrary behavior
411 // 1) No plugin in source track: Paste silence into destination
413 // 2) Plugin in source track: plugin in source track is inserted into
414 // existing destination track plugin sets, new sets being added when
417 void Track::insert_track(Track *track,
424 // Calculate minimum length of data to pad.
425 int64_t min_length = to_units(
426 MAX(edl_length, track->get_length()),
428 //printf("Track::insert_track %d %s %jd\n", __LINE__, title, min_length);
430 // Decide whether to copy settings based on load_mode
431 if(replace_default) copy_settings(track);
433 edits->insert_edits(track->edits,
434 to_units(position, 0),
439 insert_plugin_set(track,
440 to_units(position, 0),
445 automation->insert_track(track->automation,
446 to_units(position, 0),
454 // Called by insert_track
455 void Track::insert_plugin_set(Track *track,
460 // Extend plugins if no incoming plugins
461 if(!track->plugin_set.total)
463 shift_effects(position,
468 for(int i = 0; i < track->plugin_set.total; i++)
470 if(i >= plugin_set.total)
471 plugin_set.append(new PluginSet(edl, this));
473 plugin_set.values[i]->insert_edits(track->plugin_set.values[i],
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(),
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)
659 for(int i = 0; i < plugin_set.total; 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;
849 int Track::dump(FILE *fp)
851 fprintf(fp," Data type %d\n", data_type);
852 fprintf(fp," Title %s\n", title);
853 fprintf(fp," Edits:\n");
854 for(Edit* current = edits->first; current; current = NEXT)
858 automation->dump(fp);
859 fprintf(fp," Plugin Sets: %d\n", plugin_set.total);
861 for(int i = 0; i < plugin_set.total; i++)
862 plugin_set.values[i]->dump(fp);
863 //printf("Track::dump 2\n");
887 Track::Track() : ListItem<Track>()
892 // ======================================== accounting
894 int Track::number_of()
896 return tracks->number_of(this);
911 // ================================================= editing
913 int Track::select_auto(AutoConf *auto_conf, int cursor_x, int cursor_y)
918 int Track::move_auto(AutoConf *auto_conf, int cursor_x, int cursor_y, int shift_down)
923 int Track::release_auto()
928 // used for copying automation alone
929 int Track::copy_automation(double selectionstart,
935 int64_t start = to_units(selectionstart, 0);
936 int64_t end = to_units(selectionend, 1);
938 file->tag.set_title("TRACK");
942 file->append_newline();
944 automation->copy(start, end, file, default_only, active_only);
946 if(edl->session->auto_conf->plugins)
948 for(int i = 0; i < plugin_set.total; i++)
951 plugin_set.values[i]->copy_keyframes(start,
959 file->tag.set_title("/TRACK");
961 file->append_newline();
962 file->append_newline();
963 file->append_newline();
964 file->append_newline();
969 int Track::paste_automation(double selectionstart,
977 // Only used for pasting automation alone.
982 int current_pluginset;
984 if(data_type == TRACK_AUDIO)
985 scale = edl->session->sample_rate / sample_rate;
987 scale = edl->session->frame_rate / frame_rate;
989 total_length *= scale;
990 start = to_units(selectionstart, 0);
991 length = to_units(total_length, 1);
993 current_pluginset = 0;
994 //printf("Track::paste_automation 1\n");
998 result = file->read_tag();
1002 if(file->tag.title_is("/TRACK"))
1005 if(automation->paste(start, length, scale, file,
1006 default_only, active_only, 0)) {}
1007 else if(file->tag.title_is("PLUGINSET")) {
1008 if(current_pluginset < plugin_set.total) {
1009 plugin_set.values[current_pluginset]->
1010 paste_keyframes(start, length, file,
1011 default_only, active_only);
1012 current_pluginset++;
1022 void Track::clear_automation(double selectionstart,
1023 double selectionend,
1027 int64_t start = to_units(selectionstart, 0);
1028 int64_t end = to_units(selectionend, 1);
1030 automation->clear(start, end, edl->session->auto_conf, 0);
1032 if(edl->session->auto_conf->plugins)
1034 for(int i = 0; i < plugin_set.total; i++)
1036 plugin_set.values[i]->clear_keyframes(start, end);
1042 void Track::set_automation_mode(double selectionstart,
1043 double selectionend,
1046 int64_t start = to_units(selectionstart, 0);
1047 int64_t end = to_units(selectionend, 1);
1049 automation->set_automation_mode(start, end, mode, edl->session->auto_conf);
1055 int Track::copy(double start,
1058 const char *output_path)
1060 // Use a copy of the selection in converted units
1061 // So copy_automation doesn't reconvert.
1062 int64_t start_unit = to_units(start, 0);
1063 int64_t end_unit = to_units(end, 1);
1068 file->tag.set_title("TRACK");
1069 file->tag.set_property("RECORD", record);
1070 file->tag.set_property("NUDGE", nudge);
1071 file->tag.set_property("PLAY", play);
1072 file->tag.set_property("GANG", gang);
1073 file->tag.set_property("DRAW", draw);
1074 file->tag.set_property("EXPAND", expand_view);
1075 file->tag.set_property("TRACK_W", track_w);
1076 file->tag.set_property("TRACK_H", track_h);
1079 file->append_newline();
1082 file->tag.set_title("TITLE");
1084 file->append_text(title);
1085 file->tag.set_title("/TITLE");
1087 file->append_newline();
1089 // if(data_type == TRACK_AUDIO)
1090 // file->tag.set_property("TYPE", "AUDIO");
1092 // file->tag.set_property("TYPE", "VIDEO");
1094 // file->append_tag();
1095 // file->append_newline();
1097 edits->copy(start_unit, end_unit, file, output_path);
1100 auto_conf.set_all(1);
1101 automation->copy(start_unit, end_unit, file, 0, 0);
1104 for(int i = 0; i < plugin_set.total; i++)
1106 plugin_set.values[i]->copy(start_unit, end_unit, file);
1109 copy_derived(start_unit, end_unit, file);
1111 file->tag.set_title("/TRACK");
1113 file->append_newline();
1114 file->append_newline();
1115 file->append_newline();
1116 file->append_newline();
1121 int Track::copy_assets(double start,
1123 ArrayList<Asset*> *asset_list)
1127 start = to_units(start, 0);
1128 end = to_units(end, 1);
1130 Edit *current = edits->editof((int64_t)start, PLAY_FORWARD, 0);
1133 while(current && current->startproject < end)
1135 // Check for duplicate assets
1138 for(i = 0, result = 0; i < asset_list->total; i++)
1140 if(asset_list->values[i] == current->asset) result = 1;
1142 // append pointer to new asset
1143 if(!result) asset_list->append(current->asset);
1156 int Track::clear(double start,
1165 // Edits::move_auto calls this routine after the units are converted to the track
1167 //printf("Track::clear 1 %d %d %d\n", edit_edits, edit_labels, edit_plugins);
1170 start = to_units(start, 0);
1171 end = to_units(end, 1);
1176 automation->clear((int64_t)start, (int64_t)end, 0, 1);
1180 for(int i = 0; i < plugin_set.total; i++)
1182 if(!trim_edits || trim_edits == (Edits*)plugin_set.values[i])
1183 plugin_set.values[i]->clear((int64_t)start, (int64_t)end, edit_autos);
1188 edits->clear((int64_t)start, (int64_t)end);
1192 int Track::clear_handle(double start,
1199 edits->clear_handle(start, end, clear_plugins, edit_autos, distance);
1203 int Track::popup_transition(int cursor_x, int cursor_y)
1210 int Track::modify_edithandles(double oldposition,
1218 edits->modify_handles(oldposition,
1232 int Track::modify_pluginhandles(double oldposition,
1240 for(int i = 0; i < plugin_set.total; i++)
1242 if(!trim_edits || trim_edits == (Edits*)plugin_set.values[i])
1243 plugin_set.values[i]->modify_handles(oldposition,
1247 // Don't allow plugin tweeks to affect edits.
1258 int Track::paste_silence(double start, double end, int edit_plugins, int edit_autos)
1260 int64_t start_i = to_units(start, 0);
1261 int64_t end_i = to_units(end, 1);
1263 edits->paste_silence(start_i, end_i);
1264 if(edit_autos) shift_keyframes(start_i, end_i - start_i);
1265 if(edit_plugins) shift_effects(start_i, end_i - start_i, edit_autos);
1271 int Track::select_edit(int cursor_x,
1279 int Track::scale_time(float rate_scale, int scale_edits, int scale_autos, int64_t start, int64_t end)
1284 void Track::change_plugins(SharedLocation &old_location, SharedLocation &new_location, int do_swap)
1286 for(int i = 0; i < plugin_set.total; i++)
1288 for(Plugin *plugin = (Plugin*)plugin_set.values[i]->first;
1290 plugin = (Plugin*)plugin->next)
1292 if(plugin->plugin_type == PLUGIN_SHAREDPLUGIN)
1294 if(plugin->shared_location == old_location)
1295 plugin->shared_location = new_location;
1297 if(do_swap && plugin->shared_location == new_location)
1298 plugin->shared_location = old_location;
1304 void Track::change_modules(int old_location, int new_location, int do_swap)
1306 for(int i = 0; i < plugin_set.total; i++)
1308 for(Plugin *plugin = (Plugin*)plugin_set.values[i]->first;
1310 plugin = (Plugin*)plugin->next)
1312 if(plugin->plugin_type == PLUGIN_SHAREDPLUGIN ||
1313 plugin->plugin_type == PLUGIN_SHAREDMODULE)
1315 if(plugin->shared_location.module == old_location)
1316 plugin->shared_location.module = new_location;
1318 if(do_swap && plugin->shared_location.module == new_location)
1319 plugin->shared_location.module = old_location;
1326 int Track::playable_edit(int64_t position, int direction)
1329 if(direction == PLAY_REVERSE) position--;
1330 for(Edit *current = edits->first; current && !result; current = NEXT)
1332 if(current->startproject <= position &&
1333 current->startproject + current->length > position)
1335 //printf("Track::playable_edit %p %p\n", current->transition, current->asset);
1336 if(current->transition ||
1338 current->nested_edl) result = 1;
1345 int Track::need_edit(Edit *current, int test_transitions)
1347 return ((test_transitions && current->transition) ||
1348 (!test_transitions && current->asset));
1351 int64_t Track::plugin_change_duration(int64_t input_position,
1352 int64_t input_length,
1356 if(use_nudge) input_position += nudge;
1357 for(int i = 0; i < plugin_set.total; i++)
1359 int64_t new_duration = plugin_set.values[i]->plugin_change_duration(
1363 if(new_duration < input_length) input_length = new_duration;
1365 return input_length;
1368 int64_t Track::edit_change_duration(int64_t input_position,
1369 int64_t input_length,
1371 int test_transitions,
1375 int64_t edit_length = input_length;
1376 if(use_nudge) input_position += nudge;
1380 // ================================= Reverse playback
1381 // Get first edit on or after position
1382 for(current = edits->first;
1383 current && current->startproject + current->length <= input_position;
1389 if(current->startproject > input_position)
1391 // Before first edit
1395 if(need_edit(current, test_transitions))
1397 // Over an edit of interest.
1398 if(input_position - current->startproject < input_length)
1399 edit_length = input_position - current->startproject + 1;
1403 // Over an edit that isn't of interest.
1404 // Search for next edit of interest.
1405 for(current = PREVIOUS ;
1407 current->startproject + current->length > input_position - input_length &&
1408 !need_edit(current, test_transitions);
1413 need_edit(current, test_transitions) &&
1414 current->startproject + current->length > input_position - input_length)
1415 edit_length = input_position - current->startproject - current->length + 1;
1420 // Not over an edit. Try the last edit.
1421 current = edits->last;
1423 ((test_transitions && current->transition) ||
1424 (!test_transitions && current->asset)))
1425 edit_length = input_position - edits->length() + 1;
1430 // =================================== forward playback
1431 // Get first edit on or before position
1432 for(current = edits->last;
1433 current && current->startproject > input_position;
1439 if(current->startproject + current->length <= input_position)
1441 // Beyond last edit.
1445 if(need_edit(current, test_transitions))
1447 // Over an edit of interest.
1448 // Next edit is going to require a change.
1449 if(current->length + current->startproject - input_position < input_length)
1450 edit_length = current->startproject + current->length - input_position;
1454 // Over an edit that isn't of interest.
1455 // Search for next edit of interest.
1456 for(current = NEXT ;
1458 current->startproject < input_position + input_length &&
1459 !need_edit(current, test_transitions);
1464 need_edit(current, test_transitions) &&
1465 current->startproject < input_position + input_length)
1466 edit_length = current->startproject - input_position;
1471 // Not over an edit. Try the first edit.
1472 current = edits->first;
1474 ((test_transitions && current->transition) ||
1475 (!test_transitions && current->asset)))
1476 edit_length = edits->first->startproject - input_position;
1480 if(edit_length < input_length)
1483 return input_length;
1486 void Track::shuffle_edits(double start, double end, int first_track)
1488 ArrayList<Edit*> new_edits;
1489 ArrayList<Label*> new_labels;
1490 int64_t start_units = to_units(start, 0);
1491 int64_t end_units = to_units(end, 0);
1492 // Sample range of all edits selected
1493 //int64_t total_start_units = 0;
1494 //int64_t total_end_units = 0;
1495 // Edit before range
1496 Edit *start_edit = 0;
1497 int have_start_edit = 0;
1499 // Move all edit pointers to list
1500 for(Edit *current = edits->first;
1503 if(current->startproject >= start_units &&
1504 current->startproject + current->length <= end_units)
1506 if(!have_start_edit) start_edit = current->previous;
1507 have_start_edit = 1;
1508 //total_start_units = current->startproject;
1509 //total_end_units = current->startproject + current->length;
1510 new_edits.append(current);
1512 // Move label pointers
1513 if(first_track && edl->session->labels_follow_edits)
1515 double start_seconds = from_units(current->startproject);
1516 double end_seconds = from_units(current->startproject +
1518 for(Label *label = edl->labels->first;
1520 label = label->next)
1522 if(label->position >= start_seconds &&
1523 label->position < end_seconds)
1525 new_labels.append(label);
1526 edl->labels->remove_pointer(label);
1531 // Remove edit pointer
1532 Edit *previous = current;
1534 edits->remove_pointer(previous);
1542 // Insert pointers in random order
1543 while(new_edits.size())
1545 int index = rand() % new_edits.size();
1546 Edit *edit = new_edits.get(index);
1547 new_edits.remove_number(index);
1549 edits->insert_before(edits->first, edit);
1551 edits->insert_after(start_edit, edit);
1554 // Recalculate start position
1555 // Save old position for moving labels
1556 int64_t startproject1 = edit->startproject;
1557 int64_t startproject2 = 0;
1560 edit->startproject =
1562 edit->previous->startproject + edit->previous->length;
1566 edit->startproject = startproject2 = 0;
1570 // Insert label pointers
1571 if(first_track && edl->session->labels_follow_edits)
1573 double start_seconds1 = from_units(startproject1);
1574 double end_seconds1 = from_units(startproject1 + edit->length);
1575 double start_seconds2 = from_units(startproject2);
1576 for(int i = new_labels.size() - 1; i >= 0; i--)
1578 Label *label = new_labels.get(i);
1579 // Was in old edit position
1580 if(label->position >= start_seconds1 &&
1581 label->position < end_seconds1)
1583 // Move to new edit position
1584 double position = label->position -
1585 start_seconds1 + start_seconds2;
1586 edl->labels->insert_label(position);
1587 new_labels.remove_object_number(i);
1597 if(first_track && edl->session->labels_follow_edits)
1599 edl->labels->optimize();
1603 // exactly the same as shuffle_edits except for 1 line
1604 void Track::reverse_edits(double start, double end, int first_track)
1606 ArrayList<Edit*> new_edits;
1607 ArrayList<Label*> new_labels;
1608 int64_t start_units = to_units(start, 0);
1609 int64_t end_units = to_units(end, 0);
1610 // Sample range of all edits selected
1611 //int64_t total_start_units = 0;
1612 //int64_t total_end_units = 0;
1613 // Edit before range
1614 Edit *start_edit = 0;
1615 int have_start_edit = 0;
1617 // Move all edit pointers to list
1618 for(Edit *current = edits->first; current; )
1620 if(current->startproject >= start_units &&
1621 current->startproject + current->length <= end_units)
1623 if(!have_start_edit) start_edit = current->previous;
1624 have_start_edit = 1;
1625 //total_start_units = current->startproject;
1626 //total_end_units = current->startproject + current->length;
1627 new_edits.append(current);
1629 // Move label pointers
1630 if(first_track && edl->session->labels_follow_edits)
1632 double start_seconds = from_units(current->startproject);
1633 double end_seconds = from_units(current->startproject +
1635 for(Label *label = edl->labels->first;
1637 label = label->next)
1639 if(label->position >= start_seconds &&
1640 label->position < end_seconds)
1642 new_labels.append(label);
1643 edl->labels->remove_pointer(label);
1648 // Remove edit pointer
1649 Edit *previous = current;
1651 edits->remove_pointer(previous);
1659 // Insert pointers in reverse order
1660 while(new_edits.size())
1662 int index = new_edits.size() - 1;
1663 Edit *edit = new_edits.get(index);
1664 new_edits.remove_number(index);
1666 edits->insert_before(edits->first, edit);
1668 edits->insert_after(start_edit, edit);
1671 // Recalculate start position
1672 // Save old position for moving labels
1673 int64_t startproject1 = edit->startproject;
1674 int64_t startproject2 = 0;
1677 edit->startproject =
1679 edit->previous->startproject + edit->previous->length;
1683 edit->startproject = startproject2 = 0;
1687 // Insert label pointers
1688 if(first_track && edl->session->labels_follow_edits)
1690 double start_seconds1 = from_units(startproject1);
1691 double end_seconds1 = from_units(startproject1 + edit->length);
1692 double start_seconds2 = from_units(startproject2);
1693 for(int i = new_labels.size() - 1; i >= 0; i--)
1695 Label *label = new_labels.get(i);
1696 // Was in old edit position
1697 if(label->position >= start_seconds1 &&
1698 label->position < end_seconds1)
1700 // Move to new edit position
1701 double position = label->position -
1702 start_seconds1 + start_seconds2;
1703 edl->labels->insert_label(position);
1704 new_labels.remove_object_number(i);
1714 if(first_track && edl->session->labels_follow_edits)
1716 edl->labels->optimize();
1720 void Track::align_edits(double start,
1722 ArrayList<double> *times)
1724 int64_t start_units = to_units(start, 0);
1725 int64_t end_units = to_units(end, 0);
1727 // If 1st track with data, times is empty & we need to collect the edit times.
1730 for(Edit *current = edits->first; current; current = NEXT)
1732 if(current->startproject >= start_units &&
1733 current->startproject + current->length <= end_units)
1735 times->append(from_units(current->startproject));
1740 // All other tracks get silence or cut to align the edits on the times.
1742 int current_time = 0;
1743 for(Edit *current = edits->first;
1744 current && current_time < times->size(); )
1746 if(current->startproject >= start_units &&
1747 current->startproject + current->length <= end_units)
1749 int64_t desired_startunits = to_units(times->get(current_time), 0);
1750 int64_t current_startunits = current->startproject;
1754 if(current_startunits < desired_startunits)
1756 //printf("Track::align_edits %d\n", __LINE__);
1757 edits->paste_silence(current_startunits,
1758 desired_startunits);
1759 shift_keyframes(current_startunits,
1760 desired_startunits - current_startunits);
1763 if(current_startunits > desired_startunits)
1765 edits->clear(desired_startunits,
1766 current_startunits);
1767 if(edl->session->autos_follow_edits)
1768 shift_keyframes(desired_startunits,
1769 current_startunits - desired_startunits);
1784 int Track::purge_asset(Asset *asset)
1789 int Track::asset_used(Asset *asset)
1794 for(current_edit = edits->first; current_edit; current_edit = current_edit->next)
1796 if(current_edit->asset == asset)
1804 int Track::is_playable(int64_t position, int direction)
1810 int Track::plugin_used(int64_t position, int64_t direction)
1812 //printf("Track::plugin_used 1 %d\n", this->plugin_set.total);
1813 for(int i = 0; i < this->plugin_set.total; i++)
1815 Plugin *current_plugin = get_current_plugin(position,
1821 //printf("Track::plugin_used 2 %p %d %d\n", current_plugin, current_plugin->on, current_plugin->plugin_type);
1822 if(current_plugin &&
1823 current_plugin->on &&
1824 current_plugin->plugin_type != PLUGIN_NONE)
1829 //printf("Track::plugin_used 3 %p\n", current_plugin);
1833 // Audio is always rendered through VConsole
1834 int Track::direct_copy_possible(int64_t start, int direction, int use_nudge)
1839 int64_t Track::to_units(double position, int round)
1841 return (int64_t)position;
1844 double Track::to_doubleunits(double position)
1849 double Track::from_units(int64_t position)
1851 return (double)position;
1854 int Track::plugin_exists(Plugin *plugin)
1856 for(int number = 0; number < plugin_set.size(); number++)
1858 PluginSet *ptr = plugin_set.get(number);
1859 for(Plugin *current_plugin = (Plugin*)ptr->first;
1861 current_plugin = (Plugin*)current_plugin->next)
1863 if(current_plugin == plugin) return 1;
1867 for(Edit *current = edits->first; current; current = NEXT)
1869 if(current->transition &&
1870 (Plugin*)current->transition == plugin) return 1;