7d04cc8dc856e10adf34e7e4acade124af892f6b
[goodguy/cinelerra.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.h"
28 #include "bccmodels.h"
29 #include "bchash.h"
30 #include "bcsignals.h"
31 #include "clip.h"
32 #include "cstrdup.h"
33 #include "clipedls.h"
34 #include "edits.h"
35 #include "edl.h"
36 #include "edlsession.h"
37 #include "filexml.h"
38 #include "floatauto.h"
39 #include "floatautos.h"
40 #include "guicast.h"
41 #include "keyframe.h"
42 #include "keyframes.h"
43 #include "indexstate.h"
44 #include "labels.h"
45 #include "localsession.h"
46 #include "maskautos.h"
47 #include "mutex.h"
48 #include "panauto.h"
49 #include "panautos.h"
50 #include "playbackconfig.h"
51 #include "playabletracks.h"
52 #include "plugin.h"
53 #include "pluginset.h"
54 #include "preferences.h"
55 #include "recordconfig.h"
56 #include "recordlabel.h"
57 #include "sharedlocation.h"
58 #include "theme.h"
59 #include "tracks.h"
60 #include "transportque.inc"
61 #include "versioninfo.h"
62 #include "vedit.h"
63 #include "vtrack.h"
64
65
66
67
68 EDL::EDL(EDL *parent_edl)
69  : Indexable(0)
70 {
71         this->parent_edl = parent_edl;
72         tracks = 0;
73         labels = 0;
74         local_session = 0;
75         id = next_id();
76         path[0] = 0;
77 }
78
79
80 EDL::~EDL()
81 {
82
83         delete tracks;
84         delete labels;
85         delete local_session;
86         remove_vwindow_edls();
87         if( !parent_edl ) {
88                 delete assets;
89                 delete session;
90         }
91 }
92
93
94 void EDL::create_objects()
95 {
96         tracks = new Tracks(this);
97         assets = !parent_edl ? new Assets(this) : parent_edl->assets;
98         session = !parent_edl ? new EDLSession(this) : parent_edl->session;
99         local_session = new LocalSession(this);
100         labels = new Labels(this, "LABELS");
101 }
102
103 EDL& EDL::operator=(EDL &edl)
104 {
105 printf("EDL::operator= 1\n");
106         copy_all(&edl);
107         return *this;
108 }
109
110 int EDL::load_defaults(BC_Hash *defaults)
111 {
112         if( !parent_edl )
113                 session->load_defaults(defaults);
114
115         local_session->load_defaults(defaults);
116         return 0;
117 }
118
119 int EDL::save_defaults(BC_Hash *defaults)
120 {
121         if( !parent_edl )
122                 session->save_defaults(defaults);
123
124         local_session->save_defaults(defaults);
125         return 0;
126 }
127
128 void EDL::boundaries()
129 {
130         session->boundaries();
131         local_session->boundaries();
132 }
133
134 int EDL::create_default_tracks()
135 {
136
137         for( int i=0; i<session->video_tracks; ++i ) {
138                 tracks->add_video_track(0, 0);
139         }
140         for( int i=0; i<session->audio_tracks; ++i ) {
141                 tracks->add_audio_track(0, 0);
142         }
143         return 0;
144 }
145
146 int EDL::load_xml(FileXML *file, uint32_t load_flags)
147 {
148         int result = 0;
149         folders.clear();
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("FOLDERS") ) {
239                                 result = folders.load_xml(file);
240                         }
241                         else
242                         if( file->tag.title_is("MIXERS") ) {
243                                 if( (load_flags & LOAD_SESSION) )
244                                         mixers.load(file);
245                                 else
246                                         result = file->skip_tag();
247                         }
248                         else
249                         if( file->tag.title_is("ASSETS") ) {
250                                 if( load_flags & LOAD_ASSETS )
251                                         assets->load(file, load_flags);
252                                 else
253                                         result = file->skip_tag();
254                         }
255                         else
256                         if( file->tag.title_is(labels->xml_tag) ) {
257                                 if( load_flags & LOAD_TIMEBAR )
258                                         labels->load(file, load_flags);
259                                 else
260                                         result = file->skip_tag();
261                         }
262                         else
263                         if( file->tag.title_is("LOCALSESSION") ) {
264                                 if( (load_flags & LOAD_SESSION) ||
265                                         (load_flags & LOAD_TIMEBAR) )
266                                         local_session->load_xml(file, load_flags);
267                                 else
268                                         result = file->skip_tag();
269                         }
270                         else
271                         if( file->tag.title_is("SESSION") ) {
272                                 if( (load_flags & LOAD_SESSION) &&
273                                         !parent_edl )
274                                         session->load_xml(file, 0, load_flags);
275                                 else
276                                         result = file->skip_tag();
277                         }
278                         else
279                         if( file->tag.title_is("TRACK") ) {
280                                 tracks->load(file, track_offset, load_flags);
281                         }
282                         else
283 // Sub EDL.
284 // Causes clip creation to fail because that involves an opening EDL tag.
285                         if( file->tag.title_is("CLIP_EDL") && !parent_edl ) {
286                                 EDL *new_edl = new EDL(this);
287                                 new_edl->create_objects();
288                                 new_edl->read_xml(file, LOAD_ALL);
289                                 if( (load_flags & LOAD_ALL) == LOAD_ALL )
290                                         clips.add_clip(new_edl);
291                                 new_edl->remove_user();
292                         }
293                         else
294                         if( file->tag.title_is("NESTED_EDL") ) {
295                                 EDL *nested_edl = new EDL;
296                                 nested_edl->create_objects();
297                                 nested_edl->read_xml(file, LOAD_ALL);
298                                 if( (load_flags & LOAD_ALL) == LOAD_ALL )
299                                         nested_edls.get_nested(nested_edl);
300                                 nested_edl->remove_user();
301                         }
302                         else
303                         if( file->tag.title_is("VWINDOW_EDL") && !parent_edl ) {
304                                 EDL *new_edl = new EDL(this);
305                                 new_edl->create_objects();
306                                 new_edl->read_xml(file, LOAD_ALL);
307
308
309                                 if( (load_flags & LOAD_ALL) == LOAD_ALL ) {
310 //                                              if( vwindow_edl && !vwindow_edl_shared )
311 //                                                      vwindow_edl->remove_user();
312 //                                              vwindow_edl_shared = 0;
313 //                                              vwindow_edl = new_edl;
314
315                                         append_vwindow_edl(new_edl, 0);
316
317                                 }
318                                 else
319 // Discard if not replacing EDL
320                                 {
321                                         new_edl->remove_user();
322                                         new_edl = 0;
323                                 }
324                         }
325                 }
326         } while(!result);
327
328         boundaries();
329 //dump();
330
331         return 0;
332 }
333
334 // Output path is the path of the output file if name truncation is desired.
335 // It is a "" if complete names should be used.
336 // Called recursively by copy for clips, thus the string can't be terminated.
337 // The string is not terminated in this call.
338 int EDL::save_xml(FileXML *file, const char *output_path)
339 {
340         copy(COPY_EDL, file, output_path, 0);
341         return 0;
342 }
343
344 int EDL::copy_all(EDL *edl)
345 {
346         if( this == edl ) return 0;
347         folder_no = edl->folder_no;
348         update_index(edl);
349         copy_session(edl);
350         copy_assets(edl);
351         copy_clips(edl);
352         copy_nested(edl);
353         copy_mixers(edl);
354         tracks->copy_from(edl->tracks);
355         labels->copy_from(edl->labels);
356         return 0;
357 }
358
359 void EDL::copy_clips(EDL *edl)
360 {
361         if( this == edl ) return;
362
363         remove_vwindow_edls();
364
365 //      if( vwindow_edl && !vwindow_edl_shared )
366 //              vwindow_edl->remove_user();
367 //      vwindow_edl = 0;
368 //      vwindow_edl_shared = 0;
369
370         for( int i=0; i<edl->total_vwindow_edls(); ++i ) {
371                 EDL *new_edl = new EDL(this);
372                 new_edl->create_objects();
373                 new_edl->copy_all(edl->get_vwindow_edl(i));
374                 append_vwindow_edl(new_edl, 0);
375         }
376
377         clips.clear();
378         for( int i=0; i<edl->clips.size(); ++i ) add_clip(edl->clips[i]);
379 }
380
381 void EDL::copy_nested(EDL *edl)
382 {
383         if( this == edl ) return;
384         nested_edls.copy_nested(edl->nested_edls);
385 }
386
387 void EDL::copy_assets(EDL *edl)
388 {
389         if( this == edl ) return;
390
391         if( !parent_edl ) {
392                 assets->copy_from(edl->assets);
393         }
394 }
395
396 void EDL::copy_mixers(EDL *edl)
397 {
398         if( this == edl ) return;
399         mixers.copy_from(edl->mixers);
400 }
401
402 void EDL::copy_session(EDL *edl, int session_only)
403 {
404         if( this == edl ) return;
405
406         if( !session_only ) {
407                 strcpy(this->path, edl->path);
408                 folders.copy_from(&edl->folders);
409         }
410
411         if( !parent_edl ) {
412                 session->copy(edl->session);
413         }
414
415         if( session_only <= 0 ) {
416                 local_session->copy_from(edl->local_session);
417         }
418 }
419
420 int EDL::copy_assets(int copy_flags, double start, double end,
421                 FileXML *file, const char *output_path)
422 {
423         ArrayList<Asset*> asset_list;
424         Track* current;
425
426         file->tag.set_title("ASSETS");
427         file->append_tag();
428         file->append_newline();
429
430 // Copy everything for a save
431         if( (copy_flags & COPY_ALL_ASSETS) ) {
432                 for( Asset *asset=assets->first; asset; asset=asset->next ) {
433                         asset_list.append(asset);
434                 }
435         }
436         if( (copy_flags & COPY_USED_ASSETS) ) {
437 // Copy just the ones being used.
438                 for( current = tracks->first; current; current = NEXT ) {
439                         if( !current->record ) continue;
440                         current->copy_assets(start, end, &asset_list);
441                 }
442         }
443
444 // Paths relativised here
445         for( int i=0; i<asset_list.size(); ++i ) {
446                 asset_list[i]->write(file, 0, output_path);
447         }
448
449         file->tag.set_title("/ASSETS");
450         file->append_tag();
451         file->append_newline();
452         file->append_newline();
453         return 0;
454 }
455
456
457 int EDL::copy(int copy_flags, double start, double end,
458         FileXML *file, const char *output_path, int rewind_it)
459 {
460         file->tag.set_title("EDL");
461         file->tag.set_property("VERSION", CINELERRA_VERSION);
462 // Save path for restoration of the project title from a backup.
463         if( this->path[0] ) file->tag.set_property("PATH", path);
464         return copy_xml(copy_flags, start, end, file, "/EDL", output_path, rewind_it);
465 }
466 int EDL::copy(int copy_flags, FileXML *file, const char *output_path, int rewind_it)
467 {
468         return copy(copy_flags, 0., tracks->total_length(),
469                 file, output_path, rewind_it);
470 }
471
472 int EDL::copy_clip(int copy_flags, double start, double end,
473         FileXML *file, const char *output_path, int rewind_it)
474 {
475         file->tag.set_title("CLIP_EDL");
476         return copy_xml(copy_flags, start, end, file, "/CLIP_EDL", output_path, rewind_it);
477 }
478 int EDL::copy_clip(int copy_flags, FileXML *file, const char *output_path, int rewind_it)
479 {
480         return copy_clip(copy_flags, 0., tracks->total_length(),
481                 file, output_path, rewind_it);
482 }
483
484 int EDL::copy_nested(int copy_flags, double start, double end,
485         FileXML *file, const char *output_path, int rewind_it)
486 {
487         file->tag.set_title("NESTED_EDL");
488         if( this->path[0] ) file->tag.set_property("PATH", path);
489         return copy_xml(copy_flags, start, end, file, "/NESTED_EDL", output_path, rewind_it);
490 }
491 int EDL::copy_nested(int copy_flags, FileXML *file, const char *output_path, int rewind_it)
492 {
493         return copy_nested(copy_flags, 0., tracks->total_length(),
494                 file, output_path, rewind_it);
495 }
496
497 int EDL::copy_vwindow(int copy_flags, double start, double end,
498         FileXML *file, const char *output_path, int rewind_it)
499 {
500         file->tag.set_title("VWINDOW_EDL");
501         return copy_xml(copy_flags, start, end, file, "/VWINDOW_EDL", output_path, rewind_it);
502 }
503 int EDL::copy_vwindow(int copy_flags, FileXML *file, const char *output_path, int rewind_it)
504 {
505         return copy_vwindow(copy_flags, 0., tracks->total_length(),
506                 file, output_path, rewind_it);
507 }
508
509 int EDL::copy_xml(int copy_flags, double start, double end,
510          FileXML *file, const char *closer, const char *output_path,
511         int rewind_it)
512 {
513         file->append_tag();
514         file->append_newline();
515 // Set clipboard samples only if copying to clipboard
516         if( (copy_flags & COPY_LENGTH) ) {
517                 file->tag.set_title("CLIPBOARD");
518                 file->tag.set_property("LENGTH", end - start);
519                 file->append_tag();
520                 file->tag.set_title("/CLIPBOARD");
521                 file->append_tag();
522                 file->append_newline();
523                 file->append_newline();
524         }
525 //printf("EDL::copy 1\n");
526
527 // Sessions
528         if( (copy_flags & COPY_LOCAL_SESSION) )
529                 local_session->save_xml(file, start);
530
531 // Top level stuff.
532 // Need to copy all this from child EDL if pasting is desired.
533
534         if( (copy_flags & COPY_SESSION) )
535                 session->save_xml(file);
536
537         if( (copy_flags & COPY_VIDEO_CONFIG) )
538                 session->save_video_config(file);
539
540         if( (copy_flags & COPY_AUDIO_CONFIG) )
541                 session->save_audio_config(file);
542
543         if( (copy_flags & COPY_FOLDERS) )
544                 folders.save_xml(file);
545
546         if( (copy_flags & (COPY_ALL_ASSETS | COPY_USED_ASSETS)) )
547                 copy_assets(copy_flags, start, end, file, output_path);
548
549         if( (copy_flags & COPY_NESTED_EDL) ) {
550                 for( int i=0; i<nested_edls.size(); ++i )
551                         nested_edls[i]->copy_nested(copy_flags,
552                                 file, output_path, 0);
553         }
554 // Clips
555         if( (copy_flags & COPY_CLIPS) ) {
556                 for( int i=0; i<clips.size(); ++i )
557                         clips[i]->copy_clip(copy_flags, file, output_path, 0);
558         }
559
560         if( (copy_flags & COPY_VWINDOWS) ) {
561                 for( int i=0; i<total_vwindow_edls(); ++i )
562                         get_vwindow_edl(i)->copy_vwindow(copy_flags,
563                                 file, output_path, 0);
564         }
565
566         if( (copy_flags & COPY_MIXERS) )
567                 mixers.save(file);
568
569         file->append_newline();
570         file->append_newline();
571
572         if( (copy_flags & COPY_LABELS) )
573                 labels->copy(start, end, file);
574
575         tracks->copy(copy_flags, start, end, file, output_path);
576
577 // terminate file
578         file->tag.set_title(closer);
579         file->append_tag();
580         file->append_newline();
581
582 // For editing operations we want to rewind it for immediate pasting.
583 // For clips and saving to disk leave it alone.
584         if( rewind_it ) {
585                 file->terminate_string();
586                 file->rewind();
587         }
588         return 0;
589 }
590
591 void EDL::copy_indexables(EDL *edl)
592 {
593         for( Track *track=edl->tracks->first; track; track=track->next ) {
594                 for( Edit *edit=track->edits->first; edit; edit=edit->next ) {
595                         if( edit->asset )
596                                 assets->update(edit->asset);
597                         if( edit->nested_edl )
598                                 nested_edls.get_nested(edit->nested_edl);
599                 }
600         }
601 }
602
603 EDL *EDL::new_nested(EDL *edl, const char *path)
604 {
605         EDL *nested = new EDL;  // no parent for nested edl
606         nested->create_objects();
607         nested->copy_session(edl);
608         nested->set_path(path);
609         nested->update_index(edl);
610         nested->copy_indexables(edl);
611         nested->tracks->copy_from(edl->tracks);
612         nested_edls.append(nested);
613         return nested;
614 }
615
616 EDL *EDL::create_nested_clip(EDL *nested)
617 {
618         EDL *new_edl = new EDL(this);  // parent for clip edl
619         new_edl->create_objects();
620         new_edl->create_nested(nested);
621         return new_edl;
622 }
623
624 void EDL::create_nested(EDL *nested)
625 {
626 // Keep frame rate, sample rate, and output size unchanged.
627 // Nest all video & audio outputs
628         session->video_tracks = 1;
629         session->audio_tracks = nested->session->audio_channels;
630         create_default_tracks();
631         insert_asset(0, nested, 0, 0, 0);
632 }
633
634 void EDL::retrack()
635 {
636         int min_w = session->output_w, min_h = session->output_h;
637         for( Track *track=tracks->first; track!=0; track=track->next ) {
638                 if( track->data_type != TRACK_VIDEO ) continue;
639                 int w = min_w, h = min_h;
640                 for( Edit *current=track->edits->first; current!=0; current=NEXT ) {
641                         Indexable* indexable = current->get_source();
642                         if( !indexable ) continue;
643                         int edit_w = indexable->get_w(), edit_h = indexable->get_h();
644                         if( w < edit_w ) w = edit_w;
645                         if( h < edit_h ) h = edit_h;
646                 }
647                 if( track->track_w == w && track->track_h == h ) continue;
648                 ((MaskAutos*)track->automation->autos[AUTOMATION_MASK])->
649                         translate_masks( (w - track->track_w) / 2, (h - track->track_h) / 2);
650                 track->track_w = w;  track->track_h = h;
651         }
652 }
653
654 void EDL::rechannel()
655 {
656         for( Track *current=tracks->first; current; current=NEXT ) {
657                 if( current->data_type == TRACK_AUDIO ) {
658                         PanAutos *autos = (PanAutos*)current->automation->autos[AUTOMATION_PAN];
659                         ((PanAuto*)autos->default_auto)->rechannel();
660                         for( PanAuto *keyframe = (PanAuto*)autos->first;
661                              keyframe; keyframe = (PanAuto*)keyframe->next ) {
662                                 keyframe->rechannel();
663                         }
664                 }
665         }
666 }
667
668 void EDL::resample(double old_rate, double new_rate, int data_type)
669 {
670         for( Track *current=tracks->first; current; current=NEXT ) {
671                 if( current->data_type == data_type ) {
672                         current->resample(old_rate, new_rate);
673                 }
674         }
675 }
676
677
678 void EDL::synchronize_params(EDL *edl)
679 {
680         local_session->synchronize_params(edl->local_session);
681         for( Track *this_track=tracks->first, *that_track=edl->tracks->first;
682              this_track && that_track;
683              this_track=this_track->next, that_track=that_track->next ) {
684                 this_track->synchronize_params(that_track);
685         }
686 }
687
688 int EDL::trim_selection(double start,
689         double end,
690         int edit_labels,
691         int edit_plugins,
692         int edit_autos)
693 {
694         if( start != end ) {
695 // clear the data
696                 clear(0,
697                         start,
698                         edit_labels,
699                         edit_plugins,
700                         edit_autos);
701                 clear(end - start,
702                         tracks->total_length(),
703                         edit_labels,
704                         edit_plugins,
705                         edit_autos);
706         }
707         return 0;
708 }
709
710
711 int EDL::equivalent(double position1, double position2)
712 {
713         double threshold = session->cursor_on_frames ?
714                 0.5 / session->frame_rate : 1.0 / session->sample_rate;
715         return fabs(position2 - position1) < threshold ? 1 : 0;
716 }
717
718 double EDL::equivalent_output(EDL *edl)
719 {
720         double result = -1;
721         session->equivalent_output(edl->session, &result);
722         tracks->equivalent_output(edl->tracks, &result);
723         return result;
724 }
725
726
727 void EDL::set_path(const char *path)
728 {
729         if( &this->path[0] == path ) return;
730         strcpy(this->path, path);
731 }
732
733 void EDL::set_inpoint(double position)
734 {
735         if( equivalent(local_session->get_inpoint(), position) &&
736                 local_session->get_inpoint() >= 0 ) {
737                 local_session->unset_inpoint();
738         }
739         else {
740                 local_session->set_inpoint(align_to_frame(position, 0));
741                 if( local_session->get_outpoint() <= local_session->get_inpoint() )
742                         local_session->unset_outpoint();
743         }
744 }
745
746 void EDL::set_outpoint(double position)
747 {
748         if( equivalent(local_session->get_outpoint(), position) &&
749                 local_session->get_outpoint() >= 0 ) {
750                 local_session->unset_outpoint();
751         }
752         else {
753                 local_session->set_outpoint(align_to_frame(position, 0));
754                 if( local_session->get_inpoint() >= local_session->get_outpoint() )
755                         local_session->unset_inpoint();
756         }
757 }
758
759 void EDL::unset_inoutpoint()
760 {
761         local_session->unset_inpoint();
762         local_session->unset_outpoint();
763 }
764
765 int EDL::blade(double position)
766 {
767         return tracks->blade(position);
768 }
769
770 int EDL::clear(double start, double end,
771         int clear_labels, int clear_plugins, int edit_autos)
772 {
773         if( start == end ) {
774                 double distance = 0;
775                 tracks->clear_handle(start,
776                         end,
777                         distance,
778                         clear_labels,
779                         clear_plugins,
780                         edit_autos);
781                 if( clear_labels && distance > 0 )
782                         labels->paste_silence(start,
783                                 start + distance);
784         }
785         else {
786                 tracks->clear(start,
787                         end,
788                         clear_plugins,
789                         edit_autos);
790                 if( clear_labels )
791                         labels->clear(start,
792                                 end,
793                                 1);
794         }
795
796 // Need to put at beginning so a subsequent paste operation starts at the
797 // right position.
798         double position = local_session->get_selectionstart();
799         local_session->set_selectionend(position);
800         local_session->set_selectionstart(position);
801         return 0;
802 }
803
804 int EDL::clear_hard_edges(double start, double end)
805 {
806         return tracks->clear_hard_edges(start, end);
807 }
808
809 static int dead_edit_cmp(Edit**ap, Edit**bp)
810 {
811         Edit *a = *ap, *b = *bp;
812         if( a->track != b->track ) return 0;
813         return a->startproject > b->startproject ? -1 : 1;
814 }
815
816 void EDL::delete_edits(ArrayList<Edit*> *edits, int collapse)
817 {
818         edits->sort(dead_edit_cmp);
819         for( int i=0; i<edits->size(); ++i ) {
820                 Edit *edit = edits->get(i);
821                 Track *track = edit->track;
822                 int64_t start = edit->startproject;
823                 int64_t length = edit->length;
824                 int64_t end = start + length;
825                 if( session->autos_follow_edits ) {
826                         track->automation->clear(start, end, 0, collapse);
827                 }
828                 if( session->plugins_follow_edits ) {
829                         for( int k=0; k<track->plugin_set.size(); ++k ) {
830                                 PluginSet *plugin_set = track->plugin_set[k];
831                                 plugin_set->clear(start, end, 1);
832                                 if( !collapse )
833                                         plugin_set->paste_silence(start, end, 1);
834                                 plugin_set->optimize();
835                         }
836                 }
837                 Edit *dead_edit = edit;
838                 if( collapse ) {
839                         while( (edit=edit->next) )
840                                 edit->startproject -= length;
841                 }
842                 delete dead_edit;
843         }
844         optimize();
845 }
846
847 class Range {
848 public:
849         static int cmp(Range *ap, Range *bp);
850         double start, end;
851         bool operator ==(Range &that) { return this->start == that.start; }
852         bool operator >(Range &that) { return this->start > that.start; }
853 };
854 int Range::cmp(Range *ap, Range *bp) {
855         return ap->start < bp->start ? -1 : ap->start == bp->start ? 0 : 1;
856 }
857
858 static void get_edit_regions(ArrayList<Edit*> *edits, ArrayList<Range> &regions)
859 {
860 // move edit inclusive labels by regions
861         for( int i=0; i<edits->size(); ++i ) {
862                 Edit *edit = edits->get(i);
863                 double pos = edit->track->from_units(edit->startproject);
864                 double end = edit->track->from_units(edit->startproject + edit->length);
865                 int n = regions.size(), k = n;
866                 while( --k >= 0 ) {
867                         Range &range = regions[k];
868                         if( pos >= range.end ) continue;
869                         if( range.start >= end ) continue;
870                         int expand = 0;
871                         if( range.start > pos ) { range.start = pos;  expand = 1; }
872                         if( range.end < end ) { range.end = end;  expand = 1; }
873                         if( !expand ) break;
874                         k = n;
875                 }
876                 if( k < 0 ) {
877                         Range &range = regions.append();
878                         range.start = pos;  range.end = end;
879                 }
880         }
881         regions.sort(Range::cmp);
882 }
883
884 void EDL::delete_edit_labels(ArrayList<Edit*> *edits, int collapse)
885 {
886         ArrayList<Range> regions;
887         get_edit_regions(edits, regions);
888         int n = regions.size(), k = n;
889         while( --k >= 0 ) {
890                 Range &range = regions[k];
891                 labels->clear(range.start, range.end, collapse);
892         }
893 }
894
895 void EDL::move_edit_labels(ArrayList<Edit*> *edits, double dist)
896 {
897         ArrayList<Range> regions;
898         get_edit_regions(edits, regions);
899         int n = regions.size(), k = n;
900         Labels moved(this, 0);
901         while( --k >= 0 ) {
902                 Range &range = regions[k];
903                 Label *label = labels->label_of(range.start);
904                 for( Label *next=0; label && label->position <= range.end; label=next ) {
905                         next = label->next;
906                         labels->remove_pointer(label);
907                         label->position += dist;
908                         moved.append(label);
909                 }
910                 Label *current = labels->first;
911                 while( (label=moved.first) ) {
912                         moved.remove_pointer(label);
913                         while( current && current->position < label->position )
914                                 current = current->next;
915                         if( current && current->position == label->position ) {
916                                 delete label;  continue;
917                         }
918                         labels->insert_before(current, label);
919                 }
920         }
921 }
922
923 void EDL::modify_edithandles(double oldposition, double newposition,
924         int currentend, int handle_mode, int edit_labels,
925         int edit_plugins, int edit_autos, int group_id)
926 {
927         tracks->modify_edithandles(oldposition, newposition,
928                 currentend, handle_mode, edit_labels,
929                 edit_plugins, edit_autos, group_id);
930 }
931
932 void EDL::modify_pluginhandles(double oldposition, double newposition,
933         int currentend, int handle_mode, int edit_labels,
934         int edit_autos, Edits *trim_edits)
935 {
936         tracks->modify_pluginhandles(oldposition, newposition,
937                 currentend, handle_mode, edit_labels,
938                 edit_autos, trim_edits);
939         optimize();
940 }
941
942 void EDL::paste_silence(double start, double end,
943         int edit_labels, int edit_plugins, int edit_autos)
944 {
945         if( edit_labels )
946                 labels->paste_silence(start, end);
947         tracks->paste_silence(start, end, edit_plugins, edit_autos);
948 }
949
950
951 void EDL::remove_from_project(ArrayList<EDL*> *clips)
952 {
953         for( int i=0; i<clips->size(); ++i ) {
954                 this->clips.remove_clip(clips->get(i));
955         }
956 }
957
958 void EDL::remove_from_project(ArrayList<Indexable*> *assets)
959 {
960 // Remove from clips
961         if( !parent_edl )
962                 for( int j=0; j<clips.size(); ++j ) {
963                         clips[j]->remove_from_project(assets);
964                 }
965
966 // Remove from VWindow EDLs
967         for( int i=0; i<total_vwindow_edls(); ++i )
968                 get_vwindow_edl(i)->remove_from_project(assets);
969
970         for( int i=0; i<assets->size(); ++i ) {
971 // Remove from tracks
972                 for( Track *track=tracks->first; track; track=track->next ) {
973                         track->remove_asset(assets->get(i));
974                 }
975
976 // Remove from assets
977                 if( !parent_edl && assets->get(i)->is_asset ) {
978                         this->assets->remove_asset((Asset*)assets->get(i));
979                 }
980                 else
981                 if( !parent_edl && !assets->get(i)->is_asset ) {
982                         this->nested_edls.remove_clip((EDL*)assets->get(i));
983                 }
984         }
985 }
986
987 void EDL::update_assets(EDL *src)
988 {
989         for( Asset *current=src->assets->first; current; current=NEXT ) {
990                 assets->update(current);
991         }
992 }
993
994 int EDL::get_tracks_height(Theme *theme)
995 {
996         int total_pixels = 0;
997         for( Track *current=tracks->first; current; current=NEXT ) {
998                 total_pixels += current->vertical_span(theme);
999         }
1000         return total_pixels;
1001 }
1002
1003 int64_t EDL::get_tracks_width()
1004 {
1005         int64_t total_pixels = 0;
1006         for( Track *current=tracks->first; current; current=NEXT ) {
1007                 int64_t pixels = current->horizontal_span();
1008                 if( pixels > total_pixels ) total_pixels = pixels;
1009         }
1010 //printf("EDL::get_tracks_width %d\n", total_pixels);
1011         return total_pixels;
1012 }
1013
1014 // int EDL::calculate_output_w(int single_channel)
1015 // {
1016 //      if( single_channel ) return session->output_w;
1017 //
1018 //      int widest = 0;
1019 //      for( int i=0; i<session->video_channels; ++i )
1020 //      {
1021 //              if( session->vchannel_x[i] + session->output_w > widest ) widest = session->vchannel_x[i] + session->output_w;
1022 //      }
1023 //      return widest;
1024 // }
1025 //
1026 // int EDL::calculate_output_h(int single_channel)
1027 // {
1028 //      if( single_channel ) return session->output_h;
1029 //
1030 //      int tallest = 0;
1031 //      for( int i=0; i<session->video_channels; ++i )
1032 //      {
1033 //              if( session->vchannel_y[i] + session->output_h > tallest ) tallest = session->vchannel_y[i] + session->output_h;
1034 //      }
1035 //      return tallest;
1036 // }
1037
1038 // Get the total output size scaled to aspect ratio
1039 void EDL::calculate_conformed_dimensions(int single_channel, float &w, float &h)
1040 {
1041         if( (float)session->output_w / session->output_h > get_aspect_ratio() )
1042                 h = (w = session->output_w) / get_aspect_ratio();
1043         else
1044                 w = (h = session->output_h) * get_aspect_ratio();
1045 }
1046
1047 float EDL::get_aspect_ratio()
1048 {
1049         return session->aspect_w / session->aspect_h;
1050 }
1051
1052 int EDL::dump(FILE *fp)
1053 {
1054         if( parent_edl )
1055                 fprintf(fp,"CLIP\n");
1056         else
1057                 fprintf(fp,"EDL\n");
1058         fprintf(fp,"  clip_title: %s\n"
1059                 "  parent_edl: %p\n", local_session->clip_title, parent_edl);
1060         fprintf(fp,"  selectionstart %f\n  selectionend %f\n  loop_start %f\n  loop_end %f\n",
1061                 local_session->get_selectionstart(1),
1062                 local_session->get_selectionend(1),
1063                 local_session->loop_start,
1064                 local_session->loop_end);
1065         for( int i=0; i<TOTAL_PANES; ++i ) {
1066                 fprintf(fp,"  pane %d view_start=%jd track_start=%d\n", i,
1067                         local_session->view_start[i],
1068                         local_session->track_start[i]);
1069         }
1070
1071         if( !parent_edl ) {
1072                 fprintf(fp,"audio_channels: %d audio_tracks: %d sample_rate: %jd\n",
1073                         session->audio_channels,
1074                         session->audio_tracks,
1075                         session->sample_rate);
1076                 fprintf(fp,"  video_channels: %d\n"
1077                         "  video_tracks: %d\n"
1078                         "  frame_rate: %.2f\n"
1079                         "  frames_per_foot: %.2f\n"
1080                         "  output_w: %d\n"
1081                         "  output_h: %d\n"
1082                         "  aspect_w: %f\n"
1083                         "  aspect_h: %f\n"
1084                         "  color_model: %d\n",
1085                                 session->video_channels,
1086                                 session->video_tracks,
1087                                 session->frame_rate,
1088                                 session->frames_per_foot,
1089                                 session->output_w,
1090                                 session->output_h,
1091                                 session->aspect_w,
1092                                 session->aspect_h,
1093                                 session->color_model);
1094
1095                 fprintf(fp," CLIPS");
1096                 fprintf(fp,"  total: %d\n", clips.size());
1097                 for( int i=0; i<clips.size(); ++i ) {
1098                         fprintf(fp,"\n\n");
1099                         clips[i]->dump(fp);
1100                         fprintf(fp,"\n\n");
1101                 }
1102                 fprintf(fp," NESTED_EDLS");
1103                 fprintf(fp,"  total: %d\n", nested_edls.size());
1104                 for( int i=0; i<nested_edls.size(); ++i )
1105                         fprintf(fp,"   %s\n", nested_edls[i]->path);
1106
1107                 fprintf(fp," VWINDOW EDLS");
1108                 fprintf(fp,"  total: %d\n", total_vwindow_edls());
1109
1110                 for( int i=0; i<total_vwindow_edls(); ++i ) {
1111                         fprintf(fp,"   %s\n", get_vwindow_edl(i)->local_session->clip_title);
1112                 }
1113
1114                 fprintf(fp," ASSETS\n");
1115                 assets->dump(fp);
1116         }
1117         fprintf(fp," LABELS\n");
1118         labels->dump(fp);
1119         fprintf(fp," TRACKS\n");
1120         tracks->dump(fp);
1121 //printf("EDL::dump 2\n");
1122         return 0;
1123 }
1124
1125 EDL* EDL::add_clip(EDL *edl)
1126 {
1127 // Copy argument.  New edls are deleted from MWindow::load_filenames.
1128         EDL *new_edl = new EDL(this);
1129         new_edl->create_objects();
1130         new_edl->copy_all(edl);
1131         new_edl->folder_no = AW_CLIP_FOLDER;
1132         clips.append(new_edl);
1133         return new_edl;
1134 }
1135
1136 void EDL::insert_asset(Asset *asset,
1137         EDL *nested_edl,
1138         double position,
1139         Track *first_track,
1140         RecordLabels *labels)
1141 {
1142 // Insert asset into asset table
1143         Asset *new_asset = 0;
1144         EDL *new_nested_edl = 0;
1145
1146         if( asset ) new_asset = assets->update(asset);
1147         if( nested_edl ) new_nested_edl = nested_edls.get_nested(nested_edl);
1148
1149 // Paste video
1150         int vtrack = 0;
1151         Track *current = first_track ? first_track : tracks->first;
1152
1153
1154 // Fix length of single frame
1155         double length = 0.;
1156         int layers = 0;
1157         int channels = 0;
1158
1159         if( new_nested_edl ) {
1160                 length = new_nested_edl->tracks->total_length();
1161                 layers = 1;
1162                 channels = new_nested_edl->session->audio_channels;
1163         }
1164
1165         if( new_asset ) {
1166 // Insert 1 frame for undefined length
1167                 if( new_asset->video_length < 0 ) {
1168                         length = session->si_useduration ?
1169                                 session->si_duration :
1170                                 1.0 / session->frame_rate;
1171                 }
1172                 else {
1173                         length = new_asset->frame_rate > 0 ?
1174                                 (double)new_asset->video_length / new_asset->frame_rate :
1175                                 1.0 / session->frame_rate;
1176                 }
1177                 layers = new_asset->layers;
1178                 channels = new_asset->channels;
1179         }
1180
1181         for( ; current && vtrack<layers; current=NEXT ) {
1182                 if( !current->record || current->data_type != TRACK_VIDEO ) continue;
1183                 current->insert_asset(new_asset, new_nested_edl,
1184                         length, position, vtrack++);
1185         }
1186
1187         int atrack = 0;
1188         if( new_asset ) {
1189                 if( new_asset->audio_length < 0 ) {
1190 // Insert 1 frame for undefined length & video
1191                         if( new_asset->video_data )
1192                                 length = (double)1.0 / new_asset->frame_rate;
1193                         else
1194 // Insert 1 second for undefined length & no video
1195                                 length = 1.0;
1196                 }
1197                 else
1198                         length = (double)new_asset->audio_length /
1199                                         new_asset->sample_rate;
1200         }
1201
1202         current = tracks->first;
1203         for( ; current && atrack < channels; current=NEXT ) {
1204                 if( !current->record || current->data_type != TRACK_AUDIO ) continue;
1205                 current->insert_asset(new_asset, new_nested_edl,
1206                         length, position, atrack++);
1207         }
1208
1209 // Insert labels from a recording window.
1210         if( labels ) {
1211                 for( RecordLabel *label=labels->first; label; label=label->next ) {
1212                         this->labels->toggle_label(label->position, label->position);
1213                 }
1214         }
1215 }
1216
1217
1218
1219 void EDL::set_index_file(Indexable *indexable)
1220 {
1221         if( indexable->is_asset )
1222                 assets->update_index((Asset*)indexable);
1223         else
1224                 nested_edls.update_index((EDL*)indexable);
1225 }
1226
1227 void EDL::optimize()
1228 {
1229 //printf("EDL::optimize 1\n");
1230         double length = tracks->total_length();
1231         double preview_start = local_session->preview_start;
1232         double preview_end = local_session->preview_end;
1233         if( preview_end < 0 || preview_end > length )
1234                 preview_end = length;
1235         if( preview_start == 0 && preview_end >= length )
1236                 local_session->preview_end = -1;
1237         if( preview_start > preview_end )
1238                 local_session->preview_start = preview_end;
1239         for( Track *current=tracks->first; current; current=NEXT )
1240                 current->optimize();
1241 }
1242
1243 int EDL::next_id()
1244 {
1245         static Mutex id_lock;
1246         id_lock.lock("EDL::next_id");
1247         int result = EDLSession::current_id++;
1248         id_lock.unlock();
1249         return result;
1250 }
1251
1252 void EDL::get_shared_plugins(Track *source,
1253         ArrayList<SharedLocation*> *plugin_locations,
1254         int omit_recordable,
1255         int data_type)
1256 {
1257         for( Track *track=tracks->first; track; track=track->next ) {
1258                 if( track->record && omit_recordable ) continue;
1259                 if( track == source || track->data_type != data_type ) continue;
1260                 for( int i=0; i<track->plugin_set.size(); ++i ) {
1261                         Plugin *plugin = track->get_current_plugin(
1262                                 local_session->get_selectionstart(1),
1263                                 i, PLAY_FORWARD, 1, 0);
1264                         if( plugin && plugin->plugin_type != PLUGIN_STANDALONE ) continue;
1265                         plugin_locations->append(new SharedLocation(tracks->number_of(track), i));
1266                 }
1267         }
1268 }
1269
1270 void EDL::get_shared_tracks(Track *track,
1271         ArrayList<SharedLocation*> *module_locations,
1272         int omit_recordable, int data_type)
1273 {
1274         for( Track *current=tracks->first; current; current=NEXT ) {
1275                 if( omit_recordable && current->record ) continue;
1276                 if( current == track || current->data_type != data_type ) continue;
1277                 module_locations->append(new SharedLocation(tracks->number_of(current), 0));
1278         }
1279 }
1280
1281 // aligned frame time, account for sample truncation
1282 double EDL::frame_align(double position, int round)
1283 {
1284         if( !round && session->sample_rate > 0 ) {
1285                 int64_t sample_pos = position * session->sample_rate;
1286                 position = (sample_pos+2.) / session->sample_rate;
1287         }
1288         int64_t frame_pos = (position * session->frame_rate + (round ? 0.5 : 1e-6));
1289         return frame_pos / session->frame_rate;
1290 }
1291
1292 // Convert position to frames if alignment is enabled.
1293 double EDL::align_to_frame(double position, int round)
1294 {
1295         if( session->cursor_on_frames )
1296                 position = frame_align(position, round);
1297         return position;
1298 }
1299
1300
1301 BinFolder *EDL::get_folder(int no)
1302 {
1303         for( int i=0; i<folders.size(); ++i ) {
1304                 BinFolder *fp = folders[i];
1305                 if( no == fp->awindow_folder ) return fp;
1306         }
1307         return 0;
1308 }
1309
1310 int EDL::get_folder_number(const char *title)
1311 {
1312         for( int i=0; i<AWINDOW_FOLDERS; ++i ) {
1313                 if( !strcmp(title, AWindowGUI::folder_names[i]) )
1314                         return i;
1315         }
1316         for( int i=0; i<folders.size(); ++i ) {
1317                 if( !strcmp(title, folders[i]->title) )
1318                         return folders[i]->awindow_folder;
1319         }
1320         return AW_NO_FOLDER;
1321 }
1322
1323 const char *EDL::get_folder_name(int no)
1324 {
1325         if( no >= 0 && no<AWINDOW_FOLDERS )
1326                 return AWindowGUI::folder_names[no];
1327         BinFolder *fp = get_folder(no);
1328         return !fp ? "" : fp->title;
1329 }
1330
1331 int EDL::new_folder(const char *title, int is_clips)
1332 {
1333         if( !title[0] ) return 1;
1334         int ret = get_folder_number(title);
1335         if( ret >= 0 ) return 1;
1336         int idx = AWINDOW_FOLDERS;
1337         for( int i=0; i<folders.size(); ++i ) {
1338                 BinFolder *fp = folders[i];
1339                 int no = fp->awindow_folder;
1340                 if( no >= idx ) idx = no+1;
1341         }
1342         folders.append(new BinFolder(idx, is_clips, title));
1343         return 0;
1344 }
1345
1346 int EDL::delete_folder(const char *title)
1347 {
1348         int k = folders.size();
1349         while( --k >= 0 && strcmp(title, folders[k]->title) );
1350         if( k >= 0 )
1351                 folders.remove_object_number(k);
1352         return k;
1353 }
1354
1355 int EDL::get_use_vconsole(VEdit* *playable_edit,
1356         int64_t position, int direction, PlayableTracks *playable_tracks)
1357 {
1358         int share_playable_tracks = 1;
1359         int result = 0;
1360         VTrack *playable_track = 0;
1361         const int debug = 0;
1362         *playable_edit = 0;
1363
1364 // Calculate playable tracks when being called as a nested EDL
1365         if( !playable_tracks ) {
1366                 share_playable_tracks = 0;
1367                 playable_tracks = new PlayableTracks(this,
1368                         position, direction, TRACK_VIDEO, 1);
1369         }
1370
1371
1372 // Total number of playable tracks is 1
1373         if( playable_tracks->size() != 1 ) {
1374                 result = 1;
1375         }
1376         else {
1377                 playable_track = (VTrack*)playable_tracks->get(0);
1378         }
1379
1380 // Don't need playable tracks anymore
1381         if( !share_playable_tracks ) {
1382                 delete playable_tracks;
1383         }
1384
1385 if( debug ) printf("EDL::get_use_vconsole %d playable_tracks->size()=%d\n",
1386  __LINE__, playable_tracks->size());
1387         if( result ) return 1;
1388
1389
1390 // Test mutual conditions between direct copy rendering and this.
1391         if( !playable_track->direct_copy_possible(position,
1392                 direction,
1393                 1) )
1394                 return 1;
1395 if( debug ) printf("EDL::get_use_vconsole %d\n", __LINE__);
1396
1397         *playable_edit = (VEdit*)playable_track->edits->editof(position,
1398                 direction, 0);
1399 // No edit at current location
1400         if( !*playable_edit ) return 1;
1401 if( debug ) printf("EDL::get_use_vconsole %d\n", __LINE__);
1402
1403
1404 // Edit is nested EDL
1405         if( (*playable_edit)->nested_edl ) {
1406 // Test nested EDL
1407                 EDL *nested_edl = (*playable_edit)->nested_edl;
1408                 int64_t nested_position = (int64_t)((position -
1409                                 (*playable_edit)->startproject +
1410                                 (*playable_edit)->startsource) *
1411                         nested_edl->session->frame_rate /
1412                         session->frame_rate);
1413
1414
1415                 VEdit *playable_edit_temp = 0;
1416                 if( session->output_w != nested_edl->session->output_w ||
1417                         session->output_h != nested_edl->session->output_h ||
1418                         nested_edl->get_use_vconsole(&playable_edit_temp,
1419                                 nested_position,
1420                                 direction,
1421                                 0) )
1422                         return 1;
1423
1424                 return 0;
1425         }
1426
1427 if( debug ) printf("EDL::get_use_vconsole %d\n", __LINE__);
1428 // Edit is not a nested EDL
1429         Asset *asset = (*playable_edit)->asset;
1430 // Edit is silence
1431         if( !asset ) return 1;
1432 if( debug ) printf("EDL::get_use_vconsole %d\n", __LINE__);
1433
1434 // Asset and output device must have the same dimensions
1435         if( asset->width != session->output_w ||
1436             asset->height != session->output_h )
1437                 return 1;
1438
1439 if( debug ) printf("EDL::get_use_vconsole %d\n", __LINE__);
1440 // If we get here the frame is going to be directly copied.  Whether it is
1441 // decompressed in hardware depends on the colormodel.
1442         return 0;
1443 }
1444
1445
1446 // For Indexable
1447 int EDL::get_audio_channels()
1448 {
1449         return session->audio_channels;
1450 }
1451
1452 int EDL::get_sample_rate()
1453 {
1454         return session->sample_rate;
1455 }
1456
1457 int64_t EDL::get_audio_samples()
1458 {
1459         return (int64_t)(tracks->total_length() *
1460                 session->sample_rate);
1461 }
1462
1463 int EDL::have_audio()
1464 {
1465         return 1;
1466 }
1467
1468 int EDL::have_video()
1469 {
1470         return 1;
1471 }
1472
1473
1474 int EDL::get_w()
1475 {
1476         return session->output_w;
1477 }
1478
1479 int EDL::get_h()
1480 {
1481         return session->output_h;
1482 }
1483
1484 double EDL::get_frame_rate()
1485 {
1486         return session->frame_rate;
1487 }
1488
1489 int EDL::get_video_layers()
1490 {
1491         return 1;
1492 }
1493
1494 int64_t EDL::get_video_frames()
1495 {
1496         return (int64_t)(tracks->total_length() *
1497                 session->frame_rate);
1498 }
1499
1500 void EDL::remove_vwindow_edls()
1501 {
1502         for( int i=0; i<total_vwindow_edls(); ++i ) {
1503                 get_vwindow_edl(i)->remove_user();
1504         }
1505         vwindow_edls.remove_all();
1506 }
1507
1508 void EDL::remove_vwindow_edl(EDL *edl)
1509 {
1510         if( vwindow_edls.number_of(edl) >= 0 ) {
1511                 edl->remove_user();
1512                 vwindow_edls.remove(edl);
1513         }
1514 }
1515
1516
1517 EDL* EDL::get_vwindow_edl(int number)
1518 {
1519         return vwindow_edls.get(number);
1520 }
1521
1522 int EDL::total_vwindow_edls()
1523 {
1524         return vwindow_edls.size();
1525 }
1526
1527 void EDL::append_vwindow_edl(EDL *edl, int increase_counter)
1528 {
1529         if(vwindow_edls.number_of(edl) >= 0) return;
1530
1531         if(increase_counter) edl->add_user();
1532         vwindow_edls.append(edl);
1533 }
1534
1535
1536 double EDL::next_edit(double position)
1537 {
1538         Units::fix_double(&position);
1539         double new_position = tracks->total_length();
1540
1541         double max_rate = get_frame_rate();
1542         int sample_rate = get_sample_rate();
1543         if( sample_rate > max_rate ) max_rate = sample_rate;
1544         double min_movement = max_rate > 0 ? 1. / max_rate : 1e-6;
1545
1546 // Test for edit handles after position
1547         for( Track *track=tracks->first; track; track=track->next ) {
1548                 if( !track->record ) continue;
1549                 for( Edit *edit=track->edits->first; edit; edit=edit->next ) {
1550                         double edit_end = track->from_units(edit->startproject + edit->length);
1551                         Units::fix_double(&edit_end);
1552                         if( fabs(edit_end-position) < min_movement ) continue;
1553                         if( edit_end > position && edit_end < new_position )
1554                                 new_position = edit_end;
1555                 }
1556         }
1557         return new_position;
1558 }
1559
1560 double EDL::prev_edit(double position)
1561 {
1562         Units::fix_double(&position);
1563         double new_position = -1;
1564
1565         double max_rate = get_frame_rate();
1566         int sample_rate = get_sample_rate();
1567         if( sample_rate > max_rate ) max_rate = sample_rate;
1568         double min_movement = max_rate > 0 ? 1. / max_rate : 1e-6;
1569
1570 // Test for edit handles before cursor position
1571         for( Track *track=tracks->first; track; track=track->next ) {
1572                 if( !track->record ) continue;
1573                 for( Edit *edit=track->edits->first; edit; edit=edit->next ) {
1574                         double edit_end = track->from_units(edit->startproject);
1575                         Units::fix_double(&edit_end);
1576                         if( fabs(edit_end-position) < min_movement ) continue;
1577                         if( edit_end < position && edit_end > new_position )
1578                                 new_position = edit_end;
1579                 }
1580         }
1581         return new_position;
1582 }
1583
1584 double EDL::skip_silence(double position)
1585 {
1586         double result = position, nearest = DBL_MAX;
1587         for( Track *track=tracks->first; track; track=track->next ) {
1588                 if( !track->play ) continue;
1589                 Edit *edit = track->edits->editof(position, PLAY_FORWARD, 0);
1590                 while( edit && edit->silence() ) edit = edit->next;
1591                 if( !edit ) continue;
1592                 double pos = track->from_units(edit->startproject);
1593                 if( pos > position && pos < nearest )
1594                         nearest = result = pos;
1595         }
1596         return result;
1597 }
1598
1599 void EDL::rescale_proxy(int orig_scale, int new_scale)
1600 {
1601         if( orig_scale == new_scale ) return;
1602 // project size
1603         float orig_w = (float)session->output_w * orig_scale;
1604         float orig_h = (float)session->output_h * orig_scale;
1605         if( !parent_edl ) {
1606                 session->output_w = Units::round(orig_w / new_scale);
1607                 session->output_h = Units::round(orig_h / new_scale);
1608         }
1609
1610 // track sizes
1611         for( Track *track=tracks->first; track; track=track->next ) {
1612                 if( track->data_type != TRACK_VIDEO ) continue;
1613                 orig_w = (float)track->track_w * orig_scale;
1614                 orig_h = (float)track->track_h * orig_scale;
1615                 track->track_w = Units::round(orig_w / new_scale);
1616                 track->track_h = Units::round(orig_h / new_scale);
1617                 ((MaskAutos*)track->automation->autos[AUTOMATION_MASK])->
1618                         set_proxy(orig_scale, new_scale);
1619                 ((FloatAutos*)track->automation->autos[AUTOMATION_CAMERA_X])->
1620                         set_proxy(orig_scale, new_scale);
1621                 ((FloatAutos*)track->automation->autos[AUTOMATION_CAMERA_Y])->
1622                         set_proxy(orig_scale, new_scale);
1623                 ((FloatAutos*)track->automation->autos[AUTOMATION_PROJECTOR_X])->
1624                         set_proxy(orig_scale, new_scale);
1625                 ((FloatAutos*)track->automation->autos[AUTOMATION_PROJECTOR_Y])->
1626                         set_proxy(orig_scale, new_scale);
1627         }
1628 }
1629
1630 void EDL::set_proxy(int new_scale, int new_use_scaler,
1631         ArrayList<Indexable*> *orig_assets, ArrayList<Indexable*> *proxy_assets)
1632 {
1633         int orig_scale = session->proxy_scale;
1634         session->proxy_scale = new_scale;
1635         int orig_use_scaler = session->proxy_use_scaler;
1636         session->proxy_use_scaler = new_use_scaler;
1637         if( orig_use_scaler ) orig_scale = 1;
1638         int scale = new_use_scaler ? new_scale : 1;
1639         int asset_scale = new_scale == 1 && !new_use_scaler ? 0 : scale;
1640 // change original assets to proxy assets
1641         int folder_no = new_use_scaler || new_scale != 1 ? AW_PROXY_FOLDER : AW_MEDIA_FOLDER;
1642         for( int i=0,n=proxy_assets->size(); i<n; ++i ) {
1643                 Indexable *proxy_idxbl = proxy_assets->get(i);
1644                 proxy_idxbl->folder_no = folder_no;
1645                 if( !proxy_idxbl->is_asset ) continue;
1646                 Asset *proxy_asset = assets->update((Asset *)proxy_idxbl);
1647                 proxy_asset->width = proxy_asset->actual_width * scale;
1648                 proxy_asset->height = proxy_asset->actual_height * scale;
1649                 proxy_asset->proxy_scale = asset_scale;
1650         }
1651 // rescale to full size asset in read_frame
1652         if( new_use_scaler ) new_scale = 1;
1653         rescale_proxy(orig_scale, new_scale);
1654
1655 // replace track contents
1656         for( Track *track=tracks->first; track; track=track->next ) {
1657                 if( track->data_type != TRACK_VIDEO ) continue;
1658                 for( Edit *edit=track->edits->first; edit; edit=edit->next ) {
1659                         Indexable *idxbl = (Indexable *)edit->asset;
1660                         if( !idxbl ) idxbl = (Indexable *)edit->nested_edl;
1661                         if( !idxbl ) continue;
1662                         int i = orig_assets->size();
1663                         while( --i>=0 && strcmp(orig_assets->get(i)->path, idxbl->path) );
1664                         if( i < 0 ) continue;
1665                         Indexable *proxy_idxbl = proxy_assets->get(i);
1666                         Asset *proxy_asset = proxy_idxbl->is_asset ?
1667                                 assets->update((Asset *)proxy_idxbl) : 0;
1668                         EDL *proxy_edl = !proxy_idxbl->is_asset ?
1669                                 (EDL *)proxy_idxbl : 0;
1670                         edit->asset = proxy_asset;
1671                         edit->nested_edl = proxy_edl;
1672                 }
1673         }
1674         for( int j=0,n=clips.size(); j<n; ++j ) {
1675                 EDL *clip = clips[j];
1676                 int has_proxy = 0;
1677                 for( Track *track=clip->tracks->first; track; track=track->next ) {
1678                         if( track->data_type != TRACK_VIDEO ) continue;
1679                         for( Edit *edit=track->edits->first; edit; edit=edit->next ) {
1680                                 Indexable *idxbl = (Indexable *)edit->asset;
1681                                 if( !idxbl ) idxbl = (Indexable *)edit->nested_edl;
1682                                 if( !idxbl ) continue;
1683                                 int i = orig_assets->size();
1684                                 while( --i>=0 && strcmp(orig_assets->get(i)->path, idxbl->path) );
1685                                 if( i < 0 ) continue;
1686                                 Indexable *proxy_idxbl = proxy_assets->get(i);
1687                                 Asset *proxy_asset = proxy_idxbl->is_asset ?
1688                                         assets->update((Asset *)proxy_idxbl) : 0;
1689                                 EDL *proxy_edl = !proxy_idxbl->is_asset ?
1690                                         (EDL *)proxy_idxbl : 0;
1691                                 edit->asset = proxy_asset;
1692                                 edit->nested_edl = proxy_edl;
1693                                 has_proxy = 1;
1694                         }
1695                 }
1696                 if( has_proxy && !orig_use_scaler )
1697                         clip->rescale_proxy(orig_scale, new_scale);
1698         }
1699 }
1700
1701 void EDL::add_proxy(ArrayList<Indexable*> *orig_assets, ArrayList<Indexable*> *proxy_assets)
1702 {
1703         int asset_scale = session->proxy_scale;
1704         if( asset_scale == 1 ) asset_scale = 0;
1705         int scale = !asset_scale ? 1 : asset_scale;
1706 // update proxy geom using scale
1707         for( int i=0; i<proxy_assets->size(); ++i ) {
1708                 Asset *proxy_asset = (Asset *)proxy_assets->get(i);
1709                 proxy_asset->proxy_scale = asset_scale;
1710                 proxy_asset->width = proxy_asset->actual_width * scale;
1711                 proxy_asset->height = proxy_asset->actual_height * scale;
1712         }
1713
1714 // change original assets to proxy assets
1715         for( int i=0,n=proxy_assets->size(); i<n; ++i ) {
1716                 Asset *proxy_asset = assets->update((Asset *)proxy_assets->get(i));
1717                 proxy_asset->folder_no = AW_PROXY_FOLDER;
1718 // replace track contents
1719                 for( Track *track=tracks->first; track; track=track->next ) {
1720                         if( track->data_type != TRACK_VIDEO ) continue;
1721                         for( Edit *edit=track->edits->first; edit; edit=edit->next ) {
1722                                 if( !edit->asset ) continue;
1723                                 if( !strcmp(edit->asset->path, orig_assets->get(i)->path) ) {
1724                                         edit->asset = proxy_asset;
1725                                 }
1726                         }
1727                 }
1728         }
1729 }
1730
1731 Asset *EDL::get_proxy_asset()
1732 {
1733         return folder_no == AW_PROXY_FOLDER ?
1734                 tracks->first->edits->first->asset : 0;
1735 }
1736
1737 Track *EDL::add_new_track(int data_type)
1738 {
1739         Track *new_track = 0;
1740         switch( data_type ) {
1741         case TRACK_VIDEO:
1742                 ++session->video_tracks;
1743                 new_track = tracks->add_video_track(0, 0);
1744                 break;
1745         case TRACK_AUDIO:
1746                 ++session->audio_tracks;
1747                 new_track = tracks->add_audio_track(0, 0);
1748                 break;
1749         case TRACK_SUBTITLE:
1750                 new_track = tracks->add_subttl_track(0, 0);
1751                 break;
1752         }
1753         return new_track;
1754 }
1755
1756 double EDL::get_cursor_position(int cursor_x, int pane_no)
1757 {
1758         return (double)cursor_x * local_session->zoom_sample / session->sample_rate +
1759                 (double)local_session->view_start[pane_no] *
1760                         local_session->zoom_sample / session->sample_rate;
1761 }
1762 int64_t EDL::get_position_cursorx(double position, int pane_no)
1763 {
1764         return (int64_t)(position * session->sample_rate / local_session->zoom_sample)
1765                         - local_session->view_start[pane_no];
1766 }
1767
1768 int EDL::in_use(Indexable *indexable)
1769 {
1770         for( Track *track=tracks->first; track; track=track->next ) {
1771                 for( Edit *edit=track->edits->first; edit; edit=edit->next ) {
1772                         Indexable *idxbl = (Indexable *)edit->asset;
1773                         if( !idxbl ) idxbl = (Indexable *)edit->nested_edl;
1774                         if( !idxbl ) continue;
1775                         if( idxbl->id == indexable->id ) return 1;
1776                         if( !indexable->is_asset != !idxbl->is_asset ) continue;
1777                         if( !strcmp(idxbl->path, indexable->path) ) return 1;
1778                 }
1779         }
1780         for( int i=0; i<clips.size(); ++i )
1781                 if( clips[i]->in_use(indexable) ) return 1;
1782         for( int i=0; i<nested_edls.size(); ++i )
1783                 if( nested_edls[i]->in_use(indexable) ) return 1;
1784         return 0;
1785 }
1786
1787 int EDL::regroup(int next_id)
1788 {
1789         ArrayList<int> new_groups;
1790         for( Track *track=tracks->first; track; track=track->next ) {
1791                 for( Edit *edit=track->edits->first; edit; edit=edit->next ) {
1792                         if( !edit->group_id ) continue;
1793                         int k = new_groups.size();
1794                         while( --k >= 0 && new_groups[k] != edit->group_id );
1795                         if( k >= 0 ) continue;
1796                         new_groups.append(edit->group_id);
1797                 }
1798         }
1799         for( Track *track=tracks->first; track; track=track->next ) {
1800                 for( Edit *edit=track->edits->first; edit; edit=edit->next ) {
1801                         if( !edit->group_id ) continue;
1802                         int k = new_groups.size();
1803                         while( --k >= 0 && new_groups[k] != edit->group_id );
1804                         if( k < 0 ) continue;
1805                         edit->group_id = k + next_id;
1806                 }
1807         }
1808         return new_groups.size();
1809 }
1810
1811 EDL *EDL::selected_edits_to_clip(int packed,
1812                 double *start_position, Track **start_track,
1813                 int edit_labels, int edit_autos, int edit_plugins)
1814 {
1815         double start = DBL_MAX, end = DBL_MIN;
1816         Track *first_track=0, *last_track = 0;
1817         for( Track *track=tracks->first; track; track=track->next ) {
1818                 if( !track->record ) continue;
1819                 int empty = 1;
1820                 for( Edit *edit=track->edits->first; edit; edit=edit->next ) {
1821                         if( !edit->is_selected || edit->silence() ) continue;
1822                         double edit_pos = track->from_units(edit->startproject);
1823                         if( start > edit_pos ) start = edit_pos;
1824                         if( end < (edit_pos+=edit->length) ) end = edit_pos;
1825                         empty = 0;
1826                 }
1827                 if( empty ) continue;
1828                 if( !first_track ) first_track = track;
1829                 last_track = track;
1830         }
1831         if( start_position ) *start_position = start;
1832         if( start_track ) *start_track = first_track;
1833         if( !first_track ) return 0;
1834         EDL *new_edl = new EDL();
1835         new_edl->create_objects();
1836         new_edl->copy_session(this);
1837         const char *text = _("new_edl edit");
1838         new_edl->set_path(text);
1839         strcpy(new_edl->local_session->clip_title, text);
1840         strcpy(new_edl->local_session->clip_notes, text);
1841         new_edl->session->video_tracks = 0;
1842         new_edl->session->audio_tracks = 0;
1843         for( Track *track=tracks->first; track; track=track->next ) {
1844                 if( !track->record ) continue;
1845                 if( first_track ) {
1846                         if( first_track != track ) continue;
1847                         first_track = 0;
1848                 }
1849                 Track *new_track = 0;
1850                 if( !packed )
1851                         new_track = new_edl->add_new_track(track->data_type);
1852                 int64_t start_pos = track->to_units(start, 0);
1853                 int64_t end_pos = track->to_units(end, 0);
1854                 int64_t startproject = 0;
1855                 Edit *edit = track->edits->first;
1856                 for( ; edit; edit=edit->next ) {
1857                         if( !edit->is_selected || edit->silence() ) continue;
1858                         if( edit->startproject < start_pos ) continue;
1859                         if( edit->startproject >= end_pos ) break;
1860                         int64_t edit_start_pos = edit->startproject;
1861                         int64_t edit_end_pos = edit->startproject + edit->length;
1862                         if( !new_track )
1863                                 new_track = new_edl->add_new_track(track->data_type);
1864                         int64_t edit_pos = edit_start_pos - start_pos;
1865                         if( !packed && edit_pos > startproject ) {
1866                                 Edit *silence = new Edit(new_edl, new_track);
1867                                 silence->startproject = startproject;
1868                                 silence->length = edit_pos - startproject;
1869                                 new_track->edits->append(silence);
1870                                 startproject = edit_pos;
1871                         }
1872                         int64_t clip_start_pos = startproject;
1873                         Edit *clip_edit = new Edit(new_edl, new_track);
1874                         clip_edit->copy_from(edit);
1875                         clip_edit->startproject = startproject;
1876                         startproject += clip_edit->length;
1877                         new_track->edits->append(clip_edit);
1878                         if( edit_labels ) {
1879                                 double edit_start = track->from_units(edit_start_pos);
1880                                 double edit_end = track->from_units(edit_end_pos);
1881                                 double clip_start = new_track->from_units(clip_start_pos);
1882                                 Label *label = labels->first;
1883                                 for( ; label; label=label->next ) {
1884                                         if( label->position < edit_start ) continue;
1885                                         if( label->position >= edit_end ) break;
1886                                         double clip_position = label->position - edit_start + clip_start;
1887                                         Label *clip_label = new_edl->labels->first;
1888                                         while( clip_label && clip_label->position<clip_position )
1889                                                 clip_label = clip_label->next;
1890                                         if( clip_label && clip_label->position == clip_position ) continue;
1891                                         Label *new_label = new Label(new_edl,
1892                                                 new_edl->labels, clip_position, label->textstr);
1893                                         new_edl->labels->insert_before(clip_label, new_label);
1894                                 }
1895                         }
1896                         if( edit_autos ) {
1897                                 Automation *automation = track->automation;
1898                                 Automation *new_automation = new_track->automation;
1899                                 for( int i=0; i<AUTOMATION_TOTAL; ++i ) {
1900                                         Autos *autos = automation->autos[i];
1901                                         if( !autos ) continue;
1902                                         Autos *new_autos = new_automation->autos[i];
1903                                         new_autos->default_auto->copy_from(autos->default_auto);
1904                                         Auto *aut0 = autos->first;
1905                                         for( ; aut0; aut0=aut0->next ) {
1906                                                 if( aut0->position < edit_start_pos ) continue;
1907                                                 if( aut0->position >= edit_end_pos ) break;
1908                                                 Auto *new_auto = new_autos->new_auto();
1909                                                 new_auto->copy_from(aut0);
1910                                                 int64_t clip_position = aut0->position - edit_start_pos + clip_start_pos;
1911                                                 new_auto->position = clip_position;
1912                                                 new_autos->append(new_auto);
1913                                         }
1914                                 }
1915                         }
1916                         if( edit_plugins ) {
1917                                 while( new_track->plugin_set.size() < track->plugin_set.size() )
1918                                         new_track->plugin_set.append(0);
1919                                 for( int i=0; i<track->plugin_set.total; ++i ) {
1920                                         PluginSet *plugin_set = track->plugin_set[i];
1921                                         if( !plugin_set ) continue;
1922                                         PluginSet *new_plugin_set = new_track->plugin_set[i];
1923                                         if( !new_plugin_set ) {
1924                                                 new_plugin_set = new PluginSet(new_edl, new_track);
1925                                                 new_track->plugin_set[i] = new_plugin_set;
1926                                         }
1927                                         Plugin *plugin = (Plugin*)plugin_set->first;
1928                                         int64_t startplugin = new_plugin_set->length();
1929                                         for( ; plugin ; plugin=(Plugin*)plugin->next ) {
1930                                                 if( plugin->silence() ) continue;
1931                                                 int64_t plugin_start_pos = plugin->startproject;
1932                                                 int64_t plugin_end_pos = plugin_start_pos + plugin->length;
1933                                                 if( plugin_end_pos < start_pos ) continue;
1934                                                 if( plugin_start_pos > end_pos ) break;
1935                                                 if( plugin_start_pos < edit_start_pos )
1936                                                         plugin_start_pos = edit_start_pos;
1937                                                 if( plugin_end_pos > edit_end_pos )
1938                                                         plugin_end_pos = edit_end_pos;
1939                                                 if( plugin_start_pos >= plugin_end_pos ) continue;
1940                                                 int64_t plugin_pos = plugin_start_pos - start_pos;
1941                                                 if( !packed && plugin_pos > startplugin ) {
1942                                                         Plugin *silence = new Plugin(new_edl, new_track, "");
1943                                                         silence->startproject = startplugin;
1944                                                         silence->length = plugin_pos - startplugin;
1945                                                         new_plugin_set->append(silence);
1946                                                         startplugin = plugin_pos;
1947                                                 }
1948                                                 Plugin *new_plugin = new Plugin(new_edl, new_track, plugin->title);
1949                                                 new_plugin->copy_base(plugin);
1950                                                 new_plugin->startproject = startplugin;
1951                                                 new_plugin->length = plugin_end_pos - plugin_start_pos;
1952                                                 startplugin += new_plugin->length;
1953                                                 new_plugin_set->append(new_plugin);
1954                                                 KeyFrames *keyframes = plugin->keyframes;
1955                                                 KeyFrames *new_keyframes = new_plugin->keyframes;
1956                                                 new_keyframes->default_auto->copy_from(keyframes->default_auto);
1957                                                 new_keyframes->default_auto->position = new_plugin->startproject;
1958                                                 KeyFrame *keyframe = (KeyFrame*)keyframes->first;
1959                                                 for( ; keyframe; keyframe=(KeyFrame*)keyframe->next ) {
1960                                                         if( keyframe->position < edit_start_pos ) continue;
1961                                                         if( keyframe->position >= edit_end_pos ) break;
1962                                                         KeyFrame *clip_keyframe = new KeyFrame(new_edl, new_keyframes);
1963                                                         clip_keyframe->copy_from(keyframe);
1964                                                         int64_t key_position = keyframe->position - start_pos;
1965                                                         if( packed )
1966                                                                 key_position += new_plugin->startproject - plugin_pos;
1967                                                         clip_keyframe->position = key_position;
1968                                                         new_keyframes->append(clip_keyframe);
1969                                                 }
1970                                         }
1971                                 }
1972                         }
1973                 }
1974                 if( last_track == track ) break;
1975         }
1976         return new_edl;
1977 }
1978
1979 EDL *EDL::selected_edits_to_clip(int packed, double *start_position, Track **start_track)
1980 {
1981         return selected_edits_to_clip(packed, start_position, start_track,
1982                 session->labels_follow_edits,
1983                 session->autos_follow_edits,
1984                 session->plugins_follow_edits);
1985 }
1986
1987 void EDL::paste_edits(EDL *clip, Track *first_track, double position, int overwrite,
1988                 int edit_edits, int edit_labels, int edit_autos, int edit_plugins)
1989 {
1990         if( !first_track )
1991                 first_track = tracks->first;
1992         Track *src = clip->tracks->first;
1993         for( Track *track=first_track; track && src; track=track->next ) {
1994                 if( !track->record ) continue;
1995                 int64_t pos = track->to_units(position, 0);
1996                 if( edit_edits ) {
1997                         for( Edit *edit=src->edits->first; edit; edit=edit->next ) {
1998                                 if( edit->silence() ) continue;
1999                                 int64_t start = pos + edit->startproject;
2000                                 int64_t len = edit->length, end = start + len;
2001                                 if( overwrite )
2002                                         track->edits->clear(start, end);
2003                                 Edit *dst = track->edits->insert_new_edit(start);
2004                                 dst->copy_from(edit);
2005                                 dst->startproject = start;
2006                                 dst->is_selected = 1;
2007                                 while( (dst=dst->next) != 0 )
2008                                         dst->startproject += edit->length;
2009                                 if( overwrite ) continue;
2010                                 if( edit_labels && track == first_track ) {
2011                                         double dst_pos = track->from_units(start);
2012                                         double dst_len = track->from_units(len);
2013                                         for( Label *label=labels->first; label; label=label->next ) {
2014                                                 if( label->position >= dst_pos )
2015                                                         label->position += dst_len;
2016                                         }
2017                                 }
2018                                 if( edit_autos ) {
2019                                         for( int i=0; i<AUTOMATION_TOTAL; ++i ) {
2020                                                 Autos *autos = track->automation->autos[i];
2021                                                 if( !autos ) continue;
2022                                                 for( Auto *aut0=autos->first; aut0; aut0=aut0->next ) {
2023                                                         if( aut0->position >= start )
2024                                                                 aut0->position += edit->length;
2025                                                 }
2026                                         }
2027                                 }
2028                                 if( edit_plugins ) {
2029                                         for( int i=0; i<track->plugin_set.size(); ++i ) {
2030                                                 PluginSet *plugin_set = track->plugin_set[i];
2031                                                 Plugin *plugin = (Plugin *)plugin_set->first;
2032                                                 for( ; plugin; plugin=(Plugin *)plugin->next ) {
2033                                                         if( plugin->startproject >= start )
2034                                                                 plugin->startproject += edit->length;
2035                                                         else if( plugin->startproject+plugin->length > end )
2036                                                                 plugin->length += edit->length;
2037                                                         Auto *default_keyframe = plugin->keyframes->default_auto;
2038                                                         if( default_keyframe->position >= start )
2039                                                                 default_keyframe->position += edit->length;
2040                                                         KeyFrame *keyframe = (KeyFrame*)plugin->keyframes->first;
2041                                                         for( ; keyframe; keyframe=(KeyFrame*)keyframe->next ) {
2042                                                                 if( keyframe->position >= start )
2043                                                                         keyframe->position += edit->length;
2044                                                         }
2045                                                 }
2046                                                 plugin_set->optimize();
2047                                         }
2048                                 }
2049                         }
2050                 }
2051                 if( edit_autos ) {
2052                         for( int i=0; i<AUTOMATION_TOTAL; ++i ) {
2053                                 Autos *src_autos = src->automation->autos[i];
2054                                 if( !src_autos ) continue;
2055                                 Autos *autos = track->automation->autos[i];
2056                                 for( Auto *aut0=src_autos->first; aut0; aut0=aut0->next ) {
2057                                         int64_t auto_pos = pos + aut0->position;
2058                                         autos->insert_auto(auto_pos, aut0);
2059                                 }
2060                         }
2061                 }
2062                 if( edit_plugins ) {
2063                         for( int i=0; i<src->plugin_set.size(); ++i ) {
2064                                 PluginSet *plugin_set = src->plugin_set[i];
2065                                 if( !plugin_set ) continue;
2066                                 while( i >= track->plugin_set.size() )
2067                                         track->plugin_set.append(0);
2068                                 PluginSet *dst_plugin_set = track->plugin_set[i];
2069                                 if( !dst_plugin_set ) {
2070                                         dst_plugin_set = new PluginSet(this, track);
2071                                         track->plugin_set[i] = dst_plugin_set;
2072                                 }
2073                                 Plugin *plugin = (Plugin *)plugin_set->first;
2074                                 if( plugin ) track->expand_view = 1;
2075                                 for( ; plugin; plugin=(Plugin *)plugin->next ) {
2076                                         int64_t start = pos + plugin->startproject;
2077                                         int64_t end = start + plugin->length;
2078                                         if( overwrite || edit_edits )
2079                                                 dst_plugin_set->clear(start, end, 1);
2080                                         Plugin *new_plugin = dst_plugin_set->insert_plugin(plugin->title,
2081                                                 start, end-start, plugin->plugin_type, &plugin->shared_location,
2082                                                 (KeyFrame*)plugin->keyframes->default_auto, 0);
2083                                         KeyFrame *keyframe = (KeyFrame*)plugin->keyframes->first;
2084                                         for( ; keyframe; keyframe=(KeyFrame*)keyframe->next ) {
2085                                                 int64_t keyframe_pos = pos + keyframe->position;
2086                                                 new_plugin->keyframes->insert_auto(keyframe_pos, keyframe);
2087                                         }
2088                                         while( (new_plugin=(Plugin *)new_plugin->next) ) {
2089                                                 KeyFrame *keyframe = (KeyFrame*)new_plugin->keyframes->first;
2090                                                 for( ; keyframe; keyframe=(KeyFrame*)keyframe->next )
2091                                                         keyframe->position += plugin->length;
2092                                         }
2093                                 }
2094                         }
2095                 }
2096                 src = src->next;
2097         }
2098         if( edit_labels ) {
2099                 Label *edl_label = labels->first;
2100                 for( Label *label=clip->labels->first; label; label=label->next ) {
2101                         double label_pos = position + label->position;
2102                         int exists = 0;
2103                         while( edl_label &&
2104                                 !(exists=equivalent(edl_label->position, label_pos)) &&
2105                                 edl_label->position < position ) edl_label = edl_label->next;
2106                         if( exists ) continue;
2107                         labels->insert_before(edl_label,
2108                                 new Label(this, labels, label_pos, label->textstr));
2109                 }
2110         }
2111         optimize();
2112 }
2113
2114 void EDL::paste_edits(EDL *clip, Track *first_track, double position, int overwrite)
2115 {
2116         paste_edits(clip, first_track, position, overwrite, 1,
2117                 session->labels_follow_edits,
2118                 session->autos_follow_edits,
2119                 session->plugins_follow_edits);
2120 }
2121
2122 void EDL::replace_assets(ArrayList<Indexable*> &orig_idxbls, ArrayList<Asset*> &new_assets)
2123 {
2124         for( Track *track=tracks->first; track; track=track->next ) {
2125                 for( Edit *edit=track->edits->first; edit; edit=edit->next ) {
2126                         Indexable *idxbl = (Indexable *)edit->asset;
2127                         if( !idxbl ) continue;
2128                         int i = orig_idxbls.size();
2129                         while( --i>=0 && strcmp(orig_idxbls[i]->path, idxbl->path) );
2130                         if( i < 0 ) continue;
2131                         Asset *new_asset = new_assets[i];
2132                         if( track->data_type == TRACK_VIDEO && !new_asset->video_data ) continue;
2133                         if( track->data_type == TRACK_AUDIO && !new_asset->audio_data ) continue;
2134                         edit->asset = assets->update(new_assets[i]);
2135                 }
2136         }
2137         if( !parent_edl ) {
2138                 for( int j=0,n=clips.size(); j<n; ++j )
2139                         clips[j]->replace_assets(orig_idxbls, new_assets);
2140         }
2141 }
2142