1 |
# |
---|
2 |
# Copyright (c) 2013 by Takashi Sakamoto |
---|
3 |
# Copyright (C) 2005-2008 by Pieter Palmers |
---|
4 |
# |
---|
5 |
# This file is part of FFADO |
---|
6 |
# FFADO = Free FireWire (pro-)audio drivers for Linux |
---|
7 |
# |
---|
8 |
# FFADO is based upon FreeBoB. |
---|
9 |
# |
---|
10 |
# This program is free software: you can redistribute it and/or modify |
---|
11 |
# it under the terms of the GNU General Public License as published by |
---|
12 |
# the Free Software Foundation, either version 2 of the License, or |
---|
13 |
# (at your option) version 3 of the License. |
---|
14 |
# |
---|
15 |
# This program is distributed in the hope that it will be useful, |
---|
16 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
17 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
18 |
# GNU General Public License for more details. |
---|
19 |
# |
---|
20 |
# You should have received a copy of the GNU General Public License |
---|
21 |
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
---|
22 |
# |
---|
23 |
|
---|
24 |
# from PyQt4.QtCore import Qt |
---|
25 |
# from PyQt4.QtGui import QSizePolicy, QHBoxLayout, QVBoxLayout, QGroupBox |
---|
26 |
# from PyQt4.QtGui import QWidget, QTabWidget, QLabel, QSlider, QToolButton |
---|
27 |
from ffado.import_pyqt import * |
---|
28 |
|
---|
29 |
from math import log10 |
---|
30 |
from ffado.config import * |
---|
31 |
|
---|
32 |
import logging |
---|
33 |
log = logging.getLogger('MAudioBeBoB') |
---|
34 |
|
---|
35 |
class MAudio_BeBoB_Input_Widget(QWidget): |
---|
36 |
def __init__(self, parent=None): |
---|
37 |
QWidget.__init__(self, parent) |
---|
38 |
uicLoad("ffado/mixer/maudio_bebob_input", self) |
---|
39 |
|
---|
40 |
class MAudio_BeBoB_Output_Widget(QWidget): |
---|
41 |
def __init__(self, parent=None): |
---|
42 |
QWidget.__init__(self, parent) |
---|
43 |
uicLoad("ffado/mixer/maudio_bebob_output", self) |
---|
44 |
|
---|
45 |
|
---|
46 |
class MAudio_BeBoB(QWidget): |
---|
47 |
def __init__(self, parent=None): |
---|
48 |
QWidget.__init__(self, parent) |
---|
49 |
|
---|
50 |
info = { |
---|
51 |
0x0000000a: (0, "Ozonic"), |
---|
52 |
0x00010062: (1, "FireWire Solo"), |
---|
53 |
0x00010060: (2, "FireWire Audiophile"), |
---|
54 |
0x00010046: (3, "FireWire 410"), |
---|
55 |
0x00010071: (4, "FireWire 1814"), |
---|
56 |
0x00010091: (4, "ProjectMix I/O"), |
---|
57 |
} |
---|
58 |
|
---|
59 |
labels = ( |
---|
60 |
{ |
---|
61 |
"inputs": ("Analog 1/2", "Analog 3/4", |
---|
62 |
"Stream 1/2", "Stream 3/4"), |
---|
63 |
"mixers": ("Mixer 1/2", "Mixer 3/4"), |
---|
64 |
"outputs": ("Analog 1/2", "Analog 3/4") |
---|
65 |
}, |
---|
66 |
{ |
---|
67 |
"inputs": ("Analog 1/2", "Digital 1/2", |
---|
68 |
"Stream 1/2", "Stream 3/4"), |
---|
69 |
"mixers": ("Mixer 1/2", "Mixer 3/4"), |
---|
70 |
"outputs": ("Analog 1/2", "Digital 1/2") |
---|
71 |
}, |
---|
72 |
{ |
---|
73 |
"inputs": ("Analog 1/2", "Digital 1/2", |
---|
74 |
"Stream 1/2", "Stream 3/4", "Stream 5/6"), |
---|
75 |
"mixers": ("Mixer 1/2", "Mixer 3/4", "Mixer 5/6", "Aux 1/2"), |
---|
76 |
"outputs": ("Analog 1/2", "Analog 3/4", "Digital 1/2", |
---|
77 |
"Headphone 1/2") |
---|
78 |
}, |
---|
79 |
{ |
---|
80 |
"inputs": ("Analog 1/2", "Digital 1/2", |
---|
81 |
"Stream 1/2", "Stream 3/4", "Stream 5/6", |
---|
82 |
"Stream 7/8", "Stream 9/10"), |
---|
83 |
"mixers": ("Mixer 1/2", "Mixer 3/4", "Mixer 5/6", "Mixer 7/8", |
---|
84 |
"Mixer 9/10", "Aux 1/2"), |
---|
85 |
"outputs": ("Analog 1/2", "Analog 3/4", "Analog 5/6", "Analog 7/8", |
---|
86 |
"Digital 1/2", "Headphone 1/2") |
---|
87 |
}, |
---|
88 |
{ |
---|
89 |
"inputs": ("Analog 1/2", "Analog 3/4", "Analog 5/6", "Analog 7/8", |
---|
90 |
"Stream 1/2", "Stream 3/4", "S/PDIF 1/2", |
---|
91 |
"ADAT 1/2", "ADAT 3/4", "ADAT 5/6", "ADAT 7/8"), |
---|
92 |
"mixers": ("Mixer 1/2", "Mixer 3/4", "Aux 1/2"), |
---|
93 |
"outputs": ("Analog 1/2", "Analog 3/4", |
---|
94 |
"Headphone 1/2", "Headphone 3/4") |
---|
95 |
} |
---|
96 |
) |
---|
97 |
|
---|
98 |
# hardware inputs and stream playbacks |
---|
99 |
# format: function_id/channel_idx/panning-able |
---|
100 |
# NOTE: function_id = channel_idx = panning-able = labels["inputs"] |
---|
101 |
inputs = ( |
---|
102 |
( |
---|
103 |
(0x03, 0x04, 0x01, 0x02), |
---|
104 |
((0x01, 0x02), (0x01, 0x02), (0x01, 0x02), (0x01, 0x02)), |
---|
105 |
(True, True, False, False) |
---|
106 |
), |
---|
107 |
( |
---|
108 |
(0x01, 0x02, 0x04, 0x03), |
---|
109 |
((0x01, 0x02), (0x01, 0x02), (0x01, 0x02), (0x01, 0x02)), |
---|
110 |
(True, True, False, False) |
---|
111 |
), |
---|
112 |
( |
---|
113 |
(0x04, 0x05, 0x01, 0x02, 0x03), |
---|
114 |
((0x01, 0x02), (0x01, 0x02), |
---|
115 |
(0x01, 0x02), (0x01, 0x02), (0x01, 0x02)), |
---|
116 |
(True, True, False, False, False) |
---|
117 |
), |
---|
118 |
( |
---|
119 |
(0x03, 0x04, 0x02, 0x01, 0x01, 0x01, 0x01), |
---|
120 |
((0x01, 0x02), (0x01, 0x02), (0x01, 0x02), |
---|
121 |
(0x01, 0x02), (0x03, 0x04), (0x05, 0x06), (0x07, 0x08)), |
---|
122 |
(True, True, False, False, False, False, False) |
---|
123 |
), |
---|
124 |
( |
---|
125 |
(0x01, 0x02, 0x03, 0x04, 0x0a, 0x0b, 0x05, 0x06, 0x07, 0x08, 0x09), |
---|
126 |
((0x01, 0x02), (0x01, 0x02), (0x01, 0x02), (0x01, 0x02), |
---|
127 |
(0x01, 0x02), (0x01, 0x02), (0x01, 0x02), |
---|
128 |
(0x01, 0x02), (0x01, 0x02), (0x01, 0x02), (0x01, 0x02)), |
---|
129 |
(True, True, True, True, False, False, True, |
---|
130 |
True, True, True, True) |
---|
131 |
) |
---|
132 |
) |
---|
133 |
|
---|
134 |
# jack sources except for headphone |
---|
135 |
# format: function_id/source id |
---|
136 |
# NOTE: "function_id" = labels["output"] - "Headphone 1/2/3/4" |
---|
137 |
# NOTE: "source_id" = labels["mixer"] |
---|
138 |
jack_src = ( |
---|
139 |
None, |
---|
140 |
None, |
---|
141 |
((0x01, 0x02, 0x03), |
---|
142 |
(0x00, 0x00, 0x00, 0x01)), |
---|
143 |
((0x02, 0x03, 0x04, 0x05, 0x06), |
---|
144 |
(0x00, 0x00, 0x00, 0x00, 0x00, 0x01)), |
---|
145 |
((0x03, 0x04), |
---|
146 |
(0x00, 0x01, 0x02)) |
---|
147 |
) |
---|
148 |
|
---|
149 |
# headphone sources |
---|
150 |
# format: sink id/source id |
---|
151 |
# NOTE: "source_id" = labels["mixer"] |
---|
152 |
hp_src = ( |
---|
153 |
None, |
---|
154 |
None, |
---|
155 |
((0x04,), |
---|
156 |
(0x00, 0x01, 0x02, 0x03)), |
---|
157 |
((0x07,), |
---|
158 |
(0x02, 0x03, 0x04, 0x05, 0x06, 0x07)), |
---|
159 |
((0x01, 0x02), |
---|
160 |
(0x01, 0x02, 0x04)) |
---|
161 |
) |
---|
162 |
|
---|
163 |
# hardware outputs |
---|
164 |
# format: function id |
---|
165 |
# NOTE: "function_id" = labels["output"] |
---|
166 |
outputs = ( |
---|
167 |
(0x05, 0x06), |
---|
168 |
(0x02, 0x03), |
---|
169 |
(0x0c, 0x0d, 0x0e, 0x0f), |
---|
170 |
(0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f), |
---|
171 |
(0x0c, 0x0d, 0x0f, 0x10) |
---|
172 |
) |
---|
173 |
|
---|
174 |
# Mixer inputs/outputs |
---|
175 |
# format: function_id/out_stereo_channel_id/in_id/in_stereo_channel_id |
---|
176 |
# NOTE: function_id = out_stereo_channel_id = labels["mixers"] |
---|
177 |
# NOTE: in_id = in_stereo_channel_id = labels["inputs"] |
---|
178 |
mixers = ( |
---|
179 |
( |
---|
180 |
(0x01, 0x02), |
---|
181 |
((0x01, 0x02), (0x01, 0x02)), |
---|
182 |
(0x02, 0x03, 0x00, 0x01), |
---|
183 |
((0x01, 0x02), (0x01, 0x02), (0x01, 0x02), (0x01, 0x02)) |
---|
184 |
), |
---|
185 |
( |
---|
186 |
(0x01, 0x01), |
---|
187 |
((0x01, 0x02), (0x03, 0x04)), |
---|
188 |
(0x00, 0x01, 0x03, 0x02), |
---|
189 |
((0x01, 0x02), (0x01, 0x02), (0x01, 0x02), (0x01, 0x02)) |
---|
190 |
), |
---|
191 |
( |
---|
192 |
(0x01, 0x02, 0x03, 0x04), |
---|
193 |
((0x01, 0x02), (0x01, 0x02), (0x01, 0x02), (0x01, 0x02)), |
---|
194 |
(0x03, 0x04, 0x00, 0x01, 0x02), |
---|
195 |
((0x01, 0x02), (0x01, 0x02), (0x01, 0x02), |
---|
196 |
(0x01, 0x02), (0x01, 0x02)) |
---|
197 |
), |
---|
198 |
( |
---|
199 |
(0x01, 0x01, 0x01, 0x01, 0x01, 0x07), |
---|
200 |
((0x01, 0x02), (0x03, 0x04), |
---|
201 |
(0x05, 0x06), (0x07, 0x08), (0x09, 0x0a), (0x01, 0x02)), |
---|
202 |
(0x02, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00), |
---|
203 |
((0x01, 0x02), (0x01, 0x02), |
---|
204 |
(0x01, 0x02), (0x01, 0x02), (0x03, 0x04), |
---|
205 |
(0x05, 0x06), (0x07, 0x08)) |
---|
206 |
), |
---|
207 |
( |
---|
208 |
(0x01, 0x02, 0x03), |
---|
209 |
((0x01, 0x02), (0x01, 0x02), (0x01, 0x02)), |
---|
210 |
(0x01, 0x01, 0x01, 0x01, |
---|
211 |
0x02, 0x02, 0x03, |
---|
212 |
0x04, 0x04, 0x04, 0x04), |
---|
213 |
((0x01, 0x02), (0x03, 0x04), (0x05, 0x06), (0x07, 0x08), |
---|
214 |
(0x01, 0x02), (0x03, 0x04), (0x01, 0x02), |
---|
215 |
(0x01, 0x02), (0x03, 0x04), (0x05, 0x06), (0x07, 0x08)) |
---|
216 |
) |
---|
217 |
) |
---|
218 |
|
---|
219 |
# Aux mixer inputs/outputs |
---|
220 |
# format: function_id/input_id/input_stereo_channel_id |
---|
221 |
# NOTE: input_id = labels["inputs"] |
---|
222 |
aux = ( |
---|
223 |
None, |
---|
224 |
None, |
---|
225 |
( |
---|
226 |
0x0b, |
---|
227 |
(0x09, 0x0a, 0x06, 0x07, 0x08), |
---|
228 |
((0x01, 0x02), (0x01, 0x02), |
---|
229 |
(0x01, 0x02), (0x01, 0x02), (0x01, 0x02)) |
---|
230 |
), |
---|
231 |
( |
---|
232 |
0x09, |
---|
233 |
(0x07, 0x08, 0x06, 0x05, 0x05, 0x05, 0x05), |
---|
234 |
((0x01, 0x02), (0x01, 0x02), (0x01, 0x02), |
---|
235 |
(0x01, 0x02), (0x03, 0x04), (0x05, 0x06), (0x07, 0x08)) |
---|
236 |
), |
---|
237 |
( |
---|
238 |
0x0e, |
---|
239 |
(0x13, 0x14, 0x15, 0x16, 0x11, 0x12, 0x17, 0x18, 0x19, 0x1a, 0x1b), |
---|
240 |
((0x01, 0x02), (0x01, 0x02), (0x01, 0x02), (0x01, 0x02), |
---|
241 |
(0x01, 0x02), (0x01, 0x02), (0x01, 0x02), |
---|
242 |
(0x01, 0x02), (0x01, 0x02), (0x01, 0x02), (0x01, 0x02)) |
---|
243 |
) |
---|
244 |
) |
---|
245 |
|
---|
246 |
def getDisplayTitle(self): |
---|
247 |
model = self.configrom.getModelId() |
---|
248 |
return self.info[model][1] |
---|
249 |
|
---|
250 |
def buildMixer(self): |
---|
251 |
self.Selectors = {} |
---|
252 |
self.Pannings = {} |
---|
253 |
self.Volumes = {} |
---|
254 |
self.Mutes = {} |
---|
255 |
self.Mixers = {} |
---|
256 |
self.FW410HP = 0 |
---|
257 |
|
---|
258 |
model = self.configrom.getModelId() |
---|
259 |
if model not in self.info: |
---|
260 |
return |
---|
261 |
|
---|
262 |
self.id = self.info[model][0] |
---|
263 |
|
---|
264 |
tabs_layout = QHBoxLayout(self) |
---|
265 |
tabs = QTabWidget(self) |
---|
266 |
|
---|
267 |
self.addInputTab(tabs) |
---|
268 |
self.addMixTab(tabs) |
---|
269 |
if self.aux[self.id] is not None: |
---|
270 |
self.addAuxTab(tabs) |
---|
271 |
self.addOutputTab(tabs) |
---|
272 |
|
---|
273 |
tabs_layout.addWidget(tabs) |
---|
274 |
|
---|
275 |
|
---|
276 |
def addInputTab(self, tabs): |
---|
277 |
tab_input = QWidget(self) |
---|
278 |
tabs.addTab(tab_input, "In") |
---|
279 |
|
---|
280 |
tab_input_layout = QHBoxLayout() |
---|
281 |
tab_input.setLayout(tab_input_layout) |
---|
282 |
|
---|
283 |
in_labels = self.labels[self.id]["inputs"] |
---|
284 |
in_ids = self.inputs[self.id][0] |
---|
285 |
in_pan = self.inputs[self.id][2] |
---|
286 |
|
---|
287 |
for i in range(len(in_ids)): |
---|
288 |
l_idx = self.inputs[self.id][1][i][0] |
---|
289 |
r_idx = self.inputs[self.id][1][i][1] |
---|
290 |
|
---|
291 |
widget = MAudio_BeBoB_Input_Widget(tab_input) |
---|
292 |
tab_input_layout.addWidget(widget) |
---|
293 |
|
---|
294 |
widget.name.setText(in_labels[i]) |
---|
295 |
|
---|
296 |
self.Volumes[widget.l_sld] = ( |
---|
297 |
"/Mixer/Feature_Volume_%d" % in_ids[i], l_idx, |
---|
298 |
widget.r_sld, r_idx, |
---|
299 |
widget.link |
---|
300 |
) |
---|
301 |
self.Volumes[widget.r_sld] = ( |
---|
302 |
"/Mixer/Feature_Volume_%d" % in_ids[i], r_idx, |
---|
303 |
widget.l_sld, l_idx, |
---|
304 |
widget.link |
---|
305 |
) |
---|
306 |
self.Mutes[widget.mute] = (widget.l_sld, widget.r_sld) |
---|
307 |
|
---|
308 |
if not in_pan[i]: |
---|
309 |
widget.l_pan.setDisabled(True) |
---|
310 |
widget.r_pan.setDisabled(True) |
---|
311 |
else: |
---|
312 |
self.Pannings[widget.l_pan] = ( |
---|
313 |
"/Mixer/Feature_LRBalance_%d" % in_ids[i], |
---|
314 |
l_idx |
---|
315 |
) |
---|
316 |
self.Pannings[widget.r_pan] = ( |
---|
317 |
"/Mixer/Feature_LRBalance_%d" % in_ids[i], |
---|
318 |
r_idx |
---|
319 |
) |
---|
320 |
|
---|
321 |
tab_input_layout.addStretch() |
---|
322 |
|
---|
323 |
|
---|
324 |
def addMixTab(self, tabs): |
---|
325 |
tab_mix = QWidget(self) |
---|
326 |
tabs.addTab(tab_mix, "Mix") |
---|
327 |
|
---|
328 |
tab_layout = QHBoxLayout() |
---|
329 |
tab_mix.setLayout(tab_layout) |
---|
330 |
|
---|
331 |
in_labels = self.labels[self.id]["inputs"] |
---|
332 |
in_idxs = self.inputs[self.id][0] |
---|
333 |
|
---|
334 |
mix_labels = self.labels[self.id]["mixers"] |
---|
335 |
mix_idxs = self.mixers[self.id][0] |
---|
336 |
|
---|
337 |
for i in range(len(mix_idxs)): |
---|
338 |
if mix_labels[i] == 'Aux 1/2': |
---|
339 |
continue |
---|
340 |
|
---|
341 |
grp = QGroupBox(tab_mix) |
---|
342 |
grp_layout = QVBoxLayout() |
---|
343 |
grp.setLayout(grp_layout) |
---|
344 |
tab_layout.addWidget(grp) |
---|
345 |
|
---|
346 |
label = QLabel(grp) |
---|
347 |
grp_layout.addWidget(label) |
---|
348 |
|
---|
349 |
label.setText(mix_labels[i]) |
---|
350 |
label.setAlignment(Qt.AlignCenter) |
---|
351 |
label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum) |
---|
352 |
|
---|
353 |
for j in range(len(in_idxs)): |
---|
354 |
mix_in_id = self.mixers[self.id][2][j] |
---|
355 |
|
---|
356 |
button = QToolButton(grp) |
---|
357 |
grp_layout.addWidget(button) |
---|
358 |
|
---|
359 |
button.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum) |
---|
360 |
button.setText('%s In' % in_labels[j]) |
---|
361 |
button.setCheckable(True) |
---|
362 |
|
---|
363 |
self.Mixers[button] = ( |
---|
364 |
"/Mixer/EnhancedMixer_%d" % mix_idxs[i], |
---|
365 |
mix_in_id, j, i |
---|
366 |
) |
---|
367 |
|
---|
368 |
grp_layout.addStretch() |
---|
369 |
tab_layout.addStretch() |
---|
370 |
|
---|
371 |
def addAuxTab(self, tabs): |
---|
372 |
#local functions |
---|
373 |
def addLinkButton(parent, layout): |
---|
374 |
button = QToolButton(parent) |
---|
375 |
layout.addWidget(button) |
---|
376 |
button.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum) |
---|
377 |
button.setText('Link') |
---|
378 |
button.setCheckable(True) |
---|
379 |
return button |
---|
380 |
def addMuteButton(parent, layout): |
---|
381 |
button = QToolButton(parent) |
---|
382 |
layout.addWidget(button) |
---|
383 |
button.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum) |
---|
384 |
button.setText('Mute') |
---|
385 |
button.setCheckable(True) |
---|
386 |
return button |
---|
387 |
|
---|
388 |
# local processing |
---|
389 |
tab_aux = QWidget(self) |
---|
390 |
tabs.addTab(tab_aux, "Aux") |
---|
391 |
|
---|
392 |
layout = QHBoxLayout() |
---|
393 |
tab_aux.setLayout(layout) |
---|
394 |
|
---|
395 |
aux_label = self.labels[self.id]["mixers"][-1] |
---|
396 |
aux_id = self.aux[self.id][0] |
---|
397 |
|
---|
398 |
aux_in_labels = self.labels[self.id]["inputs"] |
---|
399 |
aux_in_ids = self.aux[self.id][1] |
---|
400 |
|
---|
401 |
for i in range(len(aux_in_ids)): |
---|
402 |
in_ch_l = self.aux[self.id][2][i][0] |
---|
403 |
in_ch_r = self.aux[self.id][2][i][1] |
---|
404 |
|
---|
405 |
grp = QGroupBox(tab_aux) |
---|
406 |
grp_layout = QVBoxLayout() |
---|
407 |
grp.setLayout(grp_layout) |
---|
408 |
layout.addWidget(grp) |
---|
409 |
|
---|
410 |
label = QLabel(grp) |
---|
411 |
grp_layout.addWidget(label) |
---|
412 |
label.setText("%s\nIn" % aux_in_labels[i]) |
---|
413 |
label.setAlignment(Qt.AlignCenter) |
---|
414 |
|
---|
415 |
grp_sld = QGroupBox(grp) |
---|
416 |
grp_sld_layout = QHBoxLayout() |
---|
417 |
grp_sld.setLayout(grp_sld_layout) |
---|
418 |
grp_layout.addWidget(grp_sld) |
---|
419 |
|
---|
420 |
l_sld = QSlider(grp_sld) |
---|
421 |
grp_sld_layout.addWidget(l_sld) |
---|
422 |
r_sld = QSlider(grp_sld) |
---|
423 |
grp_sld_layout.addWidget(r_sld) |
---|
424 |
|
---|
425 |
button = addLinkButton(grp, grp_layout) |
---|
426 |
self.Volumes[l_sld] = ( |
---|
427 |
"/Mixer/Feature_Volume_%d" % aux_in_ids[i], in_ch_l, |
---|
428 |
r_sld, in_ch_r, |
---|
429 |
button |
---|
430 |
) |
---|
431 |
self.Volumes[r_sld] = ( |
---|
432 |
"/Mixer/Feature_Volume_%d" % aux_in_ids[i], in_ch_r, |
---|
433 |
l_sld, in_ch_l, |
---|
434 |
button |
---|
435 |
) |
---|
436 |
|
---|
437 |
button = addMuteButton(grp, grp_layout) |
---|
438 |
self.Mutes[button] = (l_sld, r_sld) |
---|
439 |
|
---|
440 |
grp = QGroupBox(tab_aux) |
---|
441 |
grp_layout = QVBoxLayout() |
---|
442 |
grp.setLayout(grp_layout) |
---|
443 |
layout.addWidget(grp) |
---|
444 |
|
---|
445 |
label = QLabel(grp) |
---|
446 |
grp_layout.addWidget(label) |
---|
447 |
label.setText("%s\nOut" % aux_label) |
---|
448 |
label.setAlignment(Qt.AlignCenter) |
---|
449 |
|
---|
450 |
grp_sld = QGroupBox(grp) |
---|
451 |
grp_sld_layout = QHBoxLayout() |
---|
452 |
grp_sld.setLayout(grp_sld_layout) |
---|
453 |
grp_layout.addWidget(grp_sld) |
---|
454 |
|
---|
455 |
l_sld = QSlider(grp_sld) |
---|
456 |
grp_sld_layout.addWidget(l_sld) |
---|
457 |
r_sld = QSlider(grp_sld) |
---|
458 |
grp_sld_layout.addWidget(r_sld) |
---|
459 |
|
---|
460 |
button = addLinkButton(grp, grp_layout) |
---|
461 |
self.Volumes[l_sld] = ( |
---|
462 |
"/Mixer/Feature_Volume_%d" % aux_id, 1, |
---|
463 |
r_sld, 2, |
---|
464 |
button |
---|
465 |
) |
---|
466 |
self.Volumes[r_sld] = ( |
---|
467 |
"/Mixer/Feature_Volume_%d" % aux_id, 2, |
---|
468 |
l_sld, 1, |
---|
469 |
button |
---|
470 |
) |
---|
471 |
|
---|
472 |
button = addMuteButton(grp, grp_layout) |
---|
473 |
self.Mutes[button] = (l_sld, r_sld) |
---|
474 |
|
---|
475 |
layout.addStretch() |
---|
476 |
|
---|
477 |
def addOutputTab(self, tabs): |
---|
478 |
tab_out = QWidget(self) |
---|
479 |
tabs.addTab(tab_out, "Out") |
---|
480 |
|
---|
481 |
layout = QHBoxLayout() |
---|
482 |
tab_out.setLayout(layout) |
---|
483 |
|
---|
484 |
out_labels = self.labels[self.id]["outputs"] |
---|
485 |
out_ids = self.outputs[self.id] |
---|
486 |
|
---|
487 |
mixer_labels = self.labels[self.id]["mixers"] |
---|
488 |
|
---|
489 |
if self.jack_src[self.id] is None: |
---|
490 |
for i in range(len(out_ids)): |
---|
491 |
label = QLabel(tab_out) |
---|
492 |
layout.addWidget(label) |
---|
493 |
label.setText("%s Out is fixed to %s Out" % |
---|
494 |
(mixer_labels[i], out_labels[i])) |
---|
495 |
return |
---|
496 |
|
---|
497 |
mixer_ids = self.jack_src[self.id][1] |
---|
498 |
|
---|
499 |
|
---|
500 |
for i in range(len(out_ids)): |
---|
501 |
out_label = out_labels[i] |
---|
502 |
if out_label.find('Headphone') >= 0: |
---|
503 |
continue |
---|
504 |
|
---|
505 |
out_id = self.jack_src[self.id][0][i] |
---|
506 |
|
---|
507 |
widget = MAudio_BeBoB_Output_Widget(tab_out) |
---|
508 |
layout.addWidget(widget) |
---|
509 |
|
---|
510 |
widget.name.setText(out_label) |
---|
511 |
|
---|
512 |
self.Volumes[widget.l_sld] = ( |
---|
513 |
"/Mixer/Feature_Volume_%d" % out_ids[i], 1, |
---|
514 |
widget.r_sld, 2, |
---|
515 |
widget.link |
---|
516 |
) |
---|
517 |
self.Volumes[widget.r_sld] = ( |
---|
518 |
"/Mixer/Feature_Volume_%d" % out_ids[i], 2, |
---|
519 |
widget.l_sld, 1, |
---|
520 |
widget.link |
---|
521 |
) |
---|
522 |
self.Mutes[widget.mute] = (widget.l_sld, widget.r_sld) |
---|
523 |
|
---|
524 |
self.Selectors[widget.cmb_src] = ("/Mixer/Selector_%d" % out_id, ) |
---|
525 |
|
---|
526 |
for j in range(len(mixer_ids)): |
---|
527 |
if i != j and j != len(mixer_ids) - 1: |
---|
528 |
continue |
---|
529 |
widget.cmb_src.addItem("%s Out" % mixer_labels[j], mixer_ids[j]) |
---|
530 |
|
---|
531 |
# add headphone |
---|
532 |
hp_idx = 0 |
---|
533 |
for i in range(len(out_ids)): |
---|
534 |
out_label = out_labels[i] |
---|
535 |
if out_label.find('Headphone') < 0: |
---|
536 |
continue |
---|
537 |
|
---|
538 |
hp_label = self.labels[self.id]["outputs"][i] |
---|
539 |
hp_id = self.hp_src[self.id][0][hp_idx] |
---|
540 |
hp_idx += 1 |
---|
541 |
|
---|
542 |
mixer_labels = self.labels[self.id]["mixers"] |
---|
543 |
|
---|
544 |
widget = MAudio_BeBoB_Output_Widget(tab_out) |
---|
545 |
layout.addWidget(widget) |
---|
546 |
|
---|
547 |
widget.name.setText(hp_label) |
---|
548 |
|
---|
549 |
mixer_labels = self.labels[self.id]["mixers"] |
---|
550 |
mixer_ids = self.mixers[self.id][0] |
---|
551 |
|
---|
552 |
self.Volumes[widget.l_sld] = ( |
---|
553 |
"/Mixer/Feature_Volume_%d" % out_ids[i], 1, |
---|
554 |
widget.r_sld, 2, |
---|
555 |
widget.link |
---|
556 |
) |
---|
557 |
self.Volumes[widget.r_sld] = ( |
---|
558 |
"/Mixer/Feature_Volume_%d" % out_ids[i], 2, |
---|
559 |
widget.l_sld, 1, |
---|
560 |
widget.link |
---|
561 |
) |
---|
562 |
self.Mutes[widget.mute] = (widget.l_sld, widget.r_sld) |
---|
563 |
|
---|
564 |
for i in range(len(mixer_ids)): |
---|
565 |
widget.cmb_src.addItem("%s Out" % mixer_labels[i], mixer_ids[i]) |
---|
566 |
|
---|
567 |
if self.id != 3: |
---|
568 |
self.Selectors[widget.cmb_src] = ("/Mixer/Selector_%d" % hp_id, ) |
---|
569 |
else: |
---|
570 |
widget.cmb_src.activated.connect(self.update410HP) |
---|
571 |
self.FW410HP = widget.cmb_src |
---|
572 |
|
---|
573 |
layout.addStretch() |
---|
574 |
|
---|
575 |
def initValues(self): |
---|
576 |
for ctl, params in list(self.Selectors.items()): |
---|
577 |
path = params[0] |
---|
578 |
state = self.hw.getDiscrete(path) |
---|
579 |
ctl.setCurrentIndex(state) |
---|
580 |
ctl.activated.connect(self.updateSelector) |
---|
581 |
|
---|
582 |
# Right - Center - Left |
---|
583 |
# 0x8000 - 0x0000 - 0x0001 - 0x7FFE |
---|
584 |
# ..., -1, 0, +1, ... |
---|
585 |
for ctl, params in list(self.Pannings.items()): |
---|
586 |
path = params[0] |
---|
587 |
idx = params[1] |
---|
588 |
curr = self.hw.getContignuous(path, idx) |
---|
589 |
state = -(curr / 0x7FFE) * 50 + 50 |
---|
590 |
ctl.setValue(state) |
---|
591 |
ctl.valueChanged.connect(self.updatePanning) |
---|
592 |
|
---|
593 |
for ctl, params in list(self.Volumes.items()): |
---|
594 |
path = params[0] |
---|
595 |
idx = params[1] |
---|
596 |
p_idx = params[3] |
---|
597 |
link = params[4] |
---|
598 |
|
---|
599 |
db = self.hw.getContignuous(path, idx) |
---|
600 |
vol = self.db2vol(db) |
---|
601 |
ctl.setValue(vol) |
---|
602 |
ctl.valueChanged.connect(self.updateVolume) |
---|
603 |
|
---|
604 |
# to activate link button, a pair is checked twice, sign... |
---|
605 |
pair_db = self.hw.getContignuous(path, p_idx) |
---|
606 |
if pair_db == db: |
---|
607 |
link.setChecked(True) |
---|
608 |
|
---|
609 |
for ctl, params in list(self.Mutes.items()): |
---|
610 |
ctl.clicked.connect(self.updateMute) |
---|
611 |
|
---|
612 |
for ctl, params in list(self.Mixers.items()): |
---|
613 |
path = params[0] |
---|
614 |
in_id = params[1] |
---|
615 |
mix_in_idx = params[2] |
---|
616 |
mix_out_idx = params[3] |
---|
617 |
in_ch_l = self.mixers[self.id][3][mix_in_idx][0] |
---|
618 |
out_ch_l = self.mixers[self.id][1][mix_out_idx][0] |
---|
619 |
# see /libffado/src/bebob/bebob_mixer.cpp |
---|
620 |
mux_id = self.getMultiplexedId(in_id, in_ch_l, out_ch_l) |
---|
621 |
curr = self.hw.getContignuous(path, mux_id) |
---|
622 |
if curr == 0: |
---|
623 |
state = True |
---|
624 |
else: |
---|
625 |
state = False |
---|
626 |
ctl.setChecked(state) |
---|
627 |
ctl.clicked.connect(self.updateMixer) |
---|
628 |
|
---|
629 |
if self.id == 3: |
---|
630 |
self.read410HP() |
---|
631 |
|
---|
632 |
# helper functions |
---|
633 |
def vol2db(self, vol): |
---|
634 |
return (log10(vol + 1) - 2) * 16384 |
---|
635 |
|
---|
636 |
def db2vol(self, db): |
---|
637 |
return pow(10, db / 16384 + 2) - 1 |
---|
638 |
|
---|
639 |
def getMultiplexedId(self, in_id, in_ch_l, out_ch_l): |
---|
640 |
# see /libffado/src/bebob/bebob_mixer.cpp |
---|
641 |
return (in_id << 8) | (in_ch_l << 4) | (out_ch_l << 0) |
---|
642 |
|
---|
643 |
def updateSelector(self, state): |
---|
644 |
sender = self.sender() |
---|
645 |
path = self.Selectors[sender][0] |
---|
646 |
log.debug("set %s to %d" % (path, state)) |
---|
647 |
self.hw.setDiscrete(path, state) |
---|
648 |
|
---|
649 |
def updatePanning(self, state): |
---|
650 |
sender = self.sender() |
---|
651 |
path = self.Pannings[sender][0] |
---|
652 |
idx = self.Pannings[sender][1] |
---|
653 |
value = (state - 50) * 0x7FFE / -50 |
---|
654 |
log.debug("set %s for %d to %d(%d)" % (path, idx, value, state)) |
---|
655 |
self.hw.setContignuous(path, value, idx) |
---|
656 |
|
---|
657 |
def updateVolume(self, vol): |
---|
658 |
sender = self.sender() |
---|
659 |
path = self.Volumes[sender][0] |
---|
660 |
idx = self.Volumes[sender][1] |
---|
661 |
pair = self.Volumes[sender][2] |
---|
662 |
link = self.Volumes[sender][4] |
---|
663 |
|
---|
664 |
db = self.vol2db(vol) |
---|
665 |
log.debug("set %s for %d to %d(%d)" % (path, idx, db, vol)) |
---|
666 |
self.hw.setContignuous(path, db, idx) |
---|
667 |
|
---|
668 |
if link.isChecked(): |
---|
669 |
pair.setValue(vol) |
---|
670 |
|
---|
671 |
# device remeber gain even if muted |
---|
672 |
def updateMute(self, state): |
---|
673 |
sender = self.sender() |
---|
674 |
l_sld = self.Mutes[sender][0] |
---|
675 |
r_sld = self.Mutes[sender][1] |
---|
676 |
|
---|
677 |
if state: |
---|
678 |
db = 0x8000 |
---|
679 |
else: |
---|
680 |
db = 0x0000 |
---|
681 |
for w in [l_sld, r_sld]: |
---|
682 |
path = self.Volumes[w][0] |
---|
683 |
self.hw.setContignuous(path, db) |
---|
684 |
w.setDisabled(state) |
---|
685 |
|
---|
686 |
def updateMixer(self, checked): |
---|
687 |
if checked: |
---|
688 |
state = 0x0000 |
---|
689 |
else: |
---|
690 |
state = 0x8000 |
---|
691 |
|
---|
692 |
sender = self.sender() |
---|
693 |
path = self.Mixers[sender][0] |
---|
694 |
in_id = self.Mixers[sender][1] |
---|
695 |
mix_in_idx = self.Mixers[sender][2] |
---|
696 |
mix_out_idx = self.Mixers[sender][3] |
---|
697 |
in_ch_l = self.mixers[self.id][3][mix_in_idx][0] |
---|
698 |
out_ch_l = self.mixers[self.id][1][mix_out_idx][0] |
---|
699 |
|
---|
700 |
mux_id = self.getMultiplexedId(in_id, in_ch_l, out_ch_l) |
---|
701 |
|
---|
702 |
log.debug("set %s for 0x%04X(%d/%d/%d) to %d" % |
---|
703 |
(path, mux_id, in_id, in_ch_l, out_ch_l, state)) |
---|
704 |
self.hw.setContignuous(path, state, mux_id) |
---|
705 |
|
---|
706 |
def read410HP(self): |
---|
707 |
path = "/Mixer/Selector_7" |
---|
708 |
sel = self.hw.getDiscrete(path) |
---|
709 |
if sel > 0: |
---|
710 |
enbl = 5 |
---|
711 |
else: |
---|
712 |
enbl = -1 |
---|
713 |
|
---|
714 |
path = "/Mixer/EnhancedMixer_7" |
---|
715 |
for i in range(5): |
---|
716 |
in_id = 0 |
---|
717 |
in_ch_l = i * 2 + 1 |
---|
718 |
out_ch_l = 1 |
---|
719 |
mux_id = self.getMultiplexedId(in_id, in_ch_l, out_ch_l) |
---|
720 |
state = self.hw.getContignuous(path, mux_id) |
---|
721 |
if enbl < 0 and state == 0: |
---|
722 |
enbl = i |
---|
723 |
else: |
---|
724 |
self.hw.setContignuous(path, 0x8000, mux_id) |
---|
725 |
# if inconsistency between Selector and Mixer, set AUX as default |
---|
726 |
if enbl == -1: |
---|
727 |
self.hw.setDiscrete('/Mixer/Selector_7', 1) |
---|
728 |
enbl = 5 |
---|
729 |
|
---|
730 |
self.FW410HP.setCurrentIndex(enbl) |
---|
731 |
|
---|
732 |
def update410HP(self, state): |
---|
733 |
# each output from mixer can be multiplexed in headphone |
---|
734 |
# but here they are exclusive because of GUI simpleness, sigh... |
---|
735 |
path = "/Mixer/EnhancedMixer_7" |
---|
736 |
for i in range(5): |
---|
737 |
in_id = 0 |
---|
738 |
in_ch_l = i * 2 + 1 |
---|
739 |
out_ch_l = 1 |
---|
740 |
mux_id = self.getMultiplexedId(in_id, in_ch_l, out_ch_l) |
---|
741 |
if i == state: |
---|
742 |
value = 0x0000 |
---|
743 |
else: |
---|
744 |
value = 0x8000 |
---|
745 |
self.hw.setContignuous(path, value, mux_id) |
---|
746 |
|
---|
747 |
# Mixer/Aux is selectable exclusively |
---|
748 |
path = "/Mixer/Selector_7" |
---|
749 |
sel = (state == 5) |
---|
750 |
self.hw.setDiscrete(path, sel) |
---|
751 |
|
---|