proxy cpus usage, unlock win before render_proxy, snap tweaks
[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 // this is all screwed up
627 //  inserts defaults/bogus everywhere
628 #if 0
629 // Copy keyframes
630                                         FileXML temp;
631                                         AutoConf temp_autoconf;
632
633                                         temp_autoconf.set_all(1);
634
635                                         source_track->automation->copy(source_edit->startproject,
636                                                 source_edit->startproject + source_edit->length,
637                                                 &temp,
638                                                 0,
639                                                 0);
640                                         temp.terminate_string();
641                                         temp.rewind();
642 // Insert new keyframes
643 //printf("Tracks::move_edits 2 %d %p\n", result->startproject, result->asset);
644                                         source_track->automation->clear(source_edit->startproject,
645                                                 source_edit->startproject + source_edit->length,
646                                                 &temp_autoconf,
647                                                 1);
648                                         int64_t position_a = position_i;
649                                         if (dest_track == source_track)
650                                         {
651                                                 if (position_a > source_edit->startproject)
652                                                         position_a -= source_length;
653                                         }
654
655                                         dest_track->automation->paste_silence(position_a,
656                                                 position_a + source_length);
657                                         while(!temp.read_tag())
658                                                 dest_track->automation->paste(position_a,
659                                                         source_length, 1.0, &temp, 0, 1,
660                                                         &temp_autoconf);
661 #endif
662 // Insert new edit
663                                         Edit *dest_edit = dest_track->edits->shift(position_i,
664                                                 source_length);
665                                         Edit *result = dest_track->edits->insert_before(dest_edit,
666                                                 dest_track->edits->create_edit());
667                                         result->copy_from(source_edit);
668                                         result->startproject = position_i;
669                                         result->length = source_length;
670
671 // Clear source
672                                         source_track->edits->clear(source_edit->startproject,
673                                                 source_edit->startproject + source_length);
674
675         /*
676 //this is outline for future thinking how it is supposed to be done trough C&P mechanisms
677                                         temp.reset_tag();
678                                         source_track->cut(source_edit->startproject,
679                                                 source_edit->startproject + source_edit->length,
680                                                 &temp,
681                                                 NULL);
682                                         temp.terminate_string();
683                                         temp.rewind();
684                                         dest_track->paste_silence(position_a,
685                                                 position_a + source_length,
686                                                 edit_plugins);
687                                         while(!temp.read_tag())
688                                                 dest_track->paste(position_a,          // MISSING PIECE OF FUNCTIONALITY
689                                                         source_length,
690                                                         1.0,
691                                                         &temp,
692                                                         0,
693                                                         &temp_autoconf);
694         */
695
696
697                                 } else
698                                 if (behaviour == 1)
699                                 // ONLY edit is moved, all other edits stay where they are
700                                 {
701                                         // Copy edit to temp, delete the edit, insert the edit
702                                         Edit *temp_edit = dest_track->edits->create_edit();
703                                         temp_edit->copy_from(source_edit);
704                                         // we call the edits directly since we do not want to move keyframes or anything else
705                                         source_track->edits->clear(source_startproject,
706                                                 source_startproject + source_length);
707                                         source_track->edits->paste_silence(source_startproject,
708                                                 source_startproject + source_length);
709
710                                         dest_track->edits->clear(position_i,
711                                                 position_i + source_length);
712                                         Edit *dest_edit = dest_track->edits->shift(position_i,  source_length);
713                                         Edit *result = dest_track->edits->insert_before(dest_edit,
714                                                 dest_track->edits->create_edit());
715                                         result->copy_from(temp_edit);
716                                         result->startproject = position_i;
717                                         result->length = source_length;
718                                         delete temp_edit;
719                                 }
720                                 source_track->optimize();
721                                 dest_track->optimize();
722                         }
723                 }
724         }
725 }
726
727 void Tracks::move_effect(Plugin *plugin, Track *track, int64_t position)
728 {
729         Track *source_track = plugin->track;
730         Plugin *result = 0;
731 // Create a new plugin set
732         double start = track->from_units(position);
733         double length = track->from_units(plugin->length);
734
735         result = track->insert_effect("", &plugin->shared_location, 0, 0,
736                                 start, length, plugin->plugin_type);
737         result->copy_from(plugin);
738         result->shift(position - plugin->startproject);
739
740 // Clear new plugin from old set
741         plugin->plugin_set->clear(plugin->startproject,
742                 plugin->startproject + plugin->length,
743                 edl->session->autos_follow_edits);
744
745         source_track->optimize();
746 }
747
748 void Tracks::move_effect(Plugin *plugin, PluginSet *plugin_set, int64_t position)
749 {
750 // src/dest track must be the same
751 // replace plugin in source plugin_set with silence
752         PluginSet *src_plugin_set = plugin->plugin_set;
753         Plugin *silent = new Plugin(edl, src_plugin_set, "");
754         silent->startproject = plugin->startproject;
755         silent->length = plugin->length;
756         src_plugin_set->insert_after(plugin, silent);
757         src_plugin_set->remove_pointer(plugin);
758 // truncate previous plugin
759         Plugin *dest = (Plugin *)plugin_set->editof(position, PLAY_FORWARD, 0);
760 // add plugin after dest
761         plugin_set->insert_after(dest, plugin);
762         if( dest ) {
763                 dest->length = position - dest->startproject;
764                 if( dest->length < 0 ) dest->length = 0;
765         }
766 // update plugin position
767         plugin->startproject = position;
768         plugin->plugin_set = plugin_set;
769         plugin->edits = plugin_set;
770         src_plugin_set->track->optimize();
771 }
772
773 int Tracks::concatenate_tracks(int edit_plugins, int edit_autos)
774 {
775         Track *output_track, *first_output_track, *input_track;
776         int i, data_type = TRACK_AUDIO;
777         double output_start;
778         int result = 0;
779
780 // Relocate tracks
781         for(i = 0; i < 2; i++)
782         {
783 // Get first output track
784                 for(output_track = first;
785                         output_track;
786                         output_track = output_track->next)
787                         if(output_track->data_type == data_type &&
788                                 output_track->record) break;
789
790                 first_output_track = output_track;
791
792 // Get first input track
793                 for(input_track = first;
794                         input_track;
795                         input_track = input_track->next)
796                 {
797                         if(input_track->data_type == data_type &&
798                                 input_track->play &&
799                                 !input_track->record) break;
800                 }
801
802
803                 if(output_track && input_track)
804                 {
805 // Transfer input track to end of output track one at a time
806                         while(input_track)
807                         {
808                                 output_start = output_track->get_length();
809                                 output_track->insert_track(input_track,
810                                         output_start,
811                                         0,
812                                         edit_plugins,
813                                         edit_autos,
814                                         0);
815
816 // Get next source and destination
817                                 for(input_track = input_track->next;
818                                         input_track;
819                                         input_track = input_track->next)
820                                 {
821
822                                         if(input_track->data_type == data_type &&
823                                                 !input_track->record &&
824                                                 input_track->play) break;
825                                 }
826
827                                 for(output_track = output_track->next;
828                                         output_track;
829                                         output_track = output_track->next)
830                                 {
831                                         if(output_track->data_type == data_type &&
832                                                 output_track->record) break;
833                                 }
834
835                                 if(!output_track)
836                                 {
837                                         output_track = first_output_track;
838                                 }
839                         }
840                         result = 1;
841                 }
842
843                 if(data_type == TRACK_AUDIO) data_type = TRACK_VIDEO;
844         }
845
846         return result;
847 }
848
849 int Tracks::delete_all_tracks()
850 {
851         while(last) delete last;
852         return 0;
853 }
854
855
856 void Tracks::change_modules(int old_location, int new_location, int do_swap)
857 {
858         for(Track* current = first ; current; current = current->next)
859         {
860                 current->change_modules(old_location, new_location, do_swap);
861         }
862 }
863
864 void Tracks::change_plugins(SharedLocation &old_location, SharedLocation &new_location, int do_swap)
865 {
866         for(Track* current = first ; current; current = current->next)
867         {
868                 current->change_plugins(old_location, new_location, do_swap);
869         }
870 }
871
872
873
874 // =========================================== EDL editing
875
876
877 int Tracks::copy(double start,
878         double end,
879         int all,
880         FileXML *file,
881         const char *output_path)
882 {
883 // nothing selected
884         if(start == end && !all) return 1;
885
886         Track* current;
887
888         for(current = first;
889                 current;
890                 current = NEXT)
891         {
892                 if(current->record || all)
893                 {
894                         current->copy(start, end, file,output_path);
895                 }
896         }
897
898         return 0;
899 }
900
901
902
903 int Tracks::move_track_up(Track *track)
904 {
905         Track *next_track = track->previous;
906         if(!next_track) next_track = last;
907
908         change_modules(number_of(track), number_of(next_track), 1);
909
910 // printf("Tracks::move_track_up 1 %p %p\n", track, next_track);
911 // int count = 0;
912 // for(Track *current = first; current && count < 5; current = NEXT, count++)
913 //      printf("Tracks::move_track_up %p %p %p\n", current->previous, current, current->next);
914 // printf("Tracks::move_track_up 2\n");
915 //
916         swap(track, next_track);
917
918 // count = 0;
919 // for(Track *current = first; current && count < 5; current = NEXT, count++)
920 //      printf("Tracks::move_track_up %p %p %p\n", current->previous, current, current->next);
921 // printf("Tracks::move_track_up 3\n");
922
923         return 0;
924 }
925
926 int Tracks::move_track_down(Track *track)
927 {
928         Track *next_track = track->next;
929         if(!next_track) next_track = first;
930
931         change_modules(number_of(track), number_of(next_track), 1);
932         swap(track, next_track);
933         return 0;
934 }
935
936
937 int Tracks::move_tracks_up()
938 {
939         Track *track, *next_track;
940         int result = 0;
941
942         for(track = first;
943                 track;
944                 track = next_track)
945         {
946                 next_track = track->next;
947
948                 if(track->record)
949                 {
950                         if(track->previous)
951                         {
952                                 change_modules(number_of(track->previous), number_of(track), 1);
953
954                                 swap(track->previous, track);
955                                 result = 1;
956                         }
957                 }
958         }
959
960         return result;
961 }
962
963 int Tracks::move_tracks_down()
964 {
965         Track *track, *previous_track;
966         int result = 0;
967
968         for(track = last;
969                 track;
970                 track = previous_track)
971         {
972                 previous_track = track->previous;
973
974                 if(track->record)
975                 {
976                         if(track->next)
977                         {
978                                 change_modules(number_of(track), number_of(track->next), 1);
979
980                                 swap(track, track->next);
981                                 result = 1;
982                         }
983                 }
984         }
985
986         return result;
987 }
988
989
990
991 void Tracks::paste_audio_transition(PluginServer *server)
992 {
993         for(Track *current = first; current; current = NEXT)
994         {
995                 if(current->data_type == TRACK_AUDIO &&
996                         current->record)
997                 {
998                         int64_t position = current->to_units(
999                                 edl->local_session->get_selectionstart(), 0);
1000                         Edit *current_edit = current->edits->editof(position,
1001                                 PLAY_FORWARD,
1002                                 0);
1003                         if( !current_edit && position == current->edits->length() ) {
1004                                 double length = edl->session->default_transition_length;
1005                                 int64_t units = current->to_units(length, 1);
1006                                 current_edit = current->edits->create_silence(position, position+units);
1007                         }
1008                         if(current_edit)
1009                         {
1010                                 paste_transition(server, current_edit);
1011                         }
1012                 }
1013         }
1014 }
1015
1016 void Tracks::paste_automation(double selectionstart,
1017         FileXML *file,
1018         int default_only,
1019         int active_only,
1020         int typeless)
1021 {
1022         Track* current_track = 0;
1023         Track* current_atrack = 0;
1024         Track* current_vtrack = 0;
1025         Track* dst_track = 0;
1026         int src_type;
1027         int result = 0;
1028         double length;
1029         double frame_rate = edl->session->frame_rate;
1030         int64_t sample_rate = edl->session->sample_rate;
1031         char string[BCTEXTLEN];
1032         string[0] = 0;
1033
1034 // Search for start
1035         do{
1036           result = file->read_tag();
1037         }while(!result &&
1038                 !file->tag.title_is("AUTO_CLIPBOARD"));
1039
1040         if(!result)
1041         {
1042                 length = file->tag.get_property("LENGTH", 0);
1043                 frame_rate = file->tag.get_property("FRAMERATE", frame_rate);
1044                 sample_rate = file->tag.get_property("SAMPLERATE", sample_rate);
1045
1046
1047                 do
1048                 {
1049                         result = file->read_tag();
1050
1051                         if(!result)
1052                         {
1053                                 if(file->tag.title_is("/AUTO_CLIPBOARD"))
1054                                 {
1055                                         result = 1;
1056                                 }
1057                                 else
1058                                 if(file->tag.title_is("TRACK"))
1059                                 {
1060                                         file->tag.get_property("TYPE", string);
1061                                         if(!strcmp(string, "AUDIO"))
1062                                         {
1063                                                 src_type = TRACK_AUDIO;
1064                                         }
1065                                         else
1066                                         {
1067                                                 src_type = TRACK_VIDEO;
1068                                         }
1069
1070 // paste to any media type
1071                                         if(typeless)
1072                                         {
1073                                                 if(!current_track) current_track = first;
1074                                                 while(current_track && !current_track->record)
1075                                                         current_track = current_track->next;
1076                                                 dst_track = current_track;
1077                                         }
1078                                         else
1079                                         if(!strcmp(string, "AUDIO"))
1080                                         {
1081 // Get next audio track
1082                                                 if(!current_atrack)
1083                                                         current_atrack = first;
1084                                                 else
1085                                                         current_atrack = current_atrack->next;
1086
1087                                                 while(current_atrack &&
1088                                                         (current_atrack->data_type != TRACK_AUDIO ||
1089                                                         !current_atrack->record))
1090                                                         current_atrack = current_atrack->next;
1091                                                 dst_track = current_atrack;
1092                                         }
1093                                         else
1094                                         {
1095 // Get next video track
1096                                                 if(!current_vtrack)
1097                                                         current_vtrack = first;
1098                                                 else
1099                                                         current_vtrack = current_vtrack->next;
1100
1101                                                 while(current_vtrack &&
1102                                                         (current_vtrack->data_type != TRACK_VIDEO ||
1103                                                         !current_vtrack->record))
1104                                                         current_vtrack = current_vtrack->next;
1105
1106                                                 dst_track = current_vtrack;
1107                                         }
1108
1109                                         if(dst_track)
1110                                         {
1111                                                 double frame_rate2 = frame_rate;
1112                                                 double sample_rate2 = sample_rate;
1113
1114                                                 if(src_type != dst_track->data_type)
1115                                                 {
1116                                                         frame_rate2 = sample_rate;
1117                                                         sample_rate2 = frame_rate;
1118                                                 }
1119
1120                                                 dst_track->paste_automation(selectionstart,
1121                                                         length,
1122                                                         frame_rate2,
1123                                                         sample_rate2,
1124                                                         file,
1125                                                         default_only,
1126                                                         active_only);
1127                                         }
1128                                 }
1129                         }
1130                 }while(!result);
1131         }
1132 }
1133
1134 // int Tracks::paste_default_keyframe(FileXML *file)
1135 // {
1136 //      paste_automation(0, file, 1, 0);
1137 //      return 0;
1138 // }
1139
1140 void Tracks::paste_transition(PluginServer *server, Edit *dest_edit)
1141 {
1142         dest_edit->insert_transition(server->title);
1143 }
1144
1145 void Tracks::paste_video_transition(PluginServer *server, int first_track)
1146 {
1147         for(Track *current = first; current; current = NEXT)
1148         {
1149                 if(current->data_type == TRACK_VIDEO &&
1150                         current->record)
1151                 {
1152                         int64_t position = current->to_units(
1153                                 edl->local_session->get_selectionstart(), 0);
1154                         Edit *current_edit = current->edits->editof(position,
1155                                 PLAY_FORWARD,
1156                                 0);
1157                         if( !current_edit && position == current->edits->length() ) {
1158                                 double length = edl->session->default_transition_length;
1159                                 int64_t units = current->to_units(length, 1);
1160                                 current_edit = current->edits->create_silence(position, position+units);
1161                         }
1162                         if(current_edit)
1163                         {
1164                                 paste_transition(server, current_edit);
1165                         }
1166                         if(first_track) break;
1167                 }
1168         }
1169 }
1170
1171
1172 int Tracks::paste_silence(double start,
1173         double end,
1174         int edit_plugins,
1175         int edit_autos)
1176 {
1177         Track* current_track;
1178
1179         for(current_track = first;
1180                 current_track;
1181                 current_track = current_track->next)
1182         {
1183                 if(current_track->record)
1184                 {
1185                         current_track->paste_silence(start,
1186                                 end,
1187                                 edit_plugins,
1188                                 edit_autos);
1189                 }
1190         }
1191         return 0;
1192 }
1193
1194
1195
1196 int Tracks::select_auto(int cursor_x, int cursor_y)
1197 {
1198         int result = 0;
1199         for(Track* current = first; current && !result; current = NEXT) { result = current->select_auto(&auto_conf, cursor_x, cursor_y); }
1200         return result;
1201 }
1202
1203 int Tracks::move_auto(int cursor_x, int cursor_y, int shift_down)
1204 {
1205         int result = 0;
1206
1207         for(Track* current = first; current && !result; current = NEXT)
1208         {
1209                 result = current->move_auto(&auto_conf, cursor_x, cursor_y, shift_down);
1210         }
1211         return 0;
1212 }
1213
1214 int Tracks::modify_edithandles(double &oldposition,
1215         double &newposition,
1216         int currentend,
1217         int handle_mode,
1218         int edit_labels,
1219         int edit_plugins,
1220         int edit_autos)
1221 {
1222         Track *current;
1223
1224         for(current = first; current; current = NEXT)
1225         {
1226                 if(current->record)
1227                 {
1228                         current->modify_edithandles(oldposition,
1229                                 newposition,
1230                                 currentend,
1231                                 handle_mode,
1232                                 edit_labels,
1233                                 edit_plugins,
1234                                 edit_autos);
1235                 }
1236         }
1237         return 0;
1238 }
1239
1240 int Tracks::modify_pluginhandles(double &oldposition,
1241         double &newposition,
1242         int currentend,
1243         int handle_mode,
1244         int edit_labels,
1245         int edit_autos,
1246         Edits *trim_edits)
1247 {
1248         Track *current;
1249
1250         for(current = first; current; current = NEXT)
1251         {
1252                 if(current->record)
1253                 {
1254                         current->modify_pluginhandles(oldposition,
1255                                 newposition,
1256                                 currentend,
1257                                 handle_mode,
1258                                 edit_labels,
1259                                 edit_autos,
1260                                 trim_edits);
1261                 }
1262         }
1263         return 0;
1264 }
1265
1266
1267
1268 int Tracks::purge_asset(Asset *asset)
1269 {
1270         Track *current_track;
1271         int result = 0;
1272
1273         for(current_track = first; current_track; current_track = current_track->next)
1274         {
1275                 result += current_track->purge_asset(asset);
1276         }
1277         return result;
1278 }
1279
1280 int Tracks::asset_used(Asset *asset)
1281 {
1282         Track *current_track;
1283         int result = 0;
1284
1285         for(current_track = first; current_track; current_track = current_track->next)
1286         {
1287                 result += current_track->asset_used(asset);
1288         }
1289         return result;
1290 }
1291
1292 int Tracks::scale_time(float rate_scale, int ignore_record, int scale_edits, int scale_autos, int64_t start, int64_t end)
1293 {
1294         Track *current_track;
1295
1296         for(current_track = first;
1297                 current_track;
1298                 current_track = current_track->next)
1299         {
1300                 if((current_track->record || ignore_record) &&
1301                         current_track->data_type == TRACK_VIDEO)
1302                 {
1303                         current_track->scale_time(rate_scale, scale_edits, scale_autos, start, end);
1304                 }
1305         }
1306         return 0;
1307 }
1308