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