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"
32 #include "localsession.h"
34 #include "mainsession.h"
35 #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");
91 Indexable* Edit::get_source()
93 if(asset) return asset;
94 if(nested_edl) return nested_edl;
98 int Edit::copy(int64_t start,
101 const char *output_path)
104 //printf("Edit::copy 1\n");
106 int64_t endproject = startproject + length;
109 if((startproject >= start && startproject <= end) || // startproject in range
110 (endproject <= end && endproject >= start) || // endproject in range
111 (startproject <= start && endproject >= end)) // range in project
114 int64_t startproject_in_selection = startproject; // start of edit in selection in project
115 int64_t startsource_in_selection = startsource; // start of source in selection in source
116 //int64_t endsource_in_selection = startsource + length; // end of source in selection
117 int64_t length_in_selection = length; // length of edit in selection
118 //printf("Edit::copy 2\n");
120 if(startproject < start)
121 { // start is after start of edit in project
122 int64_t length_difference = start - startproject;
124 startsource_in_selection += length_difference;
125 startproject_in_selection += length_difference;
126 length_in_selection -= length_difference;
128 //printf("Edit::copy 3\n");
131 { // end is before end of edit in project
132 length_in_selection = end - startproject_in_selection;
135 //printf("Edit::copy 4\n");
136 if(file) // only if not counting
138 file->tag.set_title("EDIT");
139 file->tag.set_property("STARTSOURCE", startsource_in_selection);
140 file->tag.set_property("CHANNEL", (int64_t)channel);
141 file->tag.set_property("LENGTH", length_in_selection);
142 file->tag.set_property("HARD_LEFT", hard_left);
143 file->tag.set_property("HARD_RIGHT", hard_right);
144 if(user_title[0]) file->tag.set_property("USER_TITLE", user_title);
145 //printf("Edit::copy 5\n");
147 copy_properties_derived(file, length_in_selection);
150 // file->append_newline();
151 //printf("Edit::copy 6\n");
155 file->tag.set_title("NESTED_EDL");
156 file->tag.set_property("SRC", nested_edl->path);
158 file->tag.set_title("/NESTED_EDL");
160 file->append_newline();
165 //printf("Edit::copy 6 %s\n", asset->path);
166 char stored_path[BCTEXTLEN];
167 char asset_directory[BCTEXTLEN];
168 char output_directory[BCTEXTLEN];
171 //printf("Edit::copy %d %s\n", __LINE__, asset->path);
172 fs.extract_dir(asset_directory, asset->path);
173 //printf("Edit::copy %d %s\n", __LINE__, asset->path);
176 fs.extract_dir(output_directory, output_path);
178 output_directory[0] = 0;
179 //printf("Edit::copy %s, %s %s, %s\n", asset->path, asset_directory, output_path, output_directory);
181 if(output_path && !strcmp(asset_directory, output_directory))
182 fs.extract_name(stored_path, asset->path);
184 strcpy(stored_path, asset->path);
186 file->tag.set_title("FILE");
187 file->tag.set_property("SRC", stored_path);
189 file->tag.set_title("/FILE");
195 transition->save_xml(file);
198 //printf("Edit::copy 7\n");
199 file->tag.set_title("/EDIT");
201 file->append_newline();
202 //printf("Edit::copy 8\n");
204 //printf("Edit::copy 9\n");
211 //printf("Edit::copy 10\n");
216 int64_t Edit::get_source_end(int64_t default_)
221 void Edit::insert_transition(char *title)
223 //printf("Edit::insert_transition this=%p title=%p title=%s\n", this, title, title);
225 transition = new Transition(edl, this, title,
226 track->to_units(edl->session->default_transition_length, 1));
229 void Edit::detach_transition()
231 if(transition) delete transition;
237 return (track->data_type != TRACK_SUBTITLE ?
238 asset || nested_edl :
239 *((SEdit *)this)->get_text()) ? 0 : 1;
243 void Edit::copy_from(Edit *edit)
245 this->nested_edl = edl->nested_edls->get_copy(edit->nested_edl);
246 this->asset = edl->assets->update(edit->asset);
247 this->startsource = edit->startsource;
248 this->startproject = edit->startproject;
249 this->length = edit->length;
250 this->hard_left = edit->hard_left;
251 this->hard_right = edit->hard_right;
252 strcpy (this->user_title, edit->user_title);
256 if(!transition) transition = new Transition(edl,
258 edit->transition->title,
259 edit->transition->length);
260 *this->transition = *edit->transition;
262 this->channel = edit->channel;
265 void Edit::equivalent_output(Edit *edit, int64_t *result)
267 // End of edit changed
268 if(startproject + length != edit->startproject + edit->length)
270 int64_t new_length = MIN(startproject + length,
271 edit->startproject + edit->length);
272 if(*result < 0 || new_length < *result)
273 *result = new_length;
277 // Different nested EDLs
278 (edit->nested_edl && !nested_edl) ||
279 (!edit->nested_edl && nested_edl) ||
281 (edit->asset == 0 && asset != 0) ||
282 (edit->asset != 0 && asset == 0) ||
283 // different transitions
284 (edit->transition == 0 && transition != 0) ||
285 (edit->transition != 0 && transition == 0) ||
287 (startproject != edit->startproject) ||
288 (startsource != edit->startsource) ||
289 // Transition changed
290 (transition && edit->transition &&
291 !transition->identical(edit->transition)) ||
293 (asset && edit->asset &&
294 !asset->equivalent(*edit->asset, 1, 1, edl)) ||
295 // Nested EDL changed
296 (nested_edl && edit->nested_edl &&
297 strcmp(nested_edl->path, edit->nested_edl->path))
300 // Start of edit changed
301 if(*result < 0 || startproject < *result) *result = startproject;
306 Edit& Edit::operator=(Edit& edit)
308 //printf("Edit::operator= called\n");
313 void Edit::synchronize_params(Edit *edit)
319 // Comparison for ResourcePixmap drawing
320 int Edit::identical(Edit &edit)
322 int result = (this->nested_edl == edit.nested_edl &&
323 this->asset == edit.asset &&
324 this->startsource == edit.startsource &&
325 this->startproject == edit.startproject &&
326 this->length == edit.length &&
327 this->hard_left == edit.hard_left &&
328 this->hard_right == edit.hard_right &&
329 this->transition == edit.transition &&
330 this->channel == edit.channel);
334 int Edit::operator==(Edit &edit)
336 return identical(edit);
339 double Edit::frames_per_picon()
341 return Units::round(picon_w()) / frame_w();
344 double Edit::frame_w()
346 return track->from_units(1) *
347 edl->session->sample_rate /
348 edl->local_session->zoom_sample;
351 double Edit::picon_w()
358 else if(nested_edl) {
359 w = nested_edl->session->output_w;
360 h = nested_edl->session->output_h;
362 return w>0 && h>0 ? ((double)edl->local_session->zoom_track*w)/h : 0;
367 return edl->local_session->zoom_track;
371 int Edit::dump(FILE *fp)
373 fprintf(fp," EDIT %p\n", this); fflush(fp);
374 fprintf(fp," nested_edl=%p %s asset=%p %s\n",
376 nested_edl ? nested_edl->path : "",
378 asset ? asset->path : "");
380 fprintf(fp," channel %d\n", channel);
383 fprintf(fp," TRANSITION %p\n", transition);
384 transition->dump(fp);
386 fprintf(fp," startsource %jd startproject %jd hard lt/rt %d/%d length %jd\n",
387 startsource, startproject, hard_left, hard_right, length); fflush(fp);
391 int Edit::load_properties(FileXML *file, int64_t &startproject)
393 startsource = file->tag.get_property("STARTSOURCE", (int64_t)0);
394 length = file->tag.get_property("LENGTH", (int64_t)0);
395 hard_left = file->tag.get_property("HARD_LEFT", (int64_t)0);
396 hard_right = file->tag.get_property("HARD_RIGHT", (int64_t)0);
398 file->tag.get_property("USER_TITLE", user_title);
399 this->startproject = startproject;
400 load_properties_derived(file);
404 void Edit::shift(int64_t difference)
406 //printf("Edit::shift 1 %p %jd %jd\n", this, startproject, difference);
407 startproject += difference;
408 //printf("Edit::shift 2 %jd %jd\n", startproject, difference);
411 int Edit::shift_start_in(int edit_mode,
420 int64_t cut_length = newposition - oldposition;
421 int64_t end_previous_source, end_source;
423 if(edit_mode == MOVE_ALL_EDITS)
425 if(cut_length < length)
427 edits->clear_recursive(oldposition,
437 edits->clear_recursive(oldposition,
438 startproject + length,
447 if(edit_mode == MOVE_ONE_EDIT)
449 // Paste silence and cut
450 //printf("Edit::shift_start_in 1\n");
453 Edit *new_edit = edits->create_edit();
454 new_edit->startproject = this->startproject;
455 new_edit->length = 0;
456 edits->insert_before(this,
459 //printf("Edit::shift_start_in 2 %p\n", previous);
461 end_previous_source = previous->get_source_end(previous->startsource + previous->length + cut_length);
462 if(end_previous_source > 0 &&
463 previous->startsource + previous->length + cut_length > end_previous_source)
464 cut_length = end_previous_source - previous->startsource - previous->length;
466 if(cut_length < length)
468 startproject += cut_length;
469 startsource += cut_length;
470 length -= cut_length;
471 previous->length += cut_length;
472 //printf("Edit::shift_start_in 2\n");
475 { // Clear entire edit
477 previous->length += cut_length;
478 for(Edit* current_edit = this; current_edit; current_edit = current_edit->next)
480 current_edit->startproject += cut_length;
482 edits->clear_recursive(oldposition + cut_length,
483 startproject + cut_length,
490 //printf("Edit::shift_start_in 3\n");
493 if(edit_mode == MOVE_NO_EDITS)
495 end_source = get_source_end(startsource + length + cut_length);
496 if(end_source > 0 && startsource + length + cut_length > end_source)
497 cut_length = end_source - startsource - length;
499 startsource += cut_length;
504 int Edit::shift_start_out(int edit_mode,
513 int64_t cut_length = oldposition - newposition;
516 if(asset || nested_edl)
518 int64_t end_source = get_source_end(1);
520 //printf("Edit::shift_start_out 1 %jd %jd\n", startsource, cut_length);
521 if(end_source > 0 && startsource < cut_length)
523 cut_length = startsource;
527 if(edit_mode == MOVE_ALL_EDITS)
529 //printf("Edit::shift_start_out 10 %jd\n", cut_length);
530 startsource -= cut_length;
531 length += cut_length;
534 edits->shift_keyframes_recursive(startproject,
537 edits->shift_effects_recursive(startproject,
541 for(Edit* current_edit = next; current_edit; current_edit = current_edit->next)
543 current_edit->startproject += cut_length;
547 if(edit_mode == MOVE_ONE_EDIT)
551 if(cut_length < previous->length)
552 { // Cut into previous edit
553 previous->length -= cut_length;
554 startproject -= cut_length;
555 startsource -= cut_length;
556 length += cut_length;
557 printf("Edit::shift_start_out 2\n");
560 { // Clear entire previous edit
561 cut_length = previous->length;
562 previous->length = 0;
563 length += cut_length;
564 startsource -= cut_length;
565 startproject -= cut_length;
570 if(edit_mode == MOVE_NO_EDITS)
572 startsource -= cut_length;
575 // Fix infinite length files
576 if(startsource < 0) startsource = 0;
580 int Edit::shift_end_in(int edit_mode,
589 int64_t cut_length = oldposition - newposition;
591 if(edit_mode == MOVE_ALL_EDITS)
593 //printf("Edit::shift_end_in 1\n");
594 if(newposition > startproject)
595 { // clear partial edit
596 //printf("Edit::shift_end_in %p %p\n", track->edits, edits);
597 edits->clear_recursive(newposition,
606 { // clear entire edit
607 edits->clear_recursive(startproject,
617 if(edit_mode == MOVE_ONE_EDIT)
623 int64_t end_source = next->get_source_end(1);
625 if(end_source > 0 && next->startsource - cut_length < 0)
627 cut_length = next->startsource;
631 if(cut_length < length)
633 length -= cut_length;
634 next->startproject -= cut_length;
635 next->startsource -= cut_length;
636 next->length += cut_length;
637 //printf("Edit::shift_end_in 2 %d\n", cut_length);
642 next->length += cut_length;
643 next->startsource -= cut_length;
644 next->startproject -= cut_length;
645 length -= cut_length;
650 if(cut_length < length)
652 length -= cut_length;
657 edits->clear_recursive(startproject,
668 // Does nothing for plugins
669 if(edit_mode == MOVE_NO_EDITS)
671 //printf("Edit::shift_end_in 3\n");
672 int64_t end_source = get_source_end(1);
673 if(end_source > 0 && startsource < cut_length)
675 cut_length = startsource;
677 startsource -= cut_length;
682 int Edit::shift_end_out(int edit_mode,
691 int64_t cut_length = newposition - oldposition;
692 int64_t endsource = get_source_end(startsource + length + cut_length);
694 // check end of edit against end of source file
695 if(endsource > 0 && startsource + length + cut_length > endsource)
696 cut_length = endsource - startsource - length;
698 //printf("Edit::shift_end_out 1 %jd %d %d %d\n", oldposition, newposition, this->length, cut_length);
699 if(edit_mode == MOVE_ALL_EDITS)
702 this->length += cut_length;
704 // Effects are shifted in length extension
706 edits->shift_effects_recursive(oldposition /* startproject */,
710 edits->shift_keyframes_recursive(oldposition /* startproject */,
713 for(Edit* current_edit = next; current_edit; current_edit = current_edit->next)
715 current_edit->startproject += cut_length;
719 if(edit_mode == MOVE_ONE_EDIT)
723 if(cut_length < next->length)
725 length += cut_length;
726 next->startproject += cut_length;
727 next->startsource += cut_length;
728 next->length -= cut_length;
729 //printf("Edit::shift_end_out %d cut_length=%d\n", __LINE__, cut_length);
733 //printf("Edit::shift_end_out %d cut_length=%d next->length=%d\n", __LINE__, cut_length, next->length);
734 cut_length = next->length;
735 next->startproject += next->length;
736 next->startsource += next->length;
738 length += cut_length;
744 length += cut_length;
748 if(edit_mode == MOVE_NO_EDITS)
750 startsource += cut_length;
783 int Edit::popup_transition(float view_start, float zoom_units, int cursor_x, int cursor_y)
785 int64_t left, right, left_unit, right_unit;
786 if(!transition) return 0;
787 get_handle_parameters(left, right, left_unit, right_unit, view_start, zoom_units);
789 if(cursor_x > left && cursor_x < right)
791 // transition->popup_transition(cursor_x, cursor_y);
797 int Edit::select_handle(float view_start, float zoom_units, int cursor_x, int cursor_y, int64_t &selection)
799 int64_t left, right, left_unit, right_unit;
800 get_handle_parameters(left, right, left_unit, right_unit, view_start, zoom_units);
802 int64_t pixel1, pixel2;
804 pixel2 = pixel1 + 10;
807 // cursor_x is faked in acanvas
808 if(cursor_x >= pixel1 && cursor_x <= pixel2)
810 selection = left_unit;
811 return 1; // left handle
814 //int64_t endproject = startproject + length;
816 pixel1 = pixel2 - 10;
819 if(cursor_x >= pixel1 && cursor_x <= pixel2)
821 selection = right_unit;
822 return 2; // right handle