]> git.0d.be Git - jack_mixer.git/blob - scale.py
Set version to 14 in preparation for next release
[jack_mixer.git] / scale.py
1 # This file is part of jack_mixer
2 #
3 # Copyright (C) 2006 Nedko Arnaudov <nedko@arnaudov.name>
4 #
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
8 #
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.
13 #
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.
17
18 import logging
19 import math
20
21 import jack_mixer_c
22
23
24 log = logging.getLogger(__name__)
25
26
27 class Mark:
28     '''Encapsulates scale linear function edge and coefficients for scale = a * dB + b formula'''
29     def __init__(self, db, scale, text = None):
30         self.db = db
31         self.scale = scale
32         if text == None:
33             self.text = "%.0f" % math.fabs(db)
34         else:
35             self.text = text
36
37 class Base:
38     '''Scale abstraction, various scale implementation derive from this class'''
39     def __init__(self, scale_id, description):
40         self.marks = []
41         self.scale_id = scale_id
42         self.description = description
43         self.scale = jack_mixer_c.Scale()
44
45     def add_threshold(self, db, scale, is_mark, text = None):
46         self.scale.add_threshold(db, scale)
47         if is_mark:
48             self.marks.append(Mark(db, scale, text))
49
50     def calculate_coefficients(self):
51         self.scale.calculate_coefficients()
52
53     def db_to_scale(self, db):
54         '''Convert dBFS value to number in range 0.0-1.0 used in GUI'''
55         #log.debug("db_to_scale(%f)", db)
56         return self.scale.db_to_scale(db)
57
58     def scale_to_db(self, scale):
59         '''Convert number in range 0.0-1.0 used in GUI to dBFS value'''
60         return self.scale.scale_to_db(scale)
61
62     def add_mark(self, db):
63         self.marks.append(Mark(db, -1.0))
64
65     def get_marks(self):
66         return self.marks
67
68     def scale_marks(self):
69         for i in self.marks:
70             if i.scale == -1.0:
71                 i.scale = self.db_to_scale(i.db)
72
73
74 # IEC 60268-18 Peak programme level meters - Digital audio peak level meter
75 # Adapted from meterbridge, may be wrong, I'm not buying standards, event if they cost $45
76 # If someone has the standard, please either share it with me or fix the code.
77 class IEC268(Base):
78     '''IEC 60268-18 Peak programme level meters - Digital audio peak level meter'''
79     def __init__(self):
80         Base.__init__(self, "iec_268",
81                       "IEC 60268-18 Peak programme level meters - Digital audio peak level meter")
82         self.add_threshold(-70.0, 0.0, False)
83         self.add_threshold(-60.0, 0.05, True)
84         self.add_threshold(-50.0, 0.075, True)
85         self.add_threshold(-40.0, 0.15, True)
86         self.add_mark(-35.0)
87         self.add_threshold(-30.0, 0.3, True)
88         self.add_mark(-25.0)
89         self.add_threshold(-20.0, 0.5, True)
90         self.add_mark(-15.0)
91         self.add_mark(-10.0)
92         self.add_mark(-5.0)
93         self.add_threshold(0.0, 1.0, True)
94         self.calculate_coefficients()
95         self.scale_marks()
96
97
98 class IEC268Minimalistic(Base):
99     '''IEC 60268-18 Peak programme level meters - Digital audio peak level meter,
100        fewer marks'''
101     def __init__(self):
102         Base.__init__(self, 'iec_268_minimalistic',
103                       'IEC 60268-18 Peak programme level meters - Digital audio peak level meter, fewer marks')
104         self.add_threshold(-70.0, 0.0, False)
105         self.add_threshold(-60.0, 0.05, True)
106         self.add_threshold(-50.0, 0.075, False)
107         self.add_threshold(-40.0, 0.15, True)
108         self.add_threshold(-30.0, 0.3, True)
109         self.add_threshold(-20.0, 0.5, True)
110         self.add_mark(-10.0)
111         self.add_threshold(0.0, 1.0, True)
112         self.calculate_coefficients()
113         self.scale_marks()
114
115
116 class Linear70dB(Base):
117     '''Linear scale with range from -70 to 0 dBFS'''
118     def __init__(self):
119         Base.__init__(self, "linear_70dB", "Linear scale with range from -70 to 0 dBFS")
120         self.add_threshold(-70.0, 0.0, False)
121         self.add_mark(-60.0)
122         self.add_mark(-50.0)
123         self.add_mark(-40.0)
124         self.add_mark(-35.0)
125         self.add_mark(-30.0)
126         self.add_mark(-25.0)
127         self.add_mark(-20.0)
128         self.add_mark(-15.0)
129         self.add_mark(-10.0)
130         self.add_mark(-5.0)
131         self.add_threshold(0.0, 1.0, True)
132         self.calculate_coefficients()
133         self.scale_marks()
134
135
136 class Linear30dB(Base):
137     '''Linear scale with range from -30 to +30 dBFS'''
138     def __init__(self):
139         Base.__init__(self, "linear_30dB", "Linear scale with range from -30 to +30 dBFS")
140         self.add_threshold(-30.0, 0.0, False)
141         self.add_threshold(+30.0, 1.0, True)
142         self.calculate_coefficients()
143         self.scale_marks()
144
145 class K20(Base):
146     '''K20 scale'''
147     def __init__(self):
148         Base.__init__(self, "K20", "K20 scale")
149         self.add_mark(-200, "")
150         self.add_mark(-60, "-40")
151         self.add_mark(-55, "")
152         self.add_mark(-50, "-30")
153         self.add_mark(-45, "")
154         self.add_mark(-40, "-20")
155         self.add_mark(-35, "")
156         self.add_mark(-30, "-10")
157         self.add_mark(-26, "-6")
158         self.add_mark(-23, "-3")
159         self.add_mark(-20, "0")
160         self.add_mark(-17, "3")
161         self.add_mark(-14, "6")
162         self.add_mark(-10, "10")
163         self.add_mark(-5, "15")
164         self.add_mark(0, "20")
165
166     def db_to_scale(self, db):
167         v = math.pow(10.0, db/20.0)
168         return self.mapk20(v)/450.0
169
170     def add_mark(self, db, text):
171         self.marks.append(Mark(db, self.db_to_scale(db), text))
172
173     def mapk20(self, v):
174         if v < 0.001: return (24000 * v)
175         v = math.log10(v) + 3
176         if v < 2.0: return (24.3 + v * (100 + v * 16))
177         if v > 3.0: v = 3.0
178         return (v * 161.7 - 35.1)
179
180
181 class K14(Base):
182     '''K14 scale'''
183     def __init__(self):
184         Base.__init__(self, "K14", "K14 scale")
185         self.add_mark(-200, "")
186         self.add_mark(-54, "-40")
187         self.add_mark(-35-14, "")
188         self.add_mark(-30-14, "-30")
189         self.add_mark(-25-14, "")
190         self.add_mark(-20-14, "-20")
191         self.add_mark(-15-14, "")
192         self.add_mark(-10-14, "-10")
193         self.add_mark(-6-14, "-6")
194         self.add_mark(-3-14, "-3")
195         self.add_mark(-14, "0")
196         self.add_mark(3-14, "3")
197         self.add_mark(6-14, "6")
198         self.add_mark(10-14, "10")
199         self.add_mark(14-14, "14")
200
201     def db_to_scale(self, db):
202         v = math.pow(10.0, db/20.0)
203         return self.mapk14(v)/448.3
204
205     def add_mark(self, db, text):
206         self.marks.append(Mark(db, self.db_to_scale(db), text))
207
208     def mapk14(self, v):
209         if v < 0.002: return int(12000 * v);
210         v = math.log10(v) + 2.7;
211         if v < 2.0: return int(20.3 + v * (80 + v * 32));
212         if v > 2.7: v = 2.7;
213         return int(v * 200 - 91.7);
214
215 def scale_test1(scale):
216     for i in range(-97 * 2, 1, 1):
217         db = float(i)/2.0
218         print("%5.1f dB maps to %f" % (db, scale.db_to_scale(db)))
219
220
221 def scale_test2(scale):
222     for i in range(101):
223         s = float(i)/100.0
224         print("%.2f maps to %.1f dB" % (s, scale.scale_to_db(s)))
225
226
227 def print_db_to_scale(scale, db):
228     print("%-.1f dB maps to %f" % (db, scale.db_to_scale(db)))
229
230
231 def scale_test3(scale):
232     print_db_to_scale(scale, +77.0)
233     print_db_to_scale(scale, +7.0)
234     print_db_to_scale(scale, 0.0)
235     print_db_to_scale(scale, -107.0)
236
237
238 def _test(*args, **kwargs):
239     scale = Linear30dB()
240     scale_test1(scale)
241     scale_test2(scale)
242     scale_test3(scale)
243
244
245 if __name__ == '__main__':
246     _test()