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