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