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