mirror of
https://github.com/cookiengineer/audacity
synced 2025-05-03 00:59:43 +02:00
278 lines
5.9 KiB
C++
278 lines
5.9 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>
|
|
#include <wx/debug.h>
|
|
|
|
enum NumberScaleType {
|
|
nstLinear,
|
|
nstLogarithmic,
|
|
nstMel,
|
|
nstBark,
|
|
nstErb,
|
|
nstPeriod,
|
|
|
|
nstNumScaleTypes,
|
|
};
|
|
|
|
|
|
class NumberScale
|
|
{
|
|
public:
|
|
NumberScale()
|
|
: mType(nstLinear), mValue0(0), mValue1(1)
|
|
{}
|
|
|
|
NumberScale(NumberScaleType type, float value0, float value1)
|
|
: mType(type)
|
|
{
|
|
switch (mType) {
|
|
case nstLinear:
|
|
{
|
|
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:
|
|
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 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 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 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:
|
|
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
|