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