From 2326bb834760012479c514bcc304bfcdc974ac82 Mon Sep 17 00:00:00 2001 From: "RichardAsh1981@gmail.com" Date: Sat, 29 Dec 2012 16:28:28 +0000 Subject: [PATCH] Commit most of patch-envelope-range-2.patch from Maarten Baert, excluding an unrelated change and some independent ones already committed. There is an outstanding potential issue with the TimeTrack:: copy constructor awaiting further input --- src/Envelope.cpp | 279 +++++++++++++++++------------------ src/Envelope.h | 60 +++++--- src/TimeTrack.cpp | 5 +- src/TrackPanel.cpp | 11 +- src/effects/Equalization.cpp | 4 +- 5 files changed, 187 insertions(+), 172 deletions(-) diff --git a/src/Envelope.cpp b/src/Envelope.cpp index 77b709498..15bb88bab 100644 --- a/src/Envelope.cpp +++ b/src/Envelope.cpp @@ -60,6 +60,9 @@ Envelope::Envelope() mDirty = false; mIsDeleting = false; mMirror = true; + + mMinValue = 1.0e-7; + mMaxValue = 2.0; mButton = wxMOUSE_BTN_NONE; } @@ -81,7 +84,15 @@ void Envelope::Mirror(bool mirror) void Envelope::Flatten(double value) { WX_CLEAR_ARRAY(mEnv); - SetDefaultValue(value); + mDefaultValue = ClampValue(value); +} + +void Envelope::SetRange(double minValue, double maxValue) { + mMinValue = minValue; + mMaxValue = maxValue; + mDefaultValue = ClampValue(mDefaultValue); + for( unsigned int i = 0; i < mEnv.Count(); i++ ) + mEnv[i]->SetVal(mEnv[i]->GetVal()); // this clamps the value to the new range } EnvPoint * Envelope::AddPointAtEnd( double t, double val ) @@ -90,9 +101,7 @@ EnvPoint * Envelope::AddPointAtEnd( double t, double val ) // TODO: switch over to using an array of EnvPoints // rather than an array of pointers to EnvPoints. // What value does that add? - EnvPoint *pt = new EnvPoint(); - pt->t = t; - pt->val = val; + EnvPoint *pt = new EnvPoint(this, t, val); mEnv.Add(pt); return pt; } @@ -109,7 +118,7 @@ void Envelope::CopyFrom(const Envelope *e, double t0, double t1) int i = 0; // Skip the points that come before the copied region - while( (i < len) && e->mOffset + e->mEnv[i]->t <= t0) + while( (i < len) && e->mOffset + e->mEnv[i]->GetT() <= t0) i++; // Create the point at 0 if it needs interpolated representation @@ -117,8 +126,8 @@ void Envelope::CopyFrom(const Envelope *e, double t0, double t1) AddPointAtEnd( 0, e->GetValue(mOffset) ); // Copy points from inside the copied region - while ( (i < len) && e->mOffset + e->mEnv[i]->t - mOffset < mTrackLen) { - AddPointAtEnd( e->mOffset + e->mEnv[i]->t - mOffset, e->mEnv[i]->val ); + while ( (i < len) && e->mOffset + e->mEnv[i]->GetT() - mOffset < mTrackLen) { + AddPointAtEnd( e->mOffset + e->mEnv[i]->GetT() - mOffset, e->mEnv[i]->GetVal() ); i++; } @@ -190,15 +199,15 @@ void Envelope::DrawPoints(wxDC & dc, const wxRect & r, double h, double pps, boo dc.SetBrush(*wxWHITE_BRUSH); for (int i = 0; i < (int)mEnv.Count(); i++) { - if (mEnv[i]->t >= h && mEnv[i]->t <= tright) { + if (mEnv[i]->GetT() >= h && mEnv[i]->GetT() <= tright) { // Change colour if this is the draggable point... if (i == mDragPoint) { dc.SetPen(AColor::envelopePen); dc.SetBrush(AColor::envelopeBrush); } - double v = mEnv[i]->val; - int x = int ((mEnv[i]->t - h) * pps); + double v = mEnv[i]->GetVal(); + int x = int ((mEnv[i]->GetT() - h) * pps); int y, y2; y = GetWaveYPos(v, zoomMin, zoomMax, r.height, dB, @@ -286,8 +295,8 @@ void Envelope::WriteXML(XMLWriter &xmlFile) for (ctrlPt = 0; ctrlPt < mEnv.GetCount(); ctrlPt++) { xmlFile.StartTag(wxT("controlpoint")); - xmlFile.WriteAttr(wxT("t"), mEnv[ctrlPt]->t, 12); - xmlFile.WriteAttr(wxT("val"), mEnv[ctrlPt]->val, 12); + xmlFile.WriteAttr(wxT("t"), mEnv[ctrlPt]->GetT(), 12); + xmlFile.WriteAttr(wxT("val"), mEnv[ctrlPt]->GetVal(), 12); xmlFile.EndTag(wxT("controlpoint")); } @@ -305,10 +314,8 @@ void Envelope::WriteXML(XMLWriter &xmlFile) /// @dB - display mode either linear or log. /// @zoomMin - vertical scale, typically -1.0 /// @zoomMax - vertical scale, typically +1.0 -/// @eMin - clips result to this range. -/// @eMax - clips result to this range. float Envelope::ValueOfPixel( int y, int height, bool upper, bool dB, - float zoomMin, float zoomMax, float eMin, float eMax ) + float zoomMin, float zoomMax) { float v; @@ -324,22 +331,12 @@ float Envelope::ValueOfPixel( int y, int height, bool upper, bool dB, if (dB) v = fromDB(v); - // JC: The eMin/eMax code originally assumed a symmetrical range. - // so only eMin was needed. I'm very dubious about the lower curve - // behaviour and expect some funny behaviour when dragging - // the lower curve when we have asymmetric ranges. - - // Upper curve: gets clamped between eMin and eMax. Looks OK. - // Lower curve: reset to eMin if > 0 otherwise made positive and <=eMax. - if ((upper && v < eMin) || (!upper && v > 0)) - v = eMin; - else if (!upper) - v = -v; - - if(v > eMax) - v = eMax; - - return v; + // MB: this is mostly equivalent to what the old code did, I'm not sure + // if anything special is needed for asymmetric ranges + if(upper) + return ClampValue(v); + else + return ClampValue(-v); } /// HandleMouseButtonDown either finds an existing control point or adds a new one @@ -350,10 +347,10 @@ float Envelope::ValueOfPixel( int y, int height, bool upper, bool dB, /// Also we may be showing an inner envelope (at 0.5 the range). bool Envelope::HandleMouseButtonDown(wxMouseEvent & event, wxRect & r, double h, double pps, bool dB, - float zoomMin, float zoomMax, float eMin, float eMax) + float zoomMin, float zoomMax) { int ctr = (int)(r.height * zoomMax / (zoomMax - zoomMin)); - bool upper = (zoomMin == eMin) || (event.m_y - r.y < ctr); + bool upper = !mMirror || (zoomMin >= 0.0) || (event.m_y - r.y < ctr); int clip_y = event.m_y - r.y; if(clip_y < 0) clip_y = 0; //keeps point in rect r, even if mouse isn't @@ -378,22 +375,22 @@ bool Envelope::HandleMouseButtonDown(wxMouseEvent & event, wxRect & r, // TODO: extract this into a function FindNearestControlPoint() // TODO: also fix it so that we can drag the last point on an envelope. for (int i = 0; i < len; i++) { //search for control point nearest click - if (mEnv[i]->t >= tleft && mEnv[i]->t <= tright) { + if (mEnv[i]->GetT() >= tleft && mEnv[i]->GetT() <= tright) { - int x = int ((mEnv[i]->t + mOffset - h) * pps) + r.x; + int x = int ((mEnv[i]->GetT() + mOffset - h) * pps) + r.x; int y[4]; int numControlPoints; // Outer control points - y[0] = GetWaveYPos( mEnv[i]->val, zoomMin, zoomMax, r.height, + y[0] = GetWaveYPos( mEnv[i]->GetVal(), zoomMin, zoomMax, r.height, dB, true, dBr, false); - y[1] = GetWaveYPos( -mEnv[i]->val, zoomMin, zoomMax, r.height, + y[1] = GetWaveYPos( -mEnv[i]->GetVal(), zoomMin, zoomMax, r.height, dB, true, dBr, false); // Inner control points(contour) - y[2] = GetWaveYPos( mEnv[i]->val, zoomMin, zoomMax, r.height, + y[2] = GetWaveYPos( mEnv[i]->GetVal(), zoomMin, zoomMax, r.height, dB, false, dBr, false); - y[3] = GetWaveYPos( -mEnv[i]->val-.00000001, zoomMin, zoomMax, + y[3] = GetWaveYPos( -mEnv[i]->GetVal()-.00000001, zoomMin, zoomMax, r.height, dB, false, dBr, false); numControlPoints = 4; @@ -450,7 +447,7 @@ bool Envelope::HandleMouseButtonDown(wxMouseEvent & event, wxRect & r, } double newVal = ValueOfPixel(clip_y, r.height, upper, dB, - zoomMin, zoomMax, eMin, eMax); + zoomMin, zoomMax); mDragPoint = Insert(when, newVal); mDirty = true; @@ -458,8 +455,8 @@ bool Envelope::HandleMouseButtonDown(wxMouseEvent & event, wxRect & r, mUpper = upper; - mInitialWhen = mEnv[mDragPoint]->t; - mInitialVal = mEnv[mDragPoint]->val; + mInitialWhen = mEnv[mDragPoint]->GetT(); + mInitialVal = mEnv[mDragPoint]->GetVal(); mInitialX = event.m_x; mInitialY = event.m_y+mContourOffset; @@ -484,26 +481,26 @@ void Envelope::MarkDragPointForDeletion() // There is only one point - just move it // off screen and at default height. // temporary state when dragging only! - mEnv[mDragPoint]->t = -1000000.0; - mEnv[mDragPoint]->val = mDefaultValue; + mEnv[mDragPoint]->SetT(-1000000.0); + mEnv[mDragPoint]->SetVal(mDefaultValue); return; } // Place it exactly on one of its neighbours. int iNeighbourPoint = mDragPoint + ((mDragPoint > 0) ? -1:+1); - mEnv[mDragPoint]->t = mEnv[iNeighbourPoint]->t; - mEnv[mDragPoint]->val = mEnv[iNeighbourPoint]->val; + mEnv[mDragPoint]->SetT(mEnv[iNeighbourPoint]->GetT()); + mEnv[mDragPoint]->SetVal(mEnv[iNeighbourPoint]->GetVal()); } void Envelope::MoveDraggedPoint( wxMouseEvent & event, wxRect & r, double h, double pps, bool dB, - float zoomMin, float zoomMax, float eMin, float eMax) + float zoomMin, float zoomMax) { int clip_y = event.m_y - r.y; if(clip_y < 0) clip_y = 0; if(clip_y > r.height) clip_y = r.height; double newVal = ValueOfPixel(clip_y, r.height, mUpper, dB, - zoomMin, zoomMax, eMin, eMax); + zoomMin, zoomMax); wxASSERT( pps > 0 ); // We no longer tolerate multiple envelope points at the same t. @@ -519,15 +516,15 @@ void Envelope::MoveDraggedPoint( wxMouseEvent & event, wxRect & r, double limitHi = mTrackLen; if (mDragPoint > 0) - limitLo = mEnv[mDragPoint - 1]->t + mTrackEpsilon; + limitLo = mEnv[mDragPoint - 1]->GetT() + mTrackEpsilon; if (mDragPoint < (int)mEnv.Count() - 1 ) - limitHi = mEnv[mDragPoint + 1]->t - mTrackEpsilon; + limitHi = mEnv[mDragPoint + 1]->GetT() - mTrackEpsilon; newWhen = Limit( limitLo, newWhen, limitHi ); newWhen = Limit( mTrackEpsilon, newWhen, mTrackLen - mTrackEpsilon); - mEnv[mDragPoint]->t = newWhen; - mEnv[mDragPoint]->val = newVal; + mEnv[mDragPoint]->SetT(newWhen); + mEnv[mDragPoint]->SetVal(newVal); } @@ -545,7 +542,7 @@ bool Envelope::HandleDragging( wxMouseEvent & event, wxRect & r, // IF we're in the rect THEN we're not deleting this point (anymore). mIsDeleting = false; // ...we're dragging it. - MoveDraggedPoint( event, r,h,pps,dB, zoomMin, zoomMax, eMin, eMax ); + MoveDraggedPoint( event, r,h,pps,dB, zoomMin, zoomMax); return true; } @@ -580,14 +577,14 @@ void Envelope::Delete( int point ) // Returns true if parent needs to be redrawn bool Envelope::MouseEvent(wxMouseEvent & event, wxRect & r, double h, double pps, bool dB, - float zoomMin, float zoomMax, float eMin, float eMax) + float zoomMin, float zoomMax) { if (event.ButtonDown() && mButton == wxMOUSE_BTN_NONE) return HandleMouseButtonDown( event, r, h, pps,dB, - zoomMin, zoomMax, eMin, eMax); + zoomMin, zoomMax); if (event.Dragging() && mDragPoint >= 0) return HandleDragging( event, r, h, pps,dB, - zoomMin, zoomMax, eMin, eMax); + zoomMin, zoomMax); if (event.ButtonUp() && event.GetButton() == mButton) return HandleMouseButtonUp( event, r, h, pps, dB, zoomMin, zoomMax); @@ -611,7 +608,7 @@ void Envelope::CollapseRegion(double t0, double t1) // Remove points in deleted region. for (i = 0; i < len - 0; i++) - if (mEnv[i]->t >= t0 && mEnv[i]->t < t1) { + if (mEnv[i]->GetT() >= t0 && mEnv[i]->GetT() < t1) { delete mEnv[i]; mEnv.RemoveAt(i); len--; @@ -620,8 +617,8 @@ void Envelope::CollapseRegion(double t0, double t1) // Shift points left after deleted region. for (i = 0; i < len; i++) - if (mEnv[i]->t >= t1) - mEnv[i]->t -= (t1 - t0); + if (mEnv[i]->GetT() >= t1) + mEnv[i]->SetT(mEnv[i]->GetT() - (t1 - t0)); mTrackLen -= (t1-t0); } @@ -716,11 +713,11 @@ Old analysis of cases: // See if existing points need shifting to the right, and what Case we are in for (i = 0; i < len; i++) { - if (mEnv[i]->t > t0) + if (mEnv[i]->GetT() > t0) someToShift = true; else { pos = i; // last point not moved - if ( fabs(mEnv[i]->t - t0) - 1/500000.0 < 0.0 ) // close enough to a point + if ( fabs(mEnv[i]->GetT() - t0) - 1/500000.0 < 0.0 ) // close enough to a point onPoint = true; } } @@ -738,7 +735,7 @@ Old analysis of cases: // 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]->t +=mTrackEpsilon; // Case 1: move it R slightly to avoid duplicate point + mEnv[0]->SetT(mEnv[0]->GetT() + mTrackEpsilon); // Case 1: move it R slightly to avoid duplicate point someToShift = true; // there is now, even if there wasn't before //wxLogDebug(wxT("Case 1")); } @@ -751,7 +748,7 @@ Old analysis of cases: else { if(atEnd) { // insertion at the end if(onPoint) { // last env point is at RH end, Case 2: - mEnv[0]->t -= mTrackEpsilon; // move it L slightly to avoid duplicate point + mEnv[0]->SetT(mEnv[0]->GetT() - mTrackEpsilon); // move it L slightly to avoid duplicate point //wxLogDebug(wxT("Case 2")); } else { // Case 4: @@ -761,7 +758,7 @@ Old analysis of cases: } else { if(onPoint) { // Case 7: move the point L and insert a new one to the R - mEnv[pos]->t -= mTrackEpsilon; + mEnv[pos]->SetT(mEnv[pos]->GetT() - mTrackEpsilon); Insert(t0 + mTrackEpsilon, splitval); someToShift = true; //wxLogDebug(wxT("Case 7")); @@ -789,8 +786,8 @@ Old analysis of cases: if(someToShift) { len = mEnv.Count(); // it may well have changed for (i = 0; i < len; i++) - if (mEnv[i]->t > t0) - mEnv[i]->t += deltat; + if (mEnv[i]->GetT() > t0) + mEnv[i]->SetT(mEnv[i]->GetT() + deltat); } mTrackLen += deltat; } @@ -811,11 +808,11 @@ Old analysis of cases: // Copy points from inside the selection len = e->mEnv.Count(); for (i = 0; i < len; i++) - pos=Insert(t0 + e->mEnv[i]->t, e->mEnv[i]->val); + pos=Insert(t0 + e->mEnv[i]->GetT(), e->mEnv[i]->GetVal()); /* if(len != 0) for (i = 0; i < mEnv.Count(); i++) - wxLogDebug(wxT("Fixed i %d when %.18f val %f"),i,mEnv[i]->t,mEnv[i]->val); */ + wxLogDebug(wxT("Fixed i %d when %.18f val %f"),i,mEnv[i]->GetT(),mEnv[i]->GetVal()); */ if(pointsAdded) while(e->mEnv.Count() != 0) @@ -837,13 +834,13 @@ void Envelope::RemoveUnneededPoints(double time, double tolerence) return; for (i = 0; i < len; i++) { - when = mEnv[i]->t; + when = mEnv[i]->GetT(); if(time >= 0) { if(fabs(when + mOffset - time) > 0.00025) // 2 samples at 8kHz, 11 at 44.1kHz continue; } - val = mEnv[i]->val; + val = mEnv[i]->GetVal(); Delete(i); // try it to see if it's doing anything val1 = GetValue(when + mOffset); bool bExcludePoint = true; @@ -869,8 +866,8 @@ void Envelope::InsertSpace(double t0, double tlen) unsigned int i; for (i = 0; i < len; i++) - if (mEnv[i]->t > t0) - mEnv[i]->t += tlen; + if (mEnv[i]->GetT() > t0) + mEnv[i]->SetT(mEnv[i]->GetT() + tlen); mTrackLen += tlen; } @@ -881,13 +878,13 @@ int Envelope::Move(double when, double value) return -1; int i = 0; - while (i < len && when > mEnv[i]->t) + while (i < len && when > mEnv[i]->GetT()) i++; - if (i >= len || when < mEnv[i]->t) + if (i >= len || when < mEnv[i]->GetT()) return -1; - mEnv[i]->val = value; + mEnv[i]->SetVal(value); return 0; } @@ -906,8 +903,8 @@ void Envelope::GetPoints(double *bufferWhen, n = bufferLen; int i; for (i = 0; i < n; i++) { - bufferWhen[i] = mEnv[i]->t; - bufferValue[i] = mEnv[i]->val; + bufferWhen[i] = mEnv[i]->GetT(); + bufferValue[i] = mEnv[i]->GetVal(); } } @@ -973,21 +970,19 @@ int Envelope::Insert(double when, double value) int i = 0; - while (i < len && when > mEnv[i]->t) + while (i < len && when > mEnv[i]->GetT()) i++; - if(i < len && when == mEnv[i]->t) { + if(i < len && when == mEnv[i]->GetT()) { // modify existing - mEnv[i]->val = value; + mEnv[i]->SetVal(value); } else{ // Add new - EnvPoint *e = new EnvPoint(); - e->t = when; - e->val = value; + EnvPoint *e = new EnvPoint(this, when, value); if (i < len) { mEnv.Insert(e, i); } else { @@ -1010,7 +1005,7 @@ void Envelope::SetTrackLen(double trackLen) int len = mEnv.Count(); for (int i = 0; i < len; i++) - if (mEnv[i]->t > mTrackLen) { + if (mEnv[i]->GetT() > mTrackLen) { delete mEnv[i]; mEnv.RemoveAt(i); len--; @@ -1045,7 +1040,7 @@ void Envelope::BinarySearchForTime( int &Lo, int &Hi, double t ) const wxASSERT( Hi > Lo ); while (Hi > (Lo + 1)) { int mid = (Lo + Hi) / 2; - if (t < mEnv[mid]->t) + if (t < mEnv[mid]->GetT()) Hi = mid; else Lo = mid; @@ -1060,8 +1055,7 @@ void Envelope::BinarySearchForTime( int &Lo, int &Hi, double t ) const /// @return value there, or its (safe) log10. double Envelope::GetInterpolationStartValueAtPoint( int iPoint ) const { - //TODO-MB: make minimum value adjustable and apply this consistently - double v = std::max(1.0e-7, mEnv[ iPoint ]->val); + double v = mEnv[ iPoint ]->GetVal(); if( !mDB ) return v; else @@ -1091,14 +1085,14 @@ void Envelope::GetValues(double *buffer, int bufferLen, continue; } // IF before envelope THEN first value - if (t <= mEnv[0]->t) { - buffer[b] = mEnv[0]->val; + if (t <= mEnv[0]->GetT()) { + buffer[b] = mEnv[0]->GetVal(); t += tstep; continue; } // IF after envelope THEN last value - if (t >= mEnv[len - 1]->t) { - buffer[b] = mEnv[len - 1]->val; + if (t >= mEnv[len - 1]->GetT()) { + buffer[b] = mEnv[len - 1]->GetVal(); t += tstep; continue; } @@ -1112,8 +1106,8 @@ void Envelope::GetValues(double *buffer, int bufferLen, int lo,hi; BinarySearchForTime( lo, hi, t ); - tprev = mEnv[lo]->t; - tnext = mEnv[hi]->t; + tprev = mEnv[lo]->GetT(); + tnext = mEnv[hi]->GetT(); vprev = GetInterpolationStartValueAtPoint( lo ); vnext = GetInterpolationStartValueAtPoint( hi ); @@ -1155,16 +1149,16 @@ void Envelope::GetValues(double *buffer, int bufferLen, int Envelope::NumberOfPointsAfter(double t) { - if( t >= mEnv[mEnv.Count()-1]->t ) + if( t >= mEnv[mEnv.Count()-1]->GetT() ) return 0; - else if( t < mEnv[0]->t ) + else if( t < mEnv[0]->GetT() ) return mEnv.Count(); else { int lo,hi; BinarySearchForTime( lo, hi, t ); - if( mEnv[hi]->t == t ) + if( mEnv[hi]->GetT() == t ) return mEnv.Count() - (hi+1); else return mEnv.Count() - hi; @@ -1173,18 +1167,18 @@ int Envelope::NumberOfPointsAfter(double t) double Envelope::NextPointAfter(double t) { - if( mEnv[mEnv.Count()-1]->t < t ) + if( mEnv[mEnv.Count()-1]->GetT() < t ) return t; - else if( t < mEnv[0]->t ) - return mEnv[0]->t; + else if( t < mEnv[0]->GetT() ) + return mEnv[0]->GetT(); else { int lo,hi; BinarySearchForTime( lo, hi, t ); - if( mEnv[hi]->t == t ) - return mEnv[hi+1]->t; + if( mEnv[hi]->GetT() == t ) + return mEnv[hi+1]->GetT(); else - return mEnv[hi]->t; + return mEnv[hi]->GetT(); } } @@ -1302,25 +1296,25 @@ double Envelope::Integral( double t0, double t1 ) double total = 0.0, lastT, lastVal; unsigned int i; // this is the next point to check - if(t0 < mEnv[0]->t) // t0 preceding the first point + if(t0 < mEnv[0]->GetT()) // t0 preceding the first point { - if(t1 <= mEnv[0]->t) - return (t1 - t0) * mEnv[0]->val; + if(t1 <= mEnv[0]->GetT()) + return (t1 - t0) * mEnv[0]->GetVal(); i = 1; - lastT = mEnv[0]->t; - lastVal = mEnv[0]->val; + lastT = mEnv[0]->GetT(); + lastVal = mEnv[0]->GetVal(); total += (lastT - t0) * lastVal; } - else if(t0 >= mEnv[count - 1]->t) // t0 following the last point + else if(t0 >= mEnv[count - 1]->GetT()) // t0 following the last point { - return (t1 - t0) * mEnv[count - 1]->val; + 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]->val, mEnv[hi]->val, (t0 - mEnv[lo]->t) / (mEnv[hi]->t - mEnv[lo]->t), mDB); + 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. } @@ -1332,16 +1326,16 @@ double Envelope::Integral( double t0, double t1 ) { return total + (t1 - lastT) * lastVal; } - else if(mEnv[i]->t >= t1) // this point follows the end of the range + else if(mEnv[i]->GetT() >= t1) // this point follows the end of the range { - double thisVal = InterpolatePoints(mEnv[i - 1]->val, mEnv[i]->val, (t1 - mEnv[i - 1]->t) / (mEnv[i]->t - mEnv[i - 1]->t), mDB); + 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 { - total += IntegrateInterpolated(lastVal, mEnv[i]->val, mEnv[i]->t - lastT, mDB); - lastT = mEnv[i]->t; - lastVal = mEnv[i]->val; + total += IntegrateInterpolated(lastVal, mEnv[i]->GetVal(), mEnv[i]->GetT() - lastT, mDB); + lastT = mEnv[i]->GetT(); + lastVal = mEnv[i]->GetVal(); i++; } } @@ -1362,25 +1356,25 @@ double Envelope::IntegralOfInverse( double t0, double t1 ) double total = 0.0, lastT, lastVal; unsigned int i; // this is the next point to check - if(t0 < mEnv[0]->t) // t0 preceding the first point + if(t0 < mEnv[0]->GetT()) // t0 preceding the first point { - if(t1 <= mEnv[0]->t) - return (t1 - t0) / mEnv[0]->val; + if(t1 <= mEnv[0]->GetT()) + return (t1 - t0) / mEnv[0]->GetVal(); i = 1; - lastT = mEnv[0]->t; - lastVal = mEnv[0]->val; + lastT = mEnv[0]->GetT(); + lastVal = mEnv[0]->GetVal(); total += (lastT - t0) / lastVal; } - else if(t0 >= mEnv[count - 1]->t) // t0 following the last point + else if(t0 >= mEnv[count - 1]->GetT()) // t0 following the last point { - return (t1 - t0) / mEnv[count - 1]->val; + 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]->val, mEnv[hi]->val, (t0 - mEnv[lo]->t) / (mEnv[hi]->t - mEnv[lo]->t), mDB); + 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. } @@ -1392,16 +1386,16 @@ double Envelope::IntegralOfInverse( double t0, double t1 ) { return total + (t1 - lastT) / lastVal; } - else if(mEnv[i]->t >= t1) // this point follows the end of the range + else if(mEnv[i]->GetT() >= t1) // this point follows the end of the range { - double thisVal = InterpolatePoints(mEnv[i - 1]->val, mEnv[i]->val, (t1 - mEnv[i - 1]->t) / (mEnv[i]->t - mEnv[i - 1]->t), mDB); + 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]->val, mEnv[i]->t - lastT, mDB); - lastT = mEnv[i]->t; - lastVal = mEnv[i]->val; + total += IntegrateInverseInterpolated(lastVal, mEnv[i]->GetVal(), mEnv[i]->GetT() - lastT, mDB); + lastT = mEnv[i]->GetT(); + lastVal = mEnv[i]->GetVal(); i++; } } @@ -1423,26 +1417,26 @@ double Envelope::SolveIntegralOfInverse( double t0, double area ) double lastT, lastVal; unsigned int i; // this is the next point to check - if(t0 < mEnv[0]->t) // t0 preceding the first point + if(t0 < mEnv[0]->GetT()) // t0 preceding the first point { i = 1; - lastT = mEnv[0]->t; - lastVal = mEnv[0]->val; + lastT = mEnv[0]->GetT(); + lastVal = mEnv[0]->GetVal(); double added = (lastT - t0) / lastVal; if(added >= area) - return t0 + area * mEnv[0]->val; + return t0 + area * mEnv[0]->GetVal(); area -= added; } - else if(t0 >= mEnv[count - 1]->t) // t0 following the last point + else if(t0 >= mEnv[count - 1]->GetT()) // t0 following the last point { - return t0 + area * mEnv[count - 1]->val; + 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]->val, mEnv[hi]->val, (t0 - mEnv[lo]->t) / (mEnv[hi]->t - mEnv[lo]->t), mDB); + 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. } @@ -1456,12 +1450,12 @@ double Envelope::SolveIntegralOfInverse( double t0, double area ) } else { - double added = IntegrateInverseInterpolated(lastVal, mEnv[i]->val, mEnv[i]->t - lastT, mDB); + double added = IntegrateInverseInterpolated(lastVal, mEnv[i]->GetVal(), mEnv[i]->GetT() - lastT, mDB); if(added >= area) - return lastT + SolveIntegrateInverseInterpolated(lastVal, mEnv[i]->val, mEnv[i]->t - lastT, area, mDB); + return lastT + SolveIntegrateInverseInterpolated(lastVal, mEnv[i]->GetVal(), mEnv[i]->GetT() - lastT, area, mDB); area -= added; - lastT = mEnv[i]->t; - lastVal = mEnv[i]->val; + lastT = mEnv[i]->GetT(); + lastVal = mEnv[i]->GetVal(); i++; } } @@ -1470,7 +1464,7 @@ double Envelope::SolveIntegralOfInverse( double t0, double area ) void Envelope::print() { for( unsigned int i = 0; i < mEnv.Count(); i++ ) - printf( "(%.2f, %.2f)\n", mEnv[i]->t, mEnv[i]->val ); + printf( "(%.2f, %.2f)\n", mEnv[i]->GetT(), mEnv[i]->GetVal() ); } void checkResult( int n, double a, double b ) @@ -1489,24 +1483,20 @@ void Envelope::testMe() SetInterpolateDB(false); Mirror(false); - SetDefaultValue(0.5); Flatten(0.5); checkResult( 1, Integral(0.0,100.0), 50); checkResult( 2, Integral(-10.0,10.0), 10); - SetDefaultValue(1.0); Flatten(0.5); checkResult( 3, Integral(0.0,100.0), 50); checkResult( 4, Integral(-10.0,10.0), 10); checkResult( 5, Integral(-20.0,-10.0), 5); - SetDefaultValue(0.5); Flatten(0.5); Insert( 5.0, 0.5 ); checkResult( 6, Integral(0.0,100.0), 50); checkResult( 7, Integral(-10.0,10.0), 10); - SetDefaultValue(0.5); Flatten(0.0); Insert( 0.0, 0.0 ); Insert( 5.0, 1.0 ); @@ -1519,7 +1509,6 @@ void Envelope::testMe() // Integrals should be additive checkResult( 8, result - resulta - resultb, 0); - SetDefaultValue(0.5); Flatten(0.0); Insert( 0.0, 0.0 ); Insert( 5.0, 1.0 ); diff --git a/src/Envelope.h b/src/Envelope.h index a3126570b..410289eb4 100644 --- a/src/Envelope.h +++ b/src/Envelope.h @@ -27,12 +27,26 @@ class wxMouseEvent; class wxTextFile; class DirManager; +class Envelope; #define ENV_DB_RANGE 60 -struct EnvPoint : public XMLTagHandler { - double t; - double val; +class EnvPoint : public XMLTagHandler { + +public: + EnvPoint(Envelope *envelope, double t, double val) + { + mEnvelope = envelope; + mT = t; + mVal = ClampValue(val); + } + + double ClampValue(double val); // this calls mEnvelope->ClampValue(), implementation is below the Envelope class + + double GetT() { return mT; } + void SetT(double t) { mT = t; } + double GetVal() { return mVal; } + void SetVal(double val) { mVal = ClampValue(val); } bool HandleXMLTag(const wxChar *tag, const wxChar **attrs) { @@ -41,9 +55,9 @@ struct EnvPoint : public XMLTagHandler { const wxChar *attr = *attrs++; const wxChar *value = *attrs++; if (!wxStrcmp(attr, wxT("t"))) - t = Internat::CompatibleToDouble(value); + SetT(Internat::CompatibleToDouble(value)); else if (!wxStrcmp(attr, wxT("val"))) - val = Internat::CompatibleToDouble(value); + SetVal(Internat::CompatibleToDouble(value)); } return true; } @@ -56,15 +70,11 @@ struct EnvPoint : public XMLTagHandler { return NULL; } - void WriteXML(XMLWriter &xmlFile) - { - // FIX-ME: Is this ever called, vs the loop in Envelope::WriteXML()? - wxASSERT(false); - //xmlFile.StartTag(wxT("controlpoint")); - //xmlFile.WriteAttr(wxT("t"), t, 8); - //xmlFile.WriteAttr(wxT("val"), val); - //xmlFile.EndTag(wxT("controlpoint")); - } +private: + Envelope *mEnvelope; + double mT; + double mVal; + }; // TODO: Become an array of EnvPoint rather than of pointers to. @@ -86,8 +96,13 @@ class Envelope : public XMLTagHandler { void Mirror(bool mirror); void Flatten(double value); - void SetDefaultValue(double value) {mDefaultValue=value;} int GetDragPoint(void) {return mDragPoint;} + + double GetMinValue() { return mMinValue; } + double GetMaxValue() { return mMaxValue; } + void SetRange(double minValue, double maxValue); + + double ClampValue(double value) { return std::max(mMinValue, std::min(mMaxValue, value)); } #if LEGACY_PROJECT_FILE_SUPPORT // File I/O @@ -107,10 +122,10 @@ class Envelope : public XMLTagHandler { // Each ofthese returns true if parents needs to be redrawn bool MouseEvent(wxMouseEvent & event, wxRect & r, double h, double pps, bool dB, - float zoomMin=-1.0, float zoomMax=1.0, float eMin=0., float eMax=2.); + float zoomMin=-1.0, float zoomMax=1.0); bool HandleMouseButtonDown( wxMouseEvent & event, wxRect & r, double h, double pps, bool dB, - float zoomMin=-1.0, float zoomMax=1.0, float eMin=0., float eMax=2.); + float zoomMin=-1.0, float zoomMax=1.0); bool HandleDragging( wxMouseEvent & event, wxRect & r, double h, double pps, bool dB, float zoomMin=-1.0, float zoomMax=1.0, float eMin=0., float eMax=2.); @@ -183,12 +198,12 @@ private: EnvPoint * AddPointAtEnd( double t, double val ); void MarkDragPointForDeletion(); float ValueOfPixel( int y, int height, bool upper, bool dB, - float zoomMin, float zoomMax, float eMin=-10000. , float eMax=10000.); + float zoomMin, float zoomMax); void BinarySearchForTime( int &Lo, int &Hi, double t ) const; double GetInterpolationStartValueAtPoint( int iPoint ) const; void MoveDraggedPoint( wxMouseEvent & event, wxRect & r, double h, double pps, bool dB, - float zoomMin, float zoomMax, float eMin, float eMax); + float zoomMin, float zoomMax); // Possibly inline functions: // This function resets them integral memoizers (call whenever the Envelope changes) @@ -225,6 +240,8 @@ private: int mButton; bool mDB; bool mDirty; + + double mMinValue, mMaxValue; // These are memoizing variables for Integral() double lastIntegral_t0; @@ -233,5 +250,10 @@ private: }; +inline double EnvPoint::ClampValue(double val) +{ + return mEnvelope->ClampValue(val); +} + #endif diff --git a/src/TimeTrack.cpp b/src/TimeTrack.cpp index dbb8c1155..552952cc8 100644 --- a/src/TimeTrack.cpp +++ b/src/TimeTrack.cpp @@ -43,6 +43,7 @@ TimeTrack::TimeTrack(DirManager *projDirManager): mEnvelope->Flatten(1.0); mEnvelope->Mirror(false); mEnvelope->SetOffset(0); + mEnvelope->SetRange(0.1, 10.0); //TODO-MB: are these sensible values? SetDefaultName(_("Time Track")); SetName(GetDefaultName()); @@ -65,8 +66,9 @@ TimeTrack::TimeTrack(TimeTrack &orig): SetInterpolateLog(orig.GetInterpolateLog()); // this calls Envelope::SetInterpolateDB mEnvelope->Flatten(1.0); mEnvelope->Mirror(false); - mEnvelope->Paste(0.0, orig.mEnvelope); mEnvelope->SetOffset(0); + mEnvelope->SetRange(0.1, 10.0); + mEnvelope->Paste(0.0, orig.mEnvelope); mRuler = new Ruler(); mRuler->SetLabelEdges(false); @@ -260,7 +262,6 @@ void TimeTrack::Draw(wxDC & dc, const wxRect & r, double h, double pps) void TimeTrack::testMe() { - GetEnvelope()->SetDefaultValue(0.5); GetEnvelope()->Flatten(0.0); GetEnvelope()->Insert( 0.0, 0.2 ); GetEnvelope()->Insert( 5.0 - 0.001, 0.2 ); diff --git a/src/TrackPanel.cpp b/src/TrackPanel.cpp index 6445d6941..a3dd6a478 100644 --- a/src/TrackPanel.cpp +++ b/src/TrackPanel.cpp @@ -7394,22 +7394,23 @@ void TrackPanel::OnSetTimeTrackRange(wxCommandEvent & /*event*/) long lower = (long) (t->GetRangeLower() * 100.0 + 0.5); long upper = (long) (t->GetRangeUpper() * 100.0 + 0.5); + // MB: these lower/upper limits match the maximum allowed range of the time track + // envelope, but this is not strictly required lower = wxGetNumberFromUser(_("Change lower speed limit (%) to:"), _("Lower speed limit"), _("Lower speed limit"), lower, - 13, - 1200); + 10, + 1000); upper = wxGetNumberFromUser(_("Change upper speed limit (%) to:"), _("Upper speed limit"), _("Upper speed limit"), upper, lower+1, - 1200); + 1000); - //TODO-MB: what's the meaning of these values? - if( lower >= 13 && upper <= 1200 && lower < upper ) { + if( lower >= 10 && upper <= 1000 && lower < upper ) { t->SetRangeLower((double)lower / 100.0); t->SetRangeUpper((double)upper / 100.0); MakeParentPushState(wxString::Format(_("Set range to '%d' - '%d'"), diff --git a/src/effects/Equalization.cpp b/src/effects/Equalization.cpp index 0e8c81e38..9968746f3 100644 --- a/src/effects/Equalization.cpp +++ b/src/effects/Equalization.cpp @@ -830,7 +830,7 @@ void EqualizationPanel::OnMouseEvent(wxMouseEvent & event) } if (mEnvelope->MouseEvent(event, mEnvRect, 0.0, mEnvRect.width, false, - dBMin, dBMax, dBMin, dBMax)) + dBMin, dBMax)) { mParent->EnvelopeUpdated(); RecalcRequired = true; @@ -918,10 +918,12 @@ EqualizationDialog::EqualizationDialog(EffectEqualization * effect, mLogEnvelope = new Envelope(); mLogEnvelope->SetInterpolateDB(false); mLogEnvelope->Mirror(false); + mLogEnvelope->SetRange(-120.0, 60.0); // MB: this is the highest possible range mLinEnvelope = new Envelope(); mLinEnvelope->SetInterpolateDB(false); mLinEnvelope->Mirror(false); + mLinEnvelope->SetRange(-120.0, 60.0); // MB: this is the highest possible range mLoFreq = loFreq; mHiFreq = hiFreq;