Merge CV, ver=5.1; ops/methods from HV, and interface from CV where possible
[goodguy/history.git] / cinelerra-5.1 / cinelerra / edl.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 1997-2012 Adam Williams <broadcast at earthling dot net>
5  *
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.
10  *
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.
15  *
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
19  *
20  */
21
22 #include "asset.h"
23 #include "assets.h"
24 #include "atrack.h"
25 #include "autoconf.h"
26 #include "automation.h"
27 #include "awindowgui.inc"
28 #include "bcsignals.h"
29 #include "clip.h"
30 #include "bccmodels.h"
31 #include "bchash.h"
32 #include "edits.h"
33 #include "edl.h"
34 #include "edlsession.h"
35 #include "filexml.h"
36 #include "guicast.h"
37 #include "indexstate.h"
38 #include "labels.h"
39 #include "localsession.h"
40 #include "mutex.h"
41 #include "nestededls.h"
42 #include "panauto.h"
43 #include "panautos.h"
44 #include "playbackconfig.h"
45 #include "playabletracks.h"
46 #include "plugin.h"
47 #include "preferences.h"
48 #include "recordconfig.h"
49 #include "recordlabel.h"
50 #include "sharedlocation.h"
51 #include "theme.h"
52 #include "tracks.h"
53 #include "transportque.inc"
54 #include "versioninfo.h"
55 #include "vedit.h"
56 #include "vtrack.h"
57
58
59
60
61 Mutex* EDL::id_lock = 0;
62
63
64
65 EDL::EDL(EDL *parent_edl)
66  : Indexable(0)
67 {
68         this->parent_edl = parent_edl;
69         tracks = 0;
70         labels = 0;
71         local_session = 0;
72 //      vwindow_edl = 0;
73 //      vwindow_edl_shared = 0;
74
75         folders.set_array_delete();
76
77         new_folder(CLIP_FOLDER);
78
79         new_folder(MEDIA_FOLDER);
80
81         id = next_id();
82         path[0] = 0;
83 }
84
85
86 EDL::~EDL()
87 {
88
89         if(tracks)
90         {
91                 delete tracks;
92         }
93         if(labels)
94         {
95                 delete labels;
96         }
97
98         if(local_session)
99         {
100                 delete local_session;
101         }
102
103
104         remove_vwindow_edls();
105
106 //      if(vwindow_edl && !vwindow_edl_shared)
107 //              vwindow_edl->Garbage::remove_user();
108
109         if(!parent_edl)
110         {
111                 delete assets;
112                 delete session;
113         }
114
115
116         folders.remove_all_objects();
117         for(int i = 0; i < clips.size(); i++)
118                 clips.get(i)->Garbage::remove_user();
119         clips.remove_all();
120         delete nested_edls;
121 }
122
123
124
125 void EDL::create_objects()
126 {
127         tracks = new Tracks(this);
128         if(!parent_edl)
129         {
130                 assets = new Assets(this);
131                 session = new EDLSession(this);
132         }
133         else
134         {
135                 assets = parent_edl->assets;
136                 session = parent_edl->session;
137         }
138
139         local_session = new LocalSession(this);
140         labels = new Labels(this, "LABELS");
141         nested_edls = new NestedEDLs;
142 //      last_playback_position = 0;
143 }
144
145 EDL& EDL::operator=(EDL &edl)
146 {
147 printf("EDL::operator= 1\n");
148         copy_all(&edl);
149         return *this;
150 }
151
152 int EDL::load_defaults(BC_Hash *defaults)
153 {
154         if(!parent_edl)
155                 session->load_defaults(defaults);
156
157         local_session->load_defaults(defaults);
158         return 0;
159 }
160
161 int EDL::save_defaults(BC_Hash *defaults)
162 {
163         if(!parent_edl)
164                 session->save_defaults(defaults);
165
166         local_session->save_defaults(defaults);
167         return 0;
168 }
169
170 void EDL::boundaries()
171 {
172         session->boundaries();
173         local_session->boundaries();
174 }
175
176 int EDL::create_default_tracks()
177 {
178
179         for(int i = 0; i < session->video_tracks; i++)
180         {
181                 tracks->add_video_track(0, 0);
182         }
183         for(int i = 0; i < session->audio_tracks; i++)
184         {
185                 tracks->add_audio_track(0, 0);
186         }
187         return 0;
188 }
189
190 int EDL::load_xml(FileXML *file,
191         uint32_t load_flags)
192 {
193         int result = 0;
194 // Track numbering offset for replacing undo data.
195         int track_offset = 0;
196
197 // Clear objects
198         folders.remove_all_objects();
199
200         if((load_flags & LOAD_ALL) == LOAD_ALL)
201         {
202                 remove_vwindow_edls();
203         }
204
205
206 // Search for start of master EDL.
207
208 // The parent_edl test caused clip creation to fail since those XML files
209 // contained an EDL tag.
210
211 // The parent_edl test is required to make EDL loading work because
212 // when loading an EDL the EDL tag is already read by the parent.
213
214         if(!parent_edl)
215         {
216                 do{
217                   result = file->read_tag();
218                 }while(!result &&
219                         !file->tag.title_is("XML") &&
220                         !file->tag.title_is("EDL"));
221         }
222
223         if(!result)
224         {
225 // Get path for backups
226 //              path[0] = 0;
227                 file->tag.get_property("path", path);
228
229 // Erase everything
230                 if((load_flags & LOAD_ALL) == LOAD_ALL ||
231                         (load_flags & LOAD_EDITS) == LOAD_EDITS)
232                 {
233                         while(tracks->last) delete tracks->last;
234                 }
235
236                 if((load_flags & LOAD_ALL) == LOAD_ALL)
237                 {
238                         for(int i = 0; i < clips.size(); i++)
239                                 clips.get(i)->Garbage::remove_user();
240                         clips.remove_all();
241                 }
242
243                 if(load_flags & LOAD_TIMEBAR)
244                 {
245                         while(labels->last) delete labels->last;
246                         local_session->unset_inpoint();
247                         local_session->unset_outpoint();
248                 }
249
250 // This was originally in LocalSession::load_xml
251                 if(load_flags & LOAD_SESSION)
252                 {
253                         local_session->clipboard_length = 0;
254                 }
255
256                 do{
257                         result = file->read_tag();
258
259                         if(!result)
260                         {
261                                 if(file->tag.title_is("/XML") ||
262                                         file->tag.title_is("/EDL") ||
263                                         file->tag.title_is("/CLIP_EDL") ||
264                                         file->tag.title_is("/VWINDOW_EDL"))
265                                 {
266                                         result = 1;
267                                 }
268                                 else
269                                 if(file->tag.title_is("CLIPBOARD"))
270                                 {
271                                         local_session->clipboard_length =
272                                                 file->tag.get_property("LENGTH", (double)0);
273                                 }
274                                 else
275                                 if(file->tag.title_is("VIDEO"))
276                                 {
277                                         if((load_flags & LOAD_VCONFIG) &&
278                                                 (load_flags & LOAD_SESSION))
279                                                 session->load_video_config(file, 0, load_flags);
280                                 }
281                                 else
282                                 if(file->tag.title_is("AUDIO"))
283                                 {
284                                         if((load_flags & LOAD_ACONFIG) &&
285                                                 (load_flags & LOAD_SESSION))
286                                                 session->load_audio_config(file, 0, load_flags);
287                                 }
288                                 else
289                                 if(file->tag.title_is("FOLDER"))
290                                 {
291                                         char folder[BCTEXTLEN];
292                                         strcpy(folder, file->read_text());
293                                         new_folder(folder);
294                                 }
295                                 else
296                                 if(file->tag.title_is("ASSETS"))
297                                 {
298                                         if(load_flags & LOAD_ASSETS)
299                                                 assets->load(file, load_flags);
300                                 }
301                                 else
302                                 if(file->tag.title_is(labels->xml_tag))
303                                 {
304                                         if(load_flags & LOAD_TIMEBAR)
305                                                 labels->load(file, load_flags);
306                                 }
307                                 else
308                                 if(file->tag.title_is("LOCALSESSION"))
309                                 {
310                                         if((load_flags & LOAD_SESSION) ||
311                                                 (load_flags & LOAD_TIMEBAR))
312                                                 local_session->load_xml(file, load_flags);
313                                 }
314                                 else
315                                 if(file->tag.title_is("SESSION"))
316                                 {
317                                         if((load_flags & LOAD_SESSION) &&
318                                                 !parent_edl)
319                                                 session->load_xml(file, 0, load_flags);
320                                 }
321                                 else
322                                 if(file->tag.title_is("TRACK"))
323                                 {
324                                         tracks->load(file, track_offset, load_flags);
325                                 }
326                                 else
327 // Sub EDL.
328 // Causes clip creation to fail because that involves an opening EDL tag.
329                                 if(file->tag.title_is("CLIP_EDL") && !parent_edl)
330                                 {
331                                         EDL *new_edl = new EDL(this);
332                                         new_edl->create_objects();
333                                         new_edl->load_xml(file, LOAD_ALL);
334
335                                         if((load_flags & LOAD_ALL) == LOAD_ALL)
336                                                 clips.append(new_edl);
337                                         else
338                                                 new_edl->Garbage::remove_user();
339                                 }
340                                 else
341                                 if(file->tag.title_is("VWINDOW_EDL") && !parent_edl)
342                                 {
343                                         EDL *new_edl = new EDL(this);
344                                         new_edl->create_objects();
345                                         new_edl->load_xml(file, LOAD_ALL);
346
347
348                                         if((load_flags & LOAD_ALL) == LOAD_ALL)
349                                         {
350 //                                              if(vwindow_edl && !vwindow_edl_shared)
351 //                                                      vwindow_edl->Garbage::remove_user();
352 //                                              vwindow_edl_shared = 0;
353 //                                              vwindow_edl = new_edl;
354
355                                                 append_vwindow_edl(new_edl, 0);
356
357                                         }
358                                         else
359 // Discard if not replacing EDL
360                                         {
361                                                 new_edl->Garbage::remove_user();
362                                                 new_edl = 0;
363                                         }
364                                 }
365                         }
366                 }while(!result);
367         }
368         boundaries();
369 //dump();
370
371         return 0;
372 }
373
374 // Output path is the path of the output file if name truncation is desired.
375 // It is a "" if complete names should be used.
376 // Called recursively by copy for clips, thus the string can't be terminated.
377 // The string is not terminated in this call.
378 int EDL::save_xml(FileXML *file,
379         const char *output_path,
380         int is_clip,
381         int is_vwindow)
382 {
383         copy(0,
384                 tracks->total_length(),
385                 1,
386                 is_clip,
387                 is_vwindow,
388                 file,
389                 output_path,
390                 0);
391         return 0;
392 }
393
394 int EDL::copy_all(EDL *edl)
395 {
396         if(this == edl) return 0;
397         update_index(edl);
398         nested_edls->clear();
399         copy_session(edl);
400         copy_assets(edl);
401         copy_clips(edl);
402         tracks->copy_from(edl->tracks);
403         labels->copy_from(edl->labels);
404         return 0;
405 }
406
407 void EDL::copy_clips(EDL *edl)
408 {
409         if(this == edl) return;
410
411         remove_vwindow_edls();
412
413 //      if(vwindow_edl && !vwindow_edl_shared)
414 //              vwindow_edl->Garbage::remove_user();
415 //      vwindow_edl = 0;
416 //      vwindow_edl_shared = 0;
417
418         for(int i = 0; i < edl->total_vwindow_edls(); i++)
419         {
420                 EDL *new_edl = new EDL(this);
421                 new_edl->create_objects();
422                 new_edl->copy_all(edl->get_vwindow_edl(i));
423                 append_vwindow_edl(new_edl, 0);
424         }
425
426         for(int i = 0; i < clips.size(); i++)
427                 clips.get(i)->Garbage::remove_user();
428         clips.remove_all();
429         for(int i = 0; i < edl->clips.total; i++)
430         {
431                 add_clip(edl->clips.values[i]);
432         }
433 }
434
435 void EDL::copy_assets(EDL *edl)
436 {
437         if(this == edl) return;
438
439         if(!parent_edl)
440         {
441                 assets->copy_from(edl->assets);
442         }
443 }
444
445 void EDL::copy_session(EDL *edl, int session_only)
446 {
447         if(this == edl) return;
448
449         if(!session_only)
450         {
451                 strcpy(this->path, edl->path);
452 //printf("EDL::copy_session %p %s\n", this, this->path);
453
454                 folders.remove_all_objects();
455                 for(int i = 0; i < edl->folders.total; i++)
456                 {
457                         char *new_folder;
458                         folders.append(new_folder = new char[strlen(edl->folders.values[i]) + 1]);
459                         strcpy(new_folder, edl->folders.values[i]);
460                 }
461         }
462
463         if(!parent_edl)
464         {
465                 session->copy(edl->session);
466         }
467
468         if(!session_only)
469         {
470                 local_session->copy_from(edl->local_session);
471         }
472 }
473
474 int EDL::copy_assets(double start,
475         double end,
476         FileXML *file,
477         int all,
478         const char *output_path)
479 {
480         ArrayList<Asset*> asset_list;
481         Track* current;
482
483         file->tag.set_title("ASSETS");
484         file->append_tag();
485         file->append_newline();
486
487 // Copy everything for a save
488         if(all)
489         {
490                 for(Asset *asset = assets->first;
491                         asset;
492                         asset = asset->next)
493                 {
494                         asset_list.append(asset);
495                 }
496         }
497         else
498 // Copy just the ones being used.
499         {
500                 for(current = tracks->first;
501                         current;
502                         current = NEXT)
503                 {
504                         if(current->record)
505                         {
506                                 current->copy_assets(start,
507                                         end,
508                                         &asset_list);
509                         }
510                 }
511         }
512
513 // Paths relativised here
514         for(int i = 0; i < asset_list.total; i++)
515         {
516                 asset_list.values[i]->write(file,
517                         0,
518                         output_path);
519         }
520
521         file->tag.set_title("/ASSETS");
522         file->append_tag();
523         file->append_newline();
524         file->append_newline();
525         return 0;
526 }
527
528 int EDL::copy(double start,
529         double end,
530         int all,
531         int is_clip,
532         int is_vwindow,
533         FileXML *file,
534         const char *output_path,
535         int rewind_it)
536 {
537 //printf("EDL::copy 1\n");
538 // begin file
539         if(is_clip)
540                 file->tag.set_title("CLIP_EDL");
541         else
542         if(is_vwindow)
543                 file->tag.set_title("VWINDOW_EDL");
544         else
545         {
546                 file->tag.set_title("EDL");
547                 file->tag.set_property("VERSION", CINELERRA_VERSION);
548 // Save path for restoration of the project title from a backup.
549                 if(this->path[0])
550                 {
551                         file->tag.set_property("PATH", path);
552                 }
553         }
554
555         file->append_tag();
556         file->append_newline();
557
558 // Set clipboard samples only if copying to clipboard
559         if(!all)
560         {
561                 file->tag.set_title("CLIPBOARD");
562                 file->tag.set_property("LENGTH", end - start);
563                 file->append_tag();
564                 file->tag.set_title("/CLIPBOARD");
565                 file->append_tag();
566                 file->append_newline();
567                 file->append_newline();
568         }
569 //printf("EDL::copy 1\n");
570
571 // Sessions
572         local_session->save_xml(file, start);
573
574 //printf("EDL::copy 1\n");
575
576 // Top level stuff.
577 //      if(!parent_edl)
578         {
579 // Need to copy all this from child EDL if pasting is desired.
580 // Session
581                 session->save_xml(file);
582                 session->save_video_config(file);
583                 session->save_audio_config(file);
584
585 // Folders
586                 for(int i = 0; i < folders.total; i++)
587                 {
588                         file->tag.set_title("FOLDER");
589                         file->append_tag();
590                         file->append_text(folders.values[i]);
591                         file->tag.set_title("/FOLDER");
592                         file->append_tag();
593                         file->append_newline();
594                 }
595
596 // Media
597 // Don't replicate all assets for every clip.
598 // The assets for the clips are probably in the mane EDL.
599                 if(!is_clip)
600                         copy_assets(start,
601                                 end,
602                                 file,
603                                 all,
604                                 output_path);
605
606 // Clips
607 // Don't want this if using clipboard
608                 if(all)
609                 {
610                         for(int i = 0; i < total_vwindow_edls(); i++)
611                         {
612                                 get_vwindow_edl(i)->save_xml(file,
613                                         output_path,
614                                         0,
615                                         1);
616                         }
617
618                         for(int i = 0; i < clips.total; i++)
619                                 clips.values[i]->save_xml(file,
620                                         output_path,
621                                         1,
622                                         0);
623                 }
624
625                 file->append_newline();
626                 file->append_newline();
627         }
628
629
630 //printf("EDL::copy 1\n");
631
632         labels->copy(start, end, file);
633 //printf("EDL::copy 1\n");
634         tracks->copy(start, end, all, file, output_path);
635 //printf("EDL::copy 2\n");
636
637 // terminate file
638         if(is_clip)
639                 file->tag.set_title("/CLIP_EDL");
640         else
641         if(is_vwindow)
642                 file->tag.set_title("/VWINDOW_EDL");
643         else
644                 file->tag.set_title("/EDL");
645         file->append_tag();
646         file->append_newline();
647
648
649 // For editing operations we want to rewind it for immediate pasting.
650 // For clips and saving to disk leave it alone.
651         if(rewind_it)
652         {
653                 file->terminate_string();
654                 file->rewind();
655         }
656         return 0;
657 }
658
659 void EDL::rechannel()
660 {
661         for(Track *current = tracks->first; current; current = NEXT)
662         {
663                 if(current->data_type == TRACK_AUDIO)
664                 {
665                         PanAutos *autos = (PanAutos*)current->automation->autos[AUTOMATION_PAN];
666                         ((PanAuto*)autos->default_auto)->rechannel();
667                         for(PanAuto *keyframe = (PanAuto*)autos->first;
668                                 keyframe;
669                                 keyframe = (PanAuto*)keyframe->next)
670                         {
671                                 keyframe->rechannel();
672                         }
673                 }
674         }
675 }
676
677 void EDL::resample(double old_rate, double new_rate, int data_type)
678 {
679         for(Track *current = tracks->first; current; current = NEXT)
680         {
681                 if(current->data_type == data_type)
682                 {
683                         current->resample(old_rate, new_rate);
684                 }
685         }
686 }
687
688
689 void EDL::synchronize_params(EDL *edl)
690 {
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,
695                 that_track = that_track->next)
696         {
697                 this_track->synchronize_params(that_track);
698         }
699 }
700
701 int EDL::trim_selection(double start,
702         double end,
703         int edit_labels,
704         int edit_plugins,
705         int edit_autos)
706 {
707         if(start != end)
708         {
709 // clear the data
710                 clear(0,
711                         start,
712                         edit_labels,
713                         edit_plugins,
714                         edit_autos);
715                 clear(end - start,
716                         tracks->total_length(),
717                         edit_labels,
718                         edit_plugins,
719                         edit_autos);
720         }
721         return 0;
722 }
723
724
725 int EDL::equivalent(double position1, double position2)
726 {
727         double threshold = (double).5 / session->frame_rate;
728         if(session->cursor_on_frames)
729                 threshold = (double).5 / session->frame_rate;
730         else
731                 threshold = (double)1 / session->sample_rate;
732
733         if(fabs(position2 - position1) < threshold)
734         return 1;
735     else
736         return 0;
737 }
738
739 double EDL::equivalent_output(EDL *edl)
740 {
741         double result = -1;
742         session->equivalent_output(edl->session, &result);
743         tracks->equivalent_output(edl->tracks, &result);
744         return result;
745 }
746
747
748 void EDL::set_path(char *path)
749 {
750         strcpy(this->path, path);
751 }
752
753 void EDL::set_inpoint(double position)
754 {
755         if(equivalent(local_session->get_inpoint(), position) &&
756                 local_session->get_inpoint() >= 0)
757         {
758                 local_session->unset_inpoint();
759         }
760         else
761         {
762                 local_session->set_inpoint(align_to_frame(position, 0));
763                 if(local_session->get_outpoint() <= local_session->get_inpoint())
764                         local_session->unset_outpoint();
765         }
766 }
767
768 void EDL::set_outpoint(double position)
769 {
770         if(equivalent(local_session->get_outpoint(), position) &&
771                 local_session->get_outpoint() >= 0)
772         {
773                 local_session->unset_outpoint();
774         }
775         else
776         {
777                 local_session->set_outpoint(align_to_frame(position, 0));
778                 if(local_session->get_inpoint() >= local_session->get_outpoint())
779                         local_session->unset_inpoint();
780         }
781 }
782
783
784 int EDL::clear(double start,
785         double end,
786         int clear_labels,
787         int clear_plugins,
788         int edit_autos)
789 {
790         if(start == end)
791         {
792                 double distance = 0;
793                 tracks->clear_handle(start,
794                         end,
795                         distance,
796                         clear_labels,
797                         clear_plugins,
798                         edit_autos);
799                 if(clear_labels && distance > 0)
800                         labels->paste_silence(start,
801                                 start + distance);
802         }
803         else
804         {
805                 tracks->clear(start,
806                         end,
807                         clear_plugins,
808                         edit_autos);
809                 if(clear_labels)
810                         labels->clear(start,
811                                 end,
812                                 1);
813         }
814
815 // Need to put at beginning so a subsequent paste operation starts at the
816 // right position.
817         double position = local_session->get_selectionstart();
818         local_session->set_selectionend(position);
819         local_session->set_selectionstart(position);
820         return 0;
821 }
822
823 void EDL::modify_edithandles(double oldposition,
824         double newposition,
825         int currentend,
826         int handle_mode,
827         int edit_labels,
828         int edit_plugins,
829         int edit_autos)
830 {
831         tracks->modify_edithandles(oldposition,
832                 newposition,
833                 currentend,
834                 handle_mode,
835                 edit_labels,
836                 edit_plugins,
837                 edit_autos);
838         labels->modify_handles(oldposition,
839                 newposition,
840                 currentend,
841                 handle_mode,
842                 edit_labels);
843 }
844
845 void EDL::modify_pluginhandles(double oldposition,
846         double newposition,
847         int currentend,
848         int handle_mode,
849         int edit_labels,
850         int edit_autos,
851         Edits *trim_edits)
852 {
853         tracks->modify_pluginhandles(oldposition,
854                 newposition,
855                 currentend,
856                 handle_mode,
857                 edit_labels,
858                 edit_autos,
859                 trim_edits);
860         optimize();
861 }
862
863 void EDL::paste_silence(double start,
864         double end,
865         int edit_labels,
866         int edit_plugins,
867         int edit_autos)
868 {
869         if(edit_labels)
870                 labels->paste_silence(start, end);
871         tracks->paste_silence(start,
872                 end,
873                 edit_plugins,
874                 edit_autos);
875 }
876
877
878 void EDL::remove_from_project(ArrayList<EDL*> *clips)
879 {
880         for(int i = 0; i < clips->size(); i++)
881         {
882                 for(int j = 0; j < this->clips.size(); j++)
883                 {
884                         if(this->clips.get(j) == clips->values[i])
885                         {
886                                 EDL *clip = this->clips.get(j);
887                                 this->clips.remove(clip);
888                                 clip->Garbage::remove_user();
889                         }
890                 }
891         }
892 }
893
894 void EDL::remove_from_project(ArrayList<Indexable*> *assets)
895 {
896 // Remove from clips
897         if(!parent_edl)
898                 for(int j = 0; j < clips.total; j++)
899                 {
900                         clips.values[j]->remove_from_project(assets);
901                 }
902
903 // Remove from VWindow EDLs
904         for(int i = 0; i < total_vwindow_edls(); i++)
905                 get_vwindow_edl(i)->remove_from_project(assets);
906
907         for(int i = 0; i < assets->size(); i++)
908         {
909 // Remove from tracks
910                 for(Track *track = tracks->first; track; track = track->next)
911                 {
912                         track->remove_asset(assets->get(i));
913                 }
914
915 // Remove from assets
916                 if(!parent_edl && assets->get(i)->is_asset)
917                 {
918                         this->assets->remove_asset((Asset*)assets->get(i));
919                 }
920                 else
921                 if(!parent_edl && !assets->get(i)->is_asset)
922                 {
923                         this->nested_edls->remove_edl((EDL*)assets->get(i));
924                 }
925         }
926 }
927
928 void EDL::update_assets(EDL *src)
929 {
930         for(Asset *current = src->assets->first;
931                 current;
932                 current = NEXT)
933         {
934                 assets->update(current);
935         }
936 }
937
938 int EDL::get_tracks_height(Theme *theme)
939 {
940         int total_pixels = 0;
941         for(Track *current = tracks->first;
942                 current;
943                 current = NEXT)
944         {
945                 total_pixels += current->vertical_span(theme);
946         }
947         return total_pixels;
948 }
949
950 int64_t EDL::get_tracks_width()
951 {
952         int64_t total_pixels = 0;
953         for(Track *current = tracks->first;
954                 current;
955                 current = NEXT)
956         {
957                 int64_t pixels = current->horizontal_span();
958                 if(pixels > total_pixels) total_pixels = pixels;
959         }
960 //printf("EDL::get_tracks_width %d\n", total_pixels);
961         return total_pixels;
962 }
963
964 // int EDL::calculate_output_w(int single_channel)
965 // {
966 //      if(single_channel) return session->output_w;
967 //
968 //      int widest = 0;
969 //      for(int i = 0; i < session->video_channels; i++)
970 //      {
971 //              if(session->vchannel_x[i] + session->output_w > widest) widest = session->vchannel_x[i] + session->output_w;
972 //      }
973 //      return widest;
974 // }
975 //
976 // int EDL::calculate_output_h(int single_channel)
977 // {
978 //      if(single_channel) return session->output_h;
979 //
980 //      int tallest = 0;
981 //      for(int i = 0; i < session->video_channels; i++)
982 //      {
983 //              if(session->vchannel_y[i] + session->output_h > tallest) tallest = session->vchannel_y[i] + session->output_h;
984 //      }
985 //      return tallest;
986 // }
987
988 // Get the total output size scaled to aspect ratio
989 void EDL::calculate_conformed_dimensions(int single_channel, float &w, float &h)
990 {
991         w = session->output_w;
992         h = session->output_h;
993
994         if((float)session->output_w / session->output_h > get_aspect_ratio())
995         {
996                 h = (float)h *
997                         (session->output_w / get_aspect_ratio() / session->output_h);
998         }
999         else
1000         {
1001                 w = (float)w *
1002                         (h * get_aspect_ratio() / session->output_w);
1003         }
1004 }
1005
1006 float EDL::get_aspect_ratio()
1007 {
1008         return session->aspect_w / session->aspect_h;
1009 }
1010
1011 int EDL::dump(FILE *fp)
1012 {
1013         if(parent_edl)
1014                 fprintf(fp,"CLIP\n");
1015         else
1016                 fprintf(fp,"EDL\n");
1017         fprintf(fp,"  clip_title: %s\n"
1018                 "  parent_edl: %p\n", local_session->clip_title, parent_edl);
1019         fprintf(fp,"  selectionstart %f\n  selectionend %f\n  loop_start %f\n  loop_end %f\n",
1020                 local_session->get_selectionstart(1),
1021                 local_session->get_selectionend(1),
1022                 local_session->loop_start,
1023                 local_session->loop_end);
1024         for(int i = 0; i < TOTAL_PANES; i++)
1025         {
1026                 fprintf(fp,"  pane %d view_start=%jd track_start=%jd\n", i,
1027                         local_session->view_start[i],
1028                         local_session->track_start[i]);
1029         }
1030
1031         if(!parent_edl)
1032         {
1033                 fprintf(fp,"audio_channels: %d audio_tracks: %d sample_rate: %jd\n",
1034                         session->audio_channels,
1035                         session->audio_tracks,
1036                         session->sample_rate);
1037                 fprintf(fp,"  video_channels: %d\n"
1038                         "  video_tracks: %d\n"
1039                         "  frame_rate: %.2f\n"
1040                         "  frames_per_foot: %.2f\n"
1041                         "  output_w: %d\n"
1042                         "  output_h: %d\n"
1043                         "  aspect_w: %f\n"
1044                         "  aspect_h: %f\n"
1045                         "  color_model: %d\n",
1046                                 session->video_channels,
1047                                 session->video_tracks,
1048                                 session->frame_rate,
1049                                 session->frames_per_foot,
1050                                 session->output_w,
1051                                 session->output_h,
1052                                 session->aspect_w,
1053                                 session->aspect_h,
1054                                 session->color_model);
1055
1056                 fprintf(fp," CLIPS\n");
1057                 fprintf(fp,"  total: %d\n", clips.total);
1058
1059                 for(int i = 0; i < clips.total; i++)
1060                 {
1061                         fprintf(fp,"\n\n");
1062                         clips.values[i]->dump(fp);
1063                         fprintf(fp,"\n\n");
1064                 }
1065
1066                 fprintf(fp," VWINDOW EDLS\n");
1067                 fprintf(fp,"  total: %d\n", total_vwindow_edls());
1068
1069                 for(int i = 0; i < total_vwindow_edls(); i++)
1070                 {
1071                         fprintf(fp,"   %s\n", get_vwindow_edl(i)->local_session->clip_title);
1072                 }
1073
1074                 fprintf(fp," ASSETS\n");
1075                 assets->dump(fp);
1076         }
1077         fprintf(fp," LABELS\n");
1078         labels->dump(fp);
1079         fprintf(fp," TRACKS\n");
1080         tracks->dump(fp);
1081 //printf("EDL::dump 2\n");
1082         return 0;
1083 }
1084
1085 EDL* EDL::add_clip(EDL *edl)
1086 {
1087 // Copy argument.  New edls are deleted from MWindow::load_filenames.
1088         EDL *new_edl = new EDL(this);
1089         new_edl->create_objects();
1090         new_edl->copy_all(edl);
1091         clips.append(new_edl);
1092         return new_edl;
1093 }
1094
1095 void EDL::insert_asset(Asset *asset,
1096         EDL *nested_edl,
1097         double position,
1098         Track *first_track,
1099         RecordLabels *labels)
1100 {
1101 // Insert asset into asset table
1102         Asset *new_asset = 0;
1103         EDL *new_nested_edl = 0;
1104
1105         if(asset) new_asset = assets->update(asset);
1106         if(nested_edl) new_nested_edl = nested_edls->get_copy(nested_edl);
1107
1108 // Paste video
1109         int vtrack = 0;
1110         Track *current = first_track ? first_track : tracks->first;
1111
1112
1113 // Fix length of single frame
1114         double length = 0.;
1115         int layers = 0;
1116         int channels = 0;
1117
1118         if(new_nested_edl)
1119         {
1120                 length = new_nested_edl->tracks->total_playable_length();
1121                 layers = 1;
1122                 channels = new_nested_edl->session->audio_channels;
1123         }
1124
1125         if(new_asset)
1126         {
1127 // Insert 1 frame for undefined length
1128                 if(new_asset->video_length < 0)
1129                 {
1130                         length = session->si_useduration ?
1131                                 session->si_duration :
1132                                 1.0 / session->frame_rate;
1133                 }
1134                 else {
1135                         length = new_asset->frame_rate > 0 ?
1136                                 (double)new_asset->video_length / new_asset->frame_rate :
1137                                 1.0 / session->frame_rate;
1138                 }
1139                 layers = new_asset->layers;
1140                 channels = new_asset->channels;
1141         }
1142
1143         for( ;
1144                 current && vtrack < layers;
1145                 current = NEXT)
1146         {
1147                 if(!current->record ||
1148                         current->data_type != TRACK_VIDEO)
1149                         continue;
1150
1151                 current->insert_asset(new_asset,
1152                         new_nested_edl,
1153                         length,
1154                         position,
1155                         vtrack);
1156
1157                 vtrack++;
1158         }
1159
1160         int atrack = 0;
1161         if(new_asset)
1162         {
1163                 if(new_asset->audio_length < 0)
1164                 {
1165 // Insert 1 frame for undefined length & video
1166                         if(new_asset->video_data)
1167                                 length = (double)1.0 / new_asset->frame_rate;
1168                         else
1169 // Insert 1 second for undefined length & no video
1170                                 length = 1.0;
1171                 }
1172                 else
1173                         length = (double)new_asset->audio_length /
1174                                         new_asset->sample_rate;
1175         }
1176
1177         for(current = tracks->first;
1178                 current && atrack < channels;
1179                 current = NEXT)
1180         {
1181                 if(!current->record ||
1182                         current->data_type != TRACK_AUDIO)
1183                         continue;
1184
1185                 current->insert_asset(new_asset,
1186                         new_nested_edl,
1187                         length,
1188                         position,
1189                         atrack);
1190
1191
1192                 atrack++;
1193         }
1194
1195 // Insert labels from a recording window.
1196         if(labels)
1197         {
1198                 for(RecordLabel *label = labels->first; label; label = label->next)
1199                 {
1200                         this->labels->toggle_label(label->position, label->position);
1201                 }
1202         }
1203 }
1204
1205
1206
1207 void EDL::set_index_file(Indexable *indexable)
1208 {
1209         if(indexable->is_asset)
1210                 assets->update_index((Asset*)indexable);
1211         else
1212                 nested_edls->update_index((EDL*)indexable);
1213 }
1214
1215 void EDL::optimize()
1216 {
1217 //printf("EDL::optimize 1\n");
1218         if(local_session->preview_start < 0) local_session->preview_start = 0;
1219         double length = tracks->total_length();
1220         if(local_session->preview_end > length) local_session->preview_end = length;
1221         if(local_session->preview_start >= local_session->preview_end ) {
1222                 local_session->preview_start = 0;
1223                 local_session->preview_end = length;
1224         }
1225         for(Track *current = tracks->first; current; current = NEXT)
1226                 current->optimize();
1227 }
1228
1229 int EDL::next_id()
1230 {
1231         id_lock->lock("EDL::next_id");
1232         int result = EDLSession::current_id++;
1233         id_lock->unlock();
1234         return result;
1235 }
1236
1237 void EDL::get_shared_plugins(Track *source,
1238         ArrayList<SharedLocation*> *plugin_locations,
1239         int omit_recordable,
1240         int data_type)
1241 {
1242         for(Track *track = tracks->first; track; track = track->next)
1243         {
1244                 if(!track->record || !omit_recordable)
1245                 {
1246                         if(track != source &&
1247                                 track->data_type == data_type)
1248                         {
1249                                 for(int i = 0; i < track->plugin_set.total; i++)
1250                                 {
1251                                         Plugin *plugin = track->get_current_plugin(
1252                                                 local_session->get_selectionstart(1),
1253                                                 i,
1254                                                 PLAY_FORWARD,
1255                                                 1,
1256                                                 0);
1257                                         if(plugin && plugin->plugin_type == PLUGIN_STANDALONE)
1258                                         {
1259                                                 plugin_locations->append(new SharedLocation(tracks->number_of(track), i));
1260                                         }
1261                                 }
1262                         }
1263                 }
1264         }
1265 }
1266
1267 void EDL::get_shared_tracks(Track *track,
1268         ArrayList<SharedLocation*> *module_locations,
1269         int omit_recordable,
1270         int data_type)
1271 {
1272         for(Track *current = tracks->first; current; current = NEXT)
1273         {
1274                 if(!omit_recordable || !current->record)
1275                 {
1276                         if(current != track &&
1277                                 current->data_type == data_type)
1278                         {
1279                                 module_locations->append(new SharedLocation(tracks->number_of(current), 0));
1280                         }
1281                 }
1282         }
1283 }
1284
1285 // Convert position to frames if cursor alignment is enabled
1286 double EDL::align_to_frame(double position, int round)
1287 {
1288 //printf("EDL::align_to_frame 1 %f\n", position);
1289         if(session->cursor_on_frames)
1290         {
1291 // Seconds -> Frames
1292                 double temp = (double)position * session->frame_rate;
1293 //printf("EDL::align_to_frame 2 %f\n", temp);
1294
1295 // Assert some things
1296                 if(session->sample_rate == 0)
1297                         printf("EDL::align_to_frame: sample_rate == 0\n");
1298
1299                 if(session->frame_rate == 0)
1300                         printf("EDL::align_to_frame: frame_rate == 0\n");
1301
1302 // Round frames
1303 // Always round down negative numbers
1304 // but round up only if requested
1305                 if(round)
1306                 {
1307                         temp = Units::round(temp);
1308                 }
1309                 else
1310                 {
1311 //                      if(temp < 0)
1312 //                      {
1313 //                              temp -= 0.5;
1314 //                      }
1315 //                      else
1316                                 temp = Units::to_int64(temp);
1317                 }
1318 //printf("EDL::align_to_frame 3 %f\n", temp);
1319
1320 // Frames -> Seconds
1321                 temp /= session->frame_rate;
1322
1323 //printf("EDL::align_to_frame 5 %f\n", temp);
1324
1325                 return temp;
1326         }
1327 //printf("EDL::align_to_frame 3 %d\n", position);
1328
1329
1330         return position;
1331 }
1332
1333
1334 void EDL::new_folder(const char *folder)
1335 {
1336         for(int i = 0; i < folders.total; i++)
1337         {
1338                 if(!strcasecmp(folders.values[i], folder)) return;
1339         }
1340
1341         char *new_folder;
1342         folders.append(new_folder = new char[strlen(folder) + 1]);
1343         strcpy(new_folder, folder);
1344 }
1345
1346 void EDL::delete_folder(const char *folder)
1347 {
1348         int i;
1349         for(i = 0; i < folders.total; i++)
1350         {
1351                 if(!strcasecmp(folders.values[i], folder))
1352                 {
1353                         break;
1354                 }
1355         }
1356
1357         if(i < folders.total) delete folders.values[i];
1358
1359         for( ; i < folders.total - 1; i++)
1360         {
1361                 folders.values[i] = folders.values[i + 1];
1362         }
1363 }
1364
1365 int EDL::get_use_vconsole(VEdit* *playable_edit,
1366         int64_t position,
1367         int direction,
1368         PlayableTracks *playable_tracks)
1369 {
1370         int share_playable_tracks = 1;
1371         int result = 0;
1372         VTrack *playable_track = 0;
1373         const int debug = 0;
1374         *playable_edit = 0;
1375
1376 // Calculate playable tracks when being called as a nested EDL
1377         if(!playable_tracks)
1378         {
1379                 share_playable_tracks = 0;
1380                 playable_tracks = new PlayableTracks(this,
1381                         position,
1382                         direction,
1383                         TRACK_VIDEO,
1384                         1);
1385         }
1386
1387
1388 // Total number of playable tracks is 1
1389         if(playable_tracks->size() != 1)
1390         {
1391                 result = 1;
1392         }
1393         else
1394         {
1395                 playable_track = (VTrack*)playable_tracks->get(0);
1396         }
1397
1398 // Don't need playable tracks anymore
1399         if(!share_playable_tracks)
1400         {
1401                 delete playable_tracks;
1402         }
1403
1404 if(debug) printf("EDL::get_use_vconsole %d playable_tracks->size()=%d\n",
1405 __LINE__,
1406 playable_tracks->size());
1407         if(result) return 1;
1408
1409
1410 // Test mutual conditions between direct copy rendering and this.
1411         if(!playable_track->direct_copy_possible(position,
1412                 direction,
1413                 1))
1414                 return 1;
1415 if(debug) printf("EDL::get_use_vconsole %d\n", __LINE__);
1416
1417         *playable_edit = (VEdit*)playable_track->edits->editof(position,
1418                 direction,
1419                 0);
1420 // No edit at current location
1421         if(!*playable_edit) return 1;
1422 if(debug) printf("EDL::get_use_vconsole %d\n", __LINE__);
1423
1424
1425 // Edit is nested EDL
1426         if((*playable_edit)->nested_edl)
1427         {
1428 // Test nested EDL
1429                 EDL *nested_edl = (*playable_edit)->nested_edl;
1430                 int64_t nested_position = (int64_t)((position -
1431                                 (*playable_edit)->startproject +
1432                                 (*playable_edit)->startsource) *
1433                         nested_edl->session->frame_rate /
1434                         session->frame_rate);
1435
1436
1437                 VEdit *playable_edit_temp = 0;
1438                 if(session->output_w != nested_edl->session->output_w ||
1439                         session->output_h != nested_edl->session->output_h ||
1440                         nested_edl->get_use_vconsole(&playable_edit_temp,
1441                                 nested_position,
1442                                 direction,
1443                                 0))
1444                         return 1;
1445
1446                 return 0;
1447         }
1448
1449 if(debug) printf("EDL::get_use_vconsole %d\n", __LINE__);
1450 // Edit is not a nested EDL
1451 // Edit is silence
1452         if(!(*playable_edit)->asset) return 1;
1453 if(debug) printf("EDL::get_use_vconsole %d\n", __LINE__);
1454
1455
1456 // Asset and output device must have the same dimensions
1457         if((*playable_edit)->asset->width != session->output_w ||
1458                 (*playable_edit)->asset->height != session->output_h)
1459                 return 1;
1460
1461
1462 if(debug) printf("EDL::get_use_vconsole %d\n", __LINE__);
1463
1464
1465
1466 // If we get here the frame is going to be directly copied.  Whether it is
1467 // decompressed in hardware depends on the colormodel.
1468         return 0;
1469 }
1470
1471
1472 // For Indexable
1473 int EDL::get_audio_channels()
1474 {
1475         return session->audio_channels;
1476 }
1477
1478 int EDL::get_sample_rate()
1479 {
1480         return session->sample_rate;
1481 }
1482
1483 int64_t EDL::get_audio_samples()
1484 {
1485         return (int64_t)(tracks->total_playable_length() *
1486                 session->sample_rate);
1487 }
1488
1489 int EDL::have_audio()
1490 {
1491         return 1;
1492 }
1493
1494 int EDL::have_video()
1495 {
1496         return 1;
1497 }
1498
1499
1500 int EDL::get_w()
1501 {
1502         return session->output_w;
1503 }
1504
1505 int EDL::get_h()
1506 {
1507         return session->output_h;
1508 }
1509
1510 double EDL::get_frame_rate()
1511 {
1512         return session->frame_rate;
1513 }
1514
1515 int EDL::get_video_layers()
1516 {
1517         return 1;
1518 }
1519
1520 int64_t EDL::get_video_frames()
1521 {
1522         return (int64_t)(tracks->total_playable_length() *
1523                 session->frame_rate);
1524 }
1525
1526
1527 void EDL::remove_vwindow_edls()
1528 {
1529         for(int i = 0; i < total_vwindow_edls(); i++)
1530         {
1531                 get_vwindow_edl(i)->Garbage::remove_user();
1532         }
1533         vwindow_edls.remove_all();
1534 }
1535
1536 void EDL::remove_vwindow_edl(EDL *edl)
1537 {
1538         if(vwindow_edls.number_of(edl) >= 0)
1539         {
1540                 edl->Garbage::remove_user();
1541
1542                 vwindow_edls.remove(edl);
1543         }
1544 }
1545
1546
1547 EDL* EDL::get_vwindow_edl(int number)
1548 {
1549         return vwindow_edls.get(number);
1550 }
1551
1552 int EDL::total_vwindow_edls()
1553 {
1554         return vwindow_edls.size();
1555 }
1556
1557 void EDL::append_vwindow_edl(EDL *edl, int increase_counter)
1558 {
1559         if(vwindow_edls.number_of(edl) >= 0) return;
1560
1561         if(increase_counter) edl->Garbage::add_user();
1562         vwindow_edls.append(edl);
1563 }
1564
1565