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