r125: This commit was manufactured by cvs2svn to create tag 'r1_1_7-last'.
[cinelerra_cv/mob.git] / hvirtual / cinelerra / edit.C
blob0788e912a210b062810f8d1233754b5724ccbaec
1 #include "assets.h"
2 #include "clip.h"
3 #include "edit.h"
4 #include "edits.h"
5 #include "edl.h"
6 #include "edlsession.h"
7 #include "filexml.h"
8 #include "filesystem.h"
9 #include "localsession.h"
10 #include "plugin.h"
11 #include "mainsession.h"
12 #include "trackcanvas.h"
13 #include "tracks.h"
14 #include "transition.h"
15 #include <string.h>
18 Edit::Edit()
20         reset();
23 Edit::Edit(EDL *edl, Track *track)
25         reset();
26         this->edl = edl;
27         this->track = track;
28         if(track) this->edits = track->edits;
29         id = EDL::next_id();
32 Edit::Edit(EDL *edl, Edits *edits)
34         reset();
35         this->edl = edl;
36         this->edits = edits;
37         if(edits) this->track = edits->track;
38         id = EDL::next_id();
41 Edit::~Edit()
43 //printf("Edit::~Edit 1\n");
44         if(transition) delete transition;
45 //printf("Edit::~Edit 2\n");
48 void Edit::reset()
50         edl = 0;
51         track = 0;
52         edits = 0;
53         startsource = 0;  
54         startproject = 0;        
55         length = 0;  
56         asset = 0;
57         transition = 0;
58         channel = 0;
61 int Edit::copy(int64_t start, int64_t end, FileXML *file, char *output_path)
63 // variables
64 //printf("Edit::copy 1\n");
66         int64_t endproject = startproject + length;
67         int result;
69         if((startproject >= start && startproject <= end) ||  // startproject in range
70                  (endproject <= end && endproject >= start) ||     // endproject in range
71                  (startproject <= start && endproject >= end))    // range in project
72         {   
73 // edit is in range
74                 int64_t startproject_in_selection = startproject; // start of edit in selection in project
75                 int64_t startsource_in_selection = startsource; // start of source in selection in source
76                 int64_t endsource_in_selection = startsource + length; // end of source in selection
77                 int64_t length_in_selection = length;             // length of edit in selection
78 //printf("Edit::copy 2\n");
80                 if(startproject < start)
81                 {         // start is after start of edit in project
82                         int64_t length_difference = start - startproject;
84                         startsource_in_selection += length_difference;
85                         startproject_in_selection += length_difference;
86                         length_in_selection -= length_difference;
87                 }
88 //printf("Edit::copy 3\n");
90                 if(endproject > end)
91                 {         // end is before end of edit in project
92                         length_in_selection = end - startproject_in_selection;
93                 }
94                 
95 //printf("Edit::copy 4\n");
96                 if(file)    // only if not counting
97                 {
98                         file->tag.set_title("EDIT");
99                         file->tag.set_property("STARTSOURCE", startsource_in_selection);
100                         file->tag.set_property("CHANNEL", (int64_t)channel);
101                         file->tag.set_property("LENGTH", length_in_selection);
102 //printf("Edit::copy 5\n");
104                         copy_properties_derived(file, length_in_selection);
106                         file->append_tag();
107 //                      file->append_newline();
108 //printf("Edit::copy 6\n");
110                         if(asset)
111                         {
112 //printf("Edit::copy 6 %s\n", asset->path);
113                                 char stored_path[1024];
114                                 char asset_directory[1024], output_directory[1024];
115                                 FileSystem fs;
117 //printf("Edit::copy 6 %s\n", asset->path);
118                                 fs.extract_dir(asset_directory, asset->path);
119 //printf("Edit::copy 6 %s\n", asset->path);
121                                 if(output_path)
122                                         fs.extract_dir(output_directory, output_path);
123                                 else
124                                         output_directory[0] = 0;
125 //printf("Edit::copy %s, %s %s, %s\n", asset->path, asset_directory, output_path, output_directory);
127                                 if(output_path && !strcmp(asset_directory, output_directory))
128                                         fs.extract_name(stored_path, asset->path);
129                                 else
130                                         strcpy(stored_path, asset->path);
132                                 file->tag.set_title("FILE");
133                                 file->tag.set_property("SRC", stored_path);
134                                 file->append_tag();
135                         }
137                         if(transition)
138                         {
139                                 transition->save_xml(file);
140                         }
142 //printf("Edit::copy 7\n");
143                         file->tag.set_title("/EDIT");
144                         file->append_tag();
145                         file->append_newline(); 
146 //printf("Edit::copy 8\n");
147                 }
148 //printf("Edit::copy 9\n");
149                 result = 1;
150         }
151         else
152         {
153                 result = 0;
154         }
155 //printf("Edit::copy 10\n");
156         return result;
160 int64_t Edit::get_source_end(int64_t default_)
162         return default_;
165 void Edit::insert_transition(char *title)
167 //printf("Edit::insert_transition this=%p title=%p title=%s\n", this, title, title);
168         transition = new Transition(edl, 
169                 this, 
170                 title, 
171                 track->to_units(edl->session->default_transition_length, 1));
174 void Edit::detach_transition()
176         if(transition) delete transition;
177         transition = 0;
180 int Edit::silence()
182         if(asset) 
183                 return 0;
184         else
185                 return 1;
189 void Edit::copy_from(Edit *edit)
191         this->asset = edl->assets->update(edit->asset);
192         this->startsource = edit->startsource;
193         this->startproject = edit->startproject;
194         this->length = edit->length;
195         if(edit->transition)
196         {
197                 if(!transition) transition = new Transition(edl, 
198                         this, 
199                         edit->transition->title,
200                         edit->transition->length);
201                 *this->transition = *edit->transition;
202         }
203         this->channel = edit->channel;
206 void Edit::equivalent_output(Edit *edit, int64_t *result)
208 // End of edit changed
209         if(startproject + length != edit->startproject + edit->length)
210         {
211                 int64_t new_length = MIN(startproject + length, edit->startproject + edit->length);
212                 if(*result < 0 || new_length < *result) 
213                         *result = new_length;
214         }
216 // Start of edit changed
217         if(
218 // One is silence and one isn't
219                 edit->asset == 0 && asset != 0 ||
220                 edit->asset != 0 && asset == 0 ||
221 // One has transition and one doesn't
222                 edit->transition == 0 && transition != 0 ||
223                 edit->transition != 0 && transition == 0 ||
224 // Position changed
225                 startproject != edit->startproject ||
226                 startsource != edit->startsource ||
227 // Transition changed
228                 (transition && 
229                         edit->transition && 
230                         !transition->identical(edit->transition)) ||
231 // Asset changed
232                 (asset && 
233                         edit->asset &&
234                         !asset->equivalent(*edit->asset, 1, 1))
235                 )
236         {
237                 if(*result < 0 || startproject < *result) *result = startproject;
238         }
242 Edit& Edit::operator=(Edit& edit)
244 //printf("Edit::operator= called\n");
245         copy_from(&edit);
246         return *this;
249 void Edit::synchronize_params(Edit *edit)
251         copy_from(edit);
255 // Comparison for ResourcePixmap drawing
256 int Edit::identical(Edit &edit)
258         int result = (this->asset == edit.asset &&
259         this->startsource == edit.startsource &&
260         this->startproject == edit.startproject &&
261         this->length == edit.length &&
262         this->transition == edit.transition &&
263         this->channel == edit.channel);
264         return result;
267 int Edit::operator==(Edit &edit)
269         return identical(edit);
272 double Edit::frames_per_picon()
274         return picon_w() / frame_w();
277 double Edit::frame_w()
279         return track->from_units(1) * edl->session->sample_rate / edl->local_session->zoom_sample;
282 double Edit::picon_w()
284         return (double)edl->local_session->zoom_track * asset->width / asset->height;
287 int Edit::picon_h()
289         return edl->local_session->zoom_track;
293 int Edit::dump()
295         printf("     EDIT %p\n", this); fflush(stdout);
296         printf("      asset %p\n", asset); fflush(stdout);
297         printf("      channel %d\n", channel);
298         if(transition) 
299         {
300                 printf("      TRANSITION %p\n", transition);
301                 transition->dump();
302         }
303         printf("      startsource %lld startproject %lld length %lld\n", startsource, startproject, length); fflush(stdout);
304         return 0;
307 int Edit::load_properties(FileXML *file, int64_t &startproject)
309         startsource = file->tag.get_property("STARTSOURCE", (int64_t)0);
310         length = file->tag.get_property("LENGTH", (int64_t)0);
311         this->startproject = startproject;
312         load_properties_derived(file);
313         return 0;
316 void Edit::shift(int64_t difference)
318 //printf("Edit::shift 1 %p %lld %lld\n", this, startproject, difference);
319         startproject += difference;
320 //printf("Edit::shift 2 %lld %lld\n", startproject, difference);
323 int Edit::shift_start_in(int edit_mode, 
324         int64_t newposition, 
325         int64_t oldposition,
326         int edit_edits,
327         int edit_labels,
328         int edit_plugins)
330         int64_t cut_length = newposition - oldposition;
331         int64_t end_previous_source, end_source;
333         if(edit_mode == MOVE_ALL_EDITS)
334         {
335                 if(cut_length < length)
336                 {        // clear partial 
337                         edits->clear_recursive(oldposition, 
338                                 newposition,
339                                 edit_edits,
340                                 edit_labels,
341                                 edit_plugins);
342                 }
343                 else
344                 {        // clear entire
345                         edits->clear_recursive(oldposition, 
346                                 startproject + length,
347                                 edit_edits,
348                                 edit_labels,
349                                 edit_plugins);
350                 }
351         }
352         else
353         if(edit_mode == MOVE_ONE_EDIT)
354         {
355 // Paste silence and cut
356 //printf("Edit::shift_start_in 1\n");
357                 if(!previous)
358                 {
359                         Edit *new_edit = edits->create_edit();
360                         new_edit->startproject = this->startproject;
361                         new_edit->length = 0;
362                         edits->insert_before(this, 
363                                 new_edit);
364                 }
365 //printf("Edit::shift_start_in 2 %p\n", previous);
367                 end_previous_source = previous->get_source_end(previous->startsource + previous->length + cut_length);
368                 if(end_previous_source > 0 && 
369                         previous->startsource + previous->length + cut_length > end_previous_source)
370                         cut_length = end_previous_source - previous->startsource - previous->length;
372                 if(cut_length < length)
373                 {               // Move in partial
374                         startproject += cut_length;
375                         startsource += cut_length;
376                         length -= cut_length;
377                         previous->length += cut_length;
378 //printf("Edit::shift_start_in 2\n");
379                 }
380                 else
381                 {               // Clear entire edit
382                         cut_length = length;
383                         previous->length += cut_length;
384                         for(Edit* current_edit = this; current_edit; current_edit = current_edit->next)
385                         {
386                                 current_edit->startproject += cut_length;
387                         }
388                         edits->clear_recursive(oldposition + cut_length, 
389                                 startproject + cut_length,
390                                 edit_edits,
391                                 edit_labels,
392                                 edit_plugins);
393                 }
394 //printf("Edit::shift_start_in 3\n");
395         }
396         else
397         if(edit_mode == MOVE_NO_EDITS)
398         {
399                 end_source = get_source_end(startsource + length + cut_length);
400                 if(end_source > 0 && startsource + length + cut_length > end_source)
401                         cut_length = end_source - startsource - length;
402                 
403                 startsource += cut_length;
404         }
405         return 0;
408 int Edit::shift_start_out(int edit_mode, 
409         int64_t newposition, 
410         int64_t oldposition,
411         int edit_edits,
412         int edit_labels,
413         int edit_plugins)
415         int64_t cut_length = oldposition - newposition;
417         if(asset)
418         {
419                 int64_t end_source = get_source_end(1);
421 //printf("Edit::shift_start_out 1 %lld %lld\n", startsource, cut_length);
422                 if(end_source > 0 && startsource < cut_length)
423                 {
424                         cut_length = startsource;
425                 }
426         }
428         if(edit_mode == MOVE_ALL_EDITS)
429         {
430 //printf("Edit::shift_start_out 10 %lld\n", cut_length);
431                 startsource -= cut_length;
432                 length += cut_length;
434                 edits->shift_keyframes_recursive(startproject, 
435                         cut_length);
436                 if(edit_plugins)
437                         edits->shift_effects_recursive(startproject, 
438                                 cut_length);
440                 for(Edit* current_edit = next; current_edit; current_edit = current_edit->next)
441                 {
442                         current_edit->startproject += cut_length;
443                 }
444         }
445         else
446         if(edit_mode == MOVE_ONE_EDIT)
447         {
448                 if(previous)
449                 {
450                         if(cut_length < previous->length)
451                         {   // Cut into previous edit
452                                 previous->length -= cut_length;
453                                 startproject -= cut_length;
454                                 startsource -= cut_length;
455                                 length += cut_length;
456 printf("Edit::shift_start_out 2\n");
457                         }
458                         else
459                         {   // Clear entire previous edit
460                                 cut_length = previous->length;
461                                 previous->length = 0;
462                                 length += cut_length;
463                                 startsource -= cut_length;
464                                 startproject -= cut_length;
465                         }
466                 }
467         }
468         else
469         if(edit_mode == MOVE_NO_EDITS)
470         {
471                 startsource -= cut_length;
472         }
474 // Fix infinite length files
475         if(startsource < 0) startsource = 0;
476         return 0;
479 int Edit::shift_end_in(int edit_mode, 
480         int64_t newposition, 
481         int64_t oldposition,
482         int edit_edits,
483         int edit_labels,
484         int edit_plugins)
486         int64_t cut_length = oldposition - newposition;
488         if(edit_mode == MOVE_ALL_EDITS)
489         {
490 //printf("Edit::shift_end_in 1\n");
491                 if(newposition > startproject)
492                 {        // clear partial edit
493 //printf("Edit::shift_end_in %p %p\n", track->edits, edits);
494                         edits->clear_recursive(newposition, 
495                                 oldposition,
496                                 edit_edits,
497                                 edit_labels,
498                                 edit_plugins);
499                 }
500                 else
501                 {        // clear entire edit
502                         edits->clear_recursive(startproject, 
503                                 oldposition,
504                                 edit_edits,
505                                 edit_labels,
506                                 edit_plugins);
507                 }
508         }
509         else
510         if(edit_mode == MOVE_ONE_EDIT)
511         {
512                 if(next)
513                 {
514                         if(next->asset)
515                         {
516                                 int64_t end_source = next->get_source_end(1);
518                                 if(end_source > 0 && next->startsource - cut_length < 0)
519                                 {
520                                         cut_length = next->startsource;
521                                 }
522                         }
524                         if(cut_length < length)
525                         {
526                                 length -= cut_length;
527                                 next->startproject -= cut_length;
528                                 next->startsource -= cut_length;
529                                 next->length += cut_length;
530 //printf("Edit::shift_end_in 2 %d\n", cut_length);
531                         }
532                         else
533                         {
534                                 cut_length = length;
535                                 next->length += cut_length;
536                                 next->startsource -= cut_length;
537                                 next->startproject -= cut_length;
538                                 length -= cut_length;
539                         }
540                 }
541                 else
542                 {
543                         if(cut_length < length)
544                         {
545                                 length -= cut_length;
546                         }
547                         else
548                         {
549                                 cut_length = length;
550                                 edits->clear_recursive(startproject, 
551                                         oldposition,
552                                         edit_edits,
553                                         edit_labels,
554                                         edit_plugins);
555                         }
556                 }
557         }
558         else
559 // Does nothing for plugins
560         if(edit_mode == MOVE_NO_EDITS)
561         {
562 //printf("Edit::shift_end_in 3\n");
563                 int64_t end_source = get_source_end(1);
564                 if(end_source > 0 && startsource < cut_length)
565                 {
566                         cut_length = startsource;
567                 }
568                 startsource -= cut_length;
569         }
570         return 0;
573 int Edit::shift_end_out(int edit_mode, 
574         int64_t newposition, 
575         int64_t oldposition,
576         int edit_edits,
577         int edit_labels,
578         int edit_plugins)
580         int64_t cut_length = newposition - oldposition;
581         int64_t endsource = get_source_end(startsource + length + cut_length);
583 // check end of edit against end of source file
584         if(endsource > 0 && startsource + length + cut_length > endsource)
585                 cut_length = endsource - startsource - length;
587 //printf("Edit::shift_end_out 1 %lld %d %d %d\n", oldposition, newposition, this->length, cut_length);
588         if(edit_mode == MOVE_ALL_EDITS)
589         {
590 // Extend length
591                 this->length += cut_length;
593 // Effects are shifted in length extension
594                 if(edit_plugins)
595                         edits->shift_effects_recursive(oldposition /* startproject */, 
596                                 cut_length);
597                 edits->shift_keyframes_recursive(oldposition /* startproject */, 
598                         cut_length);
600                 for(Edit* current_edit = next; current_edit; current_edit = current_edit->next)
601                 {
602                         current_edit->startproject += cut_length;
603                 }
604         }
605         else
606         if(edit_mode == MOVE_ONE_EDIT)
607         {
608                 if(next)
609                 {
610                         if(cut_length < next->length)
611                         {
612                                 length += cut_length;
613                                 next->startproject += cut_length;
614                                 next->startsource += cut_length;
615                                 next->length -= cut_length;
616 //printf("Edit::shift_end_out 2 %d\n", cut_length);
617                         }
618                         else
619                         {
620                                 cut_length = next->length;
621                                 next->length = 0;
622                                 length += cut_length;
623                         }
624                 }
625                 else
626                 {
627                         length += cut_length;
628                 }
629         }
630         else
631         if(edit_mode == MOVE_NO_EDITS)
632         {
633                 startsource += cut_length;
634         }
635         return 0;
666 int Edit::popup_transition(float view_start, float zoom_units, int cursor_x, int cursor_y)
668         int64_t left, right, left_unit, right_unit;
669         if(!transition) return 0;
670         get_handle_parameters(left, right, left_unit, right_unit, view_start, zoom_units);
672         if(cursor_x > left && cursor_x < right)
673         {
674 //              transition->popup_transition(cursor_x, cursor_y);
675                 return 1;
676         }
677         return 0;
680 int Edit::select_handle(float view_start, float zoom_units, int cursor_x, int cursor_y, int64_t &selection)
682         int64_t left, right, left_unit, right_unit;
683         get_handle_parameters(left, right, left_unit, right_unit, view_start, zoom_units);
685         int64_t pixel1, pixel2;
686         pixel1 = left;
687         pixel2 = pixel1 + 10;
689 // test left edit
690 // cursor_x is faked in acanvas
691         if(cursor_x >= pixel1 && cursor_x <= pixel2)
692         {
693                 selection = left_unit;
694                 return 1;     // left handle
695         }
697         int64_t endproject = startproject + length;
698         pixel2 = right;
699         pixel1 = pixel2 - 10;
701 // test right edit      
702         if(cursor_x >= pixel1 && cursor_x <= pixel2)
703         {
704                 selection = right_unit;
705                 return 2;     // right handle
706         }
707         return 0;