/*
* CINELERRA
- * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
+ * Copyright (C) 2008-2017 Adam Williams <broadcast at earthling dot net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
#include "bcsignals.h"
#include "cache.h"
#include "clip.h"
+#include "clipedls.h"
#include "edit.h"
#include "edits.h"
#include "edl.h"
#include "filexml.h"
#include "filesystem.h"
#include "localsession.h"
-#include "nestededls.h"
#include "plugin.h"
#include "strategies.inc"
#include "track.h"
}
-void Edits::insert_asset(Asset *asset,
- EDL *nested_edl,
- int64_t length,
- int64_t position,
- int track_number)
+void Edits::insert_asset(Asset *asset, EDL *nested_edl,
+ int64_t length, int64_t position, int track_number)
{
Edit *new_edit = insert_new_edit(position);
{
EDL *dest_nested_edl = 0;
if(source_edit->nested_edl)
- dest_nested_edl = edl->nested_edls->get_copy(source_edit->nested_edl);
+ dest_nested_edl = edl->nested_edls.get_nested(source_edit->nested_edl);
// Update Assets
Asset *dest_asset = 0;
return new_edit;
}
-
Edit* Edits::split_edit(int64_t position)
{
// Get edit containing position
Edit *edit = editof(position, PLAY_FORWARD, 0);
-// No edit found, make one - except when we are at zero position!
- if(!edit && position != 0) {
- if (length() == position) {
- edit = last; // we do not need any edit to extend past the last one
- }
- else if (!last || length() < position) {
-
- // Even when track is completely empty or split is beyond last edit, return correct edit
- Edit *empty = create_edit();
- if (last)
- empty->startproject = length(); // end of last edit
- else
- empty->startproject = 0; // empty track
- empty->length = position - empty->startproject;
- insert_after(last, empty);
- edit = empty;
- }
- else {
- // now we are now surely in situation where we have
- // a) broken edit list or b) negative position... report error!
- printf("ERROR!\n");
- printf("Trying to insert edit at position, but failed: %ji\n", position);
- printf("Dump is here:\n");
- track->dump(stdout);
- return 0;
- }
- }
if(!edit) return 0;
- return split_edit(edit, position);
-}
-
-Edit* Edits::split_edit(Edit *edit, int64_t position)
-{
// Split would have created a 0 length
// if(edit->startproject == position) return edit;
// Create anyway so the return value comes before position
Edit *new_edit = create_edit();
insert_after(edit, new_edit);
- if (edit) // if we have actually split the edit, do the funky stuff!
- {
- new_edit->copy_from(edit);
- new_edit->length = new_edit->startproject + new_edit->length - position;
- edit->length = position - edit->startproject;
- new_edit->startsource += edit->length;
-
+ new_edit->copy_from(edit);
+ new_edit->length = new_edit->startproject + new_edit->length - position;
+ edit->length = position - edit->startproject;
+ new_edit->startproject = position;
+ new_edit->startsource += edit->length;
// Decide what to do with the transition
- if(edit->length && edit->transition)
- {
- delete new_edit->transition;
- new_edit->transition = 0;
- }
+ if(edit->length && edit->transition) {
+ delete new_edit->transition;
+ new_edit->transition = 0;
+ }
- if(edit->transition && edit->transition->length > edit->length)
- edit->transition->length = edit->length;
- if(new_edit->transition && new_edit->transition->length > new_edit->length)
- new_edit->transition->length = new_edit->length;
- } else
- new_edit->length = 0;
- new_edit->startproject = position;
+ if(edit->transition && edit->transition->length > edit->length)
+ edit->transition->length = edit->length;
+ if(new_edit->transition && new_edit->transition->length > new_edit->length)
+ new_edit->transition->length = new_edit->length;
return new_edit;
}
}
}
-
-
-
-
-
-
-
-
-
-
-
-
+int Edits::is_glitch(Edit *edit)
+{
+ if( track->data_type != TRACK_AUDIO ) return 0;
+ int64_t threshold = edl->session->frame_rate > 0 ?
+ 0.5 * edl->session->sample_rate / edl->session->frame_rate : 0;
+// audio edit shorter than .5 frames is a glitch
+ return edit->length < threshold ? 1 : 0;
+}
int Edits::optimize()
{
int result = 1;
Edit *current;
-
//printf("Edits::optimize %d\n", __LINE__);
// Sort edits by starting point
while(result)
result = 0;
// delete 0 length edits
- for(current = first; !result && current; ) {
+ for( current = first; !result && current; ) {
Edit* next = current->next;
- if(current->length == 0) {
- // Be smart with transitions!
- if (next && current->transition && !next->transition) {
+ if( current->length == 0 ) {
+ if( next && current->transition && !next->transition) {
next->transition = current->transition;
next->transition->edit = next;
current->transition = 0;
current = next;
}
-//printf("Edits::optimize %d result=%d\n", __LINE__, result);
-// merge same files or transitions
- if(track->data_type == TRACK_SUBTITLE ) continue;
-
- for(current = first; !result && current && current->next; ) {
- Edit *next_edit = current->next;
-
-// printf("Edits::optimize %d %lld=%lld %d=%d %p=%p %p=%p\n",
-// __LINE__, current->startsource + current->length, next_edit->startsource,
-// current->channel, next_edit->channel, current->asset, next_edit->asset,
-// current->nested_edl, next_edit->nested_edl);
-
-
+// merge same files or transitions, and deglitch
+ if( !result && track->data_type != TRACK_SUBTITLE ) {
+ current = first;
+ if( current && !current->hard_right &&
+ current->next && !current->next->hard_left &&
+ is_glitch(current) ) {
+// if the first edit is a glitch, change it to silence
+ current->asset = 0;
+ current->nested_edl = 0;
+ }
+ 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;
+// next edit is a glitch
+ if( is_glitch(next_edit) )
+ break;
// both edits are silence & not a plugin
-// source channels are identical
-// assets are identical
- if( (current->silence() && next_edit->silence() && !current->is_plugin) ||
- (current->startsource + current->length == next_edit->startsource &&
- current->channel == next_edit->channel &&
- current->asset == next_edit->asset &&
- current->nested_edl == next_edit->nested_edl)) {
-//printf("Edits::optimize %d\n", __LINE__);
- current->length += next_edit->length;
- remove(next_edit);
- result = 1;
- continue;
- }
-
- current = current->next;
+ 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 &&
+ current->asset == next_edit->asset &&
+ current->nested_edl == next_edit->nested_edl ) {
+// and stop and start in the same frame
+ int64_t current_end = current->startsource + current->length;
+ int64_t next_start = next_edit->startsource;
+ if( current_end == next_start ||
+ EQUIV(edl->frame_align(track->from_units(current_end), 1),
+ edl->frame_align(track->from_units(next_start), 1)) )
+ break;
+ }
+ }
+ if( next_edit ) {
+ int64_t current_start = current->startproject;
+ int64_t next_end = next_edit->startproject + next_edit->length;
+ current->length = next_end - current_start;
+ remove(next_edit);
+ result = 1;
+ }
}
- if(last && last->silence()) {
+ if( last && last->silence() && !last->transition ) {
delete last;
result = 1;
}
}
-//track->dump();
return 0;
}
while( !file->read_tag() ) {
//printf("Edits::load 1 %s\n", file->tag.get_title());
- if(!strcmp(file->tag.get_title(), "EDIT"))
- {
+ if(!strcmp(file->tag.get_title(), "EDIT")) {
load_edit(file, startproject, track_offset);
}
else if(!strcmp(file->tag.get_title(), "/EDITS"))
{
Edit* current = append_new_edit();
current->load_properties(file, startproject);
+
startproject += current->length;
while( !file->read_tag() ) {
- if(file->tag.title_is("NESTED_EDL"))
- {
+ if(file->tag.title_is("NESTED_EDL")) {
char path[BCTEXTLEN];
path[0] = 0;
file->tag.get_property("SRC", path);
//printf("Edits::load_edit %d path=%s\n", __LINE__, path);
- if(path[0] != 0)
- {
- current->nested_edl = edl->nested_edls->get(path);
+ if(path[0] != 0) {
+ current->nested_edl = edl->nested_edls.load(path);
}
// printf("Edits::load_edit %d nested_edl->path=%s\n",
-// __LINE__,
-// current->nested_edl->path);
+// __LINE__, current->nested_edl->path);
}
- else if(file->tag.title_is("FILE"))
- {
+ else if(file->tag.title_is("FILE")) {
char filename[BCTEXTLEN];
filename[0] = 0;
file->tag.get_property("SRC", filename);
// Extend path
- if(filename[0] != 0)
- {
+ if(filename[0] != 0) {
char directory[BCTEXTLEN], edl_directory[BCTEXTLEN];
FileSystem fs;
fs.set_current_dir("");
fs.extract_dir(directory, filename);
- if(!strlen(directory))
- {
+ if(!strlen(directory)) {
fs.extract_dir(edl_directory, file->filename);
fs.join_names(directory, edl_directory, filename);
strcpy(filename, directory);
}
current->asset = edl->assets->get_asset(filename);
}
- else
- {
+ else {
current->asset = 0;
}
//printf("Edits::load_edit 5\n");
}
- else if(file->tag.title_is("TRANSITION"))
- {
+ else if(file->tag.title_is("TRANSITION")) {
current->transition = new Transition(edl, current, "",
track->to_units(edl->session->default_transition_length, 1));
current->transition->load_xml(file);
Edit *current = 0;
if(use_nudge && track) position += track->nudge;
- if(direction == PLAY_FORWARD)
- {
- for(current = last; current; current = PREVIOUS)
- {
+ if(direction == PLAY_FORWARD) {
+ for(current = last; current; current = PREVIOUS) {
if(current->startproject <= position && current->startproject + current->length > position)
return current;
}
}
else
- if(direction == PLAY_REVERSE)
- {
- for(current = first; current; current = NEXT)
- {
+ if(direction == PLAY_REVERSE) {
+ for(current = first; current; current = NEXT) {
if(current->startproject < position && current->startproject + current->length >= position)
return current;
}
if(track && use_nudge) position += track->nudge;
// Get the current edit
- for(current = first; current; current = NEXT)
- {
+ for(current = first; current; current = NEXT) {
if(current->startproject <= position &&
current->startproject + current->length > position)
break;
// Get the edit's asset
// TODO: descend into nested EDLs
- if(current)
- {
+ if(current) {
if(!current->asset)
current = 0;
}
Edit* edit2 = editof(end, PLAY_FORWARD, 0);
Edit* current_edit;
+ if(end == start) return; // nothing selected
if(!edit1 && !edit2) return; // nothing selected
- if(!edit2)
- { // edit2 beyond end of track
+ if(!edit2) { // edit2 beyond end of track
edit2 = last;
end = this->length();
}
- if(edit1 != edit2)
+ if( edit1 && edit2 && edit1 != edit2)
{
// in different edits
edit2->startproject += end - edit2->startproject;
// delete
- for(current_edit = edit1->next; current_edit && current_edit != edit2;)
- {
+ for(current_edit = edit1->next; current_edit && current_edit != edit2;) {
Edit* next = current_edit->next;
remove(current_edit);
current_edit = next;
}
// shift
- for(current_edit = edit2; current_edit; current_edit = current_edit->next)
- {
+ for(current_edit = edit2; current_edit; current_edit = current_edit->next) {
current_edit->startproject -= end - start;
}
}
- else
- {
+ else {
// in same edit. paste_edit depends on this
// create a new edit
current_edit = split_edit(start);
-
- current_edit->length -= end - start;
- current_edit->startsource += end - start;
-
+ if( current_edit ) {
+ current_edit->length -= end - start;
+ current_edit->startsource += end - start;
// shift
- for(current_edit = current_edit->next;
- current_edit;
- current_edit = current_edit->next)
- {
- current_edit->startproject -= end - start;
+ while( (current_edit=current_edit->next) != 0 ) {
+ current_edit->startproject -= end - start;
+ }
}
}
// Used by edit handle and plugin handle movement but plugin handle movement
// can only effect other plugins.
-void Edits::clear_recursive(int64_t start,
- int64_t end,
- int edit_edits,
- int edit_labels,
- int edit_plugins,
- int edit_autos,
+void Edits::clear_recursive(int64_t start, int64_t end,
+ int edit_edits, int edit_labels, int edit_plugins, int edit_autos,
Edits *trim_edits)
{
//printf("Edits::clear_recursive 1\n");
- track->clear(start,
- end,
- edit_edits,
- edit_labels,
- edit_plugins,
- edit_autos,
- 0,
+ track->clear(start, end,
+ edit_edits, edit_labels, edit_plugins, edit_autos, 0,
trim_edits);
}
-int Edits::clear_handle(double start,
- double end,
- int edit_plugins,
- int edit_autos,
- double &distance)
+int Edits::clear_handle(double start, double end,
+ int edit_plugins, int edit_autos, double &distance)
{
Edit *current_edit;
distance = 0.0; // if nothing is found, distance is 0!
for(current_edit = first;
current_edit && current_edit->next;
- current_edit = current_edit->next)
- {
+ current_edit = current_edit->next) {
- if(current_edit->asset &&
- current_edit->next->asset)
- {
+ if(current_edit->asset && current_edit->next->asset) {
- if(current_edit->asset->equivalent(*current_edit->next->asset,
- 0,
- 0))
- {
+ if(current_edit->asset->equivalent(*current_edit->next->asset, 0, 0, edl)) {
// Got two consecutive edits in same source
if(edl->equivalent(track->from_units(current_edit->next->startproject),
- start))
- {
+ start)) {
// handle selected
int length = -current_edit->length;
current_edit->length = current_edit->next->startsource - current_edit->startsource;
return 0;
}
-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,
+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)
{
int result = 0;
Edit *current_edit;
//printf("Edits::modify_handles 1 %d %f %f\n", currentend, newposition, oldposition);
- if(currentend == 0)
- {
+ if(currentend == 0) {
// left handle
- for(current_edit = first; current_edit && !result;)
- {
+ for(current_edit = first; current_edit && !result;) {
if(edl->equivalent(track->from_units(current_edit->startproject),
- oldposition))
- {
+ oldposition)) {
// edit matches selection
//printf("Edits::modify_handles 3 %f %f\n", newposition, oldposition);
oldposition = track->from_units(current_edit->startproject);
result = 1;
- if(newposition >= oldposition)
- {
+ 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,
if(!result) current_edit = current_edit->next;
}
}
- else
- {
+ else {
// right handle selected
- for(current_edit = first; current_edit && !result;)
- {
+ for(current_edit = first; current_edit && !result;) {
if(edl->equivalent(track->from_units(current_edit->startproject) +
- track->from_units(current_edit->length), oldposition))
- {
+ track->from_units(current_edit->length), oldposition)) {
oldposition = track->from_units(current_edit->startproject) +
track->from_units(current_edit->length);
result = 1;
//printf("Edits::modify_handle 3\n");
- if(newposition <= oldposition)
- {
+ if(newposition <= oldposition) {
// shift end of edit in
//printf("Edits::modify_handle 4\n");
current_edit->shift_end_in(edit_mode,
else
{
// move end of edit out
-//printf("Edits::modify_handle 6\n");
+//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),
void Edits::paste_silence(int64_t start, int64_t end)
{
- // paste silence does not do anything if
- // a) paste silence is on empty track
- // b) paste silence is after last edit
- // in both cases editof returns NULL
Edit *new_edit = editof(start, PLAY_FORWARD, 0);
if (!new_edit) return;
- if (!new_edit->asset)
- { // in this case we extend already existing edit
- new_edit->length += end - start;
- } else
- { // we are in fact creating a new edit
+ if( !new_edit->silence() ) {
new_edit = insert_new_edit(start);
new_edit->length = end - start;
}
- for(Edit *current = new_edit->next; current; current = NEXT)
- {
+ else
+ new_edit->length += end - start;
+
+ for(Edit *current = new_edit->next; current; current = NEXT) {
current->startproject += end - start;
}
+
return;
}
{
Edit *new_edit = insert_new_edit(start);
new_edit->length = end - start;
- for(Edit *current = new_edit->next; current; current = NEXT)
- {
+ for(Edit *current = new_edit->next; current; current = NEXT) {
current->startproject += end - start;
}
return new_edit;
{
Edit *new_edit = split_edit(position);
- for(Edit *current = first;
- current;
- current = NEXT)
- {
- if(current->startproject >= position)
- {
+ for(Edit *current = first; current; current = NEXT) {
+ if(current->startproject >= position) {
current->shift(difference);
}
}