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