4 * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
5 * Copyright (C) 2003-2016 Cinelerra CV contributors
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include "automation.inc"
26 #include "edlsession.h"
28 #include "floatauto.h"
29 #include "floatautos.h"
31 #include "localsession.h"
32 #include "transportque.inc"
34 FloatAutos::FloatAutos(EDL *edl,
39 this->default_ = default_;
40 type = AUTOMATION_TYPE_FLOAT;
45 FloatAutos::~FloatAutos()
49 void FloatAutos::set_automation_mode(int64_t start, int64_t end, int mode)
51 FloatAuto *current = (FloatAuto*)first;
54 // Is current auto in range?
55 if(current->position >= start && current->position < end)
57 current->change_curve_mode((FloatAuto::t_mode)mode);
59 current = (FloatAuto*)NEXT;
63 void FloatAutos::draw_joining_line(BC_SubWindow *canvas, int vertical, int center_pixel, int x1, int y1, int x2, int y2)
66 canvas->draw_line(center_pixel - y1, x1, center_pixel - y2, x2);
68 canvas->draw_line(x1, center_pixel + y1, x2, center_pixel + y2);
71 Auto* FloatAutos::new_auto()
73 FloatAuto *result = new FloatAuto(edl, this);
74 result->set_value(default_);
78 int FloatAutos::get_testy(float slope, int cursor_x, int ax, int ay)
80 return (int)(slope * (cursor_x - ax)) + ay;
83 int FloatAutos::automation_is_constant(int64_t start,
88 int total_autos = total();
90 if(direction == PLAY_FORWARD)
101 // No keyframes on track
104 constant = ((FloatAuto*)default_auto)->get_value();
108 // Only one keyframe on track.
111 constant = ((FloatAuto*)first)->get_value();
115 // Last keyframe is before region
116 if(last->position <= start)
118 constant = ((FloatAuto*)last)->get_value();
122 // First keyframe is after region
123 if(first->position > end)
125 constant = ((FloatAuto*)first)->get_value();
130 int64_t prev_position = -1;
131 for(Auto *current = first; current; current = NEXT)
133 int test_current_next = 0;
134 int test_previous_current = 0;
135 FloatAuto *float_current = (FloatAuto*)current;
137 // keyframes before and after region but not in region
138 if(prev_position >= 0 &&
139 prev_position < start &&
140 current->position >= end)
142 // Get value now in case change doesn't occur
143 constant = float_current->get_value();
144 test_previous_current = 1;
146 prev_position = current->position;
148 // Keyframe occurs in the region
149 if(!test_previous_current &&
150 current->position < end &&
151 current->position >= start)
154 // Get value now in case change doesn't occur
155 constant = float_current->get_value();
157 // Keyframe has neighbor
158 if(current->previous)
160 test_previous_current = 1;
165 test_current_next = 1;
169 if(test_current_next)
171 //printf("FloatAutos::automation_is_constant 1 %d\n", start);
172 FloatAuto *float_next = (FloatAuto*)current->next;
174 // Change occurs between keyframes
175 if( !EQUIV(float_current->get_value(), float_next->get_value()) ||
176 !EQUIV(float_current->get_control_out_value(), 0) ||
177 !EQUIV(float_next->get_control_in_value(), 0))
183 if(test_previous_current)
185 FloatAuto *float_previous = (FloatAuto*)current->previous;
187 // Change occurs between keyframes
188 if(!EQUIV(float_current->get_value(), float_previous->get_value()) ||
189 !EQUIV(float_current->get_control_in_value(), 0) ||
190 !EQUIV(float_previous->get_control_out_value(), 0))
192 // printf("FloatAutos::automation_is_constant %d %d %d %f %f %f %f\n",
194 // float_previous->position,
195 // float_current->position,
196 // float_previous->get_value(),
197 // float_current->get_value(),
198 // float_previous->get_control_out_value(),
199 // float_current->get_control_in_value());
205 // Got nothing that changes in the region.
209 double FloatAutos::get_automation_constant(int64_t start, int64_t end)
211 Auto *current_auto, *before = 0, *after = 0;
213 // quickly get autos just outside range
214 get_neighbors(start, end, &before, &after);
216 // no auto before range so use first
218 current_auto = before;
220 current_auto = first;
222 // no autos at all so use default value
223 if(!current_auto) current_auto = default_auto;
225 return ((FloatAuto*)current_auto)->get_value();
229 float FloatAutos::get_value(int64_t position,
231 FloatAuto* &previous,
234 // Calculate bezier equation at position
235 previous = (FloatAuto*)get_prev_auto(position, direction, (Auto* &)previous, 0);
236 next = (FloatAuto*)get_next_auto(position, direction, (Auto* &)next, 0);
239 if( !next && !previous )
240 return ((FloatAuto*)default_auto)->get_value();
241 if( next == previous )
242 return previous->get_value();
244 if( direction == PLAY_FORWARD) {
245 if( !previous ) return next->get_value(1);
246 if( !next ) return previous->get_value(0);
247 if( EQUIV(previous->get_value(0), next->get_value(1)) ) {
248 if( (previous->curve_mode == FloatAuto::LINEAR &&
249 next->curve_mode == FloatAuto::LINEAR) ||
250 (EQUIV(previous->get_control_out_value(), 0) &&
251 EQUIV(next->get_control_in_value(), 0)) ) {
252 return previous->get_value(0);
256 else if(direction == PLAY_REVERSE) {
257 if( !previous ) return next->get_value(0);
258 if( !next ) return previous->get_value(1);
259 if( EQUIV(previous->get_value(0), next->get_value(1)) ) {
260 if( (previous->curve_mode == FloatAuto::LINEAR &&
261 next->curve_mode == FloatAuto::LINEAR) ||
262 (EQUIV(previous->get_control_in_value(), 0) &&
263 EQUIV(next->get_control_out_value(), 0)) ) {
264 return previous->get_value(1);
268 // at this point: previous and next not NULL, positions differ, value not constant.
270 return calculate_bezier(previous, next, position, direction);
274 float FloatAutos::calculate_bezier(FloatAuto *previous, FloatAuto *next,
275 int64_t position, int direction)
277 int edge = direction == PLAY_FORWARD ? 0 : 1;
278 if( next->position == previous->position )
279 return previous->get_value(edge);
281 float y0 = previous->get_value(edge);
282 float y3 = next->get_value(1-edge);
285 float y1 = y0 + (direction == PLAY_FORWARD ?
286 previous->get_control_out_value() :
287 previous->get_control_in_value());
288 float y2 = y3 + (direction == PLAY_FORWARD ?
289 next->get_control_in_value() :
290 next->get_control_out_value());
291 float t = (float)(position - previous->position) /
292 (next->position - previous->position);
295 float tpow3 = t * t * t;
297 float invtpow2 = invt * invt;
298 float invtpow3 = invt * invt * invt;
300 float result = ( invtpow3 * y0
301 + 3 * t * invtpow2 * y1
302 + 3 * tpow2 * invt * y2
304 //printf("FloatAutos::get_value(t=%5.3f)->%6.2f (prev,pos,next)=(%d,%d,%d)\n", t, result, previous->position, position, next->position);
310 float FloatAutos::calculate_bezier_derivation(FloatAuto *previous, FloatAuto *next, int64_t position)
311 // calculate the slope of the interpolating bezier function at given position.
312 // computed slope is based on the actual position scale (in frames or samples)
314 float scale = next->position - previous->position;
316 if( !previous->get_control_out_position() )
318 return previous->get_control_out_value() / previous->get_control_out_position();
320 float y0 = previous->get_value(0);
321 float y3 = next->get_value(1);
324 float y1 = y0 + previous->get_control_out_value();
325 float y2 = y3 + next->get_control_in_value();
327 float t = (float)(position - previous->position) / scale;
331 float invtpow2 = invt * invt;
335 - invt * ( 2*t - invt ) * y1
336 + t * ( 2*invt - t ) * y2
340 return slope / scale;
345 void FloatAutos::get_extents(float *min,
347 int *coords_undefined,
353 printf("FloatAutos::get_extents edl == NULL\n");
359 printf("FloatAutos::get_extents track == NULL\n");
366 FloatAuto *current = (FloatAuto*)default_auto;
367 if(*coords_undefined)
369 *min = *max = current->get_value();
370 *coords_undefined = 0;
373 *min = MIN(current->get_value(), *min);
374 *max = MAX(current->get_value(), *max);
378 for(FloatAuto *current = (FloatAuto*)first; current; current = (FloatAuto*)NEXT)
380 if(current->position >= unit_start && current->position < unit_end)
382 if(*coords_undefined)
384 *min = *max = current->get_value();
385 *coords_undefined = 0;
388 *min = MIN(current->get_value(), *min);
389 *min = MIN(current->get_value() + current->get_control_in_value(), *min);
390 *min = MIN(current->get_value() + current->get_control_out_value(), *min);
392 *max = MAX(current->get_value(), *max);
393 *max = MAX(current->get_value() + current->get_control_in_value(), *max);
394 *max = MAX(current->get_value() + current->get_control_out_value(), *max);
398 // Test joining regions
401 int64_t unit_step = edl->local_session->zoom_sample;
402 if(track->data_type == TRACK_VIDEO)
403 unit_step = (int64_t)(unit_step *
404 edl->session->frame_rate /
405 edl->session->sample_rate);
406 unit_step = MAX(unit_step, 1);
407 for(int64_t position = unit_start;
409 position += unit_step)
411 float value = get_value(position,PLAY_FORWARD,prev,next);
412 if(*coords_undefined)
415 *coords_undefined = 0;
419 *min = MIN(value, *min);
420 *max = MAX(value, *max);
425 void FloatAutos::set_proxy(int orig_scale, int new_scale)
428 orig_value = ((FloatAuto*)default_auto)->value * orig_scale;
429 ((FloatAuto*)default_auto)->value = orig_value / new_scale;
430 orig_value = ((FloatAuto*)default_auto)->value1 * orig_scale;
431 ((FloatAuto*)default_auto)->value1 = orig_value / new_scale;
433 for( FloatAuto *current= (FloatAuto*)first; current; current=(FloatAuto*)NEXT ) {
434 orig_value = current->value * orig_scale;
435 current->value = orig_value / new_scale;
436 orig_value = current->value1 * orig_scale;
437 current->value1 = orig_value / new_scale;
438 orig_value = current->control_in_value * orig_scale;
439 current->control_in_value = orig_value / new_scale;
440 orig_value = current->control_out_value * orig_scale;
441 current->control_out_value = orig_value / new_scale;
445 void FloatAutos::dump()
447 printf(" FloatAutos::dump %p\n", this);
448 printf(" Default: position %jd value=%f\n",
449 default_auto->position, ((FloatAuto*)default_auto)->get_value());
450 for(Auto* current = first; current; current = NEXT)
452 printf(" position %jd value=%7.3f invalue=%7.3f outvalue=%7.3f %s\n",
454 ((FloatAuto*)current)->get_value(),
455 ((FloatAuto*)current)->get_control_in_value(),
456 ((FloatAuto*)current)->get_control_out_value(),
457 FloatAuto::curve_name(((FloatAuto*)current)->curve_mode));
461 double FloatAutos::automation_integral(int64_t start, int64_t length, int direction)
463 if( direction == PLAY_REVERSE )
470 int64_t pos = start, len = length, end = pos + len;
472 int64_t prev_pos = 0, next_pos = end;
473 Auto *zprev = 0, *znext = 0;
474 FloatAuto *prev = (FloatAuto*)get_prev_auto(pos, direction, zprev, 0);
475 if( prev ) prev_pos = prev->position;
476 FloatAuto *next = (FloatAuto*)get_next_auto(pos, direction, znext, 0);
477 if( next ) next_pos = next->position;
478 if( !prev && !next ) prev = (FloatAuto*)default_auto;
479 double dt = next_pos - prev_pos;
480 double t0 = (pos - prev_pos) / dt;
481 if( (pos = next_pos) > end ) pos = end;
482 double t1 = (pos - prev_pos) / dt;
484 double y0 = !prev ? next->get_value(1) : prev->get_value(0);
485 double y1 = y0 + (!prev ? 0 : prev->get_control_out_value());
486 double y3 = !next ? prev->get_value(0) : next->get_value(1);
487 double y2 = y3 + (!next ? 0 : next->get_control_in_value());
488 if( y0 != y1 || y1 != y2 || y2 != y3 ) {
489 // bezier definite integral t0..t1
490 double f4 = -y0/4 + 3*y1/4 - 3*y2/4 + y3/4;
491 double f3 = y0 - 2*y1 + y2;
492 double f2 = -3*y0/2 + 3*y1/2;
493 double f1 = y0, t = t0;
494 double t2 = t*t, t3 = t2*t, t4 = t3*t;
495 t0 = t4*f4 + t3*f3 + t2*f2 + t*f1;
496 t = t1; t2 = t*t; t3 = t2*t; t4 = t3*t;
497 t1 = t4*f4 + t3*f3 + t2*f2 + t*f1;
502 value += dt * (t1 - t0);
508 int64_t FloatAutos::speed_position(double pos)
510 double length = track->get_length();
511 int64_t l = -1, r = track->to_units(length, 1);
513 for( int i=32; --i >= 0 && automation_integral(0,r,PLAY_FORWARD) <= pos; r*=2 );
514 for( int i=64; --i >= 0 && (r-l)>1; ) {
515 int64_t m = (l + r) / 2;
516 double t = automation_integral(0,m,PLAY_FORWARD) - pos;
517 *(t >= 0 ? &r : &l) = m;