annotate base/AudioLevel.cpp @ 282:d9319859a4cf tip

(none)
author benoitrigolleau
date Fri, 31 Oct 2008 11:00:24 +0000
parents fc9323a41f5a
children
rev   line source
lbajardsilogic@0 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
lbajardsilogic@0 2
lbajardsilogic@0 3 /*
lbajardsilogic@0 4 Sonic Visualiser
lbajardsilogic@0 5 An audio file viewer and annotation editor.
lbajardsilogic@0 6 Centre for Digital Music, Queen Mary, University of London.
lbajardsilogic@0 7
lbajardsilogic@0 8 This program is free software; you can redistribute it and/or
lbajardsilogic@0 9 modify it under the terms of the GNU General Public License as
lbajardsilogic@0 10 published by the Free Software Foundation; either version 2 of the
lbajardsilogic@0 11 License, or (at your option) any later version. See the file
lbajardsilogic@0 12 COPYING included with this distribution for more information.
lbajardsilogic@0 13 */
lbajardsilogic@0 14
lbajardsilogic@0 15 /*
lbajardsilogic@0 16 This is a modified version of a source file from the
lbajardsilogic@0 17 Rosegarden MIDI and audio sequencer and notation editor.
lbajardsilogic@0 18 This file copyright 2000-2006 Chris Cannam.
lbajardsilogic@0 19 */
lbajardsilogic@0 20
lbajardsilogic@0 21 #include "AudioLevel.h"
lbajardsilogic@0 22 #include <cmath>
lbajardsilogic@0 23 #include <iostream>
lbajardsilogic@0 24 #include <map>
lbajardsilogic@0 25 #include <vector>
lbajardsilogic@0 26 #include <cassert>
lbajardsilogic@0 27
lbajardsilogic@0 28 const float AudioLevel::DB_FLOOR = -1000.f;
lbajardsilogic@0 29
lbajardsilogic@0 30 struct FaderDescription
lbajardsilogic@0 31 {
lbajardsilogic@0 32 FaderDescription(float _minDb, float _maxDb, float _zeroPoint) :
lbajardsilogic@0 33 minDb(_minDb), maxDb(_maxDb), zeroPoint(_zeroPoint) { }
lbajardsilogic@0 34
lbajardsilogic@0 35 float minDb;
lbajardsilogic@0 36 float maxDb;
lbajardsilogic@0 37 float zeroPoint; // as fraction of total throw
lbajardsilogic@0 38 };
lbajardsilogic@0 39
lbajardsilogic@0 40 static const FaderDescription faderTypes[] = {
lbajardsilogic@0 41 FaderDescription(-40.f, +6.f, 0.75f), // short
lbajardsilogic@0 42 FaderDescription(-70.f, +10.f, 0.80f), // long
lbajardsilogic@0 43 FaderDescription(-70.f, 0.f, 1.00f), // IEC268
lbajardsilogic@0 44 FaderDescription(-70.f, +10.f, 0.80f), // IEC268 long
lbajardsilogic@0 45 FaderDescription(-40.f, 0.f, 1.00f), // preview
lbajardsilogic@0 46 };
lbajardsilogic@0 47
lbajardsilogic@0 48 //typedef std::vector<float> LevelList;
lbajardsilogic@0 49 //static std::map<int, LevelList> previewLevelCache;
lbajardsilogic@0 50 //static const LevelList &getPreviewLevelCache(int levels);
lbajardsilogic@0 51
lbajardsilogic@0 52 float
lbajardsilogic@0 53 AudioLevel::multiplier_to_dB(float multiplier)
lbajardsilogic@0 54 {
lbajardsilogic@0 55 if (multiplier == 0.f) return DB_FLOOR;
lbajardsilogic@0 56 else if (multiplier < 0.f) return multiplier_to_dB(-multiplier);
lbajardsilogic@0 57 float dB = 10 * log10f(multiplier);
lbajardsilogic@0 58 return dB;
lbajardsilogic@0 59 }
lbajardsilogic@0 60
lbajardsilogic@0 61 float
lbajardsilogic@0 62 AudioLevel::dB_to_multiplier(float dB)
lbajardsilogic@0 63 {
lbajardsilogic@0 64 if (dB == DB_FLOOR) return 0.f;
lbajardsilogic@0 65 float m = powf(10.f, dB / 10.f);
lbajardsilogic@0 66 return m;
lbajardsilogic@0 67 }
lbajardsilogic@0 68
lbajardsilogic@0 69 /* IEC 60-268-18 fader levels. Thanks to Steve Harris. */
lbajardsilogic@0 70
lbajardsilogic@0 71 static float iec_dB_to_fader(float db)
lbajardsilogic@0 72 {
lbajardsilogic@0 73 float def = 0.0f; // Meter deflection %age
lbajardsilogic@0 74
lbajardsilogic@0 75 if (db < -70.0f) {
lbajardsilogic@0 76 def = 0.0f;
lbajardsilogic@0 77 } else if (db < -60.0f) {
lbajardsilogic@0 78 def = (db + 70.0f) * 0.25f;
lbajardsilogic@0 79 } else if (db < -50.0f) {
lbajardsilogic@0 80 def = (db + 60.0f) * 0.5f + 5.0f;
lbajardsilogic@0 81 } else if (db < -40.0f) {
lbajardsilogic@0 82 def = (db + 50.0f) * 0.75f + 7.5f;
lbajardsilogic@0 83 } else if (db < -30.0f) {
lbajardsilogic@0 84 def = (db + 40.0f) * 1.5f + 15.0f;
lbajardsilogic@0 85 } else if (db < -20.0f) {
lbajardsilogic@0 86 def = (db + 30.0f) * 2.0f + 30.0f;
lbajardsilogic@0 87 } else {
lbajardsilogic@0 88 def = (db + 20.0f) * 2.5f + 50.0f;
lbajardsilogic@0 89 }
lbajardsilogic@0 90
lbajardsilogic@0 91 return def;
lbajardsilogic@0 92 }
lbajardsilogic@0 93
lbajardsilogic@0 94 static float iec_fader_to_dB(float def) // Meter deflection %age
lbajardsilogic@0 95 {
lbajardsilogic@0 96 float db = 0.0f;
lbajardsilogic@0 97
lbajardsilogic@0 98 if (def >= 50.0f) {
lbajardsilogic@0 99 db = (def - 50.0f) / 2.5f - 20.0f;
lbajardsilogic@0 100 } else if (def >= 30.0f) {
lbajardsilogic@0 101 db = (def - 30.0f) / 2.0f - 30.0f;
lbajardsilogic@0 102 } else if (def >= 15.0f) {
lbajardsilogic@0 103 db = (def - 15.0f) / 1.5f - 40.0f;
lbajardsilogic@0 104 } else if (def >= 7.5f) {
lbajardsilogic@0 105 db = (def - 7.5f) / 0.75f - 50.0f;
lbajardsilogic@0 106 } else if (def >= 5.0f) {
lbajardsilogic@0 107 db = (def - 5.0f) / 0.5f - 60.0f;
lbajardsilogic@0 108 } else {
lbajardsilogic@0 109 db = (def / 0.25f) - 70.0f;
lbajardsilogic@0 110 }
lbajardsilogic@0 111
lbajardsilogic@0 112 return db;
lbajardsilogic@0 113 }
lbajardsilogic@0 114
lbajardsilogic@0 115 float
lbajardsilogic@0 116 AudioLevel::fader_to_dB(int level, int maxLevel, FaderType type)
lbajardsilogic@0 117 {
lbajardsilogic@0 118 if (level == 0) return DB_FLOOR;
lbajardsilogic@0 119
lbajardsilogic@0 120 if (type == IEC268Meter || type == IEC268LongMeter) {
lbajardsilogic@0 121
lbajardsilogic@0 122 float maxPercent = iec_dB_to_fader(faderTypes[type].maxDb);
lbajardsilogic@0 123 float percent = float(level) * maxPercent / float(maxLevel);
lbajardsilogic@0 124 float dB = iec_fader_to_dB(percent);
lbajardsilogic@0 125 return dB;
lbajardsilogic@0 126
lbajardsilogic@0 127 } else { // scale proportional to sqrt(fabs(dB))
lbajardsilogic@0 128
lbajardsilogic@0 129 int zeroLevel = int(maxLevel * faderTypes[type].zeroPoint);
lbajardsilogic@0 130
lbajardsilogic@0 131 if (level >= zeroLevel) {
lbajardsilogic@0 132
lbajardsilogic@0 133 float value = level - zeroLevel;
lbajardsilogic@0 134 float scale = float(maxLevel - zeroLevel) /
lbajardsilogic@0 135 sqrtf(faderTypes[type].maxDb);
lbajardsilogic@0 136 value /= scale;
lbajardsilogic@0 137 float dB = powf(value, 2.f);
lbajardsilogic@0 138 return dB;
lbajardsilogic@0 139
lbajardsilogic@0 140 } else {
lbajardsilogic@0 141
lbajardsilogic@0 142 float value = zeroLevel - level;
lbajardsilogic@0 143 float scale = zeroLevel / sqrtf(0.f - faderTypes[type].minDb);
lbajardsilogic@0 144 value /= scale;
lbajardsilogic@0 145 float dB = powf(value, 2.f);
lbajardsilogic@0 146 return 0.f - dB;
lbajardsilogic@0 147 }
lbajardsilogic@0 148 }
lbajardsilogic@0 149 }
lbajardsilogic@0 150
lbajardsilogic@0 151
lbajardsilogic@0 152 int
lbajardsilogic@0 153 AudioLevel::dB_to_fader(float dB, int maxLevel, FaderType type)
lbajardsilogic@0 154 {
lbajardsilogic@0 155 if (dB == DB_FLOOR) return 0;
lbajardsilogic@0 156
lbajardsilogic@0 157 if (type == IEC268Meter || type == IEC268LongMeter) {
lbajardsilogic@0 158
lbajardsilogic@0 159 // The IEC scale gives a "percentage travel" for a given dB
lbajardsilogic@0 160 // level, but it reaches 100% at 0dB. So we want to treat the
lbajardsilogic@0 161 // result not as a percentage, but as a scale between 0 and
lbajardsilogic@0 162 // whatever the "percentage" for our (possibly >0dB) max dB is.
lbajardsilogic@0 163
lbajardsilogic@0 164 float maxPercent = iec_dB_to_fader(faderTypes[type].maxDb);
lbajardsilogic@0 165 float percent = iec_dB_to_fader(dB);
lbajardsilogic@0 166 int faderLevel = int((maxLevel * percent) / maxPercent + 0.01f);
lbajardsilogic@0 167
lbajardsilogic@0 168 if (faderLevel < 0) faderLevel = 0;
lbajardsilogic@0 169 if (faderLevel > maxLevel) faderLevel = maxLevel;
lbajardsilogic@0 170 return faderLevel;
lbajardsilogic@0 171
lbajardsilogic@0 172 } else {
lbajardsilogic@0 173
lbajardsilogic@0 174 int zeroLevel = int(maxLevel * faderTypes[type].zeroPoint);
lbajardsilogic@0 175
lbajardsilogic@0 176 if (dB >= 0.f) {
lbajardsilogic@0 177
lbajardsilogic@0 178 if (faderTypes[type].maxDb <= 0.f) {
lbajardsilogic@0 179
lbajardsilogic@0 180 return maxLevel;
lbajardsilogic@0 181
lbajardsilogic@0 182 } else {
lbajardsilogic@0 183
lbajardsilogic@0 184 float value = sqrtf(dB);
lbajardsilogic@0 185 float scale = (maxLevel - zeroLevel) / sqrtf(faderTypes[type].maxDb);
lbajardsilogic@0 186 value *= scale;
lbajardsilogic@0 187 int level = int(value + 0.01f) + zeroLevel;
lbajardsilogic@0 188 if (level > maxLevel) level = maxLevel;
lbajardsilogic@0 189 return level;
lbajardsilogic@0 190 }
lbajardsilogic@0 191
lbajardsilogic@0 192 } else {
lbajardsilogic@0 193
lbajardsilogic@0 194 dB = 0.f - dB;
lbajardsilogic@0 195 float value = sqrtf(dB);
lbajardsilogic@0 196 float scale = zeroLevel / sqrtf(0.f - faderTypes[type].minDb);
lbajardsilogic@0 197 value *= scale;
lbajardsilogic@0 198 int level = zeroLevel - int(value + 0.01f);
lbajardsilogic@0 199 if (level < 0) level = 0;
lbajardsilogic@0 200 return level;
lbajardsilogic@0 201 }
lbajardsilogic@0 202 }
lbajardsilogic@0 203 }
lbajardsilogic@0 204
lbajardsilogic@0 205
lbajardsilogic@0 206 float
lbajardsilogic@0 207 AudioLevel::fader_to_multiplier(int level, int maxLevel, FaderType type)
lbajardsilogic@0 208 {
lbajardsilogic@0 209 if (level == 0) return 0.f;
lbajardsilogic@0 210 return dB_to_multiplier(fader_to_dB(level, maxLevel, type));
lbajardsilogic@0 211 }
lbajardsilogic@0 212
lbajardsilogic@0 213 int
lbajardsilogic@0 214 AudioLevel::multiplier_to_fader(float multiplier, int maxLevel, FaderType type)
lbajardsilogic@0 215 {
lbajardsilogic@0 216 if (multiplier == 0.f) return 0;
lbajardsilogic@0 217 float dB = multiplier_to_dB(multiplier);
lbajardsilogic@0 218 int fader = dB_to_fader(dB, maxLevel, type);
lbajardsilogic@0 219 return fader;
lbajardsilogic@0 220 }
lbajardsilogic@0 221
lbajardsilogic@0 222 /*
lbajardsilogic@0 223 const LevelList &
lbajardsilogic@0 224 getPreviewLevelCache(int levels)
lbajardsilogic@0 225 {
lbajardsilogic@0 226 LevelList &ll = previewLevelCache[levels];
lbajardsilogic@0 227 if (ll.empty()) {
lbajardsilogic@0 228 for (int i = 0; i <= levels; ++i) {
lbajardsilogic@0 229 float m = AudioLevel::fader_to_multiplier
lbajardsilogic@0 230 (i + levels/4, levels + levels/4, AudioLevel::PreviewLevel);
lbajardsilogic@0 231 if (levels == 1) m /= 100; // noise
lbajardsilogic@0 232 ll.push_back(m);
lbajardsilogic@0 233 }
lbajardsilogic@0 234 }
lbajardsilogic@0 235 return ll;
lbajardsilogic@0 236 }
lbajardsilogic@0 237 */
lbajardsilogic@0 238
lbajardsilogic@0 239 int
lbajardsilogic@0 240 AudioLevel::multiplier_to_preview(float m, int levels)
lbajardsilogic@0 241 {
lbajardsilogic@0 242 assert(levels > 0);
lbajardsilogic@0 243 return multiplier_to_fader(m, levels, PreviewLevel);
lbajardsilogic@0 244
lbajardsilogic@0 245 /* The original multiplier_to_preview which follows is not thread-safe.
lbajardsilogic@0 246
lbajardsilogic@0 247 if (m < 0.f) return -multiplier_to_preview(-m, levels);
lbajardsilogic@0 248
lbajardsilogic@0 249 const LevelList &ll = getPreviewLevelCache(levels);
lbajardsilogic@0 250 int result = -1;
lbajardsilogic@0 251
lbajardsilogic@0 252 int lo = 0, hi = levels;
lbajardsilogic@0 253
lbajardsilogic@0 254 // binary search
lbajardsilogic@0 255 int level = -1;
lbajardsilogic@0 256 while (result < 0) {
lbajardsilogic@0 257 int newlevel = (lo + hi) / 2;
lbajardsilogic@0 258 if (newlevel == level ||
lbajardsilogic@0 259 newlevel == 0 ||
lbajardsilogic@0 260 newlevel == levels) {
lbajardsilogic@0 261 result = newlevel;
lbajardsilogic@0 262 break;
lbajardsilogic@0 263 }
lbajardsilogic@0 264 level = newlevel;
lbajardsilogic@0 265 if (ll[level] >= m) {
lbajardsilogic@0 266 hi = level;
lbajardsilogic@0 267 } else if (ll[level+1] >= m) {
lbajardsilogic@0 268 result = level;
lbajardsilogic@0 269 } else {
lbajardsilogic@0 270 lo = level;
lbajardsilogic@0 271 }
lbajardsilogic@0 272 }
lbajardsilogic@0 273
lbajardsilogic@0 274 return result;
lbajardsilogic@0 275
lbajardsilogic@0 276 */
lbajardsilogic@0 277 }
lbajardsilogic@0 278
lbajardsilogic@0 279 float
lbajardsilogic@0 280 AudioLevel::preview_to_multiplier(int level, int levels)
lbajardsilogic@0 281 {
lbajardsilogic@0 282 assert(levels > 0);
lbajardsilogic@0 283 return fader_to_multiplier(level, levels, PreviewLevel);
lbajardsilogic@0 284 /*
lbajardsilogic@0 285 if (level < 0) return -preview_to_multiplier(-level, levels);
lbajardsilogic@0 286 const LevelList &ll = getPreviewLevelCache(levels);
lbajardsilogic@0 287 return ll[level];
lbajardsilogic@0 288 */
lbajardsilogic@0 289 }
lbajardsilogic@0 290
lbajardsilogic@0 291