clear cache for undo/redo, alt-# range chk, shortcuts docs, plugin_set segv
[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         plugin->edits = plugin_set;
767         src_plugin_set->track->optimize();
768 }
769
770 int Tracks::concatenate_tracks(int edit_plugins, int edit_autos)
771 {
772         Track *output_track, *first_output_track, *input_track;
773         int i, data_type = TRACK_AUDIO;
774         double output_start;
775         int result = 0;
776
777 // Relocate tracks
778         for(i = 0; i < 2; i++)
779         {
780 // Get first output track
781                 for(output_track = first;
782                         output_track;
783                         output_track = output_track->next)
784                         if(output_track->data_type == data_type &&
785                                 output_track->record) break;
786
787                 first_output_track = output_track;
788
789 // Get first input track
790                 for(input_track = first;
791                         input_track;
792                         input_track = input_track->next)
793                 {
794                         if(input_track->data_type == data_type &&
795                                 input_track->play &&
796                                 !input_track->record) break;
797                 }
798
799
800                 if(output_track && input_track)
801                 {
802 // Transfer input track to end of output track one at a time
803                         while(input_track)
804                         {
805                                 output_start = output_track->get_length();
806                                 output_track->insert_track(input_track,
807                                         output_start,
808                                         0,
809                                         edit_plugins,
810                                         edit_autos,
811                                         0);
812
813 // Get next source and destination
814                                 for(input_track = input_track->next;
815                                         input_track;
816                                         input_track = input_track->next)
817                                 {
818
819                                         if(input_track->data_type == data_type &&
820                                                 !input_track->record &&
821                                                 input_track->play) break;
822                                 }
823
824                                 for(output_track = output_track->next;
825                                         output_track;
826                                         output_track = output_track->next)
827                                 {
828                                         if(output_track->data_type == data_type &&
829                                                 output_track->record) break;
830                                 }
831
832                                 if(!output_track)
833                                 {
834                                         output_track = first_output_track;
835                                 }
836                         }
837                         result = 1;
838                 }
839
840                 if(data_type == TRACK_AUDIO) data_type = TRACK_VIDEO;
841         }
842
843         return result;
844 }
845
846 int Tracks::delete_all_tracks()
847 {
848         while(last) delete last;
849         return 0;
850 }
851
852
853 void Tracks::change_modules(int old_location, int new_location, int do_swap)
854 {
855         for(Track* current = first ; current; current = current->next)
856         {
857                 current->change_modules(old_location, new_location, do_swap);
858         }
859 }
860
861 void Tracks::change_plugins(SharedLocation &old_location, SharedLocation &new_location, int do_swap)
862 {
863         for(Track* current = first ; current; current = current->next)
864         {
865                 current->change_plugins(old_location, new_location, do_swap);
866         }
867 }
868
869
870
871 // =========================================== EDL editing
872
873
874 int Tracks::copy(double start,
875         double end,
876         int all,
877         FileXML *file,
878         const char *output_path)
879 {
880 // nothing selected
881         if(start == end && !all) return 1;
882
883         Track* current;
884
885         for(current = first;
886                 current;
887                 current = NEXT)
888         {
889                 if(current->record || all)
890                 {
891                         current->copy(start, end, file,output_path);
892                 }
893         }
894
895         return 0;
896 }
897
898
899
900 int Tracks::move_track_up(Track *track)
901 {
902         Track *next_track = track->previous;
903         if(!next_track) next_track = last;
904
905         change_modules(number_of(track), number_of(next_track), 1);
906
907 // printf("Tracks::move_track_up 1 %p %p\n", track, next_track);
908 // int count = 0;
909 // for(Track *current = first; current && count < 5; current = NEXT, count++)
910 //      printf("Tracks::move_track_up %p %p %p\n", current->previous, current, current->next);
911 // printf("Tracks::move_track_up 2\n");
912 //
913         swap(track, next_track);
914
915 // count = 0;
916 // for(Track *current = first; current && count < 5; current = NEXT, count++)
917 //      printf("Tracks::move_track_up %p %p %p\n", current->previous, current, current->next);
918 // printf("Tracks::move_track_up 3\n");
919
920         return 0;
921 }
922
923 int Tracks::move_track_down(Track *track)
924 {
925         Track *next_track = track->next;
926         if(!next_track) next_track = first;
927
928         change_modules(number_of(track), number_of(next_track), 1);
929         swap(track, next_track);
930         return 0;
931 }
932
933
934 int Tracks::move_tracks_up()
935 {
936         Track *track, *next_track;
937         int result = 0;
938
939         for(track = first;
940                 track;
941                 track = next_track)
942         {
943                 next_track = track->next;
944
945                 if(track->record)
946                 {
947                         if(track->previous)
948                         {
949                                 change_modules(number_of(track->previous), number_of(track), 1);
950
951                                 swap(track->previous, track);
952                                 result = 1;
953                         }
954                 }
955         }
956
957         return result;
958 }
959
960 int Tracks::move_tracks_down()
961 {
962         Track *track, *previous_track;
963         int result = 0;
964
965         for(track = last;
966                 track;
967                 track = previous_track)
968         {
969                 previous_track = track->previous;
970
971                 if(track->record)
972                 {
973                         if(track->next)
974                         {
975                                 change_modules(number_of(track), number_of(track->next), 1);
976
977                                 swap(track, track->next);
978                                 result = 1;
979                         }
980                 }
981         }
982
983         return result;
984 }
985
986
987
988 void Tracks::paste_audio_transition(PluginServer *server)
989 {
990         for(Track *current = first; current; current = NEXT)
991         {
992                 if(current->data_type == TRACK_AUDIO &&
993                         current->record)
994                 {
995                         int64_t position = current->to_units(
996                                 edl->local_session->get_selectionstart(), 0);
997                         Edit *current_edit = current->edits->editof(position,
998                                 PLAY_FORWARD,
999                                 0);
1000                         if( !current_edit && position == current->edits->length() ) {
1001                                 double length = edl->session->default_transition_length;
1002                                 int64_t units = current->to_units(length, 1);
1003                                 current_edit = current->edits->create_silence(position, position+units);
1004                         }
1005                         if(current_edit)
1006                         {
1007                                 paste_transition(server, current_edit);
1008                         }
1009                 }
1010         }
1011 }
1012
1013 void Tracks::paste_automation(double selectionstart,
1014         FileXML *file,
1015         int default_only,
1016         int active_only,
1017         int typeless)
1018 {
1019         Track* current_track = 0;
1020         Track* current_atrack = 0;
1021         Track* current_vtrack = 0;
1022         Track* dst_track = 0;
1023         int src_type;
1024         int result = 0;
1025         double length;
1026         double frame_rate = edl->session->frame_rate;
1027         int64_t sample_rate = edl->session->sample_rate;
1028         char string[BCTEXTLEN];
1029         string[0] = 0;
1030
1031 // Search for start
1032         do{
1033           result = file->read_tag();
1034         }while(!result &&
1035                 !file->tag.title_is("AUTO_CLIPBOARD"));
1036
1037         if(!result)
1038         {
1039                 length = file->tag.get_property("LENGTH", 0);
1040                 frame_rate = file->tag.get_property("FRAMERATE", frame_rate);
1041                 sample_rate = file->tag.get_property("SAMPLERATE", sample_rate);
1042
1043
1044                 do
1045                 {
1046                         result = file->read_tag();
1047
1048                         if(!result)
1049                         {
1050                                 if(file->tag.title_is("/AUTO_CLIPBOARD"))
1051                                 {
1052                                         result = 1;
1053                                 }
1054                                 else
1055                                 if(file->tag.title_is("TRACK"))
1056                                 {
1057                                         file->tag.get_property("TYPE", string);
1058                                         if(!strcmp(string, "AUDIO"))
1059                                         {
1060                                                 src_type = TRACK_AUDIO;
1061                                         }
1062                                         else
1063                                         {
1064                                                 src_type = TRACK_VIDEO;
1065                                         }
1066
1067 // paste to any media type
1068                                         if(typeless)
1069                                         {
1070                                                 if(!current_track) current_track = first;
1071                                                 while(current_track && !current_track->record)
1072                                                         current_track = current_track->next;
1073                                                 dst_track = current_track;
1074                                         }
1075                                         else
1076                                         if(!strcmp(string, "AUDIO"))
1077                                         {
1078 // Get next audio track
1079                                                 if(!current_atrack)
1080                                                         current_atrack = first;
1081                                                 else
1082                                                         current_atrack = current_atrack->next;
1083
1084                                                 while(current_atrack &&
1085                                                         (current_atrack->data_type != TRACK_AUDIO ||
1086                                                         !current_atrack->record))
1087                                                         current_atrack = current_atrack->next;
1088                                                 dst_track = current_atrack;
1089                                         }
1090                                         else
1091                                         {
1092 // Get next video track
1093                                                 if(!current_vtrack)
1094                                                         current_vtrack = first;
1095                                                 else
1096                                                         current_vtrack = current_vtrack->next;
1097
1098                                                 while(current_vtrack &&
1099                                                         (current_vtrack->data_type != TRACK_VIDEO ||
1100                                                         !current_vtrack->record))
1101                                                         current_vtrack = current_vtrack->next;
1102
1103                                                 dst_track = current_vtrack;
1104                                         }
1105
1106                                         if(dst_track)
1107                                         {
1108                                                 double frame_rate2 = frame_rate;
1109                                                 double sample_rate2 = sample_rate;
1110
1111                                                 if(src_type != dst_track->data_type)
1112                                                 {
1113                                                         frame_rate2 = sample_rate;
1114                                                         sample_rate2 = frame_rate;
1115                                                 }
1116
1117                                                 dst_track->paste_automation(selectionstart,
1118                                                         length,
1119                                                         frame_rate2,
1120                                                         sample_rate2,
1121                                                         file,
1122                                                         default_only,
1123                                                         active_only);
1124                                         }
1125                                 }
1126                         }
1127                 }while(!result);
1128         }
1129 }
1130
1131 // int Tracks::paste_default_keyframe(FileXML *file)
1132 // {
1133 //      paste_automation(0, file, 1, 0);
1134 //      return 0;
1135 // }
1136
1137 void Tracks::paste_transition(PluginServer *server, Edit *dest_edit)
1138 {
1139         dest_edit->insert_transition(server->title);
1140 }
1141
1142 void Tracks::paste_video_transition(PluginServer *server, int first_track)
1143 {
1144         for(Track *current = first; current; current = NEXT)
1145         {
1146                 if(current->data_type == TRACK_VIDEO &&
1147                         current->record)
1148                 {
1149                         int64_t position = current->to_units(
1150                                 edl->local_session->get_selectionstart(), 0);
1151                         Edit *current_edit = current->edits->editof(position,
1152                                 PLAY_FORWARD,
1153                                 0);
1154                         if( !current_edit && position == current->edits->length() ) {
1155                                 double length = edl->session->default_transition_length;
1156                                 int64_t units = current->to_units(length, 1);
1157                                 current_edit = current->edits->create_silence(position, position+units);
1158                         }
1159                         if(current_edit)
1160                         {
1161                                 paste_transition(server, current_edit);
1162                         }
1163                         if(first_track) break;
1164                 }
1165         }
1166 }
1167
1168
1169 int Tracks::paste_silence(double start,
1170         double end,
1171         int edit_plugins,
1172         int edit_autos)
1173 {
1174         Track* current_track;
1175
1176         for(current_track = first;
1177                 current_track;
1178                 current_track = current_track->next)
1179         {
1180                 if(current_track->record)
1181                 {
1182                         current_track->paste_silence(start,
1183                                 end,
1184                                 edit_plugins,
1185                                 edit_autos);
1186                 }
1187         }
1188         return 0;
1189 }
1190
1191
1192
1193 int Tracks::select_auto(int cursor_x, int cursor_y)
1194 {
1195         int result = 0;
1196         for(Track* current = first; current && !result; current = NEXT) { result = current->select_auto(&auto_conf, cursor_x, cursor_y); }
1197         return result;
1198 }
1199
1200 int Tracks::move_auto(int cursor_x, int cursor_y, int shift_down)
1201 {
1202         int result = 0;
1203
1204         for(Track* current = first; current && !result; current = NEXT)
1205         {
1206                 result = current->move_auto(&auto_conf, cursor_x, cursor_y, shift_down);
1207         }
1208         return 0;
1209 }
1210
1211 int Tracks::modify_edithandles(double &oldposition,
1212         double &newposition,
1213         int currentend,
1214         int handle_mode,
1215         int edit_labels,
1216         int edit_plugins,
1217         int edit_autos)
1218 {
1219         Track *current;
1220
1221         for(current = first; current; current = NEXT)
1222         {
1223                 if(current->record)
1224                 {
1225                         current->modify_edithandles(oldposition,
1226                                 newposition,
1227                                 currentend,
1228                                 handle_mode,
1229                                 edit_labels,
1230                                 edit_plugins,
1231                                 edit_autos);
1232                 }
1233         }
1234         return 0;
1235 }
1236
1237 int Tracks::modify_pluginhandles(double &oldposition,
1238         double &newposition,
1239         int currentend,
1240         int handle_mode,
1241         int edit_labels,
1242         int edit_autos,
1243         Edits *trim_edits)
1244 {
1245         Track *current;
1246
1247         for(current = first; current; current = NEXT)
1248         {
1249                 if(current->record)
1250                 {
1251                         current->modify_pluginhandles(oldposition,
1252                                 newposition,
1253                                 currentend,
1254                                 handle_mode,
1255                                 edit_labels,
1256                                 edit_autos,
1257                                 trim_edits);
1258                 }
1259         }
1260         return 0;
1261 }
1262
1263
1264
1265 int Tracks::purge_asset(Asset *asset)
1266 {
1267         Track *current_track;
1268         int result = 0;
1269
1270         for(current_track = first; current_track; current_track = current_track->next)
1271         {
1272                 result += current_track->purge_asset(asset);
1273         }
1274         return result;
1275 }
1276
1277 int Tracks::asset_used(Asset *asset)
1278 {
1279         Track *current_track;
1280         int result = 0;
1281
1282         for(current_track = first; current_track; current_track = current_track->next)
1283         {
1284                 result += current_track->asset_used(asset);
1285         }
1286         return result;
1287 }
1288
1289 int Tracks::scale_time(float rate_scale, int ignore_record, int scale_edits, int scale_autos, int64_t start, int64_t end)
1290 {
1291         Track *current_track;
1292
1293         for(current_track = first;
1294                 current_track;
1295                 current_track = current_track->next)
1296         {
1297                 if((current_track->record || ignore_record) &&
1298                         current_track->data_type == TRACK_VIDEO)
1299                 {
1300                         current_track->scale_time(rate_scale, scale_edits, scale_autos, start, end);
1301                 }
1302         }
1303         return 0;
1304 }
1305