1 /**********************************************************************
2 
3 Audacity: A Digital Audio Editor
4 
5 NumberScale.h
6 
7 Paul Licameli
8 
9 **********************************************************************/
10 
11 #ifndef __AUDACITY_NUMBER_SCALE__
12 #define __AUDACITY_NUMBER_SCALE__
13 
14 #include <algorithm>
15 #include <cmath>
16 
17 enum NumberScaleType {
18    nstLinear,
19    nstLogarithmic,
20    nstMel,
21    nstBark,
22    nstErb,
23    nstPeriod,
24 
25    nstNumScaleTypes,
26    nstNone,
27 };
28 
29 
30 class NumberScale
31 {
32 public:
NumberScale()33    NumberScale()
34       : mType(nstNone), mValue0(0), mValue1(1)
35    {}
36 
NumberScale(NumberScaleType type,float value0,float value1)37    NumberScale(NumberScaleType type, float value0, float value1)
38       : mType(type)
39    {
40       switch (mType) {
41       case nstLinear:
42       case nstNone:
43       {
44          mValue0 = value0;
45          mValue1 = value1;
46       }
47       break;
48       case nstLogarithmic:
49       {
50          mValue0 = logf(value0);
51          mValue1 = logf(value1);
52       }
53       break;
54       case nstMel:
55       {
56          mValue0 = hzToMel(value0);
57          mValue1 = hzToMel(value1);
58       }
59       break;
60       case nstBark:
61       {
62          mValue0 = hzToBark(value0);
63          mValue1 = hzToBark(value1);
64       }
65       break;
66       case nstErb:
67       {
68          mValue0 = hzToErb(value0);
69          mValue1 = hzToErb(value1);
70       }
71       break;
72       case nstPeriod:
73       {
74          mValue0 = hzToPeriod(value0);
75          mValue1 = hzToPeriod(value1);
76       }
77       break;
78       default:
79          wxASSERT(false);
80       }
81    }
82 
Reversal()83    NumberScale Reversal() const
84    {
85       NumberScale result(*this);
86       std::swap(result.mValue0, result.mValue1);
87       return result;
88    }
89 
90    bool operator == (const NumberScale& other) const
91    {
92       return mType == other.mType
93          && mValue0 == other.mValue0
94          && mValue1 == other.mValue1;
95    }
96 
97    bool operator != (const NumberScale &other) const
98    {
99       return !(*this == other);
100    }
101 
hzToMel(float hz)102    static inline float hzToMel(float hz)
103    {
104       return 1127 * log(1 + hz / 700);
105    }
106 
melToHz(float mel)107    static inline float melToHz(float mel)
108    {
109       return 700 * (exp(mel / 1127) - 1);
110    }
111 
hzToBark(float hz)112    static inline float hzToBark(float hz)
113    {
114       // Traunmueller's formula
115       const float z1 = 26.81 * hz / (1960 + hz) - 0.53;
116       if (z1 < 2.0)
117          return z1 + 0.15 * (2.0 - z1);
118       else if (z1 > 20.1)
119          return z1 + 0.22 * (z1 - 20.1);
120       else
121          return z1;
122    }
123 
barkToHz(float z1)124    static inline float barkToHz(float z1)
125    {
126       if (z1 < 2.0)
127          z1 = 2.0 + (z1 - 2.0) / 0.85;
128       else if (z1 > 20.1)
129          z1 = 20.1 + (z1 - 20.1) / 1.22;
130       return 1960 * (z1 + 0.53) / (26.28 - z1);
131    }
132 
hzToErb(float hz)133    static inline float hzToErb(float hz)
134    {
135       return 11.17268 * log(1 + (46.06538 * hz) / (hz + 14678.49));
136    }
137 
erbToHz(float erb)138    static inline float erbToHz(float erb)
139    {
140       return 676170.4 / (47.06538 - exp(0.08950404 * erb)) - 14678.49;
141    }
142 
hzToPeriod(float hz)143    static inline float hzToPeriod(float hz)
144    {
145       return -1.0 / std::max (1.0f, hz);
146    }
147 
periodToHz(float u)148    static inline float periodToHz(float u)
149    {
150       return -1.0 / u;
151    }
152 
153    // Random access
PositionToValue(float pp)154    float PositionToValue(float pp) const
155    {
156       switch (mType) {
157       default:
158          wxASSERT(false);
159       case nstLinear:
160       case nstNone:
161          return mValue0 + pp * (mValue1 - mValue0);
162       case nstLogarithmic:
163          return exp(mValue0 + pp * (mValue1 - mValue0));
164       case nstMel:
165          return melToHz(mValue0 + pp * (mValue1 - mValue0));
166       case nstBark:
167          return barkToHz(mValue0 + pp * (mValue1 - mValue0));
168       case nstErb:
169          return erbToHz(mValue0 + pp * (mValue1 - mValue0));
170       case nstPeriod:
171          return periodToHz(mValue0 + pp * (mValue1 - mValue0));
172       }
173    }
174 
175    // STL-idiom iteration
176 
177    class Iterator
178    {
179    public:
Iterator(NumberScaleType type,float step,float value)180       Iterator(NumberScaleType type, float step, float value)
181          : mType(type), mStep(step), mValue(value)
182       {
183       }
184 
185       float operator * () const
186       {
187          switch (mType) {
188          default:
189             wxASSERT(false);
190          case nstLinear:
191          case nstNone:
192          case nstLogarithmic:
193             return mValue;
194          case nstMel:
195             return melToHz(mValue);
196          case nstBark:
197             return barkToHz(mValue);
198          case nstErb:
199             return erbToHz(mValue);
200          case nstPeriod:
201             return periodToHz(mValue);
202          }
203       }
204 
205       Iterator &operator ++()
206       {
207          switch (mType) {
208          case nstLinear:
209          case nstNone:
210          case nstMel:
211          case nstBark:
212          case nstErb:
213          case nstPeriod:
214             mValue += mStep;
215             break;
216          case nstLogarithmic:
217             mValue *= mStep;
218             break;
219          default:
220             wxASSERT(false);
221          }
222          return *this;
223       }
224 
225    private:
226       const NumberScaleType mType;
227       const float mStep;
228       float mValue;
229    };
230 
begin(float nPositions)231    Iterator begin(float nPositions) const
232    {
233       switch (mType) {
234       default:
235          wxASSERT(false);
236       case nstLinear:
237       case nstNone:
238       case nstMel:
239       case nstBark:
240       case nstErb:
241       case nstPeriod:
242          return Iterator
243             (mType,
244              nPositions == 1 ? 0 : (mValue1 - mValue0) / (nPositions - 1),
245              mValue0);
246       case nstLogarithmic:
247          return Iterator
248             (mType,
249              nPositions == 1 ? 1 : exp((mValue1 - mValue0) / (nPositions - 1)),
250              exp(mValue0));
251       }
252    }
253 
254    // Inverse
ValueToPosition(float val)255    float ValueToPosition(float val) const
256    {
257       switch (mType) {
258       default:
259          wxASSERT(false);
260       case nstLinear:
261       case nstNone:
262          return ((val - mValue0) / (mValue1 - mValue0));
263       case nstLogarithmic:
264          return ((log(val) - mValue0) / (mValue1 - mValue0));
265       case nstMel:
266          return ((hzToMel(val) - mValue0) / (mValue1 - mValue0));
267       case nstBark:
268          return ((hzToBark(val) - mValue0) / (mValue1 - mValue0));
269       case nstErb:
270          return ((hzToErb(val) - mValue0) / (mValue1 - mValue0));
271       case nstPeriod:
272          return ((hzToPeriod(val) - mValue0) / (mValue1 - mValue0));
273       }
274    }
275 
276 private:
277    NumberScaleType mType;
278    float mValue0;
279    float mValue1;
280 };
281 
282 #endif
283