Credit Andrew - fix vorbis audio which was scratchy and ensure aging plugin does...
[goodguy/cinelerra.git] / cinelerra-5.1 / cinelerra / edits.C
index a79bb171d9ba2f4178f4d5a7b45b54506a4a9a44..71dd3b18e293ad41af189f0d9f161ceb1f010822 100644 (file)
@@ -31,6 +31,7 @@
 #include "edits.h"
 #include "edl.h"
 #include "edlsession.h"
+#include "ffmpeg.h"
 #include "file.h"
 #include "filexml.h"
 #include "filesystem.h"
@@ -178,7 +179,7 @@ void Edits::insert_edits(Edits *source_edits,
 // Open destination area
                Edit *dest_edit = insert_new_edit(position + source_edit->startproject);
 
-               dest_edit->copy_from(source_edit);
+               dest_edit->clone_from(source_edit);
                dest_edit->asset = dest_asset;
                dest_edit->nested_edl = dest_nested_edl;
                dest_edit->startproject = position + source_edit->startproject;
@@ -220,10 +221,10 @@ Edit* Edits::insert_new_edit(int64_t position)
 {
 //printf("Edits::insert_new_edit 1\n");
        Edit *current = split_edit(position);
-       if(current) current = PREVIOUS;
 
 //printf("Edits::insert_new_edit 1\n");
        Edit *new_edit = create_edit();
+       if( current ) current = PREVIOUS;
 //printf("Edits::insert_new_edit 1\n");
        insert_after(current, new_edit);
        new_edit->startproject = position;
@@ -242,11 +243,21 @@ Edit* Edits::split_edit(int64_t position)
 
        Edit *new_edit = create_edit();
        insert_after(edit, new_edit);
-       new_edit->copy_from(edit);
+       new_edit->clone_from(edit);
        new_edit->length = new_edit->startproject + new_edit->length - position;
        edit->length = position - edit->startproject;
+       if( !new_edit->length || edit->silence() )
+               new_edit->hard_left = new_edit->hard_right = 0;
+       else if( !edit->length )
+               edit->hard_left = edit->hard_right = 0;
+       else {
+               new_edit->hard_right = edit->hard_right;
+               new_edit->hard_left = edit->hard_right = 0;
+       }
        new_edit->startproject = position;
-       new_edit->startsource += edit->length;
+       int64_t edit_start = edit->startproject;
+       int64_t edit_end = edit_start + edit->length;
+       new_edit->startsource += track->speed_length(edit_start, edit_end);
 
 // Decide what to do with the transition
        if(edit->length && edit->transition) {
@@ -324,6 +335,14 @@ int Edits::optimize()
                }
        }
 
+// trim edits before position 0
+       while( first && first->startproject+first->length < 0 )
+               delete first;
+       if( first && first->startproject < 0 ) {
+               first->length += first->startproject;
+               first->startproject = 0;
+       }
+
 // Insert silence between edits which aren't consecutive
        for(current = last; current; current = current->previous)
        {
@@ -357,13 +376,19 @@ int Edits::optimize()
 
 // delete 0 length edits
                for( current = first; !result && current; ) {
-                       Edit* next = current->next;
+                       Edit* prev = current->previous, *next = current->next;
                        if( current->length == 0 ) {
                                if( next && current->transition && !next->transition) {
                                        next->transition = current->transition;
                                        next->transition->edit = next;
                                        current->transition = 0;
                                }
+                               if( !current->silence() ) {
+                                       if( current->hard_left && next && !next->silence() )
+                                               next->hard_left = 1;
+                                       if( current->hard_right && prev && !prev->silence())
+                                               prev->hard_right = 1;
+                               }
                                delete current;
                                result = 1;
                                break;
@@ -384,13 +409,14 @@ int Edits::optimize()
                        Edit *next_edit = 0;
                        for( ; current && (next_edit=current->next); current=NEXT ) {
 // both edges are not hard edges
-                               if( current->hard_right || next_edit->hard_left ) continue;
+                               if( current->hard_right || next_edit->hard_left )
+                                       continue;
 // next edit is a glitch
                                if( is_glitch(next_edit) )
                                        break;
 // both edits are silence & not a plugin
-                               if( !current->is_plugin && current->silence() &&
-                                   !next_edit->is_plugin && next_edit->silence() )
+                               if( !current->is_plugin() && current->silence() &&
+                                   !next_edit->is_plugin() && next_edit->silence() )
                                        break;
 // source channels are identical & assets are identical
                                if( !result && current->channel == next_edit->channel &&
@@ -409,12 +435,14 @@ int Edits::optimize()
                                int64_t current_start = current->startproject;
                                int64_t next_end = next_edit->startproject + next_edit->length;
                                current->length = next_end - current_start;
+                               current->hard_right = next_edit->hard_right;
                                remove(next_edit);
                                result = 1;
                        }
                }
 
-               if( last && last->silence() && !last->transition ) {
+               if( last && last->silence() &&
+                   !last->transition && !last->hard_left && !last->hard_right ) {
                        delete last;
                        result = 1;
                }
@@ -532,6 +560,13 @@ Edit* Edits::editof(int64_t position, int direction, int use_nudge)
        return 0;     // return 0 on failure
 }
 
+Edit* Edits::get_edit(int id)
+{
+       Edit *current = first;
+       while( current && current->orig_id != id ) current = NEXT;
+       return current;
+}
+
 Edit* Edits::get_playable_edit(int64_t position, int use_nudge)
 {
        Edit *current;
@@ -603,7 +638,7 @@ void Edits::clear(int64_t start, int64_t end)
 //printf("Edits::clear 3.5 %d %d %d %d\n", edit1->startproject, edit1->length, edit2->startproject, edit2->length);
                edit1->length = start - edit1->startproject;
                edit2->length -= end - edit2->startproject;
-               edit2->startsource += end - edit2->startproject;
+               edit2->startsource += track->speed_length(edit2->startproject, end);
                edit2->startproject += end - edit2->startproject;
 
 // delete
@@ -623,7 +658,7 @@ void Edits::clear(int64_t start, int64_t end)
                current_edit = split_edit(start);
                if( current_edit ) {
                        current_edit->length -= end - start;
-                       current_edit->startsource += end - start;
+                       current_edit->startsource += track->speed_length(start, end);
 // shift
                        while( (current_edit=current_edit->next) != 0 ) {
                                current_edit->startproject -= end - start;
@@ -642,8 +677,7 @@ void Edits::clear_recursive(int64_t start, int64_t end,
 {
 //printf("Edits::clear_recursive 1\n");
        track->clear(start, end,
-               edit_edits, edit_labels, edit_plugins, edit_autos, 0,
-               trim_edits);
+               edit_edits, edit_labels, edit_plugins, edit_autos, trim_edits);
 }
 
 
@@ -679,8 +713,7 @@ int Edits::clear_handle(double start, double end,
 // Lengthen effects
                                        if(edit_plugins)
                                                track->shift_effects(current_edit->next->startproject,
-                                                       length,
-                                                       edit_autos);
+                                                               length, edit_autos, 0);
 
                                        for(current_edit = current_edit->next; current_edit; current_edit = current_edit->next)
                                        {
@@ -700,47 +733,38 @@ int Edits::clear_handle(double start, double end,
 
 int Edits::modify_handles(double oldposition, double newposition, int currentend,
        int edit_mode, int edit_edits, int edit_labels, int edit_plugins, int edit_autos,
-       Edits *trim_edits)
+       Edits *trim_edits, int group_id)
 {
        int result = 0;
        Edit *current_edit;
+       Edit *left = 0, *right = 0;
+       if( group_id > 0 ) {
+               double start = DBL_MAX, end = DBL_MIN;
+               for( Edit *edit=first; edit; edit=edit->next ) {
+                       if( edit->group_id != group_id ) continue;
+                       double edit_start = edit->track->from_units(edit->startproject);
+                       if( edit_start < start ) { start = edit_start;  left = edit; }
+                       double edit_end = edit->track->from_units(edit->startproject+edit->length);
+                       if( edit_end > end ) { end = edit_end;  right = edit; }
+               }
+       }
 
 //printf("Edits::modify_handles 1 %d %f %f\n", currentend, newposition, oldposition);
        if(currentend == 0) {
 // left handle
                for(current_edit = first; current_edit && !result;) {
-                       if(edl->equivalent(track->from_units(current_edit->startproject),
-                               oldposition)) {
+                       if( group_id > 0 ? current_edit == left :
+                           edl->equivalent(track->from_units(current_edit->startproject),
+                               oldposition) ) {
 // edit matches selection
 //printf("Edits::modify_handles 3 %f %f\n", newposition, oldposition);
+                               double delta = newposition - oldposition;
                                oldposition = track->from_units(current_edit->startproject);
+                               if( group_id > 0 ) newposition = oldposition + delta;
+                               current_edit->shift_start(edit_mode,
+                                       track->to_units(newposition, 0), track->to_units(oldposition, 0),
+                                       edit_labels, edit_autos, edit_plugins, trim_edits);
                                result = 1;
-
-                               if(newposition >= oldposition) {
-//printf("Edits::modify_handle 1 %s %f %f\n", track->title, oldposition, newposition);
-// shift start of edit in
-                                       current_edit->shift_start_in(edit_mode,
-                                               track->to_units(newposition, 0),
-                                               track->to_units(oldposition, 0),
-                                               edit_edits,
-                                               edit_labels,
-                                               edit_plugins,
-                                               edit_autos,
-                                               trim_edits);
-                               }
-                               else
-                               {
-//printf("Edits::modify_handle 2 %s\n", track->title);
-// move start of edit out
-                                       current_edit->shift_start_out(edit_mode,
-                                               track->to_units(newposition, 0),
-                                               track->to_units(oldposition, 0),
-                                               edit_edits,
-                                               edit_labels,
-                                               edit_plugins,
-                                               edit_autos,
-                                               trim_edits);
-                               }
                        }
 
                        if(!result) current_edit = current_edit->next;
@@ -749,40 +773,18 @@ int Edits::modify_handles(double oldposition, double newposition, int currentend
        else {
 // right handle selected
                for(current_edit = first; current_edit && !result;) {
-                       if(edl->equivalent(track->from_units(current_edit->startproject) +
-                               track->from_units(current_edit->length), oldposition)) {
-               oldposition = track->from_units(current_edit->startproject) +
+                       if( group_id > 0 ? current_edit == right :
+                           edl->equivalent(track->from_units(current_edit->startproject) +
+                                       track->from_units(current_edit->length), oldposition) ) {
+                               double delta = newposition - oldposition;
+                               oldposition = track->from_units(current_edit->startproject) +
                                        track->from_units(current_edit->length);
+                               if( group_id > 0 ) newposition = oldposition + delta;
                                result = 1;
 
-//printf("Edits::modify_handle 3\n");
-                               if(newposition <= oldposition) {
-// shift end of edit in
-//printf("Edits::modify_handle 4\n");
-                                       current_edit->shift_end_in(edit_mode,
-                                               track->to_units(newposition, 0),
-                                               track->to_units(oldposition, 0),
-                                               edit_edits,
-                                               edit_labels,
-                                               edit_plugins,
-                                               edit_autos,
-                                               trim_edits);
-//printf("Edits::modify_handle 5\n");
-                               }
-                               else
-                               {
-// move end of edit out
-//printf("Edits::modify_handle %d edit_mode=%d\n", __LINE__, edit_mode);
-                                       current_edit->shift_end_out(edit_mode,
-                                               track->to_units(newposition, 0),
-                                               track->to_units(oldposition, 0),
-                                               edit_edits,
-                                               edit_labels,
-                                               edit_plugins,
-                                               edit_autos,
-                                               trim_edits);
-//printf("Edits::modify_handle 7\n");
-                               }
+                               current_edit->shift_end(edit_mode,
+                                       track->to_units(newposition, 0), track->to_units(oldposition, 0),
+                                       edit_labels, edit_autos, edit_plugins, trim_edits);
                        }
 
                        if(!result) current_edit = current_edit->next;
@@ -794,13 +796,12 @@ int Edits::modify_handles(double oldposition, double newposition, int currentend
        return 0;
 }
 
-
 void Edits::paste_silence(int64_t start, int64_t end)
 {
        Edit *new_edit = editof(start, PLAY_FORWARD, 0);
        if (!new_edit) return;
 
-       if( !new_edit->silence() ) {
+       if( !new_edit->silence() || new_edit->hard_right ) {
                new_edit = insert_new_edit(start);
                new_edit->length = end - start;
        }
@@ -844,6 +845,82 @@ void Edits::shift_keyframes_recursive(int64_t position, int64_t length)
 
 void Edits::shift_effects_recursive(int64_t position, int64_t length, int edit_autos)
 {
-       track->shift_effects(position, length, edit_autos);
+       track->shift_effects(position, length, edit_autos, 0);
+}
+
+double Edits::early_timecode()
+{
+       double result = -1;
+       for( Edit *edit=first; edit; edit=edit->next ) {
+               Asset *asset = edit->asset;
+               if( !asset ) continue;
+               if( asset->timecode < -1 )
+                       asset->timecode = FFMPEG::get_timecode(asset->path,
+                               track->data_type, edit->channel,
+                               edl->session->frame_rate);
+               if( asset->timecode < 0 ) continue;
+               if( result < 0 ||  result > asset->timecode )
+                       result = asset->timecode;
+       }
+       return result;
+}
+
+void Edits::align_timecodes(double offset)
+{
+       for( Edit *edit=first, *next=0; edit; edit=next ) {
+               next = edit->next;
+               if( edit->silence() ) delete edit;
+       }
+       for( Edit *edit=first, *next=0; edit; edit=next ) {
+               next = edit->next;
+               Asset *asset = edit->asset;
+               if( !asset && asset->timecode < 0 ) continue;
+               double position = asset->timecode - offset;
+               edit->startproject = track->to_units(position, 1) + edit->startsource;
+       }
+       int result = 1;
+       while( result ) {
+               result = 0;
+               for( Edit *edit=first, *next=0; edit; edit=next ) {
+                       next = edit->next;
+                       if( !next || next->startproject >= edit->startproject ) continue;
+                       swap(next, edit);
+                       next = edit;
+                       result = 1;
+               }
+       }
+       int64_t startproject = 0;
+       for( Edit *edit=first, *next=0; edit; edit=next ) {
+               if( (next = edit->next) != 0 ) {
+                       int64_t length = next->startproject - startproject;
+                       if( length > edit->length ) edit->length = length;
+               }
+               int64_t length = edit->startproject - startproject;
+               if( length > 0 ) {
+                       Edit *new_edit = create_edit();
+                       insert_before(edit, new_edit);
+                       new_edit->startproject = startproject;
+                       new_edit->length = length;
+                       startproject = edit->startproject;
+               }
+               startproject += edit->length;
+       }
+}
+
+void Edits::update_idxbl_length(int id, int64_t du)
+{
+       for( Edit *edit=first; edit; edit=edit->next ) {
+               Indexable *idxbl = edit->asset ? (Indexable *)edit->asset :
+                       edit->nested_edl ? (Indexable *)edit->nested_edl : 0;
+               if( !idxbl || idxbl->id != id ) continue;
+               edit->length += du;
+               if(  edit->length > 0 && edit->next ) {
+                       int64_t next_start = edit->next->startproject;
+                       int64_t edit_end = edit->startproject + edit->length;
+                       if( edit_end > next_start )
+                               edit->length = next_start - edit->startproject;
+               }
+               if( edit->length < 0 ) edit->length = 0;
+       }
 }