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