CHANGELOG.md: Adjust for LADIOS jack_mixer
[jack_mixer.git] / jack_mixer / scale.py
blobe6e902dcfffd54b7c5f293a8b86aefc5e3039a63
1 # This file is part of jack_mixer
3 # Copyright (C) 2006 Nedko Arnaudov <nedko@arnaudov.name>
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; version 2 of the License
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 import logging
19 import math
21 from ._jack_mixer import Scale
24 log = logging.getLogger(__name__)
27 class Mark:
28 """Encapsulates scale linear function edge and coefficients for scale = a * dB + b formula"""
30 def __init__(self, db, scale, text=None):
31 self.db = db
32 self.scale = scale
33 if text is None:
34 # TODO: l10n
35 self.text = "%.0f" % math.fabs(db)
36 else:
37 self.text = text
40 class Base:
41 """Scale abstraction, various scale implementation derive from this class"""
43 def __init__(self, scale_id, description):
44 self.marks = []
45 self.scale_id = scale_id
46 self.description = description
47 self.scale = Scale()
49 def add_threshold(self, db, scale, is_mark, text=None):
50 self.scale.add_threshold(db, scale)
51 if is_mark:
52 self.marks.append(Mark(db, scale, text))
54 def calculate_coefficients(self):
55 self.scale.calculate_coefficients()
57 def db_to_scale(self, db):
58 """Convert dBFS value to number in range 0.0-1.0 used in GUI"""
59 # log.debug("db_to_scale(%f)", db)
60 return self.scale.db_to_scale(db)
62 def scale_to_db(self, scale):
63 """Convert number in range 0.0-1.0 used in GUI to dBFS value"""
64 return self.scale.scale_to_db(scale)
66 def add_mark(self, db):
67 self.marks.append(Mark(db, -1.0))
69 def get_marks(self):
70 return self.marks
72 def scale_marks(self):
73 for i in self.marks:
74 if i.scale == -1.0:
75 i.scale = self.db_to_scale(i.db)
78 # IEC 60268-18 Peak programme level meters - Digital audio peak level meter
79 # Adapted from meterbridge, may be wrong, I'm not buying standards, even if they cost $45
80 # If someone has the standard, please either share it with me or fix the code.
81 class IEC268(Base):
82 """IEC 60268-18 Peak programme level meters - Digital audio peak level meter"""
84 def __init__(self):
85 Base.__init__(
86 self,
87 "iec_268",
88 _("IEC 60268-18 Peak programme level meters - Digital audio peak level meter"),
90 self.add_threshold(-70.0, 0.0, False)
91 self.add_threshold(-60.0, 0.05, True)
92 self.add_threshold(-50.0, 0.075, True)
93 self.add_threshold(-40.0, 0.15, True)
94 self.add_mark(-35.0)
95 self.add_threshold(-30.0, 0.3, True)
96 self.add_mark(-25.0)
97 self.add_threshold(-20.0, 0.5, True)
98 self.add_mark(-15.0)
99 self.add_mark(-10.0)
100 self.add_mark(-5.0)
101 self.add_threshold(0.0, 1.0, True)
102 self.calculate_coefficients()
103 self.scale_marks()
106 class IEC268Minimalistic(Base):
107 """IEC 60268-18 Peak programme level meters - Digital audio peak level meter,
108 fewer marks"""
110 def __init__(self):
111 Base.__init__(
112 self,
113 "iec_268_minimalistic",
115 "IEC 60268-18 Peak programme level meters - "
116 "Digital audio peak level meter, fewer marks"
119 self.add_threshold(-70.0, 0.0, False)
120 self.add_threshold(-60.0, 0.05, True)
121 self.add_threshold(-50.0, 0.075, False)
122 self.add_threshold(-40.0, 0.15, True)
123 self.add_threshold(-30.0, 0.3, True)
124 self.add_threshold(-20.0, 0.5, True)
125 self.add_mark(-10.0)
126 self.add_threshold(0.0, 1.0, True)
127 self.calculate_coefficients()
128 self.scale_marks()
131 class Linear70dB(Base):
132 """Linear scale with range from -70 to 0 dBFS"""
134 def __init__(self):
135 Base.__init__(self, "linear_70dB", _("Linear scale with range from -70 to 0 dBFS"))
136 self.add_threshold(-70.0, 0.0, False)
137 self.add_mark(-60.0)
138 self.add_mark(-50.0)
139 self.add_mark(-40.0)
140 self.add_mark(-35.0)
141 self.add_mark(-30.0)
142 self.add_mark(-25.0)
143 self.add_mark(-20.0)
144 self.add_mark(-15.0)
145 self.add_mark(-10.0)
146 self.add_mark(-5.0)
147 self.add_threshold(0.0, 1.0, True)
148 self.calculate_coefficients()
149 self.scale_marks()
152 class Linear30dB(Base):
153 """Linear scale with range from -30 to +30 dBFS"""
155 def __init__(self):
156 Base.__init__(self, "linear_30dB", _("Linear scale with range from -30 to +30 dBFS"))
157 self.add_threshold(-30.0, 0.0, False)
158 self.add_threshold(+30.0, 1.0, True)
159 self.calculate_coefficients()
160 self.scale_marks()
163 class K20(Base):
164 """K20 scale"""
166 def __init__(self):
167 Base.__init__(self, "K20", _("K20 scale"))
168 self.add_mark(-200, "")
169 self.add_mark(-60, "-40")
170 self.add_mark(-55, "")
171 self.add_mark(-50, "-30")
172 self.add_mark(-45, "")
173 self.add_mark(-40, "-20")
174 self.add_mark(-35, "")
175 self.add_mark(-30, "-10")
176 self.add_mark(-26, "-6")
177 self.add_mark(-23, "-3")
178 self.add_mark(-20, "0")
179 self.add_mark(-17, "3")
180 self.add_mark(-14, "6")
181 self.add_mark(-10, "10")
182 self.add_mark(-5, "15")
183 self.add_mark(0, "20")
185 def db_to_scale(self, db):
186 v = math.pow(10.0, db / 20.0)
187 return self.mapk20(v) / 450.0
189 def add_mark(self, db, text):
190 self.marks.append(Mark(db, self.db_to_scale(db), text))
192 def mapk20(self, v):
193 if v < 0.001:
194 return 24000 * v
195 v = math.log10(v) + 3
196 if v < 2.0:
197 return 24.3 + v * (100 + v * 16)
198 if v > 3.0:
199 v = 3.0
200 return v * 161.7 - 35.1
203 class K14(Base):
204 """K14 scale"""
206 def __init__(self):
207 Base.__init__(self, "K14", _("K14 scale"))
208 self.add_mark(-200, "")
209 self.add_mark(-54, "-40")
210 self.add_mark(-35 - 14, "")
211 self.add_mark(-30 - 14, "-30")
212 self.add_mark(-25 - 14, "")
213 self.add_mark(-20 - 14, "-20")
214 self.add_mark(-15 - 14, "")
215 self.add_mark(-10 - 14, "-10")
216 self.add_mark(-6 - 14, "-6")
217 self.add_mark(-3 - 14, "-3")
218 self.add_mark(-14, "0")
219 self.add_mark(3 - 14, "3")
220 self.add_mark(6 - 14, "6")
221 self.add_mark(10 - 14, "10")
222 self.add_mark(14 - 14, "14")
224 def db_to_scale(self, db):
225 v = math.pow(10.0, db / 20.0)
226 return self.mapk14(v) / 448.3
228 def add_mark(self, db, text):
229 self.marks.append(Mark(db, self.db_to_scale(db), text))
231 def mapk14(self, v):
232 if v < 0.002:
233 return int(12000 * v)
234 v = math.log10(v) + 2.7
235 if v < 2.0:
236 return int(20.3 + v * (80 + v * 32))
237 if v > 2.7:
238 v = 2.7
239 return int(v * 200 - 91.7)
242 def scale_test1(scale):
243 for i in range(-97 * 2, 1, 1):
244 db = float(i) / 2.0
245 print("%5.1f dB maps to %f" % (db, scale.db_to_scale(db)))
248 def scale_test2(scale):
249 for i in range(101):
250 s = float(i) / 100.0
251 print("%.2f maps to %.1f dB" % (s, scale.scale_to_db(s)))
254 def print_db_to_scale(scale, db):
255 print("%-.1f dB maps to %f" % (db, scale.db_to_scale(db)))
258 def scale_test3(scale):
259 print_db_to_scale(scale, +77.0)
260 print_db_to_scale(scale, +7.0)
261 print_db_to_scale(scale, 0.0)
262 print_db_to_scale(scale, -107.0)
265 def _test(*args, **kwargs):
266 scale = Linear30dB()
267 scale_test1(scale)
268 scale_test2(scale)
269 scale_test3(scale)
272 if __name__ == "__main__":
273 _test()