4 * Copyright (C) 1997-2012 Adam Williams <broadcast at earthling dot net>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 #include "automation.h"
27 #include "awindowgui.h"
28 #include "bccmodels.h"
30 #include "bcsignals.h"
36 #include "edlsession.h"
38 #include "floatauto.h"
39 #include "floatautos.h"
42 #include "keyframes.h"
43 #include "indexstate.h"
45 #include "localsession.h"
46 #include "maskautos.h"
50 #include "playbackconfig.h"
51 #include "playabletracks.h"
53 #include "pluginset.h"
54 #include "preferences.h"
55 #include "recordconfig.h"
56 #include "recordlabel.h"
57 #include "sharedlocation.h"
60 #include "transportque.inc"
61 #include "versioninfo.h"
68 EDL::EDL(EDL *parent_edl)
71 this->parent_edl = parent_edl;
86 remove_vwindow_edls();
94 void EDL::create_objects()
96 tracks = new Tracks(this);
97 assets = !parent_edl ? new Assets(this) : parent_edl->assets;
98 session = !parent_edl ? new EDLSession(this) : parent_edl->session;
99 local_session = new LocalSession(this);
100 labels = new Labels(this, "LABELS");
103 EDL& EDL::operator=(EDL &edl)
105 printf("EDL::operator= 1\n");
110 int EDL::load_defaults(BC_Hash *defaults)
113 session->load_defaults(defaults);
115 local_session->load_defaults(defaults);
119 int EDL::save_defaults(BC_Hash *defaults)
122 session->save_defaults(defaults);
124 local_session->save_defaults(defaults);
128 void EDL::boundaries()
130 session->boundaries();
131 local_session->boundaries();
134 int EDL::create_default_tracks()
137 for( int i=0; i<session->video_tracks; ++i ) {
138 tracks->add_video_track(0, 0);
140 for( int i=0; i<session->audio_tracks; ++i ) {
141 tracks->add_audio_track(0, 0);
146 int EDL::load_xml(FileXML *file, uint32_t load_flags)
151 if( (load_flags & LOAD_ALL) == LOAD_ALL ) {
152 remove_vwindow_edls();
156 // Search for start of master EDL.
158 // The parent_edl test caused clip creation to fail since those XML files
159 // contained an EDL tag.
161 // The parent_edl test is required to make EDL loading work because
162 // when loading an EDL the EDL tag is already read by the parent.
166 result = file->read_tag();
168 !file->tag.title_is("XML") &&
169 !file->tag.title_is("EDL"));
171 return result ? result : read_xml(file, load_flags);
174 int EDL::read_xml(FileXML *file, uint32_t load_flags)
177 // Track numbering offset for replacing undo data.
178 int track_offset = 0;
180 // Get path for backups
181 file->tag.get_property("path", path);
184 if( (load_flags & LOAD_ALL) == LOAD_ALL ||
185 (load_flags & LOAD_EDITS) == LOAD_EDITS ) {
186 while(tracks->last) delete tracks->last;
189 if( (load_flags & LOAD_ALL) == LOAD_ALL ) {
191 mixers.remove_all_objects();
194 if( load_flags & LOAD_TIMEBAR ) {
195 while(labels->last) delete labels->last;
196 local_session->unset_inpoint();
197 local_session->unset_outpoint();
200 // This was originally in LocalSession::load_xml
201 if( load_flags & LOAD_SESSION ) {
202 local_session->clipboard_length = 0;
206 result = file->read_tag();
209 if( file->tag.title_is("/XML") ||
210 file->tag.title_is("/EDL") ||
211 file->tag.title_is("/CLIP_EDL") ||
212 file->tag.title_is("/NESTED_EDL") ||
213 file->tag.title_is("/VWINDOW_EDL") ) {
217 if( file->tag.title_is("CLIPBOARD") ) {
218 local_session->clipboard_length =
219 file->tag.get_property("LENGTH", (double)0);
222 if( file->tag.title_is("VIDEO") ) {
223 if( (load_flags & LOAD_VCONFIG) &&
224 (load_flags & LOAD_SESSION) )
225 session->load_video_config(file, 0, load_flags);
227 result = file->skip_tag();
230 if( file->tag.title_is("AUDIO") ) {
231 if( (load_flags & LOAD_ACONFIG) &&
232 (load_flags & LOAD_SESSION) )
233 session->load_audio_config(file, 0, load_flags);
235 result = file->skip_tag();
238 if( file->tag.title_is("FOLDERS") ) {
239 result = folders.load_xml(file);
242 if( file->tag.title_is("MIXERS") ) {
243 if( (load_flags & LOAD_SESSION) )
246 result = file->skip_tag();
249 if( file->tag.title_is("ASSETS") ) {
250 if( load_flags & LOAD_ASSETS )
251 assets->load(file, load_flags);
253 result = file->skip_tag();
256 if( file->tag.title_is(labels->xml_tag) ) {
257 if( load_flags & LOAD_TIMEBAR )
258 labels->load(file, load_flags);
260 result = file->skip_tag();
263 if( file->tag.title_is("LOCALSESSION") ) {
264 if( (load_flags & LOAD_SESSION) ||
265 (load_flags & LOAD_TIMEBAR) )
266 local_session->load_xml(file, load_flags);
268 result = file->skip_tag();
271 if( file->tag.title_is("SESSION") ) {
272 if( (load_flags & LOAD_SESSION) &&
274 session->load_xml(file, 0, load_flags);
276 result = file->skip_tag();
279 if( file->tag.title_is("TRACK") ) {
280 tracks->load(file, track_offset, load_flags);
284 // Causes clip creation to fail because that involves an opening EDL tag.
285 if( file->tag.title_is("CLIP_EDL") && !parent_edl ) {
286 EDL *new_edl = new EDL(this);
287 new_edl->create_objects();
288 new_edl->read_xml(file, LOAD_ALL);
289 if( (load_flags & LOAD_ALL) == LOAD_ALL )
290 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") && !parent_edl ) {
304 EDL *new_edl = new EDL(this);
305 new_edl->create_objects();
306 new_edl->read_xml(file, LOAD_ALL);
309 if( (load_flags & LOAD_ALL) == LOAD_ALL ) {
310 // if( vwindow_edl && !vwindow_edl_shared )
311 // vwindow_edl->remove_user();
312 // vwindow_edl_shared = 0;
313 // vwindow_edl = new_edl;
315 append_vwindow_edl(new_edl, 0);
319 // Discard if not replacing EDL
321 new_edl->remove_user();
334 // Output path is the path of the output file if name truncation is desired.
335 // It is a "" if complete names should be used.
336 // Called recursively by copy for clips, thus the string can't be terminated.
337 // The string is not terminated in this call.
338 int EDL::save_xml(FileXML *file, const char *output_path)
340 copy(COPY_EDL, file, output_path, 0);
344 int EDL::copy_all(EDL *edl)
346 if( this == edl ) return 0;
347 folder_no = edl->folder_no;
354 tracks->copy_from(edl->tracks);
355 labels->copy_from(edl->labels);
359 void EDL::copy_clips(EDL *edl)
361 if( this == edl ) return;
363 remove_vwindow_edls();
365 // if( vwindow_edl && !vwindow_edl_shared )
366 // vwindow_edl->remove_user();
368 // vwindow_edl_shared = 0;
370 for( int i=0; i<edl->total_vwindow_edls(); ++i ) {
371 EDL *new_edl = new EDL(this);
372 new_edl->create_objects();
373 new_edl->copy_all(edl->get_vwindow_edl(i));
374 append_vwindow_edl(new_edl, 0);
378 for( int i=0; i<edl->clips.size(); ++i ) add_clip(edl->clips[i]);
381 void EDL::copy_nested(EDL *edl)
383 if( this == edl ) return;
384 nested_edls.copy_nested(edl->nested_edls);
387 void EDL::copy_assets(EDL *edl)
389 if( this == edl ) return;
392 assets->copy_from(edl->assets);
396 void EDL::copy_mixers(EDL *edl)
398 if( this == edl ) return;
399 mixers.copy_from(edl->mixers);
402 void EDL::copy_session(EDL *edl, int session_only)
404 if( this == edl ) return;
406 if( !session_only ) {
407 strcpy(this->path, edl->path);
408 folders.copy_from(&edl->folders);
412 session->copy(edl->session);
415 if( session_only <= 0 ) {
416 local_session->copy_from(edl->local_session);
420 int EDL::copy_assets(int copy_flags, double start, double end,
421 FileXML *file, const char *output_path)
423 ArrayList<Asset*> asset_list;
426 file->tag.set_title("ASSETS");
428 file->append_newline();
430 // Copy everything for a save
431 if( (copy_flags & COPY_ALL_ASSETS) ) {
432 for( Asset *asset=assets->first; asset; asset=asset->next ) {
433 asset_list.append(asset);
436 if( (copy_flags & COPY_USED_ASSETS) ) {
437 // Copy just the ones being used.
438 for( current = tracks->first; current; current = NEXT ) {
439 if( !current->record ) continue;
440 current->copy_assets(start, end, &asset_list);
444 // Paths relativised here
445 for( int i=0; i<asset_list.size(); ++i ) {
446 asset_list[i]->write(file, 0, output_path);
449 file->tag.set_title("/ASSETS");
451 file->append_newline();
452 file->append_newline();
457 int EDL::copy(int copy_flags, double start, double end,
458 FileXML *file, const char *output_path, int rewind_it)
460 file->tag.set_title("EDL");
461 file->tag.set_property("VERSION", CINELERRA_VERSION);
462 // Save path for restoration of the project title from a backup.
463 if( this->path[0] ) file->tag.set_property("PATH", path);
464 return copy_xml(copy_flags, start, end, file, "/EDL", output_path, rewind_it);
466 int EDL::copy(int copy_flags, FileXML *file, const char *output_path, int rewind_it)
468 return copy(copy_flags, 0., tracks->total_length(),
469 file, output_path, rewind_it);
472 int EDL::copy_clip(int copy_flags, double start, double end,
473 FileXML *file, const char *output_path, int rewind_it)
475 file->tag.set_title("CLIP_EDL");
476 return copy_xml(copy_flags, start, end, file, "/CLIP_EDL", output_path, rewind_it);
478 int EDL::copy_clip(int copy_flags, FileXML *file, const char *output_path, int rewind_it)
480 return copy_clip(copy_flags, 0., tracks->total_length(),
481 file, output_path, rewind_it);
484 int EDL::copy_nested(int copy_flags, double start, double end,
485 FileXML *file, const char *output_path, int rewind_it)
487 file->tag.set_title("NESTED_EDL");
488 if( this->path[0] ) file->tag.set_property("PATH", path);
489 return copy_xml(copy_flags, start, end, file, "/NESTED_EDL", output_path, rewind_it);
491 int EDL::copy_nested(int copy_flags, FileXML *file, const char *output_path, int rewind_it)
493 return copy_nested(copy_flags, 0., tracks->total_length(),
494 file, output_path, rewind_it);
497 int EDL::copy_vwindow(int copy_flags, double start, double end,
498 FileXML *file, const char *output_path, int rewind_it)
500 file->tag.set_title("VWINDOW_EDL");
501 return copy_xml(copy_flags, start, end, file, "/VWINDOW_EDL", output_path, rewind_it);
503 int EDL::copy_vwindow(int copy_flags, FileXML *file, const char *output_path, int rewind_it)
505 return copy_vwindow(copy_flags, 0., tracks->total_length(),
506 file, output_path, rewind_it);
509 int EDL::copy_xml(int copy_flags, double start, double end,
510 FileXML *file, const char *closer, const char *output_path,
514 file->append_newline();
515 // Set clipboard samples only if copying to clipboard
516 if( (copy_flags & COPY_LENGTH) ) {
517 file->tag.set_title("CLIPBOARD");
518 file->tag.set_property("LENGTH", end - start);
520 file->tag.set_title("/CLIPBOARD");
522 file->append_newline();
523 file->append_newline();
525 //printf("EDL::copy 1\n");
528 if( (copy_flags & COPY_LOCAL_SESSION) )
529 local_session->save_xml(file, start);
532 // Need to copy all this from child EDL if pasting is desired.
534 if( (copy_flags & COPY_SESSION) )
535 session->save_xml(file);
537 if( (copy_flags & COPY_VIDEO_CONFIG) )
538 session->save_video_config(file);
540 if( (copy_flags & COPY_AUDIO_CONFIG) )
541 session->save_audio_config(file);
543 if( (copy_flags & COPY_FOLDERS) )
544 folders.save_xml(file);
546 if( (copy_flags & (COPY_ALL_ASSETS | COPY_USED_ASSETS)) )
547 copy_assets(copy_flags, start, end, file, output_path);
549 if( (copy_flags & COPY_NESTED_EDL) ) {
550 for( int i=0; i<nested_edls.size(); ++i )
551 nested_edls[i]->copy_nested(copy_flags,
552 file, output_path, 0);
555 if( (copy_flags & COPY_CLIPS) ) {
556 for( int i=0; i<clips.size(); ++i )
557 clips[i]->copy_clip(copy_flags, file, output_path, 0);
560 if( (copy_flags & COPY_VWINDOWS) ) {
561 for( int i=0; i<total_vwindow_edls(); ++i )
562 get_vwindow_edl(i)->copy_vwindow(copy_flags,
563 file, output_path, 0);
566 if( (copy_flags & COPY_MIXERS) )
569 file->append_newline();
570 file->append_newline();
572 if( (copy_flags & COPY_LABELS) )
573 labels->copy(start, end, file);
575 tracks->copy(copy_flags, start, end, file, output_path);
578 file->tag.set_title(closer);
580 file->append_newline();
582 // For editing operations we want to rewind it for immediate pasting.
583 // For clips and saving to disk leave it alone.
585 file->terminate_string();
591 void EDL::copy_indexables(EDL *edl)
593 for( Track *track=edl->tracks->first; track; track=track->next ) {
594 for( Edit *edit=track->edits->first; edit; edit=edit->next ) {
596 assets->update(edit->asset);
597 if( edit->nested_edl )
598 nested_edls.get_nested(edit->nested_edl);
603 EDL *EDL::new_nested(EDL *edl, const char *path)
605 EDL *nested = new EDL; // no parent for nested edl
606 nested->create_objects();
607 nested->copy_session(edl);
608 nested->set_path(path);
609 nested->update_index(edl);
610 nested->copy_indexables(edl);
611 nested->tracks->copy_from(edl->tracks);
612 nested_edls.append(nested);
616 EDL *EDL::create_nested_clip(EDL *nested)
618 EDL *new_edl = new EDL(this); // parent for clip edl
619 new_edl->create_objects();
620 new_edl->create_nested(nested);
624 void EDL::create_nested(EDL *nested)
626 // Keep frame rate, sample rate, and output size unchanged.
627 // Nest all video & audio outputs
628 session->video_tracks = 1;
629 session->audio_tracks = nested->session->audio_channels;
630 create_default_tracks();
631 insert_asset(0, nested, 0, 0, 0);
636 int min_w = session->output_w, min_h = session->output_h;
637 for( Track *track=tracks->first; track!=0; track=track->next ) {
638 if( track->data_type != TRACK_VIDEO ) continue;
639 int w = min_w, h = min_h;
640 for( Edit *current=track->edits->first; current!=0; current=NEXT ) {
641 Indexable* indexable = current->get_source();
642 if( !indexable ) continue;
643 int edit_w = indexable->get_w(), edit_h = indexable->get_h();
644 if( w < edit_w ) w = edit_w;
645 if( h < edit_h ) h = edit_h;
647 if( track->track_w == w && track->track_h == h ) continue;
648 ((MaskAutos*)track->automation->autos[AUTOMATION_MASK])->
649 translate_masks( (w - track->track_w) / 2, (h - track->track_h) / 2);
650 track->track_w = w; track->track_h = h;
654 void EDL::rechannel()
656 for( Track *current=tracks->first; current; current=NEXT ) {
657 if( current->data_type == TRACK_AUDIO ) {
658 PanAutos *autos = (PanAutos*)current->automation->autos[AUTOMATION_PAN];
659 ((PanAuto*)autos->default_auto)->rechannel();
660 for( PanAuto *keyframe = (PanAuto*)autos->first;
661 keyframe; keyframe = (PanAuto*)keyframe->next ) {
662 keyframe->rechannel();
668 void EDL::resample(double old_rate, double new_rate, int data_type)
670 for( Track *current=tracks->first; current; current=NEXT ) {
671 if( current->data_type == data_type ) {
672 current->resample(old_rate, new_rate);
678 void EDL::synchronize_params(EDL *edl)
680 local_session->synchronize_params(edl->local_session);
681 for( Track *this_track=tracks->first, *that_track=edl->tracks->first;
682 this_track && that_track;
683 this_track=this_track->next, that_track=that_track->next ) {
684 this_track->synchronize_params(that_track);
688 int EDL::trim_selection(double start,
702 tracks->total_length(),
711 int EDL::equivalent(double position1, double position2)
713 double threshold = session->cursor_on_frames ?
714 0.5 / session->frame_rate : 1.0 / session->sample_rate;
715 return fabs(position2 - position1) < threshold ? 1 : 0;
718 double EDL::equivalent_output(EDL *edl)
721 session->equivalent_output(edl->session, &result);
722 tracks->equivalent_output(edl->tracks, &result);
727 void EDL::set_path(const char *path)
729 if( &this->path[0] == path ) return;
730 strcpy(this->path, path);
733 void EDL::set_inpoint(double position)
735 if( equivalent(local_session->get_inpoint(), position) &&
736 local_session->get_inpoint() >= 0 ) {
737 local_session->unset_inpoint();
740 local_session->set_inpoint(align_to_frame(position, 0));
741 if( local_session->get_outpoint() <= local_session->get_inpoint() )
742 local_session->unset_outpoint();
746 void EDL::set_outpoint(double position)
748 if( equivalent(local_session->get_outpoint(), position) &&
749 local_session->get_outpoint() >= 0 ) {
750 local_session->unset_outpoint();
753 local_session->set_outpoint(align_to_frame(position, 0));
754 if( local_session->get_inpoint() >= local_session->get_outpoint() )
755 local_session->unset_inpoint();
759 void EDL::unset_inoutpoint()
761 local_session->unset_inpoint();
762 local_session->unset_outpoint();
765 int EDL::blade(double position)
767 return tracks->blade(position);
770 int EDL::clear(double start, double end,
771 int clear_labels, int clear_plugins, int edit_autos)
775 tracks->clear_handle(start,
781 if( clear_labels && distance > 0 )
782 labels->paste_silence(start,
796 // Need to put at beginning so a subsequent paste operation starts at the
798 double position = local_session->get_selectionstart();
799 local_session->set_selectionend(position);
800 local_session->set_selectionstart(position);
804 int EDL::clear_hard_edges(double start, double end)
806 return tracks->clear_hard_edges(start, end);
809 static int dead_edit_cmp(Edit**ap, Edit**bp)
811 Edit *a = *ap, *b = *bp;
812 if( a->track != b->track ) return 0;
813 return a->startproject > b->startproject ? -1 : 1;
816 void EDL::delete_edits(ArrayList<Edit*> *edits, int collapse)
818 edits->sort(dead_edit_cmp);
819 for( int i=0; i<edits->size(); ++i ) {
820 Edit *edit = edits->get(i);
821 Track *track = edit->track;
822 int64_t start = edit->startproject;
823 int64_t length = edit->length;
824 int64_t end = start + length;
825 if( session->autos_follow_edits ) {
826 track->automation->clear(start, end, 0, collapse);
828 if( session->plugins_follow_edits ) {
829 for( int k=0; k<track->plugin_set.size(); ++k ) {
830 PluginSet *plugin_set = track->plugin_set[k];
831 plugin_set->clear(start, end, 1);
833 plugin_set->paste_silence(start, end, 1);
834 plugin_set->optimize();
837 Edit *dead_edit = edit;
839 while( (edit=edit->next) )
840 edit->startproject -= length;
849 static int cmp(Range *ap, Range *bp);
851 bool operator ==(Range &that) { return this->start == that.start; }
852 bool operator >(Range &that) { return this->start > that.start; }
854 int Range::cmp(Range *ap, Range *bp) {
855 return ap->start < bp->start ? -1 : ap->start == bp->start ? 0 : 1;
858 static void get_edit_regions(ArrayList<Edit*> *edits, ArrayList<Range> ®ions)
860 // move edit inclusive labels by regions
861 for( int i=0; i<edits->size(); ++i ) {
862 Edit *edit = edits->get(i);
863 double pos = edit->track->from_units(edit->startproject);
864 double end = edit->track->from_units(edit->startproject + edit->length);
865 int n = regions.size(), k = n;
867 Range &range = regions[k];
868 if( pos >= range.end ) continue;
869 if( range.start >= end ) continue;
871 if( range.start > pos ) { range.start = pos; expand = 1; }
872 if( range.end < end ) { range.end = end; expand = 1; }
877 Range &range = regions.append();
878 range.start = pos; range.end = end;
881 regions.sort(Range::cmp);
884 void EDL::delete_edit_labels(ArrayList<Edit*> *edits, int collapse)
886 ArrayList<Range> regions;
887 get_edit_regions(edits, regions);
888 int n = regions.size(), k = n;
890 Range &range = regions[k];
891 labels->clear(range.start, range.end, collapse);
895 void EDL::move_edit_labels(ArrayList<Edit*> *edits, double dist)
897 ArrayList<Range> regions;
898 get_edit_regions(edits, regions);
899 int n = regions.size(), k = n;
900 Labels moved(this, 0);
902 Range &range = regions[k];
903 Label *label = labels->label_of(range.start);
904 for( Label *next=0; label && label->position <= range.end; label=next ) {
906 labels->remove_pointer(label);
907 label->position += dist;
910 Label *current = labels->first;
911 while( (label=moved.first) ) {
912 moved.remove_pointer(label);
913 while( current && current->position < label->position )
914 current = current->next;
915 if( current && current->position == label->position ) {
916 delete label; continue;
918 labels->insert_before(current, label);
923 void EDL::modify_edithandles(double oldposition, double newposition,
924 int currentend, int handle_mode, int edit_labels,
925 int edit_plugins, int edit_autos, int group_id)
927 tracks->modify_edithandles(oldposition, newposition,
928 currentend, handle_mode, edit_labels,
929 edit_plugins, edit_autos, group_id);
932 void EDL::modify_pluginhandles(double oldposition, double newposition,
933 int currentend, int handle_mode, int edit_labels,
934 int edit_autos, Edits *trim_edits)
936 tracks->modify_pluginhandles(oldposition, newposition,
937 currentend, handle_mode, edit_labels,
938 edit_autos, trim_edits);
942 void EDL::paste_silence(double start, double end,
943 int edit_labels, int edit_plugins, int edit_autos)
946 labels->paste_silence(start, end);
947 tracks->paste_silence(start, end, edit_plugins, edit_autos);
951 void EDL::remove_from_project(ArrayList<EDL*> *clips)
953 for( int i=0; i<clips->size(); ++i ) {
954 this->clips.remove_clip(clips->get(i));
958 void EDL::remove_from_project(ArrayList<Indexable*> *assets)
962 for( int j=0; j<clips.size(); ++j ) {
963 clips[j]->remove_from_project(assets);
966 // Remove from VWindow EDLs
967 for( int i=0; i<total_vwindow_edls(); ++i )
968 get_vwindow_edl(i)->remove_from_project(assets);
970 for( int i=0; i<assets->size(); ++i ) {
971 // Remove from tracks
972 for( Track *track=tracks->first; track; track=track->next ) {
973 track->remove_asset(assets->get(i));
976 // Remove from assets
977 if( !parent_edl && assets->get(i)->is_asset ) {
978 this->assets->remove_asset((Asset*)assets->get(i));
981 if( !parent_edl && !assets->get(i)->is_asset ) {
982 this->nested_edls.remove_clip((EDL*)assets->get(i));
987 void EDL::update_assets(EDL *src)
989 for( Asset *current=src->assets->first; current; current=NEXT ) {
990 assets->update(current);
994 int EDL::get_tracks_height(Theme *theme)
996 int total_pixels = 0;
997 for( Track *current=tracks->first; current; current=NEXT ) {
998 total_pixels += current->vertical_span(theme);
1000 return total_pixels;
1003 int64_t EDL::get_tracks_width()
1005 int64_t total_pixels = 0;
1006 for( Track *current=tracks->first; current; current=NEXT ) {
1007 int64_t pixels = current->horizontal_span();
1008 if( pixels > total_pixels ) total_pixels = pixels;
1010 //printf("EDL::get_tracks_width %d\n", total_pixels);
1011 return total_pixels;
1014 // int EDL::calculate_output_w(int single_channel)
1016 // if( single_channel ) return session->output_w;
1019 // for( int i=0; i<session->video_channels; ++i )
1021 // if( session->vchannel_x[i] + session->output_w > widest ) widest = session->vchannel_x[i] + session->output_w;
1026 // int EDL::calculate_output_h(int single_channel)
1028 // if( single_channel ) return session->output_h;
1031 // for( int i=0; i<session->video_channels; ++i )
1033 // if( session->vchannel_y[i] + session->output_h > tallest ) tallest = session->vchannel_y[i] + session->output_h;
1038 // Get the total output size scaled to aspect ratio
1039 void EDL::calculate_conformed_dimensions(int single_channel, float &w, float &h)
1041 if( (float)session->output_w / session->output_h > get_aspect_ratio() )
1042 h = (w = session->output_w) / get_aspect_ratio();
1044 w = (h = session->output_h) * get_aspect_ratio();
1047 float EDL::get_aspect_ratio()
1049 return session->aspect_w / session->aspect_h;
1052 int EDL::dump(FILE *fp)
1055 fprintf(fp,"CLIP\n");
1057 fprintf(fp,"EDL\n");
1058 fprintf(fp," clip_title: %s\n"
1059 " parent_edl: %p\n", local_session->clip_title, parent_edl);
1060 fprintf(fp," selectionstart %f\n selectionend %f\n loop_start %f\n loop_end %f\n",
1061 local_session->get_selectionstart(1),
1062 local_session->get_selectionend(1),
1063 local_session->loop_start,
1064 local_session->loop_end);
1065 for( int i=0; i<TOTAL_PANES; ++i ) {
1066 fprintf(fp," pane %d view_start=%jd track_start=%d\n", i,
1067 local_session->view_start[i],
1068 local_session->track_start[i]);
1072 fprintf(fp,"audio_channels: %d audio_tracks: %d sample_rate: %jd\n",
1073 session->audio_channels,
1074 session->audio_tracks,
1075 session->sample_rate);
1076 fprintf(fp," video_channels: %d\n"
1077 " video_tracks: %d\n"
1078 " frame_rate: %.2f\n"
1079 " frames_per_foot: %.2f\n"
1084 " color_model: %d\n",
1085 session->video_channels,
1086 session->video_tracks,
1087 session->frame_rate,
1088 session->frames_per_foot,
1093 session->color_model);
1095 fprintf(fp," CLIPS");
1096 fprintf(fp," total: %d\n", clips.size());
1097 for( int i=0; i<clips.size(); ++i ) {
1102 fprintf(fp," NESTED_EDLS");
1103 fprintf(fp," total: %d\n", nested_edls.size());
1104 for( int i=0; i<nested_edls.size(); ++i )
1105 fprintf(fp," %s\n", nested_edls[i]->path);
1107 fprintf(fp," VWINDOW EDLS");
1108 fprintf(fp," total: %d\n", total_vwindow_edls());
1110 for( int i=0; i<total_vwindow_edls(); ++i ) {
1111 fprintf(fp," %s\n", get_vwindow_edl(i)->local_session->clip_title);
1114 fprintf(fp," ASSETS\n");
1117 fprintf(fp," LABELS\n");
1119 fprintf(fp," TRACKS\n");
1121 //printf("EDL::dump 2\n");
1125 EDL* EDL::add_clip(EDL *edl)
1127 // Copy argument. New edls are deleted from MWindow::load_filenames.
1128 EDL *new_edl = new EDL(this);
1129 new_edl->create_objects();
1130 new_edl->copy_all(edl);
1131 new_edl->folder_no = AW_CLIP_FOLDER;
1132 clips.append(new_edl);
1136 void EDL::insert_asset(Asset *asset,
1140 RecordLabels *labels)
1142 // Insert asset into asset table
1143 Asset *new_asset = 0;
1144 EDL *new_nested_edl = 0;
1146 if( asset ) new_asset = assets->update(asset);
1147 if( nested_edl ) new_nested_edl = nested_edls.get_nested(nested_edl);
1151 Track *current = first_track ? first_track : tracks->first;
1154 // Fix length of single frame
1159 if( new_nested_edl ) {
1160 length = new_nested_edl->tracks->total_length();
1162 channels = new_nested_edl->session->audio_channels;
1166 // Insert 1 frame for undefined length
1167 if( new_asset->video_length < 0 ) {
1168 length = session->si_useduration ?
1169 session->si_duration :
1170 1.0 / session->frame_rate;
1173 length = new_asset->frame_rate > 0 ?
1174 (double)new_asset->video_length / new_asset->frame_rate :
1175 1.0 / session->frame_rate;
1177 layers = new_asset->layers;
1178 channels = new_asset->channels;
1181 for( ; current && vtrack<layers; current=NEXT ) {
1182 if( !current->record || current->data_type != TRACK_VIDEO ) continue;
1183 current->insert_asset(new_asset, new_nested_edl,
1184 length, position, vtrack++);
1189 if( new_asset->audio_length < 0 ) {
1190 // Insert 1 frame for undefined length & video
1191 if( new_asset->video_data )
1192 length = (double)1.0 / new_asset->frame_rate;
1194 // Insert 1 second for undefined length & no video
1198 length = (double)new_asset->audio_length /
1199 new_asset->sample_rate;
1202 current = tracks->first;
1203 for( ; current && atrack < channels; current=NEXT ) {
1204 if( !current->record || current->data_type != TRACK_AUDIO ) continue;
1205 current->insert_asset(new_asset, new_nested_edl,
1206 length, position, atrack++);
1209 // Insert labels from a recording window.
1211 for( RecordLabel *label=labels->first; label; label=label->next ) {
1212 this->labels->toggle_label(label->position, label->position);
1219 void EDL::set_index_file(Indexable *indexable)
1221 if( indexable->is_asset )
1222 assets->update_index((Asset*)indexable);
1224 nested_edls.update_index((EDL*)indexable);
1227 void EDL::optimize()
1229 //printf("EDL::optimize 1\n");
1230 double length = tracks->total_length();
1231 double preview_start = local_session->preview_start;
1232 double preview_end = local_session->preview_end;
1233 if( preview_end < 0 || preview_end > length )
1234 preview_end = length;
1235 if( preview_start == 0 && preview_end >= length )
1236 local_session->preview_end = -1;
1237 if( preview_start > preview_end )
1238 local_session->preview_start = preview_end;
1239 for( Track *current=tracks->first; current; current=NEXT )
1240 current->optimize();
1245 static Mutex id_lock;
1246 id_lock.lock("EDL::next_id");
1247 int result = EDLSession::current_id++;
1252 void EDL::get_shared_plugins(Track *source,
1253 ArrayList<SharedLocation*> *plugin_locations,
1254 int omit_recordable,
1257 for( Track *track=tracks->first; track; track=track->next ) {
1258 if( track->record && omit_recordable ) continue;
1259 if( track == source || track->data_type != data_type ) continue;
1260 for( int i=0; i<track->plugin_set.size(); ++i ) {
1261 Plugin *plugin = track->get_current_plugin(
1262 local_session->get_selectionstart(1),
1263 i, PLAY_FORWARD, 1, 0);
1264 if( plugin && plugin->plugin_type != PLUGIN_STANDALONE ) continue;
1265 plugin_locations->append(new SharedLocation(tracks->number_of(track), i));
1270 void EDL::get_shared_tracks(Track *track,
1271 ArrayList<SharedLocation*> *module_locations,
1272 int omit_recordable, int data_type)
1274 for( Track *current=tracks->first; current; current=NEXT ) {
1275 if( omit_recordable && current->record ) continue;
1276 if( current == track || current->data_type != data_type ) continue;
1277 module_locations->append(new SharedLocation(tracks->number_of(current), 0));
1281 // aligned frame time, account for sample truncation
1282 double EDL::frame_align(double position, int round)
1284 if( !round && session->sample_rate > 0 ) {
1285 int64_t sample_pos = position * session->sample_rate;
1286 position = (sample_pos+2.) / session->sample_rate;
1288 int64_t frame_pos = (position * session->frame_rate + (round ? 0.5 : 1e-6));
1289 return frame_pos / session->frame_rate;
1292 // Convert position to frames if alignment is enabled.
1293 double EDL::align_to_frame(double position, int round)
1295 if( session->cursor_on_frames )
1296 position = frame_align(position, round);
1301 BinFolder *EDL::get_folder(int no)
1303 for( int i=0; i<folders.size(); ++i ) {
1304 BinFolder *fp = folders[i];
1305 if( no == fp->awindow_folder ) return fp;
1310 int EDL::get_folder_number(const char *title)
1312 for( int i=0; i<AWINDOW_FOLDERS; ++i ) {
1313 if( !strcmp(title, AWindowGUI::folder_names[i]) )
1316 for( int i=0; i<folders.size(); ++i ) {
1317 if( !strcmp(title, folders[i]->title) )
1318 return folders[i]->awindow_folder;
1320 return AW_NO_FOLDER;
1323 const char *EDL::get_folder_name(int no)
1325 if( no >= 0 && no<AWINDOW_FOLDERS )
1326 return AWindowGUI::folder_names[no];
1327 BinFolder *fp = get_folder(no);
1328 return !fp ? "" : fp->title;
1331 int EDL::new_folder(const char *title, int is_clips)
1333 if( !title[0] ) return 1;
1334 int ret = get_folder_number(title);
1335 if( ret >= 0 ) return 1;
1336 int idx = AWINDOW_FOLDERS;
1337 for( int i=0; i<folders.size(); ++i ) {
1338 BinFolder *fp = folders[i];
1339 int no = fp->awindow_folder;
1340 if( no >= idx ) idx = no+1;
1342 folders.append(new BinFolder(idx, is_clips, title));
1346 int EDL::delete_folder(const char *title)
1348 int k = folders.size();
1349 while( --k >= 0 && strcmp(title, folders[k]->title) );
1351 folders.remove_object_number(k);
1355 int EDL::get_use_vconsole(VEdit* *playable_edit,
1356 int64_t position, int direction, PlayableTracks *playable_tracks)
1358 int share_playable_tracks = 1;
1360 VTrack *playable_track = 0;
1361 const int debug = 0;
1364 // Calculate playable tracks when being called as a nested EDL
1365 if( !playable_tracks ) {
1366 share_playable_tracks = 0;
1367 playable_tracks = new PlayableTracks(this,
1368 position, direction, TRACK_VIDEO, 1);
1372 // Total number of playable tracks is 1
1373 if( playable_tracks->size() != 1 ) {
1377 playable_track = (VTrack*)playable_tracks->get(0);
1380 // Don't need playable tracks anymore
1381 if( !share_playable_tracks ) {
1382 delete playable_tracks;
1385 if( debug ) printf("EDL::get_use_vconsole %d playable_tracks->size()=%d\n",
1386 __LINE__, playable_tracks->size());
1387 if( result ) return 1;
1390 // Test mutual conditions between direct copy rendering and this.
1391 if( !playable_track->direct_copy_possible(position,
1395 if( debug ) printf("EDL::get_use_vconsole %d\n", __LINE__);
1397 *playable_edit = (VEdit*)playable_track->edits->editof(position,
1399 // No edit at current location
1400 if( !*playable_edit ) return 1;
1401 if( debug ) printf("EDL::get_use_vconsole %d\n", __LINE__);
1404 // Edit is nested EDL
1405 if( (*playable_edit)->nested_edl ) {
1407 EDL *nested_edl = (*playable_edit)->nested_edl;
1408 int64_t nested_position = (int64_t)((position -
1409 (*playable_edit)->startproject +
1410 (*playable_edit)->startsource) *
1411 nested_edl->session->frame_rate /
1412 session->frame_rate);
1415 VEdit *playable_edit_temp = 0;
1416 if( session->output_w != nested_edl->session->output_w ||
1417 session->output_h != nested_edl->session->output_h ||
1418 nested_edl->get_use_vconsole(&playable_edit_temp,
1427 if( debug ) printf("EDL::get_use_vconsole %d\n", __LINE__);
1428 // Edit is not a nested EDL
1429 Asset *asset = (*playable_edit)->asset;
1431 if( !asset ) return 1;
1432 if( debug ) printf("EDL::get_use_vconsole %d\n", __LINE__);
1434 // Asset and output device must have the same dimensions
1435 if( asset->width != session->output_w ||
1436 asset->height != session->output_h )
1439 if( debug ) printf("EDL::get_use_vconsole %d\n", __LINE__);
1440 // If we get here the frame is going to be directly copied. Whether it is
1441 // decompressed in hardware depends on the colormodel.
1447 int EDL::get_audio_channels()
1449 return session->audio_channels;
1452 int EDL::get_sample_rate()
1454 return session->sample_rate;
1457 int64_t EDL::get_audio_samples()
1459 return (int64_t)(tracks->total_length() *
1460 session->sample_rate);
1463 int EDL::have_audio()
1468 int EDL::have_video()
1476 return session->output_w;
1481 return session->output_h;
1484 double EDL::get_frame_rate()
1486 return session->frame_rate;
1489 int EDL::get_video_layers()
1494 int64_t EDL::get_video_frames()
1496 return (int64_t)(tracks->total_length() *
1497 session->frame_rate);
1500 void EDL::remove_vwindow_edls()
1502 for( int i=0; i<total_vwindow_edls(); ++i ) {
1503 get_vwindow_edl(i)->remove_user();
1505 vwindow_edls.remove_all();
1508 void EDL::remove_vwindow_edl(EDL *edl)
1510 if( vwindow_edls.number_of(edl) >= 0 ) {
1512 vwindow_edls.remove(edl);
1517 EDL* EDL::get_vwindow_edl(int number)
1519 return vwindow_edls.get(number);
1522 int EDL::total_vwindow_edls()
1524 return vwindow_edls.size();
1527 void EDL::append_vwindow_edl(EDL *edl, int increase_counter)
1529 if(vwindow_edls.number_of(edl) >= 0) return;
1531 if(increase_counter) edl->add_user();
1532 vwindow_edls.append(edl);
1536 double EDL::next_edit(double position)
1538 Units::fix_double(&position);
1539 double new_position = tracks->total_length();
1541 double max_rate = get_frame_rate();
1542 int sample_rate = get_sample_rate();
1543 if( sample_rate > max_rate ) max_rate = sample_rate;
1544 double min_movement = max_rate > 0 ? 1. / max_rate : 1e-6;
1546 // Test for edit handles after position
1547 for( Track *track=tracks->first; track; track=track->next ) {
1548 if( !track->record ) continue;
1549 for( Edit *edit=track->edits->first; edit; edit=edit->next ) {
1550 double edit_end = track->from_units(edit->startproject + edit->length);
1551 Units::fix_double(&edit_end);
1552 if( fabs(edit_end-position) < min_movement ) continue;
1553 if( edit_end > position && edit_end < new_position )
1554 new_position = edit_end;
1557 return new_position;
1560 double EDL::prev_edit(double position)
1562 Units::fix_double(&position);
1563 double new_position = -1;
1565 double max_rate = get_frame_rate();
1566 int sample_rate = get_sample_rate();
1567 if( sample_rate > max_rate ) max_rate = sample_rate;
1568 double min_movement = max_rate > 0 ? 1. / max_rate : 1e-6;
1570 // Test for edit handles before cursor position
1571 for( Track *track=tracks->first; track; track=track->next ) {
1572 if( !track->record ) continue;
1573 for( Edit *edit=track->edits->first; edit; edit=edit->next ) {
1574 double edit_end = track->from_units(edit->startproject);
1575 Units::fix_double(&edit_end);
1576 if( fabs(edit_end-position) < min_movement ) continue;
1577 if( edit_end < position && edit_end > new_position )
1578 new_position = edit_end;
1581 return new_position;
1584 double EDL::skip_silence(double position)
1586 double result = position, nearest = DBL_MAX;
1587 for( Track *track=tracks->first; track; track=track->next ) {
1588 if( !track->play ) continue;
1589 Edit *edit = track->edits->editof(position, PLAY_FORWARD, 0);
1590 while( edit && edit->silence() ) edit = edit->next;
1591 if( !edit ) continue;
1592 double pos = track->from_units(edit->startproject);
1593 if( pos > position && pos < nearest )
1594 nearest = result = pos;
1599 void EDL::rescale_proxy(int orig_scale, int new_scale)
1601 if( orig_scale == new_scale ) return;
1603 float orig_w = (float)session->output_w * orig_scale;
1604 float orig_h = (float)session->output_h * orig_scale;
1606 session->output_w = Units::round(orig_w / new_scale);
1607 session->output_h = Units::round(orig_h / new_scale);
1611 for( Track *track=tracks->first; track; track=track->next ) {
1612 if( track->data_type != TRACK_VIDEO ) continue;
1613 orig_w = (float)track->track_w * orig_scale;
1614 orig_h = (float)track->track_h * orig_scale;
1615 track->track_w = Units::round(orig_w / new_scale);
1616 track->track_h = Units::round(orig_h / new_scale);
1617 ((MaskAutos*)track->automation->autos[AUTOMATION_MASK])->
1618 set_proxy(orig_scale, new_scale);
1619 ((FloatAutos*)track->automation->autos[AUTOMATION_CAMERA_X])->
1620 set_proxy(orig_scale, new_scale);
1621 ((FloatAutos*)track->automation->autos[AUTOMATION_CAMERA_Y])->
1622 set_proxy(orig_scale, new_scale);
1623 ((FloatAutos*)track->automation->autos[AUTOMATION_PROJECTOR_X])->
1624 set_proxy(orig_scale, new_scale);
1625 ((FloatAutos*)track->automation->autos[AUTOMATION_PROJECTOR_Y])->
1626 set_proxy(orig_scale, new_scale);
1630 void EDL::set_proxy(int new_scale, int new_use_scaler,
1631 ArrayList<Indexable*> *orig_assets, ArrayList<Indexable*> *proxy_assets)
1633 int orig_scale = session->proxy_scale;
1634 session->proxy_scale = new_scale;
1635 int orig_use_scaler = session->proxy_use_scaler;
1636 session->proxy_use_scaler = new_use_scaler;
1637 if( orig_use_scaler ) orig_scale = 1;
1638 int scale = new_use_scaler ? new_scale : 1;
1639 int asset_scale = new_scale == 1 && !new_use_scaler ? 0 : scale;
1640 // change original assets to proxy assets
1641 int folder_no = new_use_scaler || new_scale != 1 ? AW_PROXY_FOLDER : AW_MEDIA_FOLDER;
1642 for( int i=0,n=proxy_assets->size(); i<n; ++i ) {
1643 Indexable *proxy_idxbl = proxy_assets->get(i);
1644 proxy_idxbl->folder_no = folder_no;
1645 if( !proxy_idxbl->is_asset ) continue;
1646 Asset *proxy_asset = assets->update((Asset *)proxy_idxbl);
1647 proxy_asset->width = proxy_asset->actual_width * scale;
1648 proxy_asset->height = proxy_asset->actual_height * scale;
1649 proxy_asset->proxy_scale = asset_scale;
1651 // rescale to full size asset in read_frame
1652 if( new_use_scaler ) new_scale = 1;
1653 rescale_proxy(orig_scale, new_scale);
1655 // replace track contents
1656 for( Track *track=tracks->first; track; track=track->next ) {
1657 if( track->data_type != TRACK_VIDEO ) continue;
1658 for( Edit *edit=track->edits->first; edit; edit=edit->next ) {
1659 Indexable *idxbl = (Indexable *)edit->asset;
1660 if( !idxbl ) idxbl = (Indexable *)edit->nested_edl;
1661 if( !idxbl ) continue;
1662 int i = orig_assets->size();
1663 while( --i>=0 && strcmp(orig_assets->get(i)->path, idxbl->path) );
1664 if( i < 0 ) continue;
1665 Indexable *proxy_idxbl = proxy_assets->get(i);
1666 Asset *proxy_asset = proxy_idxbl->is_asset ?
1667 assets->update((Asset *)proxy_idxbl) : 0;
1668 EDL *proxy_edl = !proxy_idxbl->is_asset ?
1669 (EDL *)proxy_idxbl : 0;
1670 edit->asset = proxy_asset;
1671 edit->nested_edl = proxy_edl;
1674 for( int j=0,n=clips.size(); j<n; ++j ) {
1675 EDL *clip = clips[j];
1677 for( Track *track=clip->tracks->first; track; track=track->next ) {
1678 if( track->data_type != TRACK_VIDEO ) continue;
1679 for( Edit *edit=track->edits->first; edit; edit=edit->next ) {
1680 Indexable *idxbl = (Indexable *)edit->asset;
1681 if( !idxbl ) idxbl = (Indexable *)edit->nested_edl;
1682 if( !idxbl ) continue;
1683 int i = orig_assets->size();
1684 while( --i>=0 && strcmp(orig_assets->get(i)->path, idxbl->path) );
1685 if( i < 0 ) continue;
1686 Indexable *proxy_idxbl = proxy_assets->get(i);
1687 Asset *proxy_asset = proxy_idxbl->is_asset ?
1688 assets->update((Asset *)proxy_idxbl) : 0;
1689 EDL *proxy_edl = !proxy_idxbl->is_asset ?
1690 (EDL *)proxy_idxbl : 0;
1691 edit->asset = proxy_asset;
1692 edit->nested_edl = proxy_edl;
1696 if( has_proxy && !orig_use_scaler )
1697 clip->rescale_proxy(orig_scale, new_scale);
1701 void EDL::add_proxy(ArrayList<Indexable*> *orig_assets, ArrayList<Indexable*> *proxy_assets)
1703 int asset_scale = session->proxy_scale;
1704 if( asset_scale == 1 ) asset_scale = 0;
1705 int scale = !asset_scale ? 1 : asset_scale;
1706 // update proxy geom using scale
1707 for( int i=0; i<proxy_assets->size(); ++i ) {
1708 Asset *proxy_asset = (Asset *)proxy_assets->get(i);
1709 proxy_asset->proxy_scale = asset_scale;
1710 proxy_asset->width = proxy_asset->actual_width * scale;
1711 proxy_asset->height = proxy_asset->actual_height * scale;
1714 // change original assets to proxy assets
1715 for( int i=0,n=proxy_assets->size(); i<n; ++i ) {
1716 Asset *proxy_asset = assets->update((Asset *)proxy_assets->get(i));
1717 proxy_asset->folder_no = AW_PROXY_FOLDER;
1718 // replace track contents
1719 for( Track *track=tracks->first; track; track=track->next ) {
1720 if( track->data_type != TRACK_VIDEO ) continue;
1721 for( Edit *edit=track->edits->first; edit; edit=edit->next ) {
1722 if( !edit->asset ) continue;
1723 if( !strcmp(edit->asset->path, orig_assets->get(i)->path) ) {
1724 edit->asset = proxy_asset;
1731 Asset *EDL::get_proxy_asset()
1733 return folder_no == AW_PROXY_FOLDER ?
1734 tracks->first->edits->first->asset : 0;
1737 Track *EDL::add_new_track(int data_type)
1739 Track *new_track = 0;
1740 switch( data_type ) {
1742 ++session->video_tracks;
1743 new_track = tracks->add_video_track(0, 0);
1746 ++session->audio_tracks;
1747 new_track = tracks->add_audio_track(0, 0);
1749 case TRACK_SUBTITLE:
1750 new_track = tracks->add_subttl_track(0, 0);
1756 double EDL::get_cursor_position(int cursor_x, int pane_no)
1758 return (double)cursor_x * local_session->zoom_sample / session->sample_rate +
1759 (double)local_session->view_start[pane_no] *
1760 local_session->zoom_sample / session->sample_rate;
1762 int64_t EDL::get_position_cursorx(double position, int pane_no)
1764 return (int64_t)(position * session->sample_rate / local_session->zoom_sample)
1765 - local_session->view_start[pane_no];
1768 int EDL::in_use(Indexable *indexable)
1770 for( Track *track=tracks->first; track; track=track->next ) {
1771 for( Edit *edit=track->edits->first; edit; edit=edit->next ) {
1772 Indexable *idxbl = (Indexable *)edit->asset;
1773 if( !idxbl ) idxbl = (Indexable *)edit->nested_edl;
1774 if( !idxbl ) continue;
1775 if( idxbl->id == indexable->id ) return 1;
1776 if( !indexable->is_asset != !idxbl->is_asset ) continue;
1777 if( !strcmp(idxbl->path, indexable->path) ) return 1;
1780 for( int i=0; i<clips.size(); ++i )
1781 if( clips[i]->in_use(indexable) ) return 1;
1782 for( int i=0; i<nested_edls.size(); ++i )
1783 if( nested_edls[i]->in_use(indexable) ) return 1;
1787 int EDL::regroup(int next_id)
1789 ArrayList<int> new_groups;
1790 for( Track *track=tracks->first; track; track=track->next ) {
1791 for( Edit *edit=track->edits->first; edit; edit=edit->next ) {
1792 if( !edit->group_id ) continue;
1793 int k = new_groups.size();
1794 while( --k >= 0 && new_groups[k] != edit->group_id );
1795 if( k >= 0 ) continue;
1796 new_groups.append(edit->group_id);
1799 for( Track *track=tracks->first; track; track=track->next ) {
1800 for( Edit *edit=track->edits->first; edit; edit=edit->next ) {
1801 if( !edit->group_id ) continue;
1802 int k = new_groups.size();
1803 while( --k >= 0 && new_groups[k] != edit->group_id );
1804 if( k < 0 ) continue;
1805 edit->group_id = k + next_id;
1808 return new_groups.size();
1811 EDL *EDL::selected_edits_to_clip(int packed,
1812 double *start_position, Track **start_track,
1813 int edit_labels, int edit_autos, int edit_plugins)
1815 double start = DBL_MAX, end = DBL_MIN;
1816 Track *first_track=0, *last_track = 0;
1817 for( Track *track=tracks->first; track; track=track->next ) {
1818 if( !track->record ) continue;
1820 for( Edit *edit=track->edits->first; edit; edit=edit->next ) {
1821 if( !edit->is_selected || edit->silence() ) continue;
1822 double edit_pos = track->from_units(edit->startproject);
1823 if( start > edit_pos ) start = edit_pos;
1824 if( end < (edit_pos+=edit->length) ) end = edit_pos;
1827 if( empty ) continue;
1828 if( !first_track ) first_track = track;
1831 if( start_position ) *start_position = start;
1832 if( start_track ) *start_track = first_track;
1833 if( !first_track ) return 0;
1834 EDL *new_edl = new EDL();
1835 new_edl->create_objects();
1836 new_edl->copy_session(this);
1837 const char *text = _("new_edl edit");
1838 new_edl->set_path(text);
1839 strcpy(new_edl->local_session->clip_title, text);
1840 strcpy(new_edl->local_session->clip_notes, text);
1841 new_edl->session->video_tracks = 0;
1842 new_edl->session->audio_tracks = 0;
1843 for( Track *track=tracks->first; track; track=track->next ) {
1844 if( !track->record ) continue;
1846 if( first_track != track ) continue;
1849 Track *new_track = 0;
1851 new_track = new_edl->add_new_track(track->data_type);
1852 int64_t start_pos = track->to_units(start, 0);
1853 int64_t end_pos = track->to_units(end, 0);
1854 int64_t startproject = 0;
1855 Edit *edit = track->edits->first;
1856 for( ; edit; edit=edit->next ) {
1857 if( !edit->is_selected || edit->silence() ) continue;
1858 if( edit->startproject < start_pos ) continue;
1859 if( edit->startproject >= end_pos ) break;
1860 int64_t edit_start_pos = edit->startproject;
1861 int64_t edit_end_pos = edit->startproject + edit->length;
1863 new_track = new_edl->add_new_track(track->data_type);
1864 int64_t edit_pos = edit_start_pos - start_pos;
1865 if( !packed && edit_pos > startproject ) {
1866 Edit *silence = new Edit(new_edl, new_track);
1867 silence->startproject = startproject;
1868 silence->length = edit_pos - startproject;
1869 new_track->edits->append(silence);
1870 startproject = edit_pos;
1872 int64_t clip_start_pos = startproject;
1873 Edit *clip_edit = new Edit(new_edl, new_track);
1874 clip_edit->copy_from(edit);
1875 clip_edit->startproject = startproject;
1876 startproject += clip_edit->length;
1877 new_track->edits->append(clip_edit);
1879 double edit_start = track->from_units(edit_start_pos);
1880 double edit_end = track->from_units(edit_end_pos);
1881 double clip_start = new_track->from_units(clip_start_pos);
1882 Label *label = labels->first;
1883 for( ; label; label=label->next ) {
1884 if( label->position < edit_start ) continue;
1885 if( label->position >= edit_end ) break;
1886 double clip_position = label->position - edit_start + clip_start;
1887 Label *clip_label = new_edl->labels->first;
1888 while( clip_label && clip_label->position<clip_position )
1889 clip_label = clip_label->next;
1890 if( clip_label && clip_label->position == clip_position ) continue;
1891 Label *new_label = new Label(new_edl,
1892 new_edl->labels, clip_position, label->textstr);
1893 new_edl->labels->insert_before(clip_label, new_label);
1897 Automation *automation = track->automation;
1898 Automation *new_automation = new_track->automation;
1899 for( int i=0; i<AUTOMATION_TOTAL; ++i ) {
1900 Autos *autos = automation->autos[i];
1901 if( !autos ) continue;
1902 Autos *new_autos = new_automation->autos[i];
1903 new_autos->default_auto->copy_from(autos->default_auto);
1904 Auto *aut0 = autos->first;
1905 for( ; aut0; aut0=aut0->next ) {
1906 if( aut0->position < edit_start_pos ) continue;
1907 if( aut0->position >= edit_end_pos ) break;
1908 Auto *new_auto = new_autos->new_auto();
1909 new_auto->copy_from(aut0);
1910 int64_t clip_position = aut0->position - edit_start_pos + clip_start_pos;
1911 new_auto->position = clip_position;
1912 new_autos->append(new_auto);
1916 if( edit_plugins ) {
1917 while( new_track->plugin_set.size() < track->plugin_set.size() )
1918 new_track->plugin_set.append(0);
1919 for( int i=0; i<track->plugin_set.total; ++i ) {
1920 PluginSet *plugin_set = track->plugin_set[i];
1921 if( !plugin_set ) continue;
1922 PluginSet *new_plugin_set = new_track->plugin_set[i];
1923 if( !new_plugin_set ) {
1924 new_plugin_set = new PluginSet(new_edl, new_track);
1925 new_track->plugin_set[i] = new_plugin_set;
1927 Plugin *plugin = (Plugin*)plugin_set->first;
1928 int64_t startplugin = new_plugin_set->length();
1929 for( ; plugin ; plugin=(Plugin*)plugin->next ) {
1930 if( plugin->silence() ) continue;
1931 int64_t plugin_start_pos = plugin->startproject;
1932 int64_t plugin_end_pos = plugin_start_pos + plugin->length;
1933 if( plugin_end_pos < start_pos ) continue;
1934 if( plugin_start_pos > end_pos ) break;
1935 if( plugin_start_pos < edit_start_pos )
1936 plugin_start_pos = edit_start_pos;
1937 if( plugin_end_pos > edit_end_pos )
1938 plugin_end_pos = edit_end_pos;
1939 if( plugin_start_pos >= plugin_end_pos ) continue;
1940 int64_t plugin_pos = plugin_start_pos - start_pos;
1941 if( !packed && plugin_pos > startplugin ) {
1942 Plugin *silence = new Plugin(new_edl, new_track, "");
1943 silence->startproject = startplugin;
1944 silence->length = plugin_pos - startplugin;
1945 new_plugin_set->append(silence);
1946 startplugin = plugin_pos;
1948 Plugin *new_plugin = new Plugin(new_edl, new_track, plugin->title);
1949 new_plugin->copy_base(plugin);
1950 new_plugin->startproject = startplugin;
1951 new_plugin->length = plugin_end_pos - plugin_start_pos;
1952 startplugin += new_plugin->length;
1953 new_plugin_set->append(new_plugin);
1954 KeyFrames *keyframes = plugin->keyframes;
1955 KeyFrames *new_keyframes = new_plugin->keyframes;
1956 new_keyframes->default_auto->copy_from(keyframes->default_auto);
1957 new_keyframes->default_auto->position = new_plugin->startproject;
1958 KeyFrame *keyframe = (KeyFrame*)keyframes->first;
1959 for( ; keyframe; keyframe=(KeyFrame*)keyframe->next ) {
1960 if( keyframe->position < edit_start_pos ) continue;
1961 if( keyframe->position >= edit_end_pos ) break;
1962 KeyFrame *clip_keyframe = new KeyFrame(new_edl, new_keyframes);
1963 clip_keyframe->copy_from(keyframe);
1964 int64_t key_position = keyframe->position - start_pos;
1966 key_position += new_plugin->startproject - plugin_pos;
1967 clip_keyframe->position = key_position;
1968 new_keyframes->append(clip_keyframe);
1974 if( last_track == track ) break;
1979 EDL *EDL::selected_edits_to_clip(int packed, double *start_position, Track **start_track)
1981 return selected_edits_to_clip(packed, start_position, start_track,
1982 session->labels_follow_edits,
1983 session->autos_follow_edits,
1984 session->plugins_follow_edits);
1987 void EDL::paste_edits(EDL *clip, Track *first_track, double position, int overwrite,
1988 int edit_edits, int edit_labels, int edit_autos, int edit_plugins)
1991 first_track = tracks->first;
1992 Track *src = clip->tracks->first;
1993 for( Track *track=first_track; track && src; track=track->next ) {
1994 if( !track->record ) continue;
1995 int64_t pos = track->to_units(position, 0);
1997 for( Edit *edit=src->edits->first; edit; edit=edit->next ) {
1998 if( edit->silence() ) continue;
1999 int64_t start = pos + edit->startproject;
2000 int64_t len = edit->length, end = start + len;
2002 track->edits->clear(start, end);
2003 Edit *dst = track->edits->insert_new_edit(start);
2004 dst->copy_from(edit);
2005 dst->startproject = start;
2006 dst->is_selected = 1;
2007 while( (dst=dst->next) != 0 )
2008 dst->startproject += edit->length;
2009 if( overwrite ) continue;
2010 if( edit_labels && track == first_track ) {
2011 double dst_pos = track->from_units(start);
2012 double dst_len = track->from_units(len);
2013 for( Label *label=labels->first; label; label=label->next ) {
2014 if( label->position >= dst_pos )
2015 label->position += dst_len;
2019 for( int i=0; i<AUTOMATION_TOTAL; ++i ) {
2020 Autos *autos = track->automation->autos[i];
2021 if( !autos ) continue;
2022 for( Auto *aut0=autos->first; aut0; aut0=aut0->next ) {
2023 if( aut0->position >= start )
2024 aut0->position += edit->length;
2028 if( edit_plugins ) {
2029 for( int i=0; i<track->plugin_set.size(); ++i ) {
2030 PluginSet *plugin_set = track->plugin_set[i];
2031 Plugin *plugin = (Plugin *)plugin_set->first;
2032 for( ; plugin; plugin=(Plugin *)plugin->next ) {
2033 if( plugin->startproject >= start )
2034 plugin->startproject += edit->length;
2035 else if( plugin->startproject+plugin->length > end )
2036 plugin->length += edit->length;
2037 Auto *default_keyframe = plugin->keyframes->default_auto;
2038 if( default_keyframe->position >= start )
2039 default_keyframe->position += edit->length;
2040 KeyFrame *keyframe = (KeyFrame*)plugin->keyframes->first;
2041 for( ; keyframe; keyframe=(KeyFrame*)keyframe->next ) {
2042 if( keyframe->position >= start )
2043 keyframe->position += edit->length;
2046 plugin_set->optimize();
2052 for( int i=0; i<AUTOMATION_TOTAL; ++i ) {
2053 Autos *src_autos = src->automation->autos[i];
2054 if( !src_autos ) continue;
2055 Autos *autos = track->automation->autos[i];
2056 for( Auto *aut0=src_autos->first; aut0; aut0=aut0->next ) {
2057 int64_t auto_pos = pos + aut0->position;
2058 autos->insert_auto(auto_pos, aut0);
2062 if( edit_plugins ) {
2063 for( int i=0; i<src->plugin_set.size(); ++i ) {
2064 PluginSet *plugin_set = src->plugin_set[i];
2065 if( !plugin_set ) continue;
2066 while( i >= track->plugin_set.size() )
2067 track->plugin_set.append(0);
2068 PluginSet *dst_plugin_set = track->plugin_set[i];
2069 if( !dst_plugin_set ) {
2070 dst_plugin_set = new PluginSet(this, track);
2071 track->plugin_set[i] = dst_plugin_set;
2073 Plugin *plugin = (Plugin *)plugin_set->first;
2074 if( plugin ) track->expand_view = 1;
2075 for( ; plugin; plugin=(Plugin *)plugin->next ) {
2076 int64_t start = pos + plugin->startproject;
2077 int64_t end = start + plugin->length;
2078 if( overwrite || edit_edits )
2079 dst_plugin_set->clear(start, end, 1);
2080 Plugin *new_plugin = dst_plugin_set->insert_plugin(plugin->title,
2081 start, end-start, plugin->plugin_type, &plugin->shared_location,
2082 (KeyFrame*)plugin->keyframes->default_auto, 0);
2083 KeyFrame *keyframe = (KeyFrame*)plugin->keyframes->first;
2084 for( ; keyframe; keyframe=(KeyFrame*)keyframe->next ) {
2085 int64_t keyframe_pos = pos + keyframe->position;
2086 new_plugin->keyframes->insert_auto(keyframe_pos, keyframe);
2088 while( (new_plugin=(Plugin *)new_plugin->next) ) {
2089 KeyFrame *keyframe = (KeyFrame*)new_plugin->keyframes->first;
2090 for( ; keyframe; keyframe=(KeyFrame*)keyframe->next )
2091 keyframe->position += plugin->length;
2099 Label *edl_label = labels->first;
2100 for( Label *label=clip->labels->first; label; label=label->next ) {
2101 double label_pos = position + label->position;
2104 !(exists=equivalent(edl_label->position, label_pos)) &&
2105 edl_label->position < position ) edl_label = edl_label->next;
2106 if( exists ) continue;
2107 labels->insert_before(edl_label,
2108 new Label(this, labels, label_pos, label->textstr));
2114 void EDL::paste_edits(EDL *clip, Track *first_track, double position, int overwrite)
2116 paste_edits(clip, first_track, position, overwrite, 1,
2117 session->labels_follow_edits,
2118 session->autos_follow_edits,
2119 session->plugins_follow_edits);