1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-07-31 16:09:28 +02:00

Other spectrogram scales, easily defined!! -- and include bug fixes 1038, 1039

This commit is contained in:
Paul Licameli 2015-06-16 14:10:21 -04:00
parent 9b9ceab6ab
commit 846c5d454e
5 changed files with 158 additions and 11 deletions

View File

@ -19,6 +19,10 @@ Paul Licameli
enum NumberScaleType {
nstLinear,
nstLogarithmic,
nstMel,
nstBark,
nstErb,
nstUndertone,
nstNumScaleTypes,
};
@ -46,6 +50,34 @@ public:
mUnit = 1.0;
}
break;
case nstMel:
{
mValue0 = hzToMel(value0);
mValue1 = hzToMel(value1);
mUnit = unit;
}
break;
case nstBark:
{
mValue0 = hzToBark(value0);
mValue1 = hzToBark(value1);
mUnit = unit;
}
break;
case nstErb:
{
mValue0 = hzToErb(value0);
mValue1 = hzToErb(value1);
mUnit = unit;
}
break;
case nstUndertone:
{
mValue0 = hzToUndertone(value0);
mValue1 = hzToUndertone(value1);
mUnit = unit;
}
break;
default:
wxASSERT(false);
}
@ -71,6 +103,57 @@ public:
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 hzToUndertone(float hz)
{
return -1.0 / std::max (1.0f, hz);
}
static inline float undertoneToHz(float u)
{
return -1.0 / u;
}
// Random access
float PositionToValue(float pp) const
{
@ -81,6 +164,14 @@ public:
return mValue0 + pp * (mValue1 - mValue0);
case nstLogarithmic:
return exp(mValue0 + pp * (mValue1 - mValue0));
case nstMel:
return melToHz(mValue0 + pp * (mValue1 - mValue0)) / mUnit;
case nstBark:
return barkToHz(mValue0 + pp * (mValue1 - mValue0)) / mUnit;
case nstErb:
return erbToHz(mValue0 + pp * (mValue1 - mValue0)) / mUnit;
case nstUndertone:
return undertoneToHz(mValue0 + pp * (mValue1 - mValue0)) / mUnit;
}
}
@ -102,6 +193,14 @@ public:
case nstLinear:
case nstLogarithmic:
return mValue;
case nstMel:
return melToHz(mValue) / mUnit;
case nstBark:
return barkToHz(mValue) / mUnit;
case nstErb:
return erbToHz(mValue) / mUnit;
case nstUndertone:
return undertoneToHz(mValue) / mUnit;
}
}
@ -109,6 +208,10 @@ public:
{
switch (mType) {
case nstLinear:
case nstMel:
case nstBark:
case nstErb:
case nstUndertone:
mValue += mStep;
break;
case nstLogarithmic:
@ -133,6 +236,10 @@ public:
default:
wxASSERT(false);
case nstLinear:
case nstMel:
case nstBark:
case nstErb:
case nstUndertone:
return Iterator
(mType, (mValue1 - mValue0) / nPositions, mValue0, mUnit);
case nstLogarithmic:
@ -151,6 +258,14 @@ public:
return ((val - mValue0) / (mValue1 - mValue0));
case nstLogarithmic:
return ((log(val) - mValue0) / (mValue1 - mValue0));
case nstMel:
return ((hzToMel(val * mUnit) - mValue0) / (mValue1 - mValue0));
case nstBark:
return ((hzToBark(val * mUnit) - mValue0) / (mValue1 - mValue0));
case nstErb:
return ((hzToErb(val * mUnit) - mValue0) / (mValue1 - mValue0));
case nstUndertone:
return ((hzToUndertone(val * mUnit) - mValue0) / (mValue1 - mValue0));
}
}

View File

