4 * Copyright (C) 1997-2012 Adam Williams <broadcast at earthling dot net>
5 * Copyright (C) 2003-2016 Cinelerra CV contributors
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 #include "automation.h"
28 #include "awindowgui.h"
29 #include "bccmodels.h"
31 #include "bcsignals.h"
37 #include "edlsession.h"
40 #include "floatauto.h"
41 #include "floatautos.h"
44 #include "keyframes.h"
45 #include "indexstate.h"
47 #include "localsession.h"
48 #include "maskautos.h"
52 #include "playbackconfig.h"
53 #include "playabletracks.h"
55 #include "pluginset.h"
56 #include "preferences.h"
57 #include "recordconfig.h"
58 #include "recordlabel.h"
59 #include "sharedlocation.h"
62 #include "transportque.inc"
63 #include "versioninfo.h"
70 EDL::EDL(EDL *parent_edl)
73 this->parent_edl = parent_edl;
88 remove_vwindow_edls();
96 void EDL::create_objects()
98 tracks = new Tracks(this);
99 assets = !parent_edl ? new Assets(this) : parent_edl->assets;
100 session = !parent_edl ? new EDLSession(this) : parent_edl->session;
101 local_session = new LocalSession(this);
102 labels = new Labels(this, "LABELS");
105 EDL& EDL::operator=(EDL &edl)
107 printf("EDL::operator= 1\n");
112 int EDL::load_defaults(BC_Hash *defaults)
115 session->load_defaults(defaults);
117 local_session->load_defaults(defaults);
121 int EDL::save_defaults(BC_Hash *defaults)
124 session->save_defaults(defaults);
126 local_session->save_defaults(defaults);
130 void EDL::boundaries()
132 session->boundaries();
133 local_session->boundaries();
136 int EDL::create_default_tracks()
139 for( int i=0; i<session->video_tracks; ++i ) {
140 tracks->add_video_track(0, 0);
142 for( int i=0; i<session->audio_tracks; ++i ) {
143 tracks->add_audio_track(0, 0);
148 int EDL::load_xml(FileXML *file, uint32_t load_flags)
153 if( (load_flags & LOAD_ALL) == LOAD_ALL ) {
154 remove_vwindow_edls();
158 // Search for start of master EDL.
160 // The parent_edl test caused clip creation to fail since those XML files
161 // contained an EDL tag.
163 // The parent_edl test is required to make EDL loading work because
164 // when loading an EDL the EDL tag is already read by the parent.
168 result = file->read_tag();
170 !file->tag.title_is("XML") &&
171 !file->tag.title_is("EDL"));
173 return result ? result : read_xml(file, load_flags);
176 int EDL::read_xml(FileXML *file, uint32_t load_flags)
179 // Track numbering offset for replacing undo data.
180 int track_offset = 0;
182 // Get path for backups
183 file->tag.get_property("path", path);
186 if( (load_flags & LOAD_ALL) == LOAD_ALL ||
187 (load_flags & LOAD_EDITS) == LOAD_EDITS ) {
188 while(tracks->last) delete tracks->last;
191 if( (load_flags & LOAD_ALL) == LOAD_ALL ) {
193 mixers.remove_all_objects();
196 if( load_flags & LOAD_TIMEBAR ) {
197 while(labels->last) delete labels->last;
198 local_session->unset_inpoint();
199 local_session->unset_outpoint();
202 // This was originally in LocalSession::load_xml
203 if( load_flags & LOAD_SESSION ) {
204 local_session->clipboard_length = 0;
208 result = file->read_tag();
211 if( file->tag.title_is("/XML") ||
212 file->tag.title_is("/EDL") ||
213 file->tag.title_is("/CLIP_EDL") ||
214 file->tag.title_is("/NESTED_EDL") ||
215 file->tag.title_is("/VWINDOW_EDL") ) {
219 if( file->tag.title_is("CLIPBOARD") ) {
220 local_session->clipboard_length =
221 file->tag.get_property("LENGTH", (double)0);
224 if( file->tag.title_is("VIDEO") ) {
225 if( (load_flags & LOAD_VCONFIG) &&
226 (load_flags & LOAD_SESSION) )
227 session->load_video_config(file, 0, load_flags);
229 result = file->skip_tag();
232 if( file->tag.title_is("AUDIO") ) {
233 if( (load_flags & LOAD_ACONFIG) &&
234 (load_flags & LOAD_SESSION) )
235 session->load_audio_config(file, 0, load_flags);
237 result = file->skip_tag();
240 if( file->tag.title_is("FOLDERS") ) {
241 result = folders.load_xml(file);
244 if( file->tag.title_is("MIXERS") ) {
245 if( (load_flags & LOAD_SESSION) )
248 result = file->skip_tag();
251 if( file->tag.title_is("ASSETS") ) {
252 if( load_flags & LOAD_ASSETS )
253 assets->load(file, load_flags);
255 result = file->skip_tag();
258 if( file->tag.title_is(labels->xml_tag) ) {
259 if( load_flags & LOAD_TIMEBAR )
260 labels->load(file, load_flags);
262 result = file->skip_tag();
265 if( file->tag.title_is("LOCALSESSION") ) {
266 if( (load_flags & LOAD_SESSION) ||
267 (load_flags & LOAD_TIMEBAR) )
268 local_session->load_xml(file, load_flags);
270 result = file->skip_tag();
273 if( file->tag.title_is("SESSION") ) {
274 if( (load_flags & LOAD_SESSION) && !parent_edl )
275 session->load_xml(file, 0, load_flags);
277 result = file->skip_tag();
280 if( file->tag.title_is("TRACK") ) {
281 tracks->load(file, track_offset, load_flags);
284 if( file->tag.title_is("CLIP_EDL") ) {
285 EDL *new_edl = new EDL(this);
286 new_edl->create_objects();
287 new_edl->read_xml(file, LOAD_ALL);
288 if( (load_flags & LOAD_ALL) == LOAD_ALL ) {
289 clips.add_clip(new_edl);
291 new_edl->remove_user();
294 if( file->tag.title_is("NESTED_EDL") ) {
295 EDL *nested_edl = new EDL;
296 nested_edl->create_objects();
297 nested_edl->read_xml(file, LOAD_ALL);
298 if( (load_flags & LOAD_ALL) == LOAD_ALL )
299 nested_edls.get_nested(nested_edl);
300 nested_edl->remove_user();
303 if( file->tag.title_is("VWINDOW_EDL") ) {
305 EDL *new_edl = new EDL(this);
306 new_edl->create_objects();
307 new_edl->read_xml(file, LOAD_ALL);
310 if( (load_flags & LOAD_ALL) == LOAD_ALL ) {
311 append_vwindow_edl(new_edl, 0);
313 else { // Discard if not replacing EDL
314 new_edl->remove_user();
318 result = file->skip_tag();
329 // Output path is the path of the output file if name truncation is desired.
330 // It is a "" if complete names should be used.
331 // Called recursively by copy for clips, thus the string can't be terminated.
332 // The string is not terminated in this call.
333 int EDL::save_xml(FileXML *file, const char *output_path)
335 copy(COPY_EDL, file, output_path, 0);
339 int EDL::copy_all(EDL *edl)
341 if( this == edl ) return 0;
342 folder_no = edl->folder_no;
349 tracks->copy_from(edl->tracks);
350 labels->copy_from(edl->labels);
354 void EDL::copy_clips(EDL *edl)
356 if( this == edl ) return;
358 remove_vwindow_edls();
360 // if( vwindow_edl && !vwindow_edl_shared )
361 // vwindow_edl->remove_user();
363 // vwindow_edl_shared = 0;
365 for( int i=0; i<edl->total_vwindow_edls(); ++i ) {
366 EDL *new_edl = new EDL(this);
367 new_edl->create_objects();
368 new_edl->copy_all(edl->get_vwindow_edl(i));
369 append_vwindow_edl(new_edl, 0);
373 for( int i=0; i<edl->clips.size(); ++i ) add_clip(edl->clips[i]);
376 void EDL::copy_nested(EDL *edl)
378 if( this == edl ) return;
379 nested_edls.copy_nested(edl->nested_edls);
382 void EDL::copy_assets(EDL *edl)
384 if( this == edl ) return;
387 assets->copy_from(edl->assets);
391 void EDL::copy_mixers(EDL *edl)
393 if( this == edl ) return;
394 mixers.copy_from(edl->mixers);
397 void EDL::copy_session(EDL *edl, int session_only)
399 if( this == edl ) return;
401 if( !session_only ) {
402 strcpy(this->path, edl->path);
403 folders.copy_from(&edl->folders);
407 session->copy(edl->session);
410 if( session_only <= 0 ) {
411 local_session->copy_from(edl->local_session);
415 int EDL::copy_assets(int copy_flags, double start, double end,
416 FileXML *file, const char *output_path)
418 ArrayList<Asset*> asset_list;
421 file->tag.set_title("ASSETS");
423 file->append_newline();
425 // Copy everything for a save
426 if( (copy_flags & COPY_ALL_ASSETS) ) {
427 for( Asset *asset=assets->first; asset; asset=asset->next ) {
428 asset_list.append(asset);
431 if( (copy_flags & COPY_USED_ASSETS) ) {
432 // Copy just the ones being used.
433 for( current = tracks->first; current; current = NEXT ) {
434 if( !current->is_armed() ) continue;
435 current->copy_assets(start, end, &asset_list);
439 // Paths relativised here
440 for( int i=0; i<asset_list.size(); ++i ) {
441 asset_list[i]->write(file, 0, output_path);
444 file->tag.set_title("/ASSETS");
446 file->append_newline();
447 file->append_newline();
452 int EDL::copy(int copy_flags, double start, double end,
453 FileXML *file, const char *output_path, int rewind_it)
455 file->tag.set_title("EDL");
456 file->tag.set_property("VERSION", CINELERRA_VERSION);
457 // Save path for restoration of the project title from a backup.
458 if( this->path[0] ) file->tag.set_property("PATH", path);
459 return copy_xml(copy_flags, start, end, file, "/EDL", output_path, rewind_it);
461 int EDL::copy(int copy_flags, FileXML *file, const char *output_path, int rewind_it)
463 return copy(copy_flags, 0., tracks->total_length(),
464 file, output_path, rewind_it);
467 int EDL::copy_clip(int copy_flags, double start, double end,
468 FileXML *file, const char *output_path, int rewind_it)
470 file->tag.set_title("CLIP_EDL");
471 return copy_xml(copy_flags, start, end, file, "/CLIP_EDL", output_path, rewind_it);
473 int EDL::copy_clip(int copy_flags, FileXML *file, const char *output_path, int rewind_it)
475 return copy_clip(copy_flags, 0., tracks->total_length(),
476 file, output_path, rewind_it);
479 int EDL::copy_nested(int copy_flags, double start, double end,
480 FileXML *file, const char *output_path, int rewind_it)
482 file->tag.set_title("NESTED_EDL");
483 if( this->path[0] ) file->tag.set_property("PATH", path);
484 return copy_xml(copy_flags, start, end, file, "/NESTED_EDL", output_path, rewind_it);
486 int EDL::copy_nested(int copy_flags, FileXML *file, const char *output_path, int rewind_it)
488 return copy_nested(copy_flags, 0., tracks->total_length(),
489 file, output_path, rewind_it);
492 int EDL::copy_vwindow(int copy_flags, double start, double end,
493 FileXML *file, const char *output_path, int rewind_it)
495 file->tag.set_title("VWINDOW_EDL");
496 return copy_xml(copy_flags, start, end, file, "/VWINDOW_EDL", output_path, rewind_it);
498 int EDL::copy_vwindow(int copy_flags, FileXML *file, const char *output_path, int rewind_it)
500 return copy_vwindow(copy_flags, 0., tracks->total_length(),
501 file, output_path, rewind_it);
504 int EDL::copy_xml(int copy_flags, double start, double end,
505 FileXML *file, const char *closer, const char *output_path,
509 file->append_newline();
510 // Set clipboard samples only if copying to clipboard
511 if( (copy_flags & COPY_LENGTH) ) {
512 file->tag.set_title("CLIPBOARD");
513 file->tag.set_property("LENGTH", end - start);
515 file->tag.set_title("/CLIPBOARD");
517 file->append_newline();
518 file->append_newline();
520 //printf("EDL::copy 1\n");
523 if( (copy_flags & COPY_LOCAL_SESSION) )
524 local_session->save_xml(file, start);
527 // Need to copy all this from child EDL if pasting is desired.
529 if( (copy_flags & COPY_SESSION) )
530 session->save_xml(file);
532 if( (copy_flags & COPY_VIDEO_CONFIG) )
533 session->save_video_config(file);
535 if( (copy_flags & COPY_AUDIO_CONFIG) )
536 session->save_audio_config(file);
538 if( (copy_flags & COPY_FOLDERS) )
539 folders.save_xml(file);
541 if( (copy_flags & (COPY_ALL_ASSETS | COPY_USED_ASSETS)) )
542 copy_assets(copy_flags, start, end, file, output_path);
544 if( (copy_flags & COPY_NESTED_EDL) ) {
545 for( int i=0; i<nested_edls.size(); ++i )
546 nested_edls[i]->copy_nested(copy_flags,
547 file, output_path, 0);
550 if( (copy_flags & COPY_CLIPS) ) {
551 for( int i=0; i<clips.size(); ++i )
552 clips[i]->copy_clip(copy_flags, file, output_path, 0);
555 if( (copy_flags & COPY_VWINDOWS) ) {
556 for( int i=0; i<total_vwindow_edls(); ++i )
557 get_vwindow_edl(i)->copy_vwindow(copy_flags,
558 file, output_path, 0);
561 if( (copy_flags & COPY_MIXERS) )
564 file->append_newline();
565 file->append_newline();
567 if( (copy_flags & COPY_LABELS) )
568 labels->copy(start, end, file);
570 tracks->copy(copy_flags, start, end, file, output_path);
573 file->tag.set_title(closer);
575 file->append_newline();
577 // For editing operations we want to rewind it for immediate pasting.
578 // For clips and saving to disk leave it alone.
580 file->terminate_string();
586 void EDL::copy_indexables(EDL *edl)
588 for( Track *track=edl->tracks->first; track; track=track->next ) {
589 for( Edit *edit=track->edits->first; edit; edit=edit->next ) {
591 assets->update(edit->asset);
592 if( edit->nested_edl )
593 nested_edls.get_nested(edit->nested_edl);
598 EDL *EDL::new_nested_clip(EDL *edl, const char *path)
600 EDL *nested = new EDL; // no parent for nested edl
601 nested->create_objects();
602 nested->copy_session(edl);
603 nested->set_path(path);
604 nested->update_index(edl);
605 nested->copy_indexables(edl);
606 nested->tracks->copy_from(edl->tracks);
607 nested_edls.append(nested);
611 EDL *EDL::get_nested_edl(const char *path)
613 for( int i=0; i<nested_edls.size(); ++i ) {
614 EDL *nested_edl = nested_edls[i];
615 if( !strcmp(path, nested_edl->path) )
622 EDL *EDL::create_nested_clip(EDL *nested)
624 EDL *new_edl = new EDL(this); // parent for clip edl
625 new_edl->create_objects();
626 new_edl->create_nested(nested);
630 void EDL::create_nested(EDL *nested)
632 int video_tracks = 0, audio_tracks = 0;
633 for( Track *track=nested->tracks->first; track!=0; track=track->next ) {
634 if( track->data_type == TRACK_VIDEO && track->play ) ++video_tracks;
635 if( track->data_type == TRACK_AUDIO && track->play ) ++audio_tracks;
637 // renderengine properties
638 if( video_tracks > 0 )
640 if( audio_tracks > 0 )
641 audio_tracks = nested->session->audio_channels;
643 // Keep frame rate, sample rate, and output size unchanged.
644 // Nest all video & audio outputs
645 session->video_channels = video_tracks;
646 session->audio_channels = audio_tracks;
647 session->video_tracks = 1;
648 session->audio_tracks = audio_tracks;
649 create_default_tracks();
650 insert_asset(0, nested, 0, 0, 0);
653 void EDL::overwrite_clip(EDL *clip)
655 int folder = folder_no;
656 char clip_title[BCTEXTLEN], clip_notes[BCTEXTLEN], clip_icon[BCSTRLEN];
658 strcpy(clip_title, local_session->clip_title);
659 strcpy(clip_notes, local_session->clip_notes);
660 strcpy(clip_icon, local_session->clip_icon);
665 strcpy(local_session->clip_title, clip_title);
666 strcpy(local_session->clip_notes, clip_notes);
667 strcpy(local_session->clip_icon, clip_icon);
669 if( !clip_icon[0] ) return;
670 // discard old clip icon to reconstruct
671 char clip_icon_path[BCTEXTLEN];
672 snprintf(clip_icon_path, sizeof(clip_icon_path),
673 "%s/%s", File::get_config_path(), clip_icon);
674 remove(clip_icon_path);
679 int min_w = session->output_w, min_h = session->output_h;
680 for( Track *track=tracks->first; track!=0; track=track->next ) {
681 if( track->data_type != TRACK_VIDEO ) continue;
682 int w = min_w, h = min_h;
683 for( Edit *current=track->edits->first; current!=0; current=NEXT ) {
684 Indexable* indexable = current->get_source();
685 if( !indexable ) continue;
686 int edit_w = indexable->get_w(), edit_h = indexable->get_h();
687 if( w < edit_w ) w = edit_w;
688 if( h < edit_h ) h = edit_h;
690 if( track->track_w == w && track->track_h == h ) continue;
691 ((MaskAutos*)track->automation->autos[AUTOMATION_MASK])->
692 translate_masks( (w - track->track_w) / 2, (h - track->track_h) / 2);
693 track->track_w = w; track->track_h = h;
697 void EDL::rechannel()
699 for( Track *current=tracks->first; current; current=NEXT ) {
700 if( current->data_type == TRACK_AUDIO ) {
701 PanAutos *autos = (PanAutos*)current->automation->autos[AUTOMATION_PAN];
702 ((PanAuto*)autos->default_auto)->rechannel();
703 for( PanAuto *keyframe = (PanAuto*)autos->first;
704 keyframe; keyframe = (PanAuto*)keyframe->next ) {
705 keyframe->rechannel();
711 void EDL::resample(double old_rate, double new_rate, int data_type)
713 for( Track *current=tracks->first; current; current=NEXT ) {
714 if( current->data_type == data_type ) {
715 current->resample(old_rate, new_rate);
721 void EDL::synchronize_params(EDL *edl)
723 local_session->synchronize_params(edl->local_session);
724 for( Track *this_track=tracks->first, *that_track=edl->tracks->first;
725 this_track && that_track;
726 this_track=this_track->next, that_track=that_track->next ) {
727 this_track->synchronize_params(that_track);
731 int EDL::trim_selection(double start,
745 tracks->total_length(),
754 int EDL::equivalent(double position1, double position2)
756 double threshold = session->cursor_on_frames ?
757 0.5 / session->frame_rate : 1.0 / session->sample_rate;
758 return fabs(position2 - position1) < threshold ? 1 : 0;
761 double EDL::equivalent_output(EDL *edl)
764 session->equivalent_output(edl->session, &result);
765 tracks->equivalent_output(edl->tracks, &result);
770 void EDL::set_path(const char *path)
772 if( &this->path[0] == path ) return;
773 strcpy(this->path, path);
776 void EDL::set_inpoint(double position)
778 if( equivalent(local_session->get_inpoint(), position) &&
779 local_session->get_inpoint() >= 0 ) {
780 local_session->unset_inpoint();
783 local_session->set_inpoint(align_to_frame(position, 0));
784 if( local_session->get_outpoint() <= local_session->get_inpoint() )
785 local_session->unset_outpoint();
789 void EDL::set_outpoint(double position)
791 if( equivalent(local_session->get_outpoint(), position) &&
792 local_session->get_outpoint() >= 0 ) {
793 local_session->unset_outpoint();
796 local_session->set_outpoint(align_to_frame(position, 0));
797 if( local_session->get_inpoint() >= local_session->get_outpoint() )
798 local_session->unset_inpoint();
802 void EDL::unset_inoutpoint()
804 local_session->unset_inpoint();
805 local_session->unset_outpoint();
808 int EDL::blade(double position)
810 return tracks->blade(position);
813 int EDL::clear(double start, double end,
814 int clear_labels, int clear_plugins, int edit_autos)
818 tracks->clear_handle(start,
824 if( clear_labels && distance > 0 )
825 labels->paste_silence(start,
839 // Need to put at beginning so a subsequent paste operation starts at the
841 double position = local_session->get_selectionstart();
842 local_session->set_selectionend(position);
843 local_session->set_selectionstart(position);
847 int EDL::clear_hard_edges(double start, double end)
849 return tracks->clear_hard_edges(start, end);
852 static int dead_edit_cmp(Edit**ap, Edit**bp)
854 Edit *a = *ap, *b = *bp;
855 if( a->track != b->track ) return 0;
856 return a->startproject > b->startproject ? -1 : 1;
859 void EDL::delete_edits(ArrayList<Edit*> *edits, int collapse)
861 edits->sort(dead_edit_cmp);
862 for( int i=0; i<edits->size(); ++i ) {
863 Edit *edit = edits->get(i);
864 Track *track = edit->track;
865 int64_t start = edit->startproject;
866 int64_t length = edit->length;
867 int64_t end = start + length;
868 if( session->autos_follow_edits ) {
869 track->automation->clear(start, end, 0, collapse);
871 if( session->plugins_follow_edits ) {
872 for( int k=0; k<track->plugin_set.size(); ++k ) {
873 PluginSet *plugin_set = track->plugin_set[k];
874 plugin_set->clear(start, end, 1);
876 plugin_set->paste_silence(start, end, 1);
877 plugin_set->optimize();
880 Edit *dead_edit = edit;
882 while( (edit=edit->next) )
883 edit->startproject -= length;
892 static int cmp(Range *ap, Range *bp);
894 bool operator ==(Range &that) { return this->start == that.start; }
895 bool operator >(Range &that) { return this->start > that.start; }
897 int Range::cmp(Range *ap, Range *bp) {
898 return ap->start < bp->start ? -1 : ap->start == bp->start ? 0 : 1;
901 static void get_edit_regions(ArrayList<Edit*> *edits, ArrayList<Range> ®ions)
903 // move edit inclusive labels by regions
904 for( int i=0; i<edits->size(); ++i ) {
905 Edit *edit = edits->get(i);
906 volatile double pos = edit->track->from_units(edit->startproject);
907 volatile double end = edit->track->from_units(edit->startproject + edit->length);
908 int n = regions.size(), k = n;
910 Range &range = regions[k];
911 if( pos >= range.end ) continue;
912 if( range.start >= end ) continue;
914 if( range.start > pos ) { range.start = pos; expand = 1; }
915 if( range.end < end ) { range.end = end; expand = 1; }
920 Range &range = regions.append();
921 range.start = pos; range.end = end;
924 regions.sort(Range::cmp);
927 void EDL::delete_edit_labels(ArrayList<Edit*> *edits, int collapse)
929 ArrayList<Range> regions;
930 get_edit_regions(edits, regions);
931 int n = regions.size(), k = n;
933 Range &range = regions[k];
934 labels->clear(range.start, range.end, collapse);
938 void EDL::move_edit_labels(ArrayList<Edit*> *edits, double dist)
940 ArrayList<Range> regions;
941 get_edit_regions(edits, regions);
942 int n = regions.size(), k = n;
943 Labels moved(this, 0);
945 Range &range = regions[k];
946 Label *label = labels->label_of(range.start);
947 for( Label *next=0; label && label->position <= range.end; label=next ) {
949 labels->remove_pointer(label);
950 label->position += dist;
953 Label *current = labels->first;
954 while( (label=moved.first) ) {
955 moved.remove_pointer(label);
956 while( current && current->position < label->position )
957 current = current->next;
958 if( current && current->position == label->position ) {
959 delete label; continue;
961 labels->insert_before(current, label);
966 void EDL::modify_edithandles(double oldposition, double newposition,
967 int currentend, int handle_mode, int edit_labels,
968 int edit_plugins, int edit_autos, int group_id)
970 tracks->modify_edithandles(oldposition, newposition,
971 currentend, handle_mode, edit_labels,
972 edit_plugins, edit_autos, group_id);
975 void EDL::modify_pluginhandles(double oldposition, double newposition,
976 int currentend, int handle_mode, int edit_labels,
977 int edit_autos, Edits *trim_edits)
979 tracks->modify_pluginhandles(oldposition, newposition,
980 currentend, handle_mode, edit_labels,
981 edit_autos, trim_edits);
985 void EDL::paste_silence(double start, double end,
986 int edit_labels, int edit_plugins, int edit_autos)
989 labels->paste_silence(start, end);
990 tracks->paste_silence(start, end, edit_plugins, edit_autos);
994 void EDL::remove_from_project(ArrayList<EDL*> *clips)
996 for( int i=0; i<clips->size(); ++i ) {
997 this->clips.remove_clip(clips->get(i));
1001 void EDL::remove_from_project(ArrayList<Indexable*> *assets)
1003 // Remove from clips
1005 for( int j=0; j<clips.size(); ++j ) {
1006 clips[j]->remove_from_project(assets);
1009 // Remove from VWindow EDLs
1010 for( int i=0; i<total_vwindow_edls(); ++i )
1011 get_vwindow_edl(i)->remove_from_project(assets);
1013 for( int i=0; i<assets->size(); ++i ) {
1014 // Remove from tracks
1015 for( Track *track=tracks->first; track; track=track->next ) {
1016 track->remove_asset(assets->get(i));
1019 // Remove from assets
1020 if( !parent_edl && assets->get(i)->is_asset ) {
1021 this->assets->remove_asset((Asset*)assets->get(i));
1024 if( !parent_edl && !assets->get(i)->is_asset ) {
1025 this->nested_edls.remove_clip((EDL*)assets->get(i));
1030 void EDL::update_assets(EDL *src)
1032 for( Asset *current=src->assets->first; current; current=NEXT ) {
1033 assets->update(current);
1037 int EDL::get_tracks_height(Theme *theme)
1039 int total_pixels = 0;
1040 for( Track *current=tracks->first; current; current=NEXT ) {
1041 if( current->is_hidden() ) continue;
1042 total_pixels += current->vertical_span(theme);
1044 return total_pixels;
1047 int64_t EDL::get_tracks_width()
1049 int64_t total_pixels = 0;
1050 for( Track *current=tracks->first; current; current=NEXT ) {
1051 if( current->is_hidden() ) continue;
1052 int64_t pixels = current->horizontal_span();
1053 if( pixels > total_pixels ) total_pixels = pixels;
1055 //printf("EDL::get_tracks_width %d\n", total_pixels);
1056 return total_pixels;
1059 // int EDL::calculate_output_w(int single_channel)
1061 // if( single_channel ) return session->output_w;
1064 // for( int i=0; i<session->video_channels; ++i )
1066 // if( session->vchannel_x[i] + session->output_w > widest ) widest = session->vchannel_x[i] + session->output_w;
1071 // int EDL::calculate_output_h(int single_channel)
1073 // if( single_channel ) return session->output_h;
1076 // for( int i=0; i<session->video_channels; ++i )
1078 // if( session->vchannel_y[i] + session->output_h > tallest ) tallest = session->vchannel_y[i] + session->output_h;
1083 // Get the total output size scaled to aspect ratio
1084 void EDL::calculate_conformed_dimensions(int single_channel, float &w, float &h)
1086 if( (float)session->output_w / session->output_h > get_aspect_ratio() )
1087 h = (w = session->output_w) / get_aspect_ratio();
1089 w = (h = session->output_h) * get_aspect_ratio();
1092 float EDL::get_aspect_ratio()
1094 return session->aspect_w / session->aspect_h;
1097 int EDL::dump(FILE *fp)
1100 fprintf(fp,"CLIP\n");
1102 fprintf(fp,"EDL\n");
1103 fprintf(fp," clip_title: %s\n"
1104 " parent_edl: %p\n", local_session->clip_title, parent_edl);
1105 fprintf(fp," selectionstart %f\n selectionend %f\n loop_start %f\n loop_end %f\n",
1106 local_session->get_selectionstart(1),
1107 local_session->get_selectionend(1),
1108 local_session->loop_start,
1109 local_session->loop_end);
1110 for( int i=0; i<TOTAL_PANES; ++i ) {
1111 fprintf(fp," pane %d view_start=%jd track_start=%d\n", i,
1112 local_session->view_start[i],
1113 local_session->track_start[i]);
1117 fprintf(fp,"audio_channels: %d audio_tracks: %d sample_rate: %jd\n",
1118 session->audio_channels,
1119 session->audio_tracks,
1120 session->sample_rate);
1121 fprintf(fp," video_channels: %d\n"
1122 " video_tracks: %d\n"
1123 " frame_rate: %.2f\n"
1124 " frames_per_foot: %.2f\n"
1129 " color_model: %d\n",
1130 session->video_channels,
1131 session->video_tracks,
1132 session->frame_rate,
1133 session->frames_per_foot,
1138 session->color_model);
1140 fprintf(fp," CLIPS");
1141 fprintf(fp," total: %d\n", clips.size());
1142 for( int i=0; i<clips.size(); ++i ) {
1147 fprintf(fp," NESTED_EDLS");
1148 fprintf(fp," total: %d\n", nested_edls.size());
1149 for( int i=0; i<nested_edls.size(); ++i )
1150 fprintf(fp," %s\n", nested_edls[i]->path);
1152 fprintf(fp," VWINDOW EDLS");
1153 fprintf(fp," total: %d\n", total_vwindow_edls());
1155 for( int i=0; i<total_vwindow_edls(); ++i ) {
1156 fprintf(fp," %s\n", get_vwindow_edl(i)->local_session->clip_title);
1159 fprintf(fp," ASSETS\n");
1162 fprintf(fp," LABELS\n");
1164 fprintf(fp," TRACKS\n");
1166 //printf("EDL::dump 2\n");
1170 EDL* EDL::add_clip(EDL *edl)
1172 // Copy argument. New edls are deleted from MWindow::load_filenames.
1173 EDL *new_edl = new EDL(this);
1174 new_edl->create_objects();
1175 new_edl->copy_all(edl);
1176 new_edl->folder_no = AW_CLIP_FOLDER;
1177 clips.append(new_edl);
1181 void EDL::insert_asset(Asset *asset,
1185 RecordLabels *labels)
1187 // Insert asset into asset table
1188 Asset *new_asset = 0;
1189 EDL *new_nested_edl = 0;
1191 if( asset ) new_asset = assets->update(asset);
1192 if( nested_edl ) new_nested_edl = nested_edls.get_nested(nested_edl);
1196 Track *current = first_track ? first_track : tracks->first;
1199 // Fix length of single frame
1204 if( new_nested_edl ) {
1205 length = new_nested_edl->tracks->total_length();
1206 layers = new_nested_edl->session->video_channels;
1207 channels = new_nested_edl->session->audio_channels;
1211 // Insert 1 frame for undefined length
1212 if( new_asset->video_length < 0 ) {
1213 length = session->si_useduration ?
1214 session->si_duration :
1215 1.0 / session->frame_rate;
1218 length = new_asset->frame_rate > 0 ?
1219 (double)new_asset->video_length / new_asset->frame_rate :
1220 1.0 / session->frame_rate;
1222 layers = new_asset->layers;
1223 channels = new_asset->channels;
1226 for( ; current && vtrack<layers; current=NEXT ) {
1227 if( !current->is_armed() || current->data_type != TRACK_VIDEO ) continue;
1228 current->insert_asset(new_asset, new_nested_edl,
1229 length, position, vtrack++);
1234 if( new_asset->audio_length < 0 ) {
1235 // Insert 1 frame for undefined length & video
1236 if( new_asset->video_data )
1237 length = (double)1.0 / new_asset->frame_rate;
1239 // Insert 1 second for undefined length & no video
1243 length = (double)new_asset->audio_length /
1244 new_asset->sample_rate;
1247 current = tracks->first;
1248 for( ; current && atrack < channels; current=NEXT ) {
1249 if( !current->is_armed() || current->data_type != TRACK_AUDIO ) continue;
1250 current->insert_asset(new_asset, new_nested_edl,
1251 length, position, atrack++);
1254 // Insert labels from a recording window.
1256 for( RecordLabel *label=labels->first; label; label=label->next ) {
1257 this->labels->toggle_label(label->position, label->position);
1264 void EDL::set_index_file(Indexable *indexable)
1266 if( indexable->is_asset )
1267 assets->update_index((Asset*)indexable);
1269 nested_edls.update_index((EDL*)indexable);
1272 void EDL::optimize()
1274 //printf("EDL::optimize 1\n");
1275 double length = tracks->total_length();
1276 double preview_start = local_session->preview_start;
1277 double preview_end = local_session->preview_end;
1278 if( preview_end < 0 || preview_end > length )
1279 preview_end = length;
1280 if( preview_start == 0 && preview_end >= length )
1281 local_session->preview_end = -1;
1282 if( preview_start > preview_end )
1283 local_session->preview_start = preview_end;
1284 for( Track *current=tracks->first; current; current=NEXT )
1285 current->optimize();
1290 static Mutex id_lock;
1291 id_lock.lock("EDL::next_id");
1292 int result = EDLSession::current_id++;
1297 void EDL::get_shared_plugins(Track *source,
1298 ArrayList<SharedLocation*> *plugin_locations,
1299 int omit_recordable,
1302 for( Track *track=tracks->first; track; track=track->next ) {
1303 if( track->is_armed() && omit_recordable ) continue;
1304 if( track == source || track->data_type != data_type ) continue;
1305 for( int i=0; i<track->plugin_set.size(); ++i ) {
1306 Plugin *plugin = track->get_current_plugin(
1307 local_session->get_selectionstart(1),
1308 i, PLAY_FORWARD, 1, 0);
1309 if( plugin && plugin->plugin_type != PLUGIN_STANDALONE ) continue;
1310 plugin_locations->append(new SharedLocation(tracks->number_of(track), i));
1315 void EDL::get_shared_tracks(Track *track,
1316 ArrayList<SharedLocation*> *module_locations,
1317 int omit_recordable, int data_type)
1319 for( Track *current=tracks->first; current; current=NEXT ) {
1320 if( omit_recordable && current->is_armed() ) continue;
1321 if( current == track || current->data_type != data_type ) continue;
1322 module_locations->append(new SharedLocation(tracks->number_of(current), 0));
1326 // aligned frame time, account for sample truncation
1327 double EDL::frame_align(double position, int round)
1329 if( !round && session->sample_rate > 0 ) {
1330 int64_t sample_pos = position * session->sample_rate;
1331 position = (sample_pos+2.) / session->sample_rate;
1333 int64_t frame_pos = (position * session->frame_rate + (round ? 0.5 : 1e-6));
1334 return frame_pos / session->frame_rate;
1337 // Convert position to frames if alignment is enabled.
1338 double EDL::align_to_frame(double position, int round)
1340 if( session->cursor_on_frames )
1341 position = frame_align(position, round);
1346 BinFolder *EDL::get_folder(int no)
1348 for( int i=0; i<folders.size(); ++i ) {
1349 BinFolder *fp = folders[i];
1350 if( no == fp->awindow_folder ) return fp;
1355 int EDL::get_folder_number(const char *title)
1357 for( int i=0; i<AWINDOW_FOLDERS; ++i ) {
1358 if( !strcmp(title, AWindowGUI::folder_names[i]) )
1361 for( int i=0; i<folders.size(); ++i ) {
1362 if( !strcmp(title, folders[i]->title) )
1363 return folders[i]->awindow_folder;
1365 return AW_NO_FOLDER;
1368 const char *EDL::get_folder_name(int no)
1370 if( no >= 0 && no<AWINDOW_FOLDERS )
1371 return AWindowGUI::folder_names[no];
1372 BinFolder *fp = get_folder(no);
1373 return !fp ? "" : fp->title;
1376 int EDL::new_folder(const char *title, int is_clips)
1378 if( !title[0] ) return 1;
1379 int ret = get_folder_number(title);
1380 if( ret >= 0 ) return 1;
1381 int idx = AWINDOW_FOLDERS;
1382 for( int i=0; i<folders.size(); ++i ) {
1383 BinFolder *fp = folders[i];
1384 int no = fp->awindow_folder;
1385 if( no >= idx ) idx = no+1;
1387 folders.append(new BinFolder(idx, is_clips, title));
1391 int EDL::delete_folder(const char *title)
1393 int k = folders.size();
1394 while( --k >= 0 && strcmp(title, folders[k]->title) );
1396 folders.remove_object_number(k);
1400 int EDL::get_use_vconsole(VEdit* *playable_edit,
1401 int64_t position, int direction, PlayableTracks *playable_tracks)
1403 int share_playable_tracks = 1;
1405 VTrack *playable_track = 0;
1406 const int debug = 0;
1409 // Calculate playable tracks when being called as a nested EDL
1410 if( !playable_tracks ) {
1411 share_playable_tracks = 0;
1412 playable_tracks = new PlayableTracks(this,
1413 position, direction, TRACK_VIDEO, 1);
1417 // Total number of playable tracks is 1
1418 if( playable_tracks->size() != 1 ) {
1422 playable_track = (VTrack*)playable_tracks->get(0);
1425 // Don't need playable tracks anymore
1426 if( !share_playable_tracks ) {
1427 delete playable_tracks;
1430 if( debug ) printf("EDL::get_use_vconsole %d playable_tracks->size()=%d\n",
1431 __LINE__, playable_tracks->size());
1432 if( result ) return 1;
1435 // Test mutual conditions between direct copy rendering and this.
1436 if( !playable_track->direct_copy_possible(position,
1440 if( debug ) printf("EDL::get_use_vconsole %d\n", __LINE__);
1442 *playable_edit = (VEdit*)playable_track->edits->editof(position,
1444 // No edit at current location
1445 if( !*playable_edit ) return 1;
1446 if( debug ) printf("EDL::get_use_vconsole %d\n", __LINE__);
1449 // Edit is nested EDL
1450 if( (*playable_edit)->nested_edl ) {
1452 EDL *nested_edl = (*playable_edit)->nested_edl;
1453 int64_t nested_position = (int64_t)((position -
1454 (*playable_edit)->startproject +
1455 (*playable_edit)->startsource) *
1456 nested_edl->session->frame_rate /
1457 session->frame_rate);
1460 VEdit *playable_edit_temp = 0;
1461 if( session->output_w != nested_edl->session->output_w ||
1462 session->output_h != nested_edl->session->output_h ||
1463 nested_edl->get_use_vconsole(&playable_edit_temp,
1472 if( debug ) printf("EDL::get_use_vconsole %d\n", __LINE__);
1473 // Edit is not a nested EDL
1474 Asset *asset = (*playable_edit)->asset;
1476 if( !asset ) return 1;
1477 if( debug ) printf("EDL::get_use_vconsole %d\n", __LINE__);
1479 // Asset and output device must have the same dimensions
1480 if( asset->width != session->output_w ||
1481 asset->height != session->output_h )
1484 if( debug ) printf("EDL::get_use_vconsole %d\n", __LINE__);
1485 // If we get here the frame is going to be directly copied. Whether it is
1486 // decompressed in hardware depends on the colormodel.
1492 int EDL::get_audio_channels()
1494 return session->audio_channels;
1497 int EDL::get_sample_rate()
1499 return session->sample_rate;
1502 int64_t EDL::get_audio_samples()
1504 return (int64_t)(tracks->total_length() *
1505 session->sample_rate);
1508 int EDL::have_audio()
1513 int EDL::have_video()
1521 return session->output_w;
1526 return session->output_h;
1529 double EDL::get_frame_rate()
1531 return session->frame_rate;
1534 int EDL::get_video_layers()
1539 int64_t EDL::get_video_frames()
1541 return (int64_t)(tracks->total_length() *
1542 session->frame_rate);
1545 void EDL::remove_vwindow_edls()
1547 for( int i=0; i<total_vwindow_edls(); ++i ) {
1548 get_vwindow_edl(i)->remove_user();
1550 vwindow_edls.remove_all();
1553 void EDL::remove_vwindow_edl(EDL *edl)
1555 if( vwindow_edls.number_of(edl) >= 0 ) {
1557 vwindow_edls.remove(edl);
1562 EDL* EDL::get_vwindow_edl(int number)
1564 return vwindow_edls.get(number);
1567 int EDL::total_vwindow_edls()
1569 return vwindow_edls.size();
1572 void EDL::append_vwindow_edl(EDL *edl, int increase_counter)
1574 if(vwindow_edls.number_of(edl) >= 0) return;
1576 if(increase_counter) edl->add_user();
1577 vwindow_edls.append(edl);
1581 double EDL::next_edit(double position)
1583 Units::fix_double(&position);
1584 double new_position = tracks->total_length();
1586 double max_rate = get_frame_rate();
1587 int sample_rate = get_sample_rate();
1588 if( sample_rate > max_rate ) max_rate = sample_rate;
1589 double min_movement = max_rate > 0 ? 1. / max_rate : 1e-6;
1591 // Test for edit handles after position
1592 for( Track *track=tracks->first; track; track=track->next ) {
1593 if( !track->is_armed() ) continue;
1594 for( Edit *edit=track->edits->first; edit; edit=edit->next ) {
1595 double edit_end = track->from_units(edit->startproject + edit->length);
1596 Units::fix_double(&edit_end);
1597 if( fabs(edit_end-position) < min_movement ) continue;
1598 if( edit_end > position && edit_end < new_position )
1599 new_position = edit_end;
1602 return new_position;
1605 double EDL::prev_edit(double position)
1607 Units::fix_double(&position);
1608 double new_position = -1;
1610 double max_rate = get_frame_rate();
1611 int sample_rate = get_sample_rate();
1612 if( sample_rate > max_rate ) max_rate = sample_rate;
1613 double min_movement = max_rate > 0 ? 1. / max_rate : 1e-6;
1615 // Test for edit handles before cursor position
1616 for( Track *track=tracks->first; track; track=track->next ) {
1617 if( !track->is_armed() ) continue;
1618 for( Edit *edit=track->edits->first; edit; edit=edit->next ) {
1619 double edit_end = track->from_units(edit->startproject);
1620 Units::fix_double(&edit_end);
1621 if( fabs(edit_end-position) < min_movement ) continue;
1622 if( edit_end < position && edit_end > new_position )
1623 new_position = edit_end;
1626 return new_position;
1629 double EDL::skip_silence(double position)
1631 double result = position, nearest = DBL_MAX;
1632 for( Track *track=tracks->first; track; track=track->next ) {
1633 if( !track->play ) continue;
1634 Edit *edit = track->edits->editof(position, PLAY_FORWARD, 0);
1635 while( edit && edit->silence() ) edit = edit->next;
1636 if( !edit ) continue;
1637 double pos = track->from_units(edit->startproject);
1638 if( pos > position && pos < nearest )
1639 nearest = result = pos;
1644 void EDL::rescale_proxy(int orig_scale, int new_scale)
1646 if( orig_scale == new_scale ) return;
1648 float orig_w = (float)session->output_w * orig_scale;
1649 float orig_h = (float)session->output_h * orig_scale;
1651 session->output_w = Units::round(orig_w / new_scale);
1652 session->output_h = Units::round(orig_h / new_scale);
1656 for( Track *track=tracks->first; track; track=track->next ) {
1657 if( track->data_type != TRACK_VIDEO ) continue;
1658 orig_w = (float)track->track_w * orig_scale;
1659 orig_h = (float)track->track_h * orig_scale;
1660 track->track_w = Units::round(orig_w / new_scale);
1661 track->track_h = Units::round(orig_h / new_scale);
1662 ((MaskAutos*)track->automation->autos[AUTOMATION_MASK])->
1663 set_proxy(orig_scale, new_scale);
1664 ((FloatAutos*)track->automation->autos[AUTOMATION_CAMERA_X])->
1665 set_proxy(orig_scale, new_scale);
1666 ((FloatAutos*)track->automation->autos[AUTOMATION_CAMERA_Y])->
1667 set_proxy(orig_scale, new_scale);
1668 ((FloatAutos*)track->automation->autos[AUTOMATION_PROJECTOR_X])->
1669 set_proxy(orig_scale, new_scale);
1670 ((FloatAutos*)track->automation->autos[AUTOMATION_PROJECTOR_Y])->
1671 set_proxy(orig_scale, new_scale);
1675 void EDL::set_proxy(int new_scale, int new_use_scaler,
1676 ArrayList<Indexable*> *orig_assets, ArrayList<Indexable*> *proxy_assets)
1678 int orig_scale = session->proxy_scale;
1679 int proxy_scale = new_scale;
1680 if( !proxy_scale ) proxy_scale = 1;
1681 session->proxy_scale = proxy_scale;
1682 int orig_use_scaler = session->proxy_use_scaler;
1683 session->proxy_use_scaler = new_use_scaler;
1684 if( orig_use_scaler ) orig_scale = 1;
1685 int scale = new_use_scaler ? proxy_scale : 1;
1686 int asset_scale = !new_scale ? 0 : !new_use_scaler ? 1 : scale;
1687 // change original assets to proxy assets
1688 int folder_no = !new_use_scaler && !new_scale ? AW_MEDIA_FOLDER : AW_PROXY_FOLDER;
1689 for( int i=0,n=proxy_assets->size(); i<n; ++i ) {
1690 Indexable *proxy_idxbl = proxy_assets->get(i);
1691 proxy_idxbl->folder_no = folder_no;
1692 if( !proxy_idxbl->is_asset ) continue;
1693 Asset *proxy_asset = assets->update((Asset *)proxy_idxbl);
1694 proxy_asset->proxy_scale = asset_scale;
1695 if( !new_scale ) continue; // in case geom resized
1696 proxy_asset->width = proxy_asset->actual_width * scale;
1697 proxy_asset->height = proxy_asset->actual_height * scale;
1699 // rescale to full size asset in read_frame
1700 if( new_use_scaler ) proxy_scale = 1;
1701 rescale_proxy(orig_scale, proxy_scale);
1703 // replace track contents
1704 for( Track *track=tracks->first; track; track=track->next ) {
1705 if( track->data_type != TRACK_VIDEO ) continue;
1706 for( Edit *edit=track->edits->first; edit; edit=edit->next ) {
1707 Indexable *idxbl = (Indexable *)edit->asset;
1708 if( !idxbl ) idxbl = (Indexable *)edit->nested_edl;
1709 if( !idxbl ) continue;
1710 int i = orig_assets->size();
1711 while( --i>=0 && strcmp(orig_assets->get(i)->path, idxbl->path) );
1712 if( i < 0 ) continue;
1713 Indexable *proxy_idxbl = proxy_assets->get(i);
1714 Asset *proxy_asset = proxy_idxbl->is_asset ?
1715 assets->update((Asset *)proxy_idxbl) : 0;
1716 EDL *proxy_edl = !proxy_idxbl->is_asset ?
1717 (EDL *)proxy_idxbl : 0;
1718 edit->asset = proxy_asset;
1719 edit->nested_edl = proxy_edl;
1722 for( int j=0,n=clips.size(); j<n; ++j ) {
1723 EDL *clip = clips[j];
1725 for( Track *track=clip->tracks->first; track; track=track->next ) {
1726 if( track->data_type != TRACK_VIDEO ) continue;
1727 for( Edit *edit=track->edits->first; edit; edit=edit->next ) {
1728 Indexable *idxbl = (Indexable *)edit->asset;
1729 if( !idxbl ) idxbl = (Indexable *)edit->nested_edl;
1730 if( !idxbl ) continue;
1731 int i = orig_assets->size();
1732 while( --i>=0 && strcmp(orig_assets->get(i)->path, idxbl->path) );
1733 if( i < 0 ) continue;
1734 Indexable *proxy_idxbl = proxy_assets->get(i);
1735 Asset *proxy_asset = proxy_idxbl->is_asset ?
1736 assets->update((Asset *)proxy_idxbl) : 0;
1737 EDL *proxy_edl = !proxy_idxbl->is_asset ?
1738 (EDL *)proxy_idxbl : 0;
1739 edit->asset = proxy_asset;
1740 edit->nested_edl = proxy_edl;
1744 if( has_proxy && !orig_use_scaler )
1745 clip->rescale_proxy(orig_scale, proxy_scale);
1749 void EDL::add_proxy(ArrayList<Indexable*> *orig_assets, ArrayList<Indexable*> *proxy_assets)
1751 int asset_scale = session->proxy_scale;
1752 if( asset_scale == 1 ) asset_scale = 0;
1753 int scale = !asset_scale ? 1 : asset_scale;
1754 // update proxy geom using scale
1755 for( int i=0; i<proxy_assets->size(); ++i ) {
1756 Asset *proxy_asset = (Asset *)proxy_assets->get(i);
1757 proxy_asset->proxy_scale = asset_scale;
1758 proxy_asset->width = proxy_asset->actual_width * scale;
1759 proxy_asset->height = proxy_asset->actual_height * scale;
1762 // change original assets to proxy assets
1763 for( int i=0,n=proxy_assets->size(); i<n; ++i ) {
1764 Asset *proxy_asset = assets->update((Asset *)proxy_assets->get(i));
1765 proxy_asset->folder_no = AW_PROXY_FOLDER;
1766 // replace track contents
1767 for( Track *track=tracks->first; track; track=track->next ) {
1768 if( track->data_type != TRACK_VIDEO ) continue;
1769 for( Edit *edit=track->edits->first; edit; edit=edit->next ) {
1770 if( !edit->asset ) continue;
1771 if( !strcmp(edit->asset->path, orig_assets->get(i)->path) ) {
1772 edit->asset = proxy_asset;
1779 Asset *EDL::get_proxy_asset()
1781 return folder_no == AW_PROXY_FOLDER ?
1782 tracks->first->edits->first->asset : 0;
1785 Track *EDL::add_new_track(int data_type)
1787 Track *new_track = 0;
1788 switch( data_type ) {
1790 ++session->video_tracks;
1791 new_track = tracks->add_video_track(0, 0);
1794 ++session->audio_tracks;
1795 new_track = tracks->add_audio_track(0, 0);
1797 case TRACK_SUBTITLE:
1798 new_track = tracks->add_subttl_track(0, 0);
1804 double EDL::get_cursor_position(int cursor_x, int pane_no)
1806 return (double)cursor_x * local_session->zoom_sample / session->sample_rate +
1807 (double)local_session->view_start[pane_no] *
1808 local_session->zoom_sample / session->sample_rate;
1810 int64_t EDL::get_position_cursorx(double position, int pane_no)
1812 return (int64_t)(position * session->sample_rate / local_session->zoom_sample)
1813 - local_session->view_start[pane_no];
1816 int EDL::in_use(Indexable *indexable)
1818 for( Track *track=tracks->first; track; track=track->next ) {
1819 for( Edit *edit=track->edits->first; edit; edit=edit->next ) {
1820 Indexable *idxbl = (Indexable *)edit->asset;
1821 if( !idxbl ) idxbl = (Indexable *)edit->nested_edl;
1822 if( !idxbl ) continue;
1823 if( idxbl->id == indexable->id ) return 1;
1824 if( !indexable->is_asset != !idxbl->is_asset ) continue;
1825 if( !strcmp(idxbl->path, indexable->path) ) return 1;
1828 for( int i=0; i<clips.size(); ++i )
1829 if( clips[i]->in_use(indexable) ) return 1;
1830 for( int i=0; i<nested_edls.size(); ++i )
1831 if( nested_edls[i]->in_use(indexable) ) return 1;
1835 int EDL::regroup(int next_id)
1837 ArrayList<int> new_groups;
1838 for( Track *track=tracks->first; track; track=track->next ) {
1839 for( Edit *edit=track->edits->first; edit; edit=edit->next ) {
1840 if( !edit->group_id ) continue;
1841 int k = new_groups.size();
1842 while( --k >= 0 && new_groups[k] != edit->group_id );
1843 if( k >= 0 ) continue;
1844 new_groups.append(edit->group_id);
1847 for( Track *track=tracks->first; track; track=track->next ) {
1848 for( Edit *edit=track->edits->first; edit; edit=edit->next ) {
1849 if( !edit->group_id ) continue;
1850 int k = new_groups.size();
1851 while( --k >= 0 && new_groups[k] != edit->group_id );
1852 if( k < 0 ) continue;
1853 edit->group_id = k + next_id;
1856 return new_groups.size();
1859 EDL *EDL::selected_edits_to_clip(int packed,
1860 double *start_position, Track **start_track,
1861 int edit_labels, int edit_autos, int edit_plugins)
1863 double start = DBL_MAX, end = DBL_MIN;
1864 Track *first_track=0, *last_track = 0;
1865 for( Track *track=tracks->first; track; track=track->next ) {
1866 if( !track->is_armed() ) continue;
1868 for( Edit *edit=track->edits->first; edit; edit=edit->next ) {
1869 if( !edit->is_selected || edit->silence() ) continue;
1870 double edit_pos = track->from_units(edit->startproject);
1871 if( start > edit_pos ) start = edit_pos;
1872 if( end < (edit_pos+=edit->length) ) end = edit_pos;
1875 if( empty ) continue;
1876 if( !first_track ) first_track = track;
1879 if( start_position ) *start_position = start;
1880 if( start_track ) *start_track = first_track;
1881 if( !first_track ) return 0;
1882 EDL *new_edl = new EDL();
1883 new_edl->create_objects();
1884 new_edl->copy_session(this);
1885 const char *text = _("new_edl edit");
1886 new_edl->set_path(text);
1887 strcpy(new_edl->local_session->clip_title, text);
1888 strcpy(new_edl->local_session->clip_notes, text);
1889 new_edl->session->video_tracks = 0;
1890 new_edl->session->audio_tracks = 0;
1891 for( Track *track=tracks->first; track; track=track->next ) {
1892 if( !track->is_armed() ) continue;
1894 if( first_track != track ) continue;
1897 Track *new_track = 0;
1899 new_track = new_edl->add_new_track(track->data_type);
1900 int64_t start_pos = track->to_units(start, 0);
1901 int64_t end_pos = track->to_units(end, 0);
1902 int64_t startproject = 0;
1903 Edit *edit = track->edits->first;
1904 for( ; edit; edit=edit->next ) {
1905 if( !edit->is_selected || edit->silence() ) continue;
1906 if( edit->startproject < start_pos ) continue;
1907 if( edit->startproject >= end_pos ) break;
1908 int64_t edit_start_pos = edit->startproject;
1909 int64_t edit_end_pos = edit->startproject + edit->length;
1911 new_track = new_edl->add_new_track(track->data_type);
1912 int64_t edit_pos = edit_start_pos - start_pos;
1913 if( !packed && edit_pos > startproject ) {
1914 Edit *silence = new Edit(new_edl, new_track);
1915 silence->startproject = startproject;
1916 silence->length = edit_pos - startproject;
1917 new_track->edits->append(silence);
1918 startproject = edit_pos;
1920 int64_t clip_start_pos = startproject;
1921 Edit *clip_edit = new Edit(new_edl, new_track);
1922 clip_edit->clone_from(edit);
1923 clip_edit->startproject = startproject;
1924 startproject += clip_edit->length;
1925 new_track->edits->append(clip_edit);
1927 double edit_start = track->from_units(edit_start_pos);
1928 double edit_end = track->from_units(edit_end_pos);
1929 double clip_start = new_track->from_units(clip_start_pos);
1930 Label *label = labels->first;
1931 for( ; label; label=label->next ) {
1932 if( label->position < edit_start ) continue;
1933 if( label->position >= edit_end ) break;
1934 double clip_position = label->position - edit_start + clip_start;
1935 Label *clip_label = new_edl->labels->first;
1936 while( clip_label && clip_label->position<clip_position )
1937 clip_label = clip_label->next;
1938 if( clip_label && clip_label->position == clip_position ) continue;
1939 Label *new_label = new Label(new_edl,
1940 new_edl->labels, clip_position, label->textstr);
1941 new_edl->labels->insert_before(clip_label, new_label);
1945 Automation *automation = track->automation;
1946 Automation *new_automation = new_track->automation;
1947 for( int i=0; i<AUTOMATION_TOTAL; ++i ) {
1948 Autos *autos = automation->autos[i];
1949 if( !autos ) continue;
1950 Autos *new_autos = new_automation->autos[i];
1951 new_autos->default_auto->copy_from(autos->default_auto);
1952 Auto *aut0 = autos->first;
1953 for( ; aut0; aut0=aut0->next ) {
1954 if( aut0->position < edit_start_pos ) continue;
1955 if( aut0->position >= edit_end_pos ) break;
1956 Auto *new_auto = new_autos->new_auto();
1957 new_auto->copy_from(aut0);
1958 int64_t clip_position = aut0->position - edit_start_pos + clip_start_pos;
1959 new_auto->position = clip_position;
1960 new_autos->append(new_auto);
1964 if( edit_plugins ) {
1965 while( new_track->plugin_set.size() < track->plugin_set.size() )
1966 new_track->plugin_set.append(0);
1967 for( int i=0; i<track->plugin_set.total; ++i ) {
1968 PluginSet *plugin_set = track->plugin_set[i];
1969 if( !plugin_set ) continue;
1970 PluginSet *new_plugin_set = new_track->plugin_set[i];
1971 if( !new_plugin_set ) {
1972 new_plugin_set = new PluginSet(new_edl, new_track);
1973 new_track->plugin_set[i] = new_plugin_set;
1975 Plugin *plugin = (Plugin*)plugin_set->first;
1976 int64_t startplugin = new_plugin_set->length();
1977 for( ; plugin ; plugin=(Plugin*)plugin->next ) {
1978 if( plugin->silence() ) continue;
1979 int64_t plugin_start_pos = plugin->startproject;
1980 int64_t plugin_end_pos = plugin_start_pos + plugin->length;
1981 if( plugin_end_pos < start_pos ) continue;
1982 if( plugin_start_pos > end_pos ) break;
1983 if( plugin_start_pos < edit_start_pos )
1984 plugin_start_pos = edit_start_pos;
1985 if( plugin_end_pos > edit_end_pos )
1986 plugin_end_pos = edit_end_pos;
1987 if( plugin_start_pos >= plugin_end_pos ) continue;
1988 int64_t plugin_pos = plugin_start_pos - start_pos;
1989 if( !packed && plugin_pos > startplugin ) {
1990 Plugin *silence = new Plugin(new_edl, new_track, "");
1991 silence->startproject = startplugin;
1992 silence->length = plugin_pos - startplugin;
1993 new_plugin_set->append(silence);
1994 startplugin = plugin_pos;
1996 Plugin *new_plugin = new Plugin(new_edl, new_track, plugin->title);
1997 new_plugin->copy_base(plugin);
1998 new_plugin->startproject = startplugin;
1999 new_plugin->length = plugin_end_pos - plugin_start_pos;
2000 startplugin += new_plugin->length;
2001 new_plugin_set->append(new_plugin);
2002 KeyFrames *keyframes = plugin->keyframes;
2003 KeyFrames *new_keyframes = new_plugin->keyframes;
2004 new_keyframes->default_auto->copy_from(keyframes->default_auto);
2005 new_keyframes->default_auto->position = new_plugin->startproject;
2006 KeyFrame *keyframe = (KeyFrame*)keyframes->first;
2007 for( ; keyframe; keyframe=(KeyFrame*)keyframe->next ) {
2008 if( keyframe->position < edit_start_pos ) continue;
2009 if( keyframe->position >= edit_end_pos ) break;
2010 KeyFrame *clip_keyframe = new KeyFrame(new_edl, new_keyframes);
2011 clip_keyframe->copy_from(keyframe);
2012 int64_t key_position = keyframe->position - start_pos;
2014 key_position += new_plugin->startproject - plugin_pos;
2015 clip_keyframe->position = key_position;
2016 new_keyframes->append(clip_keyframe);
2022 if( last_track == track ) break;
2027 EDL *EDL::selected_edits_to_clip(int packed, double *start_position, Track **start_track)
2029 return selected_edits_to_clip(packed, start_position, start_track,
2030 session->labels_follow_edits,
2031 session->autos_follow_edits,
2032 session->plugins_follow_edits);
2035 void EDL::paste_edits(EDL *clip, Track *first_track, double position, int overwrite,
2036 int edit_edits, int edit_labels, int edit_autos, int edit_plugins)
2039 first_track = tracks->first;
2040 Track *src = clip->tracks->first;
2041 for( Track *track=first_track; track && src; track=track->next ) {
2042 if( !track->is_armed() ) continue;
2043 int64_t pos = track->to_units(position, 0);
2045 for( Edit *edit=src->edits->first; edit; edit=edit->next ) {
2046 if( edit->silence() ) continue;
2047 int64_t start = pos + edit->startproject;
2048 int64_t len = edit->length, end = start + len;
2050 track->edits->clear(start, end);
2051 Edit *dst = track->edits->insert_new_edit(start);
2052 dst->clone_from(edit);
2053 dst->startproject = start;
2054 dst->is_selected = 1;
2055 while( (dst=dst->next) != 0 )
2056 dst->startproject += edit->length;
2057 if( overwrite ) continue;
2058 if( edit_labels && track == first_track ) {
2059 double dst_pos = track->from_units(start);
2060 double dst_len = track->from_units(len);
2061 for( Label *label=labels->first; label; label=label->next ) {
2062 if( label->position >= dst_pos )
2063 label->position += dst_len;
2067 for( int i=0; i<AUTOMATION_TOTAL; ++i ) {
2068 Autos *autos = track->automation->autos[i];
2069 if( !autos ) continue;
2070 for( Auto *aut0=autos->first; aut0; aut0=aut0->next ) {
2071 if( aut0->position >= start )
2072 aut0->position += edit->length;
2076 if( edit_plugins ) {
2077 for( int i=0; i<track->plugin_set.size(); ++i ) {
2078 PluginSet *plugin_set = track->plugin_set[i];
2079 Plugin *plugin = (Plugin *)plugin_set->first;
2080 for( ; plugin; plugin=(Plugin *)plugin->next ) {
2081 if( plugin->startproject >= start )
2082 plugin->startproject += edit->length;
2083 else if( plugin->startproject+plugin->length > end )
2084 plugin->length += edit->length;
2085 Auto *default_keyframe = plugin->keyframes->default_auto;
2086 if( default_keyframe->position >= start )
2087 default_keyframe->position += edit->length;
2088 KeyFrame *keyframe = (KeyFrame*)plugin->keyframes->first;
2089 for( ; keyframe; keyframe=(KeyFrame*)keyframe->next ) {
2090 if( keyframe->position >= start )
2091 keyframe->position += edit->length;
2094 plugin_set->optimize();
2100 for( int i=0; i<AUTOMATION_TOTAL; ++i ) {
2101 Autos *src_autos = src->automation->autos[i];
2102 if( !src_autos ) continue;
2103 Autos *autos = track->automation->autos[i];
2104 for( Auto *aut0=src_autos->first; aut0; aut0=aut0->next ) {
2105 int64_t auto_pos = pos + aut0->position;
2106 autos->insert_auto(auto_pos, aut0);
2110 if( edit_plugins ) {
2111 for( int i=0; i<src->plugin_set.size(); ++i ) {
2112 PluginSet *plugin_set = src->plugin_set[i];
2113 if( !plugin_set ) continue;
2114 while( i >= track->plugin_set.size() )
2115 track->plugin_set.append(0);
2116 PluginSet *dst_plugin_set = track->plugin_set[i];
2117 if( !dst_plugin_set ) {
2118 dst_plugin_set = new PluginSet(this, track);
2119 track->plugin_set[i] = dst_plugin_set;
2121 Plugin *plugin = (Plugin *)plugin_set->first;
2122 if( plugin ) track->expand_view = 1;
2123 for( ; plugin; plugin=(Plugin *)plugin->next ) {
2124 int64_t start = pos + plugin->startproject;
2125 int64_t end = start + plugin->length;
2126 if( overwrite || edit_edits )
2127 dst_plugin_set->clear(start, end, 1);
2128 Plugin *new_plugin = dst_plugin_set->insert_plugin(plugin->title,
2129 start, end-start, plugin->plugin_type, &plugin->shared_location,
2130 (KeyFrame*)plugin->keyframes->default_auto, 0);
2131 new_plugin->on = plugin->on;
2132 KeyFrame *keyframe = (KeyFrame*)plugin->keyframes->first;
2133 for( ; keyframe; keyframe=(KeyFrame*)keyframe->next ) {
2134 int64_t keyframe_pos = pos + keyframe->position;
2135 new_plugin->keyframes->insert_auto(keyframe_pos, keyframe);
2137 while( (new_plugin=(Plugin *)new_plugin->next) ) {
2138 KeyFrame *keyframe = (KeyFrame*)new_plugin->keyframes->first;
2139 for( ; keyframe; keyframe=(KeyFrame*)keyframe->next )
2140 keyframe->position += plugin->length;
2148 Label *edl_label = labels->first;
2149 for( Label *label=clip->labels->first; label; label=label->next ) {
2150 double label_pos = position + label->position;
2153 !(exists=equivalent(edl_label->position, label_pos)) &&
2154 edl_label->position < position ) edl_label = edl_label->next;
2155 if( exists ) continue;
2156 labels->insert_before(edl_label,
2157 new Label(this, labels, label_pos, label->textstr));
2163 void EDL::paste_edits(EDL *clip, Track *first_track, double position, int overwrite)
2165 paste_edits(clip, first_track, position, overwrite, 1,
2166 session->labels_follow_edits,
2167 session->autos_follow_edits,
2168 session->plugins_follow_edits);
2171 void EDL::replace_assets(ArrayList<Indexable*> &orig_idxbls, ArrayList<Asset*> &new_assets)
2173 for( Track *track=tracks->first; track; track=track->next ) {
2174 for( Edit *edit=track->edits->first; edit; edit=edit->next ) {
2175 Indexable *idxbl = (Indexable *)edit->asset;
2176 if( !idxbl ) continue;
2177 int i = orig_idxbls.size();
2178 while( --i>=0 && strcmp(orig_idxbls[i]->path, idxbl->path) );
2179 if( i < 0 ) continue;
2180 Asset *new_asset = new_assets[i];
2181 if( track->data_type == TRACK_VIDEO && !new_asset->video_data ) continue;
2182 if( track->data_type == TRACK_AUDIO && !new_asset->audio_data ) continue;
2183 edit->asset = assets->update(new_assets[i]);
2187 for( int j=0,n=clips.size(); j<n; ++j )
2188 clips[j]->replace_assets(orig_idxbls, new_assets);
2193 int EDL::collect_effects(EDL *&group)
2195 // to remap shared plugins in copied plugin stack
2196 edl_shared_list shared_map;
2198 EDL *new_edl = new EDL(parent_edl ? parent_edl : this);
2199 new_edl->create_objects();
2200 Tracks *new_tracks = new_edl->tracks;
2201 Track *track = tracks->first;
2202 for( ; !ret && track; track=track->next ) {
2203 if( track->data_type != TRACK_AUDIO &&
2204 track->data_type != TRACK_VIDEO ) continue;
2205 Edit *edit = track->edits->first;
2206 while( edit && !edit->is_selected ) edit = edit->next;
2207 if( !edit ) continue;
2208 if( !track->is_armed() ) { ret = COLLECT_EFFECTS_RECORD; break; }
2209 Track *new_track = 0;
2210 edl_shared *location = 0;
2211 int64_t start_pos = edit->startproject;
2212 int64_t end_pos = start_pos + edit->length;
2213 int pluginsets = track->plugin_set.size();
2214 for( int i=0; i<pluginsets; ++i ) {
2215 PluginSet *plugins = track->plugin_set[i];
2216 Plugin *plugin = (Plugin *)plugins->first;
2217 for( ; plugin; plugin=(Plugin *)plugin->next ) {
2218 if( plugin->silence() ) continue;
2219 if( start_pos < plugin->startproject+plugin->length ) break;
2221 if( !plugin || plugin->startproject >= end_pos ) continue;
2223 location = &shared_map.append();
2224 location->trk = tracks->number_of(track);
2226 location->append(i);
2228 new_track = track->data_type == TRACK_AUDIO ?
2229 new_tracks->add_audio_track(0, 0) :
2230 new_tracks->add_video_track(0, 0) ;
2231 PluginSet *new_plugins = new PluginSet(new_edl, new_track);
2232 new_track->plugin_set.append(new_plugins);
2233 Plugin *new_plugin = (Plugin *)new_plugins->create_edit();
2234 new_plugin->copy_base(plugin);
2235 new_plugins->append(new_plugin);
2236 KeyFrame *keyframe = plugin->keyframes->
2237 get_prev_keyframe(start_pos, PLAY_FORWARD);
2238 KeyFrame *default_auto = (KeyFrame *)
2239 new_plugin->keyframes->default_auto;
2240 default_auto->copy_from(keyframe);
2241 default_auto->position = 0;
2242 default_auto->is_default = 1;
2244 if( !new_track ) { ret = COLLECT_EFFECTS_MISSING; break; }
2245 while( (edit=edit->next) && !edit->is_selected );
2246 if( edit ) ret = COLLECT_EFFECTS_MULTIPLE;
2248 track = new_edl->tracks->first;
2249 if( !ret && !track ) ret = COLLECT_EFFECTS_EMPTY;
2250 // remap shared plugins in copied new_edl
2251 for( ; !ret && track; track=track->next ) {
2252 int pluginsets = track->plugin_set.size();
2253 for( int i=0; i<pluginsets; ++i ) {
2254 PluginSet *plugins = track->plugin_set[i];
2255 Plugin *plugin = (Plugin *)plugins->first;
2256 for( ; plugin; plugin=(Plugin *)plugin->next ) {
2257 if( plugin->plugin_type != PLUGIN_SHAREDPLUGIN ) continue;
2258 int trk = plugin->shared_location.module;
2259 int set = plugin->shared_location.plugin;
2260 int m = shared_map.size(), n = -1;
2261 while( --m>=0 && shared_map[m].trk!=trk );
2263 edl_shared &location = shared_map[m];
2264 n = location.size();
2265 while( --n>=0 && location[n]!=set );
2267 if( n < 0 ) { ret = COLLECT_EFFECTS_MASTER; break; }
2268 plugin->shared_location.module = m;
2269 plugin->shared_location.plugin = n;
2276 new_edl->remove_user();
2280 void edl_SharedLocations::add(int trk, int plg)
2282 SharedLocation &s = append();
2283 s.module = trk; s.plugin = plg;
2286 // inserts pluginsets in group to first selected edit in tracks
2287 int EDL::insert_effects(EDL *group, Track *first_track)
2289 edl_SharedLocations edl_locs, new_locs;
2290 Track *new_track = group->tracks->first;
2291 if( !first_track ) first_track = tracks->first;
2292 Track *track = first_track;
2293 for( ; track && new_track; track=track->next ) {
2294 Edit *edit = track->edits->first;
2295 while( edit && !edit->is_selected ) edit = edit->next;
2296 if( !edit ) continue;
2297 if( !track->is_armed() ) return INSERT_EFFECTS_RECORD;
2298 if( track->data_type != new_track->data_type ) return INSERT_EFFECTS_TYPE;
2299 int gtrk = group->tracks->number_of(new_track);
2300 int trk = tracks->number_of(track);
2301 int psz = track->plugin_set.size();
2302 int new_pluginsets = new_track->plugin_set.size();
2303 for( int i=0; i<new_pluginsets; ++psz, ++i ) {
2304 new_locs.add(gtrk, i);
2305 edl_locs.add(trk, psz);
2307 while( (edit=edit->next) && !edit->is_selected );
2308 if( edit ) return INSERT_EFFECTS_MULTIPLE;
2309 new_track = new_track->next;
2311 if( new_track ) return INSERT_EFFECTS_MISSING;
2312 for( ; track; track=track->next ) {
2313 Edit *edit = track->edits->first;
2314 while( edit && !edit->is_selected ) edit = edit->next;
2315 if( edit ) return INSERT_EFFECTS_EXTRA;
2317 new_track = group->tracks->first;
2318 track = first_track;
2319 for( ; track && new_track; track=track->next ) {
2320 if( !track->is_armed() ) continue;
2321 Edit *edit = track->edits->first;
2322 while( edit && !edit->is_selected ) edit = edit->next;
2323 if( !edit ) continue;
2324 int64_t start_pos = edit->startproject;
2325 int64_t end_pos = start_pos + edit->length;
2326 int new_pluginsets = new_track->plugin_set.size();
2327 for( int i=0; i<new_pluginsets; ++i ) {
2328 Plugin *new_plugin = (Plugin *)new_track->plugin_set[i]->first;
2329 if( !new_plugin ) continue;
2330 PluginSet *plugins = new PluginSet(this, track);
2331 track->plugin_set.append(plugins);
2332 SharedLocation shared_location;
2333 if( new_plugin->plugin_type == PLUGIN_SHAREDPLUGIN ) {
2334 SharedLocation &new_loc = new_plugin->shared_location;
2335 int k = new_locs.size();
2336 while( --k>=0 && !new_loc.equivalent(&new_locs[k]) );
2337 if( k < 0 ) return INSERT_EFFECTS_MASTER;
2338 shared_location.copy_from(&edl_locs[k]);
2340 KeyFrame *default_keyframe = (KeyFrame *)new_plugin->keyframes->default_auto;
2341 plugins->insert_plugin(new_plugin->title,
2342 start_pos, end_pos - start_pos, new_plugin->plugin_type,
2343 &shared_location, default_keyframe, 0);
2344 track->expand_view = 1;
2346 new_track = new_track->next;