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