bebbbcc1559e27c4d59d7fed5fd376355f909aa2
[goodguy/cinelerra.git] / cinelerra-5.1 / cinelerra / floatautos.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  */
21
22 #include "automation.inc"
23 #include "clip.h"
24 #include "edl.h"
25 #include "edlsession.h"
26 #include "filexml.h"
27 #include "floatauto.h"
28 #include "floatautos.h"
29 #include "track.h"
30 #include "localsession.h"
31 #include "transportque.inc"
32
33 FloatAutos::FloatAutos(EDL *edl,
34                                 Track *track,
35                                 float default_)
36  : Autos(edl, track)
37 {
38         this->default_ = default_;
39         type = AUTOMATION_TYPE_FLOAT;
40         float_min = -FLT_MAX;
41         float_max = FLT_MAX;
42 }
43
44 FloatAutos::~FloatAutos()
45 {
46 }
47
48 void FloatAutos::set_automation_mode(int64_t start, int64_t end, int mode)
49 {
50         FloatAuto *current = (FloatAuto*)first;
51         while(current)
52         {
53 // Is current auto in range?
54                 if(current->position >= start && current->position < end)
55                 {
56                         current->change_curve_mode((FloatAuto::t_mode)mode);
57                 }
58                 current = (FloatAuto*)NEXT;
59         }
60 }
61
62 void FloatAutos::draw_joining_line(BC_SubWindow *canvas, int vertical, int center_pixel, int x1, int y1, int x2, int y2)
63 {
64         if(vertical)
65                 canvas->draw_line(center_pixel - y1, x1, center_pixel - y2, x2);
66         else
67                 canvas->draw_line(x1, center_pixel + y1, x2, center_pixel + y2);
68 }
69
70 Auto* FloatAutos::new_auto()
71 {
72         FloatAuto *result = new FloatAuto(edl, this);
73         result->set_value(default_);
74         return result;
75 }
76
77 int FloatAutos::get_testy(float slope, int cursor_x, int ax, int ay)
78 {
79         return (int)(slope * (cursor_x - ax)) + ay;
80 }
81
82 int FloatAutos::automation_is_constant(int64_t start,
83         int64_t length,
84         int direction,
85         double &constant)
86 {
87         int total_autos = total();
88         int64_t end;
89         if(direction == PLAY_FORWARD)
90         {
91                 end = start + length;
92         }
93         else
94         {
95                 end = start + 1;
96                 start -= length;
97         }
98
99
100 // No keyframes on track
101         if(total_autos == 0)
102         {
103                 constant = ((FloatAuto*)default_auto)->get_value();
104                 return 1;
105         }
106         else
107 // Only one keyframe on track.
108         if(total_autos == 1)
109         {
110                 constant = ((FloatAuto*)first)->get_value();
111                 return 1;
112         }
113         else
114 // Last keyframe is before region
115         if(last->position <= start)
116         {
117                 constant = ((FloatAuto*)last)->get_value();
118                 return 1;
119         }
120         else
121 // First keyframe is after region
122         if(first->position > end)
123         {
124                 constant = ((FloatAuto*)first)->get_value();
125                 return 1;
126         }
127
128 // Scan sequentially
129         int64_t prev_position = -1;
130         for(Auto *current = first; current; current = NEXT)
131         {
132                 int test_current_next = 0;
133                 int test_previous_current = 0;
134                 FloatAuto *float_current = (FloatAuto*)current;
135
136 // keyframes before and after region but not in region
137                 if(prev_position >= 0 &&
138                         prev_position < start &&
139                         current->position >= end)
140                 {
141 // Get value now in case change doesn't occur
142                         constant = float_current->get_value();
143                         test_previous_current = 1;
144                 }
145                 prev_position = current->position;
146
147 // Keyframe occurs in the region
148                 if(!test_previous_current &&
149                         current->position < end &&
150                         current->position >= start)
151                 {
152
153 // Get value now in case change doesn't occur
154                         constant = float_current->get_value();
155
156 // Keyframe has neighbor
157                         if(current->previous)
158                         {
159                                 test_previous_current = 1;
160                         }
161
162                         if(current->next)
163                         {
164                                 test_current_next = 1;
165                         }
166                 }
167
168                 if(test_current_next)
169                 {
170 //printf("FloatAutos::automation_is_constant 1 %d\n", start);
171                         FloatAuto *float_next = (FloatAuto*)current->next;
172
173 // Change occurs between keyframes
174                         if( !EQUIV(float_current->get_value(), float_next->get_value()) ||
175                                 !EQUIV(float_current->get_control_out_value(), 0) ||
176                                 !EQUIV(float_next->get_control_in_value(), 0))
177                         {
178                                 return 0;
179                         }
180                 }
181
182                 if(test_previous_current)
183                 {
184                         FloatAuto *float_previous = (FloatAuto*)current->previous;
185
186 // Change occurs between keyframes
187                         if(!EQUIV(float_current->get_value(), float_previous->get_value()) ||
188                                 !EQUIV(float_current->get_control_in_value(), 0) ||
189                                 !EQUIV(float_previous->get_control_out_value(), 0))
190                         {
191 // printf("FloatAutos::automation_is_constant %d %d %d %f %f %f %f\n",
192 // start,
193 // float_previous->position,
194 // float_current->position,
195 // float_previous->get_value(),
196 // float_current->get_value(),
197 // float_previous->get_control_out_value(),
198 // float_current->get_control_in_value());
199                                 return 0;
200                         }
201                 }
202         }
203
204 // Got nothing that changes in the region.
205         return 1;
206 }
207
208 double FloatAutos::get_automation_constant(int64_t start, int64_t end)
209 {
210         Auto *current_auto, *before = 0, *after = 0;
211
212 // quickly get autos just outside range
213         get_neighbors(start, end, &before, &after);
214
215 // no auto before range so use first
216         if(before)
217                 current_auto = before;
218         else
219                 current_auto = first;
220
221 // no autos at all so use default value
222         if(!current_auto) current_auto = default_auto;
223
224         return ((FloatAuto*)current_auto)->get_value();
225 }
226
227
228 float FloatAutos::get_value(int64_t position,
229         int direction,
230         FloatAuto* &previous,
231         FloatAuto* &next)
232 {
233 // Calculate bezier equation at position
234         previous = (FloatAuto*)get_prev_auto(position, direction, (Auto* &)previous, 0);
235         next = (FloatAuto*)get_next_auto(position, direction, (Auto* &)next, 0);
236
237 // Constant
238         if( !next && !previous )
239                 return ((FloatAuto*)default_auto)->get_value();
240         if( next == previous )
241                 return previous->get_value();
242
243         if( direction == PLAY_FORWARD) {
244                 if( !previous ) return next->get_value(1);
245                 if( !next ) return previous->get_value(0);
246                 if( EQUIV(previous->get_value(0), next->get_value(1)) ) {
247                         if( (previous->curve_mode == FloatAuto::LINEAR &&
248                              next->curve_mode == FloatAuto::LINEAR) ||
249                             (EQUIV(previous->get_control_out_value(), 0) &&
250                              EQUIV(next->get_control_in_value(), 0)) ) {
251                                 return previous->get_value(0);
252                         }
253                 }
254         }
255         else if(direction == PLAY_REVERSE) {
256                 if( !previous ) return next->get_value(0);
257                 if( !next ) return previous->get_value(1);
258                 if( EQUIV(previous->get_value(0), next->get_value(1)) ) {
259                         if( (previous->curve_mode == FloatAuto::LINEAR &&
260                              next->curve_mode == FloatAuto::LINEAR) ||
261                             (EQUIV(previous->get_control_in_value(), 0) &&
262                              EQUIV(next->get_control_out_value(), 0)) ) {
263                                 return previous->get_value(1);
264                         }
265                 }
266         }
267 // at this point: previous and next not NULL, positions differ, value not constant.
268
269         return calculate_bezier(previous, next, position, direction);
270 }
271
272
273 float FloatAutos::calculate_bezier(FloatAuto *previous, FloatAuto *next,
274                 int64_t position, int direction)
275 {
276         int edge = direction == PLAY_FORWARD ? 0 : 1;
277         if( next->position == previous->position )
278                 return previous->get_value(edge);
279
280         float y0 = previous->get_value(edge);
281         float y3 = next->get_value(1-edge);
282
283 // control points
284         float y1 = y0 + (direction == PLAY_FORWARD ?
285                 previous->get_control_out_value() :
286                 previous->get_control_in_value());
287         float y2 = y3 + (direction == PLAY_FORWARD ?
288                 next->get_control_in_value() :
289                 next->get_control_out_value());
290         float t = (float)(position - previous->position) /
291                         (next->position - previous->position);
292
293         float tpow2 = t * t;
294         float tpow3 = t * t * t;
295         float invt = 1 - t;
296         float invtpow2 = invt * invt;
297         float invtpow3 = invt * invt * invt;
298
299         float result = (  invtpow3 * y0
300                 + 3 * t     * invtpow2 * y1
301                 + 3 * tpow2 * invt     * y2
302                 +     tpow3            * y3);
303 //printf("FloatAutos::get_value(t=%5.3f)->%6.2f   (prev,pos,next)=(%d,%d,%d)\n", t, result, previous->position, position, next->position);
304
305         return result;
306 }
307
308
309 float FloatAutos::calculate_bezier_derivation(FloatAuto *previous, FloatAuto *next, int64_t position)
310 // calculate the slope of the interpolating bezier function at given position.
311 // computed slope is based on the actual position scale (in frames or samples)
312 {
313         float scale = next->position - previous->position;
314         if( scale == 0 ) {
315                 if( !previous->get_control_out_position() )
316                         return 0;
317                 return previous->get_control_out_value() / previous->get_control_out_position();
318         }
319         float y0 = previous->get_value(0);
320         float y3 = next->get_value(1);
321
322 // control points
323         float y1 = y0 + previous->get_control_out_value();
324         float y2 = y3 + next->get_control_in_value();
325 // normalized scale
326         float t = (float)(position - previous->position) / scale;
327
328         float tpow2 = t * t;
329         float invt = 1 - t;
330         float invtpow2 = invt * invt;
331
332         float slope = 3 * (
333                 - invtpow2              * y0
334                 - invt * ( 2*t - invt ) * y1
335                 + t    * ( 2*invt - t ) * y2
336                 + tpow2                 * y3
337                 );
338
339         return slope / scale;
340 }
341
342
343
344 void FloatAutos::get_extents(float *min,
345         float *max,
346         int *coords_undefined,
347         int64_t unit_start,
348         int64_t unit_end)
349 {
350         if(!edl)
351         {
352                 printf("FloatAutos::get_extents edl == NULL\n");
353                 return;
354         }
355
356         if(!track)
357         {
358                 printf("FloatAutos::get_extents track == NULL\n");
359                 return;
360         }
361
362 // Use default auto
363         if(!first)
364         {
365                 FloatAuto *current = (FloatAuto*)default_auto;
366                 if(*coords_undefined)
367                 {
368                         *min = *max = current->get_value();
369                         *coords_undefined = 0;
370                 }
371
372                 *min = MIN(current->get_value(), *min);
373                 *max = MAX(current->get_value(), *max);
374         }
375
376 // Test all handles
377         for(FloatAuto *current = (FloatAuto*)first; current; current = (FloatAuto*)NEXT)
378         {
379                 if(current->position >= unit_start && current->position < unit_end)
380                 {
381                         if(*coords_undefined)
382                         {
383                                 *min = *max = current->get_value();
384                                 *coords_undefined = 0;
385                         }
386
387                         *min = MIN(current->get_value(), *min);
388                         *min = MIN(current->get_value() + current->get_control_in_value(), *min);
389                         *min = MIN(current->get_value() + current->get_control_out_value(), *min);
390
391                         *max = MAX(current->get_value(), *max);
392                         *max = MAX(current->get_value() + current->get_control_in_value(), *max);
393                         *max = MAX(current->get_value() + current->get_control_out_value(), *max);
394                 }
395         }
396
397 // Test joining regions
398         FloatAuto *prev = 0;
399         FloatAuto *next = 0;
400         int64_t unit_step = edl->local_session->zoom_sample;
401         if(track->data_type == TRACK_VIDEO)
402                 unit_step = (int64_t)(unit_step *
403                         edl->session->frame_rate /
404                         edl->session->sample_rate);
405         unit_step = MAX(unit_step, 1);
406         for(int64_t position = unit_start;
407                 position < unit_end;
408                 position += unit_step)
409         {
410                 float value = get_value(position,PLAY_FORWARD,prev,next);
411                 if(*coords_undefined)
412                 {
413                         *min = *max = value;
414                         *coords_undefined = 0;
415                 }
416                 else
417                 {
418                         *min = MIN(value, *min);
419                         *max = MAX(value, *max);
420                 }
421         }
422 }
423
424 void FloatAutos::set_proxy(int orig_scale, int new_scale)
425 {
426         float orig_value;
427         orig_value = ((FloatAuto*)default_auto)->value * orig_scale;
428         ((FloatAuto*)default_auto)->value = orig_value / new_scale;
429         orig_value = ((FloatAuto*)default_auto)->value1 * orig_scale;
430         ((FloatAuto*)default_auto)->value1 = orig_value / new_scale;
431
432         for( FloatAuto *current= (FloatAuto*)first; current; current=(FloatAuto*)NEXT ) {
433                 orig_value = current->value * orig_scale;
434                 current->value = orig_value / new_scale;
435                 orig_value = current->value1 * orig_scale;
436                 current->value1 = orig_value / new_scale;
437                 orig_value = current->control_in_value * orig_scale;
438                 current->control_in_value = orig_value / new_scale;
439                 orig_value = current->control_out_value * orig_scale;
440                 current->control_out_value = orig_value / new_scale;
441         }
442 }
443
444 void FloatAutos::dump()
445 {
446         printf("        FloatAutos::dump %p\n", this);
447         printf("        Default: position %jd value=%f\n",
448                 default_auto->position, ((FloatAuto*)default_auto)->get_value());
449         for(Auto* current = first; current; current = NEXT)
450         {
451                 printf("        position %jd value=%7.3f invalue=%7.3f outvalue=%7.3f %s\n",
452                         current->position,
453                         ((FloatAuto*)current)->get_value(),
454                         ((FloatAuto*)current)->get_control_in_value(),
455                         ((FloatAuto*)current)->get_control_out_value(),
456                         FloatAuto::curve_name(((FloatAuto*)current)->curve_mode));
457         }
458 }
459
460 double FloatAutos::automation_integral(int64_t start, int64_t length, int direction)
461 {
462         if( direction == PLAY_REVERSE )
463                 start -= length;
464         if( start < 0 ) {
465                 length += start;
466                 start = 0;
467         }
468         double value = 0;
469         int64_t pos = start, len = length, end = pos + len;
470         while( pos < end ) {
471                 int64_t prev_pos = 0, next_pos = end;
472                 Auto *zprev = 0, *znext = 0;
473                 FloatAuto *prev = (FloatAuto*)get_prev_auto(pos, direction, zprev, 0);
474                 if( prev ) prev_pos = prev->position;
475                 FloatAuto *next = (FloatAuto*)get_next_auto(pos, direction, znext, 0);
476                 if( next ) next_pos = next->position;
477                 if( !prev && !next ) prev = (FloatAuto*)default_auto;
478                 double dt = next_pos - prev_pos;
479                 double t0 = (pos - prev_pos) / dt;
480                 if( (pos = next_pos) > end ) pos = end;
481                 double t1 = (pos - prev_pos) / dt;
482
483                 double y0 = !prev ? next->get_value(1) : prev->get_value(0);
484                 double y1 = y0 + (!prev ? 0 : prev->get_control_out_value());
485                 double y3 = !next ? prev->get_value(0) : next->get_value(1);
486                 double y2 = y3 + (!next ? 0 : next->get_control_in_value());
487                 if( y0 != y1 || y1 != y2 || y2 != y3 ) {
488 // bezier definite integral t0..t1
489                         double f4 = -y0/4 + 3*y1/4 - 3*y2/4 + y3/4;
490                         double f3 = y0 - 2*y1 + y2;
491                         double f2 = -3*y0/2 + 3*y1/2;
492                         double f1 = y0, t = t0;
493                         double t2 = t*t, t3 = t2*t, t4 = t3*t;
494                         t0 = t4*f4 + t3*f3 + t2*f2 + t*f1;
495                         t = t1;  t2 = t*t;  t3 = t2*t;  t4 = t3*t;
496                         t1 = t4*f4 + t3*f3 + t2*f2 + t*f1;
497                 }
498                 else {
499                         t0 *= y0;  t1 *= y0;
500                 }
501                 value += dt * (t1 - t0);
502         }
503
504         return value + 1e-6;
505 }
506
507 int64_t FloatAutos::speed_position(double pos)
508 {
509         double length = track->get_length();
510         int64_t l = -1, r = track->to_units(length, 1);
511         if( r < 1 ) r = 1;
512         for( int i=32; --i >= 0 && automation_integral(0,r,PLAY_FORWARD) <= pos; r*=2 );
513         for( int i=64; --i >= 0 && (r-l)>1; ) {
514                 int64_t m = (l + r) / 2;
515                 double t = automation_integral(0,m,PLAY_FORWARD) - pos;
516                 *(t >= 0 ? &r : &l) = m;
517         }
518         return r;
519 }
520