r820: Move from x-devb to xorg-dev
[cinelerra_cv/mob.git] / cinelerra / floatautos.C
blob2b57a9b50d2cff184e7c40072671af465ff33e03
1 #include "automation.inc"
2 #include "clip.h"
3 #include "edl.h"
4 #include "edlsession.h"
5 #include "filexml.h"
6 #include "floatauto.h"
7 #include "floatautos.h"
8 #include "track.h"
9 #include "localsession.h"
10 #include "transportque.inc"
12 FloatAutos::FloatAutos(EDL *edl,
13                                 Track *track, 
14                                 float default_)
15  : Autos(edl, track)
17         this->default_ = default_;
18         type = AUTOMATION_TYPE_FLOAT;
21 FloatAutos::~FloatAutos()
25 int FloatAutos::draw_joining_line(BC_SubWindow *canvas, int vertical, int center_pixel, int x1, int y1, int x2, int y2)
27         if(vertical)
28                 canvas->draw_line(center_pixel - y1, x1, center_pixel - y2, x2);
29         else
30                 canvas->draw_line(x1, center_pixel + y1, x2, center_pixel + y2);
33 Auto* FloatAutos::add_auto(int64_t position, float value)
35         FloatAuto* current = (FloatAuto*)autoof(position);
36         FloatAuto* result;
37         
38         insert_before(current, result = (FloatAuto*)new_auto());
40         result->position = position;
41         result->value = value;
42         
43         return result;
46 Auto* FloatAutos::new_auto()
48         FloatAuto *result = new FloatAuto(edl, this);
49         result->value = default_;
50         return result;
53 int FloatAutos::get_testy(float slope, int cursor_x, int ax, int ay)
55         return (int)(slope * (cursor_x - ax)) + ay;
58 int FloatAutos::automation_is_constant(int64_t start, 
59         int64_t length, 
60         int direction,
61         double &constant)
63         int total_autos = total();
64         int64_t end;
65         if(direction == PLAY_FORWARD)
66         {
67                 end = start + length;
68         }
69         else
70         {
71                 end = start + 1;
72                 start -= length;
73         }
76 // No keyframes on track
77         if(total_autos == 0)
78         {
79                 constant = ((FloatAuto*)default_auto)->value;
80                 return 1;
81         }
82         else
83 // Only one keyframe on track.
84         if(total_autos == 1)
85         {
86                 constant = ((FloatAuto*)first)->value;
87                 return 1;
88         }
89         else
90 // Last keyframe is before region
91         if(last->position <= start)
92         {
93                 constant = ((FloatAuto*)last)->value;
94                 return 1;
95         }
96         else
97 // First keyframe is after region
98         if(first->position > end)
99         {
100                 constant = ((FloatAuto*)first)->value;
101                 return 1;
102         }
104 // Scan sequentially
105         int64_t prev_position = -1;
106         for(Auto *current = first; current; current = NEXT)
107         {
108                 int test_current_next = 0;
109                 int test_previous_current = 0;
110                 FloatAuto *float_current = (FloatAuto*)current;
112 // keyframes before and after region but not in region
113                 if(prev_position >= 0 &&
114                         prev_position < start && 
115                         current->position >= end)
116                 {
117 // Get value now in case change doesn't occur
118                         constant = float_current->value;
119                         test_previous_current = 1;
120                 }
121                 prev_position = current->position;
123 // Keyframe occurs in the region
124                 if(!test_previous_current &&
125                         current->position < end && 
126                         current->position >= start)
127                 {
129 // Get value now in case change doesn't occur
130                         constant = float_current->value;
132 // Keyframe has neighbor
133                         if(current->previous)
134                         {
135                                 test_previous_current = 1;
136                         }
138                         if(current->next)
139                         {
140                                 test_current_next = 1;
141                         }
142                 }
144                 if(test_current_next)
145                 {
146 //printf("FloatAutos::automation_is_constant 1 %d\n", start);
147                         FloatAuto *float_next = (FloatAuto*)current->next;
149 // Change occurs between keyframes
150                         if(!EQUIV(float_current->value, float_next->value) ||
151                                 !EQUIV(float_current->control_out_value, 0) ||
152                                 !EQUIV(float_next->control_in_value, 0))
153                         {
154                                 return 0;
155                         }
156                 }
158                 if(test_previous_current)
159                 {
160                         FloatAuto *float_previous = (FloatAuto*)current->previous;
162 // Change occurs between keyframes
163                         if(!EQUIV(float_current->value, float_previous->value) ||
164                                 !EQUIV(float_current->control_in_value, 0) ||
165                                 !EQUIV(float_previous->control_out_value, 0))
166                         {
167 // printf("FloatAutos::automation_is_constant %d %d %d %f %f %f %f\n", 
168 // start, 
169 // float_previous->position, 
170 // float_current->position, 
171 // float_previous->value, 
172 // float_current->value, 
173 // float_previous->control_out_value, 
174 // float_current->control_in_value);
175                                 return 0;
176                         }
177                 }
178         }
180 // Got nothing that changes in the region.
181         return 1;
184 double FloatAutos::get_automation_constant(int64_t start, int64_t end)
186         Auto *current_auto, *before = 0, *after = 0;
187         
188 // quickly get autos just outside range 
189         get_neighbors(start, end, &before, &after);
191 // no auto before range so use first
192         if(before)
193                 current_auto = before;
194         else
195                 current_auto = first;
197 // no autos at all so use default value
198         if(!current_auto) current_auto = default_auto;
200         return ((FloatAuto*)current_auto)->value;
204 float FloatAutos::get_value(int64_t position, 
205         int direction, 
206         FloatAuto* &previous, 
207         FloatAuto* &next)
209         double slope;
210         double intercept;
211         int64_t slope_len;
212 // Calculate bezier equation at position
213         float y0, y1, y2, y3;
214         float t;
216         previous = (FloatAuto*)get_prev_auto(position, direction, (Auto* &)previous, 0);
217         next = (FloatAuto*)get_next_auto(position, direction, (Auto* &)next, 0);
219 // Constant
220         if(!next && !previous)
221         {
222                 return ((FloatAuto*)default_auto)->value;
223         }
224         else
225         if(!previous)
226         {
227                 return next->value;
228         }
229         else
230         if(!next)
231         {
232                 return previous->value;
233         }
234         else
235         if(next == previous)
236         {
237                 return previous->value;
238         }
239         else
240         {
241                 if(direction == PLAY_FORWARD &&
242                         EQUIV(previous->value, next->value) &&
243                         EQUIV(previous->control_out_value, 0) &&
244                         EQUIV(next->control_in_value, 0))
245                 {
246                         return previous->value;
247                 }
248                 else
249                 if(direction == PLAY_REVERSE &&
250                         EQUIV(previous->value, next->value) &&
251                         EQUIV(previous->control_in_value, 0) &&
252                         EQUIV(next->control_out_value, 0))
253                 {
254                         return previous->value;
255                 }
256         }
259 // Interpolate
260         y0 = previous->value;
261         y3 = next->value;
263         if(direction == PLAY_FORWARD)
264         {
265                 y1 = previous->value + previous->control_out_value * 2;
266                 y2 = next->value + next->control_in_value * 2;
267                 t = (double)(position - previous->position) / 
268                         (next->position - previous->position);
269 // division by 0
270                 if(next->position - previous->position == 0) return previous->value;
271         }
272         else
273         {
274                 y1 = previous->value + previous->control_in_value * 2;
275                 y2 = next->value + next->control_out_value * 2;
276                 t = (double)(previous->position - position) / 
277                         (previous->position - next->position);
278 // division by 0
279                 if(previous->position - next->position == 0) return previous->value;
280         }
282         float tpow2 = t * t;
283         float tpow3 = t * t * t;
284         float invt = 1 - t;
285         float invtpow2 = invt * invt;
286         float invtpow3 = invt * invt * invt;
287         
288         float result = (  invtpow3 * y0
289                 + 3 * t     * invtpow2 * y1
290                 + 3 * tpow2 * invt     * y2 
291                 +     tpow3            * y3);
292 //printf("FloatAutos::get_value %f %f %d %d %d %d\n", result, t, direction, position, previous->position, next->position);
294         return result;
298 //      get_fade_automation(slope,
299 //              intercept,
300 //              position,
301 //              slope_len,
302 //              PLAY_FORWARD);
303 // 
304 //      return (float)intercept;
308 void FloatAutos::get_fade_automation(double &slope,
309         double &intercept,
310         int64_t input_position,
311         int64_t &slope_len,
312         int direction)
314         Auto *current = 0;
315         FloatAuto *prev_keyframe = 
316                 (FloatAuto*)get_prev_auto(input_position, direction, current);
317         FloatAuto *next_keyframe = 
318                 (FloatAuto*)get_next_auto(input_position, direction, current);
319         int64_t new_slope_len;
321         if(direction == PLAY_FORWARD)
322         {
323                 new_slope_len = next_keyframe->position - prev_keyframe->position;
325 //printf("FloatAutos::get_fade_automation %d %d %d\n", 
326 //      prev_keyframe->position, input_position, next_keyframe->position);
328 // Two distinct automation points within range
329                 if(next_keyframe->position > prev_keyframe->position)
330                 {
331                         slope = ((double)next_keyframe->value - prev_keyframe->value) / 
332                                 new_slope_len;
333                         intercept = ((double)input_position - prev_keyframe->position) * slope + prev_keyframe->value;
335                         if(next_keyframe->position < input_position + new_slope_len)
336                                 new_slope_len = next_keyframe->position - input_position;
337                         slope_len = MIN(slope_len, new_slope_len);
338                 }
339                 else
340 // One automation point within range
341                 {
342                         slope = 0;
343                         intercept = prev_keyframe->value;
344                 }
345         }
346         else
347         {
348                 new_slope_len = prev_keyframe->position - next_keyframe->position;
349 // Two distinct automation points within range
350                 if(next_keyframe->position < prev_keyframe->position)
351                 {
352                         slope = ((double)next_keyframe->value - prev_keyframe->value) / new_slope_len;
353                         intercept = ((double)prev_keyframe->position - input_position) * slope + prev_keyframe->value;
355                         if(prev_keyframe->position > input_position - new_slope_len)
356                                 new_slope_len = input_position - prev_keyframe->position;
357                         slope_len = MIN(slope_len, new_slope_len);
358                 }
359                 else
360 // One automation point within range
361                 {
362                         slope = 0;
363                         intercept = next_keyframe->value;
364                 }
365         }
368 void FloatAutos::get_extents(float *min, 
369         float *max,
370         int *coords_undefined,
371         int64_t unit_start,
372         int64_t unit_end)
374         if(!edl)
375         {
376                 printf("FloatAutos::get_extents edl == NULL\n");
377                 return;
378         }
380         if(!track)
381         {
382                 printf("FloatAutos::get_extents track == NULL\n");
383                 return;
384         }
386 // Use default auto
387         if(!first)
388         {
389                 FloatAuto *current = (FloatAuto*)default_auto;
390                 if(*coords_undefined)
391                 {
392                         *min = *max = current->value;
393                         *coords_undefined = 0;
394                 }
396                 *min = MIN(current->value, *min);
397                 *max = MAX(current->value, *max);
398         }
400 // Test all handles
401         for(FloatAuto *current = (FloatAuto*)first; current; current = (FloatAuto*)NEXT)
402         {
403                 if(current->position >= unit_start && current->position < unit_end)
404                 {
405                         if(*coords_undefined)
406                         {
407                                 *min = *max = current->value;
408                                 *coords_undefined = 0;
409                         }
410                         
411                         *min = MIN(current->value, *min);
412                         *min = MIN(current->value + current->control_in_value, *min);
413                         *min = MIN(current->value + current->control_out_value, *min);
415                         *max = MAX(current->value, *max);
416                         *max = MAX(current->value + current->control_in_value, *max);
417                         *max = MAX(current->value + current->control_out_value, *max);
418                 }
419         }
421 // Test joining regions
422         FloatAuto *prev = 0;
423         FloatAuto *next = 0;
424         int64_t unit_step = edl->local_session->zoom_sample;
425         if(track->data_type == TRACK_VIDEO)
426                 unit_step = (int64_t)(unit_step * 
427                         edl->session->frame_rate / 
428                         edl->session->sample_rate);
429         unit_step = MAX(unit_step, 1);
430         for(int64_t position = unit_start; 
431                 position < unit_end; 
432                 position += unit_step)
433         {
434                 float value = get_value(position,
435                         PLAY_FORWARD,
436                         prev,
437                         next);
438                 if(*coords_undefined)
439                 {
440                         *min = *max = value;
441                         *coords_undefined = 0;
442                 }
443                 else
444                 {
445                         *min = MIN(value, *min);
446                         *max = MAX(value, *max);
447                 }       
448         }
451 void FloatAutos::dump()
453         printf("        FloatAutos::dump %p\n", this);
454         printf("        Default: position %lld value=%f\n", 
455                 default_auto->position, 
456                 ((FloatAuto*)default_auto)->value);
457         for(Auto* current = first; current; current = NEXT)
458         {
459                 printf("        position %lld value=%f invalue=%f outvalue=%f\n", 
460                         current->position, 
461                         ((FloatAuto*)current)->value,
462                         ((FloatAuto*)current)->control_in_value,
463                         ((FloatAuto*)current)->control_out_value);
464         }