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