initial commit
[goodguy/history.git] / cinelerra-5.0 / cinelerra / track.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 "asset.h"
22 #include "autoconf.h"
23 #include "automation.h"
24 #include "bcsignals.h"
25 #include "clip.h"
26 #include "edit.h"
27 #include "edits.h"
28 #include "edl.h"
29 #include "edlsession.h"
30 #include "filexml.h"
31 #include "floatauto.h"
32 #include "floatautos.h"
33 #include "format.inc"
34 #include "keyframe.h"
35 #include "labels.h"
36 #include "localsession.h"
37 #include "module.h"
38 #include "patch.h"
39 #include "patchbay.h"
40 #include "plugin.h"
41 #include "pluginset.h"
42 #include "mainsession.h"
43 #include "theme.h"
44 #include "intautos.h"
45 #include "track.h"
46 #include "trackcanvas.h"
47 #include "tracks.h"
48 #include "transition.h"
49 #include "transportque.inc"
50 #include "vedit.h"
51 #include "vframe.h"
52 #include <string.h>
53
54
55 Track::Track(EDL *edl, Tracks *tracks) : ListItem<Track>()
56 {
57         this->edl = edl;
58         this->tracks = tracks;
59         y_pixel = 0;
60         expand_view = 0;
61         draw = 1;
62         gang = 1;
63         title[0] = 0;
64         record = 1;
65         play = 1;
66         nudge = 0;
67         track_w = edl->session->output_w;
68         track_h = edl->session->output_h;
69         id = EDL::next_id();
70 }
71
72 Track::~Track()
73 {
74         delete automation;
75         delete edits;
76         plugin_set.remove_all_objects();
77 }
78
79 void Track::create_objects()
80 {
81 }
82
83
84 int Track::copy_settings(Track *track)
85 {
86         this->expand_view = track->expand_view;
87         this->draw = track->draw;
88         this->gang = track->gang;
89         this->record = track->record;
90         this->nudge = track->nudge;
91         this->play = track->play;
92         this->track_w = track->track_w;
93         this->track_h = track->track_h;
94         strcpy(this->title, track->title);
95         return 0;
96 }
97
98 int Track::get_id()
99 {
100         return id;
101 }
102
103
104 int Track::load_defaults(BC_Hash *defaults)
105 {
106         return 0;
107 }
108
109 void Track::equivalent_output(Track *track, double *result)
110 {
111         if(data_type != track->data_type ||
112                 track_w != track->track_w ||
113                 track_h != track->track_h ||
114                 play != track->play ||
115                 nudge != track->nudge)
116                 *result = 0;
117
118 // Convert result to track units
119         int64_t result2 = -1;
120         automation->equivalent_output(track->automation, &result2);
121         edits->equivalent_output(track->edits, &result2);
122
123         int plugin_sets = MIN(plugin_set.total, track->plugin_set.total);
124 // Test existing plugin sets
125         for(int i = 0; i < plugin_sets; i++)
126         {
127                 plugin_set.values[i]->equivalent_output(
128                         track->plugin_set.values[i], 
129                         &result2);
130         }
131
132 // New EDL has more plugin sets.  Get starting plugin in new plugin sets
133         for(int i = plugin_sets; i < plugin_set.total; i++)
134         {
135                 Plugin *current = plugin_set.values[i]->get_first_plugin();
136                 if(current)
137                 {
138                         if(result2 < 0 || current->startproject < result2)
139                                 result2 = current->startproject;
140                 }
141         }
142
143 // New EDL has fewer plugin sets.  Get starting plugin in old plugin set
144         for(int i = plugin_sets; i < track->plugin_set.total; i++)
145         {
146                 Plugin *current = track->plugin_set.values[i]->get_first_plugin();
147                 if(current)
148                 {
149                         if(result2 < 0 || current->startproject < result2)
150                                 result2 = current->startproject;
151                 }
152         }
153
154 // Number of plugin sets differs but somehow we didn't find the start of the
155 // change.  Assume 0
156         if(track->plugin_set.total != plugin_set.total && result2 < 0)
157                 result2 = 0;
158
159         if(result2 >= 0 && 
160                 (*result < 0 || from_units(result2) < *result))
161                 *result = from_units(result2);
162 }
163
164
165 int Track::is_synthesis(int64_t position, 
166         int direction)
167 {
168         int is_synthesis = 0;
169         for(int i = 0; i < plugin_set.total; i++)
170         {
171                 Plugin *plugin = get_current_plugin(position,
172                         i,
173                         direction,
174                         0,
175                         0);
176                 if(plugin)
177                 {
178 // Assume data from a shared track is synthesized
179                         if(plugin->plugin_type == PLUGIN_SHAREDMODULE) 
180                                 is_synthesis = 1;
181                         else
182                                 is_synthesis = plugin->is_synthesis(position, 
183                                         direction);
184
185 //printf("Track::is_synthesis %d %d\n", __LINE__, is_synthesis);
186                         if(is_synthesis) break;
187                 }
188         }
189         return is_synthesis;
190 }
191
192 void Track::copy_from(Track *track)
193 {
194         copy_settings(track);
195         edits->copy_from(track->edits);
196         for(int i = 0; i < this->plugin_set.total; i++)
197                 delete this->plugin_set.values[i];
198         this->plugin_set.remove_all_objects();
199
200         for(int i = 0; i < track->plugin_set.total; i++)
201         {
202                 PluginSet *new_plugin_set = plugin_set.append(new PluginSet(edl, this));
203                 new_plugin_set->copy_from(track->plugin_set.values[i]);
204         }
205         automation->copy_from(track->automation);
206         this->track_w = track->track_w;
207         this->track_h = track->track_h;
208 }
209
210 Track& Track::operator=(Track& track)
211 {
212 printf("Track::operator= 1\n");
213         copy_from(&track);
214         return *this;
215 }
216
217 int Track::vertical_span(Theme *theme)
218 {
219         int result = 0;
220         if(expand_view)
221                 result = edl->local_session->zoom_track + 
222                         plugin_set.total * 
223                         theme->get_image("plugin_bg_data")->get_h();
224         else
225                 result = edl->local_session->zoom_track;
226
227         if(edl->session->show_titles)
228                 result += theme->get_image("title_bg_data")->get_h();
229
230         return result;
231 }
232
233 double Track::get_length()
234 {
235         double total_length = 0;
236         double length = 0;
237
238 // Test edits
239         if(edits->last)
240         {
241                 length = from_units(edits->last->startproject + edits->last->length);
242                 if(length > total_length) total_length = length;
243         }
244
245 // Test plugins
246         for(int i = 0; i < plugin_set.total; i++)
247         {
248                 if(plugin_set.values[i]->last)
249                 {
250                         length = from_units(plugin_set.values[i]->last->startproject + 
251                                 plugin_set.values[i]->last->length);
252                         if(length > total_length) total_length = length;
253                 }
254         }
255
256 // Test keyframes
257         length = from_units(automation->get_length());
258         if(length > total_length) total_length = length;
259         
260
261         return total_length;
262 }
263
264 int Track::has_speed()
265 {
266         FloatAutos *autos = (FloatAutos*)automation->autos[AUTOMATION_SPEED];
267         if(autos)
268         {
269                 if(autos->first)
270                 {
271                         for(FloatAuto *current = (FloatAuto*)autos->first;
272                                 current;
273                                 current = (FloatAuto*)current->next)
274                         {
275                                 if(!EQUIV(current->value, 1.0) ||
276                                         !EQUIV(current->control_in_value, 0.0) ||
277                                         !EQUIV(current->control_out_value, 0.0))
278                                 {
279                                         return 1;
280                                 }
281                         }
282                 }
283         }
284         
285         return 0;
286 }
287
288
289
290 void Track::get_source_dimensions(double position, int &w, int &h)
291 {
292         int64_t native_position = to_units(position, 0);
293         for(Edit *current = edits->first; current; current = NEXT)
294         {
295                 if(current->startproject <= native_position &&
296                         current->startproject + current->length > native_position &&
297                         current->asset)
298                 {
299                         w = current->asset->width;
300                         h = current->asset->height;
301                         return;
302                 }
303         }
304 }
305
306
307 int64_t Track::horizontal_span()
308 {
309         return (int64_t)(get_length() * 
310                 edl->session->sample_rate / 
311                 edl->local_session->zoom_sample + 
312                 0.5);
313 }
314
315
316 int Track::load(FileXML *file, int track_offset, uint32_t load_flags)
317 {
318         int result = 0;
319         int current_plugin = 0;
320
321
322         record = file->tag.get_property("RECORD", record);
323         play = file->tag.get_property("PLAY", play);
324         gang = file->tag.get_property("GANG", gang);
325         draw = file->tag.get_property("DRAW", draw);
326         nudge = file->tag.get_property("NUDGE", nudge);
327         expand_view = file->tag.get_property("EXPAND", expand_view);
328         track_w = file->tag.get_property("TRACK_W", track_w);
329         track_h = file->tag.get_property("TRACK_H", track_h);
330
331         load_header(file, load_flags);
332
333         do{
334                 result = file->read_tag();
335
336                 if(!result)
337                 {
338                         if(file->tag.title_is("/TRACK"))
339                         {
340                                 result = 1;
341                         }
342                         else
343                         if(file->tag.title_is("TITLE"))
344                         {
345                                 file->read_text_until("/TITLE", title, BCTEXTLEN);
346                         }
347                         else
348                         if(load_flags && automation->load(file)
349                         /* strstr(file->tag.get_title(), "AUTOS") */)
350                         {
351                                 ;
352                         }
353                         else
354                         if(file->tag.title_is("EDITS"))
355                         {
356                                 if(load_flags & LOAD_EDITS)
357                                         edits->load(file, track_offset);
358                         }
359                         else
360                         if(file->tag.title_is("PLUGINSET"))
361                         {
362                                 if(load_flags & LOAD_EDITS)
363                                 {
364                                         PluginSet *plugin_set = new PluginSet(edl, this);
365                                         this->plugin_set.append(plugin_set);
366                                         plugin_set->load(file, load_flags);
367                                 }
368                                 else
369                                 if(load_flags & LOAD_AUTOMATION)
370                                 {
371                                         if(current_plugin < this->plugin_set.total)
372                                         {
373                                                 PluginSet *plugin_set = this->plugin_set.values[current_plugin];
374                                                 plugin_set->load(file, load_flags);
375                                                 current_plugin++;
376                                         }
377                                 }
378                         }
379                         else
380                                 load_derived(file, load_flags);
381                 }
382         }while(!result);
383
384
385
386         return 0;
387 }
388
389 void Track::insert_asset(Asset *asset, 
390         EDL *nested_edl,
391         double length, 
392         double position, 
393         int track_number)
394 {
395         edits->insert_asset(asset, 
396                 nested_edl,
397                 to_units(length, 1), 
398                 to_units(position, 0), 
399                 track_number);
400 }
401
402 // Insert data
403
404 // Default keyframes: We don't replace default keyframes in pasting but
405 // when inserting the first EDL of a load operation we need to replace
406 // the default keyframes.
407
408 // Plugins:  This is an arbitrary behavior
409 //
410 // 1) No plugin in source track: Paste silence into destination
411 // plugin sets.
412 // 2) Plugin in source track: plugin in source track is inserted into
413 // existing destination track plugin sets, new sets being added when
414 // necessary.
415
416 void Track::insert_track(Track *track, 
417         double position, 
418         int replace_default,
419         int edit_plugins,
420         int edit_autos,
421         double edl_length)
422 {
423 // Calculate minimum length of data to pad.
424         int64_t min_length = to_units(
425                 MAX(edl_length, track->get_length()),
426                 1);
427 //printf("Track::insert_track %d %s " _LD "\n", __LINE__, title, min_length);
428
429 // Decide whether to copy settings based on load_mode
430         if(replace_default) copy_settings(track);
431
432         edits->insert_edits(track->edits, 
433                 to_units(position, 0),
434                 min_length,
435                 edit_autos);
436
437         if(edit_plugins)
438                 insert_plugin_set(track, 
439                         to_units(position, 0),
440                         min_length,
441                         edit_autos);
442
443         if(edit_autos)
444                 automation->insert_track(track->automation, 
445                         to_units(position, 0), 
446                         min_length,
447                         replace_default);
448
449         optimize();
450
451 }
452
453 // Called by insert_track
454 void Track::insert_plugin_set(Track *track, 
455         int64_t position,
456         int64_t min_length,
457         int edit_autos)
458 {
459 // Extend plugins if no incoming plugins
460         if(!track->plugin_set.total)
461         {
462                 shift_effects(position, 
463                         min_length,
464                         edit_autos);
465         }
466         else
467         for(int i = 0; i < track->plugin_set.total; i++)
468         {
469                 if(i >= plugin_set.total)
470                         plugin_set.append(new PluginSet(edl, this));
471
472                 plugin_set.values[i]->insert_edits(track->plugin_set.values[i], 
473                         position,
474                         min_length,
475                         edit_autos);
476         }
477 }
478
479
480 Plugin* Track::insert_effect(const char *title, 
481                 SharedLocation *shared_location, 
482                 KeyFrame *default_keyframe,
483                 PluginSet *plugin_set,
484                 double start,
485                 double length,
486                 int plugin_type)
487 {
488         if(!plugin_set)
489         {
490                 plugin_set = new PluginSet(edl, this);
491                 this->plugin_set.append(plugin_set);
492         }
493
494         Plugin *plugin = 0;
495
496 // Position is identical to source plugin
497         if(plugin_type == PLUGIN_SHAREDPLUGIN)
498         {
499                 Track *source_track = tracks->get_item_number(shared_location->module);
500                 if(source_track)
501                 {
502                         Plugin *source_plugin = source_track->get_current_plugin(
503                                 edl->local_session->get_selectionstart(), 
504                                 shared_location->plugin, 
505                                 PLAY_FORWARD, 
506                                 1,
507                                 0);
508
509 // From an attach operation
510                         if(source_plugin)
511                         {
512                                 plugin = plugin_set->insert_plugin(title, 
513                                         source_plugin->startproject, 
514                                         source_plugin->length,
515                                         plugin_type, 
516                                         shared_location,
517                                         default_keyframe,
518                                         1);
519                         }
520                         else
521 // From a drag operation
522                         {
523                                 plugin = plugin_set->insert_plugin(title, 
524                                         to_units(start, 0), 
525                                         to_units(length, 0),
526                                         plugin_type, 
527                                         shared_location,
528                                         default_keyframe,
529                                         1);
530                         }
531                 }
532         }
533         else
534         {
535 // This should be done in the caller
536                 if(EQUIV(length, 0))
537                 {
538                         if(edl->local_session->get_selectionend() > 
539                                 edl->local_session->get_selectionstart())
540                         {
541                                 start = edl->local_session->get_selectionstart();
542                                 length = edl->local_session->get_selectionend() - start;
543                         }
544                         else
545                         {
546                                 start = 0;
547                                 length = get_length();
548                         }
549                 }
550 //printf("Track::insert_effect %f %f %d %d\n", start, length, to_units(start, 0), 
551 //                      to_units(length, 0));
552
553                 plugin = plugin_set->insert_plugin(title, 
554                         to_units(start, 0), 
555                         to_units(length, 0),
556                         plugin_type, 
557                         shared_location,
558                         default_keyframe,
559                         1);
560         }
561 //printf("Track::insert_effect 2 %f %f\n", start, length);
562
563         expand_view = 1;
564         return plugin;
565 }
566
567 void Track::move_plugins_up(PluginSet *plugin_set)
568 {
569         for(int i = 0; i < this->plugin_set.total; i++)
570         {
571                 if(this->plugin_set.values[i] == plugin_set)
572                 {
573                         if(i == 0) break;
574
575                         PluginSet *temp = this->plugin_set.values[i - 1];
576                         this->plugin_set.values[i - 1] = this->plugin_set.values[i];
577                         this->plugin_set.values[i] = temp;
578                         break;
579                 }
580         }
581 }
582
583 void Track::move_plugins_down(PluginSet *plugin_set)
584 {
585         for(int i = 0; i < this->plugin_set.total; i++)
586         {
587                 if(this->plugin_set.values[i] == plugin_set)
588                 {
589                         if(i == this->plugin_set.total - 1) break;
590
591                         PluginSet *temp = this->plugin_set.values[i + 1];
592                         this->plugin_set.values[i + 1] = this->plugin_set.values[i];
593                         this->plugin_set.values[i] = temp;
594                         break;
595                 }
596         }
597 }
598
599
600 void Track::remove_asset(Indexable *asset)
601 {
602         for(Edit *edit = edits->first; edit; edit = edit->next)
603         {
604                 if(asset->is_asset && 
605                         edit->asset && 
606                         edit->asset == (Asset*)asset)
607                 {
608                         edit->asset = 0;
609                 }
610                 else
611                 if(!asset->is_asset && 
612                         edit->nested_edl && 
613                         edit->nested_edl == (EDL*)asset)
614                 {
615                         edit->nested_edl = 0;
616                 }
617         }
618         optimize();
619 }
620
621 void Track::remove_pluginset(PluginSet *plugin_set)
622 {
623         int i;
624         for(i = 0; i < this->plugin_set.total; i++)
625                 if(plugin_set == this->plugin_set.values[i]) break;
626
627         this->plugin_set.remove_object(plugin_set);
628         for(i++ ; i < this->plugin_set.total; i++)
629         {
630                 SharedLocation old_location, new_location;
631                 new_location.module = old_location.module = tracks->number_of(this);
632                 old_location.plugin = i;
633                 new_location.plugin = i - 1;
634                 tracks->change_plugins(old_location, new_location, 0);
635         }
636 }
637
638 void Track::shift_keyframes(int64_t position, int64_t length)
639 {
640         automation->paste_silence(position, 
641                 position + length);
642 // Effect keyframes are shifted in shift_effects
643 }
644
645 void Track::shift_effects(int64_t position, int64_t length, int edit_autos)
646 {
647         for(int i = 0; i < plugin_set.total; i++)
648         {
649                 plugin_set.values[i]->shift_effects(position, 
650                         length,
651                         edit_autos);
652         }
653 }
654
655 void Track::detach_effect(Plugin *plugin)
656 {
657 //printf("Track::detach_effect 1\n");           
658         for(int i = 0; i < plugin_set.total; i++)
659         {
660                 PluginSet *plugin_set = this->plugin_set.values[i];
661                 for(Plugin *dest = (Plugin*)plugin_set->first; 
662                         dest; 
663                         dest = (Plugin*)dest->next)
664                 {
665                         if(dest == plugin)
666                         {
667                                 int64_t start = plugin->startproject;
668                                 int64_t end = plugin->startproject + plugin->length;
669
670                                 plugin_set->clear(start, end, 1);
671                                 plugin_set->paste_silence(start, end);
672
673 // Delete 0 length pluginsets   
674                                 plugin_set->optimize();
675 //printf("Track::detach_effect 2 %d\n", plugin_set->length());
676                                 if(!plugin_set->length()) 
677                                         this->plugin_set.remove_object(plugin_set);
678
679                                 return;
680                         }
681                 }
682         }
683 }
684
685 void Track::resample(double old_rate, double new_rate)
686 {
687         edits->resample(old_rate, new_rate);
688         automation->resample(old_rate, new_rate);
689         for(int i = 0; i < plugin_set.total; i++)
690                 plugin_set.values[i]->resample(old_rate, new_rate);
691         nudge = (int64_t)(nudge * new_rate / old_rate);
692 }
693
694 void Track::detach_shared_effects(int module)
695 {
696         for(int i = 0; i < plugin_set.size(); i++)
697         {
698                 PluginSet *plugin_set = this->plugin_set.get(i);
699                 for(Plugin *dest = (Plugin*)plugin_set->first; 
700                         dest; 
701                         )
702                 {
703                         if ((dest->plugin_type == PLUGIN_SHAREDPLUGIN ||
704                                 dest->plugin_type == PLUGIN_SHAREDMODULE)
705                             &&
706                                 dest->shared_location.module == module)
707                         {
708                                 int64_t start = dest->startproject;
709                                 int64_t end = dest->startproject + dest->length;
710
711                                 plugin_set->clear(start, end, 1);
712                                 plugin_set->paste_silence(start, end);
713
714 // Delete 0 length pluginsets
715                                 plugin_set->optimize();
716                                 if(!plugin_set->length())  
717                                 {
718                                         this->plugin_set.remove_object_number(i);
719                                         dest = 0;
720                                         --i;
721                                 }
722                                 
723                         }
724
725                         if(dest) dest = (Plugin*)dest->next;
726                 }
727         }
728 }
729
730
731 void Track::optimize()
732 {
733         edits->optimize();
734         for(int i = 0; i < plugin_set.total; i++)
735         {
736                 plugin_set.values[i]->optimize();
737 //printf("Track::optimize %d\n", plugin_set.values[i]->total());
738                 if(plugin_set.values[i]->total() <= 0)
739                 {
740                         remove_pluginset(plugin_set.values[i]);
741                         i--;
742                 }
743         }
744 }
745
746 Plugin* Track::get_current_plugin(double position, 
747         int plugin_set, 
748         int direction, 
749         int convert_units,
750         int use_nudge)
751 {
752         Plugin *current;
753         if(convert_units) position = to_units(position, 0);
754         if(use_nudge) position += nudge;
755         
756         if(plugin_set >= this->plugin_set.total || plugin_set < 0) return 0;
757
758 //printf("Track::get_current_plugin 1 %d %d %d\n", position, this->plugin_set.total, direction);
759         if(direction == PLAY_FORWARD)
760         {
761                 for(current = (Plugin*)this->plugin_set.values[plugin_set]->last; 
762                         current; 
763                         current = (Plugin*)PREVIOUS)
764                 {
765 // printf("Track::get_current_plugin 2 %d %ld %ld\n", 
766 // current->startproject, 
767 // current->startproject + current->length, 
768 // position);
769                         if(current->startproject <= position && 
770                                 current->startproject + current->length > position)
771                         {
772                                 return current;
773                         }
774                 }
775         }
776         else
777         if(direction == PLAY_REVERSE)
778         {
779                 for(current = (Plugin*)this->plugin_set.values[plugin_set]->first; 
780                         current; 
781                         current = (Plugin*)NEXT)
782                 {
783                         if(current->startproject < position && 
784                                 current->startproject + current->length >= position)
785                         {
786                                 return current;
787                         }
788                 }
789         }
790
791         return 0;
792 }
793
794 Plugin* Track::get_current_transition(double position, 
795         int direction, 
796         int convert_units,
797         int use_nudge)
798 {
799         Edit *current;
800         Plugin *result = 0;
801         if(convert_units) position = to_units(position, 0);
802         if(use_nudge) position += nudge;
803
804         if(direction == PLAY_FORWARD)
805         {
806                 for(current = edits->last; current; current = PREVIOUS)
807                 {
808                         if(current->startproject <= position && current->startproject + current->length > position)
809                         {
810 //printf("Track::get_current_transition %p\n", current->transition);
811                                 if(current->transition && position < current->startproject + current->transition->length)
812                                 {
813                                         result = current->transition;
814                                         break;
815                                 }
816                         }
817                 }
818         }
819         else
820         if(direction == PLAY_REVERSE)
821         {
822                 for(current = edits->first; current; current = NEXT)
823                 {
824                         if(current->startproject < position && current->startproject + current->length >= position)
825                         {
826                                 if(current->transition && position <= current->startproject + current->transition->length)
827                                 {
828                                         result = current->transition;
829                                         break;
830                                 }
831                         }
832                 }
833         }
834
835         return result;
836 }
837
838 void Track::synchronize_params(Track *track)
839 {
840         for(Edit *this_edit = edits->first, *that_edit = track->edits->first;
841                 this_edit && that_edit;
842                 this_edit = this_edit->next, that_edit = that_edit->next)
843         {
844                 this_edit->synchronize_params(that_edit);
845         }
846
847         for(int i = 0; i < plugin_set.total && i < track->plugin_set.total; i++)
848                 plugin_set.values[i]->synchronize_params(track->plugin_set.values[i]);
849
850         automation->copy_from(track->automation);
851         this->nudge = track->nudge;
852 }
853
854
855
856
857
858 int Track::dump(FILE *fp)
859 {
860         fprintf(fp,"   Data type %d\n", data_type);
861         fprintf(fp,"   Title %s\n", title);
862         fprintf(fp,"   Edits:\n");
863         for(Edit* current = edits->first; current; current = NEXT)
864         {
865                 current->dump(fp);
866         }
867         automation->dump(fp);
868         fprintf(fp,"   Plugin Sets: %d\n", plugin_set.total);
869
870         for(int i = 0; i < plugin_set.total; i++)
871                 plugin_set.values[i]->dump(fp);
872 //printf("Track::dump 2\n");
873         return 0;
874 }
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896 Track::Track() : ListItem<Track>()
897 {
898         y_pixel = 0;
899 }
900
901 // ======================================== accounting
902
903 int Track::number_of() 
904
905         return tracks->number_of(this); 
906 }
907
908
909
910
911
912         
913         
914
915
916
917
918
919
920 // ================================================= editing
921
922 int Track::select_auto(AutoConf *auto_conf, int cursor_x, int cursor_y)
923 {
924         return 0;
925 }
926
927 int Track::move_auto(AutoConf *auto_conf, int cursor_x, int cursor_y, int shift_down)
928 {
929         return 0;
930 }
931
932 int Track::release_auto()
933 {
934         return 0;
935 }
936
937 // used for copying automation alone
938 int Track::copy_automation(double selectionstart, 
939         double selectionend, 
940         FileXML *file,
941         int default_only,
942         int active_only)
943 {
944         int64_t start = to_units(selectionstart, 0);
945         int64_t end = to_units(selectionend, 0);
946
947         file->tag.set_title("TRACK");
948 // Video or audio
949     save_header(file);
950         file->append_tag();
951         file->append_newline();
952
953         automation->copy(start, end, file, default_only, active_only);
954
955         if(edl->session->auto_conf->plugins)
956         {
957                 for(int i = 0; i < plugin_set.total; i++)
958                 {
959                 
960                         plugin_set.values[i]->copy_keyframes(start, 
961                                 end, 
962                                 file, 
963                                 default_only,
964                                 active_only);
965                 }
966         }
967
968         file->tag.set_title("/TRACK");
969         file->append_tag();
970         file->append_newline();
971         file->append_newline();
972         file->append_newline();
973         file->append_newline();
974
975         return 0;
976 }
977
978 int Track::paste_automation(double selectionstart, 
979         double total_length, 
980         double frame_rate,
981         int64_t sample_rate,
982         FileXML *file,
983         int default_only,
984         int active_only)
985 {
986 // Only used for pasting automation alone.
987         int64_t start;
988         int64_t length;
989         int result;
990         double scale;
991         int current_pluginset;
992
993         if(data_type == TRACK_AUDIO)
994                 scale = edl->session->sample_rate / sample_rate;
995         else
996                 scale = edl->session->frame_rate / frame_rate;
997
998         total_length *= scale;
999         start = to_units(selectionstart, 0);
1000         length = to_units(total_length, 0);
1001         result = 0;
1002         current_pluginset = 0;
1003 //printf("Track::paste_automation 1\n");
1004
1005         while(!result)
1006         {
1007                 result = file->read_tag();
1008
1009                 if(!result)
1010                 {
1011                         if(file->tag.title_is("/TRACK"))
1012                                 result = 1;
1013                         else
1014                         if(automation->paste(start, 
1015                                         length, 
1016                                         scale,
1017                                         file,
1018                                         default_only,
1019                                         active_only,
1020                                         0))
1021                         {
1022                                 ;
1023                         }
1024                         else
1025                         if(file->tag.title_is("PLUGINSET"))
1026                         {
1027                                 if(current_pluginset < plugin_set.total)
1028                                 {
1029                                         plugin_set.values[current_pluginset]->paste_keyframes(start, 
1030                                                 length, 
1031                                                 file,
1032                                                 default_only,
1033                                                 active_only);
1034                                         current_pluginset++;
1035                                 }
1036                         }
1037                 }
1038         }
1039         
1040
1041         return 0;
1042 }
1043
1044 void Track::clear_automation(double selectionstart, 
1045         double selectionend, 
1046         int shift_autos,
1047         int default_only)
1048 {
1049         int64_t start = to_units(selectionstart, 0);
1050         int64_t end = to_units(selectionend, 0);
1051
1052         automation->clear(start, end, edl->session->auto_conf, 0);
1053
1054         if(edl->session->auto_conf->plugins)
1055         {
1056                 for(int i = 0; i < plugin_set.total; i++)
1057                 {
1058                         plugin_set.values[i]->clear_keyframes(start, end);
1059                 }
1060         }
1061
1062 }
1063
1064 void Track::set_automation_mode(double selectionstart, 
1065         double selectionend,
1066         int mode)
1067 {
1068         int64_t start = to_units(selectionstart, 0);
1069         int64_t end = to_units(selectionend, 0);
1070
1071         automation->set_automation_mode(start, end, mode, edl->session->auto_conf);
1072 }
1073
1074
1075
1076
1077 int Track::copy(double start, 
1078         double end, 
1079         FileXML *file, 
1080         const char *output_path)
1081 {
1082 // Use a copy of the selection in converted units
1083 // So copy_automation doesn't reconvert.
1084         int64_t start_unit = to_units(start, 0);
1085         int64_t end_unit = to_units(end, 1);
1086
1087
1088
1089
1090         file->tag.set_title("TRACK");
1091         file->tag.set_property("RECORD", record);
1092         file->tag.set_property("NUDGE", nudge);
1093         file->tag.set_property("PLAY", play);
1094         file->tag.set_property("GANG", gang);
1095         file->tag.set_property("DRAW", draw);
1096         file->tag.set_property("EXPAND", expand_view);
1097         file->tag.set_property("TRACK_W", track_w);
1098         file->tag.set_property("TRACK_H", track_h);
1099         save_header(file);
1100         file->append_tag();
1101         file->append_newline();
1102         save_derived(file);
1103
1104         file->tag.set_title("TITLE");
1105         file->append_tag();
1106         file->append_text(title);
1107         file->tag.set_title("/TITLE");
1108         file->append_tag();
1109         file->append_newline();
1110
1111 //      if(data_type == TRACK_AUDIO)
1112 //              file->tag.set_property("TYPE", "AUDIO");
1113 //      else
1114 //              file->tag.set_property("TYPE", "VIDEO");
1115 // 
1116 //      file->append_tag();
1117 //      file->append_newline();
1118
1119         edits->copy(start_unit, end_unit, file, output_path);
1120
1121         AutoConf auto_conf;
1122         auto_conf.set_all(1);
1123         automation->copy(start_unit, end_unit, file, 0, 0);
1124
1125
1126         for(int i = 0; i < plugin_set.total; i++)
1127         {
1128                 plugin_set.values[i]->copy(start_unit, end_unit, file);
1129         }
1130
1131         copy_derived(start_unit, end_unit, file);
1132
1133         file->tag.set_title("/TRACK");
1134         file->append_tag();
1135         file->append_newline();
1136         file->append_newline();
1137         file->append_newline();
1138         file->append_newline();
1139
1140         return 0;
1141 }
1142
1143 int Track::copy_assets(double start, 
1144         double end, 
1145         ArrayList<Asset*> *asset_list)
1146 {
1147         int i, result = 0;
1148
1149         start = to_units(start, 0);
1150         end = to_units(end, 0);
1151
1152         Edit *current = edits->editof((int64_t)start, PLAY_FORWARD, 0);
1153
1154 // Search all edits
1155         while(current && current->startproject < end)
1156         {
1157 // Check for duplicate assets
1158                 if(current->asset)
1159                 {
1160                         for(i = 0, result = 0; i < asset_list->total; i++)
1161                         {
1162                                 if(asset_list->values[i] == current->asset) result = 1;
1163                         }
1164 // append pointer to new asset
1165                         if(!result) asset_list->append(current->asset);
1166                 }
1167
1168                 current = NEXT;
1169         }
1170
1171         return 0;
1172 }
1173
1174
1175
1176
1177
1178 int Track::clear(double start, 
1179         double end, 
1180         int edit_edits,
1181         int edit_labels,
1182         int edit_plugins,
1183         int edit_autos,
1184         int convert_units,
1185         Edits *trim_edits)
1186 {
1187 // Edits::move_auto calls this routine after the units are converted to the track
1188 // format.
1189 //printf("Track::clear 1 %d %d %d\n", edit_edits, edit_labels, edit_plugins);
1190         if(convert_units)
1191         {
1192                 start = to_units(start, 0);
1193                 end = to_units(end, 0);
1194         }
1195
1196
1197         if(edit_autos)
1198                 automation->clear((int64_t)start, (int64_t)end, 0, 1);
1199
1200         if(edit_plugins)
1201         {
1202                 for(int i = 0; i < plugin_set.total; i++)
1203                 {
1204                         if(!trim_edits || trim_edits == (Edits*)plugin_set.values[i])
1205                                 plugin_set.values[i]->clear((int64_t)start, (int64_t)end, edit_autos);
1206                 }
1207         }
1208
1209         if(edit_edits)
1210                 edits->clear((int64_t)start, (int64_t)end);
1211         return 0;
1212 }
1213
1214 int Track::clear_handle(double start, 
1215         double end, 
1216         int clear_labels,
1217         int clear_plugins, 
1218         int edit_autos,
1219         double &distance)
1220 {
1221         edits->clear_handle(start, end, clear_plugins, edit_autos, distance);
1222         return 0;
1223 }
1224
1225 int Track::popup_transition(int cursor_x, int cursor_y)
1226 {
1227         return 0;
1228 }
1229
1230
1231
1232 int Track::modify_edithandles(double oldposition, 
1233         double newposition, 
1234         int currentend, 
1235         int handle_mode,
1236         int edit_labels,
1237         int edit_plugins,
1238         int edit_autos)
1239 {
1240         edits->modify_handles(oldposition, 
1241                 newposition, 
1242                 currentend,
1243                 handle_mode,
1244                 1,
1245                 edit_labels,
1246                 edit_plugins,
1247                 edit_autos,
1248                 0);
1249
1250
1251         return 0;
1252 }
1253
1254 int Track::modify_pluginhandles(double oldposition, 
1255         double newposition, 
1256         int currentend, 
1257         int handle_mode,
1258         int edit_labels,
1259         int edit_autos,
1260         Edits *trim_edits)
1261 {
1262         for(int i = 0; i < plugin_set.total; i++)
1263         {
1264                 if(!trim_edits || trim_edits == (Edits*)plugin_set.values[i])
1265                         plugin_set.values[i]->modify_handles(oldposition, 
1266                                 newposition, 
1267                                 currentend, 
1268                                 handle_mode,
1269 // Don't allow plugin tweeks to affect edits.
1270                                 0,
1271                                 edit_labels,
1272                                 1,
1273                                 edit_autos,
1274                                 trim_edits);
1275         }
1276         return 0;
1277 }
1278
1279
1280 int Track::paste_silence(double start, double end, int edit_plugins, int edit_autos)
1281 {
1282         int64_t start_i = to_units(start, 0);
1283         int64_t end_i = to_units(end, 1);
1284
1285         edits->paste_silence(start_i, end_i);
1286         if(edit_autos) shift_keyframes(start_i, end_i - start_i);
1287         if(edit_plugins) shift_effects(start_i, end_i - start_i, edit_autos);
1288
1289         edits->optimize();
1290         return 0;
1291 }
1292
1293 int Track::select_edit(int cursor_x, 
1294         int cursor_y, 
1295         double &new_start, 
1296         double &new_end)
1297 {
1298         return 0;
1299 }
1300
1301 int Track::scale_time(float rate_scale, int scale_edits, int scale_autos, int64_t start, int64_t end)
1302 {
1303         return 0;
1304 }
1305
1306 void Track::change_plugins(SharedLocation &old_location, SharedLocation &new_location, int do_swap)
1307 {
1308         for(int i = 0; i < plugin_set.total; i++)
1309         {
1310                 for(Plugin *plugin = (Plugin*)plugin_set.values[i]->first; 
1311                         plugin; 
1312                         plugin = (Plugin*)plugin->next)
1313                 {
1314                         if(plugin->plugin_type == PLUGIN_SHAREDPLUGIN)
1315                         {
1316                                 if(plugin->shared_location == old_location)
1317                                         plugin->shared_location = new_location;
1318                                 else
1319                                 if(do_swap && plugin->shared_location == new_location)
1320                                         plugin->shared_location = old_location;
1321                         }
1322                 }
1323         }
1324 }
1325
1326 void Track::change_modules(int old_location, int new_location, int do_swap)
1327 {
1328         for(int i = 0; i < plugin_set.total; i++)
1329         {
1330                 for(Plugin *plugin = (Plugin*)plugin_set.values[i]->first; 
1331                         plugin; 
1332                         plugin = (Plugin*)plugin->next)
1333                 {
1334                         if(plugin->plugin_type == PLUGIN_SHAREDPLUGIN ||
1335                                 plugin->plugin_type == PLUGIN_SHAREDMODULE)
1336                         {
1337                                 if(plugin->shared_location.module == old_location)
1338                                         plugin->shared_location.module = new_location;
1339                                 else
1340                                 if(do_swap && plugin->shared_location.module == new_location)
1341                                         plugin->shared_location.module = old_location;
1342                         }
1343                 }
1344         }
1345 }
1346
1347
1348 int Track::playable_edit(int64_t position, int direction)
1349 {
1350         int result = 0;
1351         if(direction == PLAY_REVERSE) position--;
1352         for(Edit *current = edits->first; current && !result; current = NEXT)
1353         {
1354                 if(current->startproject <= position && 
1355                         current->startproject + current->length > position)
1356                 {
1357 //printf("Track::playable_edit %p %p\n", current->transition, current->asset);
1358                         if(current->transition || 
1359                                 current->asset ||
1360                                 current->nested_edl) result = 1;
1361                 }
1362         }
1363         return result;
1364 }
1365
1366
1367 int Track::need_edit(Edit *current, int test_transitions)
1368 {
1369         return ((test_transitions && current->transition) ||
1370                 (!test_transitions && current->asset));
1371 }
1372
1373 int64_t Track::plugin_change_duration(int64_t input_position,
1374         int64_t input_length,
1375         int reverse,
1376         int use_nudge)
1377 {
1378         if(use_nudge) input_position += nudge;
1379         for(int i = 0; i < plugin_set.total; i++)
1380         {
1381                 int64_t new_duration = plugin_set.values[i]->plugin_change_duration(
1382                         input_position, 
1383                         input_length, 
1384                         reverse);
1385                 if(new_duration < input_length) input_length = new_duration;
1386         }
1387         return input_length;
1388 }
1389
1390 int64_t Track::edit_change_duration(int64_t input_position, 
1391         int64_t input_length, 
1392         int reverse, 
1393         int test_transitions,
1394         int use_nudge)
1395 {
1396         Edit *current;
1397         int64_t edit_length = input_length;
1398         if(use_nudge) input_position += nudge;
1399
1400         if(reverse)
1401         {
1402 // ================================= Reverse playback
1403 // Get first edit on or after position
1404                 for(current = edits->first; 
1405                         current && current->startproject + current->length <= input_position;
1406                         current = NEXT)
1407                         ;
1408
1409                 if(current)
1410                 {
1411                         if(current->startproject > input_position)
1412                         {
1413 // Before first edit
1414                                 ;
1415                         }
1416                         else
1417                         if(need_edit(current, test_transitions))
1418                         {
1419 // Over an edit of interest.
1420                                 if(input_position - current->startproject < input_length)
1421                                         edit_length = input_position - current->startproject + 1;
1422                         }
1423                         else
1424                         {
1425 // Over an edit that isn't of interest.
1426 // Search for next edit of interest.
1427                                 for(current = PREVIOUS ; 
1428                                         current && 
1429                                         current->startproject + current->length > input_position - input_length &&
1430                                         !need_edit(current, test_transitions);
1431                                         current = PREVIOUS)
1432                                         ;
1433
1434                                         if(current && 
1435                                                 need_edit(current, test_transitions) &&
1436                                                 current->startproject + current->length > input_position - input_length)
1437                         edit_length = input_position - current->startproject - current->length + 1;
1438                         }
1439                 }
1440                 else
1441                 {
1442 // Not over an edit.  Try the last edit.
1443                         current = edits->last;
1444                         if(current && 
1445                                 ((test_transitions && current->transition) ||
1446                                 (!test_transitions && current->asset)))
1447                                 edit_length = input_position - edits->last->startproject - edits->last->length + 1;
1448                 }
1449         }
1450         else
1451         {
1452 // =================================== forward playback
1453 // Get first edit on or before position
1454                 for(current = edits->last; 
1455                         current && current->startproject > input_position;
1456                         current = PREVIOUS)
1457                         ;
1458
1459                 if(current)
1460                 {
1461                         if(current->startproject + current->length <= input_position)
1462                         {
1463 // Beyond last edit.
1464                                 ;
1465                         }
1466                         else
1467                         if(need_edit(current, test_transitions))
1468                         {
1469 // Over an edit of interest.
1470 // Next edit is going to require a change.
1471                                 if(current->length + current->startproject - input_position < input_length)
1472                                         edit_length = current->startproject + current->length - input_position;
1473                         }
1474                         else
1475                         {
1476 // Over an edit that isn't of interest.
1477 // Search for next edit of interest.
1478                                 for(current = NEXT ; 
1479                                         current && 
1480                                         current->startproject < input_position + input_length &&
1481                                         !need_edit(current, test_transitions);
1482                                         current = NEXT)
1483                                         ;
1484
1485                                         if(current && 
1486                                                 need_edit(current, test_transitions) &&
1487                                                 current->startproject < input_position + input_length) 
1488                                                 edit_length = current->startproject - input_position;
1489                         }
1490                 }
1491                 else
1492                 {
1493 // Not over an edit.  Try the first edit.
1494                         current = edits->first;
1495                         if(current && 
1496                                 ((test_transitions && current->transition) ||
1497                                 (!test_transitions && current->asset)))
1498                                 edit_length = edits->first->startproject - input_position;
1499                 }
1500         }
1501
1502         if(edit_length < input_length)
1503                 return edit_length;
1504         else
1505                 return input_length;
1506 }
1507
1508 void Track::shuffle_edits(double start, double end, int first_track)
1509 {
1510         ArrayList<Edit*> new_edits;
1511         ArrayList<Label*> new_labels;
1512         int64_t start_units = to_units(start, 0);
1513         int64_t end_units = to_units(end, 0);
1514 // Sample range of all edits selected
1515         //int64_t total_start_units = 0;
1516         //int64_t total_end_units = 0;
1517 // Edit before range
1518         Edit *start_edit = 0;
1519         int have_start_edit = 0;
1520
1521 // Move all edit pointers to list
1522         for(Edit *current = edits->first; 
1523                 current; )
1524         {
1525                 if(current->startproject >= start_units &&
1526                         current->startproject + current->length <= end_units)
1527                 {
1528                         if(!have_start_edit) start_edit = current->previous;
1529                         have_start_edit = 1;
1530                         //total_start_units = current->startproject;
1531                         //total_end_units = current->startproject + current->length;
1532                         new_edits.append(current);
1533
1534 // Move label pointers
1535                         if(first_track && edl->session->labels_follow_edits)
1536                         {
1537                                 double start_seconds = from_units(current->startproject);
1538                                 double end_seconds = from_units(current->startproject +
1539                                         current->length);
1540                                 for(Label *label = edl->labels->first;
1541                                         label;
1542                                         label = label->next)
1543                                 {
1544                                         if(label->position >= start_seconds &&
1545                                                 label->position < end_seconds)
1546                                         {
1547                                                 new_labels.append(label);
1548                                                 edl->labels->remove_pointer(label);
1549                                         }
1550                                 }
1551                         }
1552
1553 // Remove edit pointer
1554                         Edit *previous = current;
1555                         current = NEXT;
1556                         edits->remove_pointer(previous);
1557                 }
1558                 else
1559                 {
1560                         current = NEXT;
1561                 }
1562         }
1563
1564 // Insert pointers in random order
1565         while(new_edits.size())
1566         {
1567                 int index = rand() % new_edits.size();
1568                 Edit *edit = new_edits.get(index);
1569                 new_edits.remove_number(index);
1570                 edits->insert_after(start_edit, edit);
1571                 start_edit = edit;
1572
1573 // Recalculate start position
1574 // Save old position for moving labels
1575                 int64_t startproject1 = edit->startproject;
1576                 int64_t startproject2 = 0;
1577                 if(edit->previous)
1578                 {
1579                         edit->startproject = 
1580                                 startproject2 =
1581                                 edit->previous->startproject + edit->previous->length;
1582                 }
1583                 else
1584                 {
1585                         edit->startproject = startproject2 = 0;
1586                 }
1587
1588
1589 // Insert label pointers
1590                 if(first_track && edl->session->labels_follow_edits)
1591                 {
1592                         double start_seconds1 = from_units(startproject1);
1593                         double start_seconds2 = from_units(startproject2);
1594                         //double end_seconds1 = from_units(edit->startproject +
1595                         //      edit->length);
1596                         for(int i = new_labels.size() - 1; i >= 0; i--)
1597                         {
1598                                 Label *label = new_labels.get(i);
1599 // Was in old edit position
1600                                 if(label->position >= start_seconds1 &&
1601                                         label->position < start_seconds2)
1602                                 {
1603 // Move to new edit position
1604                                         double position = label->position - 
1605                                                 start_seconds1 + 
1606                                                 start_seconds2;
1607                                         edl->labels->insert_label(position);
1608                                         new_labels.remove_object_number(i);
1609                                 }
1610                         }
1611                 }
1612
1613
1614         }
1615         
1616         optimize();
1617         
1618         if(first_track && edl->session->labels_follow_edits)
1619         {
1620                 edl->labels->optimize();
1621         }
1622 }
1623
1624 void Track::align_edits(double start, 
1625         double end, 
1626         ArrayList<double> *times)
1627 {
1628         int64_t start_units = to_units(start, 0);
1629         int64_t end_units = to_units(end, 0);
1630
1631 // If 1st track with data, times is empty & we need to collect the edit times.
1632         if(!times->size())
1633         {
1634                 for(Edit *current = edits->first; current; current = NEXT)
1635                 {
1636                         if(current->startproject >= start_units &&
1637                                 current->startproject + current->length <= end_units)
1638                         {
1639                                 times->append(from_units(current->startproject));
1640                         }
1641                 }
1642         }
1643         else
1644 // All other tracks get silence or cut to align the edits on the times.
1645         {
1646                 int current_time = 0;
1647                 for(Edit *current = edits->first; 
1648                         current && current_time < times->size(); )
1649                 {
1650                         if(current->startproject >= start_units &&
1651                                 current->startproject + current->length <= end_units)
1652                         {
1653                                 int64_t desired_startunits = to_units(times->get(current_time), 0);
1654                                 int64_t current_startunits = current->startproject;
1655                                 current = NEXT;
1656
1657
1658                                 if(current_startunits < desired_startunits)
1659                                 {
1660 //printf("Track::align_edits %d\n", __LINE__);
1661                                         edits->paste_silence(current_startunits,
1662                                                 desired_startunits);
1663                                         shift_keyframes(current_startunits,
1664                                                 desired_startunits - current_startunits);
1665                                 }
1666                                 else
1667                                 if(current_startunits > desired_startunits)
1668                                 {
1669                                         edits->clear(desired_startunits,
1670                                                 current_startunits);
1671                                         if(edl->session->autos_follow_edits)
1672                                                 shift_keyframes(desired_startunits,
1673                                                         current_startunits - desired_startunits);
1674                                 }
1675
1676                                 current_time++;
1677                         }
1678                         else
1679                         {
1680                                 current = NEXT;
1681                         }
1682                 }
1683         }
1684
1685         optimize();
1686 }
1687
1688 int Track::purge_asset(Asset *asset)
1689 {
1690         return 0;
1691 }
1692
1693 int Track::asset_used(Asset *asset)
1694 {
1695         Edit* current_edit;
1696         int result = 0;
1697
1698         for(current_edit = edits->first; current_edit; current_edit = current_edit->next)
1699         {
1700                 if(current_edit->asset == asset)
1701                 {
1702                         result++;
1703                 }
1704         }
1705         return result;
1706 }
1707
1708 int Track::is_playable(int64_t position, int direction)
1709 {
1710         return 1;
1711 }
1712
1713
1714 int Track::plugin_used(int64_t position, int64_t direction)
1715 {
1716 //printf("Track::plugin_used 1 %d\n", this->plugin_set.total);
1717         for(int i = 0; i < this->plugin_set.total; i++)
1718         {
1719                 Plugin *current_plugin = get_current_plugin(position, 
1720                         i, 
1721                         direction, 
1722                         0,
1723                         0);
1724
1725 //printf("Track::plugin_used 2 %p %d %d\n", current_plugin, current_plugin->on, current_plugin->plugin_type);
1726                 if(current_plugin && 
1727                         current_plugin->on && 
1728                         current_plugin->plugin_type != PLUGIN_NONE)
1729                 {
1730                         return 1;
1731                 }
1732         }
1733 //printf("Track::plugin_used 3 %p\n", current_plugin);
1734         return 0;
1735 }
1736
1737 // Audio is always rendered through VConsole
1738 int Track::direct_copy_possible(int64_t start, int direction, int use_nudge)
1739 {
1740         return 1;
1741 }
1742
1743 int64_t Track::to_units(double position, int round)
1744 {
1745         return (int64_t)position;
1746 }
1747
1748 double Track::to_doubleunits(double position)
1749 {
1750         return position;
1751 }
1752
1753 double Track::from_units(int64_t position)
1754 {
1755         return (double)position;
1756 }
1757
1758 int Track::plugin_exists(Plugin *plugin)
1759 {
1760         for(int number = 0; number < plugin_set.size(); number++)
1761         {
1762                 PluginSet *ptr = plugin_set.get(number);
1763                 for(Plugin *current_plugin = (Plugin*)ptr->first;
1764                         current_plugin;
1765                         current_plugin = (Plugin*)current_plugin->next)
1766                 {
1767                         if(current_plugin == plugin) return 1;
1768                 }
1769         }
1770
1771         for(Edit *current = edits->first; current; current = NEXT)
1772         {
1773                 if(current->transition &&
1774                         (Plugin*)current->transition == plugin) return 1;
1775         }
1776
1777
1778         return 0;
1779 }
1780
1781
1782