audacia/src/NumberScale.h

284 lines
6.1 KiB
C++

/**********************************************************************
Audacity: A Digital Audio Editor
NumberScale.h
Paul Licameli
**********************************************************************/
#ifndef __AUDACITY_NUMBER_SCALE__
#define __AUDACITY_NUMBER_SCALE__
#include <algorithm>
#include <cmath>
#include <wx/defs.h>
enum NumberScaleType {
nstLinear,
nstLogarithmic,
nstMel,
nstBark,
nstErb,
nstPeriod,
nstNumScaleTypes,
nstNone,
};
class NumberScale
{
public:
NumberScale()
: mType(nstNone), mValue0(0), mValue1(1)
{}
NumberScale(NumberScaleType type, float value0, float value1)
: mType(type)
{
switch (mType) {
case nstLinear:
case nstNone:
{
mValue0 = value0;
mValue1 = value1;
}
break;
case nstLogarithmic:
{
mValue0 = logf(value0);
mValue1 = logf(value1);
}
break;
case nstMel:
{
mValue0 = hzToMel(value0);
mValue1 = hzToMel(value1);
}
break;
case nstBark:
{
mValue0 = hzToBark(value0);
mValue1 = hzToBark(value1);
}
break;
case nstErb:
{
mValue0 = hzToErb(value0);
mValue1 = hzToErb(value1);
}
break;
case nstPeriod:
{
mValue0 = hzToPeriod(value0);
mValue1 = hzToPeriod(value1);
}
break;
default:
wxASSERT(false);
}
}
NumberScale Reversal() const
{
NumberScale result(*this);
std::swap(result.mValue0, result.mValue1);
return result;
}
bool operator == (const NumberScale& other) const
{
return mType == other.mType
&& mValue0 == other.mValue0
&& mValue1 == other.mValue1;
}
bool operator != (const NumberScale &other) const
{
return !(*this == other);
}
static inline float hzToMel(float hz)
{
return 1127 * log(1 + hz / 700);
}
static inline float melToHz(float mel)
{
return 700 * (exp(mel / 1127) - 1);
}
static inline float hzToBark(float hz)
{
// Traunmueller's formula
const float z1 = 26.81 * hz / (1960 + hz) - 0.53;
if (z1 < 2.0)
return z1 + 0.15 * (2.0 - z1);
else if (z1 > 20.1)
return z1 + 0.22 * (z1 - 20.1);
else
return z1;
}
static inline float barkToHz(float z1)
{
if (z1 < 2.0)
z1 = 2.0 + (z1 - 2.0) / 0.85;
else if (z1 > 20.1)
z1 = 20.1 + (z1 - 20.1) / 1.22;
return 1960 * (z1 + 0.53) / (26.28 - z1);
}
static inline float hzToErb(float hz)
{
return 11.17268 * log(1 + (46.06538 * hz) / (hz + 14678.49));
}
static inline float erbToHz(float erb)
{
return 676170.4 / (47.06538 - exp(0.08950404 * erb)) - 14678.49;
}
static inline float hzToPeriod(float hz)
{
return -1.0 / std::max (1.0f, hz);
}
static inline float periodToHz(float u)
{
return -1.0 / u;
}
// Random access
float PositionToValue(float pp) const
{
switch (mType) {
default:
wxASSERT(false);
case nstLinear:
case nstNone:
return mValue0 + pp * (mValue1 - mValue0);
case nstLogarithmic:
return exp(mValue0 + pp * (mValue1 - mValue0));
case nstMel:
return melToHz(mValue0 + pp * (mValue1 - mValue0));
case nstBark:
return barkToHz(mValue0 + pp * (mValue1 - mValue0));
case nstErb:
return erbToHz(mValue0 + pp * (mValue1 - mValue0));
case nstPeriod:
return periodToHz(mValue0 + pp * (mValue1 - mValue0));
}
}
// STL-idiom iteration
class Iterator
{
public:
Iterator(NumberScaleType type, float step, float value)
: mType(type), mStep(step), mValue(value)
{
}
float operator * () const
{
switch (mType) {
default:
wxASSERT(false);
case nstLinear:
case nstNone:
case nstLogarithmic:
return mValue;
case nstMel:
return melToHz(mValue);
case nstBark:
return barkToHz(mValue);
case nstErb:
return erbToHz(mValue);
case nstPeriod:
return periodToHz(mValue);
}
}
Iterator &operator ++()
{
switch (mType) {
case nstLinear:
case nstNone:
case nstMel:
case nstBark:
case nstErb:
case nstPeriod:
mValue += mStep;
break;
case nstLogarithmic:
mValue *= mStep;
break;
default:
wxASSERT(false);
}
return *this;
}
private:
const NumberScaleType mType;
const float mStep;
float mValue;
};
Iterator begin(float nPositions) const
{
switch (mType) {
default:
wxASSERT(false);
case nstLinear:
case nstNone:
case nstMel:
case nstBark:
case nstErb:
case nstPeriod:
return Iterator
(mType,
nPositions == 1 ? 0 : (mValue1 - mValue0) / (nPositions - 1),
mValue0);
case nstLogarithmic:
return Iterator
(mType,
nPositions == 1 ? 1 : exp((mValue1 - mValue0) / (nPositions - 1)),
exp(mValue0));
}
}
// Inverse
float ValueToPosition(float val) const
{
switch (mType) {
default:
wxASSERT(false);
case nstLinear:
case nstNone:
return ((val - mValue0) / (mValue1 - mValue0));
case nstLogarithmic:
return ((log(val) - mValue0) / (mValue1 - mValue0));
case nstMel:
return ((hzToMel(val) - mValue0) / (mValue1 - mValue0));
case nstBark:
return ((hzToBark(val) - mValue0) / (mValue1 - mValue0));
case nstErb:
return ((hzToErb(val) - mValue0) / (mValue1 - mValue0));
case nstPeriod:
return ((hzToPeriod(val) - mValue0) / (mValue1 - mValue0));
}
}
private:
NumberScaleType mType;
float mValue0;
float mValue1;
};
#endif