r851: Merge 2.1:
[cinelerra_cv/ct.git] / cinelerra / edit.C
blob9ff0c6ebee7586c51afaa4841224e8cfb93eec87
1 #include "asset.h"
2 #include "assets.h"
3 #include "clip.h"
4 #include "edit.h"
5 #include "edits.h"
6 #include "edl.h"
7 #include "edlsession.h"
8 #include "filexml.h"
9 #include "filesystem.h"
10 #include "localsession.h"
11 #include "plugin.h"
12 #include "mainsession.h"
13 #include "trackcanvas.h"
14 #include "tracks.h"
15 #include "transition.h"
16 #include <string.h>
19 Edit::Edit()
21         reset();
24 Edit::Edit(EDL *edl, Track *track)
26         reset();
27         this->edl = edl;
28         this->track = track;
29         if(track) this->edits = track->edits;
30         id = EDL::next_id();
33 Edit::Edit(EDL *edl, Edits *edits)
35         reset();
36         this->edl = edl;
37         this->edits = edits;
38         if(edits) this->track = edits->track;
39         id = EDL::next_id();
42 Edit::~Edit()
44 //printf("Edit::~Edit 1\n");
45         if(transition) delete transition;
46 //printf("Edit::~Edit 2\n");
49 void Edit::reset()
51         edl = 0;
52         track = 0;
53         edits = 0;
54         startsource = 0;  
55         startproject = 0;        
56         length = 0;  
57         asset = 0;
58         transition = 0;
59         channel = 0;
60         user_title[0] = 0;
63 int Edit::copy(int64_t start, int64_t end, FileXML *file, char *output_path)
65 // variables
66 //printf("Edit::copy 1\n");
68         int64_t endproject = startproject + length;
69         int result;
71         if((startproject >= start && startproject <= end) ||  // startproject in range
72                  (endproject <= end && endproject >= start) ||     // endproject in range
73                  (startproject <= start && endproject >= end))    // range in project
74         {   
75 // edit is in range
76                 int64_t startproject_in_selection = startproject; // start of edit in selection in project
77                 int64_t startsource_in_selection = startsource; // start of source in selection in source
78                 int64_t endsource_in_selection = startsource + length; // end of source in selection
79                 int64_t length_in_selection = length;             // length of edit in selection
80 //printf("Edit::copy 2\n");
82                 if(startproject < start)
83                 {         // start is after start of edit in project
84                         int64_t length_difference = start - startproject;
86                         startsource_in_selection += length_difference;
87                         startproject_in_selection += length_difference;
88                         length_in_selection -= length_difference;
89                 }
90 //printf("Edit::copy 3\n");
92                 if(endproject > end)
93                 {         // end is before end of edit in project
94                         length_in_selection = end - startproject_in_selection;
95                 }
96                 
97 //printf("Edit::copy 4\n");
98                 if(file)    // only if not counting
99                 {
100                         file->tag.set_title("EDIT");
101                         file->tag.set_property("STARTSOURCE", startsource_in_selection);
102                         file->tag.set_property("CHANNEL", (int64_t)channel);
103                         file->tag.set_property("LENGTH", length_in_selection);
104                         if(user_title[0]) file->tag.set_property("USER_TITLE", user_title);
105 //printf("Edit::copy 5\n");
107                         copy_properties_derived(file, length_in_selection);
109                         file->append_tag();
110 //                      file->append_newline();
111 //printf("Edit::copy 6\n");
113                         if(asset)
114                         {
115 //printf("Edit::copy 6 %s\n", asset->path);
116                                 char stored_path[1024];
117                                 char asset_directory[1024], output_directory[1024];
118                                 FileSystem fs;
120 //printf("Edit::copy 6 %s\n", asset->path);
121                                 fs.extract_dir(asset_directory, asset->path);
122 //printf("Edit::copy 6 %s\n", asset->path);
124                                 if(output_path)
125                                         fs.extract_dir(output_directory, output_path);
126                                 else
127                                         output_directory[0] = 0;
128 //printf("Edit::copy %s, %s %s, %s\n", asset->path, asset_directory, output_path, output_directory);
130                                 if(output_path && !strcmp(asset_directory, output_directory))
131                                         fs.extract_name(stored_path, asset->path);
132                                 else
133                                         strcpy(stored_path, asset->path);
135                                 file->tag.set_title("FILE");
136                                 file->tag.set_property("SRC", stored_path);
137                                 file->append_tag();
138                                 file->tag.set_title("/FILE");
139                                 file->append_tag();
140                         }
142                         if(transition)
143                         {
144                                 transition->save_xml(file);
145                         }
147 //printf("Edit::copy 7\n");
148                         file->tag.set_title("/EDIT");
149                         file->append_tag();
150                         file->append_newline(); 
151 //printf("Edit::copy 8\n");
152                 }
153 //printf("Edit::copy 9\n");
154                 result = 1;
155         }
156         else
157         {
158                 result = 0;
159         }
160 //printf("Edit::copy 10\n");
161         return result;
165 int64_t Edit::get_source_end(int64_t default_)
167         return default_;
170 void Edit::insert_transition(char *title)
172 //printf("Edit::insert_transition this=%p title=%p title=%s\n", this, title, title);
173         transition = new Transition(edl, 
174                 this, 
175                 title, 
176                 track->to_units(edl->session->default_transition_length, 1));
179 void Edit::detach_transition()
181         if(transition) delete transition;
182         transition = 0;
185 int Edit::silence()
187         if(asset) 
188                 return 0;
189         else
190                 return 1;
194 void Edit::copy_from(Edit *edit)
196         this->asset = edl->assets->update(edit->asset);
197         this->startsource = edit->startsource;
198         this->startproject = edit->startproject;
199         this->length = edit->length;
200         strcpy (this->user_title, edit->user_title);
202         if(edit->transition)
203         {
204                 if(!transition) transition = new Transition(edl, 
205                         this, 
206                         edit->transition->title,
207                         edit->transition->length);
208                 *this->transition = *edit->transition;
209         }
210         this->channel = edit->channel;
213 void Edit::equivalent_output(Edit *edit, int64_t *result)
215 // End of edit changed
216         if(startproject + length != edit->startproject + edit->length)
217         {
218                 int64_t new_length = MIN(startproject + length, edit->startproject + edit->length);
219                 if(*result < 0 || new_length < *result) 
220                         *result = new_length;
221         }
223 // Start of edit changed
224         if(
225 // One is silence and one isn't
226                 edit->asset == 0 && asset != 0 ||
227                 edit->asset != 0 && asset == 0 ||
228 // One has transition and one doesn't
229                 edit->transition == 0 && transition != 0 ||
230                 edit->transition != 0 && transition == 0 ||
231 // Position changed
232                 startproject != edit->startproject ||
233                 startsource != edit->startsource ||
234 // Transition changed
235                 (transition && 
236                         edit->transition && 
237                         !transition->identical(edit->transition)) ||
238 // Asset changed
239                 (asset && 
240                         edit->asset &&
241                         !asset->equivalent(*edit->asset, 1, 1))
242                 )
243         {
244                 if(*result < 0 || startproject < *result) *result = startproject;
245         }
249 Edit& Edit::operator=(Edit& edit)
251 //printf("Edit::operator= called\n");
252         copy_from(&edit);
253         return *this;
256 void Edit::synchronize_params(Edit *edit)
258         copy_from(edit);
262 // Comparison for ResourcePixmap drawing
263 int Edit::identical(Edit &edit)
265         int result = (this->asset == edit.asset &&
266         this->startsource == edit.startsource &&
267         this->startproject == edit.startproject &&
268         this->length == edit.length &&
269         this->transition == edit.transition &&
270         this->channel == edit.channel);
271         return result;
274 int Edit::operator==(Edit &edit)
276         return identical(edit);
279 double Edit::frames_per_picon()
281         return Units::round(picon_w()) / frame_w();
284 double Edit::frame_w()
286         return track->from_units(1) * 
287                 edl->session->sample_rate / 
288                 edl->local_session->zoom_sample;
291 double Edit::picon_w()
293         return (double)edl->local_session->zoom_track * 
294                 asset->width / 
295                 asset->height;
298 int Edit::picon_h()
300         return edl->local_session->zoom_track;
304 int Edit::dump()
306         printf("     EDIT %p\n", this); fflush(stdout);
307         printf("      asset %p\n", asset); fflush(stdout);
308         printf("      channel %d\n", channel);
309         if(transition) 
310         {
311                 printf("      TRANSITION %p\n", transition);
312                 transition->dump();
313         }
314         printf("      startsource %lld startproject %lld length %lld\n", startsource, startproject, length); fflush(stdout);
315         return 0;
318 int Edit::load_properties(FileXML *file, int64_t &startproject)
320         startsource = file->tag.get_property("STARTSOURCE", (int64_t)0);
321         length = file->tag.get_property("LENGTH", (int64_t)0);
322         user_title[0] = 0;
323         file->tag.get_property("USER_TITLE", user_title);
324         this->startproject = startproject;
325         load_properties_derived(file);
326         return 0;
329 void Edit::shift(int64_t difference)
331 //printf("Edit::shift 1 %p %lld %lld\n", this, startproject, difference);
332         startproject += difference;
333 //printf("Edit::shift 2 %lld %lld\n", startproject, difference);
336 int Edit::shift_start_in(int edit_mode, 
337         int64_t newposition, 
338         int64_t oldposition,
339         int edit_edits,
340         int edit_labels,
341         int edit_plugins,
342         Edits *trim_edits)
344         int64_t cut_length = newposition - oldposition;
345         int64_t end_previous_source, end_source;
347         if(edit_mode == MOVE_ALL_EDITS)
348         {
349                 if(cut_length < length)
350                 {        // clear partial 
351                         edits->clear_recursive(oldposition, 
352                                 newposition,
353                                 edit_edits,
354                                 edit_labels,
355                                 edit_plugins,
356                                 trim_edits);
357                 }
358                 else
359                 {        // clear entire
360                         edits->clear_recursive(oldposition, 
361                                 startproject + length,
362                                 edit_edits,
363                                 edit_labels,
364                                 edit_plugins,
365                                 trim_edits);
366                 }
367         }
368         else
369         if(edit_mode == MOVE_ONE_EDIT)
370         {
371 // Paste silence and cut
372 //printf("Edit::shift_start_in 1\n");
373                 if(!previous)
374                 {
375                         Edit *new_edit = edits->create_edit();
376                         new_edit->startproject = this->startproject;
377                         new_edit->length = 0;
378                         edits->insert_before(this, 
379                                 new_edit);
380                 }
381 //printf("Edit::shift_start_in 2 %p\n", previous);
383                 end_previous_source = previous->get_source_end(previous->startsource + previous->length + cut_length);
384                 if(end_previous_source > 0 && 
385                         previous->startsource + previous->length + cut_length > end_previous_source)
386                         cut_length = end_previous_source - previous->startsource - previous->length;
388                 if(cut_length < length)
389                 {               // Move in partial
390                         startproject += cut_length;
391                         startsource += cut_length;
392                         length -= cut_length;
393                         previous->length += cut_length;
394 //printf("Edit::shift_start_in 2\n");
395                 }
396                 else
397                 {               // Clear entire edit
398                         cut_length = length;
399                         previous->length += cut_length;
400                         for(Edit* current_edit = this; current_edit; current_edit = current_edit->next)
401                         {
402                                 current_edit->startproject += cut_length;
403                         }
404                         edits->clear_recursive(oldposition + cut_length, 
405                                 startproject + cut_length,
406                                 edit_edits,
407                                 edit_labels,
408                                 edit_plugins,
409                                 trim_edits);
410                 }
411 //printf("Edit::shift_start_in 3\n");
412         }
413         else
414         if(edit_mode == MOVE_NO_EDITS)
415         {
416                 end_source = get_source_end(startsource + length + cut_length);
417                 if(end_source > 0 && startsource + length + cut_length > end_source)
418                         cut_length = end_source - startsource - length;
419                 
420                 startsource += cut_length;
421         }
422         return 0;
425 int Edit::shift_start_out(int edit_mode, 
426         int64_t newposition, 
427         int64_t oldposition,
428         int edit_edits,
429         int edit_labels,
430         int edit_plugins,
431         Edits *trim_edits)
433         int64_t cut_length = oldposition - newposition;
435         if(asset)
436         {
437                 int64_t end_source = get_source_end(1);
439 //printf("Edit::shift_start_out 1 %lld %lld\n", startsource, cut_length);
440                 if(end_source > 0 && startsource < cut_length)
441                 {
442                         cut_length = startsource;
443                 }
444         }
446         if(edit_mode == MOVE_ALL_EDITS)
447         {
448 //printf("Edit::shift_start_out 10 %lld\n", cut_length);
449                 startsource -= cut_length;
450                 length += cut_length;
452                 edits->shift_keyframes_recursive(startproject, 
453                         cut_length);
454                 if(edit_plugins)
455                         edits->shift_effects_recursive(startproject, 
456                                 cut_length);
458                 for(Edit* current_edit = next; current_edit; current_edit = current_edit->next)
459                 {
460                         current_edit->startproject += cut_length;
461                 }
462         }
463         else
464         if(edit_mode == MOVE_ONE_EDIT)
465         {
466                 if(previous)
467                 {
468                         if(cut_length < previous->length)
469                         {   // Cut into previous edit
470                                 previous->length -= cut_length;
471                                 startproject -= cut_length;
472                                 startsource -= cut_length;
473                                 length += cut_length;
474 printf("Edit::shift_start_out 2\n");
475                         }
476                         else
477                         {   // Clear entire previous edit
478                                 cut_length = previous->length;
479                                 previous->length = 0;
480                                 length += cut_length;
481                                 startsource -= cut_length;
482                                 startproject -= cut_length;
483                         }
484                 }
485         }
486         else
487         if(edit_mode == MOVE_NO_EDITS)
488         {
489                 startsource -= cut_length;
490         }
492 // Fix infinite length files
493         if(startsource < 0) startsource = 0;
494         return 0;
497 int Edit::shift_end_in(int edit_mode, 
498         int64_t newposition, 
499         int64_t oldposition,
500         int edit_edits,
501         int edit_labels,
502         int edit_plugins,
503         Edits *trim_edits)
505         int64_t cut_length = oldposition - newposition;
507         if(edit_mode == MOVE_ALL_EDITS)
508         {
509 //printf("Edit::shift_end_in 1\n");
510                 if(newposition > startproject)
511                 {        // clear partial edit
512 //printf("Edit::shift_end_in %p %p\n", track->edits, edits);
513                         edits->clear_recursive(newposition, 
514                                 oldposition,
515                                 edit_edits,
516                                 edit_labels,
517                                 edit_plugins,
518                                 trim_edits);
519                 }
520                 else
521                 {        // clear entire edit
522                         edits->clear_recursive(startproject, 
523                                 oldposition,
524                                 edit_edits,
525                                 edit_labels,
526                                 edit_plugins,
527                                 trim_edits);
528                 }
529         }
530         else
531         if(edit_mode == MOVE_ONE_EDIT)
532         {
533                 if(next)
534                 {
535                         if(next->asset)
536                         {
537                                 int64_t end_source = next->get_source_end(1);
539                                 if(end_source > 0 && next->startsource - cut_length < 0)
540                                 {
541                                         cut_length = next->startsource;
542                                 }
543                         }
545                         if(cut_length < length)
546                         {
547                                 length -= cut_length;
548                                 next->startproject -= cut_length;
549                                 next->startsource -= cut_length;
550                                 next->length += cut_length;
551 //printf("Edit::shift_end_in 2 %d\n", cut_length);
552                         }
553                         else
554                         {
555                                 cut_length = length;
556                                 next->length += cut_length;
557                                 next->startsource -= cut_length;
558                                 next->startproject -= cut_length;
559                                 length -= cut_length;
560                         }
561                 }
562                 else
563                 {
564                         if(cut_length < length)
565                         {
566                                 length -= cut_length;
567                         }
568                         else
569                         {
570                                 cut_length = length;
571                                 edits->clear_recursive(startproject, 
572                                         oldposition,
573                                         edit_edits,
574                                         edit_labels,
575                                         edit_plugins,
576                                         trim_edits);
577                         }
578                 }
579         }
580         else
581 // Does nothing for plugins
582         if(edit_mode == MOVE_NO_EDITS)
583         {
584 //printf("Edit::shift_end_in 3\n");
585                 int64_t end_source = get_source_end(1);
586                 if(end_source > 0 && startsource < cut_length)
587                 {
588                         cut_length = startsource;
589                 }
590                 startsource -= cut_length;
591         }
592         return 0;
595 int Edit::shift_end_out(int edit_mode, 
596         int64_t newposition, 
597         int64_t oldposition,
598         int edit_edits,
599         int edit_labels,
600         int edit_plugins,
601         Edits *trim_edits)
603         int64_t cut_length = newposition - oldposition;
604         int64_t endsource = get_source_end(startsource + length + cut_length);
606 // check end of edit against end of source file
607         if(endsource > 0 && startsource + length + cut_length > endsource)
608                 cut_length = endsource - startsource - length;
610 //printf("Edit::shift_end_out 1 %lld %d %d %d\n", oldposition, newposition, this->length, cut_length);
611         if(edit_mode == MOVE_ALL_EDITS)
612         {
613 // Extend length
614                 this->length += cut_length;
616 // Effects are shifted in length extension
617                 if(edit_plugins)
618                         edits->shift_effects_recursive(oldposition /* startproject */, 
619                                 cut_length);
620                 edits->shift_keyframes_recursive(oldposition /* startproject */, 
621                         cut_length);
623                 for(Edit* current_edit = next; current_edit; current_edit = current_edit->next)
624                 {
625                         current_edit->startproject += cut_length;
626                 }
627         }
628         else
629         if(edit_mode == MOVE_ONE_EDIT)
630         {
631                 if(next)
632                 {
633                         if(cut_length < next->length)
634                         {
635                                 length += cut_length;
636                                 next->startproject += cut_length;
637                                 next->startsource += cut_length;
638                                 next->length -= cut_length;
639 //printf("Edit::shift_end_out 2 %d\n", cut_length);
640                         }
641                         else
642                         {
643                                 cut_length = next->length;
644                                 next->length = 0;
645                                 length += cut_length;
646                         }
647                 }
648                 else
649                 {
650                         length += cut_length;
651                 }
652         }
653         else
654         if(edit_mode == MOVE_NO_EDITS)
655         {
656                 startsource += cut_length;
657         }
658         return 0;
689 int Edit::popup_transition(float view_start, float zoom_units, int cursor_x, int cursor_y)
691         int64_t left, right, left_unit, right_unit;
692         if(!transition) return 0;
693         get_handle_parameters(left, right, left_unit, right_unit, view_start, zoom_units);
695         if(cursor_x > left && cursor_x < right)
696         {
697 //              transition->popup_transition(cursor_x, cursor_y);
698                 return 1;
699         }
700         return 0;
703 int Edit::select_handle(float view_start, float zoom_units, int cursor_x, int cursor_y, int64_t &selection)
705         int64_t left, right, left_unit, right_unit;
706         get_handle_parameters(left, right, left_unit, right_unit, view_start, zoom_units);
708         int64_t pixel1, pixel2;
709         pixel1 = left;
710         pixel2 = pixel1 + 10;
712 // test left edit
713 // cursor_x is faked in acanvas
714         if(cursor_x >= pixel1 && cursor_x <= pixel2)
715         {
716                 selection = left_unit;
717                 return 1;     // left handle
718         }
720         int64_t endproject = startproject + length;
721         pixel2 = right;
722         pixel1 = pixel2 - 10;
724 // test right edit      
725         if(cursor_x >= pixel1 && cursor_x <= pixel2)
726         {
727                 selection = right_unit;
728                 return 2;     // right handle
729         }
730         return 0;