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