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