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