X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fevoral%2Fsrc%2FCurve.cpp;h=44fc48f7282c168d7f31f3d70a7fa7234089cea8;hb=b855e5f3220027502a3c88f189d511fe2a5a3c2b;hp=61487098c2ce204fc95a2d531bbe7cf09cfad220;hpb=0906b39918ba0551044bd1f8c50e9de4d5aa1694;p=ardour.git diff --git a/libs/evoral/src/Curve.cpp b/libs/evoral/src/Curve.cpp index 61487098c2..44fc48f728 100644 --- a/libs/evoral/src/Curve.cpp +++ b/libs/evoral/src/Curve.cpp @@ -22,8 +22,9 @@ #include #include #include +#include -#include +#include #include "evoral/Curve.hpp" #include "evoral/ControlList.hpp" @@ -56,8 +57,8 @@ Curve::solve () (www.korf.co.uk/spline.pdf) for more details. */ - double x[npoints]; - double y[npoints]; + vector x(npoints); + vector y(npoints); uint32_t i; ControlList::EventList::const_iterator xx; @@ -124,7 +125,6 @@ Curve::solve () } else { fpi = 2 / (slope_before + slope_after); } - } /* compute second derivative for either side of control point `i' */ @@ -171,7 +171,7 @@ Curve::solve () bool Curve::rt_safe_get_vector (double x0, double x1, float *vec, int32_t veclen) { - Glib::Mutex::Lock lm(_list.lock(), Glib::TRY_LOCK); + Glib::Threads::Mutex::Lock lm(_list.lock(), Glib::Threads::TRY_LOCK); if (!lm.locked()) { return false; @@ -184,37 +184,59 @@ 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(_list.lock()); + Glib::Threads::Mutex::Lock lm(_list.lock()); _get_vector (x0, x1, vec, veclen); } void Curve::_get_vector (double x0, double x1, float *vec, int32_t veclen) { - double rx, dx, lx, hx, max_x, min_x; + double rx, lx, hx, max_x, min_x; int32_t i; int32_t original_veclen; int32_t npoints; + if (veclen == 0) { + return; + } + if ((npoints = _list.events().size()) == 0) { - for (i = 0; i < veclen; ++i) { + /* no events in list, so just fill the entire array with the default value */ + for (int32_t i = 0; i < veclen; ++i) { vec[i] = _list.default_value(); } return; } + if (npoints == 1) { + for (int32_t i = 0; i < veclen; ++i) { + vec[i] = _list.events().front()->value; + } + return; + } + /* events is now known not to be empty */ max_x = _list.events().back()->when; min_x = _list.events().front()->when; - lx = max (min_x, x0); - - if (x1 < 0) { - x1 = _list.events().back()->when; + if (x0 > max_x) { + /* totally past the end - just fill the entire array with the final value */ + for (int32_t i = 0; i < veclen; ++i) { + vec[i] = _list.events().back()->value; + } + return; } - hx = min (max_x, x1); + if (x1 < min_x) { + /* totally before the first event - fill the entire array with + * the initial value. + */ + for (int32_t i = 0; i < veclen; ++i) { + vec[i] = _list.events().front()->value; + } + return; + } original_veclen = veclen; @@ -225,16 +247,16 @@ Curve::_get_vector (double x0, double x1, float *vec, int32_t veclen) */ double frac = (min_x - x0) / (x1 - x0); - int32_t subveclen = (int32_t) floor (veclen * frac); + int64_t fill_len = (int64_t) floor (veclen * frac); - subveclen = min (subveclen, veclen); + fill_len = min (fill_len, (int64_t)veclen); - for (i = 0; i < subveclen; ++i) { + for (i = 0; i < fill_len; ++i) { vec[i] = _list.events().front()->value; } - veclen -= subveclen; - vec += subveclen; + veclen -= fill_len; + vec += fill_len; } if (veclen && x1 > max_x) { @@ -242,60 +264,52 @@ Curve::_get_vector (double x0, double x1, float *vec, int32_t veclen) /* fill some end section of the array with the default or final value */ double frac = (x1 - max_x) / (x1 - x0); - - int32_t subveclen = (int32_t) floor (original_veclen * frac); - + int64_t fill_len = (int64_t) floor (original_veclen * frac); float val; - subveclen = min (subveclen, veclen); - + fill_len = min (fill_len, (int64_t)veclen); val = _list.events().back()->value; - i = veclen - subveclen; - - for (i = veclen - subveclen; i < veclen; ++i) { + for (i = veclen - fill_len; i < veclen; ++i) { vec[i] = val; } - veclen -= subveclen; - } - - if (veclen == 0) { - return; - } - - if (npoints == 1) { - - for (i = 0; i < veclen; ++i) { - vec[i] = _list.events().front()->value; - } - return; + veclen -= fill_len; } + lx = max (min_x, x0); + hx = min (max_x, x1); if (npoints == 2) { /* linear interpolation between 2 points */ - /* XXX I'm not sure that this is the right thing to - do here. but its not a common case for the envisaged - uses. + /* XXX: this numerator / denominator stuff is pretty grim, but it's the only + way I could get the maths to be accurate; doing everything with pure doubles + gives ~1e-17 errors in the vec[i] computation. */ - if (veclen > 1) { - dx = (hx - lx) / (veclen - 1) ; - } else { - dx = 0; // not used - } + /* gradient of the line */ + double const m_num = _list.events().back()->value - _list.events().front()->value; + double const m_den = _list.events().back()->when - _list.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; + /* y intercept of the line */ + double const c = double (_list.events().back()->value) - (m_num * _list.events().back()->when / m_den); - vec[0] = _list.events().front()->value + slope * (lx - _list.events().front()->when); + /* dx that we are using */ + double dx_num = 0; + double dx_den = 1; + if (veclen > 1) { + dx_num = hx - lx; + dx_den = veclen - 1; + } - for (i = 1; i < veclen; ++i) { - vec[i] = vec[i-1] + yfrac; + if (veclen > 1) { + for (int i = 0; i < veclen; ++i) { + vec[i] = (lx * (m_num / m_den) + m_num * i * dx_num / (m_den * dx_den)) + c; + } + } else { + vec[0] = lx; } return; @@ -307,10 +321,9 @@ Curve::_get_vector (double x0, double x1, float *vec, int32_t veclen) rx = lx; + double dx = 0; if (veclen > 1) { dx = (hx - lx) / (veclen - 1); - } else { - dx = 0; } for (i = 0; i < veclen; ++i, rx += dx) { @@ -369,7 +382,7 @@ Curve::multipoint_eval (double x) if (range.first == _list.events().begin()) { /* we're before the first point */ // return default_value; - _list.events().front()->value; + return _list.events().front()->value; } if (range.second == _list.events().end()) { @@ -377,10 +390,28 @@ Curve::multipoint_eval (double x) return _list.events().back()->value; } + ControlEvent* after = (*range.second); + range.second--; + ControlEvent* before = (*range.second); + + double vdelta = after->value - before->value; + + if (vdelta == 0.0) { + return before->value; + } + + double tdelta = x - before->when; + double trange = after->when - before->when; + + return before->value + (vdelta * (tdelta / trange)); + +#if 0 double x2 = x * x; ControlEvent* ev = *range.second; - return ev->coeff[0] + (ev->coeff[1] * x) + (ev->coeff[2] * x2) + (ev->coeff[3] * x2 * x); + return = ev->coeff[0] + (ev->coeff[1] * x) + (ev->coeff[2] * x2) + (ev->coeff[3] * x2 * x); +#endif + } /* x is a control point in the data */