r860: Merge 2.1:
[cinelerra_cv.git] / cinelerra / edl.C
blobd0a968996b18c210dabc5614143fe84d082133bc
1 #include "asset.h"
2 #include "assets.h"
3 #include "atrack.h"
4 #include "autoconf.h"
5 #include "automation.h"
6 #include "awindowgui.inc"
7 #include "bcsignals.h"
8 #include "clip.h"
9 #include "colormodels.h"
10 #include "bchash.h"
11 #include "edl.h"
12 #include "edlsession.h"
13 #include "filexml.h"
14 #include "guicast.h"
15 #include "labels.h"
16 #include "localsession.h"
17 #include "mutex.h"
18 #include "panauto.h"
19 #include "panautos.h"
20 #include "playbackconfig.h"
21 #include "plugin.h"
22 #include "preferences.h"
23 #include "recordconfig.h"
24 #include "recordlabel.h"
25 #include "sharedlocation.h"
26 #include "theme.h"
27 #include "tracks.h"
28 #include "transportque.inc"
29 #include "vtrack.h"
34 Mutex* EDL::id_lock = 0;
38 EDL::EDL(EDL *parent_edl)
40         this->parent_edl = parent_edl;
41         tracks = 0;
42         labels = 0;
43         local_session = 0;
44         vwindow_edl = 0;
45         vwindow_edl_shared = 0;
48         folders.set_array_delete();
50         new_folder(CLIP_FOLDER);
52         new_folder(MEDIA_FOLDER);
54         id = next_id();
55         project_path[0] = 0;
59 EDL::~EDL()
62         if(tracks)
63         {
64                 delete tracks;
65         }
66         if(labels)
67         {
68                 delete labels;
69         }
71         if(local_session)
72         {
73                 delete local_session;
74         }
76         if(vwindow_edl && !vwindow_edl_shared)
77                 delete vwindow_edl;
79         if(!parent_edl)
80         {
81                 delete assets;
82                 delete session;
83         }
86         folders.remove_all_objects();
87         clips.remove_all_objects();
91 int EDL::create_objects()
93         tracks = new Tracks(this);
94         if(!parent_edl)
95         {
96                 assets = new Assets(this);
97                 session = new EDLSession(this);
98         }
99         else
100         {
101                 assets = parent_edl->assets;
102                 session = parent_edl->session;
103         }
104         
105         local_session = new LocalSession(this);
106         labels = new Labels(this, "LABELS");
107 //      last_playback_position = 0;
108         return 0;
111 EDL& EDL::operator=(EDL &edl)
113 printf("EDL::operator= 1\n");
114         copy_all(&edl);
115         return *this;
118 int EDL::load_defaults(BC_Hash *defaults)
120         if(!parent_edl)
121                 session->load_defaults(defaults);
123         local_session->load_defaults(defaults);
124         return 0;
127 int EDL::save_defaults(BC_Hash *defaults)
129         if(!parent_edl)
130                 session->save_defaults(defaults);
131         
132         local_session->save_defaults(defaults);
133         return 0;
136 void EDL::boundaries()
138         session->boundaries();
139         local_session->boundaries();
142 int EDL::create_default_tracks()
145         for(int i = 0; i < session->video_tracks; i++)
146         {
147                 tracks->add_video_track(0, 0);
148         }
149         for(int i = 0; i < session->audio_tracks; i++)
150         {
151                 tracks->add_audio_track(0, 0);
152         }
153         return 0;
156 int EDL::load_xml(ArrayList<PluginServer*> *plugindb,
157         FileXML *file, 
158         uint32_t load_flags)
160         int result = 0;
161 // Track numbering offset for replacing undo data.
162         int track_offset = 0;
165         folders.remove_all_objects();
167 // Search for start of master EDL.
169 // The parent_edl test caused clip creation to fail since those XML files
170 // contained an EDL tag.
172 // The parent_edl test is required to make EDL loading work because
173 // when loading an EDL the EDL tag is already read by the parent.
175         if(!parent_edl)
176         {
177                 do{
178                   result = file->read_tag();
179                 }while(!result && 
180                         !file->tag.title_is("XML") && 
181                         !file->tag.title_is("EDL"));
182         }
184         if(!result)
185         {
186 // Get path for backups
187                 project_path[0] = 0;
188                 file->tag.get_property("PROJECT_PATH", project_path);
190 // Erase everything
191                 if((load_flags & LOAD_ALL) == LOAD_ALL ||
192                         (load_flags & LOAD_EDITS) == LOAD_EDITS)
193                 {
194                         while(tracks->last) delete tracks->last;
195                 }
197                 if((load_flags & LOAD_ALL) == LOAD_ALL)
198                 {
199                         clips.remove_all_objects();
200                 }
202                 if(load_flags & LOAD_TIMEBAR)
203                 {
204                         while(labels->last) delete labels->last;
205                         local_session->unset_inpoint();
206                         local_session->unset_outpoint();
207                 }
209                 do{
210                         result = file->read_tag();
212                         if(!result)
213                         {
214                                 if(file->tag.title_is("/XML") ||
215                                         file->tag.title_is("/EDL") ||
216                                         file->tag.title_is("/CLIP_EDL") ||
217                                         file->tag.title_is("/VWINDOW_EDL"))
218                                 {
219                                         result = 1;
220                                 }
221                                 else
222                                 if(file->tag.title_is("CLIPBOARD"))
223                                 {
224                                         local_session->clipboard_length = file->tag.get_property("LENGTH", 0);
225                                 }
226                                 else
227                                 if(file->tag.title_is("VIDEO"))
228                                 {
229                                         if((load_flags & LOAD_VCONFIG) &&
230                                                 (load_flags & LOAD_SESSION))
231                                                 session->load_video_config(file, 0, load_flags);
232                                 }
233                                 else
234                                 if(file->tag.title_is("AUDIO"))
235                                 {
236                                         if((load_flags & LOAD_ACONFIG) &&
237                                                 (load_flags & LOAD_SESSION))
238                                                 session->load_audio_config(file, 0, load_flags);
239                                 }
240                                 else
241                                 if(file->tag.title_is("FOLDER"))
242                                 {
243                                         char folder[BCTEXTLEN];
244                                         strcpy(folder, file->read_text());
245                                         new_folder(folder);
246                                 }
247                                 else
248                                 if(file->tag.title_is("ASSETS"))
249                                 {
250                                         if(load_flags & LOAD_ASSETS)
251                                                 assets->load(plugindb, file, load_flags);
252                                 }
253                                 else
254                                 if(file->tag.title_is(labels->xml_tag))
255                                 {
256                                         if(load_flags & LOAD_TIMEBAR)
257                                                 labels->load(file, load_flags);
258                                 }
259                                 else
260                                 if(file->tag.title_is("LOCALSESSION"))
261                                 {
262                                         if((load_flags & LOAD_SESSION) ||
263                                                 (load_flags & LOAD_TIMEBAR))
264                                                 local_session->load_xml(file, load_flags);
265                                 }
266                                 else
267                                 if(file->tag.title_is("SESSION"))
268                                 {
269                                         if((load_flags & LOAD_SESSION) &&
270                                                 !parent_edl)
271                                                 session->load_xml(file, 0, load_flags);
272                                 }
273                                 else
274                                 if(file->tag.title_is("TRACK"))
275                                 {
276                                         tracks->load(file, track_offset, load_flags);
277                                 }
278                                 else
279 // Sub EDL.
280 // Causes clip creation to fail because that involves an opening EDL tag.
281                                 if(file->tag.title_is("CLIP_EDL") && !parent_edl)
282                                 {
283                                         EDL *new_edl = new EDL(this);
284                                         new_edl->create_objects();
285                                         new_edl->load_xml(plugindb, file, LOAD_ALL);
287                                         if((load_flags & LOAD_ALL) == LOAD_ALL)
288                                                 clips.append(new_edl);
289                                         else
290                                                 delete new_edl;
291                                 }
292                                 else
293                                 if(file->tag.title_is("VWINDOW_EDL") && !parent_edl)
294                                 {
295                                         EDL *new_edl = new EDL(this);
296                                         new_edl->create_objects();
297                                         new_edl->load_xml(plugindb, file, LOAD_ALL);
300                                         if((load_flags & LOAD_ALL) == LOAD_ALL)
301                                         {
302                                                 if(vwindow_edl && !vwindow_edl_shared) delete vwindow_edl;
303                                                 vwindow_edl = new_edl;
304                                                 vwindow_edl_shared = 0;
305                                         }
306                                         else
307                                         {
308                                                 delete new_edl;
309                                                 new_edl = 0;
310                                         }
311                                 }
312                         }
313                 }while(!result);
314         }
315         boundaries();
316 //dump();
318         return 0;
321 // Output path is the path of the output file if name truncation is desired.
322 // It is a "" if complete names should be used.
323 // Called recursively by copy for clips, thus the string can't be terminated.
324 // The string is not terminated in this call.
325 int EDL::save_xml(ArrayList<PluginServer*> *plugindb,
326         FileXML *file, 
327         char *output_path,
328         int is_clip,
329         int is_vwindow)
331         copy(0, 
332                 tracks->total_length(), 
333                 1, 
334                 is_clip,
335                 is_vwindow,
336                 file, 
337                 plugindb, 
338                 output_path,
339                 0);
340         return 0;
343 int EDL::copy_all(EDL *edl)
345         copy_session(edl);
346         copy_assets(edl);
347         copy_clips(edl);
348         tracks->copy_from(edl->tracks);
349         labels->copy_from(edl->labels);
350         return 0;
353 void EDL::copy_clips(EDL *edl)
355         if(vwindow_edl && !vwindow_edl_shared) delete vwindow_edl;
356         vwindow_edl = 0;
357         vwindow_edl_shared = 0;
358         if(edl->vwindow_edl)
359         {
360                 vwindow_edl = new EDL(this);
361                 vwindow_edl->create_objects();
362                 vwindow_edl->copy_all(edl->vwindow_edl);
363         }
364         clips.remove_all_objects();
365         for(int i = 0; i < edl->clips.total; i++)
366         {
367                 add_clip(edl->clips.values[i]);
368         }
371 void EDL::copy_assets(EDL *edl)
373         if(!parent_edl)
374         {
375                 assets->copy_from(edl->assets);
376         }
379 void EDL::copy_session(EDL *edl, int session_only)
381         if(!session_only)
383         strcpy(this->project_path, edl->project_path);
385         folders.remove_all_objects();
386         for(int i = 0; i < edl->folders.total; i++)
387         {
388                 char *new_folder;
389                 folders.append(new_folder = new char[strlen(edl->folders.values[i]) + 1]);
390                 strcpy(new_folder, edl->folders.values[i]);
391         }
392         }
394         if(!parent_edl)
395         {
396                 session->copy(edl->session);
397         }
398         
399         if(!session_only)
400         {
401         local_session->copy_from(edl->local_session);
402         }
405 int EDL::copy_assets(double start, 
406         double end, 
407         FileXML *file, 
408         int all, 
409         ArrayList<PluginServer*> *plugindb,
410         char *output_path)
412         ArrayList<Asset*> asset_list;
413         Track* current;
415         file->tag.set_title("ASSETS");
416         file->append_tag();
417         file->append_newline();
419 // Copy everything for a save
420         if(all)
421         {
422                 for(Asset *asset = assets->first;
423                         asset;
424                         asset = asset->next)
425                 {
426                         asset_list.append(asset);
427                 }
428         }
429         else
430 // Copy just the ones being used.
431         {
432                 for(current = tracks->first; 
433                         current; 
434                         current = NEXT)
435                 {
436                         if(current->record)
437                         {
438                                 current->copy_assets(start, 
439                                         end, 
440                                         &asset_list);
441                         }
442                 }
443         }
445 // Paths relativised here
446         for(int i = 0; i < asset_list.total; i++)
447         {
448                 asset_list.values[i]->write(file, 
449                         0, 
450                         output_path);
451         }
453         file->tag.set_title("/ASSETS");
454         file->append_tag();
455         file->append_newline();
456         file->append_newline();
457         return 0;
460 int EDL::copy(double start, 
461         double end, 
462         int all, 
463         int is_clip,
464         int is_vwindow,
465         FileXML *file, 
466         ArrayList<PluginServer*> *plugindb, 
467         char *output_path,
468         int rewind_it)
470 //printf("EDL::copy 1\n");
471 // begin file
472         if(is_clip)
473                 file->tag.set_title("CLIP_EDL");
474         else
475         if(is_vwindow)
476                 file->tag.set_title("VWINDOW_EDL");
477         else
478         {
479                 file->tag.set_title("EDL");
480                 file->tag.set_property("VERSION", CINELERRA_VERSION);
481 // Save path for restoration of the project title from a backup.
482                 if(this->project_path[0])
483                 {
484                         file->tag.set_property("PROJECT_PATH", project_path);
485                 }
486         }
488         file->append_tag();
489         file->append_newline();
491 // Set clipboard samples only if copying to clipboard
492         if(!all)
493         {
494                 file->tag.set_title("CLIPBOARD");
495                 file->tag.set_property("LENGTH", end - start);
496                 file->append_tag();
497                 file->tag.set_title("/CLIPBOARD");
498                 file->append_tag();
499                 file->append_newline();
500                 file->append_newline();
501         }
502 //printf("EDL::copy 1\n");
504 // Sessions
505         local_session->save_xml(file, start);
507 //printf("EDL::copy 1\n");
509 // Top level stuff.
510 //      if(!parent_edl)
511         {
512 // Need to copy all this from child EDL if pasting is desired.
513 // Session
514                 session->save_xml(file);
515                 session->save_video_config(file);
516                 session->save_audio_config(file);
518 // Folders
519                 for(int i = 0; i < folders.total; i++)
520                 {
521                         file->tag.set_title("FOLDER");
522                         file->append_tag();
523                         file->append_text(folders.values[i]);
524                         file->tag.set_title("/FOLDER");
525                         file->append_tag();
526                         file->append_newline();
527                 }
529 // Media
530 // Don't replicate all assets for every clip.
531 // The assets for the clips are probably in the mane EDL.
532                 if(!is_clip)
533                 copy_assets(start, 
534                         end, 
535                         file, 
536                         all, 
537                         plugindb,
538                         output_path);
540 // Clips
541 // Don't want this if using clipboard
542                 if(all)
543                 {
544                         if(vwindow_edl)
545                         {
546                                 
547                                 vwindow_edl->save_xml(plugindb, 
548                                         file, 
549                                         output_path,
550                                         0,
551                                         1);
552                         }
554                         for(int i = 0; i < clips.total; i++)
555                                 clips.values[i]->save_xml(plugindb, 
556                                         file, 
557                                         output_path,
558                                         1,
559                                         0);
560                 }
562                 file->append_newline();
563                 file->append_newline();
564         }
567 //printf("EDL::copy 1\n");
569         labels->copy(start, end, file);
570 //printf("EDL::copy 1\n");
571         tracks->copy(start, end, all, file, output_path);
572 //printf("EDL::copy 2\n");
574 // terminate file
575         if(is_clip)
576                 file->tag.set_title("/CLIP_EDL");
577         else
578         if(is_vwindow)
579                 file->tag.set_title("/VWINDOW_EDL");
580         else
581                 file->tag.set_title("/EDL");
582         file->append_tag();
583         file->append_newline();
586 // For editing operations we want to rewind it for immediate pasting.
587 // For clips and saving to disk leave it alone.
588         if(rewind_it)
589         {
590                 file->terminate_string();
591                 file->rewind();
592         }
593         return 0;
596 void EDL::rechannel()
598         for(Track *current = tracks->first; current; current = NEXT)
599         {
600                 if(current->data_type == TRACK_AUDIO)
601                 {
602                         PanAutos *autos = (PanAutos*)current->automation->autos[AUTOMATION_PAN];
603                         ((PanAuto*)autos->default_auto)->rechannel();
604                         for(PanAuto *keyframe = (PanAuto*)autos->first;
605                                 keyframe;
606                                 keyframe = (PanAuto*)keyframe->next)
607                         {
608                                 keyframe->rechannel();
609                         }
610                 }
611         }
614 void EDL::resample(double old_rate, double new_rate, int data_type)
616         for(Track *current = tracks->first; current; current = NEXT)
617         {
618                 if(current->data_type == data_type)
619                 {
620                         current->resample(old_rate, new_rate);
621                 }
622         }
626 void EDL::synchronize_params(EDL *edl)
628         local_session->synchronize_params(edl->local_session);
629         for(Track *this_track = tracks->first, *that_track = edl->tracks->first; 
630                 this_track && that_track; 
631                 this_track = this_track->next,
632                 that_track = that_track->next)
633         {
634                 this_track->synchronize_params(that_track);
635         }
638 int EDL::trim_selection(double start, 
639         double end,
640         int edit_labels,
641         int edit_plugins)
643         if(start != end)
644         {
645 // clear the data
646                 clear(0, 
647                         start,
648                         edit_labels,
649                         edit_plugins);
650                 clear(end - start, 
651                         tracks->total_length(),
652                         edit_labels,
653                         edit_plugins);
654         }
655         return 0;
659 int EDL::equivalent(double position1, double position2)
661         double threshold = (double).5 / session->frame_rate;
662         if(session->cursor_on_frames) 
663                 threshold = (double).5 / session->frame_rate;
664         else
665                 threshold = (double)1 / session->sample_rate;
667         if(fabs(position2 - position1) < threshold)
668         return 1;
669     else
670         return 0;
673 double EDL::equivalent_output(EDL *edl)
675         double result = -1;
676         session->equivalent_output(edl->session, &result);
677         tracks->equivalent_output(edl->tracks, &result);
678         return result;
682 void EDL::set_project_path(char *path)
684         strcpy(this->project_path, path);
687 void EDL::set_inpoint(double position)
689         if(equivalent(local_session->get_inpoint(), position) && 
690                 local_session->get_inpoint() >= 0)
691         {
692                 local_session->unset_inpoint();
693         }
694         else
695         {
696                 local_session->set_inpoint(align_to_frame(position, 0));
697                 if(local_session->get_outpoint() <= local_session->get_inpoint()) 
698                         local_session->unset_outpoint();
699         }
702 void EDL::set_outpoint(double position)
704         if(equivalent(local_session->get_outpoint(), position) && 
705                 local_session->get_outpoint() >= 0)
706         {
707                 local_session->unset_outpoint();
708         }
709         else
710         {
711                 local_session->set_outpoint(align_to_frame(position, 0));
712                 if(local_session->get_inpoint() >= local_session->get_outpoint()) 
713                         local_session->unset_inpoint();
714         }
718 int EDL::clear(double start, 
719         double end, 
720         int clear_labels,
721         int clear_plugins)
723         if(start == end)
724         {
725                 double distance = 0;
726                 tracks->clear_handle(start, 
727                         end,
728                         distance, 
729                         clear_labels,
730                         clear_plugins);
731                 if(clear_labels && distance > 0)
732                         labels->paste_silence(start, 
733                                 start + distance);
734         }
735         else
736         {
737                 tracks->clear(start, 
738                         end,
739                         clear_plugins);
740                 if(clear_labels) 
741                         labels->clear(start, 
742                                 end, 
743                                 1);
744         }
746 // Need to put at beginning so a subsequent paste operation starts at the
747 // right position.
748         double position = local_session->get_selectionstart();
749         local_session->set_selectionend(position);
750         local_session->set_selectionstart(position);
751         return 0;
754 void EDL::modify_edithandles(double oldposition, 
755         double newposition, 
756         int currentend,
757         int handle_mode,
758         int edit_labels,
759         int edit_plugins)
761         tracks->modify_edithandles(oldposition, 
762                 newposition, 
763                 currentend,
764                 handle_mode,
765                 edit_labels, 
766                 edit_plugins);
767         labels->modify_handles(oldposition, 
768                 newposition, 
769                 currentend,
770                 handle_mode,
771                 edit_labels);
774 void EDL::modify_pluginhandles(double oldposition, 
775         double newposition, 
776         int currentend, 
777         int handle_mode,
778         int edit_labels,
779         Edits *trim_edits)
781         tracks->modify_pluginhandles(oldposition, 
782                 newposition, 
783                 currentend, 
784                 handle_mode,
785                 edit_labels,
786                 trim_edits);
787         optimize();
790 void EDL::paste_silence(double start, 
791         double end, 
792         int edit_labels, 
793         int edit_plugins)
795         if(edit_labels) 
796                 labels->paste_silence(start, end);
797         tracks->paste_silence(start, 
798                 end, 
799                 edit_plugins);
803 void EDL::remove_from_project(ArrayList<EDL*> *clips)
805         for(int i = 0; i < clips->total; i++)
806         {
807                 for(int j = 0; j < this->clips.total; j++)
808                 {
809                         if(this->clips.values[j] == clips->values[i])
810                         {
811                                 this->clips.remove_object(clips->values[i]);
812                         }
813                 }
814         }
817 void EDL::remove_from_project(ArrayList<Asset*> *assets)
819 // Remove from clips
820         if(!parent_edl)
821                 for(int j = 0; j < clips.total; j++)
822                 {
823                         clips.values[j]->remove_from_project(assets);
824                 }
826 // Remove from VWindow
827         if(vwindow_edl)
828                 vwindow_edl->remove_from_project(assets);
830         for(int i = 0; i < assets->total; i++)
831         {
832 // Remove from tracks
833                 for(Track *track = tracks->first; track; track = track->next)
834                 {
835                         track->remove_asset(assets->values[i]);
836                 }
838 // Remove from assets
839                 if(!parent_edl)
840                 {
841                         this->assets->remove_asset(assets->values[i]);
842                 }
843         }
846 void EDL::update_assets(EDL *src)
848         for(Asset *current = src->assets->first;
849                 current;
850                 current = NEXT)
851         {
852                 assets->update(current);
853         }
856 int EDL::get_tracks_height(Theme *theme)
858         int total_pixels = 0;
859         for(Track *current = tracks->first;
860                 current;
861                 current = NEXT)
862         {
863                 total_pixels += current->vertical_span(theme);
864         }
865         return total_pixels;
868 int64_t EDL::get_tracks_width()
870         int64_t total_pixels = 0;
871         for(Track *current = tracks->first;
872                 current;
873                 current = NEXT)
874         {
875                 int64_t pixels = current->horizontal_span();
876                 if(pixels > total_pixels) total_pixels = pixels;
877         }
878 //printf("EDL::get_tracks_width %d\n", total_pixels);
879         return total_pixels;
882 // int EDL::calculate_output_w(int single_channel)
883 // {
884 //      if(single_channel) return session->output_w;
885 // 
886 //      int widest = 0;
887 //      for(int i = 0; i < session->video_channels; i++)
888 //      {
889 //              if(session->vchannel_x[i] + session->output_w > widest) widest = session->vchannel_x[i] + session->output_w;
890 //      }
891 //      return widest;
892 // }
893 // 
894 // int EDL::calculate_output_h(int single_channel)
895 // {
896 //      if(single_channel) return session->output_h;
897 // 
898 //      int tallest = 0;
899 //      for(int i = 0; i < session->video_channels; i++)
900 //      {
901 //              if(session->vchannel_y[i] + session->output_h > tallest) tallest = session->vchannel_y[i] + session->output_h;
902 //      }
903 //      return tallest;
904 // }
906 // Get the total output size scaled to aspect ratio
907 void EDL::calculate_conformed_dimensions(int single_channel, float &w, float &h)
909         w = session->output_w;
910         h = session->output_h;
912         if((float)session->output_w / session->output_h > get_aspect_ratio())
913         {
914                 h = (float)h * 
915                         (session->output_w / get_aspect_ratio() / session->output_h);
916         }
917         else
918         {
919                 w = (float)w * 
920                         (h * get_aspect_ratio() / session->output_w);
921         }
924 float EDL::get_aspect_ratio()
926         return session->aspect_w / session->aspect_h;
929 int EDL::dump()
931         if(parent_edl)
932                 printf("CLIP\n");
933         else
934                 printf("EDL\n");
935         printf("clip_title: %s parent_edl: %p\n", local_session->clip_title, parent_edl);
936         printf("selectionstart %f selectionend %f loop_start %f loop_end %f\n", 
937                 local_session->get_selectionstart(1), 
938                 local_session->get_selectionend(1),
939                 local_session->loop_start,
940                 local_session->loop_end);
942         if(!parent_edl)
943         {
944                 printf("audio_channels: %d "
945                         "audio_tracks: %d \n"
946                         "sample_rate: %d\n",
947                         session->audio_channels,
948                         session->audio_tracks,
949                         session->sample_rate);
950                 printf("video_channels: %d "
951                         "video_tracks: %d "
952                         "frame_rate: %.2f "
953                         "frames_per_foot: %.2f\n"
954                 "output_w: %d "
955                 "output_h: %d "
956                 "aspect_w: %f "
957                 "aspect_h %f "
958                         "color_model %d\n",
959                                 session->video_channels,
960                                 session->video_tracks,
961                                 session->frame_rate,
962                                 session->frames_per_foot,
963                         session->output_w,
964                         session->output_h,
965                         session->aspect_w,
966                         session->aspect_h,
967                                 session->color_model);
969                 printf(" EDLS\n");
970                 printf("  total: %d\n", clips.total);
971         
972                 for(int i = 0; i < clips.total; i++)
973                 {
974                         printf("\n\n");
975                         clips.values[i]->dump();
976                         printf("\n\n");
977                 }
979                 printf(" ASSETS\n");
980                 assets->dump();
981         }
982         printf(" LABELS\n");
983         labels->dump();
984         printf(" TRACKS\n");
985         tracks->dump();
986 //printf("EDL::dump 2\n");
987         return 0;
990 EDL* EDL::add_clip(EDL *edl)
992 // Copy argument.  New edls are deleted from MWindow::load_filenames.
993         EDL *new_edl = new EDL(this);
994         new_edl->create_objects();
995         new_edl->copy_all(edl);
996         clips.append(new_edl);
997         return new_edl;
1000 void EDL::insert_asset(Asset *asset, 
1001         double position, 
1002         Track *first_track, 
1003         RecordLabels *labels)
1005 // Insert asset into asset table
1006         Asset *new_asset = assets->update(asset);
1009 // Paste video
1010         int vtrack = 0;
1011         Track *current = first_track ? first_track : tracks->first;
1014 // Fix length of single frame
1015         double length;
1018         if(new_asset->video_length < 0) 
1019         {
1020         if(session->si_useduration)
1021                 length = session->si_duration;
1022         else    
1023                 length = 1.0 / session->frame_rate; 
1024         }
1025         else
1026         if(new_asset->frame_rate > 0)
1027                 length = ((double)new_asset->video_length / new_asset->frame_rate);
1028         else
1029                 length = 1.0 / session->frame_rate;
1031         for( ;
1032                 current && vtrack < new_asset->layers;
1033                 current = NEXT)
1034         {
1035                 if(!current->record || 
1036                         current->data_type != TRACK_VIDEO)
1037                         continue;
1039                 current->insert_asset(new_asset, 
1040                         length, 
1041                         position, 
1042                         vtrack);
1044                 vtrack++;
1045         }
1047         int atrack = 0;
1048         for(current = tracks->first;
1049                 current && atrack < new_asset->channels;
1050                 current = NEXT)
1051         {
1052                 if(!current->record ||
1053                         current->data_type != TRACK_AUDIO)
1054                         continue;
1056                 current->insert_asset(new_asset, 
1057                         (double)new_asset->audio_length / 
1058                                 new_asset->sample_rate, 
1059                         position, 
1060                         atrack);
1063                 atrack++;
1064         }
1066         if(labels)
1067         {
1068                 for(RecordLabel *label = labels->first; label; label = label->next)
1069                 {
1070                         this->labels->toggle_label(label->position, label->position);
1071                 }
1072         }
1077 void EDL::set_index_file(Asset *asset)
1079         assets->update_index(asset);
1082 void EDL::optimize()
1084 //printf("EDL::optimize 1\n");
1085         double length = tracks->total_length();
1086         if(local_session->preview_end > length) local_session->preview_end = length;
1087         if(local_session->preview_start > length ||
1088                 local_session->preview_start < 0) local_session->preview_start = 0;
1089         for(Track *current = tracks->first; current; current = NEXT)
1090                 current->optimize();
1093 int EDL::next_id()
1095         id_lock->lock("EDL::next_id");
1096         int result = EDLSession::current_id++;
1097         id_lock->unlock();
1098         return result;
1101 void EDL::get_shared_plugins(Track *source, 
1102         ArrayList<SharedLocation*> *plugin_locations)
1104         for(Track *track = tracks->first; track; track = track->next)
1105         {
1106                 if(track != source && 
1107                         track->data_type == source->data_type)
1108                 {
1109                         for(int i = 0; i < track->plugin_set.total; i++)
1110                         {
1111                                 Plugin *plugin = track->get_current_plugin(
1112                                         local_session->get_selectionstart(1), 
1113                                         i, 
1114                                         PLAY_FORWARD, 
1115                                         1,
1116                                         0);
1117                                 if(plugin && plugin->plugin_type == PLUGIN_STANDALONE)
1118                                 {
1119                                         plugin_locations->append(new SharedLocation(tracks->number_of(track), i));
1120                                 }
1121                         }
1122                 }
1123         }
1126 void EDL::get_shared_tracks(Track *track, ArrayList<SharedLocation*> *module_locations)
1128         for(Track *current = tracks->first; current; current = NEXT)
1129         {
1130                 if(current != track && 
1131                         current->data_type == track->data_type)
1132                 {
1133                         module_locations->append(new SharedLocation(tracks->number_of(current), 0));
1134                 }
1135         }
1138 // Convert position to frames if cursor alignment is enabled
1139 double EDL::align_to_frame(double position, int round)
1141 //printf("EDL::align_to_frame 1 %f\n", position);
1142         if(session->cursor_on_frames)
1143         {
1144 // Seconds -> Frames
1145                 double temp = (double)position * session->frame_rate;
1146 //printf("EDL::align_to_frame 2 %f\n", temp);
1148 // Assert some things
1149                 if(session->sample_rate == 0)
1150                         printf("EDL::align_to_frame: sample_rate == 0\n");
1152                 if(session->frame_rate == 0)
1153                         printf("EDL::align_to_frame: frame_rate == 0\n");
1155 // Round frames
1156 // Always round down negative numbers
1157 // but round up only if requested
1158                 if(round) 
1159                 {
1160                         temp = Units::round(temp);
1161                 }
1162                 else
1163                 {
1164 //                      if(temp < 0)
1165 //                      {
1166 //                              temp -= 0.5;
1167 //                      }
1168 //                      else
1169                                 temp = Units::to_int64(temp);
1170                 }
1171 //printf("EDL::align_to_frame 3 %f\n", temp);
1173 // Frames -> Seconds
1174                 temp /= session->frame_rate;
1176 //printf("EDL::align_to_frame 5 %f\n", temp);
1178                 return temp;
1179         }
1180 //printf("EDL::align_to_frame 3 %d\n", position);
1183         return position;
1187 void EDL::new_folder(char *folder)
1189         for(int i = 0; i < folders.total; i++)
1190         {
1191                 if(!strcasecmp(folders.values[i], folder)) return;
1192         }
1194         char *new_folder;
1195         folders.append(new_folder = new char[strlen(folder) + 1]);
1196         strcpy(new_folder, folder);
1199 void EDL::delete_folder(char *folder)
1201         int i;
1202         for(i = 0; i < folders.total; i++)
1203         {
1204                 if(!strcasecmp(folders.values[i], folder))
1205                 {
1206                         break;
1207                 }
1208         }
1210         if(i < folders.total) delete folders.values[i];
1212         for( ; i < folders.total - 1; i++)
1213         {
1214                 folders.values[i] = folders.values[i + 1];
1215         }