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 "bcsignals.h"
31 #include "bccmodels.h"
36 #include "edlsession.h"
39 #include "indexstate.h"
40 #include "interlacemodes.h"
42 #include "localsession.h"
43 #include "maskautos.h"
47 #include "playbackconfig.h"
48 #include "playabletracks.h"
50 #include "preferences.h"
51 #include "recordconfig.h"
52 #include "recordlabel.h"
53 #include "sharedlocation.h"
56 #include "transportque.inc"
57 #include "versioninfo.h"
64 EDL::EDL(EDL *parent_edl)
67 this->parent_edl = parent_edl;
71 folders.set_array_delete();
83 remove_vwindow_edls();
88 folders.remove_all_objects();
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 folders.remove_all_objects();
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("FOLDER") ) {
239 char folder[BCTEXTLEN];
240 strcpy(folder, file->read_text());
244 if( file->tag.title_is("MIXERS") ) {
245 if( (load_flags & LOAD_SESSION) )
248 result = file->skip_tag();
251 if( file->tag.title_is("ASSETS") ) {
252 if( load_flags & LOAD_ASSETS )
253 assets->load(file, load_flags);
255 result = file->skip_tag();
258 if( file->tag.title_is(labels->xml_tag) ) {
259 if( load_flags & LOAD_TIMEBAR )
260 labels->load(file, load_flags);
262 result = file->skip_tag();
265 if( file->tag.title_is("LOCALSESSION") ) {
266 if( (load_flags & LOAD_SESSION) ||
267 (load_flags & LOAD_TIMEBAR) )
268 local_session->load_xml(file, load_flags);
270 result = file->skip_tag();
273 if( file->tag.title_is("SESSION") ) {
274 if( (load_flags & LOAD_SESSION) &&
276 session->load_xml(file, 0, load_flags);
278 result = file->skip_tag();
281 if( file->tag.title_is("TRACK") ) {
282 tracks->load(file, track_offset, load_flags);
286 // Causes clip creation to fail because that involves an opening EDL tag.
287 if( file->tag.title_is("CLIP_EDL") && !parent_edl ) {
288 EDL *new_edl = new EDL(this);
289 new_edl->create_objects();
290 new_edl->read_xml(file, LOAD_ALL);
291 if( (load_flags & LOAD_ALL) == LOAD_ALL )
292 clips.add_clip(new_edl);
293 new_edl->remove_user();
296 if( file->tag.title_is("NESTED_EDL") ) {
297 EDL *nested_edl = new EDL;
298 nested_edl->create_objects();
299 nested_edl->read_xml(file, LOAD_ALL);
300 if( (load_flags & LOAD_ALL) == LOAD_ALL )
301 nested_edls.add_clip(nested_edl);
302 nested_edl->remove_user();
305 if( file->tag.title_is("VWINDOW_EDL") && !parent_edl ) {
306 EDL *new_edl = new EDL(this);
307 new_edl->create_objects();
308 new_edl->read_xml(file, LOAD_ALL);
311 if( (load_flags & LOAD_ALL) == LOAD_ALL ) {
312 // if( vwindow_edl && !vwindow_edl_shared )
313 // vwindow_edl->remove_user();
314 // vwindow_edl_shared = 0;
315 // vwindow_edl = new_edl;
317 append_vwindow_edl(new_edl, 0);
321 // Discard if not replacing EDL
323 new_edl->remove_user();
336 // Output path is the path of the output file if name truncation is desired.
337 // It is a "" if complete names should be used.
338 // Called recursively by copy for clips, thus the string can't be terminated.
339 // The string is not terminated in this call.
340 int EDL::save_xml(FileXML *file, const char *output_path)
342 copy(1, file, output_path, 0);
346 int EDL::copy_all(EDL *edl)
348 if( this == edl ) return 0;
355 tracks->copy_from(edl->tracks);
356 labels->copy_from(edl->labels);
360 void EDL::copy_clips(EDL *edl)
362 if( this == edl ) return;
364 remove_vwindow_edls();
366 // if( vwindow_edl && !vwindow_edl_shared )
367 // vwindow_edl->remove_user();
369 // vwindow_edl_shared = 0;
371 for( int i=0; i<edl->total_vwindow_edls(); ++i ) {
372 EDL *new_edl = new EDL(this);
373 new_edl->create_objects();
374 new_edl->copy_all(edl->get_vwindow_edl(i));
375 append_vwindow_edl(new_edl, 0);
379 for( int i=0; i<edl->clips.size(); ++i ) add_clip(edl->clips[i]);
382 void EDL::copy_nested(EDL *edl)
384 if( this == edl ) return;
385 nested_edls.copy_nested(edl->nested_edls);
388 void EDL::copy_assets(EDL *edl)
390 if( this == edl ) return;
393 assets->copy_from(edl->assets);
397 void EDL::copy_mixers(EDL *edl)
399 if( this == edl ) return;
400 mixers.copy_from(edl->mixers);
403 void EDL::copy_session(EDL *edl, int session_only)
405 if( this == edl ) return;
407 if( !session_only ) {
408 strcpy(this->path, edl->path);
409 //printf("EDL::copy_session %p %s\n", this, this->path);
411 folders.remove_all_objects();
412 for( int i=0; i<edl->folders.size(); ++i )
413 folders.append(cstrdup(edl->folders[i]));
417 session->copy(edl->session);
420 if( !session_only ) {
421 local_session->copy_from(edl->local_session);
425 int EDL::copy_assets(double start,
429 const char *output_path)
431 ArrayList<Asset*> asset_list;
434 file->tag.set_title("ASSETS");
436 file->append_newline();
438 // Copy everything for a save
440 for( Asset *asset=assets->first; asset; asset=asset->next ) {
441 asset_list.append(asset);
445 // Copy just the ones being used.
446 for( current = tracks->first; current; current = NEXT ) {
447 if( !current->record ) continue;
448 current->copy_assets(start, end, &asset_list);
452 // Paths relativised here
453 for( int i=0; i<asset_list.size(); ++i ) {
454 asset_list[i]->write(file, 0, output_path);
457 file->tag.set_title("/ASSETS");
459 file->append_newline();
460 file->append_newline();
465 int EDL::copy(double start, double end, int all,
466 FileXML *file, const char *output_path, int rewind_it)
468 file->tag.set_title("EDL");
469 file->tag.set_property("VERSION", CINELERRA_VERSION);
470 // Save path for restoration of the project title from a backup.
471 if( this->path[0] ) file->tag.set_property("PATH", path);
472 return copy(start, end, all,
473 "/EDL", file, output_path, rewind_it);
475 int EDL::copy(int all, FileXML *file, const char *output_path, int rewind_it)
477 return copy(0, tracks->total_length(), all, file, output_path, rewind_it);
480 int EDL::copy_clip(double start, double end, int all,
481 FileXML *file, const char *output_path, int rewind_it)
483 file->tag.set_title("CLIP_EDL");
484 return copy(start, end, all,
485 "/CLIP_EDL", file, output_path, rewind_it);
487 int EDL::copy_clip(int all, FileXML *file, const char *output_path, int rewind_it)
489 return copy_clip(0, tracks->total_length(), all, file, output_path, rewind_it);
492 int EDL::copy_nested_edl(double start, double end, int all,
493 FileXML *file, const char *output_path, int rewind_it)
495 file->tag.set_title("NESTED_EDL");
496 if( this->path[0] ) file->tag.set_property("PATH", path);
497 return copy(start, end, all,
498 "/NESTED_EDL", file, output_path, rewind_it);
500 int EDL::copy_nested_edl(int all, FileXML *file, const char *output_path, int rewind_it)
502 return copy_nested_edl(0, tracks->total_length(), all, file, output_path, rewind_it);
505 int EDL::copy_vwindow_edl(double start, double end, int all,
506 FileXML *file, const char *output_path, int rewind_it)
508 file->tag.set_title("VWINDOW_EDL");
509 return copy(start, end, all,
510 "/VWINDOW_EDL", file, output_path, rewind_it);
512 int EDL::copy_vwindow_edl(int all, FileXML *file, const char *output_path, int rewind_it)
514 return copy_vwindow_edl(0, tracks->total_length(), all, file, output_path, rewind_it);
518 int EDL::copy(double start, double end, int all,
519 const char *closer, FileXML *file,
520 const char *output_path, int rewind_it)
523 file->append_newline();
524 // Set clipboard samples only if copying to clipboard
526 file->tag.set_title("CLIPBOARD");
527 file->tag.set_property("LENGTH", end - start);
529 file->tag.set_title("/CLIPBOARD");
531 file->append_newline();
532 file->append_newline();
534 //printf("EDL::copy 1\n");
537 local_session->save_xml(file, start);
539 //printf("EDL::copy 1\n");
544 // Need to copy all this from child EDL if pasting is desired.
546 session->save_xml(file);
547 session->save_video_config(file);
548 session->save_audio_config(file);
551 for( int i=0; i<folders.size(); ++i ) {
552 file->tag.set_title("FOLDER");
554 file->append_text(folders[i]);
555 file->tag.set_title("/FOLDER");
557 file->append_newline();
561 copy_assets(start, end, file, all, output_path);
563 for( int i=0; i<nested_edls.size(); ++i )
564 nested_edls[i]->copy_nested_edl(0, tracks->total_length(), 1,
565 file, output_path, 0);
568 // Don't want this if using clipboard
570 for( int i=0; i<total_vwindow_edls(); ++i )
571 get_vwindow_edl(i)->copy_vwindow_edl(1, file, output_path, 0);
573 for( int i=0; i<clips.size(); ++i )
574 clips[i]->copy_clip(1, file, output_path, 0);
579 file->append_newline();
580 file->append_newline();
583 labels->copy(start, end, file);
584 tracks->copy(start, end, all, file, output_path);
587 file->tag.set_title(closer);
589 file->append_newline();
591 // For editing operations we want to rewind it for immediate pasting.
592 // For clips and saving to disk leave it alone.
594 file->terminate_string();
600 void EDL::copy_indexables(EDL *edl)
602 for( Track *track=edl->tracks->first; track; track=track->next ) {
603 for( Edit *edit=track->edits->first; edit; edit=edit->next ) {
605 assets->update(edit->asset);
606 if( edit->nested_edl )
607 nested_edls.get_nested(edit->nested_edl);
612 EDL *EDL::new_nested(EDL *edl, const char *path)
614 EDL *nested = new EDL; // no parent for nested edl
615 nested->create_objects();
616 nested->copy_session(edl);
617 nested->set_path(path);
618 nested->update_index(edl);
619 nested->copy_indexables(edl);
620 nested->tracks->copy_from(edl->tracks);
621 nested_edls.append(nested);
625 EDL *EDL::create_nested_clip(EDL *nested)
627 EDL *new_edl = new EDL(this); // parent for clip edl
628 new_edl->create_objects();
629 new_edl->create_nested(nested);
633 void EDL::create_nested(EDL *nested)
635 // Keep frame rate, sample rate, and output size unchanged.
636 // Nest all video & audio outputs
637 session->video_tracks = 1;
638 session->audio_tracks = nested->session->audio_channels;
639 create_default_tracks();
640 insert_asset(0, nested, 0, 0, 0);
645 int min_w = session->output_w, min_h = session->output_h;
646 for( Track *track=tracks->first; track!=0; track=track->next ) {
647 if( track->data_type != TRACK_VIDEO ) continue;
648 int w = min_w, h = min_h;
649 for( Edit *current=track->edits->first; current!=0; current=NEXT ) {
650 Indexable* indexable = current->get_source();
651 if( !indexable ) continue;
652 int edit_w = indexable->get_w(), edit_h = indexable->get_h();
653 if( w < edit_w ) w = edit_w;
654 if( h < edit_h ) h = edit_h;
656 if( track->track_w == w && track->track_h == h ) continue;
657 ((MaskAutos*)track->automation->autos[AUTOMATION_MASK])->
658 translate_masks( (w - track->track_w) / 2, (h - track->track_h) / 2);
659 track->track_w = w; track->track_h = h;
663 void EDL::rechannel()
665 for( Track *current=tracks->first; current; current=NEXT ) {
666 if( current->data_type == TRACK_AUDIO ) {
667 PanAutos *autos = (PanAutos*)current->automation->autos[AUTOMATION_PAN];
668 ((PanAuto*)autos->default_auto)->rechannel();
669 for( PanAuto *keyframe = (PanAuto*)autos->first;
670 keyframe; keyframe = (PanAuto*)keyframe->next ) {
671 keyframe->rechannel();
677 void EDL::resample(double old_rate, double new_rate, int data_type)
679 for( Track *current=tracks->first; current; current=NEXT ) {
680 if( current->data_type == data_type ) {
681 current->resample(old_rate, new_rate);
687 void EDL::synchronize_params(EDL *edl)
689 local_session->synchronize_params(edl->local_session);
690 for( Track *this_track=tracks->first, *that_track=edl->tracks->first;
691 this_track && that_track;
692 this_track=this_track->next, that_track=that_track->next ) {
693 this_track->synchronize_params(that_track);
697 int EDL::trim_selection(double start,
711 tracks->total_length(),
720 int EDL::equivalent(double position1, double position2)
722 double threshold = session->cursor_on_frames ?
723 0.5 / session->frame_rate : 1.0 / session->sample_rate;
724 return fabs(position2 - position1) < threshold ? 1 : 0;
727 double EDL::equivalent_output(EDL *edl)
730 session->equivalent_output(edl->session, &result);
731 tracks->equivalent_output(edl->tracks, &result);
736 void EDL::set_path(const char *path)
738 strcpy(this->path, path);
741 void EDL::set_inpoint(double position)
743 if( equivalent(local_session->get_inpoint(), position) &&
744 local_session->get_inpoint() >= 0 ) {
745 local_session->unset_inpoint();
748 local_session->set_inpoint(align_to_frame(position, 0));
749 if( local_session->get_outpoint() <= local_session->get_inpoint() )
750 local_session->unset_outpoint();
754 void EDL::set_outpoint(double position)
756 if( equivalent(local_session->get_outpoint(), position) &&
757 local_session->get_outpoint() >= 0 ) {
758 local_session->unset_outpoint();
761 local_session->set_outpoint(align_to_frame(position, 0));
762 if( local_session->get_inpoint() >= local_session->get_outpoint() )
763 local_session->unset_inpoint();
767 void EDL::unset_inoutpoint()
769 local_session->unset_inpoint();
770 local_session->unset_outpoint();
773 int EDL::blade(double position)
775 return tracks->blade(position);
778 int EDL::clear(double start, double end,
779 int clear_labels, int clear_plugins, int edit_autos)
783 tracks->clear_handle(start,
789 if( clear_labels && distance > 0 )
790 labels->paste_silence(start,
804 // Need to put at beginning so a subsequent paste operation starts at the
806 double position = local_session->get_selectionstart();
807 local_session->set_selectionend(position);
808 local_session->set_selectionstart(position);
812 void EDL::modify_edithandles(double oldposition,
820 tracks->modify_edithandles(oldposition,
827 labels->modify_handles(oldposition,
834 void EDL::modify_pluginhandles(double oldposition,
842 tracks->modify_pluginhandles(oldposition,
852 void EDL::paste_silence(double start,
859 labels->paste_silence(start, end);
860 tracks->paste_silence(start,
867 void EDL::remove_from_project(ArrayList<EDL*> *clips)
869 for( int i=0; i<clips->size(); ++i ) {
870 this->clips.remove_clip(clips->get(i));
874 void EDL::remove_from_project(ArrayList<Indexable*> *assets)
878 for( int j=0; j<clips.size(); ++j ) {
879 clips[j]->remove_from_project(assets);
882 // Remove from VWindow EDLs
883 for( int i=0; i<total_vwindow_edls(); ++i )
884 get_vwindow_edl(i)->remove_from_project(assets);
886 for( int i=0; i<assets->size(); ++i ) {
887 // Remove from tracks
888 for( Track *track=tracks->first; track; track=track->next ) {
889 track->remove_asset(assets->get(i));
892 // Remove from assets
893 if( !parent_edl && assets->get(i)->is_asset ) {
894 this->assets->remove_asset((Asset*)assets->get(i));
897 if( !parent_edl && !assets->get(i)->is_asset ) {
898 this->nested_edls.remove_clip((EDL*)assets->get(i));
903 void EDL::update_assets(EDL *src)
905 for( Asset *current=src->assets->first; current; current=NEXT ) {
906 assets->update(current);
910 int EDL::get_tracks_height(Theme *theme)
912 int total_pixels = 0;
913 for( Track *current=tracks->first; current; current=NEXT ) {
914 total_pixels += current->vertical_span(theme);
919 int64_t EDL::get_tracks_width()
921 int64_t total_pixels = 0;
922 for( Track *current=tracks->first; current; current=NEXT ) {
923 int64_t pixels = current->horizontal_span();
924 if( pixels > total_pixels ) total_pixels = pixels;
926 //printf("EDL::get_tracks_width %d\n", total_pixels);
930 // int EDL::calculate_output_w(int single_channel)
932 // if( single_channel ) return session->output_w;
935 // for( int i=0; i<session->video_channels; ++i )
937 // if( session->vchannel_x[i] + session->output_w > widest ) widest = session->vchannel_x[i] + session->output_w;
942 // int EDL::calculate_output_h(int single_channel)
944 // if( single_channel ) return session->output_h;
947 // for( int i=0; i<session->video_channels; ++i )
949 // if( session->vchannel_y[i] + session->output_h > tallest ) tallest = session->vchannel_y[i] + session->output_h;
954 // Get the total output size scaled to aspect ratio
955 void EDL::calculate_conformed_dimensions(int single_channel, float &w, float &h)
957 if( (float)session->output_w / session->output_h > get_aspect_ratio() )
958 h = (w = session->output_w) / get_aspect_ratio();
960 w = (h = session->output_h) * get_aspect_ratio();
963 float EDL::get_aspect_ratio()
965 return session->aspect_w / session->aspect_h;
968 int EDL::dump(FILE *fp)
971 fprintf(fp,"CLIP\n");
974 fprintf(fp," clip_title: %s\n"
975 " parent_edl: %p\n", local_session->clip_title, parent_edl);
976 fprintf(fp," selectionstart %f\n selectionend %f\n loop_start %f\n loop_end %f\n",
977 local_session->get_selectionstart(1),
978 local_session->get_selectionend(1),
979 local_session->loop_start,
980 local_session->loop_end);
981 for( int i=0; i<TOTAL_PANES; ++i ) {
982 fprintf(fp," pane %d view_start=%jd track_start=%d\n", i,
983 local_session->view_start[i],
984 local_session->track_start[i]);
988 fprintf(fp,"audio_channels: %d audio_tracks: %d sample_rate: %jd\n",
989 session->audio_channels,
990 session->audio_tracks,
991 session->sample_rate);
992 fprintf(fp," video_channels: %d\n"
993 " video_tracks: %d\n"
994 " frame_rate: %.2f\n"
995 " frames_per_foot: %.2f\n"
1000 " color_model: %d\n",
1001 session->video_channels,
1002 session->video_tracks,
1003 session->frame_rate,
1004 session->frames_per_foot,
1009 session->color_model);
1011 fprintf(fp," CLIPS");
1012 fprintf(fp," total: %d\n", clips.size());
1013 for( int i=0; i<clips.size(); ++i ) {
1018 fprintf(fp," NESTED_EDLS");
1019 fprintf(fp," total: %d\n", nested_edls.size());
1020 for( int i=0; i<nested_edls.size(); ++i )
1021 fprintf(fp," %s\n", nested_edls[i]->path);
1023 fprintf(fp," VWINDOW EDLS");
1024 fprintf(fp," total: %d\n", total_vwindow_edls());
1026 for( int i=0; i<total_vwindow_edls(); ++i ) {
1027 fprintf(fp," %s\n", get_vwindow_edl(i)->local_session->clip_title);
1030 fprintf(fp," ASSETS\n");
1033 fprintf(fp," LABELS\n");
1035 fprintf(fp," TRACKS\n");
1037 //printf("EDL::dump 2\n");
1041 EDL* EDL::add_clip(EDL *edl)
1043 // Copy argument. New edls are deleted from MWindow::load_filenames.
1044 EDL *new_edl = new EDL(this);
1045 new_edl->create_objects();
1046 new_edl->copy_all(edl);
1047 clips.append(new_edl);
1051 void EDL::insert_asset(Asset *asset,
1055 RecordLabels *labels)
1057 // Insert asset into asset table
1058 Asset *new_asset = 0;
1059 EDL *new_nested_edl = 0;
1061 if( asset ) new_asset = assets->update(asset);
1062 if( nested_edl ) new_nested_edl = nested_edls.get_nested(nested_edl);
1066 Track *current = first_track ? first_track : tracks->first;
1069 // Fix length of single frame
1074 if( new_nested_edl ) {
1075 length = new_nested_edl->tracks->total_length();
1077 channels = new_nested_edl->session->audio_channels;
1081 // Insert 1 frame for undefined length
1082 if( new_asset->video_length < 0 ) {
1083 length = session->si_useduration ?
1084 session->si_duration :
1085 1.0 / session->frame_rate;
1088 length = new_asset->frame_rate > 0 ?
1089 (double)new_asset->video_length / new_asset->frame_rate :
1090 1.0 / session->frame_rate;
1092 layers = new_asset->layers;
1093 channels = new_asset->channels;
1096 for( ; current && vtrack<layers; current=NEXT ) {
1097 if( !current->record || current->data_type != TRACK_VIDEO ) continue;
1098 current->insert_asset(new_asset, new_nested_edl,
1099 length, position, vtrack++);
1104 if( new_asset->audio_length < 0 ) {
1105 // Insert 1 frame for undefined length & video
1106 if( new_asset->video_data )
1107 length = (double)1.0 / new_asset->frame_rate;
1109 // Insert 1 second for undefined length & no video
1113 length = (double)new_asset->audio_length /
1114 new_asset->sample_rate;
1117 current = tracks->first;
1118 for( ; current && atrack < channels; current=NEXT ) {
1119 if( !current->record || current->data_type != TRACK_AUDIO ) continue;
1120 current->insert_asset(new_asset, new_nested_edl,
1121 length, position, atrack++);
1124 // Insert labels from a recording window.
1126 for( RecordLabel *label=labels->first; label; label=label->next ) {
1127 this->labels->toggle_label(label->position, label->position);
1134 void EDL::set_index_file(Indexable *indexable)
1136 if( indexable->is_asset )
1137 assets->update_index((Asset*)indexable);
1139 nested_edls.update_index((EDL*)indexable);
1142 void EDL::optimize()
1144 //printf("EDL::optimize 1\n");
1145 if( local_session->preview_start < 0 ) local_session->preview_start = 0;
1146 double length = tracks->total_length();
1147 if( local_session->preview_end > length ) local_session->preview_end = length;
1148 if( local_session->preview_start >= local_session->preview_end ) {
1149 local_session->preview_start = 0;
1150 local_session->preview_end = length;
1152 for( Track *current=tracks->first; current; current=NEXT )
1153 current->optimize();
1158 static Mutex id_lock;
1159 id_lock.lock("EDL::next_id");
1160 int result = EDLSession::current_id++;
1165 void EDL::get_shared_plugins(Track *source,
1166 ArrayList<SharedLocation*> *plugin_locations,
1167 int omit_recordable,
1170 for( Track *track=tracks->first; track; track=track->next ) {
1171 if( track->record && omit_recordable ) continue;
1172 if( track == source || track->data_type != data_type ) continue;
1173 for( int i=0; i<track->plugin_set.size(); ++i ) {
1174 Plugin *plugin = track->get_current_plugin(
1175 local_session->get_selectionstart(1),
1176 i, PLAY_FORWARD, 1, 0);
1177 if( plugin && plugin->plugin_type != PLUGIN_STANDALONE ) continue;
1178 plugin_locations->append(new SharedLocation(tracks->number_of(track), i));
1183 void EDL::get_shared_tracks(Track *track,
1184 ArrayList<SharedLocation*> *module_locations,
1185 int omit_recordable, int data_type)
1187 for( Track *current=tracks->first; current; current=NEXT ) {
1188 if( omit_recordable && current->record ) continue;
1189 if( current == track || current->data_type != data_type ) continue;
1190 module_locations->append(new SharedLocation(tracks->number_of(current), 0));
1194 // aligned frame time
1195 double EDL::frame_align(double position, int round)
1197 double frame_pos = position * session->frame_rate;
1198 frame_pos = (int64_t)(frame_pos + (round ? 0.5 : 1e-6));
1199 position = frame_pos / session->frame_rate;
1203 // Convert position to frames if alignment is enabled.
1204 double EDL::align_to_frame(double position, int round)
1206 if( session->cursor_on_frames )
1207 position = frame_align(position, round);
1212 void EDL::new_folder(const char *folder)
1214 for( int i=0; i<folders.size(); ++i )
1215 if( !strcasecmp(folders[i], folder) ) return;
1216 folders.append(cstrdup(folder));
1219 void EDL::delete_folder(const char *folder)
1221 int i = folders.size();
1222 while( --i >= 0 && strcasecmp(folders[i], folder) );
1223 if( i >= 0 ) folders.remove_number(i);
1226 int EDL::get_use_vconsole(VEdit* *playable_edit,
1227 int64_t position, int direction, PlayableTracks *playable_tracks)
1229 int share_playable_tracks = 1;
1231 VTrack *playable_track = 0;
1232 const int debug = 0;
1235 // Calculate playable tracks when being called as a nested EDL
1236 if( !playable_tracks ) {
1237 share_playable_tracks = 0;
1238 playable_tracks = new PlayableTracks(this,
1239 position, direction, TRACK_VIDEO, 1);
1243 // Total number of playable tracks is 1
1244 if( playable_tracks->size() != 1 ) {
1248 playable_track = (VTrack*)playable_tracks->get(0);
1251 // Don't need playable tracks anymore
1252 if( !share_playable_tracks ) {
1253 delete playable_tracks;
1256 if( debug ) printf("EDL::get_use_vconsole %d playable_tracks->size()=%d\n",
1257 __LINE__, playable_tracks->size());
1258 if( result ) return 1;
1261 // Test mutual conditions between direct copy rendering and this.
1262 if( !playable_track->direct_copy_possible(position,
1266 if( debug ) printf("EDL::get_use_vconsole %d\n", __LINE__);
1268 *playable_edit = (VEdit*)playable_track->edits->editof(position,
1270 // No edit at current location
1271 if( !*playable_edit ) return 1;
1272 if( debug ) printf("EDL::get_use_vconsole %d\n", __LINE__);
1275 // Edit is nested EDL
1276 if( (*playable_edit)->nested_edl ) {
1278 EDL *nested_edl = (*playable_edit)->nested_edl;
1279 int64_t nested_position = (int64_t)((position -
1280 (*playable_edit)->startproject +
1281 (*playable_edit)->startsource) *
1282 nested_edl->session->frame_rate /
1283 session->frame_rate);
1286 VEdit *playable_edit_temp = 0;
1287 if( session->output_w != nested_edl->session->output_w ||
1288 session->output_h != nested_edl->session->output_h ||
1289 nested_edl->get_use_vconsole(&playable_edit_temp,
1298 if( debug ) printf("EDL::get_use_vconsole %d\n", __LINE__);
1299 // Edit is not a nested EDL
1300 Asset *asset = (*playable_edit)->asset;
1302 if( !asset ) return 1;
1303 if( debug ) printf("EDL::get_use_vconsole %d\n", __LINE__);
1305 // Asset and output device must have the same dimensions
1306 if( asset->width != session->output_w ||
1307 asset->height != session->output_h )
1311 if( debug ) printf("EDL::get_use_vconsole %d\n", __LINE__);
1312 // Asset and output device must have same resulting de-interlacing method
1313 if( ilaceautofixmethod2(session->interlace_mode,
1314 asset->interlace_autofixoption, asset->interlace_mode,
1315 asset->interlace_fixmethod) != ILACE_FIXMETHOD_NONE )
1318 // If we get here the frame is going to be directly copied. Whether it is
1319 // decompressed in hardware depends on the colormodel.
1325 int EDL::get_audio_channels()
1327 return session->audio_channels;
1330 int EDL::get_sample_rate()
1332 return session->sample_rate;
1335 int64_t EDL::get_audio_samples()
1337 return (int64_t)(tracks->total_length() *
1338 session->sample_rate);
1341 int EDL::have_audio()
1346 int EDL::have_video()
1354 return session->output_w;
1359 return session->output_h;
1362 double EDL::get_frame_rate()
1364 return session->frame_rate;
1367 int EDL::get_video_layers()
1372 int64_t EDL::get_video_frames()
1374 return (int64_t)(tracks->total_length() *
1375 session->frame_rate);
1379 void EDL::remove_vwindow_edls()
1381 for( int i=0; i<total_vwindow_edls(); ++i ) {
1382 get_vwindow_edl(i)->remove_user();
1384 vwindow_edls.remove_all();
1387 void EDL::remove_vwindow_edl(EDL *edl)
1389 if( vwindow_edls.number_of(edl) >= 0 ) {
1391 vwindow_edls.remove(edl);
1396 EDL* EDL::get_vwindow_edl(int number)
1398 return vwindow_edls.get(number);
1401 int EDL::total_vwindow_edls()
1403 return vwindow_edls.size();
1406 void EDL::append_vwindow_edl(EDL *edl, int increase_counter)
1408 if(vwindow_edls.number_of(edl) >= 0) return;
1410 if(increase_counter) edl->add_user();
1411 vwindow_edls.append(edl);
1415 double EDL::next_edit(double position)
1417 Units::fix_double(&position);
1418 double new_position = tracks->total_length();
1420 double max_rate = get_frame_rate();
1421 int sample_rate = get_sample_rate();
1422 if( sample_rate > max_rate ) max_rate = sample_rate;
1423 double min_movement = max_rate > 0 ? 1. / max_rate : 1e-6;
1425 // Test for edit handles after position
1426 for( Track *track=tracks->first; track; track=track->next ) {
1427 if( !track->record ) continue;
1428 for( Edit *edit=track->edits->first; edit; edit=edit->next ) {
1429 double edit_end = track->from_units(edit->startproject + edit->length);
1430 Units::fix_double(&edit_end);
1431 if( fabs(edit_end-position) < min_movement ) continue;
1432 if( edit_end > position && edit_end < new_position )
1433 new_position = edit_end;
1436 return new_position;
1439 double EDL::prev_edit(double position)
1441 Units::fix_double(&position);
1442 double new_position = -1;
1444 double max_rate = get_frame_rate();
1445 int sample_rate = get_sample_rate();
1446 if( sample_rate > max_rate ) max_rate = sample_rate;
1447 double min_movement = max_rate > 0 ? 1. / max_rate : 1e-6;
1449 // Test for edit handles before cursor position
1450 for( Track *track=tracks->first; track; track=track->next ) {
1451 if( !track->record ) continue;
1452 for( Edit *edit=track->edits->first; edit; edit=edit->next ) {
1453 double edit_end = track->from_units(edit->startproject);
1454 Units::fix_double(&edit_end);
1455 if( fabs(edit_end-position) < min_movement ) continue;
1456 if( edit_end < position && edit_end > new_position )
1457 new_position = edit_end;
1460 return new_position;