@ -830,6 +830,10 @@ void TrackArtist::UpdateVRuler(Track *t, wxRect & rect)
}
break;
case SpectrogramSettings::stLogarithmic:
case SpectrogramSettings::stMel:
case SpectrogramSettings::stBark:
case SpectrogramSettings::stErb:
case SpectrogramSettings::stUndertone:
{
// SpectrumLog

View File

@ -161,6 +161,10 @@ const wxArrayString &SpectrogramSettings::GetScaleNames()
// Keep in correspondence with enum SpectrogramSettings::ScaleType:
theArray.Add(_("Linear"));
theArray.Add(_("Logarithmic"));
theArray.Add(_("Mel"));
theArray.Add(_("Bark"));
theArray.Add(_("Erb"));
theArray.Add(_("Undertone"));
}
return theArray;
@ -529,6 +533,7 @@ NumberScale SpectrogramSettings::GetScale
{
int minFreq, maxFreq;
NumberScaleType type = nstLinear;
const int half = GetFFTLength(autocorrelation) / 2;
// Don't assume the correspondence of the enums will remain direct in the future.
// Do this switch.
@ -539,6 +544,14 @@ NumberScale SpectrogramSettings::GetScale
type = nstLinear; break;
case stLogarithmic:
type = nstLogarithmic; break;
case stMel:
type = nstMel; break;
case stBark:
type = nstBark; break;
case stErb:
type = nstErb; break;
case stUndertone:
type = nstUndertone; break;
}
switch (scaleType) {
@ -549,12 +562,20 @@ NumberScale SpectrogramSettings::GetScale
maxFreq = GetMaxFreq(rate);
break;
case stLogarithmic:
case stMel:
case stBark:
case stErb:
minFreq = GetLogMinFreq(rate);
maxFreq = GetLogMaxFreq(rate);
break;
case stUndertone:
{
const float bin2 = rate / half;
minFreq = std::max(int(0.5 + bin2), GetLogMinFreq(rate));
maxFreq = GetLogMaxFreq(rate);
}
break;
}
const int half = GetFFTLength(autocorrelation) / 2;
return NumberScale(type, minFreq, maxFreq,
bins ? rate / (2 * half) : 1.0f);

View File

@ -54,6 +54,10 @@ public:
enum ScaleType {
stLinear,
stLogarithmic,
stMel,
stBark,
stErb,
stUndertone,
stNumScaleTypes,
};

View File

@ -1192,7 +1192,7 @@ void Ruler::Update(TimeTrack* timetrack)// Envelope *speedEnv, long minSpeed, lo
: NumberScale(nstLogarithmic, mMin, mMax, 1.0f)
);
mDigits=2; //TODO: implement dynamic digit computation
mDigits=2; //TODO: implement dynamic digit computation
double loLog = log10(mMin);
double hiLog = log10(mMax);
int loDecade = (int) floor(loLog);
@ -1208,7 +1208,7 @@ void Ruler::Update(TimeTrack* timetrack)// Envelope *speedEnv, long minSpeed, lo
for(i=0; i<=steps; i++)
{ // if(i!=0)
{ val = decade;
if(val > rMin && val < rMax) {
if(val >= rMin && val < rMax) {
const int pos(0.5 + mLength * numberScale.ValueToPosition(val));
Tick(pos, val, true, false);
}
@ -1244,13 +1244,16 @@ void Ruler::Update(TimeTrack* timetrack)// Envelope *speedEnv, long minSpeed, lo
{ start=100; end= 10; mstep=-1;
}
steps++;
for(i=0; i<=steps; i++) {
for(int f=start; f!=int(end); f+=mstep) {
if (int(f/10)!=f/10.0f) {
val = decade * f/10;
if(val >= rMin && val < rMax) {
const int pos(0.5 + mLength * numberScale.ValueToPosition(val));
Tick(pos, val, false, false);
for (i = 0; i <= steps; i++) {
// PRL: Bug1038. Don't label 1.6, rounded, as a duplicate tick for "2"
if (!(mFormat == IntFormat && decade < 10.0)) {
for (int f = start; f != int(end); f += mstep) {
if (int(f / 10) != f / 10.0f) {
val = decade * f / 10;
if (val >= rMin && val < rMax) {
const int pos(0.5 + mLength * numberScale.ValueToPosition(val));
Tick(pos, val, false, false);
}
}
}
}