r802: Remove renderframfsclient and renderfarmfsserver .h and .C from Makefile.am...
[cinelerra_cv/mob.git] / cinelerra / tracksedit.C
blobaaee8e39a81f710d944eef991f18c7260f896e44
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 int Tracks::clear_default_keyframe()
67         for(Track *current = first; current; current = NEXT)
68         {
69                 if(current->record)
70                         current->clear_automation(0, 0, 0, 1);
71         }
72         return 0;
75 int Tracks::clear_handle(double start, 
76         double end,
77         double &longest_distance,
78         int clear_labels,
79         int clear_plugins)
81         Track* current_track;
82         double distance;
84         for(current_track = first; current_track; current_track = current_track->next)
85         {
86                 if(current_track->record)
87                 {
88                         current_track->clear_handle(start, 
89                                 end, 
90                                 clear_labels,
91                                 clear_plugins, 
92                                 distance);
93                         if(distance > longest_distance) longest_distance = distance;
94                 }
95         }
97         return 0;
100 int Tracks::copy_automation(double selectionstart, 
101         double selectionend, 
102         FileXML *file,
103         int default_only,
104         int autos_only)
106 // called by MWindow::copy_automation for copying automation alone
107         Track* current_track;
109         file->tag.set_title("AUTO_CLIPBOARD");
110         file->tag.set_property("LENGTH", selectionend - selectionstart);
111         file->tag.set_property("FRAMERATE", edl->session->frame_rate);
112         file->tag.set_property("SAMPLERATE", edl->session->sample_rate);
113         file->append_tag();
114         file->append_newline();
115         file->append_newline();
117         for(current_track = first; 
118                 current_track; 
119                 current_track = current_track->next)
120         {
121                 if(current_track->record)
122                 {
123                         current_track->copy_automation(selectionstart, 
124                                 selectionend, 
125                                 file,
126                                 default_only,
127                                 autos_only);
128                 }
129         }
131         file->tag.set_title("/AUTO_CLIPBOARD");
132         file->append_tag();
133         file->append_newline();
134         file->terminate_string();
135         return 0;
138 int Tracks::copy_default_keyframe(FileXML *file)
140         copy_automation(0, 0, file, 1, 0);
141         return 0;
144 int Tracks::delete_tracks()
146         int total_deleted = 0;
147         int done = 0;
149         while(!done)
150         {
151                 done = 1;
152                 for (Track* current = first;
153                         current && done;
154                         current = NEXT)
155                 {
156                         if(current->record)
157                         {
158                                 delete_track(current);
159                                 total_deleted++;
160                                 done = 0;
161                         }
162                 }
163         }
164         return total_deleted;
167 void Tracks::move_edits(ArrayList<Edit*> *edits, 
168         Track *track,
169         double position,
170         int edit_labels,  // Ignored
171         int edit_plugins,  // Ignored
172         int behaviour)
174 //printf("Tracks::move_edits 1\n");
175         for(Track *dest_track = track; dest_track; dest_track = dest_track->next)
176         {
177                 if(dest_track->record)
178                 {
179 // Need a local copy of the source edit since the original source edit may
180 // change in the editing operation.
181                         Edit *source_edit = 0;
182                         Track *source_track = 0;
185 // Get source track
186                         if(dest_track->data_type == TRACK_AUDIO)
187                         {
188                                 int current_aedit = 0;
190                                 while(current_aedit < edits->total &&
191                                         edits->values[current_aedit]->track->data_type != TRACK_AUDIO)
192                                         current_aedit++;
194                                 if(current_aedit < edits->total)
195                                 {
196                                         source_edit = edits->values[current_aedit];
197                                         source_track = source_edit->track;
198                                         edits->remove_number(current_aedit);
199                                 }
200                         }
201                         else
202                         if(dest_track->data_type == TRACK_VIDEO)
203                         {
204                                 int current_vedit = 0;
205                                 while(current_vedit < edits->total &&
206                                         edits->values[current_vedit]->track->data_type != TRACK_VIDEO)
207                                         current_vedit++;
209                                 if(current_vedit < edits->total)
210                                 {
211                                         source_edit = edits->values[current_vedit];
212                                         source_track = source_edit->track;
213                                         edits->remove_number(current_vedit);
214                                 }
215                         }
217 //printf("Tracks::move_edits 2 %s %s %d\n", source_track->title, dest_track->title, source_edit->length);
218                         if(source_edit)
219                         {
220                                 int64_t position_i = source_track->to_units(position, 0);
221 // Source edit changes
222                                 int64_t source_length = source_edit->length;
223                                 int64_t source_startproject = source_edit->startproject;
225                                 if (behaviour == 0)
226                                 {
227                                 // This works like this: CUT edit, INSERT edit at final position, keyframes also follow
228                                 // FIXME: there should be a GUI way to tell whenever user also wants to move autos or not
229 // Copy keyframes
230                                         FileXML temp;
231                                         AutoConf temp_autoconf;
233                                         temp_autoconf.set_all();
235                                         source_track->automation->copy(source_edit->startproject, 
236                                                 source_edit->startproject + source_edit->length, 
237                                                 &temp, 
238                                                 0,
239                                                 0);
240                                         temp.terminate_string();
241                                         temp.rewind();
242 // Insert new keyframes
243 //printf("Tracks::move_edits 2 %d %p\n", result->startproject, result->asset);
244                                         source_track->automation->clear(source_edit->startproject,
245                                                 source_edit->startproject + source_edit->length, 
246                                                 &temp_autoconf,
247                                                 1);
248                                         int64_t position_a = position_i;
249                                         if (dest_track == source_track)
250                                         {
251                                                 if (position_a > source_edit->startproject)
252                                                         position_a -= source_length;
253                                         }               
255                                         dest_track->automation->paste_silence(position_a, 
256                                                 position_a + source_length);
257                                         while(!temp.read_tag())
258                                                 dest_track->automation->paste(position_a, 
259                                                         source_length, 
260                                                         1.0, 
261                                                         &temp, 
262                                                         0,
263                                                         &temp_autoconf);
265 // Insert new edit
266                                         Edit *dest_edit = dest_track->edits->shift(position_i, 
267                                                 source_length);
268                                         Edit *result = dest_track->edits->insert_before(dest_edit, 
269                                                 new Edit(edl, dest_track));
270                                         result->copy_from(source_edit);
271                                         result->startproject = position_i;
272                                         result->length = source_length;
274 // Clear source
275                                         source_track->edits->clear(source_edit->startproject, 
276                                                 source_edit->startproject + source_length);
278         /*
279 //this is outline for future thinking how it is supposed to be done trough C&P mechanisms
280                                         temp.reset_tag();
281                                         source_track->cut(source_edit->startproject, 
282                                                 source_edit->startproject + source_edit->length, 
283                                                 &temp, 
284                                                 NULL);
285                                         temp.terminate_string();
286                                         temp.rewind();
287                                         dest_track->paste_silence(position_a, 
288                                                 position_a + source_length,
289                                                 edit_plugins);
290                                         while(!temp.read_tag())
291                                                 dest_track->paste(position_a,          // MISSING PIECE OF FUNCTIONALITY 
292                                                         source_length, 
293                                                         1.0, 
294                                                         &temp, 
295                                                         0,
296                                                         &temp_autoconf);
297         */
299                         
300                                 } else
301                                 if (behaviour == 1)
302                                 // ONLY edit is moved, all other edits stay where they are
303                                 {
304                                         // Copy edit to temp, delete the edit, insert the edit
305                                         Edit *temp_edit = new Edit(edl, dest_track); 
306                                         temp_edit->copy_from(source_edit);
307                                         // we call the edits directly since we do not want to move keyframes or anything else
308                                         source_track->edits->clear(source_startproject, 
309                                                 source_startproject + source_length);
310                                         source_track->edits->paste_silence(source_startproject, 
311                                                 source_startproject + source_length); 
313                                         dest_track->edits->clear(position_i, 
314                                                 position_i + source_length);
315                                         Edit *dest_edit = dest_track->edits->shift(position_i,  source_length);
316                                         Edit *result = dest_track->edits->insert_before(dest_edit, 
317                                                 new Edit(edl, dest_track));
318                                         result->copy_from(temp_edit);
319                                         result->startproject = position_i;
320                                         result->length = source_length;
321                                         delete temp_edit;
322                                 }
323                                         
325                                         
326                                 source_track->optimize();
327                                 dest_track->optimize();
328                         }
329                 }
330         }
333 void Tracks::move_effect(Plugin *plugin,
334         PluginSet *dest_plugin_set,
335         Track *dest_track, 
336         int64_t dest_position)
338         Track *source_track = plugin->track;
339         Plugin *result = 0;
341 // Insert on an existing plugin set
342         if(!dest_track && dest_plugin_set)
343         {
344                 Track *dest_track = dest_plugin_set->track;
347 // Assume this operation never splits a plugin
348 // Shift destination plugins back
349                 dest_plugin_set->shift(dest_position, plugin->length);
351 // Insert new plugin
352                 Plugin *current = 0;
353                 for(current = (Plugin*)dest_plugin_set->first; current; current = (Plugin*)NEXT)
354                         if(current->startproject >= dest_position) break;
356                 result = (Plugin*)dest_plugin_set->insert_before(current, 
357                         new Plugin(edl, dest_plugin_set, ""));
358         }
359         else
360 // Create a new plugin set
361         {
362                 double length = 0;
363                 double start = 0;
364                 if(edl->local_session->get_selectionend() > 
365                         edl->local_session->get_selectionstart())
366                 {
367                         start = edl->local_session->get_selectionstart();
368                         length = edl->local_session->get_selectionend() - 
369                                 start;
370                 }
371                 else
372                 if(dest_track->get_length() > 0)
373                 {
374                         start = 0;
375                         length = dest_track->get_length();
376                 }
377                 else
378                 {
379                         start = 0;
380                         length = dest_track->from_units(plugin->length);
381                 }
384                 result = dest_track->insert_effect("", 
385                                 &plugin->shared_location, 
386                                 0,
387                                 0,
388                                 start,
389                                 length,
390                                 plugin->plugin_type);
391         }
395         result->copy_from(plugin);
396         result->shift(dest_position - plugin->startproject);
398 // Clear new plugin from old set
399         plugin->plugin_set->clear(plugin->startproject, plugin->startproject + plugin->length);
402         source_track->optimize();
407 int Tracks::concatenate_tracks(int edit_plugins)
409         Track *output_track, *first_output_track, *input_track;
410         int i, data_type = TRACK_AUDIO;
411         double output_start;
412         FileXML *clipboard;
413         int result = 0;
414         IntAuto *play_keyframe = 0;
416 // Relocate tracks
417         for(i = 0; i < 2; i++)
418         {
419 // Get first output track
420                 for(output_track = first; 
421                         output_track; 
422                         output_track = output_track->next)
423                         if(output_track->data_type == data_type && 
424                                 output_track->record) break;
426                 first_output_track = output_track;
428 // Get first input track
429                 for(input_track = first;
430                         input_track;
431                         input_track = input_track->next)
432                 {
433                         if(input_track->data_type == data_type &&
434                                 input_track->play && 
435                                 !input_track->record) break;
436                 }
439                 if(output_track && input_track)
440                 {
441 // Transfer input track to end of output track one at a time
442                         while(input_track)
443                         {
444                                 output_start = output_track->get_length();
445                                 output_track->insert_track(input_track, 
446                                         output_start, 
447                                         0,
448                                         edit_plugins);
450 // Get next source and destination
451                                 for(input_track = input_track->next; 
452                                         input_track; 
453                                         input_track = input_track->next)
454                                 {
456                                         if(input_track->data_type == data_type && 
457                                                 !input_track->record && 
458                                                 input_track->play) break;
459                                 }
461                                 for(output_track = output_track->next; 
462                                         output_track; 
463                                         output_track = output_track->next)
464                                 {
465                                         if(output_track->data_type == data_type && 
466                                                 output_track->record) break;
467                                 }
469                                 if(!output_track)
470                                 {
471                                         output_track = first_output_track;
472                                 }
473                         }
474                         result = 1;
475                 }
477                 if(data_type == TRACK_AUDIO) data_type = TRACK_VIDEO;
478         }
480         return result;
483 int Tracks::delete_all_tracks()
485         while(last) delete last;
486         return 0;
490 void Tracks::change_modules(int old_location, int new_location, int do_swap)
492         for(Track* current = first ; current; current = current->next)
493         {
494                 current->change_modules(old_location, new_location, do_swap);
495         }
498 void Tracks::change_plugins(SharedLocation &old_location, SharedLocation &new_location, int do_swap)
500         for(Track* current = first ; current; current = current->next)
501         {
502                 current->change_plugins(old_location, new_location, do_swap);
503         }
508 // =========================================== EDL editing
511 int Tracks::copy(double start, 
512         double end, 
513         int all, 
514         FileXML *file, 
515         char *output_path)
517 // nothing selected
518         if(start == end && !all) return 1;
520         Track* current;
522         for(current = first; 
523                 current; 
524                 current = NEXT)
525         {
526                 if(current->record || all)
527                 {
528                         current->copy(start, end, file,output_path);
529                 }
530         }
532         return 0;
537 int Tracks::move_track_up(Track *track)
539         Track *next_track = track->previous;
540         if(!next_track) next_track = last;
542         change_modules(number_of(track), number_of(next_track), 1);
544 // printf("Tracks::move_track_up 1 %p %p\n", track, next_track);
545 // int count = 0;
546 // for(Track *current = first; current && count < 5; current = NEXT, count++)
547 //      printf("Tracks::move_track_up %p %p %p\n", current->previous, current, current->next);
548 // printf("Tracks::move_track_up 2\n");
549 // 
550         swap(track, next_track);
552 // count = 0;
553 // for(Track *current = first; current && count < 5; current = NEXT, count++)
554 //      printf("Tracks::move_track_up %p %p %p\n", current->previous, current, current->next);
555 // printf("Tracks::move_track_up 3\n");
557         return 0;
560 int Tracks::move_track_down(Track *track)
562         Track *next_track = track->next;
563         if(!next_track) next_track = first;
565         change_modules(number_of(track), number_of(next_track), 1);
566         swap(track, next_track);
567         return 0;
571 int Tracks::move_tracks_up()
573         Track *track, *next_track;
574         int result = 0;
576         for(track = first;
577                 track; 
578                 track = next_track)
579         {
580                 next_track = track->next;
582                 if(track->record)
583                 {
584                         if(track->previous)
585                         {
586                                 change_modules(number_of(track->previous), number_of(track), 1);
588                                 swap(track->previous, track);
589                                 result = 1;
590                         }
591                 }
592         }
594         return result;
597 int Tracks::move_tracks_down()
599         Track *track, *previous_track;
600         int result = 0;
601         
602         for(track = last;
603                 track; 
604                 track = previous_track)
605         {
606                 previous_track = track->previous;
608                 if(track->record)
609                 {
610                         if(track->next)
611                         {
612                                 change_modules(number_of(track), number_of(track->next), 1);
614                                 swap(track, track->next);
615                                 result = 1;
616                         }
617                 }
618         }
619         
620         return result;
625 void Tracks::paste_audio_transition(PluginServer *server)
627         for(Track *current = first; current; current = NEXT)
628         {
629                 if(current->data_type == TRACK_AUDIO &&
630                         current->record)
631                 {
632                         int64_t position = current->to_units(
633                                 edl->local_session->get_selectionstart(), 0);
634                         Edit *current_edit = current->edits->editof(position, 
635                                 PLAY_FORWARD,
636                                 0);
637                         if(current_edit)
638                         {
639                                 paste_transition(server, current_edit);
640                         }
641                 }
642         }
645 void Tracks::paste_automation(double selectionstart, 
646         FileXML *file,
647         int default_only)
649         Track* current_atrack = 0;
650         Track* current_vtrack = 0;
651         int result = 0;
652         double length;
653         double frame_rate = edl->session->frame_rate;
654         int64_t sample_rate = edl->session->sample_rate;
655         char string[BCTEXTLEN];
656         sprintf(string, "");
658 // Search for start
659         do{
660           result = file->read_tag();
661         }while(!result && 
662                 !file->tag.title_is("AUTO_CLIPBOARD"));
664         if(!result)
665         {
666                 length = file->tag.get_property("LENGTH", 0);
667                 frame_rate = file->tag.get_property("FRAMERATE", frame_rate);
668                 sample_rate = file->tag.get_property("SAMPLERATE", sample_rate);
671                 do
672                 {
673                         result = file->read_tag();
675                         if(!result)
676                         {
677                                 if(file->tag.title_is("/AUTO_CLIPBOARD"))
678                                 {
679                                         result = 1;
680                                 }
681                                 else
682                                 if(file->tag.title_is("TRACK"))
683                                 {
684                                         file->tag.get_property("TYPE", string);
685                                         
686                                         if(!strcmp(string, "AUDIO"))
687                                         {
688 // Get next audio track
689                                                 if(!current_atrack)
690                                                         current_atrack = first;
691                                                 else
692                                                         current_atrack = current_atrack->next;
694                                                 while(current_atrack && 
695                                                         (current_atrack->data_type != TRACK_AUDIO ||
696                                                         !current_atrack->record))
697                                                         current_atrack = current_atrack->next;
699 // Paste it
700                                                 if(current_atrack)
701                                                 {
702                                                         current_atrack->paste_automation(selectionstart,
703                                                                 length,
704                                                                 frame_rate,
705                                                                 sample_rate,
706                                                                 file,
707                                                                 default_only);
708                                                 }
709                                         }
710                                         else
711                                         {
712 // Get next video track
713                                                 if(!current_vtrack)
714                                                         current_vtrack = first;
715                                                 else
716                                                         current_vtrack = current_vtrack->next;
718                                                 while(current_vtrack && 
719                                                         (current_vtrack->data_type != TRACK_VIDEO ||
720                                                         !current_vtrack->record))
721                                                         current_vtrack = current_vtrack->next;
723 // Paste it
724                                                 if(current_vtrack)
725                                                 {
726 //printf("Tracks::paste_automation 1 %s %d\n", current_vtrack->title, current_vtrack->record);
727                                                         current_vtrack->paste_automation(selectionstart,
728                                                                 length,
729                                                                 frame_rate,
730                                                                 sample_rate,
731                                                                 file,
732                                                                 default_only);
733                                                 }
734                                         }
735                                 }
736                         }
737                 }while(!result);
738         }
741 int Tracks::paste_default_keyframe(FileXML *file)
743         paste_automation(0, file, 1);
744         return 0;
747 void Tracks::paste_transition(PluginServer *server, Edit *dest_edit)
749         dest_edit->insert_transition(server->title);
752 void Tracks::paste_video_transition(PluginServer *server, int first_track)
754         for(Track *current = first; current; current = NEXT)
755         {
756                 if(current->data_type == TRACK_VIDEO &&
757                         current->record)
758                 {
759                         int64_t position = current->to_units(
760                                 edl->local_session->get_selectionstart(), 0);
761                         Edit *current_edit = current->edits->editof(position, 
762                                 PLAY_FORWARD,
763                                 0);
764                         if(current_edit)
765                         {
766                                 paste_transition(server, current_edit);
767                         }
768                         if(first_track) break;
769                 }
770         }
774 int Tracks::paste_silence(double start, double end, int edit_plugins)
776         Track* current_track;
778         for(current_track = first; 
779                 current_track; 
780                 current_track = current_track->next)
781         {
782                 if(current_track->record) 
783                 { 
784                         current_track->paste_silence(start, end, edit_plugins); 
785                 }
786         }
787         return 0;
792 int Tracks::select_auto(int cursor_x, int cursor_y)
794         int result = 0;
795         for(Track* current = first; current && !result; current = NEXT) { result = current->select_auto(&auto_conf, cursor_x, cursor_y); }
796         return result;
799 int Tracks::move_auto(int cursor_x, int cursor_y, int shift_down)
801         int result = 0;
803         for(Track* current = first; current && !result; current = NEXT) 
804         {
805                 result = current->move_auto(&auto_conf, cursor_x, cursor_y, shift_down); 
806         }
807         return 0;
810 int Tracks::modify_edithandles(double &oldposition, 
811         double &newposition, 
812         int currentend, 
813         int handle_mode,
814         int edit_labels,
815         int edit_plugins)
817         Track *current;
819         for(current = first; current; current = NEXT)
820         {
821                 if(current->record)
822                 {
823                         current->modify_edithandles(oldposition, 
824                                 newposition, 
825                                 currentend,
826                                 handle_mode,
827                                 edit_labels,
828                                 edit_plugins);
829                 }
830         }
831         return 0;
834 int Tracks::modify_pluginhandles(double &oldposition, 
835         double &newposition, 
836         int currentend, 
837         int handle_mode,
838         int edit_labels,
839         Edits *trim_edits)
841         Track *current;
843         for(current = first; current; current = NEXT)
844         {
845                 if(current->record)
846                 {
847                         current->modify_pluginhandles(oldposition, 
848                                 newposition, 
849                                 currentend, 
850                                 handle_mode,
851                                 edit_labels,
852                                 trim_edits);
853                 }
854         }
855         return 0;
860 int Tracks::purge_asset(Asset *asset)
862         Track *current_track;
863         int result = 0;
864         
865         for(current_track = first; current_track; current_track = current_track->next)
866         {
867                 result += current_track->purge_asset(asset); 
868         }
869         return result;
872 int Tracks::asset_used(Asset *asset)
874         Track *current_track;
875         int result = 0;
876         
877         for(current_track = first; current_track; current_track = current_track->next)
878         {
879                 result += current_track->asset_used(asset); 
880         }
881         return result;
884 int Tracks::scale_time(float rate_scale, int ignore_record, int scale_edits, int scale_autos, int64_t start, int64_t end)
886         Track *current_track;
888         for(current_track = first; 
889                 current_track; 
890                 current_track = current_track->next)
891         {
892                 if((current_track->record || ignore_record) && 
893                         current_track->data_type == TRACK_VIDEO)
894                 {
895                         current_track->scale_time(rate_scale, scale_edits, scale_autos, start, end);
896                 }
897         }
898         return 0;