remove whitespace at eol
[goodguy/history.git] / cinelerra-5.1 / cinelerra / tracksedit.C
1 /*
2  * CINELERRA
3  * Copyright (C) 2010 Adam Williams <broadcast at earthling dot net>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  *
19  */
20
21 #include "assets.h"
22 #include "atrack.h"
23 #include "automation.h"
24 #include "aedits.h"
25 #include "bcsignals.h"
26 #include "edit.h"
27 #include "edits.h"
28 #include "edl.h"
29 #include "edlsession.h"
30 #include "filexml.h"
31 #include "intauto.h"
32 #include "intautos.h"
33 #include "labels.h"
34 #include "localsession.h"
35 #include "mainundo.h"
36 #include "module.h"
37 #include "mainsession.h"
38 #include "pluginserver.h"
39 #include "pluginset.h"
40 #include "plugin.h"
41 #include "timebar.h"
42 #include "trackcanvas.h"
43 #include "tracks.h"
44 #include "trackscroll.h"
45 #include "transition.h"
46 #include "transportque.h"
47 #include "vtrack.h"
48 #include <string.h>
49
50 int Tracks::clear(double start, double end, int clear_plugins, int edit_autos)
51 {
52         Track *current_track;
53
54         for(current_track = first;
55                 current_track;
56                 current_track = current_track->next)
57         {
58                 if(current_track->record)
59                 {
60                         current_track->clear(start,
61                                 end,
62                                 1, // edits
63                                 1, // labels
64                                 clear_plugins,
65                                 edit_autos,
66                                 1,
67                                 0);
68                 }
69         }
70         return 0;
71 }
72
73 void Tracks::clear_automation(double selectionstart, double selectionend)
74 {
75         Track* current_track;
76
77         for(current_track = first; current_track; current_track = current_track->next)
78         {
79                 if(current_track->record)
80                 {
81                         current_track->clear_automation(selectionstart,
82                                 selectionend,
83                                 0,
84                                 0);
85                 }
86         }
87 }
88
89 void Tracks::clear_transitions(double start, double end)
90 {
91         for(Track *current_track = first;
92                 current_track;
93                 current_track = current_track->next)
94         {
95                 if(current_track->record)
96                 {
97                         int64_t start_units = current_track->to_units(start, 0);
98                         int64_t end_units = current_track->to_units(end, 0);
99
100                         for(Edit *current_edit = current_track->edits->first;
101                                 current_edit;
102                                 current_edit = current_edit->next)
103                         {
104                                 if(current_edit->startproject >= start_units &&
105                                         current_edit->startproject < end_units &&
106                                         current_edit->transition)
107                                 {
108                                         current_edit->detach_transition();
109                                 }
110                         }
111                 }
112         }
113 }
114
115 void Tracks::shuffle_edits(double start, double end)
116 {
117 // This doesn't affect automation or effects
118 // Labels follow the first track.
119         int first_track = 1;
120         for(Track *current_track = first;
121                 current_track;
122                 current_track = current_track->next)
123         {
124                 if(current_track->record)
125                 {
126                         current_track->shuffle_edits(start, end, first_track);
127
128                         first_track = 0;
129                 }
130         }
131 }
132
133 void Tracks::reverse_edits(double start, double end)
134 {
135 // This doesn't affect automation or effects
136 // Labels follow the first track.
137         int first_track = 1;
138         for(Track *current_track = first;
139                 current_track;
140                 current_track = current_track->next)
141         {
142                 if(current_track->record)
143                 {
144                         current_track->reverse_edits(start, end, first_track);
145
146                         first_track = 0;
147                 }
148         }
149 }
150 void Tracks::align_edits(double start, double end)
151 {
152 // This doesn't affect automation or effects
153         ArrayList<double> times;
154
155         for(Track *current_track = first;
156                 current_track;
157                 current_track = current_track->next)
158         {
159                 if(current_track->record)
160                 {
161                         current_track->align_edits(start, end, &times);
162                 }
163         }
164 }
165
166 void Tracks::set_edit_length(double start, double end, double length)
167 {
168         int first_track = 1;
169         for(Track *current_track = first;
170                 current_track;
171                 current_track = current_track->next)
172         {
173                 if(current_track->record)
174                 {
175 #define USE_FLOATING_LENGTHS
176
177 #ifdef USE_FLOATING_LENGTHS
178
179
180 // The first edit anchors the length offsets.
181 // Round edits up & down so they end where they would if they all had floating point lengths.
182                         //int first_edit = 1;
183                         int64_t start_units = current_track->to_units(start, 0);
184                         int64_t end_units = current_track->to_units(end, 0);
185 // Total time of edits accumulated, in track units
186                         int64_t total_units = 0;
187 // Number of length offsets added so far
188                         int total_lengths = 0;
189
190                         for(Edit *current_edit = current_track->edits->last;
191                                 current_edit;
192                                 current_edit = current_edit->previous)
193                         {
194                                 if(current_edit->startproject >= start_units &&
195                                         current_edit->startproject + current_edit->length <= end_units)
196                                 {
197 // Calculate true length based on number of length offsets & total time
198                                         double end_time = (1 + total_lengths) * length;
199                                         int64_t length_units = current_track->to_units(end_time, 0) -
200                                                 total_units;
201                                         if(length_units < 1) length_units = 1;
202 printf("Tracks::set_edit_length %d %f %f\n", __LINE__, end_time, current_track->from_units(total_units));
203                                         total_units += length_units;
204
205 // Go in using the edit handle interface
206                                         int64_t starting_length = current_edit->length;
207
208                                         if(length_units < current_edit->length)
209                                         {
210                                                 current_edit->shift_end_in(MOVE_ALL_EDITS,
211                                                         current_edit->startproject + length_units,
212                                                         current_edit->startproject + current_edit->length,
213                                                         1,
214                                                         edl->session->labels_follow_edits,
215                                                         edl->session->plugins_follow_edits,
216                                                         edl->session->autos_follow_edits,
217                                                         0);
218                                         }
219                                         else
220                                         {
221                                                 current_edit->shift_end_out(MOVE_ALL_EDITS,
222                                                         current_edit->startproject + length_units,
223                                                         current_edit->startproject + current_edit->length,
224                                                         1,
225                                                         edl->session->labels_follow_edits,
226                                                         edl->session->plugins_follow_edits,
227                                                         edl->session->autos_follow_edits,
228                                                         0);
229                                         }
230
231                                         int64_t ending_length = current_edit->length;
232
233                                         if(edl->session->labels_follow_edits && first_track)
234                                         {
235 // printf("Tracks::set_edit_length %d %f %f\n",
236 // __LINE__,
237 // current_track->from_units(current_edit->startproject + starting_length),
238 // current_track->from_units(current_edit->startproject + ending_length));
239                                                  edl->labels->modify_handles(
240                                                         current_track->from_units(current_edit->startproject + starting_length),
241                                                         current_track->from_units(current_edit->startproject + ending_length),
242                                                         1,
243                                                         MOVE_ALL_EDITS,
244                                                         1);
245                                         }
246
247
248                                         //first_edit = 0;
249                                         total_lengths++;
250                                 }
251                         }
252
253
254
255 #else // USE_FLOATING_LENGTHS
256
257 // The first edit anchors the length offsets.
258 // The idea was to round edits up & down so they end where they should
259 // if they all had floating point lengths.  It's easier just to make sure the framerate
260 // is divisible by the required length.
261 //                      int first_edit = 1;
262                         int64_t start_units = current_track->to_units(start, 0);
263                         int64_t end_units = current_track->to_units(end, 0);
264                         int64_t length_units = current_track->to_units(length, 1);
265 // Starting time of the length offsets in seconds
266 //                      double start_time = 0;
267 // Number of length offsets added so far
268 //                      int total_lengths = 0;
269
270                         for(Edit *current_edit = current_track->edits->last;
271                                 current_edit;
272                                 current_edit = current_edit->previous)
273                         {
274                                 if(current_edit->startproject >= start_units &&
275                                         current_edit->startproject + current_edit->length <= end_units)
276                                 {
277 // Calculate starting time of length offsets
278 //                                      if(first_edit)
279 //                                      {
280 //                                              start_time = current_track->from_units(current_edit->startproject);
281 //                                      }
282
283 // Calculate true length based on number of length offsets
284 //                                      double end_time = start_time + (1 + total_lengths) * length;
285 //                                      int64_t length_units = current_track->to_units(end_time, 0) -
286 //                                              current_edit->startproject;
287 //                                      if(length_units < 1) length_units = 1;
288
289 // Go in using the edit handle interface
290                                         int64_t starting_length = current_edit->length;
291
292                                         if(length_units < current_edit->length)
293                                         {
294                                                 current_edit->shift_end_in(MOVE_ALL_EDITS,
295                                                         current_edit->startproject + length_units,
296                                                         current_edit->startproject + current_edit->length,
297                                                         1,
298                                                         edl->session->labels_follow_edits,
299                                                         edl->session->plugins_follow_edits,
300                                                         edl->session->autos_follow_edits,
301                                                         0);
302                                         }
303                                         else
304                                         {
305                                                 current_edit->shift_end_out(MOVE_ALL_EDITS,
306                                                         current_edit->startproject + length_units,
307                                                         current_edit->startproject + current_edit->length,
308                                                         1,
309                                                         edl->session->labels_follow_edits,
310                                                         edl->session->plugins_follow_edits,
311                                                         edl->session->autos_follow_edits,
312                                                         0);
313                                         }
314
315                                         int64_t ending_length = current_edit->length;
316
317                                         if(edl->session->labels_follow_edits && first_track)
318                                         {
319 // printf("Tracks::set_edit_length %d %f %f\n",
320 // __LINE__,
321 // current_track->from_units(current_edit->startproject + starting_length),
322 // current_track->from_units(current_edit->startproject + ending_length));
323                                                  edl->labels->modify_handles(
324                                                         current_track->from_units(current_edit->startproject + starting_length),
325                                                         current_track->from_units(current_edit->startproject + ending_length),
326                                                         1,
327                                                         MOVE_ALL_EDITS,
328                                                         1);
329                                         }
330
331
332 //                                      first_edit = 0;
333 //                                      total_lengths++;
334                                 }
335                         }
336 #endif // !USE_FLOATING_LENGTHS
337
338                         first_track = 0;
339                 }
340         }
341 }
342
343 void Tracks::set_transition_length(double start, double end, double length)
344 {
345         for(Track *current_track = first;
346                 current_track;
347                 current_track = current_track->next)
348         {
349                 if(current_track->record)
350                 {
351                         int64_t start_units = current_track->to_units(start, 0);
352                         int64_t end_units = current_track->to_units(end, 0);
353
354                         for(Edit *current_edit = current_track->edits->first;
355                                 current_edit;
356                                 current_edit = current_edit->next)
357                         {
358                                 if(current_edit->startproject >= start_units &&
359                                         current_edit->startproject < end_units &&
360                                         current_edit->transition)
361                                 {
362                                         current_edit->transition->length =
363                                                 current_track->to_units(length, 1);
364                                         if( current_edit == current_track->edits->last &&
365                                             current_edit->silence() ) {
366                                                 current_edit->length = current_edit->transition->length;
367                                         }
368                                 }
369                         }
370                 }
371         }
372 }
373
374 void Tracks::set_transition_length(Transition *transition, double length)
375 {
376 // Must verify existence of transition
377         int done = 0;
378         if(!transition) return;
379         for(Track *current_track = first;
380                 current_track && !done;
381                 current_track = current_track->next)
382         {
383                 for(Edit *current_edit = current_track->edits->first;
384                         current_edit && !done;
385                         current_edit = current_edit->next)
386                 {
387                         if(current_edit->transition == transition)
388                         {
389                                 transition->length = current_track->to_units(length, 1);
390                                 if( current_edit == current_track->edits->last &&
391                                     current_edit->silence() ) {
392                                         current_edit->length = current_edit->transition->length;
393                                 }
394                                 done = 1;
395                         }
396                 }
397         }
398 }
399
400 void Tracks::paste_transitions(double start, double end, int track_type, char* title)
401 {
402         for(Track *current_track = first;
403                 current_track;
404                 current_track = current_track->next)
405         {
406                 if(current_track->record && current_track->data_type == track_type)
407                 {
408                         int64_t start_units = current_track->to_units(start, 0);
409                         int64_t end_units = current_track->to_units(end, 0);
410                         if( start_units == end_units ) {
411                                 for( Edit *current_edit = current_track->edits->first;
412                                      current_edit; current_edit = current_edit->next) {
413                                         int64_t edit_start = current_edit->startproject;
414                                         int64_t edit_end = edit_start + current_edit->length;
415                                         if( edit_start > start_units ) continue;
416                                         if( start_units == current_track->edits->length() ) {
417                                                 double length = edl->session->default_transition_length;
418                                                 int64_t units = current_track->to_units(length, 1);
419                                                 current_edit = current_track->edits->
420                                                         create_silence(start_units, start_units+units);
421                                         }
422                                         else if( start_units >= edit_end ) continue;
423                                         current_edit->insert_transition(title);
424                                 }
425                         }
426                         else {
427                                 for( Edit *current_edit = current_track->edits->first;
428                                      current_edit; current_edit = current_edit->next) {
429                                         int64_t edit_start = current_edit->startproject;
430                                         if( !edit_start ) continue;
431                                         if( edit_start >= start_units && edit_start < end_units ) {
432                                                 current_edit->insert_transition(title);
433                                         }
434                                 }
435                         }
436                 }
437         }
438 }
439
440 void Tracks::set_automation_mode(double selectionstart,
441         double selectionend,
442         int mode)
443 {
444         Track* current_track;
445
446         for(current_track = first; current_track; current_track = current_track->next)
447         {
448                 if(current_track->record)
449                 {
450                         current_track->set_automation_mode(selectionstart,
451                                 selectionend,
452                                 mode);
453                 }
454         }
455 }
456
457 int Tracks::clear_default_keyframe()
458 {
459         for(Track *current = first; current; current = NEXT)
460         {
461                 if(current->record)
462                         current->clear_automation(0, 0, 0, 1);
463         }
464         return 0;
465 }
466
467 int Tracks::clear_handle(double start,
468         double end,
469         double &longest_distance,
470         int clear_labels,
471         int clear_plugins,
472         int edit_autos)
473 {
474         Track* current_track;
475         double distance;
476
477         for(current_track = first; current_track; current_track = current_track->next)
478         {
479                 if(current_track->record)
480                 {
481                         current_track->clear_handle(start,
482                                 end,
483                                 clear_labels,
484                                 clear_plugins,
485                                 edit_autos,
486                                 distance);
487                         if(distance > longest_distance) longest_distance = distance;
488                 }
489         }
490
491         return 0;
492 }
493
494 int Tracks::copy_automation(double selectionstart,
495         double selectionend,
496         FileXML *file,
497         int default_only,
498         int autos_only)
499 {
500 // called by MWindow::copy_automation for copying automation alone
501         Track* current_track;
502
503         file->tag.set_title("AUTO_CLIPBOARD");
504         file->tag.set_property("LENGTH", selectionend - selectionstart);
505         file->tag.set_property("FRAMERATE", edl->session->frame_rate);
506         file->tag.set_property("SAMPLERATE", edl->session->sample_rate);
507         file->append_tag();
508         file->append_newline();
509         file->append_newline();
510
511         for(current_track = first;
512                 current_track;
513                 current_track = current_track->next)
514         {
515                 if(current_track->record)
516                 {
517                         current_track->copy_automation(selectionstart,
518                                 selectionend,
519                                 file,
520                                 default_only,
521                                 autos_only);
522                 }
523         }
524
525         file->tag.set_title("/AUTO_CLIPBOARD");
526         file->append_tag();
527         file->append_newline();
528         file->terminate_string();
529         return 0;
530 }
531
532 // int Tracks::copy_default_keyframe(FileXML *file)
533 // {
534 //      copy_automation(0, 0, file, 1, 0);
535 //      return 0;
536 // }
537
538 int Tracks::delete_tracks()
539 {
540         int total_deleted = 0;
541         int done = 0;
542
543         while(!done)
544         {
545                 done = 1;
546                 Track *next_track = 0;
547                 for (Track* current = first; current && done; current = next_track)
548                 {
549                         next_track = current->next;
550                         if(current->record)
551                         {
552                                 delete_track(current);
553                                 current = NULL;
554                                 total_deleted++;
555                                 done = 0;
556                                 break;
557                         }
558                 }
559         }
560         return total_deleted;
561 }
562
563 void Tracks::move_edits(ArrayList<Edit*> *edits,
564         Track *track,
565         double position,
566         int edit_labels,  // Ignored
567         int edit_plugins,  // Ignored
568         int edit_autos, // Ignored
569         int behaviour)
570 {
571 //printf("Tracks::move_edits 1\n");
572         for(Track *dest_track = track; dest_track; dest_track = dest_track->next)
573         {
574                 if(dest_track->record)
575                 {
576 // Need a local copy of the source edit since the original source edit may
577 // change in the editing operation.
578                         Edit *source_edit = 0;
579                         Track *source_track = 0;
580
581
582 // Get source track
583                         if(dest_track->data_type == TRACK_AUDIO)
584                         {
585                                 int current_aedit = 0;
586
587                                 while(current_aedit < edits->total &&
588                                         edits->values[current_aedit]->track->data_type != TRACK_AUDIO)
589                                         current_aedit++;
590
591                                 if(current_aedit < edits->total)
592                                 {
593                                         source_edit = edits->values[current_aedit];
594                                         source_track = source_edit->track;
595                                         edits->remove_number(current_aedit);
596                                 }
597                         }
598                         else
599                         if(dest_track->data_type == TRACK_VIDEO)
600                         {
601                                 int current_vedit = 0;
602                                 while(current_vedit < edits->total &&
603                                         edits->values[current_vedit]->track->data_type != TRACK_VIDEO)
604                                         current_vedit++;
605
606                                 if(current_vedit < edits->total)
607                                 {
608                                         source_edit = edits->values[current_vedit];
609                                         source_track = source_edit->track;
610                                         edits->remove_number(current_vedit);
611                                 }
612                         }
613
614 //printf("Tracks::move_edits 2 %s %s %d\n", source_track->title, dest_track->title, source_edit->length);
615                         if(source_edit)
616                         {
617                                 int64_t position_i = source_track->to_units(position, 0);
618 // Source edit changes
619                                 int64_t source_length = source_edit->length;
620                                 int64_t source_startproject = source_edit->startproject;
621
622                                 if (behaviour == 0)
623                                 {
624                                 // This works like this: CUT edit, INSERT edit at final position, keyframes also follow
625                                 // FIXME: there should be a GUI way to tell whenever user also wants to move autos or not
626 // Copy keyframes
627                                         FileXML temp;
628                                         AutoConf temp_autoconf;
629
630                                         temp_autoconf.set_all(1);
631
632                                         source_track->automation->copy(source_edit->startproject,
633                                                 source_edit->startproject + source_edit->length,
634                                                 &temp,
635                                                 0,
636                                                 0);
637                                         temp.terminate_string();
638                                         temp.rewind();
639 // Insert new keyframes
640 //printf("Tracks::move_edits 2 %d %p\n", result->startproject, result->asset);
641                                         source_track->automation->clear(source_edit->startproject,
642                                                 source_edit->startproject + source_edit->length,
643                                                 &temp_autoconf,
644                                                 1);
645                                         int64_t position_a = position_i;
646                                         if (dest_track == source_track)
647                                         {
648                                                 if (position_a > source_edit->startproject)
649                                                         position_a -= source_length;
650                                         }
651
652                                         dest_track->automation->paste_silence(position_a,
653                                                 position_a + source_length);
654                                         while(!temp.read_tag())
655                                                 dest_track->automation->paste(position_a,
656                                                         source_length, 1.0, &temp, 0, 1,
657                                                         &temp_autoconf);
658
659 // Insert new edit
660                                         Edit *dest_edit = dest_track->edits->shift(position_i,
661                                                 source_length);
662                                         Edit *result = dest_track->edits->insert_before(dest_edit,
663                                                 dest_track->edits->create_edit());
664                                         result->copy_from(source_edit);
665                                         result->startproject = position_i;
666                                         result->length = source_length;
667
668 // Clear source
669                                         source_track->edits->clear(source_edit->startproject,
670                                                 source_edit->startproject + source_length);
671
672         /*
673 //this is outline for future thinking how it is supposed to be done trough C&P mechanisms
674                                         temp.reset_tag();
675                                         source_track->cut(source_edit->startproject,
676                                                 source_edit->startproject + source_edit->length,
677                                                 &temp,
678                                                 NULL);
679                                         temp.terminate_string();
680                                         temp.rewind();
681                                         dest_track->paste_silence(position_a,
682                                                 position_a + source_length,
683                                                 edit_plugins);
684                                         while(!temp.read_tag())
685                                                 dest_track->paste(position_a,          // MISSING PIECE OF FUNCTIONALITY
686                                                         source_length,
687                                                         1.0,
688                                                         &temp,
689                                                         0,
690                                                         &temp_autoconf);
691         */
692
693
694                                 } else
695                                 if (behaviour == 1)
696                                 // ONLY edit is moved, all other edits stay where they are
697                                 {
698                                         // Copy edit to temp, delete the edit, insert the edit
699                                         Edit *temp_edit = dest_track->edits->create_edit();
700                                         temp_edit->copy_from(source_edit);
701                                         // we call the edits directly since we do not want to move keyframes or anything else
702                                         source_track->edits->clear(source_startproject,
703                                                 source_startproject + source_length);
704                                         source_track->edits->paste_silence(source_startproject,
705                                                 source_startproject + source_length);
706
707                                         dest_track->edits->clear(position_i,
708                                                 position_i + source_length);
709                                         Edit *dest_edit = dest_track->edits->shift(position_i,  source_length);
710                                         Edit *result = dest_track->edits->insert_before(dest_edit,
711                                                 dest_track->edits->create_edit());
712                                         result->copy_from(temp_edit);
713                                         result->startproject = position_i;
714                                         result->length = source_length;
715                                         delete temp_edit;
716                                 }
717                                 source_track->optimize();
718                                 dest_track->optimize();
719                         }
720                 }
721         }
722 }
723
724 void Tracks::move_effect(Plugin *plugin, Track *track, int64_t position)
725 {
726         Track *source_track = plugin->track;
727         Plugin *result = 0;
728 // Create a new plugin set
729         double start = track->from_units(position);
730         double length = track->from_units(plugin->length);
731
732         result = track->insert_effect("", &plugin->shared_location, 0, 0,
733                                 start, length, plugin->plugin_type);
734         result->copy_from(plugin);
735         result->shift(position - plugin->startproject);
736
737 // Clear new plugin from old set
738         plugin->plugin_set->clear(plugin->startproject,
739                 plugin->startproject + plugin->length,
740                 edl->session->autos_follow_edits);
741
742         source_track->optimize();
743 }
744
745 void Tracks::move_effect(Plugin *plugin, PluginSet *plugin_set, int64_t position)
746 {
747 // src/dest track must be the same
748 // replace plugin in source plugin_set with silence
749         PluginSet *src_plugin_set = plugin->plugin_set;
750         Plugin *silent = new Plugin(edl, src_plugin_set, "");
751         silent->startproject = plugin->startproject;
752         silent->length = plugin->length;
753         src_plugin_set->insert_after(plugin, silent);
754         src_plugin_set->remove_pointer(plugin);
755 // truncate previous plugin
756         Plugin *dest = (Plugin *)plugin_set->editof(position, PLAY_FORWARD, 0);
757 // add plugin after dest
758         plugin_set->insert_after(dest, plugin);
759         if( dest ) {
760                 dest->length = position - dest->startproject;
761                 if( dest->length < 0 ) dest->length = 0;
762         }
763 // update plugin position
764         plugin->startproject = position;
765         plugin->plugin_set = plugin_set;
766         src_plugin_set->track->optimize();
767 }
768
769 int Tracks::concatenate_tracks(int edit_plugins, int edit_autos)
770 {
771         Track *output_track, *first_output_track, *input_track;
772         int i, data_type = TRACK_AUDIO;
773         double output_start;
774         int result = 0;
775
776 // Relocate tracks
777         for(i = 0; i < 2; i++)
778         {
779 // Get first output track
780                 for(output_track = first;
781                         output_track;
782                         output_track = output_track->next)
783                         if(output_track->data_type == data_type &&
784                                 output_track->record) break;
785
786                 first_output_track = output_track;
787
788 // Get first input track
789                 for(input_track = first;
790                         input_track;
791                         input_track = input_track->next)
792                 {
793                         if(input_track->data_type == data_type &&
794                                 input_track->play &&
795                                 !input_track->record) break;
796                 }
797
798
799                 if(output_track && input_track)
800                 {
801 // Transfer input track to end of output track one at a time
802                         while(input_track)
803                         {
804                                 output_start = output_track->get_length();
805                                 output_track->insert_track(input_track,
806                                         output_start,
807                                         0,
808                                         edit_plugins,
809                                         edit_autos,
810                                         0);
811
812 // Get next source and destination
813                                 for(input_track = input_track->next;
814                                         input_track;
815                                         input_track = input_track->next)
816                                 {
817
818                                         if(input_track->data_type == data_type &&
819                                                 !input_track->record &&
820                                                 input_track->play) break;
821                                 }
822
823                                 for(output_track = output_track->next;
824                                         output_track;
825                                         output_track = output_track->next)
826                                 {
827                                         if(output_track->data_type == data_type &&
828                                                 output_track->record) break;
829                                 }
830
831                                 if(!output_track)
832                                 {
833                                         output_track = first_output_track;
834                                 }
835                         }
836                         result = 1;
837                 }
838
839                 if(data_type == TRACK_AUDIO) data_type = TRACK_VIDEO;
840         }
841
842         return result;
843 }
844
845 int Tracks::delete_all_tracks()
846 {
847         while(last) delete last;
848         return 0;
849 }
850
851
852 void Tracks::change_modules(int old_location, int new_location, int do_swap)
853 {
854         for(Track* current = first ; current; current = current->next)
855         {
856                 current->change_modules(old_location, new_location, do_swap);
857         }
858 }
859
860 void Tracks::change_plugins(SharedLocation &old_location, SharedLocation &new_location, int do_swap)
861 {
862         for(Track* current = first ; current; current = current->next)
863         {
864                 current->change_plugins(old_location, new_location, do_swap);
865         }
866 }
867
868
869
870 // =========================================== EDL editing
871
872
873 int Tracks::copy(double start,
874         double end,
875         int all,
876         FileXML *file,
877         const char *output_path)
878 {
879 // nothing selected
880         if(start == end && !all) return 1;
881
882         Track* current;
883
884         for(current = first;
885                 current;
886                 current = NEXT)
887         {
888                 if(current->record || all)
889                 {
890                         current->copy(start, end, file,output_path);
891                 }
892         }
893
894         return 0;
895 }
896
897
898
899 int Tracks::move_track_up(Track *track)
900 {
901         Track *next_track = track->previous;
902         if(!next_track) next_track = last;
903
904         change_modules(number_of(track), number_of(next_track), 1);
905
906 // printf("Tracks::move_track_up 1 %p %p\n", track, next_track);
907 // int count = 0;
908 // for(Track *current = first; current && count < 5; current = NEXT, count++)
909 //      printf("Tracks::move_track_up %p %p %p\n", current->previous, current, current->next);
910 // printf("Tracks::move_track_up 2\n");
911 //
912         swap(track, next_track);
913
914 // count = 0;
915 // for(Track *current = first; current && count < 5; current = NEXT, count++)
916 //      printf("Tracks::move_track_up %p %p %p\n", current->previous, current, current->next);
917 // printf("Tracks::move_track_up 3\n");
918
919         return 0;
920 }
921
922 int Tracks::move_track_down(Track *track)
923 {
924         Track *next_track = track->next;
925         if(!next_track) next_track = first;
926
927         change_modules(number_of(track), number_of(next_track), 1);
928         swap(track, next_track);
929         return 0;
930 }
931
932
933 int Tracks::move_tracks_up()
934 {
935         Track *track, *next_track;
936         int result = 0;
937
938         for(track = first;
939                 track;
940                 track = next_track)
941         {
942                 next_track = track->next;
943
944                 if(track->record)
945                 {
946                         if(track->previous)
947                         {
948                                 change_modules(number_of(track->previous), number_of(track), 1);
949
950                                 swap(track->previous, track);
951                                 result = 1;
952                         }
953                 }
954         }
955
956         return result;
957 }
958
959 int Tracks::move_tracks_down()
960 {
961         Track *track, *previous_track;
962         int result = 0;
963
964         for(track = last;
965                 track;
966                 track = previous_track)
967         {
968                 previous_track = track->previous;
969
970                 if(track->record)
971                 {
972                         if(track->next)
973                         {
974                                 change_modules(number_of(track), number_of(track->next), 1);
975
976                                 swap(track, track->next);
977                                 result = 1;
978                         }
979                 }
980         }
981
982         return result;
983 }
984
985
986
987 void Tracks::paste_audio_transition(PluginServer *server)
988 {
989         for(Track *current = first; current; current = NEXT)
990         {
991                 if(current->data_type == TRACK_AUDIO &&
992                         current->record)
993                 {
994                         int64_t position = current->to_units(
995                                 edl->local_session->get_selectionstart(), 0);
996                         Edit *current_edit = current->edits->editof(position,
997                                 PLAY_FORWARD,
998                                 0);
999                         if( !current_edit && position == current->edits->length() ) {
1000                                 double length = edl->session->default_transition_length;
1001                                 int64_t units = current->to_units(length, 1);
1002                                 current_edit = current->edits->create_silence(position, position+units);
1003                         }
1004                         if(current_edit)
1005                         {
1006                                 paste_transition(server, current_edit);
1007                         }
1008                 }
1009         }
1010 }
1011
1012 void Tracks::paste_automation(double selectionstart,
1013         FileXML *file,
1014         int default_only,
1015         int active_only,
1016         int typeless)
1017 {
1018         Track* current_track = 0;
1019         Track* current_atrack = 0;
1020         Track* current_vtrack = 0;
1021         Track* dst_track = 0;
1022         int src_type;
1023         int result = 0;
1024         double length;
1025         double frame_rate = edl->session->frame_rate;
1026         int64_t sample_rate = edl->session->sample_rate;
1027         char string[BCTEXTLEN];
1028         string[0] = 0;
1029
1030 // Search for start
1031         do{
1032           result = file->read_tag();
1033         }while(!result &&
1034                 !file->tag.title_is("AUTO_CLIPBOARD"));
1035
1036         if(!result)
1037         {
1038                 length = file->tag.get_property("LENGTH", 0);
1039                 frame_rate = file->tag.get_property("FRAMERATE", frame_rate);
1040                 sample_rate = file->tag.get_property("SAMPLERATE", sample_rate);
1041
1042
1043                 do
1044                 {
1045                         result = file->read_tag();
1046
1047                         if(!result)
1048                         {
1049                                 if(file->tag.title_is("/AUTO_CLIPBOARD"))
1050                                 {
1051                                         result = 1;
1052                                 }
1053                                 else
1054                                 if(file->tag.title_is("TRACK"))
1055                                 {
1056                                         file->tag.get_property("TYPE", string);
1057                                         if(!strcmp(string, "AUDIO"))
1058                                         {
1059                                                 src_type = TRACK_AUDIO;
1060                                         }
1061                                         else
1062                                         {
1063                                                 src_type = TRACK_VIDEO;
1064                                         }
1065
1066 // paste to any media type
1067                                         if(typeless)
1068                                         {
1069                                                 if(!current_track) current_track = first;
1070                                                 while(current_track && !current_track->record)
1071                                                         current_track = current_track->next;
1072                                                 dst_track = current_track;
1073                                         }
1074                                         else
1075                                         if(!strcmp(string, "AUDIO"))
1076                                         {
1077 // Get next audio track
1078                                                 if(!current_atrack)
1079                                                         current_atrack = first;
1080                                                 else
1081                                                         current_atrack = current_atrack->next;
1082
1083                                                 while(current_atrack &&
1084                                                         (current_atrack->data_type != TRACK_AUDIO ||
1085                                                         !current_atrack->record))
1086                                                         current_atrack = current_atrack->next;
1087                                                 dst_track = current_atrack;
1088                                         }
1089                                         else
1090                                         {
1091 // Get next video track
1092                                                 if(!current_vtrack)
1093                                                         current_vtrack = first;
1094                                                 else
1095                                                         current_vtrack = current_vtrack->next;
1096
1097                                                 while(current_vtrack &&
1098                                                         (current_vtrack->data_type != TRACK_VIDEO ||
1099                                                         !current_vtrack->record))
1100                                                         current_vtrack = current_vtrack->next;
1101
1102                                                 dst_track = current_vtrack;
1103                                         }
1104
1105                                         if(dst_track)
1106                                         {
1107                                                 double frame_rate2 = frame_rate;
1108                                                 double sample_rate2 = sample_rate;
1109
1110                                                 if(src_type != dst_track->data_type)
1111                                                 {
1112                                                         frame_rate2 = sample_rate;
1113                                                         sample_rate2 = frame_rate;
1114                                                 }
1115
1116                                                 dst_track->paste_automation(selectionstart,
1117                                                         length,
1118                                                         frame_rate2,
1119                                                         sample_rate2,
1120                                                         file,
1121                                                         default_only,
1122                                                         active_only);
1123                                         }
1124                                 }
1125                         }
1126                 }while(!result);
1127         }
1128 }
1129
1130 // int Tracks::paste_default_keyframe(FileXML *file)
1131 // {
1132 //      paste_automation(0, file, 1, 0);
1133 //      return 0;
1134 // }
1135
1136 void Tracks::paste_transition(PluginServer *server, Edit *dest_edit)
1137 {
1138         dest_edit->insert_transition(server->title);
1139 }
1140
1141 void Tracks::paste_video_transition(PluginServer *server, int first_track)
1142 {
1143         for(Track *current = first; current; current = NEXT)
1144         {
1145                 if(current->data_type == TRACK_VIDEO &&
1146                         current->record)
1147                 {
1148                         int64_t position = current->to_units(
1149                                 edl->local_session->get_selectionstart(), 0);
1150                         Edit *current_edit = current->edits->editof(position,
1151                                 PLAY_FORWARD,
1152                                 0);
1153                         if( !current_edit && position == current->edits->length() ) {
1154                                 double length = edl->session->default_transition_length;
1155                                 int64_t units = current->to_units(length, 1);
1156                                 current_edit = current->edits->create_silence(position, position+units);
1157                         }
1158                         if(current_edit)
1159                         {
1160                                 paste_transition(server, current_edit);
1161                         }
1162                         if(first_track) break;
1163                 }
1164         }
1165 }
1166
1167
1168 int Tracks::paste_silence(double start,
1169         double end,
1170         int edit_plugins,
1171         int edit_autos)
1172 {
1173         Track* current_track;
1174
1175         for(current_track = first;
1176                 current_track;
1177                 current_track = current_track->next)
1178         {
1179                 if(current_track->record)
1180                 {
1181                         current_track->paste_silence(start,
1182                                 end,
1183                                 edit_plugins,
1184                                 edit_autos);
1185                 }
1186         }
1187         return 0;
1188 }
1189
1190
1191
1192 int Tracks::select_auto(int cursor_x, int cursor_y)
1193 {
1194         int result = 0;
1195         for(Track* current = first; current && !result; current = NEXT) { result = current->select_auto(&auto_conf, cursor_x, cursor_y); }
1196         return result;
1197 }
1198
1199 int Tracks::move_auto(int cursor_x, int cursor_y, int shift_down)
1200 {
1201         int result = 0;
1202
1203         for(Track* current = first; current && !result; current = NEXT)
1204         {
1205                 result = current->move_auto(&auto_conf, cursor_x, cursor_y, shift_down);
1206         }
1207         return 0;
1208 }
1209
1210 int Tracks::modify_edithandles(double &oldposition,
1211         double &newposition,
1212         int currentend,
1213         int handle_mode,
1214         int edit_labels,
1215         int edit_plugins,
1216         int edit_autos)
1217 {
1218         Track *current;
1219
1220         for(current = first; current; current = NEXT)
1221         {
1222                 if(current->record)
1223                 {
1224                         current->modify_edithandles(oldposition,
1225                                 newposition,
1226                                 currentend,
1227                                 handle_mode,
1228                                 edit_labels,
1229                                 edit_plugins,
1230                                 edit_autos);
1231                 }
1232         }
1233         return 0;
1234 }
1235
1236 int Tracks::modify_pluginhandles(double &oldposition,
1237         double &newposition,
1238         int currentend,
1239         int handle_mode,
1240         int edit_labels,
1241         int edit_autos,
1242         Edits *trim_edits)
1243 {
1244         Track *current;
1245
1246         for(current = first; current; current = NEXT)
1247         {
1248                 if(current->record)
1249                 {
1250                         current->modify_pluginhandles(oldposition,
1251                                 newposition,
1252                                 currentend,
1253                                 handle_mode,
1254                                 edit_labels,
1255                                 edit_autos,
1256                                 trim_edits);
1257                 }
1258         }
1259         return 0;
1260 }
1261
1262
1263
1264 int Tracks::purge_asset(Asset *asset)
1265 {
1266         Track *current_track;
1267         int result = 0;
1268
1269         for(current_track = first; current_track; current_track = current_track->next)
1270         {
1271                 result += current_track->purge_asset(asset);
1272         }
1273         return result;
1274 }
1275
1276 int Tracks::asset_used(Asset *asset)
1277 {
1278         Track *current_track;
1279         int result = 0;
1280
1281         for(current_track = first; current_track; current_track = current_track->next)
1282         {
1283                 result += current_track->asset_used(asset);
1284         }
1285         return result;
1286 }
1287
1288 int Tracks::scale_time(float rate_scale, int ignore_record, int scale_edits, int scale_autos, int64_t start, int64_t end)
1289 {
1290         Track *current_track;
1291
1292         for(current_track = first;
1293                 current_track;
1294                 current_track = current_track->next)
1295         {
1296                 if((current_track->record || ignore_record) &&
1297                         current_track->data_type == TRACK_VIDEO)
1298                 {
1299                         current_track->scale_time(rate_scale, scale_edits, scale_autos, start, end);
1300                 }
1301         }
1302         return 0;
1303 }
1304