comparison base/AudioLevel.cpp @ 0:da6937383da8

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