Merge branch 'ct' of git.pipapo.org:cinelerra-ct into ct
[cinelerra_cv/ct.git] / cinelerra / floatautos.C
blob9d53e07a9c38301ee8beda22b2cdb87b75daacd4
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 void FloatAutos::straighten(int64_t start, int64_t end)
27         FloatAuto *current = (FloatAuto*)first;
28         while(current)
29         {
30                 FloatAuto *previous_auto = (FloatAuto*)PREVIOUS;
31                 FloatAuto *next_auto = (FloatAuto*)NEXT;
33 // Is current auto in range?            
34                 if(current->position >= start && current->position < end)
35                 {
36                         float current_value = current->value;
38 // Determine whether to set the control in point.
39                         if(previous_auto && previous_auto->position >= start)
40                         {
41                                 float previous_value = previous_auto->value;
42                                 current->control_in_value = (previous_value - current_value) / 6.0;
43                                 if(!current->control_in_position)
44                                         current->control_in_position = -track->to_units(1.0, 0);
45                         }
47 // Determine whether to set the control out point
48                         if(next_auto && next_auto->position < end)
49                         {
50                                 float next_value = next_auto->value;
51                                 current->control_out_value = (next_value - current_value) / 6.0;
52                                 if(!current->control_out_position)
53                                         current->control_out_position = track->to_units(1.0, 0);
54                         }
55                 }
56                 current = (FloatAuto*)NEXT;
57         }
60 int FloatAutos::draw_joining_line(BC_SubWindow *canvas, int vertical, int center_pixel, int x1, int y1, int x2, int y2)
62         if(vertical)
63                 canvas->draw_line(center_pixel - y1, x1, center_pixel - y2, x2);
64         else
65                 canvas->draw_line(x1, center_pixel + y1, x2, center_pixel + y2);
68 Auto* FloatAutos::add_auto(int64_t position, float value)
70         FloatAuto* current = (FloatAuto*)autoof(position);
71         FloatAuto* result;
72         
73         insert_before(current, result = (FloatAuto*)new_auto());
75         result->position = position;
76         result->value = value;
77         
78         return result;
81 Auto* FloatAutos::new_auto()
83         FloatAuto *result = new FloatAuto(edl, this);
84         result->value = default_;
85         return result;
88 int FloatAutos::get_testy(float slope, int cursor_x, int ax, int ay)
90         return (int)(slope * (cursor_x - ax)) + ay;
93 int FloatAutos::automation_is_constant(int64_t start, 
94         int64_t length, 
95         int direction,
96         double &constant)
98         int total_autos = total();
99         int64_t end;
100         if(direction == PLAY_FORWARD)
101         {
102                 end = start + length;
103         }
104         else
105         {
106                 end = start + 1;
107                 start -= length;
108         }
111 // No keyframes on track
112         if(total_autos == 0)
113         {
114                 constant = ((FloatAuto*)default_auto)->value;
115                 return 1;
116         }
117         else
118 // Only one keyframe on track.
119         if(total_autos == 1)
120         {
121                 constant = ((FloatAuto*)first)->value;
122                 return 1;
123         }
124         else
125 // Last keyframe is before region
126         if(last->position <= start)
127         {
128                 constant = ((FloatAuto*)last)->value;
129                 return 1;
130         }
131         else
132 // First keyframe is after region
133         if(first->position > end)
134         {
135                 constant = ((FloatAuto*)first)->value;
136                 return 1;
137         }
139 // Scan sequentially
140         int64_t prev_position = -1;
141         for(Auto *current = first; current; current = NEXT)
142         {
143                 int test_current_next = 0;
144                 int test_previous_current = 0;
145                 FloatAuto *float_current = (FloatAuto*)current;
147 // keyframes before and after region but not in region
148                 if(prev_position >= 0 &&
149                         prev_position < start && 
150                         current->position >= end)
151                 {
152 // Get value now in case change doesn't occur
153                         constant = float_current->value;
154                         test_previous_current = 1;
155                 }
156                 prev_position = current->position;
158 // Keyframe occurs in the region
159                 if(!test_previous_current &&
160                         current->position < end && 
161                         current->position >= start)
162                 {
164 // Get value now in case change doesn't occur
165                         constant = float_current->value;
167 // Keyframe has neighbor
168                         if(current->previous)
169                         {
170                                 test_previous_current = 1;
171                         }
173                         if(current->next)
174                         {
175                                 test_current_next = 1;
176                         }
177                 }
179                 if(test_current_next)
180                 {
181 //printf("FloatAutos::automation_is_constant 1 %d\n", start);
182                         FloatAuto *float_next = (FloatAuto*)current->next;
184 // Change occurs between keyframes
185                         if(!EQUIV(float_current->value, float_next->value) ||
186                                 !EQUIV(float_current->control_out_value, 0) ||
187                                 !EQUIV(float_next->control_in_value, 0))
188                         {
189                                 return 0;
190                         }
191                 }
193                 if(test_previous_current)
194                 {
195                         FloatAuto *float_previous = (FloatAuto*)current->previous;
197 // Change occurs between keyframes
198                         if(!EQUIV(float_current->value, float_previous->value) ||
199                                 !EQUIV(float_current->control_in_value, 0) ||
200                                 !EQUIV(float_previous->control_out_value, 0))
201                         {
202 // printf("FloatAutos::automation_is_constant %d %d %d %f %f %f %f\n", 
203 // start, 
204 // float_previous->position, 
205 // float_current->position, 
206 // float_previous->value, 
207 // float_current->value, 
208 // float_previous->control_out_value, 
209 // float_current->control_in_value);
210                                 return 0;
211                         }
212                 }
213         }
215 // Got nothing that changes in the region.
216         return 1;
219 double FloatAutos::get_automation_constant(int64_t start, int64_t end)
221         Auto *current_auto, *before = 0, *after = 0;
222         
223 // quickly get autos just outside range 
224         get_neighbors(start, end, &before, &after);
226 // no auto before range so use first
227         if(before)
228                 current_auto = before;
229         else
230                 current_auto = first;
232 // no autos at all so use default value
233         if(!current_auto) current_auto = default_auto;
235         return ((FloatAuto*)current_auto)->value;
239 float FloatAutos::get_value(int64_t position, 
240         int direction, 
241         FloatAuto* &previous, 
242         FloatAuto* &next)
244         double slope;
245         double intercept;
246         int64_t slope_len;
247 // Calculate bezier equation at position
248         float y0, y1, y2, y3;
249         float t;
251         previous = (FloatAuto*)get_prev_auto(position, direction, (Auto* &)previous, 0);
252         next = (FloatAuto*)get_next_auto(position, direction, (Auto* &)next, 0);
254 // Constant
255         if(!next && !previous)
256         {
257                 return ((FloatAuto*)default_auto)->value;
258         }
259         else
260         if(!previous)
261         {
262                 return next->value;
263         }
264         else
265         if(!next)
266         {
267                 return previous->value;
268         }
269         else
270         if(next == previous)
271         {
272                 return previous->value;
273         }
274         else
275         {
276                 if(direction == PLAY_FORWARD &&
277                         EQUIV(previous->value, next->value) &&
278                         EQUIV(previous->control_out_value, 0) &&
279                         EQUIV(next->control_in_value, 0))
280                 {
281                         return previous->value;
282                 }
283                 else
284                 if(direction == PLAY_REVERSE &&
285                         EQUIV(previous->value, next->value) &&
286                         EQUIV(previous->control_in_value, 0) &&
287                         EQUIV(next->control_out_value, 0))
288                 {
289                         return previous->value;
290                 }
291         }
294 // Interpolate
295         y0 = previous->value;
296         y3 = next->value;
298         if(direction == PLAY_FORWARD)
299         {
300                 y1 = previous->value + previous->control_out_value * 2;
301                 y2 = next->value + next->control_in_value * 2;
302                 t = (double)(position - previous->position) / 
303                         (next->position - previous->position);
304 // division by 0
305                 if(next->position - previous->position == 0) return previous->value;
306         }
307         else
308         {
309                 y1 = previous->value + previous->control_in_value * 2;
310                 y2 = next->value + next->control_out_value * 2;
311                 t = (double)(previous->position - position) / 
312                         (previous->position - next->position);
313 // division by 0
314                 if(previous->position - next->position == 0) return previous->value;
315         }
317         float tpow2 = t * t;
318         float tpow3 = t * t * t;
319         float invt = 1 - t;
320         float invtpow2 = invt * invt;
321         float invtpow3 = invt * invt * invt;
322         
323         float result = (  invtpow3 * y0
324                 + 3 * t     * invtpow2 * y1
325                 + 3 * tpow2 * invt     * y2 
326                 +     tpow3            * y3);
327 //printf("FloatAutos::get_value %f %f %d %d %d %d\n", result, t, direction, position, previous->position, next->position);
329         return result;
333 //      get_fade_automation(slope,
334 //              intercept,
335 //              position,
336 //              slope_len,
337 //              PLAY_FORWARD);
338 // 
339 //      return (float)intercept;
343 void FloatAutos::get_fade_automation(double &slope,
344         double &intercept,
345         int64_t input_position,
346         int64_t &slope_len,
347         int direction)
349         Auto *current = 0;
350         FloatAuto *prev_keyframe = 
351                 (FloatAuto*)get_prev_auto(input_position, direction, current);
352         FloatAuto *next_keyframe = 
353                 (FloatAuto*)get_next_auto(input_position, direction, current);
354         int64_t new_slope_len;
356         if(direction == PLAY_FORWARD)
357         {
358                 new_slope_len = next_keyframe->position - prev_keyframe->position;
360 //printf("FloatAutos::get_fade_automation %d %d %d\n", 
361 //      prev_keyframe->position, input_position, next_keyframe->position);
363 // Two distinct automation points within range
364                 if(next_keyframe->position > prev_keyframe->position)
365                 {
366                         slope = ((double)next_keyframe->value - prev_keyframe->value) / 
367                                 new_slope_len;
368                         intercept = ((double)input_position - prev_keyframe->position) * slope + prev_keyframe->value;
370                         if(next_keyframe->position < input_position + new_slope_len)
371                                 new_slope_len = next_keyframe->position - input_position;
372                         slope_len = MIN(slope_len, new_slope_len);
373                 }
374                 else
375 // One automation point within range
376                 {
377                         slope = 0;
378                         intercept = prev_keyframe->value;
379                 }
380         }
381         else
382         {
383                 new_slope_len = prev_keyframe->position - next_keyframe->position;
384 // Two distinct automation points within range
385                 if(next_keyframe->position < prev_keyframe->position)
386                 {
387                         slope = ((double)next_keyframe->value - prev_keyframe->value) / new_slope_len;
388                         intercept = ((double)prev_keyframe->position - input_position) * slope + prev_keyframe->value;
390                         if(prev_keyframe->position > input_position - new_slope_len)
391                                 new_slope_len = input_position - prev_keyframe->position;
392                         slope_len = MIN(slope_len, new_slope_len);
393                 }
394                 else
395 // One automation point within range
396                 {
397                         slope = 0;
398                         intercept = next_keyframe->value;
399                 }
400         }
403 void FloatAutos::get_extents(float *min, 
404         float *max,
405         int *coords_undefined,
406         int64_t unit_start,
407         int64_t unit_end)
409         if(!edl)
410         {
411                 printf("FloatAutos::get_extents edl == NULL\n");
412                 return;
413         }
415         if(!track)
416         {
417                 printf("FloatAutos::get_extents track == NULL\n");
418                 return;
419         }
421 // Use default auto
422         if(!first)
423         {
424                 FloatAuto *current = (FloatAuto*)default_auto;
425                 if(*coords_undefined)
426                 {
427                         *min = *max = current->value;
428                         *coords_undefined = 0;
429                 }
431                 *min = MIN(current->value, *min);
432                 *max = MAX(current->value, *max);
433         }
435 // Test all handles
436         for(FloatAuto *current = (FloatAuto*)first; current; current = (FloatAuto*)NEXT)
437         {
438                 if(current->position >= unit_start && current->position < unit_end)
439                 {
440                         if(*coords_undefined)
441                         {
442                                 *min = *max = current->value;
443                                 *coords_undefined = 0;
444                         }
445                         
446                         *min = MIN(current->value, *min);
447                         *min = MIN(current->value + current->control_in_value, *min);
448                         *min = MIN(current->value + current->control_out_value, *min);
450                         *max = MAX(current->value, *max);
451                         *max = MAX(current->value + current->control_in_value, *max);
452                         *max = MAX(current->value + current->control_out_value, *max);
453                 }
454         }
456 // Test joining regions
457         FloatAuto *prev = 0;
458         FloatAuto *next = 0;
459         int64_t unit_step = edl->local_session->zoom_sample;
460         if(track->data_type == TRACK_VIDEO)
461                 unit_step = (int64_t)(unit_step * 
462                         edl->session->frame_rate / 
463                         edl->session->sample_rate);
464         unit_step = MAX(unit_step, 1);
465         for(int64_t position = unit_start; 
466                 position < unit_end; 
467                 position += unit_step)
468         {
469                 float value = get_value(position,
470                         PLAY_FORWARD,
471                         prev,
472                         next);
473                 if(*coords_undefined)
474                 {
475                         *min = *max = value;
476                         *coords_undefined = 0;
477                 }
478                 else
479                 {
480                         *min = MIN(value, *min);
481                         *max = MAX(value, *max);
482                 }       
483         }
486 void FloatAutos::dump()
488         printf("        FloatAutos::dump %p\n", this);
489         printf("        Default: position %lld value=%f\n", 
490                 default_auto->position, 
491                 ((FloatAuto*)default_auto)->value);
492         for(Auto* current = first; current; current = NEXT)
493         {
494                 printf("        position %lld value=%f invalue=%f outvalue=%f inposition=%lld outposition=%lld\n", 
495                         current->position, 
496                         ((FloatAuto*)current)->value,
497                         ((FloatAuto*)current)->control_in_value,
498                         ((FloatAuto*)current)->control_out_value,
499                         ((FloatAuto*)current)->control_in_position,
500                         ((FloatAuto*)current)->control_out_position);
501         }
504 //      Local Variables:
505 //      mode: C++
506 //      c-file-style: "linux"
507 //      End: