We should be able to write a very efficient memoizer for this but make sure it gets reset when the envelope is changed.
| 1222 | // We should be able to write a very efficient memoizer for this |
| 1223 | // but make sure it gets reset when the envelope is changed. |
| 1224 | double Envelope::Integral( double t0, double t1 ) const |
| 1225 | { |
| 1226 | if(t0 == t1) |
| 1227 | return 0.0; |
| 1228 | if(t0 > t1) |
| 1229 | { |
| 1230 | return -Integral(t1, t0); // this makes more sense than returning the default value |
| 1231 | } |
| 1232 | |
| 1233 | unsigned int count = mEnv.size(); |
| 1234 | if(count == 0) // 'empty' envelope |
| 1235 | return (t1 - t0) * mDefaultValue; |
| 1236 | |
| 1237 | t0 -= mOffset; |
| 1238 | t1 -= mOffset; |
| 1239 | |
| 1240 | double total = 0.0, lastT, lastVal; |
| 1241 | unsigned int i; // this is the next point to check |
| 1242 | if(t0 < mEnv[0].GetT()) // t0 preceding the first point |
| 1243 | { |
| 1244 | if(t1 <= mEnv[0].GetT()) |
| 1245 | return (t1 - t0) * mEnv[0].GetVal(); |
| 1246 | i = 1; |
| 1247 | lastT = mEnv[0].GetT(); |
| 1248 | lastVal = mEnv[0].GetVal(); |
| 1249 | total += (lastT - t0) * lastVal; |
| 1250 | } |
| 1251 | else if(t0 >= mEnv[count - 1].GetT()) // t0 at or following the last point |
| 1252 | { |
| 1253 | return (t1 - t0) * mEnv[count - 1].GetVal(); |
| 1254 | } |
| 1255 | else // t0 enclosed by points |
| 1256 | { |
| 1257 | // Skip any points that come before t0 using binary search |
| 1258 | int lo, hi; |
| 1259 | BinarySearchForTime(lo, hi, t0); |
| 1260 | lastVal = InterpolatePoints(mEnv[lo].GetVal(), mEnv[hi].GetVal(), (t0 - mEnv[lo].GetT()) / (mEnv[hi].GetT() - mEnv[lo].GetT()), mDB); |
| 1261 | lastT = t0; |
| 1262 | i = hi; // the point immediately after t0. |
| 1263 | } |
| 1264 | |
| 1265 | // loop through the rest of the envelope points until we get to t1 |
| 1266 | while (1) |
| 1267 | { |
| 1268 | if(i >= count) // the requested range extends beyond the last point |
| 1269 | { |
| 1270 | return total + (t1 - lastT) * lastVal; |
| 1271 | } |
| 1272 | else if(mEnv[i].GetT() >= t1) // this point follows the end of the range |
| 1273 | { |
| 1274 | double thisVal = InterpolatePoints(mEnv[i - 1].GetVal(), mEnv[i].GetVal(), (t1 - mEnv[i - 1].GetT()) / (mEnv[i].GetT() - mEnv[i - 1].GetT()), mDB); |
| 1275 | return total + IntegrateInterpolated(lastVal, thisVal, t1 - lastT, mDB); |
| 1276 | } |
| 1277 | else // this point precedes the end of the range |
| 1278 | { |
| 1279 | total += IntegrateInterpolated(lastVal, mEnv[i].GetVal(), mEnv[i].GetT() - lastT, mDB); |
| 1280 | lastT = mEnv[i].GetT(); |
| 1281 | lastVal = mEnv[i].GetVal(); |
no test coverage detected