r125: This commit was manufactured by cvs2svn to create tag 'r1_1_7-last'.
[cinelerra_cv/mob.git] / hvirtual / cinelerra / autos.C
blob29a451e6ec754777299c81933907a41816c8c50f
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 //printf("Autos::Autos 1 %p %p %p\n", this, first, last);
23 Autos::~Autos()
25         while(last) delete last;
26         delete default_auto;
29 int Autos::create_objects()
31 // Default
32         default_auto = new_auto();
33         default_auto->is_default = 1;
34         return 0;
37 Auto* Autos::new_auto()
39         return new Auto(edl, this);
42 void Autos::resample(double old_rate, double new_rate)
44         for(Auto *current = first; current; current = NEXT)
45         {
46                 current->position = (int64_t)((double)current->position * 
47                         new_rate / 
48                         old_rate + 
49                         0.5);
50         }
53 void Autos::equivalent_output(Autos *autos, int64_t startproject, int64_t *result)
55         if(
56 // Default keyframe differs
57                 (!total() && !(*default_auto == *autos->default_auto))
58                 )
59         {
60                 if(*result < 0 || *result > startproject) *result = startproject;
61         }
62         else
63 // Search for difference
64         {
65                 for(Auto *current = first, *that_current = autos->first; 
66                         current || that_current; 
67                         current = NEXT,
68                         that_current = that_current->next)
69                 {
70 // Total differs
71                         if(current && !that_current)
72                         {
73                                 int64_t position1 = (autos->last ? autos->last->position : startproject);
74                                 int64_t position2 = current->position;
75                                 if(*result < 0 || *result > MIN(position1, position2))
76                                         *result = MIN(position1, position2);
77                                 break;
78                         }
79                         else
80                         if(!current && that_current)
81                         {
82                                 int64_t position1 = (last ? last->position : startproject);
83                                 int64_t position2 = that_current->position;
84                                 if(*result < 0 || *result > MIN(position1, position2))
85                                         *result = MIN(position1, position2);
86                                 break;
87                         }
88                         else
89 // Keyframes differ
90                         if(!(*current == *that_current) || 
91                                 current->position != that_current->position)
92                         {
93                                 int64_t position1 = (current->previous ? 
94                                         current->previous->position : 
95                                         startproject);
96                                 int64_t position2 = (that_current->previous ? 
97                                         that_current->previous->position : 
98                                         startproject);
99                                 if(*result < 0 || *result > MIN(position1, position2))
100                                         *result = MIN(position1, position2);
101                                 break;
102                         }
103                 }
104         }
107 void Autos::copy_from(Autos *autos)
109         Auto *current = autos->first, *this_current = first;
111         default_auto->copy_from(autos->default_auto);
113 // Detect common memory leak bug
114         if(autos->first && !autos->last)
115         {
116                 printf("Autos::copy_from inconsistent pointers\n");
117                 exit(1);
118         }
120         for(current = autos->first; current; current = NEXT)
121         {
122 //printf("Autos::copy_from 1 %p\n", current);
123 //sleep(1);
124                 if(!this_current)
125                 {
126                         append(this_current = new_auto());
127                 }
128                 this_current->copy_from(current);
129                 this_current = this_current->next;
130         }
132         for( ; this_current; )
133         {
134                 Auto *next_current = this_current->next;
135                 delete this_current;
136                 this_current = next_current;
137         }
141 // We don't replace it in pasting but
142 // when inserting the first EDL of a load operation we need to replace
143 // the default keyframe.
144 void Autos::insert_track(Autos *automation, 
145         int64_t start_unit, 
146         int64_t length_units,
147         int replace_default)
149 // Insert silence
150         insert(start_unit, start_unit + length_units);
152         if(replace_default) default_auto->copy_from(automation->default_auto);
153         for(Auto *current = automation->first; current; current = NEXT)
154         {
155                 Auto *new_auto = insert_auto(start_unit + current->position);
156                 new_auto->copy_from(current);
157 // Override copy_from
158                 new_auto->position = current->position + start_unit;
159         }
162 Auto* Autos::get_prev_auto(int64_t position, int direction, Auto* &current, int use_default)
164 // Get on or before position
165         if(direction == PLAY_FORWARD)
166         {
167 // Try existing result
168                 if(current)
169                 {
170                         while(current && current->position < position) current = NEXT;
171                         while(current && current->position > position) current = PREVIOUS;
172                 }
174                 if(!current)
175                 {
176                         for(current = last; 
177                                 current && current->position > position; 
178                                 current = PREVIOUS) ;
179                 }
180                 if(!current && use_default) current = (first ? first : default_auto);
181         }
182         else
183 // Get on or after position
184         if(direction == PLAY_REVERSE)
185         {
186                 if(current)
187                 {
188                         while(current && current->position > position) current = PREVIOUS;
189                         while(current && current->position < position) current = NEXT;
190                 }
192                 if(!current)
193                 {
194                         for(current = first; 
195                                 current && current->position < position; 
196                                 current = NEXT) ;
197                 }
199                 if(!current && use_default) current = (last ? last : default_auto);
200         }
202         return current;
205 Auto* Autos::get_prev_auto(int direction, Auto* &current)
207         double position_double = edl->local_session->selectionstart;
208         position_double = edl->align_to_frame(position_double, 0);
209         int64_t position = track->to_units(position_double, 0);
211         return get_prev_auto(position, direction, current);
213         return current;
216 int Autos::auto_exists_for_editing(double position)
218         int result = 0;
219         
220         if(edl->session->auto_keyframes)
221         {
222                 double unit_position = position;
223                 unit_position = edl->align_to_frame(unit_position, 0);
224                 unit_position = track->to_units(unit_position, 0);
226                 for(Auto *current = first; 
227                         current; 
228                         current = NEXT)
229                 {
230                         if(edl->equivalent(current->position, unit_position))
231                         {
232                                 result = 1;
233                                 break;
234                         }
235                 }
236         }
237         else
238         {
239                 result = 1;
240         }
242         return result;
245 Auto* Autos::get_auto_for_editing(double position)
247         if(position < 0)
248         {
249                 position = edl->local_session->selectionstart;
250         }
252         Auto *result = 0;
253         position = edl->align_to_frame(position, 0);
258 //printf("Autos::get_auto_for_editing %p %p\n", first, default_auto);
260         if(edl->session->auto_keyframes)
261         {
262                 result = insert_auto(track->to_units(position, 0));
263         }
264         else
265                 result = get_prev_auto(track->to_units(position, 0), 
266                         PLAY_FORWARD, 
267                         result);
269 //printf("Autos::get_auto_for_editing %p %p %p\n", default_auto, first, result);
270         return result;
274 Auto* Autos::get_next_auto(int64_t position, int direction, Auto* &current, int use_default)
276         if(direction == PLAY_FORWARD)
277         {
278                 if(current)
279                 {
280                         while(current && current->position > position) current = PREVIOUS;
281                         while(current && current->position < position) current = NEXT;
282                 }
284                 if(!current)
285                 {
286                         for(current = first;
287                                 current && current->position <= position;
288                                 current = NEXT)
289                                 ;
290                 }
292                 if(!current && use_default) current = (last ? last : default_auto);
293         }
294         else
295         if(direction == PLAY_REVERSE)
296         {
297                 if(current)
298                 {
299                         while(current && current->position < position) current = NEXT;
300                         while(current && current->position > position) current = PREVIOUS;
301                 }
303                 if(!current)
304                 {
305                         for(current = last;
306                                 current && current->position > position;
307                                 current = PREVIOUS)
308                                 ;
309                 }
311                 if(!current && use_default) current = (first ? first : default_auto);
312         }
314         return current;
317 Auto* Autos::insert_auto(int64_t position)
319         Auto *current, *result;
321 // Test for existence
322         for(current = first; 
323                 current && !edl->equivalent(current->position, position); 
324                 current = NEXT)
325         {
326                 ;
327         }
329 //printf("Autos::insert_auto %p\n", current);
330 // Insert new
331         if(!current)
332         {
333 // Get first one on or before as a template
334                 for(current = last; 
335                         current && current->position > position; 
336                         current = PREVIOUS)
337                 {
338                         ;
339                 }
341                 if(current)
342                 {
343                         insert_after(current, result = new_auto());
344                         result->copy_from(current);
345                 }
346                 else
347                 {
348                         current = first;
349                         if(!current) current = default_auto;
351                         insert_before(first, result = new_auto());
352                         if(current) result->copy_from(current);
353                 }
355                 result->position = position;
356         }
357         else
358         {
359                 result = current;
360         }
362         return result;
365 int Autos::clear_all()
367         Auto *current_, *current;
368         
369         for(current = first; current; current = current_)
370         {
371                 current_ = NEXT;
372                 remove(current);
373         }
374         add_auto(0, default_);
375         return 0;
378 int Autos::insert(int64_t start, int64_t end)
380         int64_t length;
381         Auto *current = first;
383         for( ; current && current->position < start; current = NEXT)
384                 ;
386         length = end - start;
388         for(; current; current = NEXT)
389         {
390                 current->position += length;
391         }
392         return 0;
395 void Autos::paste(int64_t start, 
396         int64_t length, 
397         double scale, 
398         FileXML *file, 
399         int default_only)
401         int total = 0;
402         int result = 0;
404 //printf("Autos::paste %ld\n", start);
405         do{
406                 result = file->read_tag();
408                 if(!result)
409                 {
410 // End of list
411                         if(strstr(file->tag.get_title(), "AUTOS") && 
412                                 file->tag.get_title()[0] == '/')
413                         {
414                                 result = 1;
415                         }
416                         else
417                         if(!strcmp(file->tag.get_title(), "AUTO"))
418                         {
419                                 Auto *current = 0;
421 // Paste first active auto into default                         
422                                 if(default_only)
423                                 {
424                                         if(total == 1)
425                                         {
426                                                 current = default_auto;
427                                         }
428                                 }
429                                 else
430 // Paste default auto into default
431                                 if(total == 0)
432                                         current = default_auto;
433                                 else
434                                 {
435                                         int64_t position = Units::to_int64(
436                                                 (double)file->tag.get_property("POSITION", 0) *
437                                                         scale + 
438                                                         start);
439 // Paste active auto into track
440                                         current = insert_auto(position);
441                                 }
443                                 if(current)
444                                 {
445                                         current->load(file);
446                                 }
447                                 total++;
448                         }
449                 }
450         }while(!result);
451         
455 int Autos::paste_silence(int64_t start, int64_t end)
457         insert(start, end);
458         return 0;
461 int Autos::copy(int64_t start, 
462         int64_t end, 
463         FileXML *file, 
464         int default_only,
465         int autos_only)
467 // First auto is always loaded into default even if it is discarded in a paste
468 // operation
469 //printf("Autos::copy 1 %d %d %p\n", default_only, start, autoof(start));
470         if(!autos_only)
471         {
472                 default_auto->copy(0, 0, file, default_only);
473         }
475 //printf("Autos::copy 10 %d %d %p\n", default_only, start, autoof(start));
476         if(!default_only)
477         {
478                 for(Auto* current = autoof(start); 
479                         current && current->position <= end; 
480                         current = NEXT)
481                 {
482 // Want to copy single keyframes by putting the cursor on them
483                         if(current->position >= start && current->position <= end)
484                         {
485                                 current->copy(start, end, file, default_only);
486                         }
487                 }
488         }
489 // Copy default auto again to make it the active auto on the clipboard
490         else
491         {
492 // Need to force position to 0 for the case of plugins
493 // and default status to 0.
494                 default_auto->copy(0, 0, file, default_only);
495         }
496 //printf("Autos::copy 20\n");
498         return 0;
501 // Remove 3 consecutive autos with the same value
502 // Remove autos which are out of order
503 void Autos::optimize()
505         int done = 0;
507         while(!done)
508         {
509                 int consecutive = 0;
510                 done = 1;
511                 
512                 
513                 for(Auto *current = first; current; current = NEXT)
514                 {
515 // Get 3rd consecutive auto of equal value
516                         if(current != first)
517                         {
518                                 if(*current == *PREVIOUS)
519                                 {
520                                         consecutive++;
521                                         if(consecutive >= 3)
522                                         {
523                                                 delete PREVIOUS;
524                                                 break;
525                                         }
526                                 }
527                                 else
528                                         consecutive = 0;
529                                 
530                                 if(done && current->position <= PREVIOUS->position)
531                                 {
532                                         delete current;
533                                         break;
534                                 }
535                         }
536                 }
537         }
541 void Autos::remove_nonsequential(Auto *keyframe)
543         if((keyframe->next && keyframe->next->position <= keyframe->position) ||
544                 (keyframe->previous && keyframe->previous->position >= keyframe->position))
545         {
546                 delete keyframe;
547         }
553 void Autos::clear(int64_t start, 
554         int64_t end, 
555         int shift_autos)
557         int64_t length;
558         Auto *next, *current;
559         length = end - start;
562         current = autoof(start);
564 // If a range is selected don't delete the ending keyframe but do delete
565 // the beginning keyframe because shifting end handle forward shouldn't
566 // delete the first keyframe of the next edit.
568         while(current && 
569                 ((end != start && current->position < end) ||
570                 (end == start && current->position <= end)))
571         {
572                 next = NEXT;
573                 remove(current);
574                 current = next;
575         }
577         while(current && shift_autos)
578         {
579                 current->position -= length;
580                 current = NEXT;
581         }
584 int Autos::clear_auto(int64_t position)
586         Auto *current;
587         current = autoof(position);
588         if(current->position == position) remove(current);
592 int Autos::load(FileXML *file)
594         while(last)
595                 remove(last);    // remove any existing autos
597         int result = 0, first_auto = 1;
598         Auto *current;
599         
600         do{
601                 result = file->read_tag();
602                 
603                 if(!result)
604                 {
605                         if(strstr(file->tag.get_title(), "AUTOS") && file->tag.get_title()[0] == '/')
606                         {
607                                 result = 1;
608                         }
609                         else
610                         if(!strcmp(file->tag.get_title(), "AUTO"))
611                         {
612                                 if(first_auto)
613                                 {
614                                         default_auto->load(file);
615                                         default_auto->position = 0;
616                                         first_auto = 0;
617                                 }
618                                 else
619                                 {
620                                         current = append(new_auto());
621                                         current->position = file->tag.get_property("POSITION", (int64_t)0);
622                                         current->load(file);
623                                 }
624                         }
625                 }
626         }while(!result);
627         return 0;
635 int Autos::slope_adjustment(int64_t ax, double slope)
637         return (int)(ax * slope);
641 int Autos::scale_time(float rate_scale, int scale_edits, int scale_autos, int64_t start, int64_t end)
643         Auto *current;
644         
645         for(current = first; current && scale_autos; current = NEXT)
646         {
647 //              if(current->position >= start && current->position <= end)
648 //              {
649                         current->position = (int64_t)((current->position - start) * rate_scale + start + 0.5);
650 //              }
651         }
652         return 0;
655 Auto* Autos::autoof(int64_t position)
657         Auto *current;
659         for(current = first; 
660                 current && current->position < position; 
661                 current = NEXT)
662         { 
663                 ;
664         }
665         return current;     // return 0 on failure
668 Auto* Autos::nearest_before(int64_t position)
670         Auto *current;
672         for(current = last; current && current->position >= position; current = PREVIOUS)
673         { ; }
676         return current;     // return 0 on failure
679 Auto* Autos::nearest_after(int64_t position)
681         Auto *current;
683         for(current = first; current && current->position <= position; current = NEXT)
684         { ; }
687         return current;     // return 0 on failure
690 int Autos::get_neighbors(int64_t start, int64_t end, Auto **before, Auto **after)
692         if(*before == 0) *before = first;
693         if(*after == 0) *after = last; 
695         while(*before && (*before)->next && (*before)->next->position <= start)
696                 *before = (*before)->next;
697         
698         while(*after && (*after)->previous && (*after)->previous->position >= end)
699                 *after = (*after)->previous;
701         while(*before && (*before)->position > start) *before = (*before)->previous;
702         
703         while(*after && (*after)->position < end) *after = (*after)->next;
704         return 0;
707 int Autos::automation_is_constant(int64_t start, int64_t end)
709         return 0;
712 double Autos::get_automation_constant(int64_t start, int64_t end)
714         return 0;
718 int Autos::init_automation(int64_t &buffer_position,
719                                 int64_t &input_start, 
720                                 int64_t &input_end, 
721                                 int &automate, 
722                                 double &constant, 
723                                 int64_t input_position,
724                                 int64_t buffer_len,
725                                 Auto **before, 
726                                 Auto **after,
727                                 int reverse)
729         buffer_position = 0;
731 // set start and end boundaries for automation info
732         input_start = reverse ? input_position - buffer_len : input_position;
733         input_end = reverse ? input_position : input_position + buffer_len;
735 // test automation for constant value
736 // and set up *before and *after
737         if(automate)
738         {
739                 if(automation_is_constant(input_start, input_end))
740                 {
741                         constant += get_automation_constant(input_start, input_end);
742                         automate = 0;
743                 }
744         }
745         return automate;
749 int Autos::init_slope(Auto **current_auto, 
750                                 double &slope_start, 
751                                 double &slope_value,
752                                 double &slope_position, 
753                                 int64_t &input_start, 
754                                 int64_t &input_end, 
755                                 Auto **before, 
756                                 Auto **after,
757                                 int reverse)
759 // apply automation
760         *current_auto = reverse ? *after : *before;
761 // no auto before start so use first auto in range
762 // already know there is an auto since automation isn't constant
763         if(!*current_auto)
764         {
765                 *current_auto = reverse ? last : first;
766 //              slope_value = (*current_auto)->value;
767                 slope_start = input_start;
768                 slope_position = 0;
769         }
770         else
771         {
772 // otherwise get the first slope point and advance auto
773 //              slope_value = (*current_auto)->value;
774                 slope_start = (*current_auto)->position;
775                 slope_position = reverse ? slope_start - input_end : input_start - slope_start;
776                 (*current_auto) = reverse ? (*current_auto)->previous : (*current_auto)->next;
777         }
778         return 0;
782 int Autos::get_slope(Auto **current_auto, 
783                                 double &slope_start, 
784                                 double &slope_end, 
785                                 double &slope_value,
786                                 double &slope, 
787                                 int64_t buffer_len, 
788                                 int64_t buffer_position,
789                                 int reverse)
791 // get the slope
792         if(*current_auto)
793         {
794                 slope_end = reverse ? slope_start - (*current_auto)->position : (*current_auto)->position - slope_start;
795                 if(slope_end) 
796 //                      slope = ((*current_auto)->value - slope_value) / slope_end;
797 //              else
798                         slope = 0;
799         }
800         else
801         {
802                 slope = 0;
803                 slope_end = buffer_len - buffer_position;
804         }
805         return 0;
808 int Autos::advance_slope(Auto **current_auto, 
809                                 double &slope_start, 
810                                 double &slope_value,
811                                 double &slope_position, 
812                                 int reverse)
814         if(*current_auto) 
815         {
816                 slope_start = (*current_auto)->position;
817 //              slope_value = (*current_auto)->value;
818                 (*current_auto) = reverse ? (*current_auto)->previous : (*current_auto)->next;
819                 slope_position = 0;
820         }
821         return 0;
824 float Autos::value_to_percentage()
826         return 0;
829 int64_t Autos::get_length()
831         if(last) 
832                 return last->position + 1;
833         else
834                 return 0;