Fix crash on out of range MIDI events (though this shouldn't be possible at all....
[ardour.git] / libs / ardour / curve.cc
index 977b6dfd7be5088fc88df669e594497e57564a71..dcce3c0c6cd9f938c539f6d5b4f4063538e57846 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2001-2003 Paul Davis 
+    Copyright (C) 2001-2007 Paul Davis 
 
     Contains ideas derived from "Constrained Cubic Spline Interpolation" 
     by CJC Kruger (www.korf.co.uk/spline.pdf).
@@ -18,7 +18,6 @@
     along with this program; if not, write to the Free Software
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
-    $Id$
 */
 
 #include <iostream>
@@ -32,6 +31,7 @@
 #include <sigc++/bind.h>
 
 #include "ardour/curve.h"
+#include "ardour/automation_event.h"
 
 #include "i18n.h"
 
@@ -40,29 +40,11 @@ using namespace ARDOUR;
 using namespace sigc;
 using namespace PBD;
 
-Curve::Curve (double minv, double maxv, double canv, bool nostate)
-       : AutomationList (canv, nostate)
-{
-       min_yval = minv;
-       max_yval = maxv;
-}
-
-Curve::Curve (const Curve& other)
-       : AutomationList (other)
-{
-       min_yval = other.min_yval;
-       max_yval = other.max_yval;
-}
-
-Curve::Curve (const Curve& other, double start, double end)
-       : AutomationList (other, start, end)
-{
-       min_yval = other.min_yval;
-       max_yval = other.max_yval;
-}
-
-Curve::~Curve ()
+Curve::Curve (const AutomationList& al)
+       : _dirty (true)
+       , _list (al)
 {
+       _list.Dirty.connect(mem_fun(*this, &Curve::on_list_dirty));
 }
 
 void
@@ -74,7 +56,7 @@ Curve::solve ()
                return;
        }
        
