r553: Modern gccs require __attribute__((used)) for variables used only in assembly.
[cinelerra_cv.git] / cinelerra / edit.C
blob53e32919dee6f791f7567aa0c68d30e13ad1dd1e
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 picon_w() / frame_w();
284 double Edit::frame_w()
286         return track->from_units(1) * edl->session->sample_rate / edl->local_session->zoom_sample;
289 double Edit::picon_w()
291         return (double)edl->local_session->zoom_track * asset->width / asset->height;
294 int Edit::picon_h()
296         return edl->local_session->zoom_track;
300 int Edit::dump()
302         printf("     EDIT %p\n", this); fflush(stdout);
303         printf("      asset %p\n", asset); fflush(stdout);
304         printf("      channel %d\n", channel);
305         if(transition) 
306         {
307                 printf("      TRANSITION %p\n", transition);
308                 transition->dump();
309         }
310         printf("      startsource %lld startproject %lld length %lld\n", startsource, startproject, length); fflush(stdout);
311         return 0;
314 int Edit::load_properties(FileXML *file, int64_t &startproject)
316         startsource = file->tag.get_property("STARTSOURCE", (int64_t)0);
317         length = file->tag.get_property("LENGTH", (int64_t)0);
318         user_title[0] = 0;
319         file->tag.get_property("USER_TITLE", user_title);
320         this->startproject = startproject;
321         load_properties_derived(file);
322         return 0;
325 void Edit::shift(int64_t difference)
327 //printf("Edit::shift 1 %p %lld %lld\n", this, startproject, difference);
328         startproject += difference;
329 //printf("Edit::shift 2 %lld %lld\n", startproject, difference);
332 int Edit::shift_start_in(int edit_mode, 
333         int64_t newposition, 
334         int64_t oldposition,
335         int edit_edits,
336         int edit_labels,
337         int edit_plugins,
338         Edits *trim_edits)
340         int64_t cut_length = newposition - oldposition;
341         int64_t end_previous_source, end_source;
343         if(edit_mode == MOVE_ALL_EDITS)
344         {
345                 if(cut_length < length)
346                 {        // clear partial 
347                         edits->clear_recursive(oldposition, 
348                                 newposition,
349                                 edit_edits,
350                                 edit_labels,
351                                 edit_plugins,
352                                 trim_edits);
353                 }
354                 else
355                 {        // clear entire
356                         edits->clear_recursive(oldposition, 
357                                 startproject + length,
358                                 edit_edits,
359                                 edit_labels,
360                                 edit_plugins,
361                                 trim_edits);
362                 }
363         }
364         else
365         if(edit_mode == MOVE_ONE_EDIT)
366         {
367 // Paste silence and cut
368 //printf("Edit::shift_start_in 1\n");
369                 if(!previous)
370                 {
371                         Edit *new_edit = edits->create_edit();
372                         new_edit->startproject = this->startproject;
373                         new_edit->length = 0;
374                         edits->insert_before(this, 
375                                 new_edit);
376                 }
377 //printf("Edit::shift_start_in 2 %p\n", previous);
379                 end_previous_source = previous->get_source_end(previous->startsource + previous->length + cut_length);
380                 if(end_previous_source > 0 && 
381                         previous->startsource + previous->length + cut_length > end_previous_source)
382                         cut_length = end_previous_source - previous->startsource - previous->length;
384                 if(cut_length < length)
385                 {               // Move in partial
386                         startproject += cut_length;
387                         startsource += cut_length;
388                         length -= cut_length;
389                         previous->length += cut_length;
390 //printf("Edit::shift_start_in 2\n");
391                 }
392                 else
393                 {               // Clear entire edit
394                         cut_length = length;
395                         previous->length += cut_length;
396                         for(Edit* current_edit = this; current_edit; current_edit = current_edit->next)
397                         {
398                                 current_edit->startproject += cut_length;
399                         }
400                         edits->clear_recursive(oldposition + cut_length, 
401                                 startproject + cut_length,
402                                 edit_edits,
403                                 edit_labels,
404                                 edit_plugins,
405                                 trim_edits);
406                 }
407 //printf("Edit::shift_start_in 3\n");
408         }
409         else
410         if(edit_mode == MOVE_NO_EDITS)
411         {
412                 end_source = get_source_end(startsource + length + cut_length);
413                 if(end_source > 0 && startsource + length + cut_length > end_source)
414                         cut_length = end_source - startsource - length;
415                 
416                 startsource += cut_length;
417         }
418         return 0;
421 int Edit::shift_start_out(int edit_mode, 
422         int64_t newposition, 
423         int64_t oldposition,
424         int edit_edits,
425         int edit_labels,
426         int edit_plugins,
427         Edits *trim_edits)
429         int64_t cut_length = oldposition - newposition;
431         if(asset)
432         {
433                 int64_t end_source = get_source_end(1);
435 //printf("Edit::shift_start_out 1 %lld %lld\n", startsource, cut_length);
436                 if(end_source > 0 && startsource < cut_length)
437                 {
438                         cut_length = startsource;
439                 }
440         }
442         if(edit_mode == MOVE_ALL_EDITS)
443         {
444 //printf("Edit::shift_start_out 10 %lld\n", cut_length);
445                 startsource -= cut_length;
446                 length += cut_length;
448                 edits->shift_keyframes_recursive(startproject, 
449                         cut_length);
450                 if(edit_plugins)
451                         edits->shift_effects_recursive(startproject, 
452                                 cut_length);
454                 for(Edit* current_edit = next; current_edit; current_edit = current_edit->next)
455                 {
456                         current_edit->startproject += cut_length;
457                 }
458         }
459         else
460         if(edit_mode == MOVE_ONE_EDIT)
461         {
462                 if(previous)
463                 {
464                         if(cut_length < previous->length)
465                         {   // Cut into previous edit
466                                 previous->length -= cut_length;
467                                 startproject -= cut_length;
468                                 startsource -= cut_length;
469                                 length += cut_length;
470 printf("Edit::shift_start_out 2\n");
471                         }
472                         else
473                         {   // Clear entire previous edit
474                                 cut_length = previous->length;
475                                 previous->length = 0;
476                                 length += cut_length;
477                                 startsource -= cut_length;
478                                 startproject -= cut_length;
479                         }
480                 }
481         }
482         else
483         if(edit_mode == MOVE_NO_EDITS)
484         {
485                 startsource -= cut_length;
486         }
488 // Fix infinite length files
489         if(startsource < 0) startsource = 0;
490         return 0;
493 int Edit::shift_end_in(int edit_mode, 
494         int64_t newposition, 
495         int64_t oldposition,
496         int edit_edits,
497         int edit_labels,
498         int edit_plugins,
499         Edits *trim_edits)
501         int64_t cut_length = oldposition - newposition;
503         if(edit_mode == MOVE_ALL_EDITS)
504         {
505 //printf("Edit::shift_end_in 1\n");
506                 if(newposition > startproject)
507                 {        // clear partial edit
508 //printf("Edit::shift_end_in %p %p\n", track->edits, edits);
509                         edits->clear_recursive(newposition, 
510                                 oldposition,
511                                 edit_edits,
512                                 edit_labels,
513                                 edit_plugins,
514                                 trim_edits);
515                 }
516                 else
517                 {        // clear entire edit
518                         edits->clear_recursive(startproject, 
519                                 oldposition,
520                                 edit_edits,
521                                 edit_labels,
522                                 edit_plugins,
523                                 trim_edits);
524                 }
525         }
526         else
527         if(edit_mode == MOVE_ONE_EDIT)
528         {
529                 if(next)
530                 {
531                         if(next->asset)
532                         {
533                                 int64_t end_source = next->get_source_end(1);
535                                 if(end_source > 0 && next->startsource - cut_length < 0)
536                                 {
537                                         cut_length = next->startsource;
538                                 }
539                         }
541                         if(cut_length < length)
542                         {
543                                 length -= cut_length;
544                                 next->startproject -= cut_length;
545                                 next->startsource -= cut_length;
546                                 next->length += cut_length;
547 //printf("Edit::shift_end_in 2 %d\n", cut_length);
548                         }
549                         else
550                         {
551                                 cut_length = length;
552                                 next->length += cut_length;
553                                 next->startsource -= cut_length;
554                                 next->startproject -= cut_length;
555                                 length -= cut_length;
556                         }
557                 }
558                 else
559                 {
560                         if(cut_length < length)
561                         {
562                                 length -= cut_length;
563                         }
564                         else
565                         {
566                                 cut_length = length;
567                                 edits->clear_recursive(startproject, 
568                                         oldposition,
569                                         edit_edits,
570                                         edit_labels,
571                                         edit_plugins,
572                                         trim_edits);
573                         }
574                 }
575         }
576         else
577 // Does nothing for plugins
578         if(edit_mode == MOVE_NO_EDITS)
579         {
580 //printf("Edit::shift_end_in 3\n");
581                 int64_t end_source = get_source_end(1);
582                 if(end_source > 0 && startsource < cut_length)
583                 {
584                         cut_length = startsource;
585                 }
586                 startsource -= cut_length;
587         }
588         return 0;
591 int Edit::shift_end_out(int edit_mode, 
592         int64_t newposition, 
593         int64_t oldposition,
594         int edit_edits,
595         int edit_labels,
596         int edit_plugins,
597         Edits *trim_edits)
599         int64_t cut_length = newposition - oldposition;
600         int64_t endsource = get_source_end(startsource + length + cut_length);
602 // check end of edit against end of source file
603         if(endsource > 0 && startsource + length + cut_length > endsource)
604                 cut_length = endsource - startsource - length;
606 //printf("Edit::shift_end_out 1 %lld %d %d %d\n", oldposition, newposition, this->length, cut_length);
607         if(edit_mode == MOVE_ALL_EDITS)
608         {
609 // Extend length
610                 this->length += cut_length;
612 // Effects are shifted in length extension
613                 if(edit_plugins)
614                         edits->shift_effects_recursive(oldposition /* startproject */, 
615                                 cut_length);
616                 edits->shift_keyframes_recursive(oldposition /* startproject */, 
617                         cut_length);
619                 for(Edit* current_edit = next; current_edit; current_edit = current_edit->next)
620                 {
621                         current_edit->startproject += cut_length;
622                 }
623         }
624         else
625         if(edit_mode == MOVE_ONE_EDIT)
626         {
627                 if(next)
628                 {
629                         if(cut_length < next->length)
630                         {
631                                 length += cut_length;
632                                 next->startproject += cut_length;
633                                 next->startsource += cut_length;
634                                 next->length -= cut_length;
635 //printf("Edit::shift_end_out 2 %d\n", cut_length);
636                         }
637                         else
638                         {
639                                 cut_length = next->length;
640                                 next->length = 0;
641                                 length += cut_length;
642                         }
643                 }
644                 else
645                 {
646                         length += cut_length;
647                 }
648         }
649         else
650         if(edit_mode == MOVE_NO_EDITS)
651         {
652                 startsource += cut_length;
653         }
654         return 0;
685 int Edit::popup_transition(float view_start, float zoom_units, int cursor_x, int cursor_y)
687         int64_t left, right, left_unit, right_unit;
688         if(!transition) return 0;
689         get_handle_parameters(left, right, left_unit, right_unit, view_start, zoom_units);
691         if(cursor_x > left && cursor_x < right)
692         {
693 //              transition->popup_transition(cursor_x, cursor_y);
694                 return 1;
695         }
696         return 0;
699 int Edit::select_handle(float view_start, float zoom_units, int cursor_x, int cursor_y, int64_t &selection)
701         int64_t left, right, left_unit, right_unit;
702         get_handle_parameters(left, right, left_unit, right_unit, view_start, zoom_units);
704         int64_t pixel1, pixel2;
705         pixel1 = left;
706         pixel2 = pixel1 + 10;
708 // test left edit
709 // cursor_x is faked in acanvas
710         if(cursor_x >= pixel1 && cursor_x <= pixel2)
711         {
712                 selection = left_unit;
713                 return 1;     // left handle
714         }
716         int64_t endproject = startproject + length;
717         pixel2 = right;
718         pixel1 = pixel2 - 10;
720 // test right edit      
721         if(cursor_x >= pixel1 && cursor_x <= pixel2)
722         {
723                 selection = right_unit;
724                 return 2;     // right handle
725         }
726         return 0;