r125: This commit was manufactured by cvs2svn to create tag 'r1_1_7-last'.
[cinelerra_cv/mob.git] / hvirtual / cinelerra / floatautos.C
blobe896f7bad4fe92378699ed78306ea4f9676ec35d
1 #include "clip.h"
2 #include "filexml.h"
3 #include "floatauto.h"
4 #include "floatautos.h"
5 #include "transportque.inc"
7 FloatAutos::FloatAutos(EDL *edl,
8                                 Track *track, 
9                                 int color, 
10                                 float min, 
11                                 float max, 
12                                 float default_,
13                                 int virtual_h,
14                                 int use_floats)
15  : Autos(edl, track)
17         this->max = max; 
18         this->min = min;
19         this->default_ = default_;
20         this->virtual_h = virtual_h;
21         this->use_floats = use_floats;
24 FloatAutos::~FloatAutos()
28 int FloatAutos::get_track_pixels(int zoom_track, int pixel, int &center_pixel, float &yscale)
30         center_pixel = pixel + zoom_track / 2;
31         yscale = -(float)zoom_track / (max - min);
34 int FloatAutos::draw_joining_line(BC_SubWindow *canvas, int vertical, int center_pixel, int x1, int y1, int x2, int y2)
36         if(vertical)
37         canvas->draw_line(center_pixel - y1, x1, center_pixel - y2, x2);
38         else
39         canvas->draw_line(x1, center_pixel + y1, x2, center_pixel + y2);
42 Auto* FloatAutos::add_auto(int64_t position, float value)
44         FloatAuto* current = (FloatAuto*)autoof(position);
45         FloatAuto* new_auto;
46         
47         insert_before(current, new_auto = new FloatAuto(edl, this));
49         new_auto->position = position;
50         new_auto->value = value;
51         
52         return new_auto;
55 Auto* FloatAutos::append_auto()
57         return append(new FloatAuto(edl, this));
60 Auto* FloatAutos::new_auto()
62         return new FloatAuto(edl, this);
65 float FloatAutos::fix_value(float value)
67         int value_int;
68         
69         if(use_floats)
70         {
71 // Fix precision
72                 value_int = (int)(value * 100);
73                 value = (float)value_int / 100;
74         }
75         else
76         {
77 // not really floating point
78                 value_int = (int)value;
79                 value = value_int;
80         }
82         if(value < min) value = min;
83         else
84         if(value > max) value = max;
85         
86         return value;   
89 int FloatAutos::get_testy(float slope, int cursor_x, int ax, int ay)
91         return (int)(slope * (cursor_x - ax)) + ay;
94 int FloatAutos::automation_is_constant(int64_t start, 
95         int64_t length, 
96         int direction,
97         double &constant)
99         int total_autos = total();
100         int64_t end;
101         if(direction == PLAY_FORWARD)
102         {
103                 end = start + length;
104         }
105         else
106         {
107                 end = start + 1;
108                 start -= length;
109         }
111 //printf("FloatAutos::automation_is_constant 1 %d %d\n", start, end);
113 // No keyframes on track
114         if(total_autos == 0)
115         {
116                 constant = ((FloatAuto*)default_auto)->value;
117                 return 1;
118         }
119         else
120 // Only one keyframe on track.
121         if(total_autos == 1)
122         {
123                 constant = ((FloatAuto*)first)->value;
124                 return 1;
125         }
126         else
127 // Last keyframe is before region
128         if(last->position <= start)
129         {
130                 constant = ((FloatAuto*)last)->value;
131                 return 1;
132         }
133         else
134 // First keyframe is after region
135         if(first->position > end)
136         {
137                 constant = ((FloatAuto*)first)->value;
138                 return 1;
139         }
141 // Scan sequentially
142         int64_t prev_position = -1;
143         for(Auto *current = first; current; current = NEXT)
144         {
145                 int test_current_next = 0;
146                 int test_previous_current = 0;
147                 FloatAuto *float_current = (FloatAuto*)current;
149 // keyframes before and after region but not in region
150                 if(prev_position >= 0 &&
151                         prev_position < start && 
152                         current->position >= end)
153                 {
154 // Get value now in case change doesn't occur
155                         constant = float_current->value;
156                         test_previous_current = 1;
157                 }
158                 prev_position = current->position;
160 // Keyframe occurs in the region
161                 if(!test_previous_current &&
162                         current->position < end && 
163                         current->position >= start)
164                 {
166 // Get value now in case change doesn't occur
167                         constant = float_current->value;
169 // Keyframe has neighbor
170                         if(current->previous)
171                         {
172                                 test_previous_current = 1;
173                         }
175                         if(current->next)
176                         {
177                                 test_current_next = 1;
178                         }
179                 }
181                 if(test_current_next)
182                 {
183 //printf("FloatAutos::automation_is_constant 1 %d\n", start);
184                         FloatAuto *float_next = (FloatAuto*)current->next;
186 // Change occurs between keyframes
187                         if(!EQUIV(float_current->value, float_next->value) ||
188                                 !EQUIV(float_current->control_out_value, 0) ||
189                                 !EQUIV(float_next->control_in_value, 0))
190                         {
191                                 return 0;
192                         }
193                 }
195                 if(test_previous_current)
196                 {
197                         FloatAuto *float_previous = (FloatAuto*)current->previous;
199 // Change occurs between keyframes
200                         if(!EQUIV(float_current->value, float_previous->value) ||
201                                 !EQUIV(float_current->control_in_value, 0) ||
202                                 !EQUIV(float_previous->control_out_value, 0))
203                         {
204 // printf("FloatAutos::automation_is_constant %d %d %d %f %f %f %f\n", 
205 // start, 
206 // float_previous->position, 
207 // float_current->position, 
208 // float_previous->value, 
209 // float_current->value, 
210 // float_previous->control_out_value, 
211 // float_current->control_in_value);
212                                 return 0;
213                         }
214                 }
215         }
217 // Got nothing that changes in the region.
218         return 1;
221 double FloatAutos::get_automation_constant(int64_t start, int64_t end)
223         Auto *current_auto, *before = 0, *after = 0;
224         
225 // quickly get autos just outside range 
226         get_neighbors(start, end, &before, &after);
228 // no auto before range so use first
229         if(before)
230                 current_auto = before;
231         else
232                 current_auto = first;
234 // no autos at all so use default value
235         if(!current_auto) current_auto = default_auto;
237         return ((FloatAuto*)current_auto)->value;
241 float FloatAutos::get_value(int64_t position, 
242         int direction, 
243         FloatAuto* &previous, 
244         FloatAuto* &next)
246         double slope;
247         double intercept;
248         int64_t slope_len;
249 // Calculate bezier equation at position
250         float y0, y1, y2, y3;
251         float t;
253         previous = (FloatAuto*)get_prev_auto(position, direction, (Auto*)previous, 0);
254         next = (FloatAuto*)get_next_auto(position, direction, (Auto*)next, 0);
256 // Constant
257         if(!next && !previous)
258         {
259                 return ((FloatAuto*)default_auto)->value;
260         }
261         else
262         if(!previous)
263         {
264                 return next->value;
265         }
266         else
267         if(!next)
268         {
269                 return previous->value;
270         }
271         else
272         if(next == previous)
273         {
274                 return previous->value;
275         }
276         else
277         {
278                 if(direction == PLAY_FORWARD &&
279                         EQUIV(previous->value, next->value) &&
280                         EQUIV(previous->control_out_value, 0) &&
281                         EQUIV(next->control_in_value, 0))
282                 {
283                         return previous->value;
284                 }
285                 else
286                 if(direction == PLAY_REVERSE &&
287                         EQUIV(previous->value, next->value) &&
288                         EQUIV(previous->control_in_value, 0) &&
289                         EQUIV(next->control_out_value, 0))
290                 {
291                         return previous->value;
292                 }
293         }
296 // Interpolate
297         y0 = previous->value;
298         y3 = next->value;
300         if(direction == PLAY_FORWARD)
301         {
302                 y1 = previous->value + previous->control_out_value * 2;
303                 y2 = next->value + next->control_in_value * 2;
304                 t = (double)(position - previous->position) / 
305                         (next->position - previous->position);
306 // division by 0
307                 if(next->position - previous->position == 0) return previous->value;
308         }
309         else
310         {
311                 y1 = previous->value + previous->control_in_value * 2;
312                 y2 = next->value + next->control_out_value * 2;
313                 t = (double)(previous->position - position) / 
314                         (previous->position - next->position);
315 // division by 0
316                 if(previous->position - next->position == 0) return previous->value;
317         }
319         float tpow2 = t * t;
320         float tpow3 = t * t * t;
321         float invt = 1 - t;
322         float invtpow2 = invt * invt;
323         float invtpow3 = invt * invt * invt;
324         
325         float result = (  invtpow3 * y0
326                 + 3 * t     * invtpow2 * y1
327                 + 3 * tpow2 * invt     * y2 
328                 +     tpow3            * y3);
329 //printf("FloatAutos::get_value %f %f %d %d %d %d\n", result, t, direction, position, previous->position, next->position);
331         return result;
335 //      get_fade_automation(slope,
336 //              intercept,
337 //              position,
338 //              slope_len,
339 //              PLAY_FORWARD);
340 // 
341 //      return (float)intercept;
345 void FloatAutos::get_fade_automation(double &slope,
346         double &intercept,
347         int64_t input_position,
348         int64_t &slope_len,
349         int direction)
351         Auto *current = 0;
352         FloatAuto *prev_keyframe = 
353                 (FloatAuto*)get_prev_auto(input_position, direction, current);
354         FloatAuto *next_keyframe = 
355                 (FloatAuto*)get_next_auto(input_position, direction, current);
356         int64_t new_slope_len;
358         if(direction == PLAY_FORWARD)
359         {
360                 new_slope_len = next_keyframe->position - prev_keyframe->position;
362 //printf("FloatAutos::get_fade_automation %d %d %d\n", 
363 //      prev_keyframe->position, input_position, next_keyframe->position);
365 // Two distinct automation points within range
366                 if(next_keyframe->position > prev_keyframe->position)
367                 {
368                         slope = ((double)next_keyframe->value - prev_keyframe->value) / 
369                                 new_slope_len;
370                         intercept = ((double)input_position - prev_keyframe->position) * slope + prev_keyframe->value;
372                         if(next_keyframe->position < input_position + new_slope_len)
373                                 new_slope_len = next_keyframe->position - input_position;
374                         slope_len = MIN(slope_len, new_slope_len);
375                 }
376                 else
377 // One automation point within range
378                 {
379                         slope = 0;
380                         intercept = prev_keyframe->value;
381                 }
382         }
383         else
384         {
385                 new_slope_len = prev_keyframe->position - next_keyframe->position;
386 // Two distinct automation points within range
387                 if(next_keyframe->position < prev_keyframe->position)
388                 {
389                         slope = ((double)next_keyframe->value - prev_keyframe->value) / new_slope_len;
390                         intercept = ((double)prev_keyframe->position - input_position) * slope + prev_keyframe->value;
392                         if(prev_keyframe->position > input_position - new_slope_len)
393                                 new_slope_len = input_position - prev_keyframe->position;
394                         slope_len = MIN(slope_len, new_slope_len);
395                 }
396                 else
397 // One automation point within range
398                 {
399                         slope = 0;
400                         intercept = next_keyframe->value;
401                 }
402         }
405 float FloatAutos::value_to_percentage(float value)
407         return (value - min) / (max - min);
411 int FloatAutos::dump()
413         printf("        FloatAutos::dump %p\n", this);
414         printf("        Default: position %lld value=%f\n", 
415                 default_auto->position, 
416                 ((FloatAuto*)default_auto)->value);
417         for(Auto* current = first; current; current = NEXT)
418         {
419                 printf("        position %lld value=%f invalue=%f outvalue=%f\n", 
420                         current->position, 
421                         ((FloatAuto*)current)->value,
422                         ((FloatAuto*)current)->control_in_value,
423                         ((FloatAuto*)current)->control_out_value);
424         }
425         return 0;