r793: Small API addon, so plugins can 'see' camera and projector automation
[cinelerra_cv/mob.git] / cinelerra / autos.C
blob4e2e5030c498b2242e457c9295abd399158c57e1
1 #include "autos.h"
2 #include "clip.h"
3 #include "edl.h"
4 #include "edlsession.h"
5 #include "localsession.h"
6 #include "filexml.h"
7 #include "track.h"
8 #include "transportque.inc"
10 #include <string.h>
13 Autos::Autos(EDL *edl, Track *track)
14  : List<Auto>()
16         this->edl = edl;
17         this->track = track;
18         type = -1;
23 Autos::~Autos()
25         while(last) delete last;
26         delete default_auto;
29 void Autos::create_objects()
31 // Default
32         default_auto = new_auto();
33         default_auto->is_default = 1;
36 int Autos::get_type()
38         return type;
41 Auto* Autos::append_auto()
43         return append(new_auto());
47 Auto* Autos::new_auto()
49         return new Auto(edl, this);
52 void Autos::resample(double old_rate, double new_rate)
54         for(Auto *current = first; current; current = NEXT)
55         {
56                 current->position = (int64_t)((double)current->position * 
57                         new_rate / 
58                         old_rate + 
59                         0.5);
60         }
63 void Autos::equivalent_output(Autos *autos, int64_t startproject, int64_t *result)
65 // Default keyframe differs
66         if(!total() && !(*default_auto == *autos->default_auto))
67         {
68                 if(*result < 0 || *result > startproject) *result = startproject;
69         }
70         else
71 // Search for difference
72         {
73                 for(Auto *current = first, *that_current = autos->first; 
74                         current || that_current; 
75                         current = NEXT,
76                         that_current = that_current->next)
77                 {
78 // Total differs
79                         if(current && !that_current)
80                         {
81                                 int64_t position1 = (autos->last ? autos->last->position : startproject);
82                                 int64_t position2 = current->position;
83                                 if(*result < 0 || *result > MIN(position1, position2))
84                                         *result = MIN(position1, position2);
85                                 break;
86                         }
87                         else
88                         if(!current && that_current)
89                         {
90                                 int64_t position1 = (last ? last->position : startproject);
91                                 int64_t position2 = that_current->position;
92                                 if(*result < 0 || *result > MIN(position1, position2))
93                                         *result = MIN(position1, position2);
94                                 break;
95                         }
96                         else
97 // Keyframes differ
98                         if(!(*current == *that_current) || 
99                                 current->position != that_current->position)
100                         {
101                                 int64_t position1 = (current->previous ? 
102                                         current->previous->position : 
103                                         startproject);
104                                 int64_t position2 = (that_current->previous ? 
105                                         that_current->previous->position : 
106                                         startproject);
107                                 if(*result < 0 || *result > MIN(position1, position2))
108                                         *result = MIN(position1, position2);
109                                 break;
110                         }
111                 }
112         }
115 void Autos::copy_from(Autos *autos)
117         Auto *current = autos->first, *this_current = first;
119         default_auto->copy_from(autos->default_auto);
121 // Detect common memory leak bug
122         if(autos->first && !autos->last)
123         {
124                 printf("Autos::copy_from inconsistent pointers\n");
125                 exit(1);
126         }
128         for(current = autos->first; current; current = NEXT)
129         {
130 //printf("Autos::copy_from 1 %p\n", current);
131 //sleep(1);
132                 if(!this_current)
133                 {
134                         append(this_current = new_auto());
135                 }
136                 this_current->copy_from(current);
137                 this_current = this_current->next;
138         }
140         for( ; this_current; )
141         {
142                 Auto *next_current = this_current->next;
143                 delete this_current;
144                 this_current = next_current;
145         }
149 // We don't replace it in pasting but
150 // when inserting the first EDL of a load operation we need to replace
151 // the default keyframe.
152 void Autos::insert_track(Autos *automation, 
153         int64_t start_unit, 
154         int64_t length_units,
155         int replace_default)
157 // Insert silence
158         insert(start_unit, start_unit + length_units);
160         if(replace_default) default_auto->copy_from(automation->default_auto);
161         for(Auto *current = automation->first; current; current = NEXT)
162         {
163                 Auto *new_auto = insert_auto(start_unit + current->position);
164                 new_auto->copy_from(current);
165 // Override copy_from
166                 new_auto->position = current->position + start_unit;
167         }
170 Auto* Autos::get_prev_auto(int64_t position, 
171         int direction, 
172         Auto* &current, 
173         int use_default)
175 // Get on or before position
176         if(direction == PLAY_FORWARD)
177         {
178 // Try existing result
179                 if(current)
180                 {
181                         while(current && current->position < position) current = NEXT;
182                         while(current && current->position > position) current = PREVIOUS;
183                 }
185                 if(!current)
186                 {
187                         for(current = last; 
188                                 current && current->position > position; 
189                                 current = PREVIOUS) ;
190                 }
191                 if(!current && use_default) current = (first ? first : default_auto);
192         }
193         else
194 // Get on or after position
195         if(direction == PLAY_REVERSE)
196         {
197                 if(current)
198                 {
199                         while(current && current->position > position) current = PREVIOUS;
200                         while(current && current->position < position) current = NEXT;
201                 }
203                 if(!current)
204                 {
205                         for(current = first; 
206                                 current && current->position < position; 
207                                 current = NEXT) ;
208                 }
210                 if(!current && use_default) current = (last ? last : default_auto);
211         }
213         return current;
216 Auto* Autos::get_prev_auto(int direction, Auto* &current)
218         double position_double = edl->local_session->get_selectionstart(1);
219         position_double = edl->align_to_frame(position_double, 0);
220         int64_t position = track->to_units(position_double, 0);
222         return get_prev_auto(position, direction, current);
224         return current;
227 int Autos::auto_exists_for_editing(double position)
229         int result = 0;
230         
231         if(edl->session->auto_keyframes)
232         {
233                 double unit_position = position;
234                 unit_position = edl->align_to_frame(unit_position, 0);
235                 if (get_auto_at_position(unit_position))
236                         result = 1;
237         }
238         else
239         {
240                 result = 1;
241         }
243         return result;
246 Auto* Autos::get_auto_at_position(double position)
248         int64_t unit_position = track->to_units(position, 0);
250         for(Auto *current = first; 
251                 current; 
252                 current = NEXT)
253         {
254                 if(edl->equivalent(current->position, unit_position))
255                 {
256                         return current;
257                 }
258         }
259         return 0;
263 Auto* Autos::get_auto_for_editing(double position)
265         if(position < 0)
266         {
267                 position = edl->local_session->get_selectionstart(1);
268         }
270         Auto *result = 0;
271         position = edl->align_to_frame(position, 0);
276 //printf("Autos::get_auto_for_editing %p %p\n", first, default_auto);
278         if(edl->session->auto_keyframes)
279         {
280                 result = insert_auto_for_editing(track->to_units(position, 0));
281         }
282         else
283                 result = get_prev_auto(track->to_units(position, 0), 
284                         PLAY_FORWARD, 
285                         result);
287 //printf("Autos::get_auto_for_editing %p %p %p\n", default_auto, first, result);
288         return result;
292 Auto* Autos::get_next_auto(int64_t position, int direction, Auto* &current, int use_default)
294         if(direction == PLAY_FORWARD)
295         {
296                 if(current)
297                 {
298                         while(current && current->position > position) current = PREVIOUS;
299                         while(current && current->position < position) current = NEXT;
300                 }
302                 if(!current)
303                 {
304                         for(current = first;
305                                 current && current->position <= position;
306                                 current = NEXT)
307                                 ;
308                 }
310                 if(!current && use_default) current = (last ? last : default_auto);
311         }
312         else
313         if(direction == PLAY_REVERSE)
314         {
315                 if(current)
316                 {
317                         while(current && current->position < position) current = NEXT;
318                         while(current && current->position > position) current = PREVIOUS;
319                 }
321                 if(!current)
322                 {
323                         for(current = last;
324                                 current && current->position > position;
325                                 current = PREVIOUS)
326                                 ;
327                 }
329                 if(!current && use_default) current = (first ? first : default_auto);
330         }
332         return current;
335 Auto* Autos::insert_auto(int64_t position)
337         Auto *current, *result;
339 // Test for existence
340         for(current = first; 
341                 current && !edl->equivalent(current->position, position); 
342                 current = NEXT)
343         {
344                 ;
345         }
347 //printf("Autos::insert_auto %p\n", current);
348 // Insert new
349         if(!current)
350         {
351 // Get first one on or before as a template
352                 for(current = last; 
353                         current && current->position > position; 
354                         current = PREVIOUS)
355                 {
356                         ;
357                 }
359                 if(current)
360                 {
361                         insert_after(current, result = new_auto());
362                         result->copy_from(current);
363                 }
364                 else
365                 {
366                         current = first;
367                         if(!current) current = default_auto;
369                         insert_before(first, result = new_auto());
370                         if(current) result->copy_from(current);
371                 }
373                 result->position = position;
374         }
375         else
376         {
377                 result = current;
378         }
380         return result;
383 Auto* Autos::insert_auto_for_editing(int64_t position)
385         Auto *current, *result;
387 // Test for existence
388         for(current = first; 
389                 current && !edl->equivalent(current->position, position); 
390                 current = NEXT)
391         {
392                 ;
393         }
395 //printf("Autos::insert_auto_for_editing %p\n", current);
396 // Insert new
397         if(!current)
398         {
399 // Get first one on or before as a template
400                 for(current = last; 
401                         current && current->position > position; 
402                         current = PREVIOUS)
403                 {
404                         ;
405                 }
407                 if(current)
408                 {
409                         Auto *next = NEXT;
410                         insert_after(current, result = new_auto());
411                         result->interpolate_from(current, next, position);
412                 }
413                 else
414                 {
415                         current = first;
416                         if(!current) current = default_auto;
418                         insert_before(first, result = new_auto());
419                         if(current) result->copy_from(current);
420                 }
422                 result->position = position;
423         }
424         else
425         {
426                 result = current;
427         }
429         return result;
432 int Autos::clear_all()
434         Auto *current_, *current;
435         
436         for(current = first; current; current = current_)
437         {
438                 current_ = NEXT;
439                 remove(current);
440         }
441         append_auto();
442         return 0;
445 int Autos::insert(int64_t start, int64_t end)
447         int64_t length;
448         Auto *current = first;
450         for( ; current && current->position < start; current = NEXT)
451                 ;
453         length = end - start;
455         for(; current; current = NEXT)
456         {
457                 current->position += length;
458         }
459         return 0;
462 void Autos::paste(int64_t start, 
463         int64_t length, 
464         double scale, 
465         FileXML *file, 
466         int default_only)
468         int total = 0;
469         int result = 0;
471 //printf("Autos::paste %ld\n", start);
472         do{
473                 result = file->read_tag();
475                 if(!result && !file->tag.title_is("/AUTO"))
476                 {
477 // End of list
478                         if(/* strstr(file->tag.get_title(), "AUTOS") && */
479                                 file->tag.get_title()[0] == '/')
480                         {
481                                 result = 1;
482                         }
483                         else
484                         if(!strcmp(file->tag.get_title(), "AUTO"))
485                         {
486                                 Auto *current = 0;
488 // Paste first active auto into default                         
489                                 if(default_only)
490                                 {
491                                         if(total == 1)
492                                         {
493                                                 current = default_auto;
494                                         }
495                                 }
496                                 else
497 // Paste default auto into default
498                                 if(total == 0)
499                                         current = default_auto;
500                                 else
501                                 {
502                                         int64_t position = Units::to_int64(
503                                                 (double)file->tag.get_property("POSITION", 0) *
504                                                         scale + 
505                                                         start);
506 // Paste active auto into track
507                                         current = insert_auto(position);
508                                 }
510                                 if(current)
511                                 {
512                                         current->load(file);
513                                 }
514                                 total++;
515                         }
516                 }
517         }while(!result);
518         
522 int Autos::paste_silence(int64_t start, int64_t end)
524         insert(start, end);
525         return 0;
528 int Autos::copy(int64_t start, 
529         int64_t end, 
530         FileXML *file, 
531         int default_only,
532         int autos_only)
534 // First auto is always loaded into default even if it is discarded in a paste
535 // operation
536 //printf("Autos::copy 1 %d %d %p\n", default_only, start, autoof(start));
537         if(!autos_only)
538         {
539                 default_auto->copy(0, 0, file, default_only);
540         }
542 //printf("Autos::copy 10 %d %d %p\n", default_only, start, autoof(start));
543         if(!default_only)
544         {
545                 for(Auto* current = autoof(start); 
546                         current && current->position <= end; 
547                         current = NEXT)
548                 {
549 // Want to copy single keyframes by putting the cursor on them
550                         if(current->position >= start && current->position <= end)
551                         {
552                                 current->copy(start, end, file, default_only);
553                         }
554                 }
555         }
556 // Copy default auto again to make it the active auto on the clipboard
557         else
558         {
559 // Need to force position to 0 for the case of plugins
560 // and default status to 0.
561                 default_auto->copy(0, 0, file, default_only);
562         }
563 //printf("Autos::copy 20\n");
565         return 0;
568 // Remove 3 consecutive autos with the same value
569 // Remove autos which are out of order
570 void Autos::optimize()
572         int done = 0;
575 // Default auto should always be at 0
576         default_auto->position = 0;
577         while(!done)
578         {
579                 int consecutive = 0;
580                 done = 1;
581                 
582                 
583                 for(Auto *current = first; current; current = NEXT)
584                 {
585 // Get 3rd consecutive auto of equal value
586                         if(current != first)
587                         {
588                                 if(*current == *PREVIOUS)
589                                 {
590                                         consecutive++;
591                                         if(consecutive >= 3)
592                                         {
593                                                 delete PREVIOUS;
594                                                 break;
595                                         }
596                                 }
597                                 else
598                                         consecutive = 0;
599                                 
600                                 if(done && current->position <= PREVIOUS->position)
601                                 {
602                                         delete current;
603                                         break;
604                                 }
605                         }
606                 }
607         }
611 void Autos::remove_nonsequential(Auto *keyframe)
613         if((keyframe->next && keyframe->next->position <= keyframe->position) ||
614                 (keyframe->previous && keyframe->previous->position >= keyframe->position))
615         {
616                 delete keyframe;
617         }
623 void Autos::clear(int64_t start, 
624         int64_t end, 
625         int shift_autos)
627         int64_t length;
628         Auto *next, *current;
629         length = end - start;
632         current = autoof(start);
634 // If a range is selected don't delete the ending keyframe but do delete
635 // the beginning keyframe because shifting end handle forward shouldn't
636 // delete the first keyframe of the next edit.
638         while(current && 
639                 ((end != start && current->position < end) ||
640                 (end == start && current->position <= end)))
641         {
642                 next = NEXT;
643                 remove(current);
644                 current = next;
645         }
647         while(current && shift_autos)
648         {
649                 current->position -= length;
650                 current = NEXT;
651         }
654 int Autos::clear_auto(int64_t position)
656         Auto *current;
657         current = autoof(position);
658         if(current->position == position) remove(current);
662 int Autos::load(FileXML *file)
664         while(last)
665                 remove(last);    // remove any existing autos
667         int result = 0, first_auto = 1;
668         Auto *current;
669         
670         do{
671                 result = file->read_tag();
672                 
673                 if(!result && !file->tag.title_is("/AUTO"))
674                 {
675 // First tag with leading / is taken as end of autos
676                         if(/* strstr(file->tag.get_title(), "AUTOS") && */
678                                 file->tag.get_title()[0] == '/')
679                         {
680                                 result = 1;
681                         }
682                         else
683                         if(!strcmp(file->tag.get_title(), "AUTO"))
684                         {
685                                 if(first_auto)
686                                 {
687                                         default_auto->load(file);
688                                         default_auto->position = 0;
689                                         first_auto = 0;
690                                 }
691                                 else
692                                 {
693                                         current = append(new_auto());
694                                         current->position = file->tag.get_property("POSITION", (int64_t)0);
695                                         current->load(file);
696                                 }
697                         }
698                 }
699         }while(!result);
700         return 0;
708 int Autos::slope_adjustment(int64_t ax, double slope)
710         return (int)(ax * slope);
714 int Autos::scale_time(float rate_scale, int scale_edits, int scale_autos, int64_t start, int64_t end)
716         Auto *current;
717         
718         for(current = first; current && scale_autos; current = NEXT)
719         {
720 //              if(current->position >= start && current->position <= end)
721 //              {
722                         current->position = (int64_t)((current->position - start) * rate_scale + start + 0.5);
723 //              }
724         }
725         return 0;
728 Auto* Autos::autoof(int64_t position)
730         Auto *current;
732         for(current = first; 
733                 current && current->position < position; 
734                 current = NEXT)
735         { 
736                 ;
737         }
738         return current;     // return 0 on failure
741 Auto* Autos::nearest_before(int64_t position)
743         Auto *current;
745         for(current = last; current && current->position >= position; current = PREVIOUS)
746         { ; }
749         return current;     // return 0 on failure
752 Auto* Autos::nearest_after(int64_t position)
754         Auto *current;
756         for(current = first; current && current->position <= position; current = NEXT)
757         { ; }
760         return current;     // return 0 on failure
763 int Autos::get_neighbors(int64_t start, int64_t end, Auto **before, Auto **after)
765         if(*before == 0) *before = first;
766         if(*after == 0) *after = last; 
768         while(*before && (*before)->next && (*before)->next->position <= start)
769                 *before = (*before)->next;
770         
771         while(*after && (*after)->previous && (*after)->previous->position >= end)
772                 *after = (*after)->previous;
774         while(*before && (*before)->position > start) *before = (*before)->previous;
775         
776         while(*after && (*after)->position < end) *after = (*after)->next;
777         return 0;
780 int Autos::automation_is_constant(int64_t start, int64_t end)
782         return 0;
785 double Autos::get_automation_constant(int64_t start, int64_t end)
787         return 0;
791 int Autos::init_automation(int64_t &buffer_position,
792                                 int64_t &input_start, 
793                                 int64_t &input_end, 
794                                 int &automate, 
795                                 double &constant, 
796                                 int64_t input_position,
797                                 int64_t buffer_len,
798                                 Auto **before, 
799                                 Auto **after,
800                                 int reverse)
802         buffer_position = 0;
804 // set start and end boundaries for automation info
805         input_start = reverse ? input_position - buffer_len : input_position;
806         input_end = reverse ? input_position : input_position + buffer_len;
808 // test automation for constant value
809 // and set up *before and *after
810         if(automate)
811         {
812                 if(automation_is_constant(input_start, input_end))
813                 {
814                         constant += get_automation_constant(input_start, input_end);
815                         automate = 0;
816                 }
817         }
818         return automate;
822 int Autos::init_slope(Auto **current_auto, 
823                                 double &slope_start, 
824                                 double &slope_value,
825                                 double &slope_position, 
826                                 int64_t &input_start, 
827                                 int64_t &input_end, 
828                                 Auto **before, 
829                                 Auto **after,
830                                 int reverse)
832 // apply automation
833         *current_auto = reverse ? *after : *before;
834 // no auto before start so use first auto in range
835 // already know there is an auto since automation isn't constant
836         if(!*current_auto)
837         {
838                 *current_auto = reverse ? last : first;
839 //              slope_value = (*current_auto)->value;
840                 slope_start = input_start;
841                 slope_position = 0;
842         }
843         else
844         {
845 // otherwise get the first slope point and advance auto
846 //              slope_value = (*current_auto)->value;
847                 slope_start = (*current_auto)->position;
848                 slope_position = reverse ? slope_start - input_end : input_start - slope_start;
849                 (*current_auto) = reverse ? (*current_auto)->previous : (*current_auto)->next;
850         }
851         return 0;
855 int Autos::get_slope(Auto **current_auto, 
856                                 double &slope_start, 
857                                 double &slope_end, 
858                                 double &slope_value,
859                                 double &slope, 
860                                 int64_t buffer_len, 
861                                 int64_t buffer_position,
862                                 int reverse)
864 // get the slope
865         if(*current_auto)
866         {
867                 slope_end = reverse ? slope_start - (*current_auto)->position : (*current_auto)->position - slope_start;
868                 if(slope_end) 
869 //                      slope = ((*current_auto)->value - slope_value) / slope_end;
870 //              else
871                         slope = 0;
872         }
873         else
874         {
875                 slope = 0;
876                 slope_end = buffer_len - buffer_position;
877         }
878         return 0;
881 int Autos::advance_slope(Auto **current_auto, 
882                                 double &slope_start, 
883                                 double &slope_value,
884                                 double &slope_position, 
885                                 int reverse)
887         if(*current_auto) 
888         {
889                 slope_start = (*current_auto)->position;
890 //              slope_value = (*current_auto)->value;
891                 (*current_auto) = reverse ? (*current_auto)->previous : (*current_auto)->next;
892                 slope_position = 0;
893         }
894         return 0;
897 int64_t Autos::get_length()
899         if(last) 
900                 return last->position + 1;
901         else
902                 return 0;
905 void Autos::get_extents(float *min, 
906         float *max,
907         int *coords_undefined,
908         int64_t unit_start,
909         int64_t unit_end)
911         
915 void Autos::dump()