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

This commit is contained in:
RichardAsh1981@gmail.com 2012-12-29 16:28:28 +00:00
parent 9e452d66e9
commit 2326bb8347
5 changed files with 187 additions and 172 deletions

View File

@ -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 );

View File

@ -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

View File

@ -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 );

View File

@ -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'"),

View File

@ -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;