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"
41 #include "indexstate.h"
42 #include "interlacemodes.h"
44 #include "localsession.h"
45 #include "maskautos.h"
49 #include "playbackconfig.h"
50 #include "playabletracks.h"
52 #include "preferences.h"
53 #include "recordconfig.h"
54 #include "recordlabel.h"
55 #include "sharedlocation.h"
58 #include "transportque.inc"
59 #include "versioninfo.h"
66 EDL::EDL(EDL *parent_edl)
69 this->parent_edl = parent_edl;
84 remove_vwindow_edls();
92 void EDL::create_objects()
94 tracks = new Tracks(this);
95 assets = !parent_edl ? new Assets(this) : parent_edl->assets;
96 session = !parent_edl ? new EDLSession(this) : parent_edl->session;
97 local_session = new LocalSession(this);
98 labels = new Labels(this, "LABELS");
101 EDL& EDL::operator=(EDL &edl)
103 printf("EDL::operator= 1\n");
108 int EDL::load_defaults(BC_Hash *defaults)
111 session->load_defaults(defaults);
113 local_session->load_defaults(defaults);
117 int EDL::save_defaults(BC_Hash *defaults)
120 session->save_defaults(defaults);
122 local_session->save_defaults(defaults);
126 void EDL::boundaries()
128 session->boundaries();
129 local_session->boundaries();
132 int EDL::create_default_tracks()
135 for( int i=0; i<session->video_tracks; ++i ) {
136 tracks->add_video_track(0, 0);
138 for( int i=0; i<session->audio_tracks; ++i ) {
139 tracks->add_audio_track(0, 0);
144 int EDL::load_xml(FileXML *file, uint32_t load_flags)
149 if( (load_flags & LOAD_ALL) == LOAD_ALL ) {
150 remove_vwindow_edls();
154 // Search for start of master EDL.
156 // The parent_edl test caused clip creation to fail since those XML files
157 // contained an EDL tag.
159 // The parent_edl test is required to make EDL loading work because
160 // when loading an EDL the EDL tag is already read by the parent.
164 result = file->read_tag();
166 !file->tag.title_is("XML") &&
167 !file->tag.title_is("EDL"));
169 return result ? result : read_xml(file, load_flags);
172 int EDL::read_xml(FileXML *file, uint32_t load_flags)
175 // Track numbering offset for replacing undo data.
176 int track_offset = 0;
178 // Get path for backups
179 file->tag.get_property("path", path);
182 if( (load_flags & LOAD_ALL) == LOAD_ALL ||
183 (load_flags & LOAD_EDITS) == LOAD_EDITS ) {
184 while(tracks->last) delete tracks->last;
187 if( (load_flags & LOAD_ALL) == LOAD_ALL ) {
189 mixers.remove_all_objects();
192 if( load_flags & LOAD_TIMEBAR ) {
193 while(labels->last) delete labels->last;
194 local_session->unset_inpoint();
195 local_session->unset_outpoint();
198 // This was originally in LocalSession::load_xml
199 if( load_flags & LOAD_SESSION ) {
200 local_session->clipboard_length = 0;
204 result = file->read_tag();
207 if( file->tag.title_is("/XML") ||
208 file->tag.title_is("/EDL") ||
209 file->tag.title_is("/CLIP_EDL") ||
210 file->tag.title_is("/NESTED_EDL") ||
211 file->tag.title_is("/VWINDOW_EDL") ) {
215 if( file->tag.title_is("CLIPBOARD") ) {
216 local_session->clipboard_length =
217 file->tag.get_property("LENGTH", (double)0);
220 if( file->tag.title_is("VIDEO") ) {
221 if( (load_flags & LOAD_VCONFIG) &&
222 (load_flags & LOAD_SESSION) )
223 session->load_video_config(file, 0, load_flags);
225 result = file->skip_tag();
228 if( file->tag.title_is("AUDIO") ) {
229 if( (load_flags & LOAD_ACONFIG) &&
230 (load_flags & LOAD_SESSION) )
231 session->load_audio_config(file, 0, load_flags);
233 result = file->skip_tag();
236 if( file->tag.title_is("FOLDERS") ) {
237 result = folders.load_xml(file);
240 if( file->tag.title_is("MIXERS") ) {
241 if( (load_flags & LOAD_SESSION) )
244 result = file->skip_tag();
247 if( file->tag.title_is("ASSETS") ) {
248 if( load_flags & LOAD_ASSETS )
249 assets->load(file, load_flags);
251 result = file->skip_tag();
254 if( file->tag.title_is(labels->xml_tag) ) {
255 if( load_flags & LOAD_TIMEBAR )
256 labels->load(file, load_flags);
258 result = file->skip_tag();
261 if( file->tag.title_is("LOCALSESSION") ) {
262 if( (load_flags & LOAD_SESSION) ||
263 (load_flags & LOAD_TIMEBAR) )
264 local_session->load_xml(file, load_flags);
266 result = file->skip_tag();
269 if( file->tag.title_is("SESSION") ) {
270 if( (load_flags & LOAD_SESSION) &&
272 session->load_xml(file, 0, load_flags);
274 result = file->skip_tag();
277 if( file->tag.title_is("TRACK") ) {
278 tracks->load(file, track_offset, load_flags);
282 // Causes clip creation to fail because that involves an opening EDL tag.
283 if( file->tag.title_is("CLIP_EDL") && !parent_edl ) {
284 EDL *new_edl = new EDL(this);
285 new_edl->create_objects();
286 new_edl->read_xml(file, LOAD_ALL);
287 if( (load_flags & LOAD_ALL) == LOAD_ALL )
288 clips.add_clip(new_edl);
289 new_edl->remove_user();
292 if( file->tag.title_is("NESTED_EDL") ) {
293 EDL *nested_edl = new EDL;
294 nested_edl->create_objects();
295 nested_edl->read_xml(file, LOAD_ALL);
296 if( (load_flags & LOAD_ALL) == LOAD_ALL )
297 nested_edls.get_nested(nested_edl);
298 nested_edl->remove_user();
301 if( file->tag.title_is("VWINDOW_EDL") && !parent_edl ) {
302 EDL *new_edl = new EDL(this);
303 new_edl->create_objects();
304 new_edl->read_xml(file, LOAD_ALL);
307 if( (load_flags & LOAD_ALL) == LOAD_ALL ) {
308 // if( vwindow_edl && !vwindow_edl_shared )
309 // vwindow_edl->remove_user();
310 // vwindow_edl_shared = 0;
311 // vwindow_edl = new_edl;
313 append_vwindow_edl(new_edl, 0);
317 // Discard if not replacing EDL
319 new_edl->remove_user();
332 // Output path is the path of the output file if name truncation is desired.
333 // It is a "" if complete names should be used.
334 // Called recursively by copy for clips, thus the string can't be terminated.
335 // The string is not terminated in this call.
336 int EDL::save_xml(FileXML *file, const char *output_path)
338 copy(1, file, output_path, 0);
342 int EDL::copy_all(EDL *edl)
344 if( this == edl ) return 0;
345 folder_no = edl->folder_no;
352 tracks->copy_from(edl->tracks);
353 labels->copy_from(edl->labels);
357 void EDL::copy_clips(EDL *edl)
359 if( this == edl ) return;
361 remove_vwindow_edls();
363 // if( vwindow_edl && !vwindow_edl_shared )
364 // vwindow_edl->remove_user();
366 // vwindow_edl_shared = 0;
368 for( int i=0; i<edl->total_vwindow_edls(); ++i ) {
369 EDL *new_edl = new EDL(this);
370 new_edl->create_objects();
371 new_edl->copy_all(edl->get_vwindow_edl(i));
372 append_vwindow_edl(new_edl, 0);
376 for( int i=0; i<edl->clips.size(); ++i ) add_clip(edl->clips[i]);
379 void EDL::copy_nested(EDL *edl)
381 if( this == edl ) return;
382 nested_edls.copy_nested(edl->nested_edls);
385 void EDL::copy_assets(EDL *edl)
387 if( this == edl ) return;
390 assets->copy_from(edl->assets);
394 void EDL::copy_mixers(EDL *edl)
396 if( this == edl ) return;
397 mixers.copy_from(edl->mixers);
400 void EDL::copy_session(EDL *edl, int session_only)
402 if( this == edl ) return;
404 if( !session_only ) {
405 strcpy(this->path, edl->path);
406 folders.copy_from(&edl->folders);
410 session->copy(edl->session);
413 if( session_only <= 0 ) {
414 local_session->copy_from(edl->local_session);
418 int EDL::copy_assets(double start,
422 const char *output_path)
424 ArrayList<Asset*> asset_list;
427 file->tag.set_title("ASSETS");
429 file->append_newline();
431 // Copy everything for a save
433 for( Asset *asset=assets->first; asset; asset=asset->next ) {
434 asset_list.append(asset);
438 // Copy just the ones being used.
439 for( current = tracks->first; current; current = NEXT ) {
440 if( !current->record ) continue;
441 current->copy_assets(start, end, &asset_list);
445 // Paths relativised here
446 for( int i=0; i<asset_list.size(); ++i ) {
447 asset_list[i]->write(file, 0, output_path);
450 file->tag.set_title("/ASSETS");
452 file->append_newline();
453 file->append_newline();
458 int EDL::copy(double start, double end, int all,
459 FileXML *file, const char *output_path, int rewind_it)
461 file->tag.set_title("EDL");
462 file->tag.set_property("VERSION", CINELERRA_VERSION);
463 // Save path for restoration of the project title from a backup.
464 if( this->path[0] ) file->tag.set_property("PATH", path);
465 return copy(start, end, all,
466 "/EDL", file, output_path, rewind_it);
468 int EDL::copy(int all, FileXML *file, const char *output_path, int rewind_it)
470 return copy(0, tracks->total_length(), all, file, output_path, rewind_it);
473 int EDL::copy_clip(double start, double end, int all,
474 FileXML *file, const char *output_path, int rewind_it)
476 file->tag.set_title("CLIP_EDL");
477 return copy(start, end, all,
478 "/CLIP_EDL", file, output_path, rewind_it);
480 int EDL::copy_clip(int all, FileXML *file, const char *output_path, int rewind_it)
482 return copy_clip(0, tracks->total_length(), all, file, output_path, rewind_it);
485 int EDL::copy_nested_edl(double start, double end, int all,
486 FileXML *file, const char *output_path, int rewind_it)
488 file->tag.set_title("NESTED_EDL");
489 if( this->path[0] ) file->tag.set_property("PATH", path);
490 return copy(start, end, all,
491 "/NESTED_EDL", file, output_path, rewind_it);
493 int EDL::copy_nested_edl(int all, FileXML *file, const char *output_path, int rewind_it)
495 return copy_nested_edl(0, tracks->total_length(), all, file, output_path, rewind_it);
498 int EDL::copy_vwindow_edl(double start, double end, int all,
499 FileXML *file, const char *output_path, int rewind_it)
501 file->tag.set_title("VWINDOW_EDL");
502 return copy(start, end, all,
503 "/VWINDOW_EDL", file, output_path, rewind_it);
505 int EDL::copy_vwindow_edl(int all, FileXML *file, const char *output_path, int rewind_it)
507 return copy_vwindow_edl(0, tracks->total_length(), all, file, output_path, rewind_it);
511 int EDL::copy(double start, double end, int all,
512 const char *closer, FileXML *file,
513 const char *output_path, int rewind_it)
516 file->append_newline();
517 // Set clipboard samples only if copying to clipboard
519 file->tag.set_title("CLIPBOARD");
520 file->tag.set_property("LENGTH", end - start);
522 file->tag.set_title("/CLIPBOARD");
524 file->append_newline();
525 file->append_newline();
527 //printf("EDL::copy 1\n");
530 local_session->save_xml(file, start);
532 //printf("EDL::copy 1\n");
537 // Need to copy all this from child EDL if pasting is desired.
539 session->save_xml(file);
540 session->save_video_config(file);
541 session->save_audio_config(file);
542 folders.save_xml(file);
545 copy_assets(start, end, file, all, output_path);
547 for( int i=0; i<nested_edls.size(); ++i )
548 nested_edls[i]->copy_nested_edl(0, tracks->total_length(), 1,
549 file, output_path, 0);
552 // Don't want this if using clipboard
554 for( int i=0; i<total_vwindow_edls(); ++i )
555 get_vwindow_edl(i)->copy_vwindow_edl(1, file, output_path, 0);
557 for( int i=0; i<clips.size(); ++i )
558 clips[i]->copy_clip(1, file, output_path, 0);
563 file->append_newline();
564 file->append_newline();
567 labels->copy(start, end, file);
568 tracks->copy(start, end, all, file, output_path);
571 file->tag.set_title(closer);
573 file->append_newline();
575 // For editing operations we want to rewind it for immediate pasting.
576 // For clips and saving to disk leave it alone.
578 file->terminate_string();
584 void EDL::copy_indexables(EDL *edl)
586 for( Track *track=edl->tracks->first; track; track=track->next ) {
587 for( Edit *edit=track->edits->first; edit; edit=edit->next ) {
589 assets->update(edit->asset);
590 if( edit->nested_edl )
591 nested_edls.get_nested(edit->nested_edl);
596 EDL *EDL::new_nested(EDL *edl, const char *path)
598 EDL *nested = new EDL; // no parent for nested edl
599 nested->create_objects();
600 nested->copy_session(edl);
601 nested->set_path(path);
602 nested->update_index(edl);
603 nested->copy_indexables(edl);
604 nested->tracks->copy_from(edl->tracks);
605 nested_edls.append(nested);
609 EDL *EDL::create_nested_clip(EDL *nested)
611 EDL *new_edl = new EDL(this); // parent for clip edl
612 new_edl->create_objects();
613 new_edl->create_nested(nested);
617 void EDL::create_nested(EDL *nested)
619 // Keep frame rate, sample rate, and output size unchanged.
620 // Nest all video & audio outputs
621 session->video_tracks = 1;
622 session->audio_tracks = nested->session->audio_channels;
623 create_default_tracks();
624 insert_asset(0, nested, 0, 0, 0);
629 int min_w = session->output_w, min_h = session->output_h;
630 for( Track *track=tracks->first; track!=0; track=track->next ) {
631 if( track->data_type != TRACK_VIDEO ) continue;
632 int w = min_w, h = min_h;
633 for( Edit *current=track->edits->first; current!=0; current=NEXT ) {
634 Indexable* indexable = current->get_source();
635 if( !indexable ) continue;
636 int edit_w = indexable->get_w(), edit_h = indexable->get_h();
637 if( w < edit_w ) w = edit_w;
638 if( h < edit_h ) h = edit_h;
640 if( track->track_w == w && track->track_h == h ) continue;
641 ((MaskAutos*)track->automation->autos[AUTOMATION_MASK])->
642 translate_masks( (w - track->track_w) / 2, (h - track->track_h) / 2);
643 track->track_w = w; track->track_h = h;
647 void EDL::rechannel()
649 for( Track *current=tracks->first; current; current=NEXT ) {
650 if( current->data_type == TRACK_AUDIO ) {
651 PanAutos *autos = (PanAutos*)current->automation->autos[AUTOMATION_PAN];
652 ((PanAuto*)autos->default_auto)->rechannel();
653 for( PanAuto *keyframe = (PanAuto*)autos->first;
654 keyframe; keyframe = (PanAuto*)keyframe->next ) {
655 keyframe->rechannel();
661 void EDL::resample(double old_rate, double new_rate, int data_type)
663 for( Track *current=tracks->first; current; current=NEXT ) {
664 if( current->data_type == data_type ) {
665 current->resample(old_rate, new_rate);
671 void EDL::synchronize_params(EDL *edl)
673 local_session->synchronize_params(edl->local_session);
674 for( Track *this_track=tracks->first, *that_track=edl->tracks->first;
675 this_track && that_track;
676 this_track=this_track->next, that_track=that_track->next ) {
677 this_track->synchronize_params(that_track);
681 int EDL::trim_selection(double start,
695 tracks->total_length(),
704 int EDL::equivalent(double position1, double position2)
706 double threshold = session->cursor_on_frames ?
707 0.5 / session->frame_rate : 1.0 / session->sample_rate;
708 return fabs(position2 - position1) < threshold ? 1 : 0;
711 double EDL::equivalent_output(EDL *edl)
714 session->equivalent_output(edl->session, &result);
715 tracks->equivalent_output(edl->tracks, &result);
720 void EDL::set_path(const char *path)
722 if( &this->path[0] == path ) return;
723 strcpy(this->path, path);
726 void EDL::set_inpoint(double position)
728 if( equivalent(local_session->get_inpoint(), position) &&
729 local_session->get_inpoint() >= 0 ) {
730 local_session->unset_inpoint();
733 local_session->set_inpoint(align_to_frame(position, 0));
734 if( local_session->get_outpoint() <= local_session->get_inpoint() )
735 local_session->unset_outpoint();
739 void EDL::set_outpoint(double position)
741 if( equivalent(local_session->get_outpoint(), position) &&
742 local_session->get_outpoint() >= 0 ) {
743 local_session->unset_outpoint();
746 local_session->set_outpoint(align_to_frame(position, 0));
747 if( local_session->get_inpoint() >= local_session->get_outpoint() )
748 local_session->unset_inpoint();
752 void EDL::unset_inoutpoint()
754 local_session->unset_inpoint();
755 local_session->unset_outpoint();
758 int EDL::blade(double position)
760 return tracks->blade(position);
763 int EDL::clear(double start, double end,
764 int clear_labels, int clear_plugins, int edit_autos)
768 tracks->clear_handle(start,
774 if( clear_labels && distance > 0 )
775 labels->paste_silence(start,
789 // Need to put at beginning so a subsequent paste operation starts at the
791 double position = local_session->get_selectionstart();
792 local_session->set_selectionend(position);
793 local_session->set_selectionstart(position);
797 void EDL::modify_edithandles(double oldposition,
805 tracks->modify_edithandles(oldposition,
812 labels->modify_handles(oldposition,
819 void EDL::modify_pluginhandles(double oldposition,
827 tracks->modify_pluginhandles(oldposition,
837 void EDL::paste_silence(double start,
844 labels->paste_silence(start, end);
845 tracks->paste_silence(start,
852 void EDL::remove_from_project(ArrayList<EDL*> *clips)
854 for( int i=0; i<clips->size(); ++i ) {
855 this->clips.remove_clip(clips->get(i));
859 void EDL::remove_from_project(ArrayList<Indexable*> *assets)
863 for( int j=0; j<clips.size(); ++j ) {
864 clips[j]->remove_from_project(assets);
867 // Remove from VWindow EDLs
868 for( int i=0; i<total_vwindow_edls(); ++i )
869 get_vwindow_edl(i)->remove_from_project(assets);
871 for( int i=0; i<assets->size(); ++i ) {
872 // Remove from tracks
873 for( Track *track=tracks->first; track; track=track->next ) {
874 track->remove_asset(assets->get(i));
877 // Remove from assets
878 if( !parent_edl && assets->get(i)->is_asset ) {
879 this->assets->remove_asset((Asset*)assets->get(i));
882 if( !parent_edl && !assets->get(i)->is_asset ) {
883 this->nested_edls.remove_clip((EDL*)assets->get(i));
888 void EDL::update_assets(EDL *src)
890 for( Asset *current=src->assets->first; current; current=NEXT ) {
891 assets->update(current);
895 int EDL::get_tracks_height(Theme *theme)
897 int total_pixels = 0;
898 for( Track *current=tracks->first; current; current=NEXT ) {
899 total_pixels += current->vertical_span(theme);
904 int64_t EDL::get_tracks_width()
906 int64_t total_pixels = 0;
907 for( Track *current=tracks->first; current; current=NEXT ) {
908 int64_t pixels = current->horizontal_span();
909 if( pixels > total_pixels ) total_pixels = pixels;
911 //printf("EDL::get_tracks_width %d\n", total_pixels);
915 // int EDL::calculate_output_w(int single_channel)
917 // if( single_channel ) return session->output_w;
920 // for( int i=0; i<session->video_channels; ++i )
922 // if( session->vchannel_x[i] + session->output_w > widest ) widest = session->vchannel_x[i] + session->output_w;
927 // int EDL::calculate_output_h(int single_channel)
929 // if( single_channel ) return session->output_h;
932 // for( int i=0; i<session->video_channels; ++i )
934 // if( session->vchannel_y[i] + session->output_h > tallest ) tallest = session->vchannel_y[i] + session->output_h;
939 // Get the total output size scaled to aspect ratio
940 void EDL::calculate_conformed_dimensions(int single_channel, float &w, float &h)
942 if( (float)session->output_w / session->output_h > get_aspect_ratio() )
943 h = (w = session->output_w) / get_aspect_ratio();
945 w = (h = session->output_h) * get_aspect_ratio();
948 float EDL::get_aspect_ratio()
950 return session->aspect_w / session->aspect_h;
953 int EDL::dump(FILE *fp)
956 fprintf(fp,"CLIP\n");
959 fprintf(fp," clip_title: %s\n"
960 " parent_edl: %p\n", local_session->clip_title, parent_edl);
961 fprintf(fp," selectionstart %f\n selectionend %f\n loop_start %f\n loop_end %f\n",
962 local_session->get_selectionstart(1),
963 local_session->get_selectionend(1),
964 local_session->loop_start,
965 local_session->loop_end);
966 for( int i=0; i<TOTAL_PANES; ++i ) {
967 fprintf(fp," pane %d view_start=%jd track_start=%d\n", i,
968 local_session->view_start[i],
969 local_session->track_start[i]);
973 fprintf(fp,"audio_channels: %d audio_tracks: %d sample_rate: %jd\n",
974 session->audio_channels,
975 session->audio_tracks,
976 session->sample_rate);
977 fprintf(fp," video_channels: %d\n"
978 " video_tracks: %d\n"
979 " frame_rate: %.2f\n"
980 " frames_per_foot: %.2f\n"
985 " color_model: %d\n",
986 session->video_channels,
987 session->video_tracks,
989 session->frames_per_foot,
994 session->color_model);
996 fprintf(fp," CLIPS");
997 fprintf(fp," total: %d\n", clips.size());
998 for( int i=0; i<clips.size(); ++i ) {
1003 fprintf(fp," NESTED_EDLS");
1004 fprintf(fp," total: %d\n", nested_edls.size());
1005 for( int i=0; i<nested_edls.size(); ++i )
1006 fprintf(fp," %s\n", nested_edls[i]->path);
1008 fprintf(fp," VWINDOW EDLS");
1009 fprintf(fp," total: %d\n", total_vwindow_edls());
1011 for( int i=0; i<total_vwindow_edls(); ++i ) {
1012 fprintf(fp," %s\n", get_vwindow_edl(i)->local_session->clip_title);
1015 fprintf(fp," ASSETS\n");
1018 fprintf(fp," LABELS\n");
1020 fprintf(fp," TRACKS\n");
1022 //printf("EDL::dump 2\n");
1026 EDL* EDL::add_clip(EDL *edl)
1028 // Copy argument. New edls are deleted from MWindow::load_filenames.
1029 EDL *new_edl = new EDL(this);
1030 new_edl->create_objects();
1031 new_edl->copy_all(edl);
1032 new_edl->folder_no = AW_CLIP_FOLDER;
1033 clips.append(new_edl);
1037 void EDL::insert_asset(Asset *asset,
1041 RecordLabels *labels)
1043 // Insert asset into asset table
1044 Asset *new_asset = 0;
1045 EDL *new_nested_edl = 0;
1047 if( asset ) new_asset = assets->update(asset);
1048 if( nested_edl ) new_nested_edl = nested_edls.get_nested(nested_edl);
1052 Track *current = first_track ? first_track : tracks->first;
1055 // Fix length of single frame
1060 if( new_nested_edl ) {
1061 length = new_nested_edl->tracks->total_length();
1063 channels = new_nested_edl->session->audio_channels;
1067 // Insert 1 frame for undefined length
1068 if( new_asset->video_length < 0 ) {
1069 length = session->si_useduration ?
1070 session->si_duration :
1071 1.0 / session->frame_rate;
1074 length = new_asset->frame_rate > 0 ?
1075 (double)new_asset->video_length / new_asset->frame_rate :
1076 1.0 / session->frame_rate;
1078 layers = new_asset->layers;
1079 channels = new_asset->channels;
1082 for( ; current && vtrack<layers; current=NEXT ) {
1083 if( !current->record || current->data_type != TRACK_VIDEO ) continue;
1084 current->insert_asset(new_asset, new_nested_edl,
1085 length, position, vtrack++);
1090 if( new_asset->audio_length < 0 ) {
1091 // Insert 1 frame for undefined length & video
1092 if( new_asset->video_data )
1093 length = (double)1.0 / new_asset->frame_rate;
1095 // Insert 1 second for undefined length & no video
1099 length = (double)new_asset->audio_length /
1100 new_asset->sample_rate;
1103 current = tracks->first;
1104 for( ; current && atrack < channels; current=NEXT ) {
1105 if( !current->record || current->data_type != TRACK_AUDIO ) continue;
1106 current->insert_asset(new_asset, new_nested_edl,
1107 length, position, atrack++);
1110 // Insert labels from a recording window.
1112 for( RecordLabel *label=labels->first; label; label=label->next ) {
1113 this->labels->toggle_label(label->position, label->position);
1120 void EDL::set_index_file(Indexable *indexable)
1122 if( indexable->is_asset )
1123 assets->update_index((Asset*)indexable);
1125 nested_edls.update_index((EDL*)indexable);
1128 void EDL::optimize()
1130 //printf("EDL::optimize 1\n");
1131 double length = tracks->total_length();
1132 double preview_start = local_session->preview_start;
1133 double preview_end = local_session->preview_end;
1134 if( preview_end < 0 || preview_end > length )
1135 preview_end = length;
1136 if( preview_start == 0 && preview_end >= length )
1137 local_session->preview_end = -1;
1138 if( preview_start > preview_end )
1139 local_session->preview_start = preview_end;
1140 for( Track *current=tracks->first; current; current=NEXT )
1141 current->optimize();
1146 static Mutex id_lock;
1147 id_lock.lock("EDL::next_id");
1148 int result = EDLSession::current_id++;
1153 void EDL::get_shared_plugins(Track *source,
1154 ArrayList<SharedLocation*> *plugin_locations,
1155 int omit_recordable,
1158 for( Track *track=tracks->first; track; track=track->next ) {
1159 if( track->record && omit_recordable ) continue;
1160 if( track == source || track->data_type != data_type ) continue;
1161 for( int i=0; i<track->plugin_set.size(); ++i ) {
1162 Plugin *plugin = track->get_current_plugin(
1163 local_session->get_selectionstart(1),
1164 i, PLAY_FORWARD, 1, 0);
1165 if( plugin && plugin->plugin_type != PLUGIN_STANDALONE ) continue;
1166 plugin_locations->append(new SharedLocation(tracks->number_of(track), i));
1171 void EDL::get_shared_tracks(Track *track,
1172 ArrayList<SharedLocation*> *module_locations,
1173 int omit_recordable, int data_type)
1175 for( Track *current=tracks->first; current; current=NEXT ) {
1176 if( omit_recordable && current->record ) continue;
1177 if( current == track || current->data_type != data_type ) continue;
1178 module_locations->append(new SharedLocation(tracks->number_of(current), 0));
1182 // aligned frame time
1183 double EDL::frame_align(double position, int round)
1185 double frame_pos = position * session->frame_rate;
1186 frame_pos = (int64_t)(frame_pos + (round ? 0.5 : 1e-6));
1187 position = frame_pos / session->frame_rate;
1191 // Convert position to frames if alignment is enabled.
1192 double EDL::align_to_frame(double position, int round)
1194 if( session->cursor_on_frames )
1195 position = frame_align(position, round);
1200 BinFolder *EDL::get_folder(int no)
1202 for( int i=0; i<folders.size(); ++i ) {
1203 BinFolder *fp = folders[i];
1204 if( no == fp->awindow_folder ) return fp;
1209 int EDL::get_folder_number(const char *title)
1211 for( int i=0; i<AWINDOW_FOLDERS; ++i ) {
1212 if( !strcmp(title, AWindowGUI::folder_names[i]) )
1215 for( int i=0; i<folders.size(); ++i ) {
1216 if( !strcmp(title, folders[i]->title) )
1217 return folders[i]->awindow_folder;
1219 return AW_NO_FOLDER;
1222 const char *EDL::get_folder_name(int no)
1224 if( no >= 0 && no<AWINDOW_FOLDERS )
1225 return AWindowGUI::folder_names[no];
1226 BinFolder *fp = get_folder(no);
1227 return !fp ? "" : fp->title;
1230 int EDL::new_folder(const char *title, int is_clips)
1232 if( !title[0] ) return 1;
1233 int ret = get_folder_number(title);
1234 if( ret >= 0 ) return 1;
1235 int idx = AWINDOW_FOLDERS;
1236 for( int i=0; i<folders.size(); ++i ) {
1237 BinFolder *fp = folders[i];
1238 int no = fp->awindow_folder;
1239 if( no >= idx ) idx = no+1;
1241 folders.append(new BinFolder(idx, is_clips, title));
1245 int EDL::delete_folder(const char *title)
1247 int k = folders.size();
1248 while( --k >= 0 && strcmp(title, folders[k]->title) );
1250 folders.remove_object_number(k);
1254 int EDL::get_use_vconsole(VEdit* *playable_edit,
1255 int64_t position, int direction, PlayableTracks *playable_tracks)
1257 int share_playable_tracks = 1;
1259 VTrack *playable_track = 0;
1260 const int debug = 0;
1263 // Calculate playable tracks when being called as a nested EDL
1264 if( !playable_tracks ) {
1265 share_playable_tracks = 0;
1266 playable_tracks = new PlayableTracks(this,
1267 position, direction, TRACK_VIDEO, 1);
1271 // Total number of playable tracks is 1
1272 if( playable_tracks->size() != 1 ) {
1276 playable_track = (VTrack*)playable_tracks->get(0);
1279 // Don't need playable tracks anymore
1280 if( !share_playable_tracks ) {
1281 delete playable_tracks;
1284 if( debug ) printf("EDL::get_use_vconsole %d playable_tracks->size()=%d\n",
1285 __LINE__, playable_tracks->size());
1286 if( result ) return 1;
1289 // Test mutual conditions between direct copy rendering and this.
1290 if( !playable_track->direct_copy_possible(position,
1294 if( debug ) printf("EDL::get_use_vconsole %d\n", __LINE__);
1296 *playable_edit = (VEdit*)playable_track->edits->editof(position,
1298 // No edit at current location
1299 if( !*playable_edit ) return 1;
1300 if( debug ) printf("EDL::get_use_vconsole %d\n", __LINE__);
1303 // Edit is nested EDL
1304 if( (*playable_edit)->nested_edl ) {
1306 EDL *nested_edl = (*playable_edit)->nested_edl;
1307 int64_t nested_position = (int64_t)((position -
1308 (*playable_edit)->startproject +
1309 (*playable_edit)->startsource) *
1310 nested_edl->session->frame_rate /
1311 session->frame_rate);
1314 VEdit *playable_edit_temp = 0;
1315 if( session->output_w != nested_edl->session->output_w ||
1316 session->output_h != nested_edl->session->output_h ||
1317 nested_edl->get_use_vconsole(&playable_edit_temp,
1326 if( debug ) printf("EDL::get_use_vconsole %d\n", __LINE__);
1327 // Edit is not a nested EDL
1328 Asset *asset = (*playable_edit)->asset;
1330 if( !asset ) return 1;
1331 if( debug ) printf("EDL::get_use_vconsole %d\n", __LINE__);
1333 // Asset and output device must have the same dimensions
1334 if( asset->width != session->output_w ||
1335 asset->height != session->output_h )
1339 if( debug ) printf("EDL::get_use_vconsole %d\n", __LINE__);
1340 // Asset and output device must have same resulting de-interlacing method
1341 if( ilaceautofixmethod2(session->interlace_mode,
1342 asset->interlace_autofixoption, asset->interlace_mode,
1343 asset->interlace_fixmethod) != ILACE_FIXMETHOD_NONE )
1346 // If we get here the frame is going to be directly copied. Whether it is
1347 // decompressed in hardware depends on the colormodel.
1353 int EDL::get_audio_channels()
1355 return session->audio_channels;
1358 int EDL::get_sample_rate()
1360 return session->sample_rate;
1363 int64_t EDL::get_audio_samples()
1365 return (int64_t)(tracks->total_length() *
1366 session->sample_rate);
1369 int EDL::have_audio()
1374 int EDL::have_video()
1382 return session->output_w;
1387 return session->output_h;
1390 double EDL::get_frame_rate()
1392 return session->frame_rate;
1395 int EDL::get_video_layers()
1400 int64_t EDL::get_video_frames()
1402 return (int64_t)(tracks->total_length() *
1403 session->frame_rate);
1406 void EDL::remove_vwindow_edls()
1408 for( int i=0; i<total_vwindow_edls(); ++i ) {
1409 get_vwindow_edl(i)->remove_user();
1411 vwindow_edls.remove_all();
1414 void EDL::remove_vwindow_edl(EDL *edl)
1416 if( vwindow_edls.number_of(edl) >= 0 ) {
1418 vwindow_edls.remove(edl);
1423 EDL* EDL::get_vwindow_edl(int number)
1425 return vwindow_edls.get(number);
1428 int EDL::total_vwindow_edls()
1430 return vwindow_edls.size();
1433 void EDL::append_vwindow_edl(EDL *edl, int increase_counter)
1435 if(vwindow_edls.number_of(edl) >= 0) return;
1437 if(increase_counter) edl->add_user();
1438 vwindow_edls.append(edl);
1442 double EDL::next_edit(double position)
1444 Units::fix_double(&position);
1445 double new_position = tracks->total_length();
1447 double max_rate = get_frame_rate();
1448 int sample_rate = get_sample_rate();
1449 if( sample_rate > max_rate ) max_rate = sample_rate;
1450 double min_movement = max_rate > 0 ? 1. / max_rate : 1e-6;
1452 // Test for edit handles after position
1453 for( Track *track=tracks->first; track; track=track->next ) {
1454 if( !track->record ) continue;
1455 for( Edit *edit=track->edits->first; edit; edit=edit->next ) {
1456 double edit_end = track->from_units(edit->startproject + edit->length);
1457 Units::fix_double(&edit_end);
1458 if( fabs(edit_end-position) < min_movement ) continue;
1459 if( edit_end > position && edit_end < new_position )
1460 new_position = edit_end;
1463 return new_position;
1466 double EDL::prev_edit(double position)
1468 Units::fix_double(&position);
1469 double new_position = -1;
1471 double max_rate = get_frame_rate();
1472 int sample_rate = get_sample_rate();
1473 if( sample_rate > max_rate ) max_rate = sample_rate;
1474 double min_movement = max_rate > 0 ? 1. / max_rate : 1e-6;
1476 // Test for edit handles before cursor position
1477 for( Track *track=tracks->first; track; track=track->next ) {
1478 if( !track->record ) continue;
1479 for( Edit *edit=track->edits->first; edit; edit=edit->next ) {
1480 double edit_end = track->from_units(edit->startproject);
1481 Units::fix_double(&edit_end);
1482 if( fabs(edit_end-position) < min_movement ) continue;
1483 if( edit_end < position && edit_end > new_position )
1484 new_position = edit_end;
1487 return new_position;
1490 void EDL::rescale_proxy(int orig_scale, int new_scale)
1492 if( orig_scale == new_scale ) return;
1494 float orig_w = (float)session->output_w * orig_scale;
1495 float orig_h = (float)session->output_h * orig_scale;
1497 session->output_w = Units::round(orig_w / new_scale);
1498 session->output_h = Units::round(orig_h / new_scale);
1502 for( Track *track=tracks->first; track; track=track->next ) {
1503 if( track->data_type != TRACK_VIDEO ) continue;
1504 orig_w = (float)track->track_w * orig_scale;
1505 orig_h = (float)track->track_h * orig_scale;
1506 track->track_w = Units::round(orig_w / new_scale);
1507 track->track_h = Units::round(orig_h / new_scale);
1508 ((MaskAutos*)track->automation->autos[AUTOMATION_MASK])->
1509 set_proxy(orig_scale, new_scale);
1510 ((FloatAutos*)track->automation->autos[AUTOMATION_CAMERA_X])->
1511 set_proxy(orig_scale, new_scale);
1512 ((FloatAutos*)track->automation->autos[AUTOMATION_CAMERA_Y])->
1513 set_proxy(orig_scale, new_scale);
1514 ((FloatAutos*)track->automation->autos[AUTOMATION_PROJECTOR_X])->
1515 set_proxy(orig_scale, new_scale);
1516 ((FloatAutos*)track->automation->autos[AUTOMATION_PROJECTOR_Y])->
1517 set_proxy(orig_scale, new_scale);
1521 void EDL::set_proxy(int new_scale, int use_scaler,
1522 ArrayList<Indexable*> *orig_assets, ArrayList<Indexable*> *proxy_assets)
1524 int orig_scale = session->proxy_scale;
1525 int orig_use_scaler = session->proxy_use_scaler;
1527 // rescale to full size asset in read_frame
1528 session->proxy_scale = new_scale;
1529 session->proxy_use_scaler = use_scaler;
1532 for( int i=0; i<proxy_assets->size(); ++i ) {
1533 Asset *proxy_asset = (Asset *)proxy_assets->get(i);
1534 proxy_asset->width = orig_assets->get(i)->get_w();
1535 proxy_asset->height = orig_assets->get(i)->get_h();
1540 if( !orig_use_scaler )
1541 rescale_proxy(orig_scale, new_scale);
1543 // change original assets to proxy assets
1544 int folder_no = use_scaler || new_scale != 1 ? AW_PROXY_FOLDER : AW_MEDIA_FOLDER;
1545 for( int i=0,n=proxy_assets->size(); i<n; ++i ) {
1546 Indexable *proxy_idxbl = proxy_assets->get(i);
1547 proxy_idxbl->folder_no = folder_no;
1548 if( !proxy_idxbl->is_asset ) continue;
1549 Asset *proxy_asset = assets->update((Asset *)proxy_idxbl);
1550 if( proxy_asset == (Asset *)proxy_idxbl ) continue;
1551 proxy_asset->width = proxy_idxbl->get_w();
1552 proxy_asset->height = proxy_idxbl->get_h();
1554 // replace track contents
1555 for( Track *track=tracks->first; track; track=track->next ) {
1556 if( track->data_type != TRACK_VIDEO ) continue;
1557 for( Edit *edit=track->edits->first; edit; edit=edit->next ) {
1558 Indexable *idxbl = (Indexable *)edit->asset;
1559 if( !idxbl ) idxbl = (Indexable *)edit->nested_edl;
1560 if( !idxbl ) continue;
1561 int i = orig_assets->size();
1562 while( --i>=0 && strcmp(orig_assets->get(i)->path, idxbl->path) );
1563 if( i < 0 ) continue;
1564 Indexable *proxy_idxbl = proxy_assets->get(i);
1565 Asset *proxy_asset = proxy_idxbl->is_asset ?
1566 assets->update((Asset *)proxy_idxbl) : 0;
1567 EDL *proxy_edl = !proxy_idxbl->is_asset ?
1568 (EDL *)proxy_idxbl : 0;
1569 edit->asset = proxy_asset;
1570 edit->nested_edl = proxy_edl;
1573 for( int j=0,n=clips.size(); j<n; ++j ) {
1574 EDL *clip = clips[j];
1576 for( Track *track=clip->tracks->first; track; track=track->next ) {
1577 if( track->data_type != TRACK_VIDEO ) continue;
1578 for( Edit *edit=track->edits->first; edit; edit=edit->next ) {
1579 Indexable *idxbl = (Indexable *)edit->asset;
1580 if( !idxbl ) idxbl = (Indexable *)edit->nested_edl;
1581 if( !idxbl ) continue;
1582 int i = orig_assets->size();
1583 while( --i>=0 && strcmp(orig_assets->get(i)->path, idxbl->path) );
1584 if( i < 0 ) continue;
1585 Indexable *proxy_idxbl = proxy_assets->get(i);
1586 Asset *proxy_asset = proxy_idxbl->is_asset ?
1587 assets->update((Asset *)proxy_idxbl) : 0;
1588 EDL *proxy_edl = !proxy_idxbl->is_asset ?
1589 (EDL *)proxy_idxbl : 0;
1590 edit->asset = proxy_asset;
1591 edit->nested_edl = proxy_edl;
1595 if( has_proxy && !orig_use_scaler )
1596 clip->rescale_proxy(orig_scale, new_scale);
1600 void EDL::add_proxy(int use_scaler,
1601 ArrayList<Indexable*> *orig_assets, ArrayList<Indexable*> *proxy_assets)
1604 for( int i=0,n=proxy_assets->size(); i<n; ++i ) {
1605 Asset *proxy_asset = (Asset *)proxy_assets->get(i);
1606 proxy_asset->width = orig_assets->get(i)->get_w();
1607 proxy_asset->height = orig_assets->get(i)->get_h();
1611 // change original assets to proxy assets
1612 for( int i=0,n=proxy_assets->size(); i<n; ++i ) {
1613 Asset *proxy_asset = assets->update((Asset *)proxy_assets->get(i));
1614 proxy_asset->folder_no = AW_PROXY_FOLDER;
1615 // replace track contents
1616 for( Track *track=tracks->first; track; track=track->next ) {
1617 if( track->data_type != TRACK_VIDEO ) continue;
1618 for( Edit *edit=track->edits->first; edit; edit=edit->next ) {
1619 if( !edit->asset ) continue;
1620 if( !strcmp(edit->asset->path, orig_assets->get(i)->path) ) {
1621 edit->asset = proxy_asset;
1628 Asset *EDL::get_proxy_asset()
1630 return folder_no == AW_PROXY_FOLDER ?
1631 tracks->first->edits->first->asset : 0;
1634 double EDL::get_cursor_position(int cursor_x, int pane_no)
1636 return (double)cursor_x * local_session->zoom_sample / session->sample_rate +
1637 (double)local_session->view_start[pane_no] *
1638 local_session->zoom_sample / session->sample_rate;
1641 int EDL::in_use(Indexable *indexable)
1643 for( Track *track=tracks->first; track; track=track->next ) {
1644 for( Edit *edit=track->edits->first; edit; edit=edit->next ) {
1645 Indexable *idxbl = (Indexable *)edit->asset;
1646 if( !idxbl ) idxbl = (Indexable *)edit->nested_edl;
1647 if( !idxbl ) continue;
1648 if( idxbl->id == indexable->id ) return 1;
1649 if( !indexable->is_asset != !idxbl->is_asset ) continue;
1650 if( !strcmp(idxbl->path, indexable->path) ) return 1;
1653 for( int i=0; i<clips.size(); ++i )
1654 if( clips[i]->in_use(indexable) ) return 1;
1655 for( int i=0; i<nested_edls.size(); ++i )
1656 if( nested_edls[i]->in_use(indexable) ) return 1;