mirror of
https://github.com/cookiengineer/audacity
synced 2025-05-05 14:18:53 +02:00
Public Envelope methods all take & return ABSOLUTE time values...
... rather than some of them being relative to the Envelope's offset. In case of the envelopes used in TimeTrack or Equalization, offset was always zero, so this doesn't matter, except to make the contract of the Envelope class more explicit and sensible in isolation. In case of InsertSpace at least, this does fix an obscure bug, which could only happen when you have a clip, with an envelope, that starts before zero, and you select a region overlapping that clip and some other clip, with a void between, and you use the Join command. Aren't you relieved that's fixed now?
This commit is contained in:
parent
9c683a4f19
commit
26c4d65bd4
229
src/Envelope.cpp
229
src/Envelope.cpp
@ -499,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.InsertOrReplace(when - mEnvelope.GetOffset(), newVal));
|
||||
mEnvelope.SetDragPoint(mEnvelope.InsertOrReplaceRelative(when - mEnvelope.GetOffset(), newVal));
|
||||
mDirty = true;
|
||||
}
|
||||
|
||||
@ -732,7 +732,7 @@ Old analysis of cases:
|
||||
//wxLogDebug(wxT("Case 1"));
|
||||
}
|
||||
else {
|
||||
InsertOrReplace(t0 + mTrackEpsilon, splitval); // Case 3: insert a point to maintain the envelope
|
||||
InsertOrReplaceRelative(t0 + mTrackEpsilon, splitval); // Case 3: insert a point to maintain the envelope
|
||||
someToShift = true;
|
||||
//wxLogDebug(wxT("Case 3"));
|
||||
}
|
||||
@ -744,21 +744,21 @@ Old analysis of cases:
|
||||
//wxLogDebug(wxT("Case 2"));
|
||||
}
|
||||
else { // Case 4:
|
||||
InsertOrReplace(t0 - mTrackEpsilon, splitval); // insert a point to maintain the envelope
|
||||
InsertOrReplaceRelative(t0 - mTrackEpsilon, splitval); // insert a point to maintain the envelope
|
||||
//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);
|
||||
InsertOrReplace(t0 + mTrackEpsilon, splitval);
|
||||
InsertOrReplaceRelative(t0 + mTrackEpsilon, splitval);
|
||||
someToShift = true;
|
||||
//wxLogDebug(wxT("Case 7"));
|
||||
}
|
||||
else {
|
||||
if( !beforeStart && !afterEnd ) {// Case 5: Insert points to L and R
|
||||
InsertOrReplace(t0 - mTrackEpsilon, splitval);
|
||||
InsertOrReplace(t0 + mTrackEpsilon, splitval);
|
||||
InsertOrReplaceRelative(t0 - mTrackEpsilon, splitval);
|
||||
InsertOrReplaceRelative(t0 + mTrackEpsilon, splitval);
|
||||
someToShift = true;
|
||||
//wxLogDebug(wxT("Case 5"));
|
||||
}
|
||||
@ -805,13 +805,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);
|
||||
InsertOrReplace(t0, leftval);
|
||||
InsertOrReplace(t0 + e->mTrackLen, rightval);
|
||||
InsertOrReplaceRelative(t0, leftval);
|
||||
InsertOrReplaceRelative(t0 + e->mTrackLen, rightval);
|
||||
}
|
||||
|
||||
len = e->mEnv.size();
|
||||
for (i = 0; i < len; i++)
|
||||
InsertOrReplace(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++)
|
||||
@ -846,7 +846,7 @@ void Envelope::RemoveUnneededPoints(double time, double tolerence)
|
||||
bool bExcludePoint = true;
|
||||
if( fabs(val -val1) > tolerence )
|
||||
{
|
||||
InsertOrReplace(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.
|
||||
@ -863,6 +863,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;
|
||||
|
||||
@ -874,6 +876,8 @@ void Envelope::InsertSpace(double t0, double tlen)
|
||||
|
||||
int Envelope::Reassign(double when, double value)
|
||||
{
|
||||
when -= mOffset;
|
||||
|
||||
int len = mEnv.size();
|
||||
if (len == 0)
|
||||
return -1;
|
||||
@ -904,7 +908,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();
|
||||
}
|
||||
}
|
||||
@ -926,20 +930,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::InsertOrReplace(double when, double value)
|
||||
int Envelope::InsertOrReplaceRelative(double when, double value)
|
||||
{
|
||||
#if defined(__WXDEBUG__)
|
||||
// in debug builds, do a spot of argument checking
|
||||
@ -1044,6 +1039,7 @@ double Envelope::GetValue(double t) const
|
||||
return temp;
|
||||
}
|
||||
|
||||
// relative time
|
||||
/// @param Lo returns last index at or before this time.
|
||||
/// @param Hi returns first index after this time.
|
||||
void Envelope::BinarySearchForTime( int &Lo, int &Hi, double t ) const
|
||||
@ -1195,6 +1191,7 @@ 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() )
|
||||
@ -1213,6 +1210,7 @@ int Envelope::NumberOfPointsAfter(double t) const
|
||||
}
|
||||
}
|
||||
|
||||
// relative time
|
||||
double Envelope::NextPointAfter(double t) const
|
||||
{
|
||||
if( mEnv[mEnv.size()-1].GetT() < t )
|
||||
@ -1342,6 +1340,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
|
||||
@ -1402,6 +1403,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
|
||||
@ -1458,93 +1462,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 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
|
||||
@ -1578,14 +1587,14 @@ void Envelope::testMe()
|
||||
checkResult( 5, Integral(-20.0,-10.0), 5);
|
||||
|
||||
Flatten(0.5);
|
||||
InsertOrReplace( 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);
|
||||
InsertOrReplace( 0.0, 0.0 );
|
||||
InsertOrReplace( 5.0, 1.0 );
|
||||
InsertOrReplace( 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);
|
||||
@ -1595,9 +1604,9 @@ void Envelope::testMe()
|
||||
checkResult( 8, result - resulta - resultb, 0);
|
||||
|
||||
Flatten(0.0);
|
||||
InsertOrReplace( 0.0, 0.0 );
|
||||
InsertOrReplace( 5.0, 1.0 );
|
||||
InsertOrReplace( 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);
|
||||
@ -1605,9 +1614,9 @@ void Envelope::testMe()
|
||||
checkResult( 11, Integral(t0,t1), .001);
|
||||
|
||||
mEnv.clear();
|
||||
InsertOrReplace( 0.0, 0.0 );
|
||||
InsertOrReplace( 5.0, 1.0 );
|
||||
InsertOrReplace( 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 );
|
||||
|
@ -143,9 +143,13 @@ public:
|
||||
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;
|
||||
@ -157,8 +161,9 @@ public:
|
||||
|
||||
bool IsDirty() const;
|
||||
|
||||
/** \brief Add a point at a particular spot */
|
||||
int InsertOrReplace(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
|
||||
*
|
||||
@ -175,6 +180,7 @@ public:
|
||||
size_t GetNumberOfPoints() const;
|
||||
|
||||
private:
|
||||
int InsertOrReplaceRelative(double when, double value);
|
||||
friend class EnvelopeEditor;
|
||||
/** \brief Accessor for points */
|
||||
const EnvPoint &operator[] (int index) const
|
||||
@ -200,13 +206,14 @@ 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;
|
||||
|
||||
|
@ -2393,8 +2393,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()->InsertOrReplace(t - c->GetOffset() - 1.0 / c->GetRate(), val); // frame end points
|
||||
c->GetEnvelope()->InsertOrReplace(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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user