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