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