double Envelope::IntegralOfInverse( double t0, double t1 ) { if(t0 == t1) return 0.0; if(t0 > t1) { return -IntegralOfInverse(t1, t0); // this makes more sense than returning the default value } unsigned int count = mEnv.Count(); if(count == 0) // 'empty' envelope return (t1 - t0) / mDefaultValue; double total = 0.0, lastT, lastVal; unsigned int i; // this is the next point to check if(t0 < mEnv[0]->GetT()) // t0 preceding the first point { if(t1 <= mEnv[0]->GetT()) return (t1 - t0) / mEnv[0]->GetVal(); i = 1; lastT = mEnv[0]->GetT(); lastVal = mEnv[0]->GetVal(); total += (lastT - t0) / lastVal; } else if(t0 >= mEnv[count - 1]->GetT()) // t0 following the last point { return (t1 - t0) / mEnv[count - 1]->GetVal(); } else // t0 enclosed by points { // Skip any points that come before t0 using binary search int lo, hi; BinarySearchForTime(lo, hi, t0); lastVal = InterpolatePoints(mEnv[lo]->GetVal(), mEnv[hi]->GetVal(), (t0 - mEnv[lo]->GetT()) / (mEnv[hi]->GetT() - mEnv[lo]->GetT()), mDB); lastT = t0; i = hi; // the point immediately after t0. } // loop through the rest of the envelope points until we get to t1 while (1) { if(i >= count) // the requested range extends beyond the last point { return total + (t1 - lastT) / lastVal; } else if(mEnv[i]->GetT() >= t1) // this point follows the end of the range { double thisVal = InterpolatePoints(mEnv[i - 1]->GetVal(), mEnv[i]->GetVal(), (t1 - mEnv[i - 1]->GetT()) / (mEnv[i]->GetT() - mEnv[i - 1]->GetT()), mDB); return total + IntegrateInverseInterpolated(lastVal, thisVal, t1 - lastT, mDB); } else // this point preceeds the end of the range { total += IntegrateInverseInterpolated(lastVal, mEnv[i]->GetVal(), mEnv[i]->GetT() - lastT, mDB); lastT = mEnv[i]->GetT(); lastVal = mEnv[i]->GetVal(); i++; } } }
double Envelope::NextPointAfter(double t) { if( mEnv[mEnv.Count()-1]->GetT() < t ) return t; else if( t < mEnv[0]->GetT() ) return mEnv[0]->GetT(); else { int lo,hi; BinarySearchForTime( lo, hi, t ); if( mEnv[hi]->GetT() == t ) return mEnv[hi+1]->GetT(); else return mEnv[hi]->GetT(); } }
int Envelope::NumberOfPointsAfter(double t) { if( t >= mEnv[mEnv.Count()-1]->GetT() ) return 0; else if( t < mEnv[0]->GetT() ) return mEnv.Count(); else { int lo,hi; BinarySearchForTime( lo, hi, t ); if( mEnv[hi]->GetT() == t ) return mEnv.Count() - (hi+1); else return mEnv.Count() - hi; } }
double Envelope::SolveIntegralOfInverse( double t0, double area ) { if(area == 0.0) return t0; unsigned int count = mEnv.Count(); if(count == 0) // 'empty' envelope return t0 + area * mDefaultValue; double lastT, lastVal; int i; // this is the next point to check if(t0 < mEnv[0]->GetT()) // t0 preceding the first point { if (area < 0) { return t0 + area * mEnv[0]->GetVal(); } else { i = 1; lastT = mEnv[0]->GetT(); lastVal = mEnv[0]->GetVal(); double added = (lastT - t0) / lastVal; if(added >= area) return t0 + area * mEnv[0]->GetVal(); area -= added; } } else if(t0 >= mEnv[count - 1]->GetT()) // t0 following the last point { if (area < 0) { i = count - 2; lastT = mEnv[count - 1]->GetT(); lastVal = mEnv[count - 1]->GetVal(); double added = (lastT - t0) / lastVal; // negative if(added <= area) return t0 + area * mEnv[count - 1]->GetVal(); area -= added; } else { return t0 + area * mEnv[count - 1]->GetVal(); } } else // t0 enclosed by points { // Skip any points that come before t0 using binary search int lo, hi; BinarySearchForTime(lo, hi, t0); lastVal = InterpolatePoints(mEnv[lo]->GetVal(), mEnv[hi]->GetVal(), (t0 - mEnv[lo]->GetT()) / (mEnv[hi]->GetT() - mEnv[lo]->GetT()), mDB); lastT = t0; if (area < 0) i = lo; else i = hi; // the point immediately after t0. } if (area < 0) { // loop BACKWARDS through the rest of the envelope points until we get to t1 // (which is less than t0) while (1) { if(i < 0) // the requested range extends beyond the leftmost point { return lastT + area * lastVal; } else { double added = -IntegrateInverseInterpolated(mEnv[i]->GetVal(), lastVal, lastT - mEnv[i]->GetT(), mDB); if(added <= area) return lastT - SolveIntegrateInverseInterpolated(lastVal, mEnv[i]->GetVal(), lastT - mEnv[i]->GetT(), -area, mDB); area -= added; lastT = mEnv[i]->GetT(); lastVal = mEnv[i]->GetVal(); --i; } } } else { // loop through the rest of the envelope points until we get to t1 while (1) { if(i >= count) // the requested range extends beyond the last point { return lastT + area * lastVal; } else { double added = IntegrateInverseInterpolated(lastVal, mEnv[i]->GetVal(), mEnv[i]->GetT() - lastT, mDB); if(added >= area) return lastT + SolveIntegrateInverseInterpolated(lastVal, mEnv[i]->GetVal(), mEnv[i]->GetT() - lastT, area, mDB); area -= added; lastT = mEnv[i]->GetT(); lastVal = mEnv[i]->GetVal(); i++; } } } }
void Envelope::GetValues(double *buffer, int bufferLen, double t0, double tstep) const { t0 -= mOffset; // JC: If bufferLen ==0 we have probably just allocated a zero sized buffer. wxASSERT( bufferLen > 0 ); int len = mEnv.Count(); double t = t0; double tprev, vprev, tnext = 0, vnext, vstep = 0; for (int b = 0; b < bufferLen; b++) { // Get easiest cases out the way first... // IF empty envelope THEN default value if (len <= 0) { buffer[b] = mDefaultValue; t += tstep; continue; } // IF before envelope THEN first value if (t <= mEnv[0]->GetT()) { buffer[b] = mEnv[0]->GetVal(); t += tstep; continue; } // IF after envelope THEN last value if (t >= mEnv[len - 1]->GetT()) { buffer[b] = mEnv[len - 1]->GetVal(); t += tstep; continue; } if (b == 0 || t > tnext) { // We're beyond our tnext, so find the next one. // Don't just increment lo or hi because we might // be zoomed far out and that could be a large number of // points to move over. That's why we binary search. int lo,hi; BinarySearchForTime( lo, hi, t ); tprev = mEnv[lo]->GetT(); tnext = mEnv[hi]->GetT(); vprev = GetInterpolationStartValueAtPoint( lo ); vnext = GetInterpolationStartValueAtPoint( hi ); // Interpolate, either linear or log depending on mDB. double dt = (tnext - tprev); double to = t - tprev; double v; if (dt > 0.0) { v = (vprev * (dt - to) + vnext * to) / dt; vstep = (vnext - vprev) * tstep / dt; } else { v = vnext; vstep = 0.0; } // An adjustment if logarithmic scale. if( mDB ) { v = pow(10.0, v); vstep = pow( 10.0, vstep ); } buffer[b] = v; } else { if (mDB){ buffer[b] = buffer[b - 1] * vstep; }else{ buffer[b] = buffer[b - 1] + vstep; } } t += tstep; } }
// We should be able to write a very efficient memoizer for this // but make sure it gets reset when the envelope is changed. double Envelope::Integral( double t0, double t1 ) { //printf( "\n\nIntegral: t0=%f, t1=%f\n", t0, t1 ); double total=0; if( t0 == t1 ) return 0; if( t0 > t1 ) { printf( "Odd things happening in Integral!\n" ); return mDefaultValue; } unsigned int i = 0; double lastT, lastVal; // t0 is one of three cases: // 0) in an 'empty' envelope // 1) preceeding the first point // 2) enclosed by points // 3) following the last point if( mEnv.Count() < 1 ) // 0: 'empty' envelope { return (t1 - t0) * mDefaultValue; } else if( t0 < mEnv[0]->t ) // 1: preceeds the first { if( t1 <= mEnv[0]->t ) { return (t1 - t0) * mEnv[0]->val; } total += (mEnv[0]->t - t0) * mEnv[0]->val; lastT = mEnv[0]->t; lastVal = mEnv[0]->val; } else if( t0 >= mEnv[mEnv.Count()-1]->t ) // 3: follows the last { return (t1 - t0) * mEnv[mEnv.Count()-1]->val; } else { // 2: bracketed // Skip any points that come before t0 using binary search int lo,hi; BinarySearchForTime( lo, hi, t0 ); i = lo; // i is now the point immediately before t0. lastVal = ((mEnv[i]->val * (mEnv[i+1]->t - t0)) + (mEnv[i+1]->val *(t0 - mEnv[i]->t))) / (mEnv[i+1]->t - mEnv[i]->t); // value at t0 lastT = t0; } // loop through the rest of the envelope points until we get to t1 while (1) { if(i >= mEnv.Count()-1) { // the requested range extends beyond last point return total + (t1 - lastT) * lastVal; } else if (mEnv[i+1]->t >= t1) { // last,i+1 bracket t1 double thisVal = ((mEnv[i]->val * (mEnv[i+1]->t - t1)) + (mEnv[i+1]->val *(t1 - mEnv[i]->t))) / (mEnv[i+1]->t - mEnv[i]->t); return total + (t1 - lastT) * (thisVal + lastVal) / 2; } else { // t1 still follows last,i+1 total += (mEnv[i+1]->t - lastT) * (mEnv[i+1]->val + lastVal) / 2; lastT = mEnv[i+1]->t; lastVal = mEnv[i+1]->val; i++; } } }