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