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