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"
31 #include "localsession.h"
32 #include "transportque.inc"
34 FloatAutos::FloatAutos(EDL *edl,
39 this->default_ = default_;
40 type = AUTOMATION_TYPE_FLOAT;
43 FloatAutos::~FloatAutos()
47 void FloatAutos::set_automation_mode(int64_t start, int64_t end, int mode)
49 FloatAuto *current = (FloatAuto*)first;
52 //FloatAuto *previous_auto = (FloatAuto*)PREVIOUS;
53 //FloatAuto *next_auto = (FloatAuto*)NEXT;
55 // Is current auto in range?
56 if(current->position >= start && current->position < end)
59 // float current_value = current->value;
61 // // Determine whether to set the control in point.
62 // if(previous_auto && previous_auto->position >= start)
64 // float previous_value = previous_auto->value;
65 // current->control_in_value = (previous_value - current_value) / 6.0;
68 // // Determine whether to set the control out point
69 // if(next_auto && next_auto->position < end)
71 // float next_value = next_auto->value;
72 // current->control_out_value = (next_value - current_value) / 6.0;
75 current = (FloatAuto*)NEXT;
79 int FloatAutos::draw_joining_line(BC_SubWindow *canvas, int vertical, int center_pixel, int x1, int y1, int x2, int y2)
82 canvas->draw_line(center_pixel - y1, x1, center_pixel - y2, x2);
84 canvas->draw_line(x1, center_pixel + y1, x2, center_pixel + y2);
89 Auto* FloatAutos::new_auto()
91 FloatAuto *result = new FloatAuto(edl, this);
92 result->value = default_;
96 int FloatAutos::get_testy(float slope, int cursor_x, int ax, int ay)
98 return (int)(slope * (cursor_x - ax)) + ay;
101 int FloatAutos::automation_is_constant(int64_t start,
106 int total_autos = total();
109 if(direction == PLAY_FORWARD)
111 end = start + length;
120 // No keyframes on track
123 constant = ((FloatAuto*)default_auto)->value;
127 // Only one keyframe on track.
130 constant = ((FloatAuto*)first)->value;
131 //printf("FloatAutos::automation_is_constant %d\n", __LINE__);
135 // Last keyframe is before region
136 if(last->position <= start)
138 constant = ((FloatAuto*)last)->value;
139 //printf("FloatAutos::automation_is_constant %d\n", __LINE__);
143 // First keyframe is after region
144 if(first->position > end)
146 constant = ((FloatAuto*)first)->value;
147 //printf("FloatAutos::automation_is_constant %d\n", __LINE__);
152 int64_t prev_position = -1;
153 for(Auto *current = first; current; current = NEXT)
155 int test_current_next = 0;
156 int test_previous_current = 0;
157 FloatAuto *float_current = (FloatAuto*)current;
159 // keyframes before and after region but not in region
160 if(prev_position >= 0 &&
161 prev_position < start &&
162 current->position >= end)
164 // Get value now in case change doesn't occur
165 constant = float_current->value;
166 test_previous_current = 1;
168 prev_position = current->position;
170 // Keyframe occurs in the region
171 if(!test_previous_current &&
172 current->position < end &&
173 current->position >= start)
176 // Get value now in case change doesn't occur
177 constant = float_current->value;
179 // Keyframe has neighbor
180 if(current->previous)
182 test_previous_current = 1;
187 test_current_next = 1;
191 if(test_current_next)
193 //printf("FloatAutos::automation_is_constant %d\n", __LINE__);
194 FloatAuto *float_next = (FloatAuto*)current->next;
196 // Change occurs between keyframes
197 if(!EQUIV(float_current->value, float_next->value) ||
198 ((float_current->mode != Auto::LINEAR ||
199 float_next->mode != Auto::LINEAR) &&
200 (!EQUIV(float_current->control_out_value, 0) ||
201 !EQUIV(float_next->control_in_value, 0))))
203 //printf("FloatAutos::automation_is_constant %d\n", __LINE__);
208 if(test_previous_current)
210 FloatAuto *float_previous = (FloatAuto*)current->previous;
212 // Change occurs between keyframes if values differ or are joined by a curve.
213 //printf("FloatAutos::automation_is_constant %d\n", __LINE__);
214 if(!EQUIV(float_current->value, float_previous->value) ||
215 ((float_current->mode != Auto::LINEAR ||
216 float_previous->mode != Auto::LINEAR) &&
217 (!EQUIV(float_current->control_out_value, 0) ||
218 !EQUIV(float_previous->control_in_value, 0))))
220 // printf("FloatAutos::automation_is_constant %d %d %d %f %f %f %f\n",
222 // float_previous->position,
223 // float_current->position,
224 // float_previous->value,
225 // float_current->value,
226 // float_previous->control_out_value,
227 // float_current->control_in_value);
228 //printf("FloatAutos::automation_is_constant %d\n", __LINE__);
233 //printf("FloatAutos::automation_is_constant %d\n", __LINE__);
235 // Got nothing that changes in the region.
239 double FloatAutos::get_automation_constant(int64_t start, int64_t end)
241 Auto *current_auto, *before = 0, *after = 0;
243 // quickly get autos just outside range
244 get_neighbors(start, end, &before, &after);
246 // no auto before range so use first
248 current_auto = before;
250 current_auto = first;
252 // no autos at all so use default value
253 if(!current_auto) current_auto = default_auto;
255 return ((FloatAuto*)current_auto)->value;
259 float FloatAutos::get_value(int64_t position,
261 FloatAuto* &previous,
264 // Calculate bezier equation at position
265 float y0, y1, y2, y3;
268 previous = (FloatAuto*)get_prev_auto(position, direction, (Auto* &)previous, 0);
269 next = (FloatAuto*)get_next_auto(position, direction, (Auto* &)next, 0);
272 if(!next && !previous) return ((FloatAuto*)default_auto)->value;
273 if(!previous) return next->value;
274 if(!next) return previous->value;
275 if(next == previous) return previous->value;
277 if(direction == PLAY_FORWARD)
279 if(EQUIV(previous->value, next->value))
281 if((previous->mode == Auto::LINEAR &&
282 next->mode == Auto::LINEAR) ||
283 (EQUIV(previous->control_out_value, 0) &&
284 EQUIV(next->control_in_value, 0)))
286 return previous->value;
291 if(direction == PLAY_REVERSE)
293 if(EQUIV(previous->value, next->value))
295 if((previous->mode == Auto::LINEAR &&
296 next->mode == Auto::LINEAR) ||
297 (EQUIV(previous->control_in_value, 0) &&
298 EQUIV(next->control_out_value, 0)))
300 return previous->value;
307 y0 = previous->value;
310 if(direction == PLAY_FORWARD)
313 if(next->position - previous->position == 0) return previous->value;
314 y1 = previous->value + previous->control_out_value * 2;
315 y2 = next->value + next->control_in_value * 2;
316 t = (double)(position - previous->position) /
317 (next->position - previous->position);
322 if(previous->position - next->position == 0) return previous->value;
323 y1 = previous->value + previous->control_in_value * 2;
324 y2 = next->value + next->control_out_value * 2;
325 t = (double)(previous->position - position) /
326 (previous->position - next->position);
330 if(previous->mode == Auto::LINEAR &&
331 next->mode == Auto::LINEAR)
333 result = previous->value + t * (next->value - previous->value);
338 float tpow3 = t * t * t;
340 float invtpow2 = invt * invt;
341 float invtpow3 = invt * invt * invt;
343 result = ( invtpow3 * y0
344 + 3 * t * invtpow2 * y1
345 + 3 * tpow2 * invt * y2
347 //printf("FloatAutos::get_value %f %f %d %d %d %d\n", result, t, direction, position, previous->position, next->position);
355 void FloatAutos::get_extents(float *min,
357 int *coords_undefined,
363 printf("FloatAutos::get_extents edl == NULL\n");
369 printf("FloatAutos::get_extents track == NULL\n");
376 FloatAuto *current = (FloatAuto*)default_auto;
377 if(*coords_undefined)
379 *min = *max = current->value;
380 *coords_undefined = 0;
383 *min = MIN(current->value, *min);
384 *max = MAX(current->value, *max);
388 for(FloatAuto *current = (FloatAuto*)first; current; current = (FloatAuto*)NEXT)
390 if(current->position >= unit_start && current->position < unit_end)
392 if(*coords_undefined)
394 *min = *max = current->value;
395 *coords_undefined = 0;
398 *min = MIN(current->value, *min);
399 *min = MIN(current->value + current->control_in_value, *min);
400 *min = MIN(current->value + current->control_out_value, *min);
402 *max = MAX(current->value, *max);
403 *max = MAX(current->value + current->control_in_value, *max);
404 *max = MAX(current->value + current->control_out_value, *max);
408 // Test joining regions
411 int64_t unit_step = edl->local_session->zoom_sample;
412 if(track->data_type == TRACK_VIDEO)
413 unit_step = (int64_t)(unit_step *
414 edl->session->frame_rate /
415 edl->session->sample_rate);
416 unit_step = MAX(unit_step, 1);
417 for(int64_t position = unit_start;
419 position += unit_step)
421 float value = get_value(position,
425 if(*coords_undefined)
428 *coords_undefined = 0;
432 *min = MIN(value, *min);
433 *max = MAX(value, *max);
438 void FloatAutos::dump()
440 printf(" FloatAutos::dump %p\n", this);
441 printf(" Default: position " _LD " value=%f\n",
442 default_auto->position,
443 ((FloatAuto*)default_auto)->value);
444 for(Auto* current = first; current; current = NEXT)
446 printf(" position " _LD " mode=%d value=%f invalue=%f outvalue=%f\n",
448 (int)((FloatAuto*)current)->mode,
449 ((FloatAuto*)current)->value,
450 ((FloatAuto*)current)->control_in_value,
451 ((FloatAuto*)current)->control_out_value);
452 // ((FloatAuto*)current)->control_in_position,
453 // ((FloatAuto*)current)->control_out_position);