Fix some assert error in EQ curves

Selected EQ curves in Draw mode should now retain their name
when they are selected.
This commit is contained in:
Steve Daulton 2016-03-08 21:38:13 +00:00
parent a856d1e3b0
commit 7d5e54e364
2 changed files with 146 additions and 68 deletions

View File

@ -517,6 +517,14 @@ bool EffectEqualization::Init()
} }
mHiFreq = rate / 2.0; mHiFreq = rate / 2.0;
// Unlikely, but better than crashing.
if (mHiFreq <= loFreqI) {
wxMessageBox( _("Track sample rate is too low for this effect."),
_("Effect Unavailable"),
wxOK | wxCENTRE);
return(false);
}
mLoFreq = loFreqI; mLoFreq = loFreqI;
mBandsInUse = 0; mBandsInUse = 0;
@ -1654,84 +1662,146 @@ void EffectEqualization::SaveCurves(const wxString &fileName)
void EffectEqualization::setCurve(int currentCurve) void EffectEqualization::setCurve(int currentCurve)
{ {
// Set current choice // Set current choice
Select( currentCurve ); Select(currentCurve);
wxASSERT( currentCurve < (int) mCurves.GetCount() ); wxASSERT( currentCurve < (int) mCurves.GetCount() );
bool changed = false;
if( mLin ) // linear freq mode? Envelope *env;
{ int numPoints = (int) mCurves[currentCurve].points.GetCount();
Envelope *env = mLinEnvelope;
env->Flatten(0.);
env->SetTrackLen(1.0);
if( mCurves[currentCurve].points.GetCount() ) if (mLin) { // linear freq mode
{ env = mLinEnvelope;
double when, value;
int i;
int nCurvePoints = mCurves[currentCurve].points.GetCount();
for(i=0;i<nCurvePoints;i++)
{
when = mCurves[currentCurve].points[i].Freq / mHiFreq;
value = mCurves[currentCurve].points[i].dB;
if(when <= 1)
env->Insert(when, value);
else
break;
}
if ( i != nCurvePoints) // there are more points at higher freqs
{
when = 1.; // set the RH end to the next highest point
value = mCurves[currentCurve].points[nCurvePoints-1].dB;
env->Insert(when, value);
changed = true;
}
}
} }
else else { // log freq mode
{ env = mLogEnvelope;
Envelope *env = mLogEnvelope; }
env->Flatten(0.); env->Flatten(0.);
env->SetTrackLen(1.0); env->SetTrackLen(1.0);
if( mCurves[currentCurve].points.GetCount() ) // Handle special case of no points.
{ if (numPoints == 0) {
double when, value; ForceRecalc();
double loLog = log10(20.); return;
}
double when, value;
// Handle special case 1 point.
if (numPoints == 1) {
// only one point, so ensure it is in range then return.
when = mCurves[currentCurve].points[0].Freq;
if (mLin) {
when = when / mHiFreq;
}
else { // log scale
// We don't go below loFreqI (20 Hz) in log view.
double loLog = log10((double)loFreqI);
double hiLog = log10(mHiFreq); double hiLog = log10(mHiFreq);
double denom = hiLog - loLog; double denom = hiLog - loLog;
int i; when = (log10(std::max((double) loFreqI, when)) - loLog)/denom;
int nCurvePoints = mCurves[currentCurve].points.GetCount(); }
value = mCurves[currentCurve].points[0].dB;
env->Insert(std::min(1.0, std::max(0.0, when)), value);
ForceRecalc();
return;
}
for(i=0;i<nCurvePoints;i++) // We have at least two points, so ensure they are in frequency order.
{ mCurves[currentCurve].points.Sort(SortCurvePoints);
double flog = log10(mCurves[currentCurve].points[i].Freq);
if( flog >= loLog ) if (mCurves[currentCurve].points[0].Freq < 0) {
{ // Corrupt or invalid curve, so bail.
when = (flog - loLog)/denom; ForceRecalc();
value = mCurves[currentCurve].points[i].dB; return;
if(when <= 1.) }
env->Insert(when, value);
else if(mLin) { // linear Hz scale
{ // we have a point beyond fs/2. Insert it so that env code can use it. for(int pointCount = 0; pointCount < numPoints; pointCount++) {
// but just this one, we have no use for the rest when = mCurves[currentCurve].points[pointCount].Freq / mHiFreq;
env->SetTrackLen(when); // can't Insert if the envelope isn't long enough value = mCurves[currentCurve].points[pointCount].dB;
env->Insert(when, value); if(when <= 1) {
break; env->Insert(when, value);
} }
} else {
else // There are more points at higher freqs, so interpolate next one then stop.
{ //get the first point as close as we can to the last point requested when = 1.0;
changed = true; double lastF = mCurves[currentCurve].points[pointCount-1].Freq;
//double f = mCurves[currentCurve].points[i].Freq; double nextF = mCurves[currentCurve].points[pointCount].Freq;
//double v = mCurves[currentCurve].points[i].dB; double lastDB = mCurves[currentCurve].points[pointCount-1].dB;
mLogEnvelope->Insert(0., mCurves[currentCurve].points[i].dB); double nextDB = mCurves[currentCurve].points[pointCount].dB;
} value = lastDB + ((nextDB - lastDB) * ((mHiFreq - lastF) / (nextF - lastF)));
env->Insert(when, value);
break;
}
}
}
else { // log Hz scale
double loLog = log10((double) loFreqI);
double hiLog = log10(mHiFreq);
double denom = hiLog - loLog;
int firstAbove20Hz;
// log scale EQ starts at 20 Hz (threshold of hearing).
// so find the first point (if any) above 20 Hz.
for (firstAbove20Hz = 0; firstAbove20Hz < numPoints; firstAbove20Hz++) {
if (mCurves[currentCurve].points[firstAbove20Hz].Freq > loFreqI)
break;
}
if (firstAbove20Hz == numPoints) {
// All points below 20 Hz, so just use final point.
when = 0.0;
value = mCurves[currentCurve].points[numPoints-1].dB;
env->Insert(when, value);
ForceRecalc();
return;
}
if (firstAbove20Hz > 0) {
// At least one point is before 20 Hz and there are more
// beyond 20 Hz, so interpolate the first
double prevF = mCurves[currentCurve].points[firstAbove20Hz-1].Freq;
prevF = log10(std::max(1.0, prevF)); // log zero is bad.
double prevDB = mCurves[currentCurve].points[firstAbove20Hz-1].dB;
double nextF = log10(mCurves[currentCurve].points[firstAbove20Hz].Freq);
double nextDB = mCurves[currentCurve].points[firstAbove20Hz].dB;
when = 0.0;
value = nextDB - ((nextDB - prevDB) * ((nextF - loLog) / (nextF - prevF)));
env->Insert(when, value);
}
// Now get the rest.
for(int pointCount = firstAbove20Hz; pointCount < numPoints; pointCount++)
{
double flog = log10(mCurves[currentCurve].points[pointCount].Freq);
wxASSERT(mCurves[currentCurve].points[pointCount].Freq >= loFreqI);
when = (flog - loLog)/denom;
value = mCurves[currentCurve].points[pointCount].dB;
if(when <= 1.0) {
env->Insert(when, value);
}
else {
// This looks weird when adjusting curve in Draw mode if
// there is a point off-screen.
/*
// we have a point beyond fs/2. Insert it so that env code can use it.
// but just this one, we have no use for the rest
env->SetTrackLen(when); // can't Insert if the envelope isn't long enough
env->Insert(when, value);
break;
*/
// interpolate the final point instead
when = 1.0;
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);
break;
} }
} }
} }
if(changed) // not all points were loaded so switch to unnamed
EnvelopeUpdated();
ForceRecalc(); ForceRecalc();
} }
@ -2272,7 +2342,10 @@ void EffectEqualization::EnvLinToLog(void)
{ {
if( when[i]*mHiFreq >= 20 ) if( when[i]*mHiFreq >= 20 )
{ {
mLogEnvelope->Insert((log10(when[i]*mHiFreq)-loLog)/denom , value[i]); // 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]);
} }
else else
{ //get the first point as close as we can to the last point requested { //get the first point as close as we can to the last point requested

View File

@ -266,6 +266,11 @@ private:
return (*first)->Name.CmpNoCase((*second)->Name); return (*first)->Name.CmpNoCase((*second)->Name);
} }
static int wxCMPFUNC_CONV SortCurvePoints (EQPoint **p0, EQPoint **p1)
{
return (*p0)->Freq > (*p1)->Freq;
}
#ifdef EXPERIMENTAL_EQ_SSE_THREADED #ifdef EXPERIMENTAL_EQ_SSE_THREADED
wxRadioButton *mMathProcessingType[5]; // default, sse, sse threaded, AVX, AVX threaded (note AVX is not implemented yet wxRadioButton *mMathProcessingType[5]; // default, sse, sse threaded, AVX, AVX threaded (note AVX is not implemented yet
wxBoxSizer *szrM; wxBoxSizer *szrM;