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"
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");
94 Indexable* Edit::get_source()
96 if(asset) return asset;
97 if(nested_edl) return nested_edl;
101 int Edit::copy(int64_t start,
104 const char *output_path)
107 //printf("Edit::copy 1\n");
109 int64_t endproject = startproject + length;
112 if((startproject >= start && startproject <= end) || // startproject in range
113 (endproject <= end && endproject >= start) || // endproject in range
114 (startproject <= start && endproject >= end)) // range in project
117 int64_t startproject_in_selection = startproject; // start of edit in selection in project
118 int64_t startsource_in_selection = startsource; // start of source in selection in source
119 //int64_t endsource_in_selection = startsource + length; // end of source in selection
120 int64_t length_in_selection = length; // length of edit in selection
121 //printf("Edit::copy 2\n");
123 if(startproject < start)
124 { // start is after start of edit in project
125 int64_t length_difference = start - startproject;
127 startsource_in_selection += length_difference;
128 startproject_in_selection += length_difference;
129 length_in_selection -= length_difference;
131 //printf("Edit::copy 3\n");
134 { // end is before end of edit in project
135 length_in_selection = end - startproject_in_selection;
138 //printf("Edit::copy 4\n");
139 if(file) // only if not counting
141 file->tag.set_title("EDIT");
142 file->tag.set_property("STARTSOURCE", startsource_in_selection);
143 file->tag.set_property("CHANNEL", (int64_t)channel);
144 file->tag.set_property("LENGTH", length_in_selection);
145 file->tag.set_property("HARD_LEFT", hard_left);
146 file->tag.set_property("HARD_RIGHT", hard_right);
147 file->tag.set_property("COLOR", color);
148 file->tag.set_property("GROUP_ID", group_id);
149 if(user_title[0]) file->tag.set_property("USER_TITLE", user_title);
150 //printf("Edit::copy 5\n");
152 copy_properties_derived(file, length_in_selection);
155 // file->append_newline();
156 //printf("Edit::copy 6\n");
160 file->tag.set_title("NESTED_EDL");
161 file->tag.set_property("SRC", nested_edl->path);
163 file->tag.set_title("/NESTED_EDL");
165 file->append_newline();
170 //printf("Edit::copy 6 %s\n", asset->path);
171 char stored_path[BCTEXTLEN];
172 char asset_directory[BCTEXTLEN];
173 char output_directory[BCTEXTLEN];
176 //printf("Edit::copy %d %s\n", __LINE__, asset->path);
177 fs.extract_dir(asset_directory, asset->path);
178 //printf("Edit::copy %d %s\n", __LINE__, asset->path);
181 fs.extract_dir(output_directory, output_path);
183 output_directory[0] = 0;
184 //printf("Edit::copy %s, %s %s, %s\n", asset->path, asset_directory, output_path, output_directory);
186 if(output_path && !strcmp(asset_directory, output_directory))
187 fs.extract_name(stored_path, asset->path);
189 strcpy(stored_path, asset->path);
191 file->tag.set_title("FILE");
192 file->tag.set_property("SRC", stored_path);
194 file->tag.set_title("/FILE");
198 if(transition && startsource_in_selection == startsource)
200 transition->save_xml(file);
203 //printf("Edit::copy 7\n");
204 file->tag.set_title("/EDIT");
206 file->append_newline();
207 //printf("Edit::copy 8\n");
209 //printf("Edit::copy 9\n");
216 //printf("Edit::copy 10\n");
221 int64_t Edit::get_source_end(int64_t default_)
226 void Edit::insert_transition(char *title)
228 //printf("Edit::insert_transition this=%p title=%p title=%s\n", this, title, title);
230 transition = new Transition(edl, this, title,
231 track->to_units(edl->session->default_transition_length, 1));
234 void Edit::detach_transition()
236 if(transition) delete transition;
242 return (track->data_type != TRACK_SUBTITLE ?
243 asset || nested_edl :
244 *((SEdit *)this)->get_text()) ? 0 : 1;
247 void Edit::set_selected(int v)
250 edl->tracks->set_group_selected(group_id, v);
252 is_selected = v >= 0 ? v : !is_selected ? 1 : 0;
255 void Edit::copy_from(Edit *edit)
257 this->nested_edl = edl->nested_edls.get_nested(edit->nested_edl);
258 this->asset = edl->assets->update(edit->asset);
259 this->startsource = edit->startsource;
260 this->startproject = edit->startproject;
261 this->length = edit->length;
262 this->hard_left = edit->hard_left;
263 this->hard_right = edit->hard_right;
264 this->color = edit->color;
265 this->group_id = edit->group_id;
266 strcpy (this->user_title, edit->user_title);
270 if(!transition) transition = new Transition(edl,
272 edit->transition->title,
273 edit->transition->length);
274 *this->transition = *edit->transition;
276 this->channel = edit->channel;
279 void Edit::equivalent_output(Edit *edit, int64_t *result)
281 // End of edit changed
282 if(startproject + length != edit->startproject + edit->length)
284 int64_t new_length = MIN(startproject + length,
285 edit->startproject + edit->length);
286 if(*result < 0 || new_length < *result)
287 *result = new_length;
291 // Different nested EDLs
292 (edit->nested_edl && !nested_edl) ||
293 (!edit->nested_edl && nested_edl) ||
295 (edit->asset == 0 && asset != 0) ||
296 (edit->asset != 0 && asset == 0) ||
297 // different transitions
298 (edit->transition == 0 && transition != 0) ||
299 (edit->transition != 0 && transition == 0) ||
301 (startproject != edit->startproject) ||
302 (startsource != edit->startsource) ||
303 // Transition changed
304 (transition && edit->transition &&
305 !transition->identical(edit->transition)) ||
307 (asset && edit->asset &&
308 !asset->equivalent(*edit->asset, 1, 1, edl)) ||
309 // Nested EDL changed
310 (nested_edl && edit->nested_edl &&
311 strcmp(nested_edl->path, edit->nested_edl->path))
314 // Start of edit changed
315 if(*result < 0 || startproject < *result) *result = startproject;
320 Edit& Edit::operator=(Edit& edit)
322 //printf("Edit::operator= called\n");
327 void Edit::synchronize_params(Edit *edit)
333 // Comparison for ResourcePixmap drawing
334 int Edit::identical(Edit &edit)
336 int result = (this->nested_edl == edit.nested_edl &&
337 this->asset == edit.asset &&
338 this->startsource == edit.startsource &&
339 this->startproject == edit.startproject &&
340 this->length == edit.length &&
341 this->transition == edit.transition &&
342 this->channel == edit.channel);
346 int Edit::operator==(Edit &edit)
348 return identical(edit);
351 double Edit::frames_per_picon()
353 return Units::round(picon_w()) / frame_w();
356 double Edit::frame_w()
358 return track->from_units(1) *
359 edl->session->sample_rate /
360 edl->local_session->zoom_sample;
363 double Edit::picon_w()
370 else if(nested_edl) {
371 w = nested_edl->session->output_w;
372 h = nested_edl->session->output_h;
374 return w>0 && h>0 ? ((double)edl->local_session->zoom_track*w)/h : 0;
379 return edl->local_session->zoom_track;
383 int Edit::dump(FILE *fp)
385 fprintf(fp," EDIT %p\n", this); fflush(fp);
386 fprintf(fp," nested_edl=%p %s asset=%p %s\n",
388 nested_edl ? nested_edl->path : "",
390 asset ? asset->path : "");
392 fprintf(fp," channel %d, color %08x, group_id %d, is_selected %d\n",
393 channel, color, group_id, is_selected);
396 fprintf(fp," TRANSITION %p\n", transition);
397 transition->dump(fp);
399 fprintf(fp," startsource %jd startproject %jd hard lt/rt %d/%d length %jd\n",
400 startsource, startproject, hard_left, hard_right, length); fflush(fp);
404 int Edit::load_properties(FileXML *file, int64_t &startproject)
406 startsource = file->tag.get_property("STARTSOURCE", (int64_t)0);
407 length = file->tag.get_property("LENGTH", (int64_t)0);
408 hard_left = file->tag.get_property("HARD_LEFT", (int64_t)0);
409 hard_right = file->tag.get_property("HARD_RIGHT", (int64_t)0);
410 color = file->tag.get_property("COLOR", 0);
411 group_id = file->tag.get_property("GROUP_ID", group_id);
413 file->tag.get_property("USER_TITLE", user_title);
414 this->startproject = startproject;
415 load_properties_derived(file);
419 void Edit::shift(int64_t difference)
421 startproject += difference;
425 int Edit::shift_start(int edit_mode, int64_t newposition, int64_t oldposition,
426 int edit_edits, int edit_labels, int edit_plugins, int edit_autos,
429 int64_t startproject = this->startproject;
430 int64_t startsource = this->startsource;
431 int64_t length = this->length;
432 int64_t source_len = get_source_end(startsource + length);
433 int64_t cut_length = newposition - oldposition;
434 source_len -= cut_length;
436 switch( edit_mode ) {
438 startproject += cut_length;
439 startsource += cut_length;
440 length -= cut_length;
443 startsource += cut_length;
445 case MOVE_EDGE_MEDIA:
446 startproject += cut_length;
447 length -= cut_length;
451 if( startproject < 0 ) {
452 startsource += startproject;
453 length += startproject;
456 if( startsource < 0 )
458 if( length > source_len )
463 int64_t start = this->startproject;
464 int64_t end = start + this->length;
466 double cut_len = track->from_units(cut_length);
467 double start_pos = edits->track->from_units(start);
468 edits->edl->labels->insert(start_pos, cut_len);
469 double end_pos = edits->track->from_units(end);
470 edits->edl->labels->insert(end_pos + cut_len, -cut_len);
473 edits->shift_keyframes_recursive(start, cut_length);
474 edits->shift_keyframes_recursive(end + cut_length, -cut_length);
477 edits->shift_effects_recursive(start, cut_length, 1);
478 edits->shift_effects_recursive(end + cut_length, -cut_length, 1);
480 if( !edit_edits && startproject < start ) {
481 edits->clear(startproject, start);
482 cut_length = start - startproject;
483 for( Edit *edit=next; edit; edit=edit->next )
484 edit->startproject += cut_length;
487 this->startproject = startproject;
488 this->startsource = startsource;
489 this->length = length;
494 int Edit::shift_end(int edit_mode, int64_t newposition, int64_t oldposition,
495 int edit_edits, int edit_labels, int edit_plugins, int edit_autos,
498 int64_t startproject = this->startproject;
499 int64_t startsource = this->startsource;
500 int64_t length = this->length;
501 int64_t source_len = get_source_end(startsource + length);
502 int64_t cut_length = newposition - oldposition;
503 source_len += cut_length;
505 switch( edit_mode ) {
507 length += cut_length;
510 startsource += cut_length;
512 case MOVE_EDGE_MEDIA:
513 startsource -= cut_length;
514 length += cut_length;
517 if( startproject < 0 ) {
518 startsource += startproject;
519 length += startproject;
522 if( startsource < 0 )
524 if( length > source_len )
529 int64_t start = this->startproject;
530 int64_t end = start + this->length;
532 double cut_len = track->from_units(cut_length);
533 double end_pos = edits->track->from_units(end);
535 edits->edl->labels->clear(end_pos + cut_len, end_pos, 1);
537 edits->edl->labels->insert(end_pos, cut_len);
539 Track *track = edits->track;
541 track->clear(end+cut_length, end,
542 0, 0, edit_autos, edit_plugins, trim_edits);
543 else if( cut_length > 0 ) {
545 track->shift_keyframes(end, cut_length);
547 track->shift_effects(end, cut_length, 1, trim_edits);
550 int64_t new_end = startproject + length;
552 cut_length = new_end - end;
553 for( Edit* edit=next; edit; edit=edit->next )
554 edit->startproject += cut_length;
556 else if( new_end > end )
557 edits->clear(end, new_end);
559 this->startproject = startproject;
560 this->startsource = startsource;
561 this->length = length;
567 int Edit::popup_transition(float view_start, float zoom_units, int cursor_x, int cursor_y)
569 int64_t left, right, left_unit, right_unit;
570 if(!transition) return 0;
571 get_handle_parameters(left, right, left_unit, right_unit, view_start, zoom_units);
573 if(cursor_x > left && cursor_x < right)
575 // transition->popup_transition(cursor_x, cursor_y);
581 int Edit::select_handle(float view_start, float zoom_units, int cursor_x, int cursor_y, int64_t &selection)
583 int64_t left, right, left_unit, right_unit;
584 get_handle_parameters(left, right, left_unit, right_unit, view_start, zoom_units);
586 int64_t pixel1, pixel2;
588 pixel2 = pixel1 + 10;
591 // cursor_x is faked in acanvas
592 if(cursor_x >= pixel1 && cursor_x <= pixel2)
594 selection = left_unit;
595 return 1; // left handle
598 //int64_t endproject = startproject + length;
600 pixel1 = pixel2 - 10;
603 if(cursor_x >= pixel1 && cursor_x <= pixel2)
605 selection = right_unit;
606 return 2; // right handle
611 void Edit::get_title(char *title)
613 if( user_title[0] ) {
614 strcpy(title, user_title);
617 Indexable *idxbl = asset ? (Indexable*)asset : (Indexable*)nested_edl;
623 fs.extract_name(title, idxbl->path);
624 if( asset || track->data_type == TRACK_AUDIO ) {
625 char number[BCSTRLEN];
626 sprintf(number, " #%d", channel + 1);
627 strcat(title, number);