-       if ((npoints = events.size()) > 2) {
+       if ((npoints = _list.events().size()) > 2) {
                
                /* Compute coefficients needed to efficiently compute a constrained spline
                   curve. See "Constrained Cubic Spline Interpolation" by CJC Kruger
@@ -84,16 +66,16 @@ Curve::solve ()
                double x[npoints];
                double y[npoints];
                uint32_t i;
-               AutomationEventList::iterator xx;
+               AutomationList::EventList::const_iterator xx;
 
-               for (i = 0, xx = events.begin(); xx != events.end(); ++xx, ++i) {
+               for (i = 0, xx = _list.events().begin(); xx != _list.events().end(); ++xx, ++i) {
                        x[i] = (double) (*xx)->when;
                        y[i] = (double) (*xx)->value;
                }
 
                double lp0, lp1, fpone;
 
-               lp0 =(x[1] - x[0])/(y[1] - y[0]);
+               lp0 = (x[1] - x[0])/(y[1] - y[0]);
                lp1 = (x[2] - x[1])/(y[2] - y[1]);
 
                if (lp0*lp1 < 0) {
@@ -104,16 +86,7 @@ Curve::solve ()
 
                double fplast = 0;
 
-               for (i = 0, xx = events.begin(); xx != events.end(); ++xx, ++i) {
-                       
-                       CurvePoint* cp = dynamic_cast<CurvePoint*>(*xx);
-
-                       if (cp == 0) {
-                               fatal  << _("programming error: ")
-                                      << X_("non-CurvePoint event found in event list for a Curve")
-                                      << endmsg;
-                               /*NOTREACHED*/
-                       }
+               for (i = 0, xx = _list.events().begin(); xx != _list.events().end(); ++xx, ++i) {
                        
                        double xdelta;   /* gcc is wrong about possible uninitialized use */
                        double xdelta2;  /* ditto */
@@ -188,10 +161,11 @@ Curve::solve ()
 
                        /* store */
 
-                       cp->coeff[0] = y[i-1] - (b * x[i-1]) - (c * xim12) - (d * xim13);
-                       cp->coeff[1] = b;
-                       cp->coeff[2] = c;
-                       cp->coeff[3] = d;
+                       (*xx)->create_coeffs();
+                       (*xx)->coeff[0] = y[i-1] - (b * x[i-1]) - (c * xim12) - (d * xim13);
+                       (*xx)->coeff[1] = b;
+                       (*xx)->coeff[2] = c;
+                       (*xx)->coeff[3] = d;
 
                        fplast = fpi;
                }
@@ -204,7 +178,7 @@ Curve::solve ()
 bool
 Curve::rt_safe_get_vector (double x0, double x1, float *vec, int32_t veclen)
 {
-       Glib::Mutex::Lock lm (lock, Glib::TRY_LOCK);
+       Glib::Mutex::Lock lm(_list.lock(), Glib::TRY_LOCK);
 
        if (!lm.locked()) {
                return false;
@@ -217,7 +191,7 @@ Curve::rt_safe_get_vector (double x0, double x1, float *vec, int32_t veclen)
 void
 Curve::get_vector (double x0, double x1, float *vec, int32_t veclen)
 {
-       Glib::Mutex::Lock lm (lock);
+       Glib::Mutex::Lock lm(_list.lock());
        _get_vector (x0, x1, vec, veclen);
 }
 
@@ -229,22 +203,22 @@ Curve::_get_vector (double x0, double x1, float *vec, int32_t veclen)
        int32_t original_veclen;
        int32_t npoints;
 
-        if ((npoints = events.size()) == 0) {
-                 for (i = 0; i < veclen; ++i) {
-                         vec[i] = default_value;
-                 }
-                 return;
+       if ((npoints = _list.events().size()) == 0) {
+               for (i = 0; i < veclen; ++i) {
+                       vec[i] = _list.default_value();
+               }
+               return;
        }
 
        /* events is now known not to be empty */
 
-       max_x = events.back()->when;
-       min_x = events.front()->when;
+       max_x = _list.events().back()->when;
+       min_x = _list.events().front()->when;
 
        lx = max (min_x, x0);
 
        if (x1 < 0) {
-               x1 = events.back()->when;
+               x1 = _list.events().back()->when;
        }
 
        hx = min (max_x, x1);
@@ -263,7 +237,7 @@ Curve::_get_vector (double x0, double x1, float *vec, int32_t veclen)
                subveclen = min (subveclen, veclen);
 
                for (i = 0; i < subveclen; ++i) {
-                       vec[i] = events.front()->value;
+                       vec[i] = _list.events().front()->value;
                }
 
                veclen -= subveclen;
@@ -282,7 +256,7 @@ Curve::_get_vector (double x0, double x1, float *vec, int32_t veclen)
                
                subveclen = min (subveclen, veclen);
 
-               val = events.back()->value;
+               val = _list.events().back()->value;
 
                i = veclen - subveclen;
 
@@ -300,7 +274,7 @@ Curve::_get_vector (double x0, double x1, float *vec, int32_t veclen)
        if (npoints == 1 ) {
        
                for (i = 0; i < veclen; ++i) {
-                       vec[i] = events.front()->value;
+                       vec[i] = _list.events().front()->value;
                }
                return;
        }
@@ -321,11 +295,11 @@ Curve::_get_vector (double x0, double x1, float *vec, int32_t veclen)
                        dx = 0; // not used
                }
        
-               double slope = (events.back()->value - events.front()->value)/  
-                       (events.back()->when - events.front()->when);
+               double slope = (_list.events().back()->value - _list.events().front()->value)/  
+                       (_list.events().back()->when - _list.events().front()->when);
                double yfrac = dx*slope;
  
-               vec[0] = events.front()->value + slope * (lx - events.front()->when);
+               vec[0] = _list.events().front()->value + slope * (lx - _list.events().front()->when);
  
                for (i = 1; i < veclen; ++i) {
                        vec[i] = vec[i-1] + yfrac;
@@ -353,27 +327,30 @@ Curve::_get_vector (double x0, double x1, float *vec, int32_t veclen)
 double
 Curve::unlocked_eval (double x)
 {
+       // I don't see the point of this...
+
        if (_dirty) {
                solve ();
        }
 
-       return shared_eval (x);
+       return _list.unlocked_eval (x);
 }
 
 double
 Curve::multipoint_eval (double x)
 {      
-       pair<AutomationEventList::iterator,AutomationEventList::iterator> range;
+       pair<AutomationList::EventList::const_iterator,AutomationList::EventList::const_iterator> range;
+
+       AutomationList::LookupCache& lookup_cache = _list.lookup_cache();
 
        if ((lookup_cache.left < 0) ||
            ((lookup_cache.left > x) || 
-            (lookup_cache.range.first == events.end()) || 
+            (lookup_cache.range.first == _list.events().end()) || 
             ((*lookup_cache.range.second)->when < x))) {
                
-               TimeComparator cmp;
                ControlEvent cp (x, 0.0);
 
-               lookup_cache.range = equal_range (events.begin(), events.end(), &cp, cmp);
+               lookup_cache.range = equal_range (_list.events().begin(), _list.events().end(), &cp, AutomationList::time_comparator);
        }
 
        range = lookup_cache.range;
@@ -395,21 +372,21 @@ Curve::multipoint_eval (double x)
                
                lookup_cache.left = x;
 
-               if (range.first == events.begin()) {
+               if (range.first == _list.events().begin()) {
                        /* we're before the first point */
                        // return default_value;
-                       events.front()->value;
+                       _list.events().front()->value;
                }
                
-               if (range.second == events.end()) {
+               if (range.second == _list.events().end()) {
                        /* we're after the last point */
-                       return events.back()->value;
+                       return _list.events().back()->value;
                }
 
                double x2 = x * x;
-               CurvePoint* cp = dynamic_cast<CurvePoint*> (*range.second);
+               ControlEvent* ev = *range.second;
 
-               return cp->coeff[0] + (cp->coeff[1] * x) + (cp->coeff[2] * x2) + (cp->coeff[3] * x2 * x);
+               return ev->coeff[0] + (ev->coeff[1] * x) + (ev->coeff[2] * x2) + (ev->coeff[3] * x2 * x);
        } 
 
        /* x is a control point in the data */
@@ -418,26 +395,6 @@ Curve::multipoint_eval (double x)
        return (*range.first)->value;
 }
 
-ControlEvent*
-Curve::point_factory (double when, double val) const
-{
-       return new CurvePoint (when, val);
-}
-
-ControlEvent*
-Curve::point_factory (const ControlEvent& other) const
-{
-       return new CurvePoint (other.when, other.value);
-}
-
-Change
-Curve::restore_state (StateManager::State& state)
-{
-       mark_dirty ();
-       return AutomationList::restore_state (state);
-}
-
-
 extern "C" {
 
 void