svcore
1.9
|
00001 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ 00002 00003 /* 00004 Sonic Visualiser 00005 An audio file viewer and annotation editor. 00006 Centre for Digital Music, Queen Mary, University of London. 00007 00008 This program is free software; you can redistribute it and/or 00009 modify it under the terms of the GNU General Public License as 00010 published by the Free Software Foundation; either version 2 of the 00011 License, or (at your option) any later version. See the file 00012 COPYING included with this distribution for more information. 00013 */ 00014 00015 /* 00016 This is a modified version of a source file from the 00017 Rosegarden MIDI and audio sequencer and notation editor. 00018 This file copyright 2000-2006 Chris Cannam. 00019 */ 00020 00021 #include "AudioLevel.h" 00022 #include <cmath> 00023 #include <iostream> 00024 #include <map> 00025 #include <vector> 00026 #include <cassert> 00027 #include "system/System.h" 00028 00029 const float AudioLevel::DB_FLOOR = -1000.f; 00030 00031 struct FaderDescription 00032 { 00033 FaderDescription(float _minDb, float _maxDb, float _zeroPoint) : 00034 minDb(_minDb), maxDb(_maxDb), zeroPoint(_zeroPoint) { } 00035 00036 float minDb; 00037 float maxDb; 00038 float zeroPoint; // as fraction of total throw 00039 }; 00040 00041 static const FaderDescription faderTypes[] = { 00042 FaderDescription(-40.f, +6.f, 0.75f), // short 00043 FaderDescription(-70.f, +10.f, 0.80f), // long 00044 FaderDescription(-70.f, 0.f, 1.00f), // IEC268 00045 FaderDescription(-70.f, +10.f, 0.80f), // IEC268 long 00046 FaderDescription(-40.f, 0.f, 1.00f), // preview 00047 }; 00048 00049 //typedef std::vector<float> LevelList; 00050 //static std::map<int, LevelList> previewLevelCache; 00051 //static const LevelList &getPreviewLevelCache(int levels); 00052 00053 float 00054 AudioLevel::multiplier_to_dB(float multiplier) 00055 { 00056 if (multiplier == 0.f) return DB_FLOOR; 00057 else if (multiplier < 0.f) return multiplier_to_dB(-multiplier); 00058 float dB = 10 * log10f(multiplier); 00059 return dB; 00060 } 00061 00062 float 00063 AudioLevel::dB_to_multiplier(float dB) 00064 { 00065 if (dB == DB_FLOOR) return 0.f; 00066 float m = powf(10.f, dB / 10.f); 00067 return m; 00068 } 00069 00070 /* IEC 60-268-18 fader levels. Thanks to Steve Harris. */ 00071 00072 static float iec_dB_to_fader(float db) 00073 { 00074 float def = 0.0f; // Meter deflection %age 00075 00076 if (db < -70.0f) { 00077 def = 0.0f; 00078 } else if (db < -60.0f) { 00079 def = (db + 70.0f) * 0.25f; 00080 } else if (db < -50.0f) { 00081 def = (db + 60.0f) * 0.5f + 2.5f; // corrected from 5.0f base, thanks Robin Gareus 00082 } else if (db < -40.0f) { 00083 def = (db + 50.0f) * 0.75f + 7.5f; 00084 } else if (db < -30.0f) { 00085 def = (db + 40.0f) * 1.5f + 15.0f; 00086 } else if (db < -20.0f) { 00087 def = (db + 30.0f) * 2.0f + 30.0f; 00088 } else { 00089 def = (db + 20.0f) * 2.5f + 50.0f; 00090 } 00091 00092 return def; 00093 } 00094 00095 static float iec_fader_to_dB(float def) // Meter deflection %age 00096 { 00097 float db = 0.0f; 00098 00099 if (def >= 50.0f) { 00100 db = (def - 50.0f) / 2.5f - 20.0f; 00101 } else if (def >= 30.0f) { 00102 db = (def - 30.0f) / 2.0f - 30.0f; 00103 } else if (def >= 15.0f) { 00104 db = (def - 15.0f) / 1.5f - 40.0f; 00105 } else if (def >= 7.5f) { 00106 db = (def - 7.5f) / 0.75f - 50.0f; 00107 } else if (def >= 2.5f) { 00108 db = (def - 2.5f) / 0.5f - 60.0f; 00109 } else { 00110 db = (def / 0.25f) - 70.0f; 00111 } 00112 00113 return db; 00114 } 00115 00116 float 00117 AudioLevel::fader_to_dB(int level, int maxLevel, FaderType type) 00118 { 00119 if (level == 0) return DB_FLOOR; 00120 00121 if (type == IEC268Meter || type == IEC268LongMeter) { 00122 00123 float maxPercent = iec_dB_to_fader(faderTypes[type].maxDb); 00124 float percent = float(level) * maxPercent / float(maxLevel); 00125 float dB = iec_fader_to_dB(percent); 00126 return dB; 00127 00128 } else { // scale proportional to sqrt(fabs(dB)) 00129 00130 int zeroLevel = int(maxLevel * faderTypes[type].zeroPoint); 00131 00132 if (level >= zeroLevel) { 00133 00134 float value = level - zeroLevel; 00135 float scale = float(maxLevel - zeroLevel) / 00136 sqrtf(faderTypes[type].maxDb); 00137 value /= scale; 00138 float dB = powf(value, 2.f); 00139 return dB; 00140 00141 } else { 00142 00143 float value = zeroLevel - level; 00144 float scale = zeroLevel / sqrtf(0.f - faderTypes[type].minDb); 00145 value /= scale; 00146 float dB = powf(value, 2.f); 00147 return 0.f - dB; 00148 } 00149 } 00150 } 00151 00152 00153 int 00154 AudioLevel::dB_to_fader(float dB, int maxLevel, FaderType type) 00155 { 00156 if (dB == DB_FLOOR) return 0; 00157 00158 if (type == IEC268Meter || type == IEC268LongMeter) { 00159 00160 // The IEC scale gives a "percentage travel" for a given dB 00161 // level, but it reaches 100% at 0dB. So we want to treat the 00162 // result not as a percentage, but as a scale between 0 and 00163 // whatever the "percentage" for our (possibly >0dB) max dB is. 00164 00165 float maxPercent = iec_dB_to_fader(faderTypes[type].maxDb); 00166 float percent = iec_dB_to_fader(dB); 00167 int faderLevel = int((maxLevel * percent) / maxPercent + 0.01f); 00168 00169 if (faderLevel < 0) faderLevel = 0; 00170 if (faderLevel > maxLevel) faderLevel = maxLevel; 00171 return faderLevel; 00172 00173 } else { 00174 00175 int zeroLevel = int(maxLevel * faderTypes[type].zeroPoint); 00176 00177 if (dB >= 0.f) { 00178 00179 if (faderTypes[type].maxDb <= 0.f) { 00180 00181 return maxLevel; 00182 00183 } else { 00184 00185 float value = sqrtf(dB); 00186 float scale = (maxLevel - zeroLevel) / sqrtf(faderTypes[type].maxDb); 00187 value *= scale; 00188 int level = int(value + 0.01f) + zeroLevel; 00189 if (level > maxLevel) level = maxLevel; 00190 return level; 00191 } 00192 00193 } else { 00194 00195 dB = 0.f - dB; 00196 float value = sqrtf(dB); 00197 float scale = zeroLevel / sqrtf(0.f - faderTypes[type].minDb); 00198 value *= scale; 00199 int level = zeroLevel - int(value + 0.01f); 00200 if (level < 0) level = 0; 00201 return level; 00202 } 00203 } 00204 } 00205 00206 00207 float 00208 AudioLevel::fader_to_multiplier(int level, int maxLevel, FaderType type) 00209 { 00210 if (level == 0) return 0.f; 00211 return dB_to_multiplier(fader_to_dB(level, maxLevel, type)); 00212 } 00213 00214 int 00215 AudioLevel::multiplier_to_fader(float multiplier, int maxLevel, FaderType type) 00216 { 00217 if (multiplier == 0.f) return 0; 00218 float dB = multiplier_to_dB(multiplier); 00219 int fader = dB_to_fader(dB, maxLevel, type); 00220 return fader; 00221 } 00222 00223 /* 00224 const LevelList & 00225 getPreviewLevelCache(int levels) 00226 { 00227 LevelList &ll = previewLevelCache[levels]; 00228 if (ll.empty()) { 00229 for (int i = 0; i <= levels; ++i) { 00230 float m = AudioLevel::fader_to_multiplier 00231 (i + levels/4, levels + levels/4, AudioLevel::PreviewLevel); 00232 if (levels == 1) m /= 100; // noise 00233 ll.push_back(m); 00234 } 00235 } 00236 return ll; 00237 } 00238 */ 00239 00240 int 00241 AudioLevel::multiplier_to_preview(float m, int levels) 00242 { 00243 assert(levels > 0); 00244 return multiplier_to_fader(m, levels, PreviewLevel); 00245 00246 /* The original multiplier_to_preview which follows is not thread-safe. 00247 00248 if (m < 0.f) return -multiplier_to_preview(-m, levels); 00249 00250 const LevelList &ll = getPreviewLevelCache(levels); 00251 int result = -1; 00252 00253 int lo = 0, hi = levels; 00254 00255 // binary search 00256 int level = -1; 00257 while (result < 0) { 00258 int newlevel = (lo + hi) / 2; 00259 if (newlevel == level || 00260 newlevel == 0 || 00261 newlevel == levels) { 00262 result = newlevel; 00263 break; 00264 } 00265 level = newlevel; 00266 if (ll[level] >= m) { 00267 hi = level; 00268 } else if (ll[level+1] >= m) { 00269 result = level; 00270 } else { 00271 lo = level; 00272 } 00273 } 00274 00275 return result; 00276 00277 */ 00278 } 00279 00280 float 00281 AudioLevel::preview_to_multiplier(int level, int levels) 00282 { 00283 assert(levels > 0); 00284 return fader_to_multiplier(level, levels, PreviewLevel); 00285 /* 00286 if (level < 0) return -preview_to_multiplier(-level, levels); 00287 const LevelList &ll = getPreviewLevelCache(levels); 00288 return ll[level]; 00289 */ 00290 } 00291 00292