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