4 * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
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.
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.
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
25 #include "automation.h"
26 #include "bcsignals.h"
32 #include "edlsession.h"
35 #include "filesystem.h"
36 #include "localsession.h"
37 #include "nestededls.h"
39 #include "strategies.inc"
41 #include "transition.h"
42 #include "transportque.inc"
46 Edits::Edits(EDL *edl, Track *track)
58 void Edits::equivalent_output(Edits *edits, int64_t *result)
60 // For the case of plugin sets, a new plugin set may be created with
61 // plugins only starting after 0. We only want to restart brender at
62 // the first plugin in this case.
63 for(Edit *current = first, *that_current = edits->first;
64 current || that_current;
66 that_current = that_current->next)
68 //printf("Edits::equivalent_output 1 %d\n", *result);
69 if(!current && that_current)
71 int64_t position1 = (last ? last->startproject + last->length : 0);
72 int64_t position2 = that_current->startproject;
73 if(*result < 0 || *result > MIN(position1, position2))
74 *result = MIN(position1, position2);
78 if(current && !that_current)
80 int64_t position1 = (edits->last ? edits->last->startproject + edits->last->length : 0);
81 int64_t position2 = current->startproject;
82 if(*result < 0 || *result > MIN(position1, position2))
83 *result = MIN(position1, position2);
88 //printf("Edits::equivalent_output 2 %d\n", *result);
89 current->equivalent_output(that_current, result);
90 //printf("Edits::equivalent_output 3 %d\n", *result);
95 void Edits::copy_from(Edits *edits)
97 while(last) delete last;
98 for(Edit *current = edits->first; current; current = NEXT)
100 Edit *new_edit = append(create_edit());
101 new_edit->copy_from(current);
106 Edits& Edits::operator=(Edits& edits)
108 printf("Edits::operator= 1\n");
114 void Edits::insert_asset(Asset *asset,
120 Edit *new_edit = insert_new_edit(position);
122 new_edit->nested_edl = nested_edl;
123 new_edit->asset = asset;
124 new_edit->startsource = 0;
125 new_edit->startproject = position;
126 new_edit->length = length;
130 if(track->data_type == TRACK_AUDIO)
131 new_edit->channel = track_number % nested_edl->session->audio_channels;
133 new_edit->channel = 0;
136 if(asset && !nested_edl)
138 if(asset->audio_data)
139 new_edit->channel = track_number % asset->channels;
141 if(asset->video_data)
142 new_edit->channel = track_number % asset->layers;
145 //printf("Edits::insert_asset %d %d\n", new_edit->channel, new_edit->length);
146 for(Edit *current = new_edit->next; current; current = NEXT)
148 current->startproject += length;
152 void Edits::insert_edits(Edits *source_edits,
157 //int64_t clipboard_end = position + min_length;
158 // Length pasted so far
159 int64_t source_len = 0;
161 // Fill region between end of edit table and beginning of pasted segment
162 // with silence. Can't call from insert_new_edit because it's recursive.
163 if(position > length())
165 paste_silence(length(), position);
169 for(Edit *source_edit = source_edits->first;
171 source_edit = source_edit->next)
173 EDL *dest_nested_edl = 0;
174 if(source_edit->nested_edl)
175 dest_nested_edl = edl->nested_edls->get_copy(source_edit->nested_edl);
178 Asset *dest_asset = 0;
179 if(source_edit->asset)
180 dest_asset = edl->assets->update(source_edit->asset);
181 // Open destination area
182 Edit *dest_edit = insert_new_edit(position + source_edit->startproject);
184 dest_edit->copy_from(source_edit);
185 dest_edit->asset = dest_asset;
186 dest_edit->nested_edl = dest_nested_edl;
187 dest_edit->startproject = position + source_edit->startproject;
191 // Shift keyframes in source edit to their position in the
192 // destination edit for plugin case
193 if(edit_autos) dest_edit->shift_keyframes(position);
197 // Shift following edits and keyframes in following edits by length
198 // in current source edit.
199 for(Edit *future_edit = dest_edit->next;
201 future_edit = future_edit->next)
203 future_edit->startproject += dest_edit->length;
204 future_edit->shift_keyframes(dest_edit->length);
207 source_len += source_edit->length;
213 // Fill remaining clipboard length with silence
214 if(source_len < min_length)
216 //printf("Edits::insert_edits %d\n", __LINE__);
217 paste_silence(position + source_len, position + min_length);
223 // Can't paste silence in here because it's used by paste_silence.
224 Edit* Edits::insert_new_edit(int64_t position)
227 //printf("Edits::insert_new_edit 1\n");
228 current = split_edit(position);
229 if(current) current = PREVIOUS;
231 //printf("Edits::insert_new_edit 1\n");
232 Edit *new_edit = create_edit();
233 //printf("Edits::insert_new_edit 1\n");
234 insert_after(current, new_edit);
235 new_edit->startproject = position;
236 //printf("Edits::insert_new_edit 2\n");
241 Edit* Edits::split_edit(int64_t position)
243 // Get edit containing position
244 Edit *edit = editof(position, PLAY_FORWARD, 0);
246 return split_edit(edit, position);
249 Edit* Edits::split_edit(Edit *edit, int64_t position)
251 // Split would have created a 0 length
252 // if(edit->startproject == position) return edit;
253 // Create anyway so the return value comes before position
255 Edit *new_edit = create_edit();
256 insert_after(edit, new_edit);
257 new_edit->copy_from(edit);
258 new_edit->length = new_edit->startproject + new_edit->length - position;
259 edit->length = position - edit->startproject;
260 new_edit->startproject = edit->startproject + edit->length;
261 new_edit->startsource += edit->length;
264 // Decide what to do with the transition
265 if(edit->length && edit->transition)
267 delete new_edit->transition;
268 new_edit->transition = 0;
271 if(edit->transition && edit->transition->length > edit->length)
272 edit->transition->length = edit->length;
273 if(new_edit->transition && new_edit->transition->length > new_edit->length)
274 new_edit->transition->length = new_edit->length;
278 int Edits::save(FileXML *xml, const char *output_path)
280 copy(0, length(), xml, output_path);
284 void Edits::resample(double old_rate, double new_rate)
286 for(Edit *current = first; current; current = NEXT)
288 current->startproject = Units::to_int64((double)current->startproject /
291 if(PREVIOUS) PREVIOUS->length = current->startproject - PREVIOUS->startproject;
292 current->startsource = Units::to_int64((double)current->startsource /
295 if(!NEXT) current->length = Units::to_int64((double)current->length /
298 if(current->transition)
300 current->transition->length = Units::to_int64(
301 (double)current->transition->length /
305 current->resample(old_rate, new_rate);
322 int Edits::optimize()
328 //printf("Edits::optimize %d\n", __LINE__);
329 // Sort edits by starting point
334 for(current = first; current; current = NEXT)
336 Edit *next_edit = NEXT;
338 if(next_edit && next_edit->startproject < current->startproject)
340 swap(next_edit, current);
346 // Insert silence between edits which aren't consecutive
347 for(current = last; current; current = current->previous)
349 if(current->previous)
351 Edit *previous_edit = current->previous;
352 if(current->startproject -
353 previous_edit->startproject -
354 previous_edit->length > 0)
356 Edit *new_edit = create_edit();
357 insert_before(current, new_edit);
358 new_edit->startproject = previous_edit->startproject + previous_edit->length;
359 new_edit->length = current->startproject -
360 previous_edit->startproject -
361 previous_edit->length;
365 if(current->startproject > 0)
367 Edit *new_edit = create_edit();
368 insert_before(current, new_edit);
369 new_edit->length = current->startproject;
379 // delete 0 length edits
381 current && !result; )
383 if(current->length == 0)
385 Edit* next = current->next;
391 current = current->next;
394 //printf("Edits::optimize %d result=%d\n", __LINE__, result);
395 // merge same files or transitions
396 if(track->data_type != TRACK_SUBTITLE )
398 current && current->next && !result; )
400 Edit *next_edit = current->next;
402 // printf("Edits::optimize %d %lld=%lld %d=%d %p=%p %p=%p\n",
404 // current->startsource + current->length,
405 // next_edit->startsource,
407 // next_edit->channel,
410 // current->nested_edl,
411 // next_edit->nested_edl);
415 // both edits are silence & not a plugin
416 (current->silence() && next_edit->silence() && !current->is_plugin) ||
417 (current->startsource + current->length == next_edit->startsource &&
418 // source channels are identical
419 current->channel == next_edit->channel &&
420 // assets are identical
421 current->asset == next_edit->asset &&
422 current->nested_edl == next_edit->nested_edl))
424 //printf("Edits::optimize %d\n", __LINE__);
425 current->length += next_edit->length;
430 current = current->next;
433 // delete last edit of 0 length or silence
434 if(track->data_type != TRACK_SUBTITLE )
435 if(last && last->silence())
447 // ===================================== file operations
449 int Edits::load(FileXML *file, int track_offset)
451 int64_t startproject = 0;
453 while( !file->read_tag() ) {
454 //printf("Edits::load 1 %s\n", file->tag.get_title());
455 if(!strcmp(file->tag.get_title(), "EDIT"))
457 load_edit(file, startproject, track_offset);
459 else if(!strcmp(file->tag.get_title(), "/EDITS"))
468 int Edits::load_edit(FileXML *file, int64_t &startproject, int track_offset)
470 Edit* current = append_new_edit();
471 current->load_properties(file, startproject);
472 startproject += current->length;
474 while( !file->read_tag() ) {
475 if(file->tag.title_is("NESTED_EDL"))
477 char path[BCTEXTLEN];
479 file->tag.get_property("SRC", path);
480 //printf("Edits::load_edit %d path=%s\n", __LINE__, path);
483 current->nested_edl = edl->nested_edls->get(path);
485 // printf("Edits::load_edit %d nested_edl->path=%s\n",
487 // current->nested_edl->path);
489 else if(file->tag.title_is("FILE"))
491 char filename[BCTEXTLEN];
493 file->tag.get_property("SRC", filename);
497 char directory[BCTEXTLEN], edl_directory[BCTEXTLEN];
499 fs.set_current_dir("");
500 fs.extract_dir(directory, filename);
501 if(!strlen(directory))
503 fs.extract_dir(edl_directory, file->filename);
504 fs.join_names(directory, edl_directory, filename);
505 strcpy(filename, directory);
507 current->asset = edl->assets->get_asset(filename);
513 //printf("Edits::load_edit 5\n");
515 else if(file->tag.title_is("TRANSITION"))
517 current->transition = new Transition(edl, current, "",
518 track->to_units(edl->session->default_transition_length, 1));
519 current->transition->load_xml(file);
521 else if(file->tag.title_is("/EDIT"))
525 //printf("Edits::load_edit %d\n", __LINE__);
527 //printf("Edits::load_edit %d\n", __LINE__);
531 // ============================================= accounting
533 int64_t Edits::length()
535 return last ? last->startproject + last->length : 0;
540 Edit* Edits::editof(int64_t position, int direction, int use_nudge)
543 if(use_nudge && track) position += track->nudge;
545 if(direction == PLAY_FORWARD)
547 for(current = last; current; current = PREVIOUS)
549 if(current->startproject <= position && current->startproject + current->length > position)
554 if(direction == PLAY_REVERSE)
556 for(current = first; current; current = NEXT)
558 if(current->startproject < position && current->startproject + current->length >= position)
563 return 0; // return 0 on failure
566 Edit* Edits::get_playable_edit(int64_t position, int use_nudge)
569 if(track && use_nudge) position += track->nudge;
571 // Get the current edit
572 for(current = first; current; current = NEXT)
574 if(current->startproject <= position &&
575 current->startproject + current->length > position)
579 // Get the edit's asset
580 // TODO: descend into nested EDLs
587 return current; // return 0 on failure
590 // ================================================ editing
594 int Edits::copy(int64_t start, int64_t end, FileXML *file, const char *output_path)
598 file->tag.set_title("EDITS");
600 file->append_newline();
602 for(current_edit = first; current_edit; current_edit = current_edit->next)
604 current_edit->copy(start, end, file, output_path);
607 file->tag.set_title("/EDITS");
609 file->append_newline();
615 void Edits::clear(int64_t start, int64_t end)
617 Edit* edit1 = editof(start, PLAY_FORWARD, 0);
618 Edit* edit2 = editof(end, PLAY_FORWARD, 0);
621 if(end == start) return; // nothing selected
622 if(!edit1 && !edit2) return; // nothing selected
626 { // edit2 beyond end of track
628 end = this->length();
633 // in different edits
635 //printf("Edits::clear 3.5 %d %d %d %d\n", edit1->startproject, edit1->length, edit2->startproject, edit2->length);
636 edit1->length = start - edit1->startproject;
637 edit2->length -= end - edit2->startproject;
638 edit2->startsource += end - edit2->startproject;
639 edit2->startproject += end - edit2->startproject;
642 for(current_edit = edit1->next; current_edit && current_edit != edit2;)
644 Edit* next = current_edit->next;
645 remove(current_edit);
649 for(current_edit = edit2; current_edit; current_edit = current_edit->next)
651 current_edit->startproject -= end - start;
656 // in same edit. paste_edit depends on this
658 current_edit = split_edit(start);
660 current_edit->length -= end - start;
661 current_edit->startsource += end - start;
664 for(current_edit = current_edit->next;
666 current_edit = current_edit->next)
668 current_edit->startproject -= end - start;
675 // Used by edit handle and plugin handle movement but plugin handle movement
676 // can only effect other plugins.
677 void Edits::clear_recursive(int64_t start,
685 //printf("Edits::clear_recursive 1\n");
697 int Edits::clear_handle(double start,
705 distance = 0.0; // if nothing is found, distance is 0!
706 for(current_edit = first;
707 current_edit && current_edit->next;
708 current_edit = current_edit->next)
713 if(current_edit->asset &&
714 current_edit->next->asset)
717 if(current_edit->asset->equivalent(*current_edit->next->asset,
722 // Got two consecutive edits in same source
723 if(edl->equivalent(track->from_units(current_edit->next->startproject),
727 int length = -current_edit->length;
728 current_edit->length = current_edit->next->startsource - current_edit->startsource;
729 length += current_edit->length;
731 // Lengthen automation
733 track->automation->paste_silence(current_edit->next->startproject,
734 current_edit->next->startproject + length);
738 track->shift_effects(current_edit->next->startproject,
742 for(current_edit = current_edit->next; current_edit; current_edit = current_edit->next)
744 current_edit->startproject += length;
747 distance = track->from_units(length);
758 int Edits::modify_handles(double oldposition,
771 //printf("Edits::modify_handles 1 %d %f %f\n", currentend, newposition, oldposition);
775 for(current_edit = first; current_edit && !result;)
777 if(edl->equivalent(track->from_units(current_edit->startproject),
780 // edit matches selection
781 //printf("Edits::modify_handles 3 %f %f\n", newposition, oldposition);
782 oldposition = track->from_units(current_edit->startproject);
785 if(newposition >= oldposition)
787 //printf("Edits::modify_handle 1 %s %f %f\n", track->title, oldposition, newposition);
788 // shift start of edit in
789 current_edit->shift_start_in(edit_mode,
790 track->to_units(newposition, 0),
791 track->to_units(oldposition, 0),
800 //printf("Edits::modify_handle 2 %s\n", track->title);
801 // move start of edit out
802 current_edit->shift_start_out(edit_mode,
803 track->to_units(newposition, 0),
804 track->to_units(oldposition, 0),
813 if(!result) current_edit = current_edit->next;
818 // right handle selected
819 for(current_edit = first; current_edit && !result;)
821 if(edl->equivalent(track->from_units(current_edit->startproject) +
822 track->from_units(current_edit->length), oldposition))
824 oldposition = track->from_units(current_edit->startproject) +
825 track->from_units(current_edit->length);
828 //printf("Edits::modify_handle 3\n");
829 if(newposition <= oldposition)
831 // shift end of edit in
832 //printf("Edits::modify_handle 4\n");
833 current_edit->shift_end_in(edit_mode,
834 track->to_units(newposition, 0),
835 track->to_units(oldposition, 0),
841 //printf("Edits::modify_handle 5\n");
845 // move end of edit out
846 //printf("Edits::modify_handle 6\n");
847 current_edit->shift_end_out(edit_mode,
848 track->to_units(newposition, 0),
849 track->to_units(oldposition, 0),
855 //printf("Edits::modify_handle 7\n");
859 if(!result) current_edit = current_edit->next;
860 //printf("Edits::modify_handle 8\n");
869 // Used by other editing commands so don't optimize
870 Edit* Edits::paste_silence(int64_t start, int64_t end)
872 Edit *new_edit = insert_new_edit(start);
873 new_edit->length = end - start;
874 for(Edit *current = new_edit->next; current; current = NEXT)
876 current->startproject += end - start;
881 Edit* Edits::shift(int64_t position, int64_t difference)
883 Edit *new_edit = split_edit(position);
885 for(Edit *current = first;
889 if(current->startproject >= position)
891 current->shift(difference);
898 void Edits::shift_keyframes_recursive(int64_t position, int64_t length)
900 track->shift_keyframes(position, length);
903 void Edits::shift_effects_recursive(int64_t position, int64_t length, int edit_autos)
905 track->shift_effects(position, length, edit_autos);