r956: README.BUILD - add more library recommendations
[cinelerra_cv/ct.git] / cinelerra / tracksedit.C
blob394a2c2b3cd5d5c8da2178a13bac509601f31e6d
1 #include "assets.h"
2 #include "atrack.h"
3 #include "automation.h"
4 #include "aedits.h"
5 #include "edit.h"
6 #include "edits.h"
7 #include "edl.h"
8 #include "edlsession.h"
9 #include "filexml.h"
10 #include "intauto.h"
11 #include "intautos.h"
12 #include "localsession.h"
13 #include "mainundo.h"
14 #include "module.h"
15 #include "mainsession.h"
16 #include "pluginserver.h"
17 #include "pluginset.h"
18 #include "timebar.h"
19 #include "trackcanvas.h"
20 #include "tracks.h"
21 #include "trackscroll.h"
22 #include "transition.h"
23 #include "transportque.h"
24 #include "vtrack.h"
25 #include <string.h>
27 int Tracks::clear(double start, double end, int clear_plugins)
29         Track *current_track;
31         for(current_track = first; 
32                 current_track; 
33                 current_track = current_track->next)
34         {
35                 if(current_track->record) 
36                 {
37                         current_track->clear(start, 
38                                 end, 
39                                 1, 
40                                 1, 
41                                 clear_plugins, 
42                                 1,
43                                 0); 
44                 }
45         }
46         return 0;
49 void Tracks::clear_automation(double selectionstart, double selectionend)
51         Track* current_track;
53         for(current_track = first; current_track; current_track = current_track->next)
54         {
55                 if(current_track->record)
56                 {
57                         current_track->clear_automation(selectionstart, 
58                                 selectionend, 
59                                 0,
60                                 0); 
61                 }
62         }
65 void Tracks::straighten_automation(double selectionstart, double selectionend)
67         Track* current_track;
69         for(current_track = first; current_track; current_track = current_track->next)
70         {
71                 if(current_track->record)
72                 {
73                         current_track->straighten_automation(selectionstart, 
74                                 selectionend); 
75                 }
76         }
79 int Tracks::clear_default_keyframe()
81         for(Track *current = first; current; current = NEXT)
82         {
83                 if(current->record)
84                         current->clear_automation(0, 0, 0, 1);
85         }
86         return 0;
89 int Tracks::clear_handle(double start, 
90         double end,
91         double &longest_distance,
92         int clear_labels,
93         int clear_plugins)
95         Track* current_track;
96         double distance;
98         for(current_track = first; current_track; current_track = current_track->next)
99         {
100                 if(current_track->record)
101                 {
102                         current_track->clear_handle(start, 
103                                 end, 
104                                 clear_labels,
105                                 clear_plugins, 
106                                 distance);
107                         if(distance > longest_distance) longest_distance = distance;
108                 }
109         }
111         return 0;
114 int Tracks::copy_automation(double selectionstart, 
115         double selectionend, 
116         FileXML *file,
117         int default_only,
118         int autos_only)
120 // called by MWindow::copy_automation for copying automation alone
121         Track* current_track;
123         file->tag.set_title("AUTO_CLIPBOARD");
124         file->tag.set_property("LENGTH", selectionend - selectionstart);
125         file->tag.set_property("FRAMERATE", edl->session->frame_rate);
126         file->tag.set_property("SAMPLERATE", edl->session->sample_rate);
127         file->append_tag();
128         file->append_newline();
129         file->append_newline();
131         for(current_track = first; 
132                 current_track; 
133                 current_track = current_track->next)
134         {
135                 if(current_track->record)
136                 {
137                         current_track->copy_automation(selectionstart, 
138                                 selectionend, 
139                                 file,
140                                 default_only,
141                                 autos_only);
142                 }
143         }
145         file->tag.set_title("/AUTO_CLIPBOARD");
146         file->append_tag();
147         file->append_newline();
148         file->terminate_string();
149         return 0;
152 int Tracks::copy_default_keyframe(FileXML *file)
154         copy_automation(0, 0, file, 1, 0);
155         return 0;
158 int Tracks::delete_tracks()
160         int total_deleted = 0;
161         int done = 0;
163         while(!done)
164         {
165                 done = 1;
166                 for (Track* current = first;
167                         current && done;
168                         current = NEXT)
169                 {
170                         if(current->record)
171                         {
172                                 delete_track(current);
173                                 total_deleted++;
174                                 done = 0;
175                         }
176                 }
177         }
178         return total_deleted;
181 void Tracks::move_edits(ArrayList<Edit*> *edits, 
182         Track *track,
183         double position,
184         int edit_labels,  // Ignored
185         int edit_plugins,  // Ignored
186         int behaviour)
188 //printf("Tracks::move_edits 1\n");
189         for(Track *dest_track = track; dest_track; dest_track = dest_track->next)
190         {
191                 if(dest_track->record)
192                 {
193 // Need a local copy of the source edit since the original source edit may
194 // change in the editing operation.
195                         Edit *source_edit = 0;
196                         Track *source_track = 0;
199 // Get source track
200                         if(dest_track->data_type == TRACK_AUDIO)
201                         {
202                                 int current_aedit = 0;
204                                 while(current_aedit < edits->total &&
205                                         edits->values[current_aedit]->track->data_type != TRACK_AUDIO)
206                                         current_aedit++;
208                                 if(current_aedit < edits->total)
209                                 {
210                                         source_edit = edits->values[current_aedit];
211                                         source_track = source_edit->track;
212                                         edits->remove_number(current_aedit);
213                                 }
214                         }
215                         else
216                         if(dest_track->data_type == TRACK_VIDEO)
217                         {
218                                 int current_vedit = 0;
219                                 while(current_vedit < edits->total &&
220                                         edits->values[current_vedit]->track->data_type != TRACK_VIDEO)
221                                         current_vedit++;
223                                 if(current_vedit < edits->total)
224                                 {
225                                         source_edit = edits->values[current_vedit];
226                                         source_track = source_edit->track;
227                                         edits->remove_number(current_vedit);
228                                 }
229                         }
231 //printf("Tracks::move_edits 2 %s %s %d\n", source_track->title, dest_track->title, source_edit->length);
232                         if(source_edit)
233                         {
234                                 int64_t position_i = source_track->to_units(position, 0);
235 // Source edit changes
236                                 int64_t source_length = source_edit->length;
237                                 int64_t source_startproject = source_edit->startproject;
239                                 if (behaviour == 0)
240                                 {
241                                 // This works like this: CUT edit, INSERT edit at final position, keyframes also follow
242                                 // FIXME: there should be a GUI way to tell whenever user also wants to move autos or not
243 // Copy keyframes
244                                         FileXML temp;
245                                         AutoConf temp_autoconf;
247                                         temp_autoconf.set_all(1);
249                                         source_track->automation->copy(source_edit->startproject, 
250                                                 source_edit->startproject + source_edit->length, 
251                                                 &temp, 
252                                                 0,
253                                                 0);
254                                         temp.terminate_string();
255                                         temp.rewind();
256 // Insert new keyframes
257 //printf("Tracks::move_edits 2 %d %p\n", result->startproject, result->asset);
258                                         source_track->automation->clear(source_edit->startproject,
259                                                 source_edit->startproject + source_edit->length, 
260                                                 &temp_autoconf,
261                                                 1);
262                                         int64_t position_a = position_i;
263                                         if (dest_track == source_track)
264                                         {
265                                                 if (position_a > source_edit->startproject)
266                                                         position_a -= source_length;
267                                         }               
269                                         dest_track->automation->paste_silence(position_a, 
270                                                 position_a + source_length);
271                                         while(!temp.read_tag())
272                                                 dest_track->automation->paste(position_a, 
273                                                         source_length, 
274                                                         1.0, 
275                                                         &temp, 
276                                                         0,
277                                                         &temp_autoconf);
279 // Insert new edit
280                                         Edit *dest_edit = dest_track->edits->shift(position_i, 
281                                                 source_length);
282                                         Edit *result = dest_track->edits->insert_before(dest_edit, 
283                                                 new Edit(edl, dest_track));
284                                         result->copy_from(source_edit);
285                                         result->startproject = position_i;
286                                         result->length = source_length;
288 // Clear source
289                                         source_track->edits->clear(source_edit->startproject, 
290                                                 source_edit->startproject + source_length);
292         /*
293 //this is outline for future thinking how it is supposed to be done trough C&P mechanisms
294                                         temp.reset_tag();
295                                         source_track->cut(source_edit->startproject, 
296                                                 source_edit->startproject + source_edit->length, 
297                                                 &temp, 
298                                                 NULL);
299                                         temp.terminate_string();
300                                         temp.rewind();
301                                         dest_track->paste_silence(position_a, 
302                                                 position_a + source_length,
303                                                 edit_plugins);
304                                         while(!temp.read_tag())
305                                                 dest_track->paste(position_a,          // MISSING PIECE OF FUNCTIONALITY 
306                                                         source_length, 
307                                                         1.0, 
308                                                         &temp, 
309                                                         0,
310                                                         &temp_autoconf);
311         */
314                                 } else
315                                 if (behaviour == 1)
316                                 // ONLY edit is moved, all other edits stay where they are
317                                 {
318                                         // Copy edit to temp, delete the edit, insert the edit
319                                         Edit *temp_edit = new Edit(edl, dest_track); 
320                                         temp_edit->copy_from(source_edit);
321                                         // we call the edits directly since we do not want to move keyframes or anything else
322                                         source_track->edits->clear(source_startproject, 
323                                                 source_startproject + source_length);
324                                         source_track->edits->paste_silence(source_startproject, 
325                                                 source_startproject + source_length); 
327                                         dest_track->edits->clear(position_i, 
328                                                 position_i + source_length);
329                                         Edit *dest_edit = dest_track->edits->shift(position_i,  source_length);
330                                         Edit *result = dest_track->edits->insert_before(dest_edit, 
331                                                 new Edit(edl, dest_track));
332                                         result->copy_from(temp_edit);
333                                         result->startproject = position_i;
334                                         result->length = source_length;
335                                         delete temp_edit;
336                                 }
337                                 source_track->optimize();
338                                 dest_track->optimize();
339                         }
340                 }
341         }
344 void Tracks::move_effect(Plugin *plugin,
345         PluginSet *dest_plugin_set,
346         Track *dest_track, 
347         int64_t dest_position)
349         Track *source_track = plugin->track;
350         Plugin *result = 0;
352 // Insert on an existing plugin set
353         if(!dest_track && dest_plugin_set)
354         {
355                 Track *dest_track = dest_plugin_set->track;
358 // Assume this operation never splits a plugin
359 // Shift destination plugins back
360                 dest_plugin_set->shift(dest_position, plugin->length);
362 // Insert new plugin
363                 Plugin *current = 0;
364                 for(current = (Plugin*)dest_plugin_set->first; current; current = (Plugin*)NEXT)
365                         if(current->startproject >= dest_position) break;
367                 result = (Plugin*)dest_plugin_set->insert_before(current, 
368                         new Plugin(edl, dest_plugin_set, ""));
369         }
370         else
371 // Create a new plugin set
372         {
373                 double length = 0;
374                 double start = 0;
375                 if(edl->local_session->get_selectionend() > 
376                         edl->local_session->get_selectionstart())
377                 {
378                         start = edl->local_session->get_selectionstart();
379                         length = edl->local_session->get_selectionend() - 
380                                 start;
381                 }
382                 else
383                 if(dest_track->get_length() > 0)
384                 {
385                         start = 0;
386                         length = dest_track->get_length();
387                 }
388                 else
389                 {
390                         start = 0;
391                         length = dest_track->from_units(plugin->length);
392                 }
395                 result = dest_track->insert_effect("", 
396                                 &plugin->shared_location, 
397                                 0,
398                                 0,
399                                 start,
400                                 length,
401                                 plugin->plugin_type);
402         }
406         result->copy_from(plugin);
407         result->shift(dest_position - plugin->startproject);
409 // Clear new plugin from old set
410         plugin->plugin_set->clear(plugin->startproject, plugin->startproject + plugin->length);
413         source_track->optimize();
418 int Tracks::concatenate_tracks(int edit_plugins)
420         Track *output_track, *first_output_track, *input_track;
421         int i, data_type = TRACK_AUDIO;
422         double output_start;
423         FileXML *clipboard;
424         int result = 0;
425         IntAuto *play_keyframe = 0;
427 // Relocate tracks
428         for(i = 0; i < 2; i++)
429         {
430 // Get first output track
431                 for(output_track = first; 
432                         output_track; 
433                         output_track = output_track->next)
434                         if(output_track->data_type == data_type && 
435                                 output_track->record) break;
437                 first_output_track = output_track;
439 // Get first input track
440                 for(input_track = first;
441                         input_track;
442                         input_track = input_track->next)
443                 {
444                         if(input_track->data_type == data_type &&
445                                 input_track->play && 
446                                 !input_track->record) break;
447                 }
450                 if(output_track && input_track)
451                 {
452 // Transfer input track to end of output track one at a time
453                         while(input_track)
454                         {
455                                 output_start = output_track->get_length();
456                                 output_track->insert_track(input_track, 
457                                         output_start, 
458                                         0,
459                                         edit_plugins);
461 // Get next source and destination
462                                 for(input_track = input_track->next; 
463                                         input_track; 
464                                         input_track = input_track->next)
465                                 {
467                                         if(input_track->data_type == data_type && 
468                                                 !input_track->record && 
469                                                 input_track->play) break;
470                                 }
472                                 for(output_track = output_track->next; 
473                                         output_track; 
474                                         output_track = output_track->next)
475                                 {
476                                         if(output_track->data_type == data_type && 
477                                                 output_track->record) break;
478                                 }
480                                 if(!output_track)
481                                 {
482                                         output_track = first_output_track;
483                                 }
484                         }
485                         result = 1;
486                 }
488                 if(data_type == TRACK_AUDIO) data_type = TRACK_VIDEO;
489         }
491         return result;
494 int Tracks::delete_all_tracks()
496         while(last) delete last;
497         return 0;
501 void Tracks::change_modules(int old_location, int new_location, int do_swap)
503         for(Track* current = first ; current; current = current->next)
504         {
505                 current->change_modules(old_location, new_location, do_swap);
506         }
509 void Tracks::change_plugins(SharedLocation &old_location, SharedLocation &new_location, int do_swap)
511         for(Track* current = first ; current; current = current->next)
512         {
513                 current->change_plugins(old_location, new_location, do_swap);
514         }
519 // =========================================== EDL editing
522 int Tracks::copy(double start, 
523         double end, 
524         int all, 
525         FileXML *file, 
526         char *output_path)
528 // nothing selected
529         if(start == end && !all) return 1;
531         Track* current;
533         for(current = first; 
534                 current; 
535                 current = NEXT)
536         {
537                 if(current->record || all)
538                 {
539                         current->copy(start, end, file,output_path);
540                 }
541         }
543         return 0;
548 int Tracks::move_track_up(Track *track)
550         Track *next_track = track->previous;
551         if(!next_track) next_track = last;
553         change_modules(number_of(track), number_of(next_track), 1);
555 // printf("Tracks::move_track_up 1 %p %p\n", track, next_track);
556 // int count = 0;
557 // for(Track *current = first; current && count < 5; current = NEXT, count++)
558 //      printf("Tracks::move_track_up %p %p %p\n", current->previous, current, current->next);
559 // printf("Tracks::move_track_up 2\n");
560 // 
561         swap(track, next_track);
563 // count = 0;
564 // for(Track *current = first; current && count < 5; current = NEXT, count++)
565 //      printf("Tracks::move_track_up %p %p %p\n", current->previous, current, current->next);
566 // printf("Tracks::move_track_up 3\n");
568         return 0;
571 int Tracks::move_track_down(Track *track)
573         Track *next_track = track->next;
574         if(!next_track) next_track = first;
576         change_modules(number_of(track), number_of(next_track), 1);
577         swap(track, next_track);
578         return 0;
582 int Tracks::move_tracks_up()
584         Track *track, *next_track;
585         int result = 0;
587         for(track = first;
588                 track; 
589                 track = next_track)
590         {
591                 next_track = track->next;
593                 if(track->record)
594                 {
595                         if(track->previous)
596                         {
597                                 change_modules(number_of(track->previous), number_of(track), 1);
599                                 swap(track->previous, track);
600                                 result = 1;
601                         }
602                 }
603         }
605         return result;
608 int Tracks::move_tracks_down()
610         Track *track, *previous_track;
611         int result = 0;
612         
613         for(track = last;
614                 track; 
615                 track = previous_track)
616         {
617                 previous_track = track->previous;
619                 if(track->record)
620                 {
621                         if(track->next)
622                         {
623                                 change_modules(number_of(track), number_of(track->next), 1);
625                                 swap(track, track->next);
626                                 result = 1;
627                         }
628                 }
629         }
630         
631         return result;
636 void Tracks::paste_audio_transition(PluginServer *server)
638         for(Track *current = first; current; current = NEXT)
639         {
640                 if(current->data_type == TRACK_AUDIO &&
641                         current->record)
642                 {
643                         int64_t position = current->to_units(
644                                 edl->local_session->get_selectionstart(), 0);
645                         Edit *current_edit = current->edits->editof(position, 
646                                 PLAY_FORWARD,
647                                 0);
648                         if(current_edit)
649                         {
650                                 paste_transition(server, current_edit);
651                         }
652                 }
653         }
656 void Tracks::loaded_lengths_to_tracklengths(int includerecordtracks)
658         Track *current_track;
659         
660         for(current_track = first; 
661             current_track; 
662             current_track = current_track->next)
663         {
664                 if(current_track->record || includerecordtracks) 
665                 {
666 // Reset the loaded_length value. (the last edit should always be a silence going to infinityish)
667                         current_track->edits->loaded_length = current_track->edits->last->startproject;
668                 }
669         }
672 void Tracks::paste_automation(double selectionstart, 
673         FileXML *file,
674         int default_only)
676         Track* current_atrack = 0;
677         Track* current_vtrack = 0;
678         int result = 0;
679         double length;
680         double frame_rate = edl->session->frame_rate;
681         int64_t sample_rate = edl->session->sample_rate;
682         char string[BCTEXTLEN];
683         sprintf(string, "");
685 // Search for start
686         do{
687           result = file->read_tag();
688         }while(!result && 
689                 !file->tag.title_is("AUTO_CLIPBOARD"));
691         if(!result)
692         {
693                 length = file->tag.get_property("LENGTH", 0);
694                 frame_rate = file->tag.get_property("FRAMERATE", frame_rate);
695                 sample_rate = file->tag.get_property("SAMPLERATE", sample_rate);
698                 do
699                 {
700                         result = file->read_tag();
702                         if(!result)
703                         {
704                                 if(file->tag.title_is("/AUTO_CLIPBOARD"))
705                                 {
706                                         result = 1;
707                                 }
708                                 else
709                                 if(file->tag.title_is("TRACK"))
710                                 {
711                                         file->tag.get_property("TYPE", string);
712                                         
713                                         if(!strcmp(string, "AUDIO"))
714                                         {
715 // Get next audio track
716                                                 if(!current_atrack)
717                                                         current_atrack = first;
718                                                 else
719                                                         current_atrack = current_atrack->next;
721                                                 while(current_atrack && 
722                                                         (current_atrack->data_type != TRACK_AUDIO ||
723                                                         !current_atrack->record))
724                                                         current_atrack = current_atrack->next;
726 // Paste it
727                                                 if(current_atrack)
728                                                 {
729                                                         current_atrack->paste_automation(selectionstart,
730                                                                 length,
731                                                                 frame_rate,
732                                                                 sample_rate,
733                                                                 file,
734                                                                 default_only);
735                                                 }
736                                         }
737                                         else
738                                         {
739 // Get next video track
740                                                 if(!current_vtrack)
741                                                         current_vtrack = first;
742                                                 else
743                                                         current_vtrack = current_vtrack->next;
745                                                 while(current_vtrack && 
746                                                         (current_vtrack->data_type != TRACK_VIDEO ||
747                                                         !current_vtrack->record))
748                                                         current_vtrack = current_vtrack->next;
750 // Paste it
751                                                 if(current_vtrack)
752                                                 {
753 //printf("Tracks::paste_automation 1 %s %d\n", current_vtrack->title, current_vtrack->record);
754                                                         current_vtrack->paste_automation(selectionstart,
755                                                                 length,
756                                                                 frame_rate,
757                                                                 sample_rate,
758                                                                 file,
759                                                                 default_only);
760                                                 }
761                                         }
762                                 }
763                         }
764                 }while(!result);
765         }
768 int Tracks::paste_default_keyframe(FileXML *file)
770         paste_automation(0, file, 1);
771         return 0;
774 void Tracks::paste_transition(PluginServer *server, Edit *dest_edit)
776         dest_edit->insert_transition(server->title);
779 void Tracks::paste_video_transition(PluginServer *server, int first_track)
781         for(Track *current = first; current; current = NEXT)
782         {
783                 if(current->data_type == TRACK_VIDEO &&
784                         current->record)
785                 {
786                         int64_t position = current->to_units(
787                                 edl->local_session->get_selectionstart(), 0);
788                         Edit *current_edit = current->edits->editof(position, 
789                                 PLAY_FORWARD,
790                                 0);
791                         if(current_edit)
792                         {
793                                 paste_transition(server, current_edit);
794                         }
795                         if(first_track) break;
796                 }
797         }
801 int Tracks::paste_silence(double start, double end, int edit_plugins)
803         Track* current_track;
805         for(current_track = first; 
806                 current_track; 
807                 current_track = current_track->next)
808         {
809                 if(current_track->record) 
810                 { 
811                         current_track->paste_silence(start, end, edit_plugins); 
812                 }
813         }
814         return 0;
819 int Tracks::select_auto(int cursor_x, int cursor_y)
821         int result = 0;
822         for(Track* current = first; current && !result; current = NEXT) { result = current->select_auto(&auto_conf, cursor_x, cursor_y); }
823         return result;
826 int Tracks::move_auto(int cursor_x, int cursor_y, int shift_down)
828         int result = 0;
830         for(Track* current = first; current && !result; current = NEXT) 
831         {
832                 result = current->move_auto(&auto_conf, cursor_x, cursor_y, shift_down); 
833         }
834         return 0;
837 int Tracks::modify_edithandles(double &oldposition, 
838         double &newposition, 
839         int currentend, 
840         int handle_mode,
841         int edit_labels,
842         int edit_plugins)
844         Track *current;
846         for(current = first; current; current = NEXT)
847         {
848                 if(current->record)
849                 {
850                         current->modify_edithandles(oldposition, 
851                                 newposition, 
852                                 currentend,
853                                 handle_mode,
854                                 edit_labels,
855                                 edit_plugins);
856                 }
857         }
858         return 0;
861 int Tracks::modify_pluginhandles(double &oldposition, 
862         double &newposition, 
863         int currentend, 
864         int handle_mode,
865         int edit_labels,
866         Edits *trim_edits)
868         Track *current;
870         for(current = first; current; current = NEXT)
871         {
872                 if(current->record)
873                 {
874                         current->modify_pluginhandles(oldposition, 
875                                 newposition, 
876                                 currentend, 
877                                 handle_mode,
878                                 edit_labels,
879                                 trim_edits);
880                 }
881         }
882         return 0;
887 int Tracks::purge_asset(Asset *asset)
889         Track *current_track;
890         int result = 0;
891         
892         for(current_track = first; current_track; current_track = current_track->next)
893         {
894                 result += current_track->purge_asset(asset); 
895         }
896         return result;
899 int Tracks::asset_used(Asset *asset)
901         Track *current_track;
902         int result = 0;
903         
904         for(current_track = first; current_track; current_track = current_track->next)
905         {
906                 result += current_track->asset_used(asset); 
907         }
908         return result;
911 int Tracks::scale_time(float rate_scale, int ignore_record, int scale_edits, int scale_autos, int64_t start, int64_t end)
913         Track *current_track;
915         for(current_track = first; 
916                 current_track; 
917                 current_track = current_track->next)
918         {
919                 if((current_track->record || ignore_record) && 
920                         current_track->data_type == TRACK_VIDEO)
921                 {
922                         current_track->scale_time(rate_scale, scale_edits, scale_autos, start, end);
923                 }
924         }
925         return 0;