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
24 #include "bcsignals.h"
29 #include "edlsession.h"
31 #include "filesystem.h"
33 #include "localsession.h"
35 #include "mainsession.h"
36 #include "nestededls.h"
37 #include "trackcanvas.h"
39 #include "transition.h"
48 Edit::Edit(EDL *edl, Track *track)
53 if(track) this->edits = track->edits;
57 Edit::Edit(EDL *edl, Edits *edits)
62 if(edits) this->track = edits->track;
68 //printf("Edit::~Edit 1\n");
69 if(transition) delete transition;
70 //printf("Edit::~Edit 2\n");
89 Indexable* Edit::get_source()
91 if(asset) return asset;
92 if(nested_edl) return nested_edl;
96 int Edit::copy(int64_t start,
99 const char *output_path)
102 //printf("Edit::copy 1\n");
104 int64_t endproject = startproject + length;
107 if((startproject >= start && startproject <= end) || // startproject in range
108 (endproject <= end && endproject >= start) || // endproject in range
109 (startproject <= start && endproject >= end)) // range in project
112 int64_t startproject_in_selection = startproject; // start of edit in selection in project
113 int64_t startsource_in_selection = startsource; // start of source in selection in source
114 //int64_t endsource_in_selection = startsource + length; // end of source in selection
115 int64_t length_in_selection = length; // length of edit in selection
116 //printf("Edit::copy 2\n");
118 if(startproject < start)
119 { // start is after start of edit in project
120 int64_t length_difference = start - startproject;
122 startsource_in_selection += length_difference;
123 startproject_in_selection += length_difference;
124 length_in_selection -= length_difference;
126 //printf("Edit::copy 3\n");
129 { // end is before end of edit in project
130 length_in_selection = end - startproject_in_selection;
133 //printf("Edit::copy 4\n");
134 if(file) // only if not counting
136 file->tag.set_title("EDIT");
137 file->tag.set_property("STARTSOURCE", startsource_in_selection);
138 file->tag.set_property("CHANNEL", (int64_t)channel);
139 file->tag.set_property("LENGTH", length_in_selection);
140 if(user_title[0]) file->tag.set_property("USER_TITLE", user_title);
141 //printf("Edit::copy 5\n");
143 copy_properties_derived(file, length_in_selection);
146 // file->append_newline();
147 //printf("Edit::copy 6\n");
151 file->tag.set_title("NESTED_EDL");
152 file->tag.set_property("SRC", nested_edl->path);
158 //printf("Edit::copy 6 %s\n", asset->path);
159 char stored_path[BCTEXTLEN];
160 char asset_directory[BCTEXTLEN];
161 char output_directory[BCTEXTLEN];
164 //printf("Edit::copy 6 %s\n", asset->path);
165 fs.extract_dir(asset_directory, asset->path);
166 //printf("Edit::copy 6 %s\n", asset->path);
169 fs.extract_dir(output_directory, output_path);
171 output_directory[0] = 0;
172 //printf("Edit::copy %s, %s %s, %s\n", asset->path, asset_directory, output_path, output_directory);
174 if(output_path && !strcmp(asset_directory, output_directory))
175 fs.extract_name(stored_path, asset->path);
177 strcpy(stored_path, asset->path);
179 file->tag.set_title("FILE");
180 file->tag.set_property("SRC", stored_path);
186 transition->save_xml(file);
189 //printf("Edit::copy 7\n");
190 file->tag.set_title("/EDIT");
192 file->append_newline();
193 //printf("Edit::copy 8\n");
195 //printf("Edit::copy 9\n");
202 //printf("Edit::copy 10\n");
207 int64_t Edit::get_source_end(int64_t default_)
212 void Edit::insert_transition(char *title)
214 //printf("Edit::insert_transition this=%p title=%p title=%s\n", this, title, title);
216 transition = new Transition(edl,
219 track->to_units(edl->session->default_transition_length, 1));
222 void Edit::detach_transition()
224 if(transition) delete transition;
230 if(asset || nested_edl)
237 void Edit::copy_from(Edit *edit)
239 this->nested_edl = edl->nested_edls->get_copy(edit->nested_edl);
240 this->asset = edl->assets->update(edit->asset);
241 this->startsource = edit->startsource;
242 this->startproject = edit->startproject;
243 this->length = edit->length;
244 strcpy (this->user_title, edit->user_title);
248 if(!transition) transition = new Transition(edl,
250 edit->transition->title,
251 edit->transition->length);
252 *this->transition = *edit->transition;
254 this->channel = edit->channel;
257 void Edit::equivalent_output(Edit *edit, int64_t *result)
259 // End of edit changed
260 if(startproject + length != edit->startproject + edit->length)
262 int64_t new_length = MIN(startproject + length,
263 edit->startproject + edit->length);
264 if(*result < 0 || new_length < *result)
265 *result = new_length;
269 // Different nested EDLs
270 (edit->nested_edl && !nested_edl) ||
271 (!edit->nested_edl && nested_edl) ||
273 (edit->asset == 0 && asset != 0) ||
274 (edit->asset != 0 && asset == 0) ||
275 // different transitions
276 (edit->transition == 0 && transition != 0) ||
277 (edit->transition != 0 && transition == 0) ||
279 (startproject != edit->startproject) ||
280 (startsource != edit->startsource) ||
281 // Transition changed
282 (transition && edit->transition &&
283 !transition->identical(edit->transition)) ||
285 (asset && edit->asset &&
286 !asset->equivalent(*edit->asset, 1, 1)) ||
287 // Nested EDL changed
288 (nested_edl && edit->nested_edl &&
289 strcmp(nested_edl->path, edit->nested_edl->path))
292 // Start of edit changed
293 if(*result < 0 || startproject < *result) *result = startproject;
298 Edit& Edit::operator=(Edit& edit)
300 //printf("Edit::operator= called\n");
305 void Edit::synchronize_params(Edit *edit)
311 // Comparison for ResourcePixmap drawing
312 int Edit::identical(Edit &edit)
314 int result = (this->nested_edl == edit.nested_edl &&
315 this->asset == edit.asset &&
316 this->startsource == edit.startsource &&
317 this->startproject == edit.startproject &&
318 this->length == edit.length &&
319 this->transition == edit.transition &&
320 this->channel == edit.channel);
324 int Edit::operator==(Edit &edit)
326 return identical(edit);
329 double Edit::frames_per_picon()
331 return Units::round(picon_w()) / frame_w();
334 double Edit::frame_w()
336 return track->from_units(1) *
337 edl->session->sample_rate /
338 edl->local_session->zoom_sample;
341 double Edit::picon_w()
344 return (double)edl->local_session->zoom_track *
348 return (double)edl->local_session->zoom_track *
349 nested_edl->session->output_w /
350 nested_edl->session->output_h;
357 return edl->local_session->zoom_track;
361 int Edit::dump(FILE *fp)
363 fprintf(fp," EDIT %p\n", this); fflush(fp);
364 fprintf(fp," nested_edl=%p %s asset=%p %s\n",
366 nested_edl ? nested_edl->path : "",
368 asset ? asset->path : "");
370 fprintf(fp," channel %d\n", channel);
373 fprintf(fp," TRANSITION %p\n", transition);
374 transition->dump(fp);
376 fprintf(fp," startsource " _LD " startproject " _LD " length " _LD "\n",
377 startsource, startproject, length); fflush(fp);
381 int Edit::load_properties(FileXML *file, int64_t &startproject)
383 startsource = file->tag.get_property("STARTSOURCE", (int64_t)0);
384 length = file->tag.get_property("LENGTH", (int64_t)0);
386 file->tag.get_property("USER_TITLE", user_title);
387 this->startproject = startproject;
388 load_properties_derived(file);
392 void Edit::shift(int64_t difference)
394 //printf("Edit::shift 1 %p " _LD " " _LD "\n", this, startproject, difference);
395 startproject += difference;
396 //printf("Edit::shift 2 " _LD " " _LD "\n", startproject, difference);
399 int Edit::shift_start_in(int edit_mode,
408 int64_t cut_length = newposition - oldposition;
409 int64_t end_previous_source, end_source;
411 if(edit_mode == MOVE_ALL_EDITS)
413 if(cut_length < length)
415 edits->clear_recursive(oldposition,
425 edits->clear_recursive(oldposition,
426 startproject + length,
435 if(edit_mode == MOVE_ONE_EDIT)
437 // Paste silence and cut
438 //printf("Edit::shift_start_in 1\n");
441 Edit *new_edit = edits->create_edit();
442 new_edit->startproject = this->startproject;
443 new_edit->length = 0;
444 edits->insert_before(this,
447 //printf("Edit::shift_start_in 2 %p\n", previous);
449 end_previous_source = previous->get_source_end(previous->startsource + previous->length + cut_length);
450 if(end_previous_source > 0 &&
451 previous->startsource + previous->length + cut_length > end_previous_source)
452 cut_length = end_previous_source - previous->startsource - previous->length;
454 if(cut_length < length)
456 startproject += cut_length;
457 startsource += cut_length;
458 length -= cut_length;
459 previous->length += cut_length;
460 //printf("Edit::shift_start_in 2\n");
463 { // Clear entire edit
465 previous->length += cut_length;
466 for(Edit* current_edit = this; current_edit; current_edit = current_edit->next)
468 current_edit->startproject += cut_length;
470 edits->clear_recursive(oldposition + cut_length,
471 startproject + cut_length,
478 //printf("Edit::shift_start_in 3\n");
481 if(edit_mode == MOVE_NO_EDITS)
483 end_source = get_source_end(startsource + length + cut_length);
484 if(end_source > 0 && startsource + length + cut_length > end_source)
485 cut_length = end_source - startsource - length;
487 startsource += cut_length;
492 int Edit::shift_start_out(int edit_mode,
501 int64_t cut_length = oldposition - newposition;
504 if(asset || nested_edl)
506 int64_t end_source = get_source_end(1);
508 //printf("Edit::shift_start_out 1 " _LD " " _LD "\n", startsource, cut_length);
509 if(end_source > 0 && startsource < cut_length)
511 cut_length = startsource;
515 if(edit_mode == MOVE_ALL_EDITS)
517 //printf("Edit::shift_start_out 10 " _LD "\n", cut_length);
518 startsource -= cut_length;
519 length += cut_length;
522 edits->shift_keyframes_recursive(startproject,
525 edits->shift_effects_recursive(startproject,
529 for(Edit* current_edit = next; current_edit; current_edit = current_edit->next)
531 current_edit->startproject += cut_length;
535 if(edit_mode == MOVE_ONE_EDIT)
539 if(cut_length < previous->length)
540 { // Cut into previous edit
541 previous->length -= cut_length;
542 startproject -= cut_length;
543 startsource -= cut_length;
544 length += cut_length;
545 printf("Edit::shift_start_out 2\n");
548 { // Clear entire previous edit
549 cut_length = previous->length;
550 previous->length = 0;
551 length += cut_length;
552 startsource -= cut_length;
553 startproject -= cut_length;
558 if(edit_mode == MOVE_NO_EDITS)
560 startsource -= cut_length;
563 // Fix infinite length files
564 if(startsource < 0) startsource = 0;
568 int Edit::shift_end_in(int edit_mode,
577 int64_t cut_length = oldposition - newposition;
579 if(edit_mode == MOVE_ALL_EDITS)
581 //printf("Edit::shift_end_in 1\n");
582 if(newposition > startproject)
583 { // clear partial edit
584 //printf("Edit::shift_end_in %p %p\n", track->edits, edits);
585 edits->clear_recursive(newposition,
594 { // clear entire edit
595 edits->clear_recursive(startproject,
605 if(edit_mode == MOVE_ONE_EDIT)
611 int64_t end_source = next->get_source_end(1);
613 if(end_source > 0 && next->startsource - cut_length < 0)
615 cut_length = next->startsource;
619 if(cut_length < length)
621 length -= cut_length;
622 next->startproject -= cut_length;
623 next->startsource -= cut_length;
624 next->length += cut_length;
625 //printf("Edit::shift_end_in 2 %d\n", cut_length);
630 next->length += cut_length;
631 next->startsource -= cut_length;
632 next->startproject -= cut_length;
633 length -= cut_length;
638 if(cut_length < length)
640 length -= cut_length;
645 edits->clear_recursive(startproject,
656 // Does nothing for plugins
657 if(edit_mode == MOVE_NO_EDITS)
659 //printf("Edit::shift_end_in 3\n");
660 int64_t end_source = get_source_end(1);
661 if(end_source > 0 && startsource < cut_length)
663 cut_length = startsource;
665 startsource -= cut_length;
670 int Edit::shift_end_out(int edit_mode,
679 int64_t cut_length = newposition - oldposition;
680 int64_t endsource = get_source_end(startsource + length + cut_length);
682 // check end of edit against end of source file
683 if(endsource > 0 && startsource + length + cut_length > endsource)
684 cut_length = endsource - startsource - length;
686 //printf("Edit::shift_end_out 1 " _LD " %d %d %d\n", oldposition, newposition, this->length, cut_length);
687 if(edit_mode == MOVE_ALL_EDITS)
690 this->length += cut_length;
692 // Effects are shifted in length extension
694 edits->shift_effects_recursive(oldposition /* startproject */,
698 edits->shift_keyframes_recursive(oldposition /* startproject */,
701 for(Edit* current_edit = next; current_edit; current_edit = current_edit->next)
703 current_edit->startproject += cut_length;
707 if(edit_mode == MOVE_ONE_EDIT)
711 if(cut_length < next->length)
713 length += cut_length;
714 next->startproject += cut_length;
715 next->startsource += cut_length;
716 next->length -= cut_length;
717 //printf("Edit::shift_end_out 2 %d\n", cut_length);
721 cut_length = next->length;
723 length += cut_length;
728 length += cut_length;
732 if(edit_mode == MOVE_NO_EDITS)
734 startsource += cut_length;
767 int Edit::popup_transition(float view_start, float zoom_units, int cursor_x, int cursor_y)
769 int64_t left, right, left_unit, right_unit;
770 if(!transition) return 0;
771 get_handle_parameters(left, right, left_unit, right_unit, view_start, zoom_units);
773 if(cursor_x > left && cursor_x < right)
775 // transition->popup_transition(cursor_x, cursor_y);
781 int Edit::select_handle(float view_start, float zoom_units, int cursor_x, int cursor_y, int64_t &selection)
783 int64_t left, right, left_unit, right_unit;
784 get_handle_parameters(left, right, left_unit, right_unit, view_start, zoom_units);
786 int64_t pixel1, pixel2;
788 pixel2 = pixel1 + 10;
791 // cursor_x is faked in acanvas
792 if(cursor_x >= pixel1 && cursor_x <= pixel2)
794 selection = left_unit;
795 return 1; // left handle
798 //int64_t endproject = startproject + length;
800 pixel1 = pixel2 - 10;
803 if(cursor_x >= pixel1 && cursor_x <= pixel2)
805 selection = right_unit;
806 return 2; // right handle