r602: Fix baver's code... don't insert timecode when show_tc is not set
[cinelerra_cv/mob.git] / cinelerra / edits.C
blob94754f2678538cda909ab78cd002c9886cf1e8c2
1 #include "aedit.h"
2 #include "asset.h"
3 #include "assets.h"
4 #include "automation.h"
5 #include "cache.h"
6 #include "clip.h"
7 #include "edit.h"
8 #include "edits.h"
9 #include "edl.h"
10 #include "edlsession.h"
11 #include "file.h"
12 #include "filexml.h"
13 #include "filesystem.h"
14 #include "localsession.h"
15 #include "plugin.h"
16 #include "strategies.inc"
17 #include "track.h"
18 #include "transition.h"
19 #include "transportque.inc"
21 #include <string.h>
23 Edits::Edits(EDL *edl, Track *track)
24  : List<Edit>()
26         this->edl = edl;
27         this->track = track;
30 Edits::~Edits()
35 void Edits::equivalent_output(Edits *edits, int64_t *result)
37 // For the case of plugin sets, a new plugin set may be created with
38 // plugins only starting after 0.  We only want to restart brender at
39 // the first plugin in this case.
40         for(Edit *current = first, *that_current = edits->first; 
41                 current || that_current; 
42                 current = NEXT,
43                 that_current = that_current->next)
44         {
45 //printf("Edits::equivalent_output 1 %d\n", *result);
46                 if(!current && that_current)
47                 {
48                         int64_t position1 = (last ? last->startproject + last->length : 0);
49                         int64_t position2 = that_current->startproject;
50                         if(*result < 0 || *result > MIN(position1, position2))
51                                 *result = MIN(position1, position2);
52                         break;
53                 }
54                 else
55                 if(current && !that_current)
56                 {
57                         int64_t position1 = (edits->last ? edits->last->startproject + edits->last->length : 0);
58                         int64_t position2 = current->startproject;
59                         if(*result < 0 || *result > MIN(position1, position2))
60                                 *result = MIN(position1, position2);
61                         break;
62                 }
63                 else
64                 {
65 //printf("Edits::equivalent_output 2 %d\n", *result);
66                         current->equivalent_output(that_current, result);
67 //printf("Edits::equivalent_output 3 %d\n", *result);
68                 }
69         }
72 void Edits::copy_from(Edits *edits)
74         while(last) delete last;
75         for(Edit *current = edits->first; current; current = NEXT)
76         {
77                 Edit *new_edit = append(create_edit());
78                 new_edit->copy_from(current);
79         }
83 Edits& Edits::operator=(Edits& edits)
85 printf("Edits::operator= 1\n");
86         copy_from(&edits);
87         return *this;
91 void Edits::insert_asset(Asset *asset,
92         int64_t length,
93         int64_t position,
94         int track_number)
96         Edit *new_edit = insert_new_edit(position);
98         new_edit->asset = asset;
99         new_edit->startsource = 0;
100         new_edit->startproject = position;
101         new_edit->length = length;
103         if(asset->audio_data)
104                 new_edit->channel = track_number % asset->channels;
105         else
106         if(asset->video_data)
107                 new_edit->channel = track_number % asset->layers;
109 //printf("Edits::insert_asset %d %d\n", new_edit->channel, new_edit->length);
110         for(Edit *current = new_edit->next; current; current = NEXT)
111         {
112                 current->startproject += length;
113         }
116 void Edits::insert_edits(Edits *source_edits, int64_t position)
118         int64_t clipboard_length = 
119                 track->to_units(source_edits->edl->local_session->clipboard_length, 1);
120         int64_t clipboard_end = position + clipboard_length;
123 // Fill region between end of edit table and beginning of pasted segment
124 // with silence.  Can't call from insert_new_edit because it's recursive.
125         if(position > length())
126         {
127                 paste_silence(length(), position);
128         }
131         for(Edit *source_edit = source_edits->first;
132                 source_edit;
133                 source_edit = source_edit->next)
134         {
135 // Update Assets
136                 Asset *dest_asset = edl->assets->update(source_edit->asset);
137 // Open destination area
138                 Edit *dest_edit = insert_new_edit(position + source_edit->startproject);
140                 dest_edit->copy_from(source_edit);
141                 dest_edit->asset = dest_asset;
142                 dest_edit->startproject = position + source_edit->startproject;
146 // Shift keyframes in source edit to their position in the
147 // destination edit for plugin case
148                 dest_edit->shift_keyframes(position);
152 // Shift following edits and keyframes in following edits by length
153 // in current source edit.
154                 for(Edit *future_edit = dest_edit->next;
155                         future_edit;
156                         future_edit = future_edit->next)
157                 {
158                         future_edit->startproject += dest_edit->length;
159                         future_edit->shift_keyframes(dest_edit->length);
160                 }
162 // Fill clipboard length with silence
163                 if(!source_edit->next && 
164                         dest_edit->startproject + dest_edit->length < clipboard_end)
165                 {
166                         paste_silence(dest_edit->startproject + dest_edit->length,
167                                 clipboard_end);
168                 }
169         }
173 // Native units
174 // Can't paste silence in here because it's used by paste_silence.
175 Edit* Edits::insert_new_edit(int64_t position)
177         Edit *current = 0;
178 //printf("Edits::insert_new_edit 1\n");
179         current = split_edit(position);
180         if(current) current = PREVIOUS;
182 //printf("Edits::insert_new_edit 1\n");
183         Edit *new_edit = create_edit();
184 //printf("Edits::insert_new_edit 1\n");
185         insert_after(current, new_edit);
186         new_edit->startproject = position;
187 //printf("Edits::insert_new_edit 2\n");
188         return new_edit;
192 Edit* Edits::split_edit(int64_t position)
194 // Get edit containing position
195         Edit *edit = editof(position, PLAY_FORWARD, 0);
197 // No edit found
198         if(!edit)
199         {
200                 return 0;
201         }
202 // Split would have created a 0 length
203 //      if(edit->startproject == position) return edit;
204 // Create anyway so the return value comes before position
206         Edit *new_edit = create_edit();
207         insert_after(edit, new_edit);
208         new_edit->copy_from(edit);
209         new_edit->length = new_edit->startproject + new_edit->length - position;
210         edit->length = position - edit->startproject;
211         new_edit->startproject = edit->startproject + edit->length;
212         new_edit->startsource += edit->length;
215 // Decide what to do with the transition
216         if(edit->length && edit->transition)
217         {
218                 delete new_edit->transition;
219                 new_edit->transition = 0;
220         }
222         if(edit->transition && edit->transition->length > edit->length) 
223                 edit->transition->length = edit->length;
224         if(new_edit->transition && new_edit->transition->length > new_edit->length)
225                 new_edit->transition->length = new_edit->length;
226         return new_edit;
229 int Edits::save(FileXML *xml, char *output_path)
231         copy(0, length(), xml, output_path);
232         return 0;
235 void Edits::resample(double old_rate, double new_rate)
237         for(Edit *current = first; current; current = NEXT)
238         {
239                 current->startproject = Units::to_int64((double)current->startproject / 
240                         old_rate * 
241                         new_rate);
242                 if(PREVIOUS) PREVIOUS->length = current->startproject - PREVIOUS->startproject;
243                 current->startsource = Units::to_int64((double)current->startsource /
244                         old_rate *
245                         new_rate);
246                 if(!NEXT) current->length = Units::to_int64((double)current->length /
247                         old_rate *
248                         new_rate);
249                 if(current->transition)
250                 {
251                         current->transition->length = Units::to_int64(
252                                 (double)current->transition->length /
253                                 old_rate *
254                                 new_rate);
255                 }
256                 current->resample(old_rate, new_rate);
257         }
273 int Edits::optimize()
275         int result = 1;
276         Edit *current;
278 //return 0;
279 // Sort edits by starting point
280         while(result)
281         {
282                 result = 0;
283                 
284                 for(current = first; current; current = NEXT)
285                 {
286                         Edit *next_edit = NEXT;
287                         
288                         if(next_edit && next_edit->startproject < current->startproject)
289                         {
290                                 swap(next_edit, current);
291                                 result = 1;
292                         }
293                 }
294         }
296 // Insert silence between edits which aren't consecutive
297         for(current = last; current; current = current->previous)
298         {
299                 if(current->previous)
300                 {
301                         Edit *previous_edit = current->previous;
302                         if(current->startproject - 
303                                 previous_edit->startproject -
304                                 previous_edit->length > 0)
305                         {
306                                 Edit *new_edit = create_edit();
307                                 insert_before(current, new_edit);
308                                 new_edit->startproject = previous_edit->startproject + previous_edit->length;
309                                 new_edit->length = current->startproject - 
310                                         previous_edit->startproject -
311                                         previous_edit->length;
312                         }
313                 }
314                 else
315                 if(current->startproject > 0)
316                 {
317                         Edit *new_edit = create_edit();
318                         insert_before(current, new_edit);
319                         new_edit->length = current->startproject;
320                 }
321         }
323         result = 1;
324         while(result)
325         {
326                 result = 0;
329 // delete 0 length edits
330                 for(current = first; 
331                         current && !result; )
332                 {
333                         if(current->length == 0)
334                         {
335                                 Edit* next = current->next;
336                                 delete current;
337                                 result = 1;
338                                 current = next;
339                         }
340                         else
341                                 current = current->next;
342                 }
344 // merge same files or transitions
345                 for(current = first; 
346                         current && current->next && !result; )
347                 {
348 // assets identical
349                         Edit *next_edit = current->next;
350                 if(current->asset == next_edit->asset && 
351                         (!current->asset ||
352                                         (current->startsource + current->length == next_edit->startsource &&
353                                 current->channel == next_edit->channel)
354                                 )
355                         )
356                 {       
357 // source positions are consecutive
358                         current->length += next_edit->length;
359                         remove(next_edit);
360                         result = 1;
361                 }
363                 current = (Plugin*)current->next;
364                 }
366 // delete last edit of 0 length or silence
367                 if(last && 
368                         (last->silence() || 
369                         !last->length))
370                 {
371                         delete last;
372                         result = 1;
373                 }
374         }
376 //track->dump();
377         return 0;
399 // ===================================== file operations
401 int Edits::load(FileXML *file, int track_offset)
403         int result = 0;
404         int64_t startproject = 0;
406         do{
407                 result = file->read_tag();
409 //printf("Edits::load 1 %s\n", file->tag.get_title());
410                 if(!result)
411                 {
412                         if(!strcmp(file->tag.get_title(), "EDIT"))
413                         {
414                                 load_edit(file, startproject, track_offset);
415                         }
416                         else
417                         if(!strcmp(file->tag.get_title(), "/EDITS"))
418                         {
419                                 result = 1;
420                         }
421                 }
422         }while(!result);
424 //track->dump();
425         optimize();
428 int Edits::load_edit(FileXML *file, int64_t &startproject, int track_offset)
430         Edit* current;
432 //printf("Edits::load_edit 1 %d\n", total());
433         current = append_new_edit();
434 //printf("Edits::load_edit 2 %d\n", total());
436         current->load_properties(file, startproject);
438         startproject += current->length;
440         int result = 0;
441 //printf("Edits::load_edit 1\n");
443         do{
444 //printf("Edits::load_edit 2\n");
445                 result = file->read_tag();
446 //printf("Edits::load_edit 3 %s\n", file->tag.get_title());
448                 if(!result)
449                 {
450                         if(file->tag.title_is("FILE"))
451                         {
452                                 char filename[1024];
453                                 sprintf(filename, SILENCE);
454                                 file->tag.get_property("SRC", filename);
455 // Extend path
456 //printf("Edits::load_edit 4 %s\n", filename);
457                                 if(strcmp(filename, SILENCE))
458                                 {
459                                         char directory[BCTEXTLEN], edl_directory[BCTEXTLEN];
460                                         FileSystem fs;
461                                         fs.set_current_dir("");
462                                         fs.extract_dir(directory, filename);
463                                         if(!strlen(directory))
464                                         {
465                                                 fs.extract_dir(edl_directory, file->filename);
466                                                 fs.join_names(directory, edl_directory, filename);
467                                                 strcpy(filename, directory);
468                                         }
469                                         current->asset = edl->assets->get_asset(filename);
470                                 }
471                                 else
472                                 {
473                                         current->asset = edl->assets->get_asset(SILENCE);
474                                 }
475 //printf("Edits::load_edit 5\n");
476                         }
477                         else
478                         if(file->tag.title_is("TRANSITION"))
479                         {
480                                 current->transition = new Transition(edl,
481                                         current, 
482                                         "",
483                                         track->to_units(edl->session->default_transition_length, 1));
484                                 current->transition->load_xml(file);
485                         }
486                         else
487                         if(file->tag.title_is(SILENCE))
488                         {
489 //printf("Edits::load_edit 6\n");
490                                 current->asset = edl->assets->get_asset(SILENCE);
491 //printf("Edits::load_edit 7\n");
492                         }
493                         else
494                         if(file->tag.title_is("/EDIT"))
495                         {
496                                 result = 1;
497                         }
498                 }
499 //printf("Edits::load_edit 8\n");
500         }while(!result);
502 //printf("Edits::load_edit 5\n");
503 // in case of incomplete edit tag
504         if(!current->asset) current->asset = edl->assets->get_asset(SILENCE);
505         return 0;
508 // ============================================= accounting
510 int64_t Edits::length()
512         if(last) 
513                 return last->startproject + last->length;
514         else 
515                 return 0;
517 // 
518 // int64_t Edits::total_length() 
519 // {
520 //      int64_t total = 0;
521 //      Edit* current;
522 //      for(current = first; current; current = NEXT)
523 //      {
524 //              total += current->length;
525 //      }
526 //      return total; 
527 // };
529 Edit* Edits::editof(int64_t position, int direction, int use_nudge)
531         Edit *current = 0;
532         if(use_nudge && track) position += track->nudge;
534         if(direction == PLAY_FORWARD)
535         {
536                 for(current = last; current; current = PREVIOUS)
537                 {
538                         if(current->startproject <= position && current->startproject + current->length > position)
539                                 return current;
540                 }
541         }
542         else
543         if(direction == PLAY_REVERSE)
544         {
545                 for(current = first; current; current = NEXT)
546                 {
547                         if(current->startproject < position && current->startproject + current->length >= position)
548                                 return current;
549                 }
550         }
552         return 0;     // return 0 on failure
555 Edit* Edits::get_playable_edit(int64_t position, int use_nudge)
557         Edit *current;
558         if(track && use_nudge) position += track->nudge;
560 // Get the current edit
561         for(current = first; current; current = NEXT)
562         {
563                 if(current->startproject <= position && 
564                         current->startproject + current->length > position)
565                         break;
566         }
568 // Get the edit's asset
569         if(current)
570         {
571                 if(!current->asset)
572                         current = 0;
573         }
575         return current;     // return 0 on failure
578 // ================================================ editing
582 int Edits::copy(int64_t start, int64_t end, FileXML *file, char *output_path)
584         Edit *current_edit;
586         file->tag.set_title("EDITS");
587         file->append_tag();
588         file->append_newline();
590         for(current_edit = first; current_edit; current_edit = current_edit->next)
591         {
592                 current_edit->copy(start, end, file, output_path);
593         }
595         file->tag.set_title("/EDITS");
596         file->append_tag();
597         file->append_newline();
602 void Edits::clear(int64_t start, int64_t end)
604         Edit* edit1 = editof(start, PLAY_FORWARD, 0);
605         Edit* edit2 = editof(end, PLAY_FORWARD, 0);
606         Edit* current_edit;
608         if(end == start) return;        // nothing selected
609         if(!edit1 && !edit2) return;       // nothing selected
612         if(!edit2)
613         {                // edit2 beyond end of track
614                 edit2 = last;
615                 end = this->length();
616         }
618         if(edit1 != edit2)
619         {
620 // in different edits
622 //printf("Edits::clear 3.5 %d %d %d %d\n", edit1->startproject, edit1->length, edit2->startproject, edit2->length);
623                 edit1->length = start - edit1->startproject;
624                 edit2->length -= end - edit2->startproject;
625                 edit2->startsource += end - edit2->startproject;
626                 edit2->startproject += end - edit2->startproject;
628 // delete
629                 for(current_edit = edit1->next; current_edit && current_edit != edit2;)
630                 {
631                         Edit* next = current_edit->next;
632                         remove(current_edit);
633                         current_edit = next;
634                 }
635 // shift
636                 for(current_edit = edit2; current_edit; current_edit = current_edit->next)
637                 {
638                         current_edit->startproject -= end - start;
639                 }
640         }
641         else
642         {
643 // in same edit. paste_edit depends on this
644 // create a new edit
645                 current_edit = split_edit(start);
647                 current_edit->length -= end - start;
648                 current_edit->startsource += end - start;
650 // shift
651                 for(current_edit = current_edit->next; 
652                         current_edit; 
653                         current_edit = current_edit->next)
654                 {            
655                         current_edit->startproject -= end - start;
656                 }
657         }
659         optimize();
662 // Used by edit handle and plugin handle movement but plugin handle movement
663 // can only effect other plugins.
664 void Edits::clear_recursive(int64_t start, 
665         int64_t end, 
666         int edit_edits,
667         int edit_labels, 
668         int edit_plugins,
669         Edits *trim_edits)
671 //printf("Edits::clear_recursive 1\n");
672         track->clear(start, 
673                 end, 
674                 edit_edits,
675                 edit_labels,
676                 edit_plugins,
677                 0,
678                 trim_edits);
682 int Edits::clear_handle(double start, 
683         double end, 
684         int edit_plugins, 
685         double &distance)
687         Edit *current_edit;
689         distance = 0.0; // if nothing is found, distance is 0!
690         for(current_edit = first; 
691                 current_edit && current_edit->next; 
692                 current_edit = current_edit->next)
693         {
697                 if(current_edit->asset && 
698                         current_edit->next->asset)
699                 {
701                         if(current_edit->asset->equivalent(*current_edit->next->asset,
702                                 0,
703                                 0))
704                         {
706 // Got two consecutive edits in same source
707                                 if(edl->equivalent(track->from_units(current_edit->next->startproject), 
708                                         start))
709                                 {
710 // handle selected
711                                         int length = -current_edit->length;
712                                         current_edit->length = current_edit->next->startsource - current_edit->startsource;
713                                         length += current_edit->length;
715 // Lengthen automation
716                                         track->automation->paste_silence(current_edit->next->startproject, 
717                                                 current_edit->next->startproject + length);
719 // Lengthen effects
720                                         if(edit_plugins)
721                                                 track->shift_effects(current_edit->next->startproject, 
722                                                         length,
723                                                         0);
725                                         for(current_edit = current_edit->next; current_edit; current_edit = current_edit->next)
726                                         {
727                                                 current_edit->startproject += length;
728                                         }
730                                         distance = track->from_units(length);
731                                         optimize();
732                                         break;
733                                 }
734                         }
735                 }
736         }
738         return 0;
741 int Edits::modify_handles(double oldposition, 
742         double newposition, 
743         int currentend,
744         int edit_mode, 
745         int edit_edits,
746         int edit_labels,
747         int edit_plugins,
748         Edits *trim_edits)
750         int result = 0;
751         Edit *current_edit;
753 //printf("Edits::modify_handles 1 %d %f %f\n", currentend, newposition, oldposition);
754         if(currentend == 0)
755         {
756 // left handle
757                 for(current_edit = first; current_edit && !result;)
758                 {
759                         if(edl->equivalent(track->from_units(current_edit->startproject), 
760                                 oldposition))
761                         {
762 // edit matches selection
763 //printf("Edits::modify_handles 3 %f %f\n", newposition, oldposition);
764                                 oldposition = track->from_units(current_edit->startproject);
765                                 result = 1;
767                                 if(newposition >= oldposition)
768                                 {
769 //printf("Edits::modify_handle 1 %s %f %f\n", track->title, oldposition, newposition);
770 // shift start of edit in
771                                         current_edit->shift_start_in(edit_mode, 
772                                                 track->to_units(newposition, 0), 
773                                                 track->to_units(oldposition, 0),
774                                                 edit_edits,
775                                                 edit_labels,
776                                                 edit_plugins,
777                                                 trim_edits);
778                                 }
779                                 else
780                                 {
781 //printf("Edits::modify_handle 2 %s\n", track->title);
782 // move start of edit out
783                                         current_edit->shift_start_out(edit_mode, 
784                                                 track->to_units(newposition, 0), 
785                                                 track->to_units(oldposition, 0),
786                                                 edit_edits,
787                                                 edit_labels,
788                                                 edit_plugins,
789                                                 trim_edits);
790                                 }
791                         }
793                         if(!result) current_edit = current_edit->next;
794                 }
795         }
796         else
797         {
798 // right handle selected
799                 for(current_edit = first; current_edit && !result;)
800                 {
801                         if(edl->equivalent(track->from_units(current_edit->startproject) + 
802                                 track->from_units(current_edit->length), oldposition))
803                         {
804                 oldposition = track->from_units(current_edit->startproject) + 
805                                         track->from_units(current_edit->length);
806                                 result = 1;
808 //printf("Edits::modify_handle 3\n");
809                                 if(newposition <= oldposition)
810                                 {     
811 // shift end of edit in
812 //printf("Edits::modify_handle 4\n");
813                                         current_edit->shift_end_in(edit_mode, 
814                                                 track->to_units(newposition, 0), 
815                                                 track->to_units(oldposition, 0),
816                                                 edit_edits,
817                                                 edit_labels,
818                                                 edit_plugins,
819                                                 trim_edits);
820 //printf("Edits::modify_handle 5\n");
821                                 }
822                                 else
823                                 {     
824 // move end of edit out
825 //printf("Edits::modify_handle 6\n");
826                                         current_edit->shift_end_out(edit_mode, 
827                                                 track->to_units(newposition, 0), 
828                                                 track->to_units(oldposition, 0),
829                                                 edit_edits,
830                                                 edit_labels,
831                                                 edit_plugins,
832                                                 trim_edits);
833 //printf("Edits::modify_handle 7\n");
834                                 }
835                         }
837                         if(!result) current_edit = current_edit->next;
838 //printf("Edits::modify_handle 8\n");
839                 }
840         }
842         optimize();
843         return 0;
847 // Used by other editing commands so don't optimize
848 Edit* Edits::paste_silence(int64_t start, int64_t end)
850         Edit *new_edit = insert_new_edit(start);
851         new_edit->length = end - start;
852         for(Edit *current = new_edit->next; current; current = NEXT)
853         {
854                 current->startproject += end - start;
855         }
856         return new_edit;
858                                      
859 Edit* Edits::shift(int64_t position, int64_t difference)
861         Edit *new_edit = split_edit(position);
863         for(Edit *current = first; 
864                 current; 
865                 current = NEXT)
866         {
867                 if(current->startproject >= position)
868                 {
869                         current->shift(difference);
870                 }
871         }
872         return new_edit;
876 void Edits::shift_keyframes_recursive(int64_t position, int64_t length)
878         track->shift_keyframes(position, length, 0);
881 void Edits::shift_effects_recursive(int64_t position, int64_t length)
883         track->shift_effects(position, length, 0);