1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-07-03 06:03:13 +02:00

Various fixes involving Envelope. More to come later.

This commit is contained in:
Paul Licameli 2017-05-07 11:16:50 -04:00
commit b6d43e4954
6 changed files with 371 additions and 337 deletions

View File

@ -42,28 +42,12 @@ a draggable point type.
#include "DirManager.h"
#include "TrackArtist.h"
Envelope::Envelope()
Envelope::Envelope(bool exponential, double minValue, double maxValue, double defaultValue)
: mDB(exponential)
, mMinValue(minValue)
, mMaxValue(maxValue)
, mDefaultValue { ClampValue(defaultValue) }
{
mOffset = 0.0;
mTrackLen = 0.0;
// Anything with a sample rate of no more than 200 KHz
// will have samples spaced apart by at least this amount,
// "epsilon". We use this to enforce that there aren't
// allowed to be multiple control points at the same t
// value.
mTrackEpsilon = 1.0 / 200000.0;
mDB = true;
mDefaultValue = 1.0;
mDragPoint = -1;
mMinValue = 1.0e-7;
mMaxValue = 2.0;
mSearchGuess = -1;
mDragPointValid = false;
}
Envelope::~Envelope()
@ -76,7 +60,7 @@ Envelope::~Envelope()
/// and rescale all envelope points accordingly (unlike SetRange, which clamps the envelope points to the NEW range).
/// @minValue - the NEW minimum value
/// @maxValue - the NEW maximum value
void Envelope::Rescale(double minValue, double maxValue)
void Envelope::RescaleValues(double minValue, double maxValue)
{
double oldMinValue = mMinValue;
double oldMaxValue = mMaxValue;
@ -196,41 +180,51 @@ EnvPoint *Envelope::AddPointAtEnd( double t, double val )
return &mEnv.back();
}
void Envelope::CopyFrom(const Envelope *e, double t0, double t1)
Envelope::Envelope(const Envelope &orig, double t0, double t1)
: mDB(orig.mDB)
, mMinValue(orig.mMinValue)
, mMaxValue(orig.mMaxValue)
, mDefaultValue(orig.mDefaultValue)
{
wxASSERT( t0 <= t1 );
mOffset = wxMax(t0, orig.mOffset);
mTrackLen = wxMin(t1, orig.mOffset + orig.mTrackLen) - mOffset;
mOffset = wxMax(t0, e->mOffset);
mTrackLen = wxMin(t1, e->mOffset + e->mTrackLen) - mOffset;
auto range1 = orig.EqualRange( t0 - orig.mOffset, 0 );
auto range2 = orig.EqualRange( t1 - orig.mOffset, 0 );
CopyRange(orig, range1.first, range2.second);
}
mEnv.clear();
int len = e->mEnv.size();
int i = 0;
Envelope::Envelope(const Envelope &orig)
: mDB(orig.mDB)
, mMinValue(orig.mMinValue)
, mMaxValue(orig.mMaxValue)
, mDefaultValue(orig.mDefaultValue)
{
mOffset = orig.mOffset;
mTrackLen = orig.mTrackLen;
CopyRange(orig, 0, orig.GetNumberOfPoints());
}
// Skip the points that come before the copied region
while ((i < len) && e->mOffset + e->mEnv[i].GetT() <= t0)
i++;
void Envelope::CopyRange(const Envelope &orig, size_t begin, size_t end)
{
int len = orig.mEnv.size();
int i = begin;
// Create the point at 0 if it needs interpolated representation
if (i>0)
AddPointAtEnd( 0, e->GetValue(mOffset) );
if ( i > 0 )
AddPointAtEnd(0, orig.GetValue(mOffset));
// Copy points from inside the copied region
while (i < len) {
const EnvPoint &point = e->mEnv[i];
const double when = e->mOffset + point.GetT() - mOffset;
if (when < mTrackLen) {
AddPointAtEnd(when, point.GetVal());
i++;
}
else
break;
for (; i < end; ++i) {
const EnvPoint &point = orig[i];
const double when = point.GetT() + (orig.mOffset - mOffset);
AddPointAtEnd(when, point.GetVal());
}
// Create the final point if it needs interpolated representation
// If the last point of e was exatly at t1, this effectively copies it too.
if (mTrackLen > 0 && i < len)
AddPointAtEnd( mTrackLen, e->GetValue(mOffset + mTrackLen));
AddPointAtEnd( mTrackLen, orig.GetValue(mOffset + mTrackLen));
}
/// Limit() limits a double value to a range.
@ -505,7 +499,7 @@ bool EnvelopeEditor::HandleMouseButtonDown(const wxMouseEvent & event, wxRect &
double newVal = ValueOfPixel(clip_y, r.height, upper, dB, dBRange,
zoomMin, zoomMax);
mEnvelope.SetDragPoint(mEnvelope.Insert(when - mEnvelope.GetOffset(), newVal));
mEnvelope.SetDragPoint(mEnvelope.InsertOrReplaceRelative(when - mEnvelope.GetOffset(), newVal));
mDirty = true;
}
@ -669,9 +663,6 @@ void Envelope::Paste(double t0, const Envelope *e)
// get values to perform framing of the insertion
double splitval = GetValue(t0 + mOffset);
if(len != 0) { // Not case 10: there are point/s in the envelope
/*
Old analysis of cases:
(see discussions on audacity-devel around 19/8/7 - 23/8/7 and beyond, "Envelopes and 'Join'")
@ -697,7 +688,7 @@ Old analysis of cases:
// In pasting in a clip we choose to preserve the envelope so that the loudness of the
// parts is unchanged.
//
// 1) This may introduce a discontnuity in the envelope at a boundary between the
// 1) This may introduce a discontinuity in the envelope at a boundary between the
// old and NEW clips. In that case we must ensure there are envelope points
// at sample positions immediately before and immediately after the boundary.
// 2) If the points have the same value we only need one of them.
@ -709,7 +700,9 @@ Old analysis of cases:
// Even simpler: we could always add two points at a boundary and then call
// RemoveUnneededPoints() (provided that function behaves correctly).
// See if existing points need shifting to the right, and what Case we are in
// See if existing points need shifting to the right, and what Case we are in
if(len != 0) {
// Not case 10: there are point/s in the envelope
for (i = 0; i < len; i++) {
if (mEnv[i].GetT() > t0)
someToShift = true;
@ -726,57 +719,66 @@ Old analysis of cases:
if( (mTrackLen - t0) < mTrackEpsilon )
atEnd = true;
if(0 > t0)
beforeStart = true; // Case 13
// Case 13
beforeStart = true;
if(mTrackLen < t0)
afterEnd = true; // Case 12
// Case 12
afterEnd = true;
// Now test for the various Cases, and try to do the right thing
if(atStart) { // insertion at the beginning
if(onPoint) { // first env point is at LH end
mEnv[0].SetT(mEnv[0].GetT() + mTrackEpsilon); // Case 1: move it R slightly to avoid duplicate point
if(atStart) {
// insertion at the beginning
if(onPoint) {
// Case 1: move it R slightly to avoid duplicate point
// first env point is at LH end
mEnv[0].SetT(mEnv[0].GetT() + mTrackEpsilon);
someToShift = true; // there is now, even if there wasn't before
//wxLogDebug(wxT("Case 1"));
}
else {
Insert(t0 + mTrackEpsilon, splitval); // Case 3: insert a point to maintain the envelope
// Case 3: insert a point to maintain the envelope
InsertOrReplaceRelative(t0 + mTrackEpsilon, splitval);
someToShift = true;
//wxLogDebug(wxT("Case 3"));
}
}
else {
if(atEnd) { // insertion at the end
if(onPoint) { // last env point is at RH end, Case 2:
mEnv[0].SetT(mEnv[0].GetT() - mTrackEpsilon); // move it L slightly to avoid duplicate point
if(atEnd) {
// insertion at the end
if(onPoint) {
// last env point is at RH end, Case 2:
// move it L slightly to avoid duplicate point
mEnv[0].SetT(mEnv[0].GetT() - mTrackEpsilon);
//wxLogDebug(wxT("Case 2"));
}
else { // Case 4:
Insert(t0 - mTrackEpsilon, splitval); // insert a point to maintain the envelope
else {
// Case 4:
// insert a point to maintain the envelope
InsertOrReplaceRelative(t0 - mTrackEpsilon, splitval);
//wxLogDebug(wxT("Case 4"));
}
}
else if(onPoint) {
// Case 7: move the point L and insert a NEW one to the R
mEnv[pos].SetT(mEnv[pos].GetT() - mTrackEpsilon);
InsertOrReplaceRelative(t0 + mTrackEpsilon, splitval);
someToShift = true;
//wxLogDebug(wxT("Case 7"));
}
else if( !beforeStart && !afterEnd ) {
// Case 5: Insert points to L and R
InsertOrReplaceRelative(t0 - mTrackEpsilon, splitval);
InsertOrReplaceRelative(t0 + mTrackEpsilon, splitval);
someToShift = true;
//wxLogDebug(wxT("Case 5"));
}
else if( beforeStart ) {
// Case 13:
//wxLogDebug(wxT("Case 13"));
}
else {
if(onPoint) { // Case 7: move the point L and insert a NEW one to the R
mEnv[pos].SetT(mEnv[pos].GetT() - mTrackEpsilon);
Insert(t0 + mTrackEpsilon, splitval);
someToShift = true;
//wxLogDebug(wxT("Case 7"));
}
else {
if( !beforeStart && !afterEnd ) {// Case 5: Insert points to L and R
Insert(t0 - mTrackEpsilon, splitval);
Insert(t0 + mTrackEpsilon, splitval);
someToShift = true;
//wxLogDebug(wxT("Case 5"));
}
else {
if( beforeStart ) { // Case 13:
//wxLogDebug(wxT("Case 13"));
}
else { // Case 12:
//wxLogDebug(wxT("Case 12"));
}
}
}
// Case 12:
//wxLogDebug(wxT("Case 12"));
}
}
@ -789,7 +791,8 @@ Old analysis of cases:
}
mTrackLen += deltat;
}
else { // Case 10:
else {
// Case 10:
if( mTrackLen == 0 ) // creating a NEW envelope
{
mTrackLen = e->mTrackLen;
@ -811,13 +814,13 @@ Old analysis of cases:
// calls for the start and end times will have no effect.
const double leftval = e->GetValue(0 + e->mOffset);
const double rightval = e->GetValue(e->mTrackLen + e->mOffset);
Insert(t0, leftval);
Insert(t0 + e->mTrackLen, rightval);
InsertOrReplaceRelative(t0, leftval);
InsertOrReplaceRelative(t0 + e->mTrackLen, rightval);
}
len = e->mEnv.size();
for (i = 0; i < len; i++)
Insert(t0 + e->mEnv[i].GetT(), e->mEnv[i].GetVal());
InsertOrReplaceRelative(t0 + e->mEnv[i].GetT(), e->mEnv[i].GetVal());
/* if(len != 0)
for (i = 0; i < mEnv.size(); i++)
@ -852,7 +855,7 @@ void Envelope::RemoveUnneededPoints(double time, double tolerence)
bool bExcludePoint = true;
if( fabs(val -val1) > tolerence )
{
Insert(when, val); // put it back, we needed it
InsertOrReplaceRelative(when, val); // put it back, we needed it
//Insert may have modified instead of inserting, if two points were at the same time.
// in which case len needs to shrink i and len, because the array size decreased.
@ -869,6 +872,8 @@ void Envelope::RemoveUnneededPoints(double time, double tolerence)
void Envelope::InsertSpace(double t0, double tlen)
// NOFAIL-GUARANTEE
{
t0 -= mOffset;
unsigned int len = mEnv.size();
unsigned int i;
@ -878,8 +883,10 @@ void Envelope::InsertSpace(double t0, double tlen)
mTrackLen += tlen;
}
int Envelope::Move(double when, double value)
int Envelope::Reassign(double when, double value)
{
when -= mOffset;
int len = mEnv.size();
if (len == 0)
return -1;
@ -910,7 +917,7 @@ void Envelope::GetPoints(double *bufferWhen,
n = bufferLen;
int i;
for (i = 0; i < n; i++) {
bufferWhen[i] = mEnv[i].GetT();
bufferWhen[i] = mEnv[i].GetT() - mOffset;
bufferValue[i] = mEnv[i].GetVal();
}
}
@ -932,20 +939,11 @@ void Envelope::GetPoints(double *bufferWhen,
/** @brief Add a control point to the envelope
*
* Control point positions start at zero and are measured in seconds from the
* start of the envelope. The position of the envelope on the project-wide
* time scale is store in seconds in Envelope::mOffset.
* This is worth remembering.
* If you call Envelope::Insert() from WaveClip, or anywhere else outside the
* Envelope class that is using project timing, subtract the envelope's mOffset
* from the time.
* If you call Envelope::Insert() from within Envelope, don't subtract mOffset
* because you are working in relative time inside the envelope
* @param when the time in seconds when the envelope point should be created.
* @param value the envelope value to use at the given point.
* @return the index of the NEW envelope point within array of envelope points.
*/
int Envelope::Insert(double when, double value)
int Envelope::InsertOrReplaceRelative(double when, double value)
{
#if defined(__WXDEBUG__)
// in debug builds, do a spot of argument checking
@ -998,6 +996,27 @@ int Envelope::Insert(double when, double value)
return i;
}
std::pair<int, int> Envelope::EqualRange( double when, double sampleTime ) const
{
// Find range of envelope points matching the given time coordinate
// (within an interval of length sampleTime)
// by binary search; if empty, it still indicates where to
// insert.
const auto tolerance = sampleTime / 2;
auto begin = mEnv.begin();
auto end = mEnv.end();
auto first = std::lower_bound(
begin, end,
EnvPoint{ const_cast<Envelope*>( this ), when - tolerance, 0.0 },
[]( const EnvPoint &point1, const EnvPoint &point2 )
{ return point1.GetT() < point2.GetT(); }
);
auto after = first;
while ( after != end && after->GetT() < when + tolerance )
++after;
return { first - begin, after - begin };
}
// Control
void Envelope::SetOffset(double newOffset)
@ -1019,6 +1038,21 @@ void Envelope::SetTrackLen(double trackLen)
}
}
void Envelope::RescaleTimes( double newLength )
// NOFAIL-GUARANTEE
{
if ( mTrackLen == 0 ) {
for ( auto &point : mEnv )
point.SetT( 0 );
}
else {
auto ratio = newLength / mTrackLen;
for ( auto &point : mEnv )
point.SetT( point.GetT() * ratio );
}
mTrackLen = newLength;
}
// Accessors
double Envelope::GetValue(double t) const
{
@ -1029,21 +1063,18 @@ double Envelope::GetValue(double t) const
return temp;
}
/// @param Lo returns last index at or before this time.
/// @param Hi returns first index after this time.
// relative time
/// @param Lo returns last index at or before this time, maybe -1
/// @param Hi returns first index after this time, maybe past the end
void Envelope::BinarySearchForTime( int &Lo, int &Hi, double t ) const
{
Lo = 0;
Hi = mEnv.size() - 1;
// JC: Do we have a problem if the envelope only has one point??
wxASSERT(Hi > Lo);
// Optimizations for the usual pattern of repeated calls with
// small increases of t.
{
if (mSearchGuess >= 0 && mSearchGuess < (int)(mEnv.size()) - 1) {
if (mSearchGuess >= 0 && mSearchGuess < mEnv.size()) {
if (t >= mEnv[mSearchGuess].GetT() &&
t < mEnv[1 + mSearchGuess].GetT()) {
(1 + mSearchGuess == mEnv.size() ||
t < mEnv[1 + mSearchGuess].GetT())) {
Lo = mSearchGuess;
Hi = 1 + mSearchGuess;
return;
@ -1051,9 +1082,10 @@ void Envelope::BinarySearchForTime( int &Lo, int &Hi, double t ) const
}
++mSearchGuess;
if (mSearchGuess >= 0 && mSearchGuess < (int)(mEnv.size()) - 1) {
if (mSearchGuess >= 0 && mSearchGuess < mEnv.size()) {
if (t >= mEnv[mSearchGuess].GetT() &&
t < mEnv[1 + mSearchGuess].GetT()) {
(1 + mSearchGuess == mEnv.size() ||
t < mEnv[1 + mSearchGuess].GetT())) {
Lo = mSearchGuess;
Hi = 1 + mSearchGuess;
return;
@ -1061,8 +1093,13 @@ void Envelope::BinarySearchForTime( int &Lo, int &Hi, double t ) const
}
}
Lo = -1;
Hi = mEnv.size();
// Invariants: Lo is not less than -1, Hi not more than size
while (Hi > (Lo + 1)) {
int mid = (Lo + Hi) / 2;
// mid must be strictly between Lo and Hi, therefore a valid index
if (t < mEnv[mid].GetT())
Hi = mid;
else
@ -1132,6 +1169,8 @@ void Envelope::GetValues(double *buffer, int bufferLen,
int lo,hi;
BinarySearchForTime( lo, hi, t );
// mEnv[0] is before t because of eliminations above, therefore lo >= 0
// mEnv[len - 1] is after t, therefore hi <= len - 1
tprev = mEnv[lo].GetT();
tnext = mEnv[hi].GetT();
@ -1180,39 +1219,24 @@ void Envelope::GetValues
buffer[xx] = GetValue(zoomInfo.PositionToTime(xx, -leftOffset));
}
// relative time
int Envelope::NumberOfPointsAfter(double t) const
{
if( t >= mEnv[mEnv.size()-1].GetT() )
return 0;
else if( t < mEnv[0].GetT() )
return mEnv.size();
else
{
int lo,hi;
BinarySearchForTime( lo, hi, t );
int lo,hi;
BinarySearchForTime( lo, hi, t );
if( mEnv[hi].GetT() == t )
return mEnv.size() - (hi+1);
else
return mEnv.size() - hi;
}
return mEnv.size() - hi;
}
// relative time
double Envelope::NextPointAfter(double t) const
{
if( mEnv[mEnv.size()-1].GetT() < t )
int lo,hi;
BinarySearchForTime( lo, hi, t );
if (hi >= mEnv.size())
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();
}
return mEnv[hi].GetT();
}
double Envelope::Average( double t0, double t1 ) const
@ -1327,6 +1351,9 @@ double Envelope::Integral( double t0, double t1 ) const
if(count == 0) // 'empty' envelope
return (t1 - t0) * mDefaultValue;
t0 -= mOffset;
t1 -= mOffset;
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
@ -1338,7 +1365,7 @@ double Envelope::Integral( double t0, double t1 ) const
lastVal = mEnv[0].GetVal();
total += (lastT - t0) * lastVal;
}
else if(t0 >= mEnv[count - 1].GetT()) // t0 following the last point
else if(t0 >= mEnv[count - 1].GetT()) // t0 at or following the last point
{
return (t1 - t0) * mEnv[count - 1].GetVal();
}
@ -1364,7 +1391,7 @@ double Envelope::Integral( double t0, double t1 ) const
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 + IntegrateInterpolated(lastVal, thisVal, t1 - lastT, mDB);
}
else // this point preceeds the end of the range
else // this point precedes the end of the range
{
total += IntegrateInterpolated(lastVal, mEnv[i].GetVal(), mEnv[i].GetT() - lastT, mDB);
lastT = mEnv[i].GetT();
@ -1387,6 +1414,9 @@ double Envelope::IntegralOfInverse( double t0, double t1 ) const
if(count == 0) // 'empty' envelope
return (t1 - t0) / mDefaultValue;
t0 -= mOffset;
t1 -= mOffset;
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
@ -1398,7 +1428,7 @@ double Envelope::IntegralOfInverse( double t0, double t1 ) const
lastVal = mEnv[0].GetVal();
total += (lastT - t0) / lastVal;
}
else if(t0 >= mEnv[count - 1].GetT()) // t0 following the last point
else if(t0 >= mEnv[count - 1].GetT()) // t0 at or following the last point
{
return (t1 - t0) / mEnv[count - 1].GetVal();
}
@ -1424,7 +1454,7 @@ double Envelope::IntegralOfInverse( double t0, double t1 ) const
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
else // this point precedes the end of the range
{
total += IntegrateInverseInterpolated(lastVal, mEnv[i].GetVal(), mEnv[i].GetT() - lastT, mDB);
lastT = mEnv[i].GetT();
@ -1443,93 +1473,98 @@ double Envelope::SolveIntegralOfInverse( double t0, double area ) const
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)
// Correct for offset!
t0 -= mOffset;
return mOffset + [&] {
// Now we can safely assume t0 is relative time!
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();
area -= added;
}
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)
else if(t0 >= mEnv[count - 1].GetT()) // t0 at or 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();
area -= added;
}
}
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 {
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
// loop through the rest of the envelope points until we get to t1
while (1)
{
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;
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++;
}
}
}
}
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::print() const
@ -1551,7 +1586,7 @@ void Envelope::testMe()
{
double t0=0, t1=0;
SetInterpolateDB(false);
SetExponential(false);
Flatten(0.5);
checkResult( 1, Integral(0.0,100.0), 50);
@ -1563,14 +1598,14 @@ void Envelope::testMe()
checkResult( 5, Integral(-20.0,-10.0), 5);
Flatten(0.5);
Insert( 5.0, 0.5 );
InsertOrReplaceRelative( 5.0, 0.5 );
checkResult( 6, Integral(0.0,100.0), 50);
checkResult( 7, Integral(-10.0,10.0), 10);
Flatten(0.0);
Insert( 0.0, 0.0 );
Insert( 5.0, 1.0 );
Insert( 10.0, 0.0 );
InsertOrReplaceRelative( 0.0, 0.0 );
InsertOrReplaceRelative( 5.0, 1.0 );
InsertOrReplaceRelative( 10.0, 0.0 );
t0 = 10.0 - .1;
t1 = 10.0 + .1;
double result = Integral(0.0,t1);
@ -1580,9 +1615,9 @@ void Envelope::testMe()
checkResult( 8, result - resulta - resultb, 0);
Flatten(0.0);
Insert( 0.0, 0.0 );
Insert( 5.0, 1.0 );
Insert( 10.0, 0.0 );
InsertOrReplaceRelative( 0.0, 0.0 );
InsertOrReplaceRelative( 5.0, 1.0 );
InsertOrReplaceRelative( 10.0, 0.0 );
t0 = 10.0 - .1;
t1 = 10.0 + .1;
checkResult( 9, Integral(0.0,t1), 5);
@ -1590,9 +1625,9 @@ void Envelope::testMe()
checkResult( 11, Integral(t0,t1), .001);
mEnv.clear();
Insert( 0.0, 0.0 );
Insert( 5.0, 1.0 );
Insert( 10.0, 0.0 );
InsertOrReplaceRelative( 0.0, 0.0 );
InsertOrReplaceRelative( 5.0, 1.0 );
InsertOrReplaceRelative( 10.0, 0.0 );
checkResult( 12, NumberOfPointsAfter( -1 ), 3 );
checkResult( 13, NumberOfPointsAfter( 0 ), 2 );
checkResult( 14, NumberOfPointsAfter( 1 ), 2 );

View File

@ -75,8 +75,15 @@ private:
typedef std::vector<EnvPoint> EnvArray;
class Envelope final : public XMLTagHandler {
public:
Envelope();
public:
// Envelope can define a piecewise linear function, or piecewise exponential.
Envelope(bool exponential, double minValue, double maxValue, double defaultValue);
Envelope(const Envelope &orig);
// Create from a subrange of another envelope.
Envelope(const Envelope &orig, double t0, double t1);
void Initialize(int numPoints);
virtual ~ Envelope();
@ -84,9 +91,8 @@ class Envelope final : public XMLTagHandler {
double GetOffset() const { return mOffset; }
double GetTrackLen() const { return mTrackLen; }
bool GetInterpolateDB() { return mDB; }
void SetInterpolateDB(bool db) { mDB = db; }
void Rescale(double minValue, double maxValue);
bool GetExponential() const { return mDB; }
void SetExponential(bool db) { mDB = db; }
void Flatten(double value);
@ -113,8 +119,6 @@ class Envelope final : public XMLTagHandler {
// Handling Cut/Copy/Paste events
void CollapseRegion(double t0, double t1);
// Takes absolute times, NOT offset-relative:
void CopyFrom(const Envelope * e, double t0, double t1);
void Paste(double t0, const Envelope *e);
void InsertSpace(double t0, double tlen);
void RemoveUnneededPoints(double time = -1, double tolerence = 0.001);
@ -122,6 +126,8 @@ class Envelope final : public XMLTagHandler {
// Control
void SetOffset(double newOffset);
void SetTrackLen(double trackLen);
void RescaleValues(double minValue, double maxValue);
void RescaleTimes( double newLength );
// Accessors
/** \brief Get envelope value at time t */
@ -138,9 +144,13 @@ class Envelope final : public XMLTagHandler {
void GetValues
(double *buffer, int bufferLen, int leftOffset, const ZoomInfo &zoomInfo) const;
private:
// relative time
int NumberOfPointsAfter(double t) const;
// relative time
double NextPointAfter(double t) const;
public:
double Average( double t0, double t1 ) const;
double AverageOfInverse( double t0, double t1 ) const;
double Integral( double t0, double t1 ) const;
@ -152,13 +162,14 @@ class Envelope final : public XMLTagHandler {
bool IsDirty() const;
/** \brief Add a point at a particular spot */
int Insert(double when, double value);
/** \brief Add a point at a particular absolute time coordinate */
int InsertOrReplace(double when, double value)
{ return InsertOrReplaceRelative( when - mOffset, value ); }
/** \brief Move a point at when to value
*
* Returns 0 if point moved, -1 if not found.*/
int Move(double when, double value);
int Reassign(double when, double value);
/** \brief DELETE a point by its position in array */
void Delete(int point);
@ -170,13 +181,16 @@ class Envelope final : public XMLTagHandler {
size_t GetNumberOfPoints() const;
private:
int InsertOrReplaceRelative(double when, double value);
friend class EnvelopeEditor;
/** \brief Accessor for points */
EnvPoint &operator[] (int index)
const EnvPoint &operator[] (int index) const
{
return mEnv[index];
}
std::pair<int, int> EqualRange( double when, double sampleTime ) const;
public:
/** \brief Returns the sets of when and value pairs */
void GetPoints(double *bufferWhen,
@ -193,47 +207,40 @@ public:
bool GetDragPointValid() const { return mDragPointValid; }
// Modify the dragged point and change its value.
// But consistency constraints may move it less then you ask for.
private:
void MoveDragPoint(double newWhen, double value);
// May delete the drag point. Restores envelope consistency.
void ClearDragPoint();
private:
EnvPoint * AddPointAtEnd( double t, double val );
void CopyRange(const Envelope &orig, size_t begin, size_t end);
// relative time
void BinarySearchForTime( int &Lo, int &Hi, double t ) const;
double GetInterpolationStartValueAtPoint( int iPoint ) const;
// Possibly inline functions:
// This function resets them integral memoizers (call whenever the Envelope changes)
void resetIntegralMemoizer() { lastIntegral_t0=0; lastIntegral_t1=0; lastIntegral_result=0; }
// The list of envelope control points.
EnvArray mEnv;
/** \brief The time at which the envelope starts, i.e. the start offset */
double mOffset;
double mOffset { 0.0 };
/** \brief The length of the envelope, which is the same as the length of the
* underlying track (normally) */
double mTrackLen;
double mTrackLen { 0.0 };
// TODO: mTrackEpsilon based on assumption of 200KHz. Needs review if/when
// we support higher sample rates.
/** \brief The shortest distance appart that points on an envelope can be
* before being considered the same point */
double mTrackEpsilon;
double mDefaultValue;
double mTrackEpsilon { 1.0 / 200000.0 };
bool mDB;
double mMinValue, mMaxValue;
// These are memoizing variables for Integral()
double lastIntegral_t0;
double lastIntegral_t1;
double lastIntegral_result;
double mDefaultValue;
// UI stuff
bool mDragPointValid;
int mDragPoint;
bool mDragPointValid { false };
int mDragPoint { -1 };
mutable int mSearchGuess;
mutable int mSearchGuess { -2 };
};
inline EnvPoint::EnvPoint(Envelope *envelope, double t, double val)

View File

@ -45,12 +45,9 @@ TimeTrack::TimeTrack(const std::shared_ptr<DirManager> &projDirManager, const Zo
mRangeUpper = 1.1;
mDisplayLog = false;
mEnvelope = std::make_unique<Envelope>();
mEnvelope = std::make_unique<Envelope>(true, TIMETRACK_MIN, TIMETRACK_MAX, 1.0);
mEnvelope->SetTrackLen(DBL_MAX);
mEnvelope->SetInterpolateDB(true);
mEnvelope->Flatten(1.0);
mEnvelope->SetOffset(0);
mEnvelope->SetRange(TIMETRACK_MIN, TIMETRACK_MAX);
SetDefaultName(_("Time Track"));
SetName(GetDefaultName());
@ -67,18 +64,12 @@ TimeTrack::TimeTrack(const TimeTrack &orig, double *pT0, double *pT1)
{
Init(orig); // this copies the TimeTrack metadata (name, range, etc)
///@TODO: Give Envelope:: a copy-constructor instead of this?
mEnvelope = std::make_unique<Envelope>();
mEnvelope->Flatten(1.0);
mEnvelope->SetTrackLen(DBL_MAX);
SetInterpolateLog(orig.GetInterpolateLog()); // this calls Envelope::SetInterpolateDB
mEnvelope->SetOffset(0);
mEnvelope->SetRange(orig.mEnvelope->GetMinValue(), orig.mEnvelope->GetMaxValue());
if ( pT0 && pT1 )
// restricted copy
mEnvelope->CopyFrom(orig.mEnvelope.get(), *pT0, *pT1);
if (pT0 && pT1)
mEnvelope = std::make_unique<Envelope>( *orig.mEnvelope, *pT0, *pT1 );
else
mEnvelope->Paste(0.0, orig.mEnvelope.get());
mEnvelope = std::make_unique<Envelope>( *orig.mEnvelope );
mEnvelope->SetTrackLen(DBL_MAX);
mEnvelope->SetOffset(0);
///@TODO: Give Ruler:: a copy-constructor instead of this?
mRuler = std::make_unique<Ruler>();
@ -145,11 +136,11 @@ Track::Holder TimeTrack::Duplicate() const
bool TimeTrack::GetInterpolateLog() const
{
return mEnvelope->GetInterpolateDB();
return mEnvelope->GetExponential();
}
void TimeTrack::SetInterpolateLog(bool interpolateLog) {
mEnvelope->SetInterpolateDB(interpolateLog);
mEnvelope->SetExponential(interpolateLog);
}
//Compute the (average) warp factor between two non-warped time points
@ -226,7 +217,7 @@ void TimeTrack::HandleXMLEndTag(const wxChar * WXUNUSED(tag))
if(mRescaleXMLValues)
{
mRescaleXMLValues = false;
mEnvelope->Rescale(mRangeLower, mRangeUpper);
mEnvelope->RescaleValues(mRangeLower, mRangeUpper);
mEnvelope->SetRange(TIMETRACK_MIN, TIMETRACK_MAX);
}
}
@ -308,10 +299,10 @@ void TimeTrack::Draw(wxDC & dc, const wxRect & r, const ZoomInfo &zoomInfo) cons
void TimeTrack::testMe()
{
GetEnvelope()->Flatten(0.0);
GetEnvelope()->Insert( 0.0, 0.2 );
GetEnvelope()->Insert( 5.0 - 0.001, 0.2 );
GetEnvelope()->Insert( 5.0 + 0.001, 1.3 );
GetEnvelope()->Insert( 10.0, 1.3 );
GetEnvelope()->InsertOrReplace(0.0, 0.2);
GetEnvelope()->InsertOrReplace(5.0 - 0.001, 0.2);
GetEnvelope()->InsertOrReplace(5.0 + 0.001, 1.3);
GetEnvelope()->InsertOrReplace(10.0, 1.3);
double value1 = GetEnvelope()->Integral(2.0, 13.0);
double expected1 = (5.0 - 2.0) * 0.2 + (13.0 - 5.0) * 1.3;

View File

@ -309,7 +309,7 @@ WaveClip::WaveClip(const std::shared_ptr<DirManager> &projDirManager,
mRate = rate;
mSequence = std::make_unique<Sequence>(projDirManager, format);
mEnvelope = std::make_unique<Envelope>();
mEnvelope = std::make_unique<Envelope>(true, 1e-7, 2.0, 1.0);
mWaveCache = std::make_unique<WaveCache>();
mSpecCache = std::make_unique<SpecCache>();
@ -328,10 +328,7 @@ WaveClip::WaveClip(const WaveClip& orig,
mRate = orig.mRate;
mSequence = std::make_unique<Sequence>(*orig.mSequence, projDirManager);
mEnvelope = std::make_unique<Envelope>();
mEnvelope->Paste(0.0, orig.mEnvelope.get());
mEnvelope->SetOffset(orig.GetOffset());
mEnvelope->SetTrackLen((orig.mSequence->GetNumSamples().as_double()) / orig.mRate);
mEnvelope = std::make_unique<Envelope>(*orig.mEnvelope);
mWaveCache = std::make_unique<WaveCache>();
mSpecCache = std::make_unique<SpecCache>();
@ -345,7 +342,6 @@ WaveClip::WaveClip(const WaveClip& orig,
mIsPlaceholder = orig.GetIsPlaceholder();
}
// to do
WaveClip::WaveClip(const WaveClip& orig,
const std::shared_ptr<DirManager> &projDirManager,
bool copyCutlines,
@ -369,10 +365,11 @@ WaveClip::WaveClip(const WaveClip& orig,
mSequence = orig.mSequence->Copy(s0, s1);
mEnvelope = std::make_unique<Envelope>();
mEnvelope->CopyFrom(orig.mEnvelope.get(),
mOffset + s0.as_double()/mRate,
mOffset + s1.as_double()/mRate);
mEnvelope = std::make_unique<Envelope>(
*orig.mEnvelope,
mOffset + s0.as_double()/mRate,
mOffset + s1.as_double()/mRate
);
if ( copyCutlines )
// Copy cutline clips that fall in the range
@ -1835,7 +1832,8 @@ void WaveClip::Unlock()
void WaveClip::SetRate(int rate)
{
mRate = rate;
UpdateEnvelopeTrackLen();
auto newLength = mSequence->GetNumSamples().as_double() / mRate;
mEnvelope->RescaleTimes( newLength );
MarkChanged();
}

View File

@ -394,9 +394,14 @@ double WaveTrack::GetRate() const
void WaveTrack::SetRate(double newRate)
{
wxASSERT( newRate > 0 );
newRate = std::max( 1.0, newRate );
auto ratio = mRate / newRate;
mRate = (int) newRate;
for (const auto &clip : mClips)
for (const auto &clip : mClips) {
clip->SetRate((int)newRate);
clip->SetOffset( clip->GetOffset() * ratio );
}
}
float WaveTrack::GetGain() const
@ -1145,13 +1150,13 @@ void WaveTrack::HandleClear(double t0, double t1,
if (clip->WithinClip(t0)) {
// start of region within clip
val = clip->GetEnvelope()->GetValue(t0);
newClip->GetEnvelope()->Insert(t0 - clip->GetOffset() - 1.0/clip->GetRate(), val);
}
if (clip->WithinClip(t1)) {
// end of region within clip
newClip->GetEnvelope()->InsertOrReplace(t0 - clip->GetOffset() - 1.0 / clip->GetRate(), val);
}
if (clip->WithinClip(t1))
{ // end of region within clip
val = clip->GetEnvelope()->GetValue(t1);
newClip->GetEnvelope()->Insert(t1 - clip->GetOffset(), val);
}
newClip->GetEnvelope()->InsertOrReplace(t1 - clip->GetOffset(), val);
}
}
newClip->Clear(t0,t1);
newClip->GetEnvelope()->RemoveUnneededPoints(t0);
@ -2393,8 +2398,8 @@ void WaveTrack::SplitAt(double t)
//make two envelope points to preserve the value.
//handle the case where we split on the 1st sample (without this we hit an assert)
if(t - 1.0/c->GetRate() >= c->GetOffset())
c->GetEnvelope()->Insert(t - c->GetOffset() - 1.0/c->GetRate(), val); // frame end points
c->GetEnvelope()->Insert(t - c->GetOffset(), val);
c->GetEnvelope()->InsertOrReplace(t - 1.0 / c->GetRate(), val); // frame end points
c->GetEnvelope()->InsertOrReplace(t, val);
auto newClip = make_movable<WaveClip>( *c, mDirManager, true );
c->Clear(t, c->GetEndTime());
newClip->Clear(c->GetStartTime(), t);

View File

@ -239,13 +239,15 @@ EffectEqualization::EffectEqualization()
mInterpolations.Add(wxGetTranslation(kInterpStrings[i]));
}
mLogEnvelope = std::make_unique<Envelope>();
mLogEnvelope->SetInterpolateDB(false);
mLogEnvelope->SetRange(MIN_dBMin, MAX_dBMax); // MB: this is the highest possible range
mLogEnvelope = std::make_unique<Envelope>
(false,
MIN_dBMin, MAX_dBMax, // MB: this is the highest possible range
1.0);
mLinEnvelope = std::make_unique<Envelope>();
mLinEnvelope->SetInterpolateDB(false);
mLinEnvelope->SetRange(MIN_dBMin, MAX_dBMax); // MB: this is the highest possible range
mLinEnvelope = std::make_unique<Envelope>
(false,
MIN_dBMin, MAX_dBMax, // MB: this is the highest possible range
1.0);
mEnvelope = (mLin ? mLinEnvelope : mLogEnvelope).get();
@ -1649,7 +1651,7 @@ void EffectEqualization::setCurve(int currentCurve)
when = (log10(std::max((double) loFreqI, when)) - loLog)/denom;
}
value = mCurves[currentCurve].points[0].dB;
env->Insert(std::min(1.0, std::max(0.0, when)), value);
env->InsertOrReplace(std::min(1.0, std::max(0.0, when)), value);
ForceRecalc();
return;
}
@ -1668,17 +1670,18 @@ void EffectEqualization::setCurve(int currentCurve)
when = mCurves[currentCurve].points[pointCount].Freq / mHiFreq;
value = mCurves[currentCurve].points[pointCount].dB;
if(when <= 1) {
env->Insert(when, value);
env->InsertOrReplace(when, value);
if (when == 1)
break;
}
else {
// There are more points at higher freqs, so interpolate next one then stop.
when = 1.0;
double lastF = mCurves[currentCurve].points[pointCount-1].Freq;
double nextF = mCurves[currentCurve].points[pointCount].Freq;
double lastDB = mCurves[currentCurve].points[pointCount-1].dB;
double nextDB = mCurves[currentCurve].points[pointCount].dB;
value = lastDB + ((nextDB - lastDB) * ((mHiFreq - lastF) / (nextF - lastF)));
env->Insert(when, value);
env->InsertOrReplace(when, value);
break;
}
}
@ -1700,7 +1703,7 @@ void EffectEqualization::setCurve(int currentCurve)
// All points below 20 Hz, so just use final point.
when = 0.0;
value = mCurves[currentCurve].points[numPoints-1].dB;
env->Insert(when, value);
env->InsertOrReplace(when, value);
ForceRecalc();
return;
}
@ -1715,7 +1718,7 @@ void EffectEqualization::setCurve(int currentCurve)
double nextDB = mCurves[currentCurve].points[firstAbove20Hz].dB;
when = 0.0;
value = nextDB - ((nextDB - prevDB) * ((nextF - loLog) / (nextF - prevF)));
env->Insert(when, value);
env->InsertOrReplace(when, value);
}
// Now get the rest.
@ -1727,7 +1730,7 @@ void EffectEqualization::setCurve(int currentCurve)
when = (flog - loLog)/denom;
value = mCurves[currentCurve].points[pointCount].dB;
if(when <= 1.0) {
env->Insert(when, value);
env->InsertOrReplace(when, value);
}
else {
// This looks weird when adjusting curve in Draw mode if
@ -1746,7 +1749,7 @@ void EffectEqualization::setCurve(int currentCurve)
double logLastF = log10(mCurves[currentCurve].points[pointCount-1].Freq);
double lastDB = mCurves[currentCurve].points[pointCount-1].dB;
value = lastDB + ((value - lastDB) * ((log10(mHiFreq) - logLastF) / (flog - logLastF)));
env->Insert(when, value);
env->InsertOrReplace(when, value);
break;
}
}
@ -2175,7 +2178,7 @@ void EffectEqualization::UpdateGraphic()
{
when = freq/mHiFreq;
value = mLinEnvelope->GetValue(when);
mLinEnvelope->Insert(when, value);
mLinEnvelope->InsertOrReplace(when, value);
}
EnvLinToLog();
@ -2247,14 +2250,14 @@ void EffectEqualization::EnvLogToLin(void)
mLinEnvelope->Flatten(0.);
mLinEnvelope->SetTrackLen(1.0);
mLogEnvelope->GetPoints( when.get(), value.get(), numPoints );
mLinEnvelope->Move(0., value[0]);
mLinEnvelope->Reassign(0., value[0]);
double loLog = log10(20.);
double hiLog = log10(mHiFreq);
double denom = hiLog - loLog;
for (size_t i = 0; i < numPoints; i++)
mLinEnvelope->Insert(pow( 10., ((when[i] * denom) + loLog))/mHiFreq , value[i]);
mLinEnvelope->Move(1., value[numPoints-1]);
mLinEnvelope->InsertOrReplace(pow( 10., ((when[i] * denom) + loLog))/mHiFreq , value[i]);
mLinEnvelope->Reassign(1., value[numPoints-1]);
}
void EffectEqualization::EnvLinToLog(void)
@ -2271,7 +2274,7 @@ void EffectEqualization::EnvLinToLog(void)
mLogEnvelope->Flatten(0.);
mLogEnvelope->SetTrackLen(1.0);
mLinEnvelope->GetPoints( when.get(), value.get(), numPoints );
mLogEnvelope->Move(0., value[0]);
mLogEnvelope->Reassign(0., value[0]);
double loLog = log10(20.);
double hiLog = log10(mHiFreq);
double denom = hiLog - loLog;
@ -2284,16 +2287,16 @@ void EffectEqualization::EnvLinToLog(void)
// Caution: on Linux, when when == 20, the log calulation rounds
// to just under zero, which causes an assert error.
double flog = (log10(when[i]*mHiFreq)-loLog)/denom;
mLogEnvelope->Insert(std::max(0.0, flog) , value[i]);
mLogEnvelope->InsertOrReplace(std::max(0.0, flog) , value[i]);
}
else
{ //get the first point as close as we can to the last point requested
changed = true;
double v = value[i];
mLogEnvelope->Insert(0., v);
mLogEnvelope->InsertOrReplace(0., v);
}
}
mLogEnvelope->Move(1., value[numPoints-1]);
mLogEnvelope->Reassign(1., value[numPoints - 1]);
if(changed)
EnvelopeUpdated(mLogEnvelope.get(), false);
@ -2308,12 +2311,7 @@ void EffectEqualization::ErrMin(void)
double correction = 1.6;
bool flag;
size_t j=0;
Envelope testEnvelope;
testEnvelope.SetInterpolateDB(false);
testEnvelope.SetRange(-120.0, 60.0);
testEnvelope.Flatten(0.);
testEnvelope.SetTrackLen(1.0);
testEnvelope.CopyFrom(mLogEnvelope.get(), 0.0, 1.0);
Envelope testEnvelope{ *mLogEnvelope };
for(size_t i = 0; i < NUM_PTS; i++)
vals[i] = testEnvelope.GetValue(mWhens[i]);
@ -2451,10 +2449,10 @@ void EffectEqualization::GraphicEQ(Envelope *env)
}
}
if(mWhens[i]<=0.)
env->Move( 0., value );
env->Insert( mWhens[i], value );
env->Reassign(0., value);
env->InsertOrReplace( mWhens[i], value );
}
env->Move( 1., value );
env->Reassign( 1., value );
break;
}
@ -2495,10 +2493,10 @@ void EffectEqualization::GraphicEQ(Envelope *env)
}
}
if(mWhens[i]<=0.)
env->Move( 0., value );
env->Insert( mWhens[i], value );
env->Reassign(0., value);
env->InsertOrReplace( mWhens[i], value );
}
env->Move( 1., value );
env->Reassign( 1., value );
break;
}
@ -2509,7 +2507,7 @@ void EffectEqualization::GraphicEQ(Envelope *env)
spline(mWhenSliders, mEQVals, mBandsInUse+1, y2);
for(double xf=0; xf<1.; xf+=1./NUM_PTS)
{
env->Insert(xf, splint(mWhenSliders, mEQVals, mBandsInUse+1, y2, xf));
env->InsertOrReplace(xf, splint(mWhenSliders, mEQVals, mBandsInUse+1, y2, xf));
}
break;
}
@ -2738,9 +2736,9 @@ void EffectEqualization::OnInvert(wxCommandEvent & WXUNUSED(event)) // Inverts a
for (size_t i = 0; i < numPoints; i++)
{
if(lin)
mLinEnvelope->Move(when[i] , -value[i]);
mLinEnvelope->Reassign(when[i] , -value[i]);
else
mLogEnvelope->Move(when[i] , -value[i]);
mLogEnvelope->Reassign(when[i] , -value[i]);
}
// copy it back to the other one (just in case)