annotate base/AudioLevel.cpp @ 0:da6937383da8

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