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