r1014: Enable horizontal scrolling with the mouse wheel by pressing Ctrl.
[cinelerra_cv/ct.git] / cinelerra / autos.C
blob4fd2927d9b9b8f3b314b4dee4ee80cc58a162452
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;
19         autoidx = -1;
20         autogrouptype = -1;
25 Autos::~Autos()
27         while(last) delete last;
28         delete default_auto;
31 void Autos::create_objects()
33 // Default
34         default_auto = new_auto();
35         default_auto->is_default = 1;
38 int Autos::get_type()
40         return type;
43 Auto* Autos::append_auto()
45         return append(new_auto());
49 Auto* Autos::new_auto()
51         return new Auto(edl, this);
54 void Autos::resample(double old_rate, double new_rate)
56         for(Auto *current = first; current; current = NEXT)
57         {
58                 current->position = (int64_t)((double)current->position * 
59                         new_rate / 
60                         old_rate + 
61                         0.5);
62         }
65 void Autos::equivalent_output(Autos *autos, int64_t startproject, int64_t *result)
67 // Default keyframe differs
68         if(!total() && !(*default_auto == *autos->default_auto))
69         {
70                 if(*result < 0 || *result > startproject) *result = startproject;
71         }
72         else
73 // Search for difference
74         {
75                 for(Auto *current = first, *that_current = autos->first; 
76                         current || that_current; 
77                         current = NEXT,
78                         that_current = that_current->next)
79                 {
80 // Total differs
81                         if(current && !that_current)
82                         {
83                                 int64_t position1 = (autos->last ? autos->last->position : startproject);
84                                 int64_t position2 = current->position;
85                                 if(*result < 0 || *result > MIN(position1, position2))
86                                         *result = MIN(position1, position2);
87                                 break;
88                         }
89                         else
90                         if(!current && that_current)
91                         {
92                                 int64_t position1 = (last ? last->position : startproject);
93                                 int64_t position2 = that_current->position;
94                                 if(*result < 0 || *result > MIN(position1, position2))
95                                         *result = MIN(position1, position2);
96                                 break;
97                         }
98                         else
99 // Keyframes differ
100                         if(!(*current == *that_current) || 
101                                 current->position != that_current->position)
102                         {
103                                 int64_t position1 = (current->previous ? 
104                                         current->previous->position : 
105                                         startproject);
106                                 int64_t position2 = (that_current->previous ? 
107                                         that_current->previous->position : 
108                                         startproject);
109                                 if(*result < 0 || *result > MIN(position1, position2))
110                                         *result = MIN(position1, position2);
111                                 break;
112                         }
113                 }
114         }
117 void Autos::copy_from(Autos *autos)
119         Auto *current = autos->first, *this_current = first;
121         default_auto->copy_from(autos->default_auto);
123 // Detect common memory leak bug
124         if(autos->first && !autos->last)
125         {
126                 printf("Autos::copy_from inconsistent pointers\n");
127                 exit(1);
128         }
130         for(current = autos->first; current; current = NEXT)
131         {
132 //printf("Autos::copy_from 1 %p\n", current);
133 //sleep(1);
134                 if(!this_current)
135                 {
136                         append(this_current = new_auto());
137                 }
138                 this_current->copy_from(current);
139                 this_current = this_current->next;
140         }
142         for( ; this_current; )
143         {
144                 Auto *next_current = this_current->next;
145                 delete this_current;
146                 this_current = next_current;
147         }
151 // We don't replace it in pasting but
152 // when inserting the first EDL of a load operation we need to replace
153 // the default keyframe.
154 void Autos::insert_track(Autos *automation, 
155         int64_t start_unit, 
156         int64_t length_units,
157         int replace_default)
159 // Insert silence
160         insert(start_unit, start_unit + length_units);
162         if(replace_default) default_auto->copy_from(automation->default_auto);
163         for(Auto *current = automation->first; current; current = NEXT)
164         {
165                 Auto *new_auto = insert_auto(start_unit + current->position);
166                 new_auto->copy_from(current);
167 // Override copy_from
168                 new_auto->position = current->position + start_unit;
169         }
172 Auto* Autos::get_prev_auto(int64_t position, 
173         int direction, 
174         Auto* &current, 
175         int use_default)
177 // Get on or before position
178         if(direction == PLAY_FORWARD)
179         {
180 // Try existing result
181                 if(current)
182                 {
183                         while(current && current->position < position) current = NEXT;
184                         while(current && current->position > position) current = PREVIOUS;
185                 }
187                 if(!current)
188                 {
189                         for(current = last; 
190                                 current && current->position > position; 
191                                 current = PREVIOUS) ;
192                 }
193                 if(!current && use_default) current = (first ? first : default_auto);
194         }
195         else
196 // Get on or after position
197         if(direction == PLAY_REVERSE)
198         {
199                 if(current)
200                 {
201                         while(current && current->position > position) current = PREVIOUS;
202                         while(current && current->position < position) current = NEXT;
203                 }
205                 if(!current)
206                 {
207                         for(current = first; 
208                                 current && current->position < position; 
209                                 current = NEXT) ;
210                 }
212                 if(!current && use_default) current = (last ? last : default_auto);
213         }
215         return current;
218 Auto* Autos::get_prev_auto(int direction, Auto* &current)
220         double position_double = edl->local_session->get_selectionstart(1);
221         position_double = edl->align_to_frame(position_double, 0);
222         int64_t position = track->to_units(position_double, 0);
224         return get_prev_auto(position, direction, current);
226         return current;
229 int Autos::auto_exists_for_editing(double position)
231         int result = 0;
232         
233         if(edl->session->auto_keyframes)
234         {
235                 double unit_position = position;
236                 unit_position = edl->align_to_frame(unit_position, 0);
237                 if (get_auto_at_position(unit_position))
238                         result = 1;
239         }
240         else
241         {
242                 result = 1;
243         }
245         return result;
248 Auto* Autos::get_auto_at_position(double position)
250         int64_t unit_position = track->to_units(position, 0);
252         for(Auto *current = first; 
253                 current; 
254                 current = NEXT)
255         {
256                 if(edl->equivalent(current->position, unit_position))
257                 {
258                         return current;
259                 }
260         }
261         return 0;
265 Auto* Autos::get_auto_for_editing(double position)
267         if(position < 0)
268         {
269                 position = edl->local_session->get_selectionstart(1);
270         }
272         Auto *result = 0;
273         position = edl->align_to_frame(position, 0);
278 //printf("Autos::get_auto_for_editing %p %p\n", first, default_auto);
280         if(edl->session->auto_keyframes)
281         {
282                 result = insert_auto_for_editing(track->to_units(position, 0));
283         }
284         else
285                 result = get_prev_auto(track->to_units(position, 0), 
286                         PLAY_FORWARD, 
287                         result);
289 //printf("Autos::get_auto_for_editing %p %p %p\n", default_auto, first, result);
290         return result;
294 Auto* Autos::get_next_auto(int64_t position, int direction, Auto* &current, int use_default)
296         if(direction == PLAY_FORWARD)
297         {
298                 if(current)
299                 {
300                         while(current && current->position > position) current = PREVIOUS;
301                         while(current && current->position < position) current = NEXT;
302                 }
304                 if(!current)
305                 {
306                         for(current = first;
307                                 current && current->position <= position;
308                                 current = NEXT)
309                                 ;
310                 }
312                 if(!current && use_default) current = (last ? last : default_auto);
313         }
314         else
315         if(direction == PLAY_REVERSE)
316         {
317                 if(current)
318                 {
319                         while(current && current->position < position) current = NEXT;
320                         while(current && current->position > position) current = PREVIOUS;
321                 }
323                 if(!current)
324                 {
325                         for(current = last;
326                                 current && current->position > position;
327                                 current = PREVIOUS)
328                                 ;
329                 }
331                 if(!current && use_default) current = (first ? first : default_auto);
332         }
334         return current;
337 Auto* Autos::insert_auto(int64_t position)
339         Auto *current, *result;
341 // Test for existence
342         for(current = first; 
343                 current && !edl->equivalent(current->position, position); 
344                 current = NEXT)
345         {
346                 ;
347         }
349 // Insert new
350         if(!current)
351         {
352 // Get first one on or before as a template
353                 for(current = last; 
354                         current && current->position > position; 
355                         current = PREVIOUS)
356                 {
357                         ;
358                 }
360                 if(current)
361                 {
362                         insert_after(current, result = new_auto());
363                         result->copy_from(current);
364                 }
365                 else
366                 {
367                         current = first;
368                         if(!current) current = default_auto;
370                         insert_before(first, result = new_auto());
371                         if(current) result->copy_from(current);
372                 }
374                 result->position = position;
375         }
376         else
377         {
378                 result = current;
379         }
381         return result;
384 Auto* Autos::insert_auto_for_editing(int64_t position)
386         Auto *current, *result;
388 // Test for existence
389         for(current = first; 
390                 current && !edl->equivalent(current->position, position); 
391                 current = NEXT)
392         {
393                 ;
394         }
396 //printf("Autos::insert_auto_for_editing %p\n", current);
397 // Insert new
398         if(!current)
399         {
400 // Get first one on or before as a template
401                 for(current = last; 
402                         current && current->position > position; 
403                         current = PREVIOUS)
404                 {
405                         ;
406                 }
408                 if(current)
409                 {
410                         Auto *next = NEXT;
411                         insert_after(current, result = new_auto());
412                         result->interpolate_from(current, next, position);
413                 }
414                 else
415                 {
416                         current = first;
417                         if(!current) current = default_auto;
419                         insert_before(first, result = new_auto());
420                         if(current) result->copy_from(current);
421                 }
423                 result->position = position;
424         }
425         else
426         {
427                 result = current;
428         }
430         return result;
433 int Autos::clear_all()
435         Auto *current_, *current;
436         
437         for(current = first; current; current = current_)
438         {
439                 current_ = NEXT;
440                 remove(current);
441         }
442         append_auto();
443         return 0;
446 int Autos::insert(int64_t start, int64_t end)
448         int64_t length;
449         Auto *current = first;
451         for( ; current && current->position < start; current = NEXT)
452                 ;
454         length = end - start;
456         for(; current; current = NEXT)
457         {
458                 current->position += length;
459         }
460         return 0;
463 void Autos::paste(int64_t start, 
464         int64_t length, 
465         double scale, 
466         FileXML *file, 
467         int default_only)
469         int total = 0;
470         int result = 0;
472 //printf("Autos::paste %ld\n", start);
473         do{
474                 result = file->read_tag();
476                 if(!result && !file->tag.title_is("/AUTO"))
477                 {
478 // End of list
479                         if(/* strstr(file->tag.get_title(), "AUTOS") && */
480                                 file->tag.get_title()[0] == '/')
481                         {
482                                 result = 1;
483                         }
484                         else
485                         if(!strcmp(file->tag.get_title(), "AUTO"))
486                         {
487                                 Auto *current = 0;
489 // Paste first active auto into default                         
490                                 if(default_only)
491                                 {
492                                         if(total == 1)
493                                         {
494                                                 current = default_auto;
495                                         }
496                                 }
497                                 else
498 // Paste default auto into default
499                                 if(total == 0)
500                                         current = default_auto;
501                                 else
502                                 {
503                                         int64_t position = Units::to_int64(
504                                                 (double)file->tag.get_property("POSITION", 0) *
505                                                         scale + 
506                                                         start);
507 // Paste active auto into track
508                                         current = insert_auto(position);
509                                 }
511                                 if(current)
512                                 {
513                                         current->load(file);
514                                 }
515                                 total++;
516                         }
517                 }
518         }while(!result);
519         
523 int Autos::paste_silence(int64_t start, int64_t end)
525         insert(start, end);
526         return 0;
529 int Autos::copy(int64_t start, 
530         int64_t end, 
531         FileXML *file, 
532         int default_only,
533         int autos_only)
535 // First auto is always loaded into default even if it is discarded in a paste
536 // operation
537 //printf("Autos::copy 1 %d %d %p\n", default_only, start, autoof(start));
538         if(!autos_only)
539         {
540                 default_auto->copy(0, 0, file, default_only);
541         }
543 //printf("Autos::copy 10 %d %d %p\n", default_only, start, autoof(start));
544         if(!default_only)
545         {
546                 for(Auto* current = autoof(start); 
547                         current && current->position <= end; 
548                         current = NEXT)
549                 {
550 // Want to copy single keyframes by putting the cursor on them
551                         if(current->position >= start && current->position <= end)
552                         {
553                                 current->copy(start, end, file, default_only);
554                         }
555                 }
556         }
557 // Copy default auto again to make it the active auto on the clipboard
558         else
559         {
560 // Need to force position to 0 for the case of plugins
561 // and default status to 0.
562                 default_auto->copy(0, 0, file, default_only);
563         }
564 //printf("Autos::copy 20\n");
566         return 0;
569 // Remove 3 consecutive autos with the same value
570 // Remove autos which are out of order
571 void Autos::optimize()
573         int done = 0;
576 // Default auto should always be at 0
577         default_auto->position = 0;
578         while(!done)
579         {
580                 int consecutive = 0;
581                 done = 1;
582                 
583                 
584                 for(Auto *current = first; current; current = NEXT)
585                 {
586 // Get 3rd consecutive auto of equal value
587                         if(current != first)
588                         {
589                                 if(*current == *PREVIOUS)
590                                 {
591                                         consecutive++;
592                                         if(consecutive >= 3)
593                                         {
594                                                 delete PREVIOUS;
595                                                 break;
596                                         }
597                                 }
598                                 else
599                                         consecutive = 0;
600                                 
601                                 if(done && current->position <= PREVIOUS->position)
602                                 {
603                                         delete current;
604                                         break;
605                                 }
606                         }
607                 }
608         }
612 void Autos::remove_nonsequential(Auto *keyframe)
614         if((keyframe->next && keyframe->next->position <= keyframe->position) ||
615                 (keyframe->previous && keyframe->previous->position >= keyframe->position))
616         {
617                 delete keyframe;
618         }
622 void Autos::straighten(int64_t start, int64_t end)
626 void Autos::clear(int64_t start, 
627         int64_t end, 
628         int shift_autos)
630         int64_t length;
631         Auto *next, *current;
632         length = end - start;
635         current = autoof(start);
637 // If a range is selected don't delete the ending keyframe but do delete
638 // the beginning keyframe because shifting end handle forward shouldn't
639 // delete the first keyframe of the next edit.
641         while(current && 
642                 ((end != start && current->position < end) ||
643                 (end == start && current->position <= end)))
644         {
645                 next = NEXT;
646                 remove(current);
647                 current = next;
648         }
650         while(current && shift_autos)
651         {
652                 current->position -= length;
653                 current = NEXT;
654         }
657 int Autos::clear_auto(int64_t position)
659         Auto *current;
660         current = autoof(position);
661         if(current->position == position) remove(current);
665 int Autos::load(FileXML *file)
667         while(last)
668                 remove(last);    // remove any existing autos
670         int result = 0, first_auto = 1;
671         Auto *current;
672         
673         do{
674                 result = file->read_tag();
675                 
676                 if(!result && !file->tag.title_is("/AUTO"))
677                 {
678 // First tag with leading / is taken as end of autos
679                         if(/* strstr(file->tag.get_title(), "AUTOS") && */
681                                 file->tag.get_title()[0] == '/')
682                         {
683                                 result = 1;
684                         }
685                         else
686                         if(!strcmp(file->tag.get_title(), "AUTO"))
687                         {
688                                 if(first_auto)
689                                 {
690                                         default_auto->load(file);
691                                         default_auto->position = 0;
692                                         first_auto = 0;
693                                 }
694                                 else
695                                 {
696                                         current = append(new_auto());
697                                         current->position = file->tag.get_property("POSITION", (int64_t)0);
698                                         current->load(file);
699                                 }
700                         }
701                 }
702         }while(!result);
703         return 0;
711 int Autos::slope_adjustment(int64_t ax, double slope)
713         return (int)(ax * slope);
717 int Autos::scale_time(float rate_scale, int scale_edits, int scale_autos, int64_t start, int64_t end)
719         Auto *current;
720         
721         for(current = first; current && scale_autos; current = NEXT)
722         {
723 //              if(current->position >= start && current->position <= end)
724 //              {
725                         current->position = (int64_t)((current->position - start) * rate_scale + start + 0.5);
726 //              }
727         }
728         return 0;
731 Auto* Autos::autoof(int64_t position)
733         Auto *current;
735         for(current = first; 
736                 current && current->position < position; 
737                 current = NEXT)
738         { 
739                 ;
740         }
741         return current;     // return 0 on failure
744 Auto* Autos::nearest_before(int64_t position)
746         Auto *current;
748         for(current = last; current && current->position >= position; current = PREVIOUS)
749         { ; }
752         return current;     // return 0 on failure
755 Auto* Autos::nearest_after(int64_t position)
757         Auto *current;
759         for(current = first; current && current->position <= position; current = NEXT)
760         { ; }
763         return current;     // return 0 on failure
766 int Autos::get_neighbors(int64_t start, int64_t end, Auto **before, Auto **after)
768         if(*before == 0) *before = first;
769         if(*after == 0) *after = last; 
771         while(*before && (*before)->next && (*before)->next->position <= start)
772                 *before = (*before)->next;
773         
774         while(*after && (*after)->previous && (*after)->previous->position >= end)
775                 *after = (*after)->previous;
777         while(*before && (*before)->position > start) *before = (*before)->previous;
778         
779         while(*after && (*after)->position < end) *after = (*after)->next;
780         return 0;
783 int Autos::automation_is_constant(int64_t start, int64_t end)
785         return 0;
788 double Autos::get_automation_constant(int64_t start, int64_t end)
790         return 0;
794 int Autos::init_automation(int64_t &buffer_position,
795                                 int64_t &input_start, 
796                                 int64_t &input_end, 
797                                 int &automate, 
798                                 double &constant, 
799                                 int64_t input_position,
800                                 int64_t buffer_len,
801                                 Auto **before, 
802                                 Auto **after,
803                                 int reverse)
805         buffer_position = 0;
807 // set start and end boundaries for automation info
808         input_start = reverse ? input_position - buffer_len : input_position;
809         input_end = reverse ? input_position : input_position + buffer_len;
811 // test automation for constant value
812 // and set up *before and *after
813         if(automate)
814         {
815                 if(automation_is_constant(input_start, input_end))
816                 {
817                         constant += get_automation_constant(input_start, input_end);
818                         automate = 0;
819                 }
820         }
821         return automate;
825 int Autos::init_slope(Auto **current_auto, 
826                                 double &slope_start, 
827                                 double &slope_value,
828                                 double &slope_position, 
829                                 int64_t &input_start, 
830                                 int64_t &input_end, 
831                                 Auto **before, 
832                                 Auto **after,
833                                 int reverse)
835 // apply automation
836         *current_auto = reverse ? *after : *before;
837 // no auto before start so use first auto in range
838 // already know there is an auto since automation isn't constant
839         if(!*current_auto)
840         {
841                 *current_auto = reverse ? last : first;
842 //              slope_value = (*current_auto)->value;
843                 slope_start = input_start;
844                 slope_position = 0;
845         }
846         else
847         {
848 // otherwise get the first slope point and advance auto
849 //              slope_value = (*current_auto)->value;
850                 slope_start = (*current_auto)->position;
851                 slope_position = reverse ? slope_start - input_end : input_start - slope_start;
852                 (*current_auto) = reverse ? (*current_auto)->previous : (*current_auto)->next;
853         }
854         return 0;
858 int Autos::get_slope(Auto **current_auto, 
859                                 double &slope_start, 
860                                 double &slope_end, 
861                                 double &slope_value,
862                                 double &slope, 
863                                 int64_t buffer_len, 
864                                 int64_t buffer_position,
865                                 int reverse)
867 // get the slope
868         if(*current_auto)
869         {
870                 slope_end = reverse ? slope_start - (*current_auto)->position : (*current_auto)->position - slope_start;
871                 if(slope_end) 
872 //                      slope = ((*current_auto)->value - slope_value) / slope_end;
873 //              else
874                         slope = 0;
875         }
876         else
877         {
878                 slope = 0;
879                 slope_end = buffer_len - buffer_position;
880         }
881         return 0;
884 int Autos::advance_slope(Auto **current_auto, 
885                                 double &slope_start, 
886                                 double &slope_value,
887                                 double &slope_position, 
888                                 int reverse)
890         if(*current_auto) 
891         {
892                 slope_start = (*current_auto)->position;
893 //              slope_value = (*current_auto)->value;
894                 (*current_auto) = reverse ? (*current_auto)->previous : (*current_auto)->next;
895                 slope_position = 0;
896         }
897         return 0;
900 int64_t Autos::get_length()
902         if(last) 
903                 return last->position + 1;
904         else
905                 return 0;
908 void Autos::get_extents(float *min, 
909         float *max,
910         int *coords_undefined,
911         int64_t unit_start,
912         int64_t unit_end)
914         
918 void Autos::dump()