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