/* * CINELERRA * Copyright (C) 2010 Adam Williams * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "assets.h" #include "atrack.h" #include "automation.h" #include "aedits.h" #include "bcsignals.h" #include "edit.h" #include "edits.h" #include "edl.h" #include "edlsession.h" #include "filexml.h" #include "intauto.h" #include "intautos.h" #include "labels.h" #include "localsession.h" #include "mainundo.h" #include "module.h" #include "mainsession.h" #include "pluginserver.h" #include "pluginset.h" #include "plugin.h" #include "timebar.h" #include "trackcanvas.h" #include "tracks.h" #include "trackscroll.h" #include "transition.h" #include "transportque.h" #include "vtrack.h" #include int Tracks::blade(double position) { for( Track *track=first; track!=0; track=track->next ) { if( !track->is_armed() ) continue; track->blade(position); } return 0; } int Tracks::clear(double start, double end, int clear_plugins, int edit_autos) { Track *current_track; for(current_track = first; current_track; current_track = current_track->next) { if(current_track->is_armed()) { current_track->clear(start, end, 1, // edits 1, // labels clear_plugins, // edit_plugins edit_autos, 0); // trim_edits } } return 0; } void Tracks::clear_automation(double selectionstart, double selectionend) { Track* current_track; for(current_track = first; current_track; current_track = current_track->next) { if(current_track->is_armed()) { current_track->clear_automation(selectionstart, selectionend, 0, 0); } } } void Tracks::clear_transitions(double start, double end) { for(Track *current_track = first; current_track; current_track = current_track->next) { if(current_track->is_armed()) { int64_t start_units = current_track->to_units(start, 0); int64_t end_units = current_track->to_units(end, 0); for(Edit *current_edit = current_track->edits->first; current_edit; current_edit = current_edit->next) { if(current_edit->startproject >= start_units && current_edit->startproject < end_units && current_edit->transition) { current_edit->detach_transition(); } } } } } int Tracks::clear_hard_edges(double start, double end) { for( Track *track=first; track; track=track->next ) { if( !track->is_armed() ) continue; int64_t start_units = track->to_units(start, 0); int64_t end_units = track->to_units(end, 0); for( Edit *edit=track->edits->first; edit; edit=edit->next ) { int64_t pos = edit->startproject; if( pos > end_units ) break; if( pos >= start_units ) { edit->hard_left = 0; if( edit->previous ) edit->previous->hard_right = 0; } pos += edit->length; if( pos > end_units ) break; if( pos >= start_units ) { edit->hard_right = 0; if( edit->next ) edit->next->hard_left = 0; } } } return 0; } void Tracks::shuffle_edits(double start, double end) { // This doesn't affect automation or effects // Labels follow the first track. int first_track = 1; for(Track *current_track = first; current_track; current_track = current_track->next) { if(current_track->is_armed()) { current_track->shuffle_edits(start, end, first_track); first_track = 0; } } } void Tracks::reverse_edits(double start, double end) { // This doesn't affect automation or effects // Labels follow the first track. int first_track = 1; for(Track *current_track = first; current_track; current_track = current_track->next) { if(current_track->is_armed()) { current_track->reverse_edits(start, end, first_track); first_track = 0; } } } void Tracks::align_edits(double start, double end) { // This doesn't affect automation or effects Track *master_track = 0; for( Track *track=first; track; track=track->next ) { if( !track->is_armed() ) continue; if( !master_track ) master_track = track; else track->align_edits(start, end, master_track); } } void Tracks::set_edit_length(double start, double end, double length) { int first_track = 1; for(Track *current_track = first; current_track; current_track = current_track->next) { if(current_track->is_armed()) { #define USE_FLOATING_LENGTHS #ifdef USE_FLOATING_LENGTHS // The first edit anchors the length offsets. // Round edits up & down so they end where they would if they all had floating point lengths. //int first_edit = 1; int64_t start_units = current_track->to_units(start, 0); int64_t end_units = current_track->to_units(end, 0); // Total time of edits accumulated, in track units int64_t total_units = 0; // Number of length offsets added so far int total_lengths = 0; for(Edit *current_edit = current_track->edits->last; current_edit; current_edit = current_edit->previous) { if(current_edit->startproject >= start_units && current_edit->startproject + current_edit->length <= end_units) { // Calculate true length based on number of length offsets & total time double end_time = (1 + total_lengths) * length; int64_t length_units = current_track->to_units(end_time, 0) - total_units; if(length_units < 1) length_units = 1; //printf("Tracks::set_edit_length %d %f %f\n", __LINE__, // end_time, current_track->from_units(total_units)); total_units += length_units; // Go in using the edit handle interface int64_t starting_length = current_edit->length; current_edit->shift_end(MOVE_RIPPLE, current_edit->startproject + length_units, current_edit->startproject + current_edit->length, 0, edl->session->autos_follow_edits, edl->session->plugins_follow_edits, 0); int64_t ending_length = current_edit->length; if(edl->session->labels_follow_edits && first_track) { // printf("Tracks::set_edit_length %d %f %f\n", // __LINE__, // current_track->from_units(current_edit->startproject + starting_length), // current_track->from_units(current_edit->startproject + ending_length)); edl->labels->modify_handles( current_track->from_units(current_edit->startproject + starting_length), current_track->from_units(current_edit->startproject + ending_length), 1); } //first_edit = 0; total_lengths++; } } #else // USE_FLOATING_LENGTHS // The first edit anchors the length offsets. // The idea was to round edits up & down so they end where they should // if they all had floating point lengths. It's easier just to make sure the framerate // is divisible by the required length. // int first_edit = 1; int64_t start_units = current_track->to_units(start, 0); int64_t end_units = current_track->to_units(end, 0); int64_t length_units = current_track->to_units(length, 1); // Starting time of the length offsets in seconds // double start_time = 0; // Number of length offsets added so far // int total_lengths = 0; for(Edit *current_edit = current_track->edits->last; current_edit; current_edit = current_edit->previous) { if(current_edit->startproject >= start_units && current_edit->startproject + current_edit->length <= end_units) { // Calculate starting time of length offsets // if(first_edit) // { // start_time = current_track->from_units(current_edit->startproject); // } // Calculate true length based on number of length offsets // double end_time = start_time + (1 + total_lengths) * length; // int64_t length_units = current_track->to_units(end_time, 0) - // current_edit->startproject; // if(length_units < 1) length_units = 1; // Go in using the edit handle interface int64_t starting_length = current_edit->length; current_edit->shift_end(MOVE_RIPPLE, current_edit->startproject + length_units, current_edit->startproject + current_edit->length, 0, edl->session->autos_follow_edits, edl->session->plugins_follow_edits, 0); int64_t ending_length = current_edit->length; if(edl->session->labels_follow_edits && first_track) { // printf("Tracks::set_edit_length %d %f %f\n", __LINE__, // current_track->from_units(current_edit->startproject + starting_length), // current_track->from_units(current_edit->startproject + ending_length)); edl->labels->modify_handles( current_track->from_units(current_edit->startproject + starting_length), current_track->from_units(current_edit->startproject + ending_length), 1); } // first_edit = 0; // total_lengths++; } } #endif // !USE_FLOATING_LENGTHS first_track = 0; } } } void Tracks::set_transition_length(double start, double end, double length) { for(Track *current_track = first; current_track; current_track = current_track->next) { if(current_track->is_armed()) { int64_t start_units = current_track->to_units(start, 0); int64_t end_units = current_track->to_units(end, 0); for(Edit *current_edit = current_track->edits->first; current_edit; current_edit = current_edit->next) { if(current_edit->startproject >= start_units && current_edit->startproject < end_units && current_edit->transition) { current_edit->transition->length = current_track->to_units(length, 1); if( current_edit == current_track->edits->last && current_edit->silence() ) { current_edit->length = current_edit->transition->length; } } } } } } void Tracks::set_transition_length(Transition *transition, double length) { // Must verify existence of transition int found = 0; if( !transition ) return; for( Track *track=first; track && !found; track=track->next ) { for( Edit *edit=track->edits->first; edit && !found; edit = edit->next ) { if( edit->transition == transition ) { transition->length = track->to_units(length, 1); if( edit == track->edits->last && edit->silence() ) { edit->length = edit->transition->length; } found = 1; } } } if( !found ) return; if( edl->session->gang_tracks == GANG_NONE ) return; Track *track = transition->edit->track; double pos = track->from_units(transition->edit->startproject); Track *current = edl->tracks->first; for( ; current; current=current->next ) { if( current == track ) continue; if( current->data_type != track->data_type ) continue; if( !current->armed_gang(track) ) continue; int64_t track_pos = current->to_units(pos, 1); Edit *edit = current->edits->editof(track_pos, PLAY_FORWARD, 0); if( !edit || !edit->transition ) continue; double edit_pos = track->from_units(edit->startproject); if( !edl->equivalent(pos, edit_pos) ) continue; // modify gang same transitions at same position if( edit->transition->Plugin::identical(transition) ) { edit->transition->length = transition->length; } if( edit == track->edits->last && edit->silence() ) { edit->length = edit->transition->length; } } } void Tracks::paste_transitions(double start, double end, int track_type, char* title) { int count = 0; for( Track *track=first; track; track=track->next ) { if( !track->is_armed() || track->data_type != track_type ) continue; for( Edit *edit=track->edits->first; edit; edit=edit->next ) { if( !edit->is_selected ) continue; edit->insert_transition(title); ++count; } } if( count > 0 ) { clear_selected_edits(); return; } for( Track *track=first; track; track=track->next ) { if( !track->is_armed() || track->data_type != track_type ) continue; int64_t start_units = track->to_units(start, 0); int64_t end_units = track->to_units(end, 0); if( start_units == end_units ) { for( Edit *edit = track->edits->first; edit; edit = edit->next) { int64_t edit_start = edit->startproject; int64_t edit_end = edit_start + edit->length; if( edit_start > start_units ) continue; if( start_units == track->edits->length() ) { double length = edl->session->default_transition_length; int64_t units = track->to_units(length, 1); edit = track->edits-> create_silence(start_units, start_units+units); } else if( start_units >= edit_end ) continue; edit->insert_transition(title); } } else { for( Edit *edit=track->edits->first; edit; edit=edit->next) { int64_t edit_start = edit->startproject; if( !edit_start ) continue; if( edit_start >= start_units && edit_start < end_units ) { edit->insert_transition(title); } } } } } void Tracks::set_automation_mode(double selectionstart, double selectionend, int mode) { Track* current_track; for(current_track = first; current_track; current_track = current_track->next) { if(current_track->is_armed()) { current_track->set_automation_mode(selectionstart, selectionend, mode); } } } int Tracks::clear_default_keyframe() { for(Track *current = first; current; current = NEXT) { if(current->is_armed()) current->clear_automation(0, 0, 0, 1); } return 0; } int Tracks::clear_handle(double start, double end, double &longest_distance, int clear_labels, int clear_plugins, int edit_autos) { Track* current_track; double distance; for(current_track = first; current_track; current_track = current_track->next) { if(current_track->is_armed()) { current_track->clear_handle(start, end, clear_labels, clear_plugins, edit_autos, distance); if(distance > longest_distance) longest_distance = distance; } } return 0; } int Tracks::copy_automation(double selectionstart, double selectionend, FileXML *file, int default_only, int autos_only) { // called by MWindow::copy_automation for copying automation alone Track* current_track; file->tag.set_title("AUTO_CLIPBOARD"); file->tag.set_property("LENGTH", selectionend - selectionstart); file->tag.set_property("FRAMERATE", edl->session->frame_rate); file->tag.set_property("SAMPLERATE", edl->session->sample_rate); file->append_tag(); file->append_newline(); file->append_newline(); for(current_track = first; current_track; current_track = current_track->next) { if(current_track->is_armed()) { current_track->copy_automation(selectionstart, selectionend, file, default_only, autos_only); } } file->tag.set_title("/AUTO_CLIPBOARD"); file->append_tag(); file->append_newline(); file->terminate_string(); return 0; } // int Tracks::copy_default_keyframe(FileXML *file) // { // copy_automation(0, 0, file, 1, 0); // return 0; // } int Tracks::delete_tracks() { int total_deleted = 0; int done = 0; int gang = edl->session->gang_tracks != GANG_NONE ? 1 : 0; while( !done ) { done = 1; for( Track* track=first, *nxt=0; done && track; track=nxt ) { nxt = track->next; if( gang ) { while( nxt && !nxt->master ) nxt = nxt->next; } if( !track->is_armed() ) continue; delete_track(track); ++total_deleted; } } return total_deleted; } void Tracks::move_edits(ArrayList *in_edits, Track *track, double position, int edit_labels, int edit_plugins, int edit_autos, int mode) { // have to make a copy, optimize kills edits ArrayList edits; for( int i=0; isize(); ++i ) { Edit *edit = in_edits->get(i); Edit *new_edit = new Edit(edit->edl, edit->track); new_edit->copy_from(edit); edits.append(new_edit); } int current_aedit = 0, current_vedit = 0; //printf("Tracks::move_edits 1\n"); for( Track *dest_track=track; dest_track; dest_track=dest_track->next ) { if( !dest_track->is_armed() ) continue; // Need a local copy of the source edit since the original source edit may // change in the editing operation. // Get source edit Edit *source_edit = 0; Track *clip_track = 0; switch( dest_track->data_type ) { case TRACK_AUDIO: { while( current_aedit < edits.size() ) { Edit *edit = edits[current_aedit++]; if( edit->track->data_type == TRACK_AUDIO ) { source_edit = edit; ATrack *atrack = new ATrack(dest_track->edl, 0); atrack->create_objects(); clip_track = atrack; break; } } break; } case TRACK_VIDEO: { while( current_vedit < edits.size() ) { Edit *edit = edits[current_vedit++]; if( edit->track->data_type == TRACK_VIDEO ) { source_edit = edit; VTrack *vtrack = new VTrack(dest_track->edl, 0); vtrack->create_objects(); clip_track = vtrack; break; } } break; } } if( !source_edit ) continue; Track *source_track = source_edit->track; int64_t start = source_edit->startproject; int64_t length = source_edit->length, end = start + length; double source_start = source_track->from_units(start); double source_end = source_track->from_units(start+length); double len = source_end - source_start; double dest_start = position; double dest_end = dest_start + len; if( edit_labels && dest_track == track ) { FileXML label_xml; Labels labels(0, "LABELS"); source_edit->edl->labels->copy(source_start, source_end, &label_xml); source_edit->edl->labels->clear(source_start, source_end, mode); if( !label_xml.read_tag() ) labels.load(&label_xml, LOAD_ALL); double pos = dest_start; if( mode && source_start < dest_start ) pos -= len; edl->labels->insert_labels(&labels, pos, len, mode); edit_labels = 0; } FileXML track_xml; source_track->copy(COPY_TRACKS, source_start, source_end, &track_xml, ""); if( !track_xml.read_tag() ) clip_track->load(&track_xml, 0, LOAD_ALL); if( !mode ) { // mute and overwrite source_track->clear(start, end, 1, 0, edit_plugins, edit_autos, 0); source_track->edits->paste_silence(start, end); if( edit_autos ) source_track->shift_keyframes(start, length); if( edit_plugins ) { int n = source_track->plugin_set.size(); if( n > 0 ) dest_track->expand_view = 1; for( int k=0; kplugin_set[k]->paste_silence(start, end, 1); } dest_track->clear(dest_start, dest_end, 1, 0, edit_plugins, edit_autos, 0); dest_track->insert_track(clip_track, dest_start, 0, edit_plugins, edit_autos, len); } else { // cut and paste dest_track->insert_track(clip_track, dest_start, 0, edit_plugins, edit_autos, len); if( source_track == dest_track && dest_start < source_start ) { source_start += len; source_end += len; } source_track->clear(source_start, source_end, 1, 0, edit_plugins, edit_autos, 0); } delete clip_track; dest_track->optimize(); } edits.remove_all_objects(); } void Tracks::move_effect(Plugin *plugin, Track *track, int64_t position) { Track *source_track = plugin->track; Plugin *result = 0; // Create a new plugin set double start = track->from_units(position); double length = track->from_units(plugin->length); result = track->insert_effect("", &plugin->shared_location, 0, 0, start, length, plugin->plugin_type); result->copy_from(plugin); result->shift(position - plugin->startproject); result->gui_id = plugin->gui_id; // Clear new plugin from old set plugin->plugin_set->clear(plugin->startproject, plugin->startproject + plugin->length, edl->session->autos_follow_edits); source_track->optimize(); } void Tracks::move_effect(Plugin *plugin, PluginSet *plugin_set, int64_t position) { // src/dest track must be the same // replace plugin in source plugin_set with silence PluginSet *src_plugin_set = plugin->plugin_set; Plugin *silent = new Plugin(edl, src_plugin_set, ""); silent->startproject = plugin->startproject; silent->length = plugin->length; src_plugin_set->insert_after(plugin, silent); src_plugin_set->remove_pointer(plugin); // truncate previous plugin Plugin *dest = (Plugin *)plugin_set->editof(position, PLAY_FORWARD, 0); // add plugin after dest plugin_set->insert_after(dest, plugin); if( dest ) { dest->length = position - dest->startproject; if( dest->length < 0 ) dest->length = 0; } // update plugin position plugin->startproject = position; plugin->plugin_set = plugin_set; plugin->edits = plugin_set; src_plugin_set->track->optimize(); } int Tracks::concatenate_tracks(int edit_plugins, int edit_autos) { Track *output_track, *first_output_track, *input_track; int i, data_type = TRACK_AUDIO; double output_start; int result = 0; // Relocate tracks for(i = 0; i < 2; i++) { // Get first output track for(output_track = first; output_track; output_track = output_track->next) if(output_track->data_type == data_type && output_track->is_armed()) break; first_output_track = output_track; // Get first input track for(input_track = first; input_track; input_track = input_track->next) { if(input_track->data_type == data_type && input_track->play && !input_track->is_armed()) break; } if(output_track && input_track) { // Transfer input track to end of output track one at a time while(input_track) { output_start = output_track->get_length(); output_track->insert_track(input_track, output_start, 0, edit_plugins, edit_autos, 0); // Get next source and destination for(input_track = input_track->next; input_track; input_track = input_track->next) { if(input_track->data_type == data_type && !input_track->is_armed() && input_track->play) break; } for(output_track = output_track->next; output_track; output_track = output_track->next) { if(output_track->data_type == data_type && output_track->is_armed()) break; } if(!output_track) { output_track = first_output_track; } } result = 1; } if(data_type == TRACK_AUDIO) data_type = TRACK_VIDEO; } return result; } int Tracks::delete_all_tracks() { while(last) delete last; return 0; } void Tracks::change_modules(int old_location, int new_location, int do_swap) { for(Track* current = first ; current; current = current->next) { current->change_modules(old_location, new_location, do_swap); } } void Tracks::change_plugins(SharedLocation &old_location, SharedLocation &new_location, int do_swap) { for(Track* current = first ; current; current = current->next) { current->change_plugins(old_location, new_location, do_swap); } } // =========================================== EDL editing int Tracks::copy(int copy_flags, double start, double end, FileXML *file, const char *output_path) { int all = (copy_flags & COPY_ALL) ? 1 : 0; // if nothing selected if( start == end && !all ) return 1; for( Track *track=first; track; track=track->next ) { if( track->is_armed() || all ) track->copy(copy_flags, start, end, file, output_path); } return 0; } int Tracks::move_track_up(Track *track) { if( first == last ) return 1; int n = 1; Track *src = track, *dst = src->previous; if( edl->session->gang_tracks != GANG_NONE ) { while( src && !src->master ) src = src->previous; if( !src ) src = first; Track *nxt = src->next; while( nxt && !nxt->master ) { ++n; nxt = nxt->next; } dst = src->previous; while( dst && !dst->master ) { dst = dst->previous; } } if( src == dst ) return 1; move_tracks(src, dst, n); return 0; } int Tracks::move_track_down(Track *track) { if( first == last ) return 1; int n = 1; Track *src = track, *dst = src->next; if( edl->session->gang_tracks != GANG_NONE ) { while( src && !src->master ) src = src->previous; if( !src ) src = first; Track *nxt = src->next; while( nxt && !nxt->master ) { ++n; nxt = nxt->next; } if( nxt ) { nxt = nxt->next; while( nxt && !nxt->master ) { nxt = nxt->next; } } else nxt = first; dst = nxt; } else dst = !dst ? first : dst->next; if( src == dst ) return 1; move_tracks(src, dst, n); return 0; } int Tracks::move_tracks_up() { if( first == last ) return 1; int n = 1; Track *src = first, *dst = 0; if( edl->session->gang_tracks != GANG_NONE ) { Track *nxt = src->next; while( nxt && !nxt->master ) { ++n; nxt = nxt->next; } } if( src == dst ) return 1; move_tracks(src, dst, n); return 0; } int Tracks::move_tracks_down() { if( first == last ) return 1; int n = 1; Track *src = last, *dst = first; if( edl->session->gang_tracks != GANG_NONE ) { while( src && !src->master ) { ++n; src = src->previous; } } if( src == dst ) return 1; move_tracks(src, dst, n); return 0; } int Tracks::swap_track_up(Track *track) { Track *next_track = track->previous; if(!next_track) next_track = last; change_modules(number_of(track), number_of(next_track), 1); swap(track, next_track); return 0; } int Tracks::swap_track_down(Track *track) { Track *next_track = track->next; if(!next_track) next_track = first; change_modules(number_of(track), number_of(next_track), 1); swap(track, next_track); return 0; } int Tracks::swap_tracks_up() { int result = 0; Track *next = first; while( next ) { Track *track = next; next = track->next; if( !track->armed ) continue; if( track->previous ) { change_modules(number_of(track->previous), number_of(track), 1); swap(track->previous, track); result = 1; } } return result; } int Tracks::swap_tracks_down() { int result = 0; Track *prev = last; while( prev ) { Track *track = prev; prev = track->previous; if( !track->armed ) continue; if( track->next ) { change_modules(number_of(track), number_of(track->next), 1); swap(track, track->next); result = 1; } } return result; } void Tracks::paste_audio_transition(PluginServer *server) { for(Track *current = first; current; current = NEXT) { if(current->data_type == TRACK_AUDIO && current->is_armed()) { int64_t position = current->to_units( edl->local_session->get_selectionstart(), 0); Edit *current_edit = current->edits->editof(position, PLAY_FORWARD, 0); if( !current_edit && position == current->edits->length() ) { double length = edl->session->default_transition_length; int64_t units = current->to_units(length, 1); current_edit = current->edits->create_silence(position, position+units); } if(current_edit) { paste_transition(server, current_edit); } } } } void Tracks::paste_automation(double selectionstart, FileXML *file, int default_only, int active_only, int typeless) { Track* current_track = 0; Track* current_atrack = 0; Track* current_vtrack = 0; Track* dst_track = 0; int result = 0; double length; double frame_rate = edl->session->frame_rate; int64_t sample_rate = edl->session->sample_rate; char string[BCTEXTLEN]; string[0] = 0; // Search for start do { result = file->read_tag(); } while(!result && !file->tag.title_is("AUTO_CLIPBOARD")); if(!result) { length = file->tag.get_property("LENGTH", 0); frame_rate = file->tag.get_property("FRAMERATE", frame_rate); sample_rate = file->tag.get_property("SAMPLERATE", sample_rate); do { result = file->read_tag(); if(!result) { if(file->tag.title_is("/AUTO_CLIPBOARD")) { result = 1; } else if(file->tag.title_is("TRACK")) { file->tag.get_property("TYPE", string); double src_rate = !strcmp(string, "AUDIO") ? sample_rate : frame_rate; double src_length = length / src_rate; // paste to any media type if(typeless) { if(!current_track) current_track = first; while(current_track && !current_track->is_armed()) current_track = current_track->next; dst_track = current_track; } else if(!strcmp(string, "AUDIO")) { // Get next audio track if(!current_atrack) current_atrack = first; else current_atrack = current_atrack->next; while(current_atrack && (current_atrack->data_type != TRACK_AUDIO || !current_atrack->is_armed())) current_atrack = current_atrack->next; dst_track = current_atrack; } else { // Get next video track if(!current_vtrack) current_vtrack = first; else current_vtrack = current_vtrack->next; while(current_vtrack && (current_vtrack->data_type != TRACK_VIDEO || !current_vtrack->is_armed())) current_vtrack = current_vtrack->next; dst_track = current_vtrack; } if(dst_track) { dst_track->paste_automation(file, selectionstart, src_length, src_rate, default_only, active_only); } } } }while(!result); } } // int Tracks::paste_default_keyframe(FileXML *file) // { // paste_automation(0, file, 1, 0); // return 0; // } void Tracks::paste_transition(PluginServer *server, Edit *dest_edit) { dest_edit->insert_transition(server->title); if( edl->session->gang_tracks == GANG_NONE ) return; Track *track = dest_edit->track; double pos = track->from_units(dest_edit->startproject); for( Track *current=first; current; current=current->next ) { if( current == track ) continue; if( current->data_type != track->data_type ) continue; if( !current->armed_gang(track) ) continue; int64_t track_pos = current->to_units(pos, 1); Edit *edit = current->edits->editof(track_pos, PLAY_FORWARD, 0); if( !edit ) continue; double edit_pos = track->from_units(edit->startproject); if( !edl->equivalent(pos, edit_pos) ) continue; edit->insert_transition(server->title); } } void Tracks::paste_video_transition(PluginServer *server, int first_track) { for(Track *current = first; current; current = NEXT) { if(current->data_type == TRACK_VIDEO && current->is_armed()) { int64_t position = current->to_units( edl->local_session->get_selectionstart(), 0); Edit *current_edit = current->edits->editof(position, PLAY_FORWARD, 0); if( !current_edit && position == current->edits->length() ) { double length = edl->session->default_transition_length; int64_t units = current->to_units(length, 1); current_edit = current->edits->create_silence(position, position+units); } if(current_edit) { paste_transition(server, current_edit); } if(first_track) break; } } } int Tracks::paste_silence(double start, double end, int edit_plugins, int edit_autos) { Track* current_track; for(current_track = first; current_track; current_track = current_track->next) { if(current_track->is_armed()) { current_track->paste_silence(start, end, edit_plugins, edit_autos); } } return 0; } int Tracks::select_auto(int cursor_x, int cursor_y) { int result = 0; for(Track* current = first; current && !result; current = NEXT) { result = current->select_auto(&auto_conf, cursor_x, cursor_y); } return result; } int Tracks::move_auto(int cursor_x, int cursor_y, int shift_down) { int result = 0; for(Track* current = first; current && !result; current = NEXT) { result = current->move_auto(&auto_conf, cursor_x, cursor_y, shift_down); } return 0; } int Tracks::modify_edithandles(double &oldposition, double &newposition, int currentend, int handle_mode, int edit_labels, int edit_plugins, int edit_autos, int group_id) { for( Track *track=first; track; track=track->next ) { if( !track->is_armed() ) continue; track->modify_edithandles(oldposition, newposition, currentend, handle_mode, edit_labels, edit_plugins, edit_autos, group_id); // labels follow first armed track edit_labels = 0; } return 0; } int Tracks::modify_pluginhandles(double &oldposition, double &newposition, int currentend, int handle_mode, int edit_labels, int edit_autos, Edits *trim_edits) { for( Track *track=first; track; track=track->next ) { if( !track->is_armed() ) continue; track->modify_pluginhandles(oldposition, newposition, currentend, handle_mode, edit_labels, edit_autos, trim_edits); } return 0; } int Tracks::purge_asset(Asset *asset) { Track *current_track; int result = 0; for(current_track = first; current_track; current_track = current_track->next) { result += current_track->purge_asset(asset); } return result; } int Tracks::asset_used(Asset *asset) { Track *current_track; int result = 0; for(current_track = first; current_track; current_track = current_track->next) { result += current_track->asset_used(asset); } return result; } int Tracks::scale_time(float rate_scale, int ignore_record, int scale_edits, int scale_autos, int64_t start, int64_t end) { Track *current_track; for(current_track = first; current_track; current_track = current_track->next) { if((current_track->is_armed() || ignore_record) && current_track->data_type == TRACK_VIDEO) { current_track->scale_time(rate_scale, scale_edits, scale_autos, start, end); } } return 0; }