4 * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
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.
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.
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
22 #include "automation.inc"
25 #include "edlsession.h"
27 #include "floatauto.h"
28 #include "floatautos.h"
30 #include "localsession.h"
31 #include "transportque.inc"
33 FloatAutos::FloatAutos(EDL *edl,
38 this->default_ = default_;
39 type = AUTOMATION_TYPE_FLOAT;
42 FloatAutos::~FloatAutos()
46 void FloatAutos::set_automation_mode(int64_t start, int64_t end, int mode)
48 FloatAuto *current = (FloatAuto*)first;
51 // Is current auto in range?
52 if(current->position >= start && current->position < end)
54 current->change_curve_mode((FloatAuto::t_mode)mode);
56 current = (FloatAuto*)NEXT;
60 void FloatAutos::draw_joining_line(BC_SubWindow *canvas, int vertical, int center_pixel, int x1, int y1, int x2, int y2)
63 canvas->draw_line(center_pixel - y1, x1, center_pixel - y2, x2);
65 canvas->draw_line(x1, center_pixel + y1, x2, center_pixel + y2);
68 Auto* FloatAutos::new_auto()
70 FloatAuto *result = new FloatAuto(edl, this);
71 result->set_value(default_);
75 int FloatAutos::get_testy(float slope, int cursor_x, int ax, int ay)
77 return (int)(slope * (cursor_x - ax)) + ay;
80 int FloatAutos::automation_is_constant(int64_t start,
85 int total_autos = total();
87 if(direction == PLAY_FORWARD)
98 // No keyframes on track
101 constant = ((FloatAuto*)default_auto)->get_value();
105 // Only one keyframe on track.
108 constant = ((FloatAuto*)first)->get_value();
112 // Last keyframe is before region
113 if(last->position <= start)
115 constant = ((FloatAuto*)last)->get_value();
119 // First keyframe is after region
120 if(first->position > end)
122 constant = ((FloatAuto*)first)->get_value();
127 int64_t prev_position = -1;
128 for(Auto *current = first; current; current = NEXT)
130 int test_current_next = 0;
131 int test_previous_current = 0;
132 FloatAuto *float_current = (FloatAuto*)current;
134 // keyframes before and after region but not in region
135 if(prev_position >= 0 &&
136 prev_position < start &&
137 current->position >= end)
139 // Get value now in case change doesn't occur
140 constant = float_current->get_value();
141 test_previous_current = 1;
143 prev_position = current->position;
145 // Keyframe occurs in the region
146 if(!test_previous_current &&
147 current->position < end &&
148 current->position >= start)
151 // Get value now in case change doesn't occur
152 constant = float_current->get_value();
154 // Keyframe has neighbor
155 if(current->previous)
157 test_previous_current = 1;
162 test_current_next = 1;
166 if(test_current_next)
168 //printf("FloatAutos::automation_is_constant 1 %d\n", start);
169 FloatAuto *float_next = (FloatAuto*)current->next;
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))
180 if(test_previous_current)
182 FloatAuto *float_previous = (FloatAuto*)current->previous;
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))
189 // printf("FloatAutos::automation_is_constant %d %d %d %f %f %f %f\n",
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());
202 // Got nothing that changes in the region.
206 double FloatAutos::get_automation_constant(int64_t start, int64_t end)
208 Auto *current_auto, *before = 0, *after = 0;
210 // quickly get autos just outside range
211 get_neighbors(start, end, &before, &after);
213 // no auto before range so use first
215 current_auto = before;
217 current_auto = first;
219 // no autos at all so use default value
220 if(!current_auto) current_auto = default_auto;
222 return ((FloatAuto*)current_auto)->get_value();
226 float FloatAutos::get_value(int64_t position,
228 FloatAuto* &previous,
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);
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();
241 if(direction == PLAY_FORWARD)
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();
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();
262 // at this point: previous and next not NULL, positions differ, value not constant.
264 return calculate_bezier(previous, next, position);
268 float FloatAutos::calculate_bezier(FloatAuto *previous, FloatAuto *next, int64_t position)
270 if(next->position - previous->position == 0) return previous->get_value();
272 float y0 = previous->get_value();
273 float y3 = next->get_value();
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);
282 float tpow3 = t * t * t;
284 float invtpow2 = invt * invt;
285 float invtpow3 = invt * invt * invt;
287 float result = ( invtpow3 * y0
288 + 3 * t * invtpow2 * y1
289 + 3 * tpow2 * invt * y2
291 //printf("FloatAutos::get_value(t=%5.3f)->%6.2f (prev,pos,next)=(%d,%d,%d)\n", t, result, previous->position, position, next->position);
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)
301 float scale = next->position - previous->position;
303 if( !previous->get_control_out_position() )
305 return previous->get_control_out_value() / previous->get_control_out_position();
307 float y0 = previous->get_value();
308 float y3 = next->get_value();
311 float y1 = previous->get_value() + previous->get_control_out_value();
312 float y2 = next->get_value() + next->get_control_in_value();
314 float t = (float)(position - previous->position) / scale;
318 float invtpow2 = invt * invt;
322 - invt * ( 2*t - invt ) * y1
323 + t * ( 2*invt - t ) * y2
327 return slope / scale;
332 void FloatAutos::get_extents(float *min,
334 int *coords_undefined,
340 printf("FloatAutos::get_extents edl == NULL\n");
346 printf("FloatAutos::get_extents track == NULL\n");
353 FloatAuto *current = (FloatAuto*)default_auto;
354 if(*coords_undefined)
356 *min = *max = current->get_value();
357 *coords_undefined = 0;
360 *min = MIN(current->get_value(), *min);
361 *max = MAX(current->get_value(), *max);
365 for(FloatAuto *current = (FloatAuto*)first; current; current = (FloatAuto*)NEXT)
367 if(current->position >= unit_start && current->position < unit_end)
369 if(*coords_undefined)
371 *min = *max = current->get_value();
372 *coords_undefined = 0;
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);
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);
385 // Test joining regions
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;
396 position += unit_step)
398 float value = get_value(position,PLAY_FORWARD,prev,next);
399 if(*coords_undefined)
402 *coords_undefined = 0;
406 *min = MIN(value, *min);
407 *max = MAX(value, *max);
412 void FloatAutos::dump()
414 printf(" FloatAutos::dump %p\n", this);
415 printf(" Default: position %jd value=%f\n",
416 default_auto->position, ((FloatAuto*)default_auto)->get_value());
417 for(Auto* current = first; current; current = NEXT)
419 printf(" position %jd value=%7.3f invalue=%7.3f outvalue=%7.3f %s\n",
421 ((FloatAuto*)current)->get_value(),
422 ((FloatAuto*)current)->get_control_in_value(),
423 ((FloatAuto*)current)->get_control_out_value(),
424 FloatAuto::curve_name(((FloatAuto*)current)->curve_mode));