root/trunk/libffado/support/mixer-qt4/ffado/mixer/rme.py

Revision 2044, 13.6 kB (checked in by jwoithe, 12 years ago)

rme: make the bandwidth limit control do something. This is yet to be extensively tested. This change means that all the FF400 mixer controls are now implemented, although some are yet to be tested and verified as working.

  • Property svn:mergeinfo set to
Line 
1 #
2 # Copyright (C) 2009, 2011 by Jonathan Woithe
3 #
4 # This file is part of FFADO
5 # FFADO = Free Firewire (pro-)audio drivers for linux
6 #
7 # FFADO is based upon FreeBoB.
8 #
9 # This program is free software: you can redistribute it and/or modify
10 # it under the terms of the GNU General Public License as published by
11 # the Free Software Foundation, either version 2 of the License, or
12 # (at your option) version 3 of the License.
13 #
14 # This program is distributed in the hope that it will be useful,
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 # GNU General Public License for more details.
18 #
19 # You should have received a copy of the GNU General Public License
20 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 #
22
23 from PyQt4 import QtGui
24
25 from PyQt4.QtCore import SIGNAL, SLOT, QObject, Qt, QTimer
26 from PyQt4.QtGui import QWidget, QApplication
27 from ffado.config import *
28
29 from ffado.widgets.matrixmixer import MatrixMixer
30
31 import logging
32 log = logging.getLogger('rme')
33
34 # Model defines.  These must agree with what is used in rme_avdevice.h.
35 RME_MODEL_NONE      = 0x0000
36 RME_MODEL_FF800     = 0x0001
37 RME_MODEL_FF400     = 0x0002
38
39 class Rme(QWidget):
40     def __init__(self,parent = None):
41         QWidget.__init__(self,parent)
42         uicLoad("ffado/mixer/rme", self)
43
44         self.init()
45
46     def init(self):
47
48         self.PhantomSwitches={
49             self.phantom_0: ['/Control/Phantom', 0],
50             self.phantom_1: ['/Control/Phantom', 1],
51             self.phantom_2: ['/Control/Phantom', 2],
52             self.phantom_3: ['/Control/Phantom', 3],
53         }
54
55         self.Switches={
56             self.ff400_chan3_opt_instr: ['/Control/Chan3_opt_instr'],
57             self.ff400_chan3_opt_pad:   ['/Control/Chan3_opt_pad'],
58             self.ff400_chan4_opt_instr: ['/Control/Chan4_opt_instr'],
59             self.ff400_chan4_opt_pad:   ['/Control/Chan4_opt_pad'],
60
61             self.spdif_output_optical:  ['/Control/SPDIF_output_optical', 0],
62             self.spdif_output_emphasis: ['/Control/SPDIF_output_emphasis', 0],
63             self.spdif_output_pro:      ['/Control/SPDIF_output_pro', 0],
64             self.spdif_output_nonaudio: ['/Control/SPDIF_output_nonaudio', 0],
65         }
66
67         self.Radiobuttons={
68             self.level_in_lo_gain: ['/Control/Input_level', 1],
69             self.level_in_p4dBu:   ['/Control/Input_level', 2],
70             self.level_in_m10dBV:  ['/Control/Input_level', 3],
71
72             self.level_out_hi_gain: ['/Control/Output_level', 1],
73             self.level_out_p4dBu:   ['/Control/Output_level', 2],
74             self.level_out_m10dBV:  ['/Control/Output_level', 3],
75
76             self.spdif_input_coax:    ['/Control/SPDIF_input_mode', 0],
77             self.spdif_input_optical: ['/Control/SPDIF_input_mode', 1],
78
79             self.phones_hi_gain: ['/Control/Phones_level', 1],
80             self.phones_p4dBu:   ['/Control/Phones_level', 2],
81             self.phones_m10dBV:  ['/Control/Phones_level', 3],
82
83             self.clock_mode_autosync: ['/Control/Clock_mode', 1],
84             self.clock_mode_master: ['/Control/Clock_mode', 0],
85
86             self.sync_ref_wordclk: ['/Control/Sync_ref', 0],
87             self.sync_ref_adat1: ['/Control/Sync_ref', 1],
88             self.sync_ref_adat2: ['/Control/Sync_ref', 2],
89             self.sync_ref_spdif: ['/Control/Sync_ref', 3],
90             self.sync_ref_tco: ['/Control/Sync_ref', 4],
91         }
92
93
94         self.Gains={
95             self.gain_mic1: ['/Control/Gains', 0],
96             self.gain_mic2: ['/Control/Gains', 1],
97             self.gain_input3: ['/Control/Gains', 2],
98             self.gain_input4: ['/Control/Gains', 3],
99         }
100
101         # Other mixer variables
102         self.is_streaming = 0
103         self.sample_rate = 0
104         self.model = 0
105         self.tco_present = 0
106
107     # Public slot: update phantom power hardware switches
108     def updatePhantomSwitch(self, a0):
109         sender = self.sender()
110         # Value is the phantom switch value, with a corresponding enable
111         # bit in the high 16 bit word
112         val = (a0 << self.PhantomSwitches[sender][1]) | (0x00010000 << self.PhantomSwitches[sender][1])
113         log.debug("phantom switch %d set to %d" % (self.PhantomSwitches[sender][1], a0))
114         self.hw.setDiscrete(self.PhantomSwitches[sender][0], val)
115
116     # Public slot: update generic switches
117     def updateSwitch(self, a0):
118         sender = self.sender()
119         log.debug("switch %s set to %d" % (self.Switches[sender][0], a0))
120         self.hw.setDiscrete(self.Switches[sender][0], a0)
121
122     # Public slot: update generic radiobuttons
123     def updateRadiobutton(self, a0):
124         sender = self.sender()
125         if (a0 != 0):
126             # Only change the control state on a button being "checked"
127             log.debug("radiobutton group %s set to %d" % (self.Radiobuttons[sender][0], self.Radiobuttons[sender][1]))
128             self.hw.setDiscrete(self.Radiobuttons[sender][0], self.Radiobuttons[sender][1])
129
130     # Public slot: update gains
131     def updateGain(self, a0):
132         sender = self.sender()
133         log.debug("gain %s[%d] set to %d" % (self.Gains[sender][0], self.Gains[sender][1], a0))
134         self.hw.setMatrixMixerValue(self.Gains[sender][0], 0, self.Gains[sender][1], a0)
135
136     def updateBandwidthLimit(self, a0):
137         # Account for the "No ADAT-2" item which will not be present on
138         # a FF400.
139         if (self.model==RME_MODEL_FF400 and a0>0):
140             a0 = a0 + 1
141         # log.debug("limit update: %d" % (a0));
142         self.hw.setDiscrete('/Control/Bandwidth_limit', a0);
143
144     def updateStreamingState(self):
145         ss = self.streamingstatus.selected()
146         ss_txt = self.streamingstatus.getEnumLabel(ss)
147         if ss_txt != 'Idle':
148             self.is_streaming = True
149         else:
150             self.is_streaming = False
151         if (self.last_streaming_state != self.is_streaming):
152             self.bandwidth_limit.setEnabled(not(self.is_streaming));
153         self.last_streaming_state = self.is_streaming
154
155     def status_update(self):
156         # log.debug("timer event")
157         self.updateStreamingState()
158         clk_mode = ['Master', 'Slave']
159         src_str = ['None', 'ADAT 1', 'ADAT 2', 'SPDIF', 'Wordclock', 'TCO']
160         sync_stat = ['No lock', 'Locked', 'Synced']
161         sysclock_mode = self.hw.getDiscrete('/Control/sysclock_mode')
162         sysclock_freq = self.hw.getDiscrete('/Control/sysclock_freq')
163         autosync_freq = self.hw.getDiscrete('/Control/autosync_freq')
164         autosync_src = self.hw.getDiscrete('/Control/autosync_src')
165         sync_status = self.hw.getDiscrete('/Control/sync_status')
166         spdif_freq = self.hw.getDiscrete('/Control/spdif_freq')
167         self.sysclock_freq.setText("%d Hz" % (sysclock_freq))
168         self.sysclock_mode.setText(clk_mode[sysclock_mode])
169         self.autosync_freq.setText("%d Hz" % (autosync_freq))
170         self.autosync_src.setText(src_str[autosync_src])
171         self.sync_check_adat1_status.setText(sync_stat[sync_status & 0x03])
172         self.sync_check_adat2_status.setText(sync_stat[(sync_status >> 2) & 0x03])
173         self.sync_check_spdif_status.setText(sync_stat[(sync_status >> 4) & 0x03])
174         self.sync_check_wclk_status.setText(sync_stat[(sync_status >> 6) & 0x03])
175         self.sync_check_tco_status.setText(sync_stat[(sync_status >> 8) & 0x03])
176         self.spdif_freq.setText("%d Hz" % (spdif_freq))
177
178     # Hide and disable a control
179     def disable_hide(self,widget):
180         widget.hide()
181         widget.setEnabled(False)
182
183     def initValues(self):
184
185         # print self.hw.servername
186         # print self.hw.basepath
187         self.inputmatrix = MatrixMixer(self.hw.servername, self.hw.basepath+"/Mixer/InputFaders", self, 0x8000, self.hw.basepath+"/Mixer/InputMutes", self.hw.basepath+"/Mixer/InputInverts")
188         layout = QtGui.QVBoxLayout()
189         scrollarea = QtGui.QScrollArea()
190         scrollarea.setWidgetResizable(True)
191         scrollarea.setWidget(self.inputmatrix)
192         layout.addWidget(scrollarea)
193         self.mixer.setLayout(layout)
194
195         self.playbackmatrix = MatrixMixer(self.hw.servername, self.hw.basepath+"/Mixer/PlaybackFaders", self, 0x8000, self.hw.basepath+"/Mixer/PlaybackMutes", self.hw.basepath+"/Mixer/PlaybackInverts")
196         layout = QtGui.QVBoxLayout()
197         scrollarea = QtGui.QScrollArea()
198         scrollarea.setWidgetResizable(True)
199         scrollarea.setWidget(self.playbackmatrix)
200         layout.addWidget(scrollarea)
201         self.playbackmixer.setLayout(layout)
202
203         self.outputmatrix = MatrixMixer(self.hw.servername, self.hw.basepath+"/Mixer/OutputFaders", self, 0x8000, self.hw.basepath+"/Mixer/OutputMutes")
204         layout = QtGui.QVBoxLayout()
205         scrollarea = QtGui.QScrollArea()
206         scrollarea.setWidgetResizable(True)
207         scrollarea.setWidget(self.outputmatrix)
208         layout.addWidget(scrollarea)
209         self.outputmixer.setLayout(layout)
210
211         self.is_streaming = False
212         self.last_streaming_state = False
213
214         # Retrieve other device settings as needed and customise the UI
215         # based on these options.
216         self.model = self.hw.getDiscrete('/Control/Model')
217         log.debug("device model identifier: %d" % (self.model))
218         self.tco_present = self.hw.getDiscrete('/Control/TCO_present')
219         log.debug("device has TCO: %d" % (self.tco_present))
220         #self.sample_rate = self.hw.getDiscrete('/Mixer/Info/SampleRate')
221         #log.debug("device sample rate: %d" % (self.sample_rate))
222
223         # The Fireface-400 only has 2 phantom-capable channels
224         if (self.model == RME_MODEL_FF400):
225             self.disable_hide(self.phantom_2)
226             self.disable_hide(self.phantom_3)
227         else:
228             self.phantom_0.setText("Mic 7")
229             self.phantom_1.setText("Mic 8")
230             self.phantom_2.setText("Mic 9")
231             self.phantom_3.setText("Mic 10")
232
233         # Instrument options, input jack selection controls and an ADAT2
234         # input are applicable only to the FF800
235         if (self.model != RME_MODEL_FF800):
236             self.instrument_options_group.setEnabled(False)
237             self.input_plug_select_group.setEnabled(False)
238             self.sync_ref_adat2.setEnabled(False)
239             self.sync_check_adat2_label.setEnabled(False)
240             self.sync_check_adat2_status.setEnabled(False)
241
242         if (not(self.tco_present)):
243             self.sync_check_tco_label.setEnabled(False)
244             self.sync_check_tco_status.setEnabled(False)
245             self.sync_ref_tco.setEnabled(False)
246
247         # Only the FF400 has specific channel 3/4 options, input gain
248         # controls and switchable phones level
249         if (self.model != RME_MODEL_FF400):
250             self.disable_hide(self.input_gains_group)
251             self.disable_hide(self.channel_3_4_options_group)
252             self.phones_level_group.setEnabled(False)
253
254         # Add the "No ADAT-2" item to the bandwidth limit control if the
255         # device is not a FF400.  Set the control to reflect the current
256         # device setting and connect an update signal.
257         if (self.model != RME_MODEL_FF400):
258             self.bandwidth_limit.insertItem(1, "No ADAT-2")
259         val = self.hw.getDiscrete('/Control/Bandwidth_limit')
260         if (self.model==RME_MODEL_FF400 and val>1):
261             val = val - 1
262         self.bandwidth_limit.setCurrentIndex(val);
263         QObject.connect(self.bandwidth_limit, SIGNAL('currentIndexChanged(int)'), self.updateBandwidthLimit)
264
265         # Get current hardware values and connect GUI element signals to
266         # their respective slots
267         for ctrl, info in self.PhantomSwitches.iteritems():
268             if (not(ctrl.isEnabled())):
269                 continue
270             val = (self.hw.getDiscrete(info[0]) >> info[1]) & 0x01
271             log.debug("phantom switch %d is %d" % (info[1], val))
272             if val:
273                 ctrl.setChecked(True)
274             else:
275                 ctrl.setChecked(False)
276             QObject.connect(ctrl, SIGNAL('toggled(bool)'), self.updatePhantomSwitch)
277
278         for ctrl, info in self.Switches.iteritems():
279             if (not(ctrl.isEnabled())):
280                 continue
281             val = self.hw.getDiscrete(info[0])
282             log.debug("switch %s is %d" % (info[0], val))
283             if val:
284                 ctrl.setChecked(True)
285             else:
286                 ctrl.setChecked(False)
287             QObject.connect(ctrl, SIGNAL('toggled(bool)'), self.updateSwitch)
288
289         for ctrl, info in self.Radiobuttons.iteritems():
290             if (not(ctrl.isEnabled())):
291                 continue;
292             # This is a touch wasteful since it means we retrieve the control
293             # value once per radio button rather than once per radio button
294             # group.  In time we might introduce radiobutton groupings in the
295             # self.* datastructures to avoid this, but for the moment this is
296             # easy and it works.
297             val = self.hw.getDiscrete(info[0])
298             if (val == info[1]):
299                 val = 1
300             else:
301                 val = 0
302             ctrl.setChecked(val)
303             log.debug("Radiobutton %s[%d] is %d" % (info[0], info[1], val))
304             QObject.connect(ctrl, SIGNAL('toggled(bool)'), self.updateRadiobutton)
305
306         for ctrl, info in self.Gains.iteritems():
307             if (not(ctrl.isEnabled())):
308                 continue
309             val = self.hw.getMatrixMixerValue(info[0], 0, info[1])
310             log.debug("gain %s[%d] is %d" % (info[0], info[1], val))
311             ctrl.setValue(val);
312             QObject.connect(ctrl, SIGNAL('valueChanged(int)'), self.updateGain)
313
314         self.updateStreamingState()
315         #log.debug("device streaming flag: %d" % (self.is_streaming))
316
317         self.update_timer = QTimer(self)
318         QObject.connect(self.update_timer, SIGNAL('timeout()'), self.status_update)
319         self.update_timer.start(1000)
320
321 # vim: et
Note: See TracBrowser for help on using the browser.