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