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