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