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

Revision 2038, 11.9 kB (checked in by jwoithe, 12 years ago)

rme: various information panes are now active in ffado-mixer: sync check, autosync reference, spdif freqency and system clock. The function of these in the presence of actual external sync sources is yet to be confirmed. The system clock information has been confirmed to update when the clock mode and/or sample rate controls are altered.

  • 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
87
88         self.Gains={
89             self.gain_mic1: ['/Control/Gains', 0],
90             self.gain_mic2: ['/Control/Gains', 1],
91             self.gain_input3: ['/Control/Gains', 2],
92             self.gain_input4: ['/Control/Gains', 3],
93         }
94
95         # Other mixer variables
96         self.is_streaming = 0
97         self.sample_rate = 0
98         self.model = 0
99         self.tco_present = 0
100
101     # Public slot: update phantom power hardware switches
102     def updatePhantomSwitch(self, a0):
103         sender = self.sender()
104         # Value is the phantom switch value, with a corresponding enable
105         # bit in the high 16 bit word
106         val = (a0 << self.PhantomSwitches[sender][1]) | (0x00010000 << self.PhantomSwitches[sender][1])
107         log.debug("phantom switch %d set to %d" % (self.PhantomSwitches[sender][1], a0))
108         self.hw.setDiscrete(self.PhantomSwitches[sender][0], val)
109
110     # Public slot: update generic switches
111     def updateSwitch(self, a0):
112         sender = self.sender()
113         log.debug("switch %s set to %d" % (self.Switches[sender][0], a0))
114         self.hw.setDiscrete(self.Switches[sender][0], a0)
115
116     # Public slot: update generic radiobuttons
117     def updateRadiobutton(self, a0):
118         sender = self.sender()
119         if (a0 != 0):
120             # Only change the control state on a button being "checked"
121             log.debug("radiobutton group %s set to %d" % (self.Radiobuttons[sender][0], self.Radiobuttons[sender][1]))
122             self.hw.setDiscrete(self.Radiobuttons[sender][0], self.Radiobuttons[sender][1])
123
124     # Public slot: update gains
125     def updateGain(self, a0):
126         sender = self.sender()
127         log.debug("gain %s[%d] set to %d" % (self.Gains[sender][0], self.Gains[sender][1], a0))
128         self.hw.setMatrixMixerValue(self.Gains[sender][0], 0, self.Gains[sender][1], a0)
129
130     def status_update(self):
131         # log.debug("timer event")
132         clk_mode = ['Master', 'Slave']
133         src_str = ['None', 'ADAT 1', 'ADAT 2', 'SPDIF', 'Wordclock', 'TCO']
134         sync_stat = ['No lock', 'Locked', 'Synced']
135         sysclock_mode = self.hw.getDiscrete('/Control/sysclock_mode')
136         sysclock_freq = self.hw.getDiscrete('/Control/sysclock_freq')
137         autosync_freq = self.hw.getDiscrete('/Control/autosync_freq')
138         autosync_src = self.hw.getDiscrete('/Control/autosync_src')
139         sync_status = self.hw.getDiscrete('/Control/sync_status')
140         spdif_freq = self.hw.getDiscrete('/Control/spdif_freq')
141         self.sysclock_freq.setText("%d Hz" % (sysclock_freq))
142         self.sysclock_mode.setText(clk_mode[sysclock_mode])
143         self.autosync_freq.setText("%d Hz" % (autosync_freq))
144         self.autosync_src.setText(src_str[autosync_src])
145         self.sync_check_adat1_status.setText(sync_stat[sync_status & 0x03])
146         self.sync_check_adat2_status.setText(sync_stat[(sync_status >> 2) & 0x03])
147         self.sync_check_spdif_status.setText(sync_stat[(sync_status >> 4) & 0x03])
148         self.sync_check_wclk_status.setText(sync_stat[(sync_status >> 6) & 0x03])
149         self.sync_check_tco_status.setText(sync_stat[(sync_status >> 8) & 0x03])
150         self.spdif_freq.setText("%d Hz" % (spdif_freq))
151
152     # Hide and disable a control
153     def disable_hide(self,widget):
154         widget.hide()
155         widget.setEnabled(False)
156
157     def initValues(self):
158
159         # print self.hw.servername
160         # print self.hw.basepath
161         self.inputmatrix = MatrixMixer(self.hw.servername, self.hw.basepath+"/Mixer/InputFaders", self, 0x8000, self.hw.basepath+"/Mixer/InputMutes", self.hw.basepath+"/Mixer/InputInverts")
162         layout = QtGui.QVBoxLayout()
163         scrollarea = QtGui.QScrollArea()
164         scrollarea.setWidgetResizable(True)
165         scrollarea.setWidget(self.inputmatrix)
166         layout.addWidget(scrollarea)
167         self.mixer.setLayout(layout)
168
169         self.playbackmatrix = MatrixMixer(self.hw.servername, self.hw.basepath+"/Mixer/PlaybackFaders", self, 0x8000, self.hw.basepath+"/Mixer/PlaybackMutes", self.hw.basepath+"/Mixer/PlaybackInverts")
170         layout = QtGui.QVBoxLayout()
171         scrollarea = QtGui.QScrollArea()
172         scrollarea.setWidgetResizable(True)
173         scrollarea.setWidget(self.playbackmatrix)
174         layout.addWidget(scrollarea)
175         self.playbackmixer.setLayout(layout)
176
177         self.outputmatrix = MatrixMixer(self.hw.servername, self.hw.basepath+"/Mixer/OutputFaders", self, 0x8000, self.hw.basepath+"/Mixer/OutputMutes")
178         layout = QtGui.QVBoxLayout()
179         scrollarea = QtGui.QScrollArea()
180         scrollarea.setWidgetResizable(True)
181         scrollarea.setWidget(self.outputmatrix)
182         layout.addWidget(scrollarea)
183         self.outputmixer.setLayout(layout)
184
185         # Is the device streaming?
186         #self.is_streaming = self.hw.getDiscrete('/Mixer/Info/IsStreaming')
187         self.is_streaming = 0
188         #log.debug("device streaming flag: %d" % (self.is_streaming))
189
190         # Retrieve other device settings as needed and customise the UI
191         # based on these options.
192         self.model = self.hw.getDiscrete('/Control/Model')
193         log.debug("device model identifier: %d" % (self.model))
194         self.tco_present = self.hw.getDiscrete('/Control/TCO_present')
195         log.debug("device has TCO: %d" % (self.tco_present))
196         #self.sample_rate = self.hw.getDiscrete('/Mixer/Info/SampleRate')
197         #log.debug("device sample rate: %d" % (self.sample_rate))
198
199         # The Fireface-400 only has 2 phantom-capable channels
200         if (self.model == RME_MODEL_FF400):
201             self.disable_hide(self.phantom_2)
202             self.disable_hide(self.phantom_3)
203         else:
204             self.phantom_0.setText("Mic 7")
205             self.phantom_1.setText("Mic 8")
206             self.phantom_2.setText("Mic 9")
207             self.phantom_3.setText("Mic 10")
208
209         # Instrument options, input jack selection controls and an ADAT2
210         # input are applicable only to the FF800
211         if (self.model != RME_MODEL_FF800):
212             self.instrument_options_group.setEnabled(False)
213             self.input_plug_select_group.setEnabled(False)
214             self.sync_ref_adat2.setEnabled(False)
215             self.sync_check_adat2_label.setEnabled(False)
216             self.sync_check_adat2_status.setEnabled(False)
217
218         if (not(self.tco_present)):
219             self.sync_check_tco_label.setEnabled(False)
220             self.sync_check_tco_status.setEnabled(False)
221
222         # Only the FF400 has specific channel 3/4 options, input gain
223         # controls and switchable phones level
224         if (self.model != RME_MODEL_FF400):
225             self.disable_hide(self.input_gains_group)
226             self.disable_hide(self.channel_3_4_options_group)
227             self.phones_level_group.setEnabled(False)
228
229         # Get current hardware values and connect GUI element signals to
230         # their respective slots
231         for ctrl, info in self.PhantomSwitches.iteritems():
232             if (not(ctrl.isEnabled())):
233                 continue
234             val = (self.hw.getDiscrete(info[0]) >> info[1]) & 0x01
235             log.debug("phantom switch %d is %d" % (info[1], val))
236             if val:
237                 ctrl.setChecked(True)
238             else:
239                 ctrl.setChecked(False)
240             QObject.connect(ctrl, SIGNAL('toggled(bool)'), self.updatePhantomSwitch)
241
242         for ctrl, info in self.Switches.iteritems():
243             if (not(ctrl.isEnabled())):
244                 continue
245             val = self.hw.getDiscrete(info[0])
246             log.debug("switch %s is %d" % (info[0], val))
247             if val:
248                 ctrl.setChecked(True)
249             else:
250                 ctrl.setChecked(False)
251             QObject.connect(ctrl, SIGNAL('toggled(bool)'), self.updateSwitch)
252
253         for ctrl, info in self.Radiobuttons.iteritems():
254             if (not(ctrl.isEnabled())):
255                 continue;
256             # This is a touch wasteful since it means we retrieve the control
257             # value once per radio button rather than once per radio button
258             # group.  In time we might introduce radiobutton groupings in the
259             # self.* datastructures to avoid this, but for the moment this is
260             # easy and it works.
261             val = self.hw.getDiscrete(info[0])
262             if (val == info[1]):
263                 val = 1
264             else:
265                 val = 0
266             ctrl.setChecked(val)
267             log.debug("Radiobutton %s[%d] is %d" % (info[0], info[1], val))
268             QObject.connect(ctrl, SIGNAL('toggled(bool)'), self.updateRadiobutton)
269
270         for ctrl, info in self.Gains.iteritems():
271             if (not(ctrl.isEnabled())):
272                 continue
273             val = self.hw.getMatrixMixerValue(info[0], 0, info[1])
274             log.debug("gain %s[%d] is %d" % (info[0], info[1], val))
275             ctrl.setValue(val);
276             QObject.connect(ctrl, SIGNAL('valueChanged(int)'), self.updateGain)
277
278         self.update_timer = QTimer(self)
279         QObject.connect(self.update_timer, SIGNAL('timeout()'), self.status_update)
280         self.update_timer.start(1000)
281
282 # vim: et
Note: See TracBrowser for help on using the browser.