/*
* CINELERRA
* Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
- *
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
+ *
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
+ *
*/
#include "automation.inc"
#include "transportque.inc"
FloatAutos::FloatAutos(EDL *edl,
- Track *track,
+ Track *track,
float default_)
: Autos(edl, track)
{
FloatAuto *current = (FloatAuto*)first;
while(current)
{
-// Is current auto in range?
+// Is current auto in range?
if(current->position >= start && current->position < end)
{
current->change_curve_mode((FloatAuto::t_mode)mode);
return (int)(slope * (cursor_x - ax)) + ay;
}
-int FloatAutos::automation_is_constant(int64_t start,
- int64_t length,
+int FloatAutos::automation_is_constant(int64_t start,
+ int64_t length,
int direction,
double &constant)
{
// keyframes before and after region but not in region
if(prev_position >= 0 &&
- prev_position < start &&
+ prev_position < start &&
current->position >= end)
{
// Get value now in case change doesn't occur
// Keyframe occurs in the region
if(!test_previous_current &&
- current->position < end &&
+ current->position < end &&
current->position >= start)
{
!EQUIV(float_current->get_control_in_value(), 0) ||
!EQUIV(float_previous->get_control_out_value(), 0))
{
-// printf("FloatAutos::automation_is_constant %d %d %d %f %f %f %f\n",
-// start,
-// float_previous->position,
-// float_current->position,
-// float_previous->get_value(),
-// float_current->get_value(),
-// float_previous->get_control_out_value(),
+// printf("FloatAutos::automation_is_constant %d %d %d %f %f %f %f\n",
+// start,
+// float_previous->position,
+// float_current->position,
+// float_previous->get_value(),
+// float_current->get_value(),
+// float_previous->get_control_out_value(),
// float_current->get_control_in_value());
return 0;
}
double FloatAutos::get_automation_constant(int64_t start, int64_t end)
{
Auto *current_auto, *before = 0, *after = 0;
-
-// quickly get autos just outside range
+
+// quickly get autos just outside range
get_neighbors(start, end, &before, &after);
// no auto before range so use first
}
-float FloatAutos::get_value(int64_t position,
- int direction,
- FloatAuto* &previous,
+float FloatAutos::get_value(int64_t position,
+ int direction,
+ FloatAuto* &previous,
FloatAuto* &next)
{
// Calculate bezier equation at position
// control points
float y1 = previous->get_value() + previous->get_control_out_value();
float y2 = next->get_value() + next->get_control_in_value();
- float t = (float)(position - previous->position) /
+ float t = (float)(position - previous->position) /
(next->position - previous->position);
float tpow2 = t * t;
float invt = 1 - t;
float invtpow2 = invt * invt;
float invtpow3 = invt * invt * invt;
-
+
float result = ( invtpow3 * y0
+ 3 * t * invtpow2 * y1
- + 3 * tpow2 * invt * y2
+ + 3 * tpow2 * invt * y2
+ tpow3 * y3);
//printf("FloatAutos::get_value(t=%5.3f)->%6.2f (prev,pos,next)=(%d,%d,%d)\n", t, result, previous->position, position, next->position);
}
float y0 = previous->get_value();
float y3 = next->get_value();
-
+
// control points
float y1 = previous->get_value() + previous->get_control_out_value();
float y2 = next->get_value() + next->get_control_in_value();
-// normalized scale
- float t = (float)(position - previous->position) / scale;
-
+// normalized scale
+ float t = (float)(position - previous->position) / scale;
+
float tpow2 = t * t;
float invt = 1 - t;
float invtpow2 = invt * invt;
-
+
float slope = 3 * (
- invtpow2 * y0
- invt * ( 2*t - invt ) * y1
- + t * ( 2*invt - t ) * y2
+ + t * ( 2*invt - t ) * y2
+ tpow2 * y3
);
-
+
return slope / scale;
}
-void FloatAutos::get_extents(float *min,
+void FloatAutos::get_extents(float *min,
float *max,
int *coords_undefined,
int64_t unit_start,
*min = *max = current->get_value();
*coords_undefined = 0;
}
-
+
*min = MIN(current->get_value(), *min);
*min = MIN(current->get_value() + current->get_control_in_value(), *min);
*min = MIN(current->get_value() + current->get_control_out_value(), *min);
FloatAuto *next = 0;
int64_t unit_step = edl->local_session->zoom_sample;
if(track->data_type == TRACK_VIDEO)
- unit_step = (int64_t)(unit_step *
- edl->session->frame_rate /
+ unit_step = (int64_t)(unit_step *
+ edl->session->frame_rate /
edl->session->sample_rate);
unit_step = MAX(unit_step, 1);
- for(int64_t position = unit_start;
- position < unit_end;
+ for(int64_t position = unit_start;
+ position < unit_end;
position += unit_step)
{
float value = get_value(position,PLAY_FORWARD,prev,next);
{
*min = MIN(value, *min);
*max = MAX(value, *max);
- }
+ }
+ }
+}
+
+void FloatAutos::set_proxy(int orig_scale, int new_scale)
+{
+ float orig_value;
+ orig_value = ((FloatAuto*)default_auto)->value * orig_scale;
+ ((FloatAuto*)default_auto)->value = orig_value / new_scale;
+
+ for( FloatAuto *current= (FloatAuto*)first; current; current=(FloatAuto*)NEXT ) {
+ orig_value = current->value * orig_scale;
+ current->value = orig_value / new_scale;
+ orig_value = current->control_in_value * orig_scale;
+ current->control_in_value = orig_value / new_scale;
+ orig_value = current->control_out_value * orig_scale;
+ current->control_out_value = orig_value / new_scale;
}
}
void FloatAutos::dump()
{
printf(" FloatAutos::dump %p\n", this);
- printf(" Default: position %jd value=%f\n",
+ printf(" Default: position %jd value=%f\n",
default_auto->position, ((FloatAuto*)default_auto)->get_value());
for(Auto* current = first; current; current = NEXT)
{
- printf(" position %jd value=%7.3f invalue=%7.3f outvalue=%7.3f %s\n",
- current->position,
+ printf(" position %jd value=%7.3f invalue=%7.3f outvalue=%7.3f %s\n",
+ current->position,
((FloatAuto*)current)->get_value(),
((FloatAuto*)current)->get_control_in_value(),
((FloatAuto*)current)->get_control_out_value(),
FloatAuto::curve_name(((FloatAuto*)current)->curve_mode));
}
}
+
+double FloatAutos::automation_integral(int64_t start, int64_t length, int direction)
+{
+ if( direction == PLAY_REVERSE )
+ start -= length;
+ if( start < 0 ) {
+ length += start;
+ start = 0;
+ }
+ int64_t end = start + length;
+ double value = 0, track_length = track->get_length();
+ int64_t pos = start, len = track->to_units(track_length,0);
+ if( end > len ) end = len;
+ while( pos < end ) {
+ int64_t prev_pos = 0, next_pos = len;
+ Auto *zprev = 0, *znext = 0;
+ FloatAuto *prev = (FloatAuto*)get_prev_auto(pos, direction, zprev, 0);
+ if( prev ) prev_pos = prev->position;
+ FloatAuto *next = (FloatAuto*)get_next_auto(pos, direction, znext, 0);
+ if( next ) next_pos = next->position;
+ if( !prev && !next ) prev = next = (FloatAuto*)default_auto;
+ else if( !prev ) prev = next;
+ else if( !next ) next = prev;
+
+ double dt = next_pos - prev_pos;
+ double t0 = (pos - prev_pos) / dt;
+ if( (pos = next_pos) > end ) pos = end;
+ double t1 = (pos - prev_pos) / dt;
+
+ double y0 = prev->get_value(), y1 = y0 + prev->get_control_out_value();
+ double y3 = next->get_value(), y2 = y3 + next->get_control_in_value();
+ if( y0 != y1 || y1 != y2 || y2 != y3 ) {
+// bezier definite integral t0..t1
+ double f4 = -y0/4 + 3*y1/4 - 3*y2/4 + y3/4;
+ double f3 = y0 - 2*y1 + y2;
+ double f2 = -3*y0/2 + 3*y1/2;
+ double f1 = y0, t = t0;
+ double t2 = t*t, t3 = t2*t, t4 = t3*t;
+ t0 = t4*f4 + t3*f3 + t2*f2 + t*f1;
+ t = t1; t2 = t*t; t3 = t2*t; t4 = t3*t;
+ t1 = t4*f4 + t3*f3 + t2*f2 + t*f1;
+ }
+ else {
+ t0 *= y0; t1 *= y0;
+ }
+ value += dt * (t1 - t0);
+ }
+
+ return value + 1e-6;
+}
+