7d152bc5ef0e59c50155e2a2a34bedbb78dd0863
[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 Edit* Edits::split_edit(int64_t position)
238 {
239 // Get edit containing position
240         Edit *edit = editof(position, PLAY_FORWARD, 0);
241         if(!edit) return 0;
242 // Split would have created a 0 length
243 //      if(edit->startproject == position) return edit;
244 // Create anyway so the return value comes before position
245
246         Edit *new_edit = create_edit();
247         insert_after(edit, new_edit);
248         new_edit->copy_from(edit);
249         new_edit->length = new_edit->startproject + new_edit->length - position;
250         edit->length = position - edit->startproject;
251         new_edit->startproject = position;
252         new_edit->startsource += edit->length;
253
254 // Decide what to do with the transition
255         if(edit->length && edit->transition) {
256                 delete new_edit->transition;
257                 new_edit->transition = 0;
258         }
259
260         if(edit->transition && edit->transition->length > edit->length)
261                 edit->transition->length = edit->length;
262         if(new_edit->transition && new_edit->transition->length > new_edit->length)
263                 new_edit->transition->length = new_edit->length;
264         return new_edit;
265 }
266
267 int Edits::save(FileXML *xml, const char *output_path)
268 {
269         copy(0, length(), xml, output_path);
270         return 0;
271 }
272
273 void Edits::resample(double old_rate, double new_rate)
274 {
275         for(Edit *current = first; current; current = NEXT)
276         {
277                 current->startproject = Units::to_int64((double)current->startproject /
278                         old_rate *
279                         new_rate);
280                 if(PREVIOUS) PREVIOUS->length = current->startproject - PREVIOUS->startproject;
281                 current->startsource = Units::to_int64((double)current->startsource /
282                         old_rate *
283                         new_rate);
284                 if(!NEXT) current->length = Units::to_int64((double)current->length /
285                         old_rate *
286                         new_rate);
287                 if(current->transition)
288                 {
289                         current->transition->length = Units::to_int64(
290                                 (double)current->transition->length /
291                                 old_rate *
292                                 new_rate);
293                 }
294                 current->resample(old_rate, new_rate);
295         }
296 }
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311 int Edits::optimize()
312 {
313         int result = 1;
314         Edit *current;
315
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 // Insert silence between edits which aren't consecutive
336         for(current = last; current; current = current->previous)
337         {
338                 if(current->previous)
339                 {
340                         Edit *previous_edit = current->previous;
341                         if(current->startproject -
342                                 previous_edit->startproject -
343                                 previous_edit->length > 0)
344                         {
345                                 Edit *new_edit = create_edit();
346                                 insert_before(current, new_edit);
347                                 new_edit->startproject = previous_edit->startproject + previous_edit->length;
348                                 new_edit->length = current->startproject -
349                                         previous_edit->startproject -
350                                         previous_edit->length;
351                         }
352                 }
353                 else
354                 if(current->startproject > 0)
355                 {
356                         Edit *new_edit = create_edit();
357                         insert_before(current, new_edit);
358                         new_edit->length = current->startproject;
359                 }
360         }
361
362         result = 1;
363         while(result) {
364                 result = 0;
365
366 // delete 0 length edits
367                 for( current = first; !result && current; ) {
368                         Edit* next = current->next;
369                         if( current->length == 0 ) {
370                                 if( next && current->transition && !next->transition) {
371                                         next->transition = current->transition;
372                                         next->transition->edit = next;
373                                         current->transition = 0;
374                                 }
375                                 delete current;
376                                 result = 1;
377                                 break;
378                         }
379                         current = next;
380                 }
381
382 //printf("Edits::optimize %d result=%d\n", __LINE__, result);
383 // merge same files or transitions
384                 if(track->data_type == TRACK_SUBTITLE ) continue;
385
386                 for(current = first; !result && current && current->next; ) {
387                         Edit *next_edit = current->next;
388
389 // printf("Edits::optimize %d %lld=%lld %d=%d %p=%p %p=%p\n",
390 // __LINE__, current->startsource + current->length, next_edit->startsource,
391 // current->channel, next_edit->channel, current->asset, next_edit->asset,
392 // current->nested_edl, next_edit->nested_edl);
393
394 // both edits are silence & not a plugin
395 // source channels are identical, assets are identical
396                         if( (current->silence() && next_edit->silence() && !current->is_plugin) ||
397                             (current->startsource + current->length == next_edit->startsource &&
398                              current->channel == next_edit->channel &&
399                              current->asset == next_edit->asset &&
400                              current->nested_edl == next_edit->nested_edl)) {
401 //printf("Edits::optimize %d\n", __LINE__);
402                                 current->length += next_edit->length;
403                                 remove(next_edit);
404                                 result = 1;
405                                 break;
406                         }
407
408                         current = current->next;
409                 }
410
411                 if(last && last->silence()) {
412                         delete last;
413                         result = 1;
414                 }
415         }
416
417 //track->dump();
418         return 0;
419 }
420
421
422 // ===================================== file operations
423
424 void Edits::load(FileXML *file, int track_offset)
425 {
426         int64_t startproject = 0;
427
428         while( last ) delete last;
429
430         while( !file->read_tag() ) {
431 //printf("Edits::load 1 %s\n", file->tag.get_title());
432                 if(!strcmp(file->tag.get_title(), "EDIT")) {
433                         load_edit(file, startproject, track_offset);
434                 }
435                 else if(!strcmp(file->tag.get_title(), "/EDITS"))
436                         break;
437         }
438
439 //track->dump();
440         optimize();
441 }
442
443 int Edits::load_edit(FileXML *file, int64_t &startproject, int track_offset)
444 {
445         Edit* current = append_new_edit();
446         current->load_properties(file, startproject);
447
448         startproject += current->length;
449
450         while( !file->read_tag() ) {
451                 if(file->tag.title_is("NESTED_EDL")) {
452                         char path[BCTEXTLEN];
453                         path[0] = 0;
454                         file->tag.get_property("SRC", path);
455 //printf("Edits::load_edit %d path=%s\n", __LINE__, path);
456                         if(path[0] != 0) {
457                                 current->nested_edl = edl->nested_edls->get(path);
458                         }
459 // printf("Edits::load_edit %d nested_edl->path=%s\n",
460 // __LINE__,
461 // current->nested_edl->path);
462                 }
463                 else if(file->tag.title_is("FILE")) {
464                         char filename[BCTEXTLEN];
465                         filename[0] = 0;
466                         file->tag.get_property("SRC", filename);
467 // Extend path
468                         if(filename[0] != 0) {
469                                 char directory[BCTEXTLEN], edl_directory[BCTEXTLEN];
470                                 FileSystem fs;
471                                 fs.set_current_dir("");
472                                 fs.extract_dir(directory, filename);
473                                 if(!strlen(directory)) {
474                                         fs.extract_dir(edl_directory, file->filename);
475                                         fs.join_names(directory, edl_directory, filename);
476                                         strcpy(filename, directory);
477                                 }
478                                 current->asset = edl->assets->get_asset(filename);
479                         }
480                         else {
481                                 current->asset = 0;
482                         }
483 //printf("Edits::load_edit 5\n");
484                 }
485                 else if(file->tag.title_is("TRANSITION")) {
486                         current->transition = new Transition(edl, current, "",
487                                 track->to_units(edl->session->default_transition_length, 1));
488                                 current->transition->load_xml(file);
489                 }
490                 else if(file->tag.title_is("/EDIT"))
491                         break;
492         }
493
494 //printf("Edits::load_edit %d\n", __LINE__);
495 //track->dump();
496 //printf("Edits::load_edit %d\n", __LINE__);
497         return 0;
498 }
499
500 // ============================================= accounting
501
502 int64_t Edits::length()
503 {
504         return last ? last->startproject + last->length : 0;
505 }
506
507
508
509 Edit* Edits::editof(int64_t position, int direction, int use_nudge)
510 {
511         Edit *current = 0;
512         if(use_nudge && track) position += track->nudge;
513
514         if(direction == PLAY_FORWARD) {
515                 for(current = last; current; current = PREVIOUS) {
516                         if(current->startproject <= position && current->startproject + current->length > position)
517                                 return current;
518                 }
519         }
520         else
521         if(direction == PLAY_REVERSE) {
522                 for(current = first; current; current = NEXT) {
523                         if(current->startproject < position && current->startproject + current->length >= position)
524                                 return current;
525                 }
526         }
527
528         return 0;     // return 0 on failure
529 }
530
531 Edit* Edits::get_playable_edit(int64_t position, int use_nudge)
532 {
533         Edit *current;
534         if(track && use_nudge) position += track->nudge;
535
536 // Get the current edit
537         for(current = first; current; current = NEXT) {
538                 if(current->startproject <= position &&
539                         current->startproject + current->length > position)
540                         break;
541         }
542
543 // Get the edit's asset
544 // TODO: descend into nested EDLs
545         if(current) {
546                 if(!current->asset)
547                         current = 0;
548         }
549
550         return current;     // return 0 on failure
551 }
552
553 // ================================================ editing
554
555
556
557 int Edits::copy(int64_t start, int64_t end, FileXML *file, const char *output_path)
558 {
559         Edit *current_edit;
560
561         file->tag.set_title("EDITS");
562         file->append_tag();
563         file->append_newline();
564
565         for(current_edit = first; current_edit; current_edit = current_edit->next)
566         {
567                 current_edit->copy(start, end, file, output_path);
568         }
569
570         file->tag.set_title("/EDITS");
571         file->append_tag();
572         file->append_newline();
573         return 0;
574 }
575
576
577
578 void Edits::clear(int64_t start, int64_t end)
579 {
580         if( start >= end ) return;
581
582         Edit* edit1 = editof(start, PLAY_FORWARD, 0);
583         Edit* edit2 = editof(end, PLAY_FORWARD, 0);
584         Edit* current_edit;
585
586         if(end == start) return;        // nothing selected
587         if(!edit1 && !edit2) return;       // nothing selected
588
589
590         if(!edit2) {                // edit2 beyond end of track
591                 edit2 = last;
592                 end = this->length();
593         }
594
595         if(edit1 != edit2)
596         {
597 // in different edits
598
599 //printf("Edits::clear 3.5 %d %d %d %d\n", edit1->startproject, edit1->length, edit2->startproject, edit2->length);
600                 edit1->length = start - edit1->startproject;
601                 edit2->length -= end - edit2->startproject;
602                 edit2->startsource += end - edit2->startproject;
603                 edit2->startproject += end - edit2->startproject;
604
605 // delete
606                 for(current_edit = edit1->next; current_edit && current_edit != edit2;) {
607                         Edit* next = current_edit->next;
608                         remove(current_edit);
609                         current_edit = next;
610                 }
611 // shift
612                 for(current_edit = edit2; current_edit; current_edit = current_edit->next) {
613                         current_edit->startproject -= end - start;
614                 }
615         }
616         else {
617 // in same edit. paste_edit depends on this
618 // create a new edit
619                 current_edit = split_edit(start);
620                 if( current_edit ) {
621                         current_edit->length -= end - start;
622                         current_edit->startsource += end - start;
623 // shift
624                         while( (current_edit=current_edit->next) != 0 ) {
625                                 current_edit->startproject -= end - start;
626                         }
627                 }
628         }
629
630         optimize();
631 }
632
633 // Used by edit handle and plugin handle movement but plugin handle movement
634 // can only effect other plugins.
635 void Edits::clear_recursive(int64_t start, int64_t end,
636         int edit_edits, int edit_labels, int edit_plugins, int edit_autos,
637         Edits *trim_edits)
638 {
639 //printf("Edits::clear_recursive 1\n");
640         track->clear(start, end,
641                 edit_edits, edit_labels, edit_plugins, edit_autos, 0,
642                 trim_edits);
643 }
644
645
646 int Edits::clear_handle(double start, double end,
647         int edit_plugins, int edit_autos, double &distance)
648 {
649         Edit *current_edit;
650
651         distance = 0.0; // if nothing is found, distance is 0!
652         for(current_edit = first;
653                 current_edit && current_edit->next;
654                 current_edit = current_edit->next) {
655
656
657
658                 if(current_edit->asset && current_edit->next->asset) {
659
660                         if(current_edit->asset->equivalent(*current_edit->next->asset,
661                                 0, 0)) {
662
663 // Got two consecutive edits in same source
664                                 if(edl->equivalent(track->from_units(current_edit->next->startproject),
665                                         start)) {
666 // handle selected
667                                         int length = -current_edit->length;
668                                         current_edit->length = current_edit->next->startsource - current_edit->startsource;
669                                         length += current_edit->length;
670
671 // Lengthen automation
672                                         if(edit_autos)
673                                                 track->automation->paste_silence(current_edit->next->startproject,
674                                                         current_edit->next->startproject + length);
675
676 // Lengthen effects
677                                         if(edit_plugins)
678                                                 track->shift_effects(current_edit->next->startproject,
679                                                         length,
680                                                         edit_autos);
681
682                                         for(current_edit = current_edit->next; current_edit; current_edit = current_edit->next)
683                                         {
684                                                 current_edit->startproject += length;
685                                         }
686
687                                         distance = track->from_units(length);
688                                         optimize();
689                                         break;
690                                 }
691                         }
692                 }
693         }
694
695         return 0;
696 }
697
698 int Edits::modify_handles(double oldposition, double newposition, int currentend,
699         int edit_mode, int edit_edits, int edit_labels, int edit_plugins, int edit_autos,
700         Edits *trim_edits)
701 {
702         int result = 0;
703         Edit *current_edit;
704
705 //printf("Edits::modify_handles 1 %d %f %f\n", currentend, newposition, oldposition);
706         if(currentend == 0) {
707 // left handle
708                 for(current_edit = first; current_edit && !result;) {
709                         if(edl->equivalent(track->from_units(current_edit->startproject),
710                                 oldposition)) {
711 // edit matches selection
712 //printf("Edits::modify_handles 3 %f %f\n", newposition, oldposition);
713                                 oldposition = track->from_units(current_edit->startproject);
714                                 result = 1;
715
716                                 if(newposition >= oldposition) {
717 //printf("Edits::modify_handle 1 %s %f %f\n", track->title, oldposition, newposition);
718 // shift start of edit in
719                                         current_edit->shift_start_in(edit_mode,
720                                                 track->to_units(newposition, 0),
721                                                 track->to_units(oldposition, 0),
722                                                 edit_edits,
723                                                 edit_labels,
724                                                 edit_plugins,
725                                                 edit_autos,
726                                                 trim_edits);
727                                 }
728                                 else
729                                 {
730 //printf("Edits::modify_handle 2 %s\n", track->title);
731 // move start of edit out
732                                         current_edit->shift_start_out(edit_mode,
733                                                 track->to_units(newposition, 0),
734                                                 track->to_units(oldposition, 0),
735                                                 edit_edits,
736                                                 edit_labels,
737                                                 edit_plugins,
738                                                 edit_autos,
739                                                 trim_edits);
740                                 }
741                         }
742
743                         if(!result) current_edit = current_edit->next;
744                 }
745         }
746         else {
747 // right handle selected
748                 for(current_edit = first; current_edit && !result;) {
749                         if(edl->equivalent(track->from_units(current_edit->startproject) +
750                                 track->from_units(current_edit->length), oldposition)) {
751                 oldposition = track->from_units(current_edit->startproject) +
752                                         track->from_units(current_edit->length);
753                                 result = 1;
754
755 //printf("Edits::modify_handle 3\n");
756                                 if(newposition <= oldposition) {
757 // shift end of edit in
758 //printf("Edits::modify_handle 4\n");
759                                         current_edit->shift_end_in(edit_mode,
760                                                 track->to_units(newposition, 0),
761                                                 track->to_units(oldposition, 0),
762                                                 edit_edits,
763                                                 edit_labels,
764                                                 edit_plugins,
765                                                 edit_autos,
766                                                 trim_edits);
767 //printf("Edits::modify_handle 5\n");
768                                 }
769                                 else
770                                 {
771 // move end of edit out
772 //printf("Edits::modify_handle 6\n");
773                                         current_edit->shift_end_out(edit_mode,
774                                                 track->to_units(newposition, 0),
775                                                 track->to_units(oldposition, 0),
776                                                 edit_edits,
777                                                 edit_labels,
778                                                 edit_plugins,
779                                                 edit_autos,
780                                                 trim_edits);
781 //printf("Edits::modify_handle 7\n");
782                                 }
783                         }
784
785                         if(!result) current_edit = current_edit->next;
786 //printf("Edits::modify_handle 8\n");
787                 }
788         }
789
790         optimize();
791         return 0;
792 }
793
794
795 void Edits::paste_silence(int64_t start, int64_t end)
796 {
797         Edit *new_edit = editof(start, PLAY_FORWARD, 0);
798         if (!new_edit) return;
799
800         if( !new_edit->silence() ) {
801                 new_edit = insert_new_edit(start);
802                 new_edit->length = end - start;
803         }
804         else
805                 new_edit->length += end - start;
806
807         for(Edit *current = new_edit->next; current; current = NEXT) {
808                 current->startproject += end - start;
809         }
810
811         return;
812 }
813
814 Edit *Edits::create_silence(int64_t start, int64_t end)
815 {
816         Edit *new_edit = insert_new_edit(start);
817         new_edit->length = end - start;
818         for(Edit *current = new_edit->next; current; current = NEXT) {
819                 current->startproject += end - start;
820         }
821         return new_edit;
822 }
823                                      
824 Edit* Edits::shift(int64_t position, int64_t difference)
825 {
826         Edit *new_edit = split_edit(position);
827
828         for(Edit *current = first; current; current = NEXT) {
829                 if(current->startproject >= position) {
830                         current->shift(difference);
831                 }
832         }
833         return new_edit;
834 }
835
836
837 void Edits::shift_keyframes_recursive(int64_t position, int64_t length)
838 {
839         track->shift_keyframes(position, length);
840 }
841
842 void Edits::shift_effects_recursive(int64_t position, int64_t length, int edit_autos)
843 {
844         track->shift_effects(position, length, edit_autos);
845 }
846