add edit speed duration update, autogroup select when modify auto
[goodguy/history.git] / cinelerra-5.1 / cinelerra / floatautos.C
index 80e9c8bfb54e10dee21e6c59d4aeab8b2c89ac9b..95dcace9ce6d97288a6357a7e93512ec7a825eb6 100644 (file)
@@ -409,6 +409,22 @@ void FloatAutos::get_extents(float *min,
        }
 }
 
+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);
@@ -424,3 +440,66 @@ void FloatAutos::dump()
                        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;
+       }
+       double value = 0;
+       int64_t pos = start, len = length, end = pos + len;
+       while( pos < end ) {
+               int64_t prev_pos = 0, next_pos = end;
+               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;
+}
+
+int64_t FloatAutos::speed_position(double pos)
+{
+       double length = track->get_length();
+       int64_t l = -1, r = track->to_units(length, 1);
+       if( r < 1 ) r = 1;
+       for( int i=32; --i >= 0 && automation_integral(0,r,PLAY_FORWARD) <= pos; r*=2 );
+       for( int i=64; --i >= 0 && (r-l)>1; ) {
+               int64_t m = (l + r) / 2;
+               double t = automation_integral(0,m,PLAY_FORWARD) - pos;
+               *(t >= 0 ? &r : &l) = m;
+       }
+       return r;
+}
+