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