ea67b6cb976fa8783d458dc262e0945508e842ca
[goodguy/cinelerra.git] / cinelerra-5.1 / cinelerra / edits.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008-2017 Adam Williams <broadcast at earthling dot net>
5  *
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.
10  *
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.
15  *
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
19  *
20  */
21
22 #include "aedit.h"
23 #include "asset.h"
24 #include "assets.h"
25 #include "automation.h"
26 #include "bcsignals.h"
27 #include "cache.h"
28 #include "clip.h"
29 #include "clipedls.h"
30 #include "edit.h"
31 #include "edits.h"
32 #include "edl.h"
33 #include "edlsession.h"
34 #include "file.h"
35 #include "filexml.h"
36 #include "filesystem.h"
37 #include "localsession.h"
38 #include "plugin.h"
39 #include "strategies.inc"
40 #include "track.h"
41 #include "transition.h"
42 #include "transportque.inc"
43
44 #include <string.h>
45
46 Edits::Edits(EDL *edl, Track *track)
47  : List<Edit>()
48 {
49         this->edl = edl;
50         this->track = track;
51 }
52
53 Edits::~Edits()
54 {
55 }
56
57
58 void Edits::equivalent_output(Edits *edits, int64_t *result)
59 {
60 // For the case of plugin sets, a new plugin set may be created with
61 // plugins only starting after 0.  We only want to restart brender at
62 // the first plugin in this case.
63         for(Edit *current = first, *that_current = edits->first;
64                 current || that_current;
65                 current = NEXT,
66                 that_current = that_current->next)
67         {
68 //printf("Edits::equivalent_output 1 %d\n", *result);
69                 if(!current && that_current)
70                 {
71                         int64_t position1 = length();
72                         int64_t position2 = that_current->startproject;
73                         if(*result < 0 || *result > MIN(position1, position2))
74                                 *result = MIN(position1, position2);
75                         break;
76                 }
77                 else
78                 if(current && !that_current)
79                 {
80                         int64_t position1 = edits->length();
81                         int64_t position2 = current->startproject;
82                         if(*result < 0 || *result > MIN(position1, position2))
83                                 *result = MIN(position1, position2);
84                         break;
85                 }
86                 else
87                 {
88 //printf("Edits::equivalent_output 2 %d\n", *result);
89                         current->equivalent_output(that_current, result);
90 //printf("Edits::equivalent_output 3 %d\n", *result);
91                 }
92         }
93 }
94
95 void Edits::copy_from(Edits *edits)
96 {
97         while(last) delete last;
98         for(Edit *current = edits->first; current; current = NEXT)
99         {
100                 Edit *new_edit = append(create_edit());
101                 new_edit->copy_from(current);
102         }
103 }
104
105 void Edits::insert_asset(Asset *asset, EDL *nested_edl,
106         int64_t length, int64_t position, int track_number)
107 {
108         Edit *new_edit = insert_new_edit(position);
109
110         new_edit->nested_edl = nested_edl;
111         new_edit->asset = asset;
112         new_edit->startsource = 0;
113         new_edit->startproject = position;
114         new_edit->length = length;
115
116         if(nested_edl)
117         {
118                 if(track->data_type == TRACK_AUDIO)
119                         new_edit->channel = track_number % nested_edl->session->audio_channels;
120                 else
121                         new_edit->channel = 0;
122         }
123
124         if(asset && !nested_edl)
125         {
126                 if(asset->audio_data)
127                         new_edit->channel = track_number % asset->channels;
128                 else
129                 if(asset->video_data)
130                         new_edit->channel = track_number % asset->layers;
131         }
132
133 //printf("Edits::insert_asset %d %d\n", new_edit->channel, new_edit->length);
134         for(Edit *current = new_edit->next; current; current = NEXT)
135         {
136                 current->startproject += length;
137         }
138 }
139
140 void Edits::insert_edits(Edits *source_edits,
141         int64_t position,
142         int64_t min_length,
143         int edit_autos)
144 {
145         //int64_t clipboard_end = position + min_length;
146 // Length pasted so far
147         int64_t source_len = 0;
148
149 // Fill region between end of edit table and beginning of pasted segment
150 // with silence.  Can't call from insert_new_edit because it's recursive.
151         if(position > length())
152         {
153                 paste_silence(length(), position);
154         }
155
156
157         for(Edit *source_edit = source_edits->first;
158                 source_edit;
159                 source_edit = source_edit->next)
160         {
161                 EDL *dest_nested_edl = 0;
162                 if(source_edit->nested_edl)
163                         dest_nested_edl = edl->nested_edls.get_nested(source_edit->nested_edl);
164
165 // Update Assets
166                 Asset *dest_asset = 0;
167                 if(source_edit->asset)
168                         dest_asset = edl->assets->update(source_edit->asset);
169 // Open destination area
170                 Edit *dest_edit = insert_new_edit(position + source_edit->startproject);
171
172                 dest_edit->clone_from(source_edit);
173                 dest_edit->asset = dest_asset;
174                 dest_edit->nested_edl = dest_nested_edl;
175                 dest_edit->startproject = position + source_edit->startproject;
176
177
178
179 // Shift keyframes in source edit to their position in the
180 // destination edit for plugin case
181                 if(edit_autos) dest_edit->shift_keyframes(position);
182
183 // Shift following edits and keyframes in following edits by length
184 // in current source edit.
185                 for(Edit *future_edit = dest_edit->next;
186                         future_edit;
187                         future_edit = future_edit->next)
188                 {
189                         future_edit->startproject += dest_edit->length;
190                         future_edit->shift_keyframes(dest_edit->length);
191                 }
192
193                 source_len += source_edit->length;
194         }
195
196
197
198
199 // Fill remaining clipboard length with silence
200         if(source_len < min_length)
201         {
202 //printf("Edits::insert_edits %d\n", __LINE__);
203                 paste_silence(position + source_len, position + min_length);
204         }
205 }
206
207
208 // Native units
209 // Can't paste silence in here because it's used by paste_silence.
210 Edit* Edits::insert_new_edit(int64_t position)
211 {
212 //printf("Edits::insert_new_edit 1\n");
213         Edit *current = split_edit(position);
214
215 //printf("Edits::insert_new_edit 1\n");
216         Edit *new_edit = create_edit();
217         if( current ) current = PREVIOUS;
218 //printf("Edits::insert_new_edit 1\n");
219         insert_after(current, new_edit);
220         new_edit->startproject = position;
221 //printf("Edits::insert_new_edit 2\n");
222         return new_edit;
223 }
224
225 Edit* Edits::split_edit(int64_t position)
226 {
227 // Get edit containing position
228         Edit *edit = editof(position, PLAY_FORWARD, 0);
229         if(!edit) return 0;
230 // Split would have created a 0 length
231 //      if(edit->startproject == position) return edit;
232 // Create anyway so the return value comes before position
233
234         Edit *new_edit = create_edit();
235         insert_after(edit, new_edit);
236         new_edit->clone_from(edit);
237         new_edit->length = new_edit->startproject + new_edit->length - position;
238         edit->length = position - edit->startproject;
239         if( !new_edit->length || edit->silence() )
240                 new_edit->hard_left = new_edit->hard_right = 0;
241         else if( !edit->length )
242                 edit->hard_left = edit->hard_right = 0;
243         else {
244                 new_edit->hard_right = edit->hard_right;
245                 new_edit->hard_left = edit->hard_right = 0;
246         }
247         new_edit->startproject = position;
248         new_edit->startsource += edit->length;
249
250 // Decide what to do with the transition
251         if(edit->length && edit->transition) {
252                 delete new_edit->transition;
253                 new_edit->transition = 0;
254         }
255
256         if(edit->transition && edit->transition->length > edit->length)
257                 edit->transition->length = edit->length;
258         if(new_edit->transition && new_edit->transition->length > new_edit->length)
259                 new_edit->transition->length = new_edit->length;
260         return new_edit;
261 }
262
263 int Edits::save(FileXML *xml, const char *output_path)
264 {
265         copy(0, length(), xml, output_path);
266         return 0;
267 }
268
269 void Edits::resample(double old_rate, double new_rate)
270 {
271         for(Edit *current = first; current; current = NEXT)
272         {
273                 current->startproject = Units::to_int64((double)current->startproject /
274                         old_rate *
275                         new_rate);
276                 if(PREVIOUS) PREVIOUS->length = current->startproject - PREVIOUS->startproject;
277                 current->startsource = Units::to_int64((double)current->startsource /
278                         old_rate *
279                         new_rate);
280                 if(!NEXT) current->length = Units::to_int64((double)current->length /
281                         old_rate *
282                         new_rate);
283                 if(current->transition)
284                 {
285                         current->transition->length = Units::to_int64(
286                                 (double)current->transition->length /
287                                 old_rate *
288                                 new_rate);
289                 }
290                 current->resample(old_rate, new_rate);
291         }
292 }
293
294 int Edits::is_glitch(Edit *edit)
295 {
296         if( track->data_type != TRACK_AUDIO ) return 0;
297         int64_t threshold = edl->session->frame_rate > 0 ?
298                 0.5 * edl->session->sample_rate / edl->session->frame_rate : 0;
299 // audio edit shorter than .5 frames is a glitch
300         return edit->length < threshold ? 1 : 0;
301 }
302
303 int Edits::optimize()
304 {
305         int result = 1;
306         Edit *current;
307
308 //printf("Edits::optimize %d\n", __LINE__);
309 // Sort edits by starting point
310         while(result)
311         {
312                 result = 0;
313
314                 for(current = first; current; current = NEXT)
315                 {
316                         Edit *next_edit = NEXT;
317
318                         if(next_edit && next_edit->startproject < current->startproject)
319                         {
320                                 swap(next_edit, current);
321                                 result = 1;
322                         }
323                 }
324         }
325
326 // trim edits before position 0
327         while( first && first->startproject+first->length < 0 )
328                 delete first;
329         if( first && first->startproject < 0 ) {
330                 first->length += first->startproject;
331                 first->startproject = 0;
332         }
333
334 // Insert silence between edits which aren't consecutive
335         for(current = last; current; current = current->previous)
336         {
337                 if(current->previous)
338                 {
339                         Edit *previous_edit = current->previous;
340                         if(current->startproject -
341                                 previous_edit->startproject -
342                                 previous_edit->length > 0)
343                         {
344                                 Edit *new_edit = create_edit();
345                                 insert_before(current, new_edit);
346                                 new_edit->startproject = previous_edit->startproject + previous_edit->length;
347                                 new_edit->length = current->startproject -
348                                         previous_edit->startproject -
349                                         previous_edit->length;
350                         }
351                 }
352                 else
353                 if(current->startproject > 0)
354                 {
355                         Edit *new_edit = create_edit();
356                         insert_before(current, new_edit);
357                         new_edit->length = current->startproject;
358                 }
359         }
360
361         result = 1;
362         while(result) {
363                 result = 0;
364
365 // delete 0 length edits
366                 for( current = first; !result && current; ) {
367                         Edit* prev = current->previous, *next = current->next;
368                         if( current->length == 0 ) {
369                                 if( next && current->transition && !next->transition) {
370                                         next->transition = current->transition;
371                                         next->transition->edit = next;
372                                         current->transition = 0;
373                                 }
374                                 if( !current->silence() ) {
375                                         if( current->hard_left && next && !next->silence() )
376                                                 next->hard_left = 1;
377                                         if( current->hard_right && prev && !prev->silence())
378                                                 prev->hard_right = 1;
379                                 }
380                                 delete current;
381                                 result = 1;
382                                 break;
383                         }
384                         current = next;
385                 }
386
387 // merge same files or transitions, and deglitch
388                 if( !result && track->data_type != TRACK_SUBTITLE ) {
389                         current = first;
390                         if( current && !current->hard_right &&
391                             current->next && !current->next->hard_left &&
392                             is_glitch(current) ) {
393 // if the first edit is a glitch, change it to silence
394                                 current->asset = 0;
395                                 current->nested_edl = 0;
396                         }
397                         Edit *next_edit = 0;
398                         for( ; current && (next_edit=current->next); current=NEXT ) {
399 // both edges are not hard edges
400                                 if( current->hard_right || next_edit->hard_left )
401                                         continue;
402 // next edit is a glitch
403                                 if( is_glitch(next_edit) )
404                                         break;
405 // both edits are silence & not a plugin
406                                 if( !current->is_plugin && current->silence() &&
407                                     !next_edit->is_plugin && next_edit->silence() )
408                                         break;
409 // source channels are identical & assets are identical
410                                 if( !result && current->channel == next_edit->channel &&
411                                     current->asset == next_edit->asset &&
412                                     current->nested_edl == next_edit->nested_edl ) {
413 //  and stop and start in the same frame
414                                         int64_t current_end = current->startsource + current->length;
415                                         int64_t next_start = next_edit->startsource;
416                                         if( current_end == next_start ||
417                                             EQUIV(edl->frame_align(track->from_units(current_end), 1),
418                                                   edl->frame_align(track->from_units(next_start), 1)) )
419                                                 break;
420                                 }
421                         }
422                         if( next_edit ) {
423                                 int64_t current_start = current->startproject;
424                                 int64_t next_end = next_edit->startproject + next_edit->length;
425                                 current->length = next_end - current_start;
426                                 current->hard_right = next_edit->hard_right;
427                                 remove(next_edit);
428                                 result = 1;
429                         }
430                 }
431
432                 if( last && last->silence() &&
433                     !last->transition && !last->hard_left && !last->hard_right ) {
434                         delete last;
435                         result = 1;
436                 }
437         }
438
439         return 0;
440 }
441
442
443 // ===================================== file operations
444
445 void Edits::load(FileXML *file, int track_offset)
446 {
447         int64_t startproject = 0;
448
449         while( last ) delete last;
450
451         while( !file->read_tag() ) {
452 //printf("Edits::load 1 %s\n", file->tag.get_title());
453                 if(!strcmp(file->tag.get_title(), "EDIT")) {
454                         load_edit(file, startproject, track_offset);
455                 }
456                 else if(!strcmp(file->tag.get_title(), "/EDITS"))
457                         break;
458         }
459
460 //track->dump();
461         optimize();
462 }
463
464 int Edits::load_edit(FileXML *file, int64_t &startproject, int track_offset)
465 {
466         Edit* current = append_new_edit();
467         current->load_properties(file, startproject);
468
469         startproject += current->length;
470
471         while( !file->read_tag() ) {
472                 if(file->tag.title_is("NESTED_EDL")) {
473                         char path[BCTEXTLEN];
474                         path[0] = 0;
475                         file->tag.get_property("SRC", path);
476 //printf("Edits::load_edit %d path=%s\n", __LINE__, path);
477                         if(path[0] != 0) {
478                                 current->nested_edl = edl->nested_edls.load(path);
479                         }
480 // printf("Edits::load_edit %d nested_edl->path=%s\n",
481 // __LINE__, current->nested_edl->path);
482                 }
483                 else if(file->tag.title_is("FILE")) {
484                         char filename[BCTEXTLEN];
485                         filename[0] = 0;
486                         file->tag.get_property("SRC", filename);
487 // Extend path
488                         if(filename[0] != 0) {
489                                 char directory[BCTEXTLEN], edl_directory[BCTEXTLEN];
490                                 FileSystem fs;
491                                 fs.set_current_dir("");
492                                 fs.extract_dir(directory, filename);
493                                 if(!strlen(directory)) {
494                                         fs.extract_dir(edl_directory, file->filename);
495                                         fs.join_names(directory, edl_directory, filename);
496                                         strcpy(filename, directory);
497                                 }
498                                 current->asset = edl->assets->get_asset(filename);
499                         }
500                         else {
501                                 current->asset = 0;
502                         }
503 //printf("Edits::load_edit 5\n");
504                 }
505                 else if(file->tag.title_is("TRANSITION")) {
506                         current->transition = new Transition(edl, current, "",
507                                 track->to_units(edl->session->default_transition_length, 1));
508                                 current->transition->load_xml(file);
509                 }
510                 else if(file->tag.title_is("/EDIT"))
511                         break;
512         }
513
514 //printf("Edits::load_edit %d\n", __LINE__);
515 //track->dump();
516 //printf("Edits::load_edit %d\n", __LINE__);
517         return 0;
518 }
519
520 // ============================================= accounting
521
522 int64_t Edits::length()
523 {
524         return last ? last->startproject + last->length : 0;
525 }
526
527
528
529 Edit* Edits::editof(int64_t position, int direction, int use_nudge)
530 {
531         Edit *current = 0;
532         if(use_nudge && track) position += track->nudge;
533
534         if(direction == PLAY_FORWARD) {
535                 for(current = last; current; current = PREVIOUS) {
536                         if(current->startproject <= position && current->startproject + current->length > position)
537                                 return current;
538                 }
539         }
540         else
541         if(direction == PLAY_REVERSE) {
542                 for(current = first; current; current = NEXT) {
543                         if(current->startproject < position && current->startproject + current->length >= position)
544                                 return current;
545                 }
546         }
547
548         return 0;     // return 0 on failure
549 }
550
551 Edit* Edits::get_playable_edit(int64_t position, int use_nudge)
552 {
553         Edit *current;
554         if(track && use_nudge) position += track->nudge;
555
556 // Get the current edit
557         for(current = first; current; current = NEXT) {
558                 if(current->startproject <= position &&
559                         current->startproject + current->length > position)
560                         break;
561         }
562
563 // Get the edit's asset
564 // TODO: descend into nested EDLs
565         if(current) {
566                 if(!current->asset)
567                         current = 0;
568         }
569
570         return current;     // return 0 on failure
571 }
572
573 // ================================================ editing
574
575
576
577 int Edits::copy(int64_t start, int64_t end, FileXML *file, const char *output_path)
578 {
579         Edit *current_edit;
580
581         file->tag.set_title("EDITS");
582         file->append_tag();
583         file->append_newline();
584
585         for(current_edit = first; current_edit; current_edit = current_edit->next)
586         {
587                 current_edit->copy(start, end, file, output_path);
588         }
589
590         file->tag.set_title("/EDITS");
591         file->append_tag();
592         file->append_newline();
593         return 0;
594 }
595
596
597
598 void Edits::clear(int64_t start, int64_t end)
599 {
600         if( start >= end ) return;
601
602         Edit* edit1 = editof(start, PLAY_FORWARD, 0);
603         Edit* edit2 = editof(end, PLAY_FORWARD, 0);
604         Edit* current_edit;
605
606         if(end == start) return;        // nothing selected
607         if(!edit1 && !edit2) return;       // nothing selected
608
609
610         if(!edit2) {                // edit2 beyond end of track
611                 edit2 = last;
612                 end = this->length();
613         }
614
615         if( edit1 && edit2 && edit1 != edit2)
616         {
617 // in different edits
618
619 //printf("Edits::clear 3.5 %d %d %d %d\n", edit1->startproject, edit1->length, edit2->startproject, edit2->length);
620                 edit1->length = start - edit1->startproject;
621                 edit2->length -= end - edit2->startproject;
622                 edit2->startsource += end - edit2->startproject;
623                 edit2->startproject += end - edit2->startproject;
624
625 // delete
626                 for(current_edit = edit1->next; current_edit && current_edit != edit2;) {
627                         Edit* next = current_edit->next;
628                         remove(current_edit);
629                         current_edit = next;
630                 }
631 // shift
632                 for(current_edit = edit2; current_edit; current_edit = current_edit->next) {
633                         current_edit->startproject -= end - start;
634                 }
635         }
636         else {
637 // in same edit. paste_edit depends on this
638 // create a new edit
639                 current_edit = split_edit(start);
640                 if( current_edit ) {
641                         current_edit->length -= end - start;
642                         current_edit->startsource += end - start;
643 // shift
644                         while( (current_edit=current_edit->next) != 0 ) {
645                                 current_edit->startproject -= end - start;
646                         }
647                 }
648         }
649
650         optimize();
651 }
652
653 // Used by edit handle and plugin handle movement but plugin handle movement
654 // can only effect other plugins.
655 void Edits::clear_recursive(int64_t start, int64_t end,
656         int edit_edits, int edit_labels, int edit_plugins, int edit_autos,
657         Edits *trim_edits)
658 {
659 //printf("Edits::clear_recursive 1\n");
660         track->clear(start, end,
661                 edit_edits, edit_labels, edit_plugins, edit_autos, trim_edits);
662 }
663
664
665 int Edits::clear_handle(double start, double end,
666         int edit_plugins, int edit_autos, double &distance)
667 {
668         Edit *current_edit;
669
670         distance = 0.0; // if nothing is found, distance is 0!
671         for(current_edit = first;
672                 current_edit && current_edit->next;
673                 current_edit = current_edit->next) {
674
675
676
677                 if(current_edit->asset && current_edit->next->asset) {
678
679                         if(current_edit->asset->equivalent(*current_edit->next->asset, 0, 0, edl)) {
680
681 // Got two consecutive edits in same source
682                                 if(edl->equivalent(track->from_units(current_edit->next->startproject),
683                                         start)) {
684 // handle selected
685                                         int length = -current_edit->length;
686                                         current_edit->length = current_edit->next->startsource - current_edit->startsource;
687                                         length += current_edit->length;
688
689 // Lengthen automation
690                                         if(edit_autos)
691                                                 track->automation->paste_silence(current_edit->next->startproject,
692                                                         current_edit->next->startproject + length);
693
694 // Lengthen effects
695                                         if(edit_plugins)
696                                                 track->shift_effects(current_edit->next->startproject,
697                                                                 length, edit_autos, 0);
698
699                                         for(current_edit = current_edit->next; current_edit; current_edit = current_edit->next)
700                                         {
701                                                 current_edit->startproject += length;
702                                         }
703
704                                         distance = track->from_units(length);
705                                         optimize();
706                                         break;
707                                 }
708                         }
709                 }
710         }
711
712         return 0;
713 }
714
715 int Edits::modify_handles(double oldposition, double newposition, int currentend,
716         int edit_mode, int edit_edits, int edit_labels, int edit_plugins, int edit_autos,
717         Edits *trim_edits, int group_id)
718 {
719         int result = 0;
720         Edit *current_edit;
721         Edit *left = 0, *right = 0;
722         if( group_id > 0 ) {
723                 double start = DBL_MAX, end = DBL_MIN;
724                 for( Edit *edit=first; edit; edit=edit->next ) {
725                         if( edit->group_id != group_id ) continue;
726                         double edit_start = edit->track->from_units(edit->startproject);
727                         if( edit_start < start ) { start = edit_start;  left = edit; }
728                         double edit_end = edit->track->from_units(edit->startproject+edit->length);
729                         if( edit_end > end ) { end = edit_end;  right = edit; }
730                 }
731         }
732
733 //printf("Edits::modify_handles 1 %d %f %f\n", currentend, newposition, oldposition);
734         if(currentend == 0) {
735 // left handle
736                 for(current_edit = first; current_edit && !result;) {
737                         if( group_id > 0 ? current_edit == left :
738                             edl->equivalent(track->from_units(current_edit->startproject),
739                                 oldposition) ) {
740 // edit matches selection
741 //printf("Edits::modify_handles 3 %f %f\n", newposition, oldposition);
742                                 double delta = newposition - oldposition;
743                                 oldposition = track->from_units(current_edit->startproject);
744                                 if( group_id > 0 ) newposition = oldposition + delta;
745                                 current_edit->shift_start(edit_mode,
746                                         track->to_units(newposition, 0), track->to_units(oldposition, 0),
747                                         edit_labels, edit_autos, edit_plugins, trim_edits);
748                                 result = 1;
749                         }
750
751                         if(!result) current_edit = current_edit->next;
752                 }
753         }
754         else {
755 // right handle selected
756                 for(current_edit = first; current_edit && !result;) {
757                         if( group_id > 0 ? current_edit == right :
758                             edl->equivalent(track->from_units(current_edit->startproject) +
759                                         track->from_units(current_edit->length), oldposition) ) {
760                                 double delta = newposition - oldposition;
761                                 oldposition = track->from_units(current_edit->startproject) +
762                                         track->from_units(current_edit->length);
763                                 if( group_id > 0 ) newposition = oldposition + delta;
764                                 result = 1;
765
766                                 current_edit->shift_end(edit_mode,
767                                         track->to_units(newposition, 0), track->to_units(oldposition, 0),
768                                         edit_labels, edit_autos, edit_plugins, trim_edits);
769                         }
770
771                         if(!result) current_edit = current_edit->next;
772 //printf("Edits::modify_handle 8\n");
773                 }
774         }
775
776         optimize();
777         return 0;
778 }
779
780 void Edits::paste_silence(int64_t start, int64_t end)
781 {
782         Edit *new_edit = editof(start, PLAY_FORWARD, 0);
783         if (!new_edit) return;
784
785         if( !new_edit->silence() || new_edit->hard_right ) {
786                 new_edit = insert_new_edit(start);
787                 new_edit->length = end - start;
788         }
789         else
790                 new_edit->length += end - start;
791
792         for(Edit *current = new_edit->next; current; current = NEXT) {
793                 current->startproject += end - start;
794         }
795
796         return;
797 }
798
799 Edit *Edits::create_silence(int64_t start, int64_t end)
800 {
801         Edit *new_edit = insert_new_edit(start);
802         new_edit->length = end - start;
803         for(Edit *current = new_edit->next; current; current = NEXT) {
804                 current->startproject += end - start;
805         }
806         return new_edit;
807 }
808
809 Edit* Edits::shift(int64_t position, int64_t difference)
810 {
811         Edit *new_edit = split_edit(position);
812
813         for(Edit *current = first; current; current = NEXT) {
814                 if(current->startproject >= position) {
815                         current->shift(difference);
816                 }
817         }
818         return new_edit;
819 }
820
821
822 void Edits::shift_keyframes_recursive(int64_t position, int64_t length)
823 {
824         track->shift_keyframes(position, length);
825 }
826
827 void Edits::shift_effects_recursive(int64_t position, int64_t length, int edit_autos)
828 {
829         track->shift_effects(position, length, edit_autos, 0);
830 }
831