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.inc"
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;
73 folders.set_array_delete();
85 remove_vwindow_edls();
90 folders.remove_all_objects();
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 folders.remove_all_objects();
153 if( (load_flags & LOAD_ALL) == LOAD_ALL ) {
154 remove_vwindow_edls();
158 // Search for start of master EDL.
160 // The parent_edl test caused clip creation to fail since those XML files
161 // contained an EDL tag.
163 // The parent_edl test is required to make EDL loading work because
164 // when loading an EDL the EDL tag is already read by the parent.
168 result = file->read_tag();
170 !file->tag.title_is("XML") &&
171 !file->tag.title_is("EDL"));
173 return result ? result : read_xml(file, load_flags);
176 int EDL::read_xml(FileXML *file, uint32_t load_flags)
179 // Track numbering offset for replacing undo data.
180 int track_offset = 0;
182 // Get path for backups
183 file->tag.get_property("path", path);
186 if( (load_flags & LOAD_ALL) == LOAD_ALL ||
187 (load_flags & LOAD_EDITS) == LOAD_EDITS ) {
188 while(tracks->last) delete tracks->last;
191 if( (load_flags & LOAD_ALL) == LOAD_ALL ) {
193 mixers.remove_all_objects();
196 if( load_flags & LOAD_TIMEBAR ) {
197 while(labels->last) delete labels->last;
198 local_session->unset_inpoint();
199 local_session->unset_outpoint();
202 // This was originally in LocalSession::load_xml
203 if( load_flags & LOAD_SESSION ) {
204 local_session->clipboard_length = 0;
208 result = file->read_tag();
211 if( file->tag.title_is("/XML") ||
212 file->tag.title_is("/EDL") ||
213 file->tag.title_is("/CLIP_EDL") ||
214 file->tag.title_is("/NESTED_EDL") ||
215 file->tag.title_is("/VWINDOW_EDL") ) {
219 if( file->tag.title_is("CLIPBOARD") ) {
220 local_session->clipboard_length =
221 file->tag.get_property("LENGTH", (double)0);
224 if( file->tag.title_is("VIDEO") ) {
225 if( (load_flags & LOAD_VCONFIG) &&
226 (load_flags & LOAD_SESSION) )
227 session->load_video_config(file, 0, load_flags);
229 result = file->skip_tag();
232 if( file->tag.title_is("AUDIO") ) {
233 if( (load_flags & LOAD_ACONFIG) &&
234 (load_flags & LOAD_SESSION) )
235 session->load_audio_config(file, 0, load_flags);
237 result = file->skip_tag();
240 if( file->tag.title_is("FOLDER") ) {
241 char folder[BCTEXTLEN];
242 strcpy(folder, file->read_text());
246 if( file->tag.title_is("MIXERS") ) {
247 if( (load_flags & LOAD_SESSION) )
250 result = file->skip_tag();
253 if( file->tag.title_is("ASSETS") ) {
254 if( load_flags & LOAD_ASSETS )
255 assets->load(file, load_flags);
257 result = file->skip_tag();
260 if( file->tag.title_is(labels->xml_tag) ) {
261 if( load_flags & LOAD_TIMEBAR )
262 labels->load(file, load_flags);
264 result = file->skip_tag();
267 if( file->tag.title_is("LOCALSESSION") ) {
268 if( (load_flags & LOAD_SESSION) ||
269 (load_flags & LOAD_TIMEBAR) )
270 local_session->load_xml(file, load_flags);
272 result = file->skip_tag();
275 if( file->tag.title_is("SESSION") ) {
276 if( (load_flags & LOAD_SESSION) &&
278 session->load_xml(file, 0, load_flags);
280 result = file->skip_tag();
283 if( file->tag.title_is("TRACK") ) {
284 tracks->load(file, track_offset, load_flags);
288 // Causes clip creation to fail because that involves an opening EDL tag.
289 if( file->tag.title_is("CLIP_EDL") && !parent_edl ) {
290 EDL *new_edl = new EDL(this);
291 new_edl->create_objects();
292 new_edl->read_xml(file, LOAD_ALL);
293 if( (load_flags & LOAD_ALL) == LOAD_ALL )
294 clips.add_clip(new_edl);
295 new_edl->remove_user();
298 if( file->tag.title_is("NESTED_EDL") ) {
299 EDL *nested_edl = new EDL;
300 nested_edl->create_objects();
301 nested_edl->read_xml(file, LOAD_ALL);
302 if( (load_flags & LOAD_ALL) == LOAD_ALL )
303 nested_edls.get_nested(nested_edl);
304 nested_edl->remove_user();
307 if( file->tag.title_is("VWINDOW_EDL") && !parent_edl ) {
308 EDL *new_edl = new EDL(this);
309 new_edl->create_objects();
310 new_edl->read_xml(file, LOAD_ALL);
313 if( (load_flags & LOAD_ALL) == LOAD_ALL ) {
314 // if( vwindow_edl && !vwindow_edl_shared )
315 // vwindow_edl->remove_user();
316 // vwindow_edl_shared = 0;
317 // vwindow_edl = new_edl;
319 append_vwindow_edl(new_edl, 0);
323 // Discard if not replacing EDL
325 new_edl->remove_user();
338 // Output path is the path of the output file if name truncation is desired.
339 // It is a "" if complete names should be used.
340 // Called recursively by copy for clips, thus the string can't be terminated.
341 // The string is not terminated in this call.
342 int EDL::save_xml(FileXML *file, const char *output_path)
344 copy(1, file, output_path, 0);
348 int EDL::copy_all(EDL *edl)
350 if( this == edl ) return 0;
357 tracks->copy_from(edl->tracks);
358 labels->copy_from(edl->labels);
362 void EDL::copy_clips(EDL *edl)
364 if( this == edl ) return;
366 remove_vwindow_edls();
368 // if( vwindow_edl && !vwindow_edl_shared )
369 // vwindow_edl->remove_user();
371 // vwindow_edl_shared = 0;
373 for( int i=0; i<edl->total_vwindow_edls(); ++i ) {
374 EDL *new_edl = new EDL(this);
375 new_edl->create_objects();
376 new_edl->copy_all(edl->get_vwindow_edl(i));
377 append_vwindow_edl(new_edl, 0);
381 for( int i=0; i<edl->clips.size(); ++i ) add_clip(edl->clips[i]);
384 void EDL::copy_nested(EDL *edl)
386 if( this == edl ) return;
387 nested_edls.copy_nested(edl->nested_edls);
390 void EDL::copy_assets(EDL *edl)
392 if( this == edl ) return;
395 assets->copy_from(edl->assets);
399 void EDL::copy_mixers(EDL *edl)
401 if( this == edl ) return;
402 mixers.copy_from(edl->mixers);
405 void EDL::copy_session(EDL *edl, int session_only)
407 if( this == edl ) return;
409 if( !session_only ) {
410 strcpy(this->path, edl->path);
411 //printf("EDL::copy_session %p %s\n", this, this->path);
413 folders.remove_all_objects();
414 for( int i=0; i<edl->folders.size(); ++i )
415 folders.append(cstrdup(edl->folders[i]));
419 session->copy(edl->session);
422 if( !session_only ) {
423 local_session->copy_from(edl->local_session);
427 int EDL::copy_assets(double start,
431 const char *output_path)
433 ArrayList<Asset*> asset_list;
436 file->tag.set_title("ASSETS");
438 file->append_newline();
440 // Copy everything for a save
442 for( Asset *asset=assets->first; asset; asset=asset->next ) {
443 asset_list.append(asset);
447 // Copy just the ones being used.
448 for( current = tracks->first; current; current = NEXT ) {
449 if( !current->record ) continue;
450 current->copy_assets(start, end, &asset_list);
454 // Paths relativised here
455 for( int i=0; i<asset_list.size(); ++i ) {
456 asset_list[i]->write(file, 0, output_path);
459 file->tag.set_title("/ASSETS");
461 file->append_newline();
462 file->append_newline();
467 int EDL::copy(double start, double end, int all,
468 FileXML *file, const char *output_path, int rewind_it)
470 file->tag.set_title("EDL");
471 file->tag.set_property("VERSION", CINELERRA_VERSION);
472 // Save path for restoration of the project title from a backup.
473 if( this->path[0] ) file->tag.set_property("PATH", path);
474 return copy(start, end, all,
475 "/EDL", file, output_path, rewind_it);
477 int EDL::copy(int all, FileXML *file, const char *output_path, int rewind_it)
479 return copy(0, tracks->total_length(), all, file, output_path, rewind_it);
482 int EDL::copy_clip(double start, double end, int all,
483 FileXML *file, const char *output_path, int rewind_it)
485 file->tag.set_title("CLIP_EDL");
486 return copy(start, end, all,
487 "/CLIP_EDL", file, output_path, rewind_it);
489 int EDL::copy_clip(int all, FileXML *file, const char *output_path, int rewind_it)
491 return copy_clip(0, tracks->total_length(), all, file, output_path, rewind_it);
494 int EDL::copy_nested_edl(double start, double end, int all,
495 FileXML *file, const char *output_path, int rewind_it)
497 file->tag.set_title("NESTED_EDL");
498 if( this->path[0] ) file->tag.set_property("PATH", path);
499 return copy(start, end, all,
500 "/NESTED_EDL", file, output_path, rewind_it);
502 int EDL::copy_nested_edl(int all, FileXML *file, const char *output_path, int rewind_it)
504 return copy_nested_edl(0, tracks->total_length(), all, file, output_path, rewind_it);
507 int EDL::copy_vwindow_edl(double start, double end, int all,
508 FileXML *file, const char *output_path, int rewind_it)
510 file->tag.set_title("VWINDOW_EDL");
511 return copy(start, end, all,
512 "/VWINDOW_EDL", file, output_path, rewind_it);
514 int EDL::copy_vwindow_edl(int all, FileXML *file, const char *output_path, int rewind_it)
516 return copy_vwindow_edl(0, tracks->total_length(), all, file, output_path, rewind_it);
520 int EDL::copy(double start, double end, int all,
521 const char *closer, FileXML *file,
522 const char *output_path, int rewind_it)
525 file->append_newline();
526 // Set clipboard samples only if copying to clipboard
528 file->tag.set_title("CLIPBOARD");
529 file->tag.set_property("LENGTH", end - start);
531 file->tag.set_title("/CLIPBOARD");
533 file->append_newline();
534 file->append_newline();
536 //printf("EDL::copy 1\n");
539 local_session->save_xml(file, start);
541 //printf("EDL::copy 1\n");
546 // Need to copy all this from child EDL if pasting is desired.
548 session->save_xml(file);
549 session->save_video_config(file);
550 session->save_audio_config(file);
553 for( int i=0; i<folders.size(); ++i ) {
554 file->tag.set_title("FOLDER");
556 file->append_text(folders[i]);
557 file->tag.set_title("/FOLDER");
559 file->append_newline();
563 copy_assets(start, end, file, all, output_path);
565 for( int i=0; i<nested_edls.size(); ++i )
566 nested_edls[i]->copy_nested_edl(0, tracks->total_length(), 1,
567 file, output_path, 0);
570 // Don't want this if using clipboard
572 for( int i=0; i<total_vwindow_edls(); ++i )
573 get_vwindow_edl(i)->copy_vwindow_edl(1, file, output_path, 0);
575 for( int i=0; i<clips.size(); ++i )
576 clips[i]->copy_clip(1, file, output_path, 0);
581 file->append_newline();
582 file->append_newline();
585 labels->copy(start, end, file);
586 tracks->copy(start, end, all, file, output_path);
589 file->tag.set_title(closer);
591 file->append_newline();
593 // For editing operations we want to rewind it for immediate pasting.
594 // For clips and saving to disk leave it alone.
596 file->terminate_string();
602 void EDL::copy_indexables(EDL *edl)
604 for( Track *track=edl->tracks->first; track; track=track->next ) {
605 for( Edit *edit=track->edits->first; edit; edit=edit->next ) {
607 assets->update(edit->asset);
608 if( edit->nested_edl )
609 nested_edls.get_nested(edit->nested_edl);
614 EDL *EDL::new_nested(EDL *edl, const char *path)
616 EDL *nested = new EDL; // no parent for nested edl
617 nested->create_objects();
618 nested->copy_session(edl);
619 nested->set_path(path);
620 nested->update_index(edl);
621 nested->copy_indexables(edl);
622 nested->tracks->copy_from(edl->tracks);
623 nested_edls.append(nested);
627 EDL *EDL::create_nested_clip(EDL *nested)
629 EDL *new_edl = new EDL(this); // parent for clip edl
630 new_edl->create_objects();
631 new_edl->create_nested(nested);
635 void EDL::create_nested(EDL *nested)
637 // Keep frame rate, sample rate, and output size unchanged.
638 // Nest all video & audio outputs
639 session->video_tracks = 1;
640 session->audio_tracks = nested->session->audio_channels;
641 create_default_tracks();
642 insert_asset(0, nested, 0, 0, 0);
647 int min_w = session->output_w, min_h = session->output_h;
648 for( Track *track=tracks->first; track!=0; track=track->next ) {
649 if( track->data_type != TRACK_VIDEO ) continue;
650 int w = min_w, h = min_h;
651 for( Edit *current=track->edits->first; current!=0; current=NEXT ) {
652 Indexable* indexable = current->get_source();
653 if( !indexable ) continue;
654 int edit_w = indexable->get_w(), edit_h = indexable->get_h();
655 if( w < edit_w ) w = edit_w;
656 if( h < edit_h ) h = edit_h;
658 if( track->track_w == w && track->track_h == h ) continue;
659 ((MaskAutos*)track->automation->autos[AUTOMATION_MASK])->
660 translate_masks( (w - track->track_w) / 2, (h - track->track_h) / 2);
661 track->track_w = w; track->track_h = h;
665 void EDL::rechannel()
667 for( Track *current=tracks->first; current; current=NEXT ) {
668 if( current->data_type == TRACK_AUDIO ) {
669 PanAutos *autos = (PanAutos*)current->automation->autos[AUTOMATION_PAN];
670 ((PanAuto*)autos->default_auto)->rechannel();
671 for( PanAuto *keyframe = (PanAuto*)autos->first;
672 keyframe; keyframe = (PanAuto*)keyframe->next ) {
673 keyframe->rechannel();
679 void EDL::resample(double old_rate, double new_rate, int data_type)
681 for( Track *current=tracks->first; current; current=NEXT ) {
682 if( current->data_type == data_type ) {
683 current->resample(old_rate, new_rate);
689 void EDL::synchronize_params(EDL *edl)
691 local_session->synchronize_params(edl->local_session);
692 for( Track *this_track=tracks->first, *that_track=edl->tracks->first;
693 this_track && that_track;
694 this_track=this_track->next, that_track=that_track->next ) {
695 this_track->synchronize_params(that_track);
699 int EDL::trim_selection(double start,
713 tracks->total_length(),
722 int EDL::equivalent(double position1, double position2)
724 double threshold = session->cursor_on_frames ?
725 0.5 / session->frame_rate : 1.0 / session->sample_rate;
726 return fabs(position2 - position1) < threshold ? 1 : 0;
729 double EDL::equivalent_output(EDL *edl)
732 session->equivalent_output(edl->session, &result);
733 tracks->equivalent_output(edl->tracks, &result);
738 void EDL::set_path(const char *path)
740 if( &this->path[0] == path ) return;
741 strcpy(this->path, path);
744 void EDL::set_inpoint(double position)
746 if( equivalent(local_session->get_inpoint(), position) &&
747 local_session->get_inpoint() >= 0 ) {
748 local_session->unset_inpoint();
751 local_session->set_inpoint(align_to_frame(position, 0));
752 if( local_session->get_outpoint() <= local_session->get_inpoint() )
753 local_session->unset_outpoint();
757 void EDL::set_outpoint(double position)
759 if( equivalent(local_session->get_outpoint(), position) &&
760 local_session->get_outpoint() >= 0 ) {
761 local_session->unset_outpoint();
764 local_session->set_outpoint(align_to_frame(position, 0));
765 if( local_session->get_inpoint() >= local_session->get_outpoint() )
766 local_session->unset_inpoint();
770 void EDL::unset_inoutpoint()
772 local_session->unset_inpoint();
773 local_session->unset_outpoint();
776 int EDL::blade(double position)
778 return tracks->blade(position);
781 int EDL::clear(double start, double end,
782 int clear_labels, int clear_plugins, int edit_autos)
786 tracks->clear_handle(start,
792 if( clear_labels && distance > 0 )
793 labels->paste_silence(start,
807 // Need to put at beginning so a subsequent paste operation starts at the
809 double position = local_session->get_selectionstart();
810 local_session->set_selectionend(position);
811 local_session->set_selectionstart(position);
815 void EDL::modify_edithandles(double oldposition,
823 tracks->modify_edithandles(oldposition,
830 labels->modify_handles(oldposition,
837 void EDL::modify_pluginhandles(double oldposition,
845 tracks->modify_pluginhandles(oldposition,
855 void EDL::paste_silence(double start,
862 labels->paste_silence(start, end);
863 tracks->paste_silence(start,
870 void EDL::remove_from_project(ArrayList<EDL*> *clips)
872 for( int i=0; i<clips->size(); ++i ) {
873 this->clips.remove_clip(clips->get(i));
877 void EDL::remove_from_project(ArrayList<Indexable*> *assets)
881 for( int j=0; j<clips.size(); ++j ) {
882 clips[j]->remove_from_project(assets);
885 // Remove from VWindow EDLs
886 for( int i=0; i<total_vwindow_edls(); ++i )
887 get_vwindow_edl(i)->remove_from_project(assets);
889 for( int i=0; i<assets->size(); ++i ) {
890 // Remove from tracks
891 for( Track *track=tracks->first; track; track=track->next ) {
892 track->remove_asset(assets->get(i));
895 // Remove from assets
896 if( !parent_edl && assets->get(i)->is_asset ) {
897 this->assets->remove_asset((Asset*)assets->get(i));
900 if( !parent_edl && !assets->get(i)->is_asset ) {
901 this->nested_edls.remove_clip((EDL*)assets->get(i));
906 void EDL::update_assets(EDL *src)
908 for( Asset *current=src->assets->first; current; current=NEXT ) {
909 assets->update(current);
913 int EDL::get_tracks_height(Theme *theme)
915 int total_pixels = 0;
916 for( Track *current=tracks->first; current; current=NEXT ) {
917 total_pixels += current->vertical_span(theme);
922 int64_t EDL::get_tracks_width()
924 int64_t total_pixels = 0;
925 for( Track *current=tracks->first; current; current=NEXT ) {
926 int64_t pixels = current->horizontal_span();
927 if( pixels > total_pixels ) total_pixels = pixels;
929 //printf("EDL::get_tracks_width %d\n", total_pixels);
933 // int EDL::calculate_output_w(int single_channel)
935 // if( single_channel ) return session->output_w;
938 // for( int i=0; i<session->video_channels; ++i )
940 // if( session->vchannel_x[i] + session->output_w > widest ) widest = session->vchannel_x[i] + session->output_w;
945 // int EDL::calculate_output_h(int single_channel)
947 // if( single_channel ) return session->output_h;
950 // for( int i=0; i<session->video_channels; ++i )
952 // if( session->vchannel_y[i] + session->output_h > tallest ) tallest = session->vchannel_y[i] + session->output_h;
957 // Get the total output size scaled to aspect ratio
958 void EDL::calculate_conformed_dimensions(int single_channel, float &w, float &h)
960 if( (float)session->output_w / session->output_h > get_aspect_ratio() )
961 h = (w = session->output_w) / get_aspect_ratio();
963 w = (h = session->output_h) * get_aspect_ratio();
966 float EDL::get_aspect_ratio()
968 return session->aspect_w / session->aspect_h;
971 int EDL::dump(FILE *fp)
974 fprintf(fp,"CLIP\n");
977 fprintf(fp," clip_title: %s\n"
978 " parent_edl: %p\n", local_session->clip_title, parent_edl);
979 fprintf(fp," selectionstart %f\n selectionend %f\n loop_start %f\n loop_end %f\n",
980 local_session->get_selectionstart(1),
981 local_session->get_selectionend(1),
982 local_session->loop_start,
983 local_session->loop_end);
984 for( int i=0; i<TOTAL_PANES; ++i ) {
985 fprintf(fp," pane %d view_start=%jd track_start=%d\n", i,
986 local_session->view_start[i],
987 local_session->track_start[i]);
991 fprintf(fp,"audio_channels: %d audio_tracks: %d sample_rate: %jd\n",
992 session->audio_channels,
993 session->audio_tracks,
994 session->sample_rate);
995 fprintf(fp," video_channels: %d\n"
996 " video_tracks: %d\n"
997 " frame_rate: %.2f\n"
998 " frames_per_foot: %.2f\n"
1003 " color_model: %d\n",
1004 session->video_channels,
1005 session->video_tracks,
1006 session->frame_rate,
1007 session->frames_per_foot,
1012 session->color_model);
1014 fprintf(fp," CLIPS");
1015 fprintf(fp," total: %d\n", clips.size());
1016 for( int i=0; i<clips.size(); ++i ) {
1021 fprintf(fp," NESTED_EDLS");
1022 fprintf(fp," total: %d\n", nested_edls.size());
1023 for( int i=0; i<nested_edls.size(); ++i )
1024 fprintf(fp," %s\n", nested_edls[i]->path);
1026 fprintf(fp," VWINDOW EDLS");
1027 fprintf(fp," total: %d\n", total_vwindow_edls());
1029 for( int i=0; i<total_vwindow_edls(); ++i ) {
1030 fprintf(fp," %s\n", get_vwindow_edl(i)->local_session->clip_title);
1033 fprintf(fp," ASSETS\n");
1036 fprintf(fp," LABELS\n");
1038 fprintf(fp," TRACKS\n");
1040 //printf("EDL::dump 2\n");
1044 EDL* EDL::add_clip(EDL *edl)
1046 // Copy argument. New edls are deleted from MWindow::load_filenames.
1047 EDL *new_edl = new EDL(this);
1048 new_edl->create_objects();
1049 new_edl->copy_all(edl);
1050 clips.append(new_edl);
1054 void EDL::insert_asset(Asset *asset,
1058 RecordLabels *labels)
1060 // Insert asset into asset table
1061 Asset *new_asset = 0;
1062 EDL *new_nested_edl = 0;
1064 if( asset ) new_asset = assets->update(asset);
1065 if( nested_edl ) new_nested_edl = nested_edls.get_nested(nested_edl);
1069 Track *current = first_track ? first_track : tracks->first;
1072 // Fix length of single frame
1077 if( new_nested_edl ) {
1078 length = new_nested_edl->tracks->total_length();
1080 channels = new_nested_edl->session->audio_channels;
1084 // Insert 1 frame for undefined length
1085 if( new_asset->video_length < 0 ) {
1086 length = session->si_useduration ?
1087 session->si_duration :
1088 1.0 / session->frame_rate;
1091 length = new_asset->frame_rate > 0 ?
1092 (double)new_asset->video_length / new_asset->frame_rate :
1093 1.0 / session->frame_rate;
1095 layers = new_asset->layers;
1096 channels = new_asset->channels;
1099 for( ; current && vtrack<layers; current=NEXT ) {
1100 if( !current->record || current->data_type != TRACK_VIDEO ) continue;
1101 current->insert_asset(new_asset, new_nested_edl,
1102 length, position, vtrack++);
1107 if( new_asset->audio_length < 0 ) {
1108 // Insert 1 frame for undefined length & video
1109 if( new_asset->video_data )
1110 length = (double)1.0 / new_asset->frame_rate;
1112 // Insert 1 second for undefined length & no video
1116 length = (double)new_asset->audio_length /
1117 new_asset->sample_rate;
1120 current = tracks->first;
1121 for( ; current && atrack < channels; current=NEXT ) {
1122 if( !current->record || current->data_type != TRACK_AUDIO ) continue;
1123 current->insert_asset(new_asset, new_nested_edl,
1124 length, position, atrack++);
1127 // Insert labels from a recording window.
1129 for( RecordLabel *label=labels->first; label; label=label->next ) {
1130 this->labels->toggle_label(label->position, label->position);
1137 void EDL::set_index_file(Indexable *indexable)
1139 if( indexable->is_asset )
1140 assets->update_index((Asset*)indexable);
1142 nested_edls.update_index((EDL*)indexable);
1145 void EDL::optimize()
1147 //printf("EDL::optimize 1\n");
1148 if( local_session->preview_start < 0 ) local_session->preview_start = 0;
1149 double length = tracks->total_length();
1150 if( local_session->preview_end > length ) local_session->preview_end = length;
1151 if( local_session->preview_start >= local_session->preview_end ) {
1152 local_session->preview_start = 0;
1153 local_session->preview_end = length;
1155 for( Track *current=tracks->first; current; current=NEXT )
1156 current->optimize();
1161 static Mutex id_lock;
1162 id_lock.lock("EDL::next_id");
1163 int result = EDLSession::current_id++;
1168 void EDL::get_shared_plugins(Track *source,
1169 ArrayList<SharedLocation*> *plugin_locations,
1170 int omit_recordable,
1173 for( Track *track=tracks->first; track; track=track->next ) {
1174 if( track->record && omit_recordable ) continue;
1175 if( track == source || track->data_type != data_type ) continue;
1176 for( int i=0; i<track->plugin_set.size(); ++i ) {
1177 Plugin *plugin = track->get_current_plugin(
1178 local_session->get_selectionstart(1),
1179 i, PLAY_FORWARD, 1, 0);
1180 if( plugin && plugin->plugin_type != PLUGIN_STANDALONE ) continue;
1181 plugin_locations->append(new SharedLocation(tracks->number_of(track), i));
1186 void EDL::get_shared_tracks(Track *track,
1187 ArrayList<SharedLocation*> *module_locations,
1188 int omit_recordable, int data_type)
1190 for( Track *current=tracks->first; current; current=NEXT ) {
1191 if( omit_recordable && current->record ) continue;
1192 if( current == track || current->data_type != data_type ) continue;
1193 module_locations->append(new SharedLocation(tracks->number_of(current), 0));
1197 // aligned frame time
1198 double EDL::frame_align(double position, int round)
1200 double frame_pos = position * session->frame_rate;
1201 frame_pos = (int64_t)(frame_pos + (round ? 0.5 : 1e-6));
1202 position = frame_pos / session->frame_rate;
1206 // Convert position to frames if alignment is enabled.
1207 double EDL::align_to_frame(double position, int round)
1209 if( session->cursor_on_frames )
1210 position = frame_align(position, round);
1215 void EDL::new_folder(const char *folder)
1217 for( int i=0; i<folders.size(); ++i )
1218 if( !strcasecmp(folders[i], folder) ) return;
1219 folders.append(cstrdup(folder));
1222 void EDL::delete_folder(const char *folder)
1224 int i = folders.size();
1225 while( --i >= 0 && strcasecmp(folders[i], folder) );
1226 if( i >= 0 ) folders.remove_number(i);
1229 int EDL::get_use_vconsole(VEdit* *playable_edit,
1230 int64_t position, int direction, PlayableTracks *playable_tracks)
1232 int share_playable_tracks = 1;
1234 VTrack *playable_track = 0;
1235 const int debug = 0;
1238 // Calculate playable tracks when being called as a nested EDL
1239 if( !playable_tracks ) {
1240 share_playable_tracks = 0;
1241 playable_tracks = new PlayableTracks(this,
1242 position, direction, TRACK_VIDEO, 1);
1246 // Total number of playable tracks is 1
1247 if( playable_tracks->size() != 1 ) {
1251 playable_track = (VTrack*)playable_tracks->get(0);
1254 // Don't need playable tracks anymore
1255 if( !share_playable_tracks ) {
1256 delete playable_tracks;
1259 if( debug ) printf("EDL::get_use_vconsole %d playable_tracks->size()=%d\n",
1260 __LINE__, playable_tracks->size());
1261 if( result ) return 1;
1264 // Test mutual conditions between direct copy rendering and this.
1265 if( !playable_track->direct_copy_possible(position,
1269 if( debug ) printf("EDL::get_use_vconsole %d\n", __LINE__);
1271 *playable_edit = (VEdit*)playable_track->edits->editof(position,
1273 // No edit at current location
1274 if( !*playable_edit ) return 1;
1275 if( debug ) printf("EDL::get_use_vconsole %d\n", __LINE__);
1278 // Edit is nested EDL
1279 if( (*playable_edit)->nested_edl ) {
1281 EDL *nested_edl = (*playable_edit)->nested_edl;
1282 int64_t nested_position = (int64_t)((position -
1283 (*playable_edit)->startproject +
1284 (*playable_edit)->startsource) *
1285 nested_edl->session->frame_rate /
1286 session->frame_rate);
1289 VEdit *playable_edit_temp = 0;
1290 if( session->output_w != nested_edl->session->output_w ||
1291 session->output_h != nested_edl->session->output_h ||
1292 nested_edl->get_use_vconsole(&playable_edit_temp,
1301 if( debug ) printf("EDL::get_use_vconsole %d\n", __LINE__);
1302 // Edit is not a nested EDL
1303 Asset *asset = (*playable_edit)->asset;
1305 if( !asset ) return 1;
1306 if( debug ) printf("EDL::get_use_vconsole %d\n", __LINE__);
1308 // Asset and output device must have the same dimensions
1309 if( asset->width != session->output_w ||
1310 asset->height != session->output_h )
1314 if( debug ) printf("EDL::get_use_vconsole %d\n", __LINE__);
1315 // Asset and output device must have same resulting de-interlacing method
1316 if( ilaceautofixmethod2(session->interlace_mode,
1317 asset->interlace_autofixoption, asset->interlace_mode,
1318 asset->interlace_fixmethod) != ILACE_FIXMETHOD_NONE )
1321 // If we get here the frame is going to be directly copied. Whether it is
1322 // decompressed in hardware depends on the colormodel.
1328 int EDL::get_audio_channels()
1330 return session->audio_channels;
1333 int EDL::get_sample_rate()
1335 return session->sample_rate;
1338 int64_t EDL::get_audio_samples()
1340 return (int64_t)(tracks->total_length() *
1341 session->sample_rate);
1344 int EDL::have_audio()
1349 int EDL::have_video()
1357 return session->output_w;
1362 return session->output_h;
1365 double EDL::get_frame_rate()
1367 return session->frame_rate;
1370 int EDL::get_video_layers()
1375 int64_t EDL::get_video_frames()
1377 return (int64_t)(tracks->total_length() *
1378 session->frame_rate);
1382 void EDL::remove_vwindow_edls()
1384 for( int i=0; i<total_vwindow_edls(); ++i ) {
1385 get_vwindow_edl(i)->remove_user();
1387 vwindow_edls.remove_all();
1390 void EDL::remove_vwindow_edl(EDL *edl)
1392 if( vwindow_edls.number_of(edl) >= 0 ) {
1394 vwindow_edls.remove(edl);
1399 EDL* EDL::get_vwindow_edl(int number)
1401 return vwindow_edls.get(number);
1404 int EDL::total_vwindow_edls()
1406 return vwindow_edls.size();
1409 void EDL::append_vwindow_edl(EDL *edl, int increase_counter)
1411 if(vwindow_edls.number_of(edl) >= 0) return;
1413 if(increase_counter) edl->add_user();
1414 vwindow_edls.append(edl);
1418 double EDL::next_edit(double position)
1420 Units::fix_double(&position);
1421 double new_position = tracks->total_length();
1423 double max_rate = get_frame_rate();
1424 int sample_rate = get_sample_rate();
1425 if( sample_rate > max_rate ) max_rate = sample_rate;
1426 double min_movement = max_rate > 0 ? 1. / max_rate : 1e-6;
1428 // Test for edit handles after position
1429 for( Track *track=tracks->first; track; track=track->next ) {
1430 if( !track->record ) continue;
1431 for( Edit *edit=track->edits->first; edit; edit=edit->next ) {
1432 double edit_end = track->from_units(edit->startproject + edit->length);
1433 Units::fix_double(&edit_end);
1434 if( fabs(edit_end-position) < min_movement ) continue;
1435 if( edit_end > position && edit_end < new_position )
1436 new_position = edit_end;
1439 return new_position;
1442 double EDL::prev_edit(double position)
1444 Units::fix_double(&position);
1445 double new_position = -1;
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 before cursor 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);
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 void EDL::rescale_proxy(int orig_scale, int new_scale)
1468 if( orig_scale == new_scale ) return;
1470 float orig_w = (float)session->output_w * orig_scale;
1471 float orig_h = (float)session->output_h * orig_scale;
1473 session->output_w = Units::round(orig_w / new_scale);
1474 session->output_h = Units::round(orig_h / new_scale);
1478 for( Track *track=tracks->first; track; track=track->next ) {
1479 if( track->data_type != TRACK_VIDEO ) continue;
1480 orig_w = (float)track->track_w * orig_scale;
1481 orig_h = (float)track->track_h * orig_scale;
1482 track->track_w = Units::round(orig_w / new_scale);
1483 track->track_h = Units::round(orig_h / new_scale);
1484 ((MaskAutos*)track->automation->autos[AUTOMATION_MASK])->
1485 set_proxy(orig_scale, new_scale);
1486 ((FloatAutos*)track->automation->autos[AUTOMATION_CAMERA_X])->
1487 set_proxy(orig_scale, new_scale);
1488 ((FloatAutos*)track->automation->autos[AUTOMATION_CAMERA_Y])->
1489 set_proxy(orig_scale, new_scale);
1490 ((FloatAutos*)track->automation->autos[AUTOMATION_PROJECTOR_X])->
1491 set_proxy(orig_scale, new_scale);
1492 ((FloatAutos*)track->automation->autos[AUTOMATION_PROJECTOR_Y])->
1493 set_proxy(orig_scale, new_scale);
1497 void EDL::set_proxy(int new_scale, int use_scaler,
1498 ArrayList<Indexable*> *orig_assets, ArrayList<Indexable*> *proxy_assets)
1500 int orig_scale = session->proxy_scale;
1501 int orig_use_scaler = session->proxy_use_scaler;
1503 // rescale to full size asset in read_frame
1504 session->proxy_scale = new_scale;
1505 session->proxy_use_scaler = use_scaler;
1508 for( int i=0; i<proxy_assets->size(); ++i ) {
1509 Asset *proxy_asset = (Asset *)proxy_assets->get(i);
1510 proxy_asset->width = orig_assets->get(i)->get_w();
1511 proxy_asset->height = orig_assets->get(i)->get_h();
1516 if( !orig_use_scaler )
1517 rescale_proxy(orig_scale, new_scale);
1519 // change original assets to proxy assets
1520 int awindow_folder = use_scaler || new_scale != 1 ? AW_PROXY_FOLDER : AW_MEDIA_FOLDER;
1521 for( int i=0,n=proxy_assets->size(); i<n; ++i ) {
1522 const char *orig_path = orig_assets->get(i)->path;
1523 Indexable *proxy_idxbl = proxy_assets->get(i);
1524 proxy_idxbl->awindow_folder = awindow_folder;
1525 Asset *proxy_asset = proxy_idxbl->is_asset ? assets->update((Asset *)proxy_idxbl) : 0;
1526 EDL *proxy_edl = !proxy_idxbl->is_asset ? (EDL *)proxy_idxbl : 0;
1527 // replace track contents
1528 for( Track *track=tracks->first; track; track=track->next ) {
1529 if( track->data_type != TRACK_VIDEO ) continue;
1530 for( Edit *edit=track->edits->first; edit; edit=edit->next ) {
1531 Indexable *idxbl = (Indexable *)edit->asset;
1532 if( !idxbl ) idxbl = (Indexable *)edit->nested_edl;
1533 if( !idxbl ) continue;
1534 if( strcmp(idxbl->path, orig_path) ) continue;
1535 edit->asset = proxy_asset;
1536 edit->nested_edl = proxy_edl;
1539 for( int j=0,m=clips.size(); j<m; ++j ) {
1540 EDL *clip = clips[j];
1542 for( Track *track=clip->tracks->first; track; track=track->next ) {
1543 if( track->data_type != TRACK_VIDEO ) continue;
1544 for( Edit *edit=track->edits->first; edit; edit=edit->next ) {
1545 Indexable *idxbl = (Indexable *)edit->asset;
1546 if( !idxbl ) idxbl = (Indexable *)edit->nested_edl;
1547 if( !idxbl ) continue;
1548 if( strcmp(idxbl->path, orig_path) ) continue;
1549 edit->asset = proxy_asset;
1550 edit->nested_edl = proxy_edl;
1554 if( has_proxy && !orig_use_scaler )
1555 clip->rescale_proxy(orig_scale, new_scale);
1560 void EDL::add_proxy(int use_scaler,
1561 ArrayList<Indexable*> *orig_assets, ArrayList<Indexable*> *proxy_assets)
1564 for( int i=0,n=proxy_assets->size(); i<n; ++i ) {
1565 Asset *proxy_asset = (Asset *)proxy_assets->get(i);
1566 proxy_asset->width = orig_assets->get(i)->get_w();
1567 proxy_asset->height = orig_assets->get(i)->get_h();
1571 // change original assets to proxy assets
1572 for( int i=0,n=proxy_assets->size(); i<n; ++i ) {
1573 Asset *proxy_asset = assets->update((Asset *)proxy_assets->get(i));
1574 proxy_asset->awindow_folder = AW_PROXY_FOLDER;
1575 // replace track contents
1576 for( Track *track=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 if( !edit->asset ) continue;
1580 if( !strcmp(edit->asset->path, orig_assets->get(i)->path) ) {
1581 edit->asset = proxy_asset;
1588 double EDL::get_cursor_position(int cursor_x, int pane_no)
1590 return (double)cursor_x * local_session->zoom_sample / session->sample_rate +
1591 (double)local_session->view_start[pane_no] *
1592 local_session->zoom_sample / session->sample_rate;