def buildMixer(self): #print self.hw #print self.hw.getText("/Generic/Nickname") self.mixer = MatrixMixer(self.hw.servername, self.hw.basepath+"/EAP/MatrixMixer", self, "Columns_are_outputs", -1, None, None, False, QTabWidget.North, QTabWidget.Rounded) self.tabs.addTab(self.mixer, "Mixer") self.router_scrollarea = self.buildRouter(self.hw.servername, self.hw.basepath+"/EAP/Router") self.tabs.addTab(self.router_scrollarea, "Crossbar Router")
def buildMixer(self): #print( self.hw ) #print( self.hw.getText("/Generic/Nickname") ) self.mixer = MatrixMixer(self.hw.servername, self.hw.basepath+"/EAP/MatrixMixer", self, "Columns_are_outputs", -1, None, None, False, QTabWidget.North, QTabWidget.Rounded) self.tabs.addTab(self.mixer, "Mixer") self.router_scrollarea = self.buildRouter(self.hw.servername, self.hw.basepath+"/EAP/Router") self.tabs.addTab(self.router_scrollarea, "Crossbar Router")
def buildMixer(self): #print self.hw #print self.hw.getText("/Generic/Nickname") self.matrix = MatrixMixer(self.hw.servername, self.hw.basepath+"/EAP/MatrixMixer", self) scrollarea = QtGui.QScrollArea(self.tabs) scrollarea.setWidgetResizable(True) scrollarea.setWidget(self.matrix) self.tabs.addTab(scrollarea, "Matrix") self.router = CrossbarRouter(self.hw.servername, self.hw.basepath+"/EAP/Router", self) scrollarea = QtGui.QScrollArea(self.tabs) scrollarea.setWidgetResizable(True) scrollarea.setWidget(self.router) self.tabs.addTab(scrollarea, "Routing") model = MonitoringModel(self.hw, self) widget = QtGui.QWidget() uicLoad("ffado/mixer/saffire_dice_monitoring.ui", widget) widget.monitoringView.setModel(model) widget.monitoringView.setItemDelegate(MonitoringDelegate(self)) self.tabs.addTab(widget, "Monitoring") self.muteInterface = BooleanControl(self.hw, self.hw.basepath+"/EAP/Monitoring/GlobalMute/State") widget.btnMute.setChecked(self.muteInterface.selected()) self.connect(widget.btnMute, QtCore.SIGNAL("toggled(bool)"), self.muteToggle) self.dimInterface = BooleanControl(self.hw, self.hw.basepath+"/EAP/Monitoring/GlobalDim/State") widget.btnDim.setChecked(self.dimInterface.selected()) self.connect(widget.btnDim, QtCore.SIGNAL("toggled(bool)"), self.dimToggle) self.dimLevelInterface = DiscreteControl(self.hw, self.hw.basepath+"/EAP/Monitoring/GlobalDim/Level") widget.dimLevel.setValue(self.dimLevelInterface.getvalue()) self.connect(widget.dimLevel, QtCore.SIGNAL("valueChanged(int)"), self.dimLevelChanged) self.volumeInterface = DiscreteControl(self.hw, self.hw.basepath+"/EAP/Monitoring/GlobalVolume/Level") widget.volumeKnob.setValue(self.volumeInterface.getvalue()) self.connect(widget.volumeKnob, QtCore.SIGNAL("valueChanged(int)"), self.volumeChanged) if self.configrom.getModelName() == "SAFFIRE_PRO_24": self.ch1inst = BooleanControl(self.hw, self.hw.basepath + "/EAP/Ch1LineInst") widget.chkInst1.setChecked(self.ch1inst.selected()) self.connect(widget.chkInst1, QtCore.SIGNAL("toggled(bool)"), self.ch1inst.select) self.ch2inst = BooleanControl(self.hw, self.hw.basepath + "/EAP/Ch2LineInst") widget.chkInst2.setChecked(self.ch2inst.selected()) self.connect(widget.chkInst2, QtCore.SIGNAL("toggled(bool)"), self.ch2inst.select) self.ch3level = BooleanControl(self.hw, self.hw.basepath + "/EAP/Ch3Level") widget.chkLevel3.setChecked(self.ch3level.selected()) self.connect(widget.chkLevel3, QtCore.SIGNAL("toggled(bool)"), self.ch3level.select) self.ch4level = BooleanControl(self.hw, self.hw.basepath + "/EAP/Ch4Level") widget.chkLevel4.setChecked(self.ch4level.selected()) self.connect(widget.chkLevel4, QtCore.SIGNAL("toggled(bool)"), self.ch4level.select) else: widget.chkInst1.deleteLater() widget.chkInst2.deleteLater() widget.chkLevel3.deleteLater() widget.chkLevel4.deleteLater()
def buildMixer(self): #print self.hw #print self.hw.getText("/Generic/Nickname") self.matrix = MatrixMixer(self.hw.servername, self.hw.basepath+"/EAP/MatrixMixer", self) scrollarea = QtGui.QScrollArea(self.tabs) scrollarea.setWidgetResizable(True) scrollarea.setWidget(self.matrix) self.tabs.addTab(scrollarea, "Matrix Mixer") self.router = CrossbarRouter(self.hw.servername, self.hw.basepath+"/EAP/Router", self) scrollarea = QtGui.QScrollArea(self.tabs) scrollarea.setWidgetResizable(True) scrollarea.setWidget(self.router) self.tabs.addTab(scrollarea, "Crossbar Router")
def initValues(self): # print self.hw.servername # print self.hw.basepath self.inputmatrix = MatrixMixer( self.hw.servername, self.hw.basepath + "/Mixer/InputFaders", self, "Columns_are_inputs", 0x8000, self.hw.basepath + "/Mixer/InputMutes", self.hw.basepath + "/Mixer/InputInverts", True) layout = QVBoxLayout() layout.addWidget(self.inputmatrix) self.mixer.setLayout(layout) self.playbackmatrix = MatrixMixer( self.hw.servername, self.hw.basepath + "/Mixer/PlaybackFaders", self, "Columns_are_inputs", 0x8000, self.hw.basepath + "/Mixer/PlaybackMutes", self.hw.basepath + "/Mixer/PlaybackInverts", True) layout = QVBoxLayout() layout.addWidget(self.playbackmatrix) self.playbackmixer.setLayout(layout) self.outputmatrix = MatrixMixer( self.hw.servername, self.hw.basepath + "/Mixer/OutputFaders", self, "Columns_are_inputs", 0x8000, self.hw.basepath + "/Mixer/OutputMutes", None, True) layout = QVBoxLayout() # This is a bit of a hack, but it works to ensure this single-row # matrix mixer doesn't fill the entire screen but also doesn't end # up with a pointless scrollbar. The matrix mixer's minimum height # is 0 according to minimumHeight(), which is probably the # fundamental issue here; however, I've already wasted too much time # trying to get this to work so if the hack is effective we'll run # with it. self.outputmatrix.setMinimumHeight(150) layout.addWidget(self.outputmatrix, 0, Qt.AlignTop) self.outputmixer.setLayout(layout) self.is_streaming = False self.last_streaming_state = False # Disable the "load settings" button if streaming is active. Its # enable state will be kept up to date by updateStreamingState(). self.control_load.setEnabled(not (self.is_streaming)) # Also disable other controls which are not yet implemented. self.mixer_preset_ffado_default.setEnabled(False) # Retrieve other device settings as needed and customise the UI # based on these options. self.model = self.hw.getDiscrete('/Control/Model') log.debug("device model identifier: %d" % (self.model)) self.tco_present = self.hw.getDiscrete('/Control/TCO_present') log.debug("device has TCO: %d" % (self.tco_present)) #self.sample_rate = self.hw.getDiscrete('/Mixer/Info/SampleRate') #log.debug("device sample rate: %d" % (self.sample_rate)) # Assume the TCO options tab is the second from the left (index 1) if (not (self.tco_present)): self.disable_hide(self.tco_options) self.tabWidget.setTabEnabled(1, False) self.tabWidget.removeTab(1) # The Fireface-400 only has 2 phantom-capable channels if (self.model == RME_MODEL_FF400): self.disable_hide(self.phantom_2) self.disable_hide(self.phantom_3) else: self.phantom_0.setText("Mic 7") self.phantom_1.setText("Mic 8") self.phantom_2.setText("Mic 9") self.phantom_3.setText("Mic 10") # Instrument options, input jack selection controls and an ADAT2 # input are applicable only to the FF800 if (self.model != RME_MODEL_FF800): self.instrument_options_group.setEnabled(False) self.input_plug_select_group.setEnabled(False) self.sync_ref_adat2.setEnabled(False) self.sync_check_adat2_label.setEnabled(False) self.sync_check_adat2_status.setEnabled(False) self.spdif_output_optical.setText("ADAT optical") self.spdif_input_optical.setText("ADAT optical") if (not (self.tco_present)): self.sync_check_tco_label.setEnabled(False) self.sync_check_tco_status.setEnabled(False) self.sync_ref_tco.setEnabled(False) # Only the FF400 has specific channel 3/4 options, input gain # controls and switchable phones level if (self.model != RME_MODEL_FF400): # Hide the upper-level frame (and everything in it) to ensure it # requests no vertical space when its contents aren't needed. self.disable_hide(self.igains_chan34_opts_frame) self.phones_level_group.setEnabled(False) # Add the "No ADAT-2" item to the bandwidth limit control if the # device is not a FF400. if (self.model != RME_MODEL_FF400): self.bandwidth_limit.insertItem(1, "No ADAT-2") self.getValuesFromFF() self.setupSignals() # Ensure the limiter checkbox has a signal handler associated with # it. If getValuesFromFF() disabled it because the front input was # not selected, setupSignals() would not have configured a handler. if (not (self.ch1_instr_limiter.isEnabled())): self.ch1_instr_limiter.toggled.connect(self.updateCheckboxes) self.updateStreamingState() #log.debug("device streaming flag: %d" % (self.is_streaming)) self.update_timer = QTimer(self) self.update_timer.timeout.connect(self.status_update) self.update_timer.start(1000)
class Rme(QWidget): def __init__(self, parent=None): QWidget.__init__(self, parent) uicLoad("ffado/mixer/rme", self) self.init() def init(self): self.PhantomSwitches = { self.phantom_0: ['/Control/Phantom', 0], self.phantom_1: ['/Control/Phantom', 1], self.phantom_2: ['/Control/Phantom', 2], self.phantom_3: ['/Control/Phantom', 3], } self.Switches = { self.ff400_chan3_opt_instr: ['/Control/Chan3_opt_instr'], self.ff400_chan3_opt_pad: ['/Control/Chan3_opt_pad'], self.ff400_chan4_opt_instr: ['/Control/Chan4_opt_instr'], self.ff400_chan4_opt_pad: ['/Control/Chan4_opt_pad'], self.spdif_output_optical: ['/Control/SPDIF_output_optical', 0], self.spdif_output_emphasis: ['/Control/SPDIF_output_emphasis', 0], self.spdif_output_pro: ['/Control/SPDIF_output_pro', 0], self.spdif_output_nonaudio: ['/Control/SPDIF_output_nonaudio', 0], } self.Radiobuttons = { self.level_in_lo_gain: ['/Control/Input_level', 0], self.level_in_p4dBu: ['/Control/Input_level', 2], self.level_in_m10dBV: ['/Control/Input_level', 1], self.level_out_hi_gain: ['/Control/Output_level', 2], self.level_out_p4dBu: ['/Control/Output_level', 1], self.level_out_m10dBV: ['/Control/Output_level', 0], self.spdif_input_coax: ['/Control/SPDIF_input_mode', 0], self.spdif_input_optical: ['/Control/SPDIF_input_mode', 1], self.phones_hi_gain: ['/Control/Phones_level', 0], self.phones_p4dBu: ['/Control/Phones_level', 1], self.phones_m10dBV: ['/Control/Phones_level', 2], self.clock_mode_autosync: ['/Control/Clock_mode', 1], self.clock_mode_master: ['/Control/Clock_mode', 0], self.sync_ref_wordclk: ['/Control/Sync_ref', 0], self.sync_ref_adat1: ['/Control/Sync_ref', 1], self.sync_ref_adat2: ['/Control/Sync_ref', 2], self.sync_ref_spdif: ['/Control/Sync_ref', 3], self.sync_ref_tco: ['/Control/Sync_ref', 4], # TCO controls self.sync_source_ltc: ['/Control/Tco_sync_src', 0], self.sync_source_video: ['/Control/Tco_sync_src', 1], self.sync_source_wordclk: ['/Control/Tco_sync_src', 2], self.frame_rate_24fps: ['/Control/Tco_frame_rate', 0], self.frame_rate_25fps: ['/Control/Tco_frame_rate', 1], self.frame_rate_29_97fps: ['/Control/Tco_frame_rate', 2], self.frame_rate_29_97dfps: ['/Control/Tco_frame_rate', 3], self.frame_rate_30fps: ['/Control/Tco_frame_rate', 4], self.frame_rate_30dfps: ['/Control/Tco_frame_rate', 5], self.sample_rate_44k1: ['/Control/Tco_sample_rate', 0], self.sample_rate_48k: ['/Control/Tco_sample_rate', 1], self.sample_rate_0pc: ['/Control/Tco_sample_rate_ofs', 0], self.sample_rate_p01pc: ['/Control/Tco_sample_rate_ofs', 1], self.sample_rate_n01pc: ['/Control/Tco_sample_rate_ofs', 2], self.sample_rate_p40pc: ['/Control/Tco_sample_rate_ofs', 3], self.sample_rate_n40pc: ['/Control/Tco_sample_rate_ofs', 4], self.wordclk_conv_1_1: ['/Control/Tco_word_clk_conv', 0], self.wordclk_conv_44k1_48k: ['/Control/Tco_word_clk_conv', 1], self.wordclk_conv_48k_44k1: ['/Control/Tco_word_clk_conv', 2], } self.Checkboxes = { self.ch1_instr_fuzz: ['/Control/Chan1_instr_opts', 0x04], self.ch1_instr_limiter: ['/Control/Chan1_instr_opts', 0x08], self.ch1_instr_filter: ['/Control/Chan1_instr_opts', 0x02], # TCO controls self.video_input_termination_on: ['/Control/Tco_video_in_term', 0x01], } self.Gains = { self.gain_mic1: ['/Control/Gains', 0], self.gain_mic2: ['/Control/Gains', 1], self.gain_input3: ['/Control/Gains', 2], self.gain_input4: ['/Control/Gains', 3], } self.Combos = { self.ff800_ch1_src: ['/Control/Chan1_source'], self.ff800_ch7_src: ['/Control/Chan7_source'], self.ff800_ch8_src: ['/Control/Chan8_source'], } self.CommandButtons = { self.control_load: ['/Control/Flash_control', 0], self.control_save: ['/Control/Flash_control', 1], self.mixer_load: ['/Control/Flash_control', 2], self.mixer_save: ['/Control/Flash_control', 3], self.mixer_preset_ffado_default: ['/Control/Mixer_preset', 0], } # Other mixer variables self.is_streaming = 0 self.sample_rate = 0 self.model = 0 self.tco_present = 0 # Public slot: update phantom power hardware switches def updatePhantomSwitch(self, a0): sender = self.sender() # Value is the phantom switch value, with a corresponding enable # bit in the high 16 bit word val = (a0 << self.PhantomSwitches[sender][1]) | ( 0x00010000 << self.PhantomSwitches[sender][1]) log.debug("phantom switch %d set to %d" % (self.PhantomSwitches[sender][1], a0)) self.hw.setDiscrete(self.PhantomSwitches[sender][0], val) # Public slot: update generic switches def updateSwitch(self, a0): sender = self.sender() log.debug("switch %s set to %d" % (self.Switches[sender][0], a0)) self.hw.setDiscrete(self.Switches[sender][0], a0) # Public slot: update generic radiobuttons def updateRadiobutton(self, a0): sender = self.sender() if (a0 != 0): # Only change the control state on a button being "checked" log.debug( "radiobutton group %s set to %d" % (self.Radiobuttons[sender][0], self.Radiobuttons[sender][1])) self.hw.setDiscrete(self.Radiobuttons[sender][0], self.Radiobuttons[sender][1]) def updateCheckboxes(self, a0): sender = self.sender() val = self.hw.getDiscrete(self.Checkboxes[sender][0]) if (a0 != 0): val = val | self.Checkboxes[sender][1] else: val = val & ~self.Checkboxes[sender][1] log.debug("checkbox group %s set to %d" % (self.Checkboxes[sender][0], val)) self.hw.setDiscrete(self.Checkboxes[sender][0], val) # Public slot: update gains def updateGain(self, a0): sender = self.sender() log.debug("gain %s[%d] set to %d" % (self.Gains[sender][0], self.Gains[sender][1], a0)) self.hw.setMatrixMixerValue(self.Gains[sender][0], 0, self.Gains[sender][1], a0) def updateBandwidthLimit(self, a0): # Account for the "No ADAT-2" item which will not be present on # a FF400. if (self.model == RME_MODEL_FF400 and a0 > 0): a0 = a0 + 1 # log.debug("limit update: %d" % (a0)); self.hw.setDiscrete('/Control/Bandwidth_limit', a0) # Public slot: send command def sendCommand(self, a0): sender = self.sender() log.debug( "command %d sent to %s" % (self.CommandButtons[sender][1], self.CommandButtons[sender][0])) self.hw.setDiscrete(self.CommandButtons[sender][0], self.CommandButtons[sender][1]) # If mixer values have been reloaded, refresh the mixer GUI. This # will also commit the new values to the hardware via the "changed" # signal handlers of the mixer elements. if (self.CommandButtons[sender][1] == 2): self.inputmatrix.refreshValues() self.outputmatrix.refreshValues() self.playbackmatrix.refreshValues() # If settings have been reloaded from flash, refresh the GUI. The # settings will be made active in the hardware via the "changed" # signal handlers of the respective GUI control widgets. if (self.CommandButtons[sender][1] == 0): self.getValuesFromFF() def updateCombo(self, a0): sender = self.sender() log.debug("combo %s set to %d" % (self.Combos[sender][0], a0)) self.hw.setDiscrete(self.Combos[sender][0], a0) # Enable the limiter control only when the front source is active if (sender == self.ff800_ch1_src): self.ch1_instr_limiter.setEnabled(a0 == 0) def updateStreamingState(self): ss = self.streamingstatus.selected() ss_txt = self.streamingstatus.getEnumLabel(ss) if ss_txt != 'Idle': self.is_streaming = True else: self.is_streaming = False if (self.last_streaming_state != self.is_streaming): self.bandwidth_limit.setEnabled(not (self.is_streaming)) self.control_load.setEnabled(not (self.is_streaming)) self.last_streaming_state = self.is_streaming def status_update(self): # log.debug("timer event") self.updateStreamingState() clk_mode = ['Master', 'Slave'] src_str = ['None', 'ADAT 1', 'ADAT 2', 'SPDIF', 'Wordclock', 'TCO'] sync_stat = ['No lock', 'Locked', 'Synced'] sysclock_mode = self.hw.getDiscrete('/Control/sysclock_mode') sysclock_freq = self.hw.getDiscrete('/Control/sysclock_freq') autosync_freq = self.hw.getDiscrete('/Control/autosync_freq') autosync_src = self.hw.getDiscrete('/Control/autosync_src') sync_status = self.hw.getDiscrete('/Control/sync_status') spdif_freq = self.hw.getDiscrete('/Control/spdif_freq') self.sysclock_freq.setText("%d Hz" % (sysclock_freq)) self.sysclock_mode.setText(clk_mode[sysclock_mode]) self.autosync_freq.setText("%d Hz" % (autosync_freq)) self.autosync_src.setText(src_str[autosync_src]) self.sync_check_adat1_status.setText(sync_stat[sync_status & 0x03]) self.sync_check_adat2_status.setText(sync_stat[(sync_status >> 2) & 0x03]) self.sync_check_spdif_status.setText(sync_stat[(sync_status >> 4) & 0x03]) self.sync_check_wclk_status.setText(sync_stat[(sync_status >> 6) & 0x03]) self.sync_check_tco_status.setText(sync_stat[(sync_status >> 8) & 0x03]) self.spdif_freq.setText("%d Hz" % (spdif_freq)) if (self.tco_present): ltc_valid_str = ['Not detected', 'Valid'] ltc_framerate_str = ['24 fps', '25 fps', '29.97 fps', '30 fps'] ltc_frametype_str = ['Normal (full frame)', 'Dropframe'] video_type_str = ['No video', 'PAL', 'NTSC'] word_clock_str = [ 'None', 'Single Speed', 'Double Speed', 'Quad Speed' ] status_str = ['Not locked', "Locked"] ltc = self.hw.getDiscrete('/Control/Tco_ltc_in') ltc_valid = self.hw.getDiscrete('/Control/Tco_input_ltc_valid') ltc_fps = self.hw.getDiscrete('/Control/Tco_input_ltc_fps') ltc_dropframe = self.hw.getDiscrete( '/Control/Tco_input_ltc_dropframe') videotype = self.hw.getDiscrete('/Control/Tco_input_video_type') wordclk = self.hw.getDiscrete('/Control/Tco_input_word_clk') input_lock = self.hw.getDiscrete('/Control/Tco_input_lock') tco_freq = self.hw.getDiscrete('/Control/Tco_freq') self.state_ltc_valid_label.setText(ltc_valid_str[ltc_valid]) if (ltc_valid): self.ltc_in_hours.setText("%02d" % (ltc >> 24)) self.ltc_in_minutes.setText("%02d" % ((ltc >> 16) & 0xff)) self.ltc_in_seconds.setText("%02d" % ((ltc >> 8) & 0xff)) self.ltc_in_frames.setText("%02d" % (ltc & 0xff)) self.state_ltc_framerate.setText(ltc_framerate_str[ltc_fps]) self.state_ltc_frame_type.setText( ltc_frametype_str[ltc_dropframe]) else: self.ltc_in_hours.setText("--") self.ltc_in_minutes.setText("--") self.ltc_in_seconds.setText("--") self.ltc_in_frames.setText("--") self.state_ltc_framerate.setText("-") self.state_ltc_frame_type.setText("-") self.state_video_type.setText(video_type_str[videotype]) self.state_word_clk.setText(word_clock_str[wordclk]) self.sync_source_status.setText(status_str[input_lock]) self.tco_frequency_label.setText("%d Hz" % (tco_freq)) # Hide and disable a control def disable_hide(self, widget): for w in widget.children(): if isinstance(w, QWidget): w.hide() w.setEnabled(False) widget.hide() widget.setEnabled(False) def setupSignals(self): # Connect signal handlers for all command buttons for ctrl, info in self.CommandButtons.items(): if (not (ctrl.isEnabled())): continue ctrl.clicked.connect(self.sendCommand) for ctrl, info in self.Combos.items(): if (not (ctrl.isEnabled())): continue ctrl.currentIndexChanged.connect(self.updateCombo) self.bandwidth_limit.currentIndexChanged.connect( self.updateBandwidthLimit) # Get current hardware values and connect GUI element signals to # their respective slots for ctrl, info in self.PhantomSwitches.items(): if (not (ctrl.isEnabled())): continue ctrl.toggled.connect(self.updatePhantomSwitch) for ctrl, info in self.Switches.items(): if (not (ctrl.isEnabled())): continue ctrl.toggled.connect(self.updateSwitch) for ctrl, info in self.Radiobuttons.items(): if (not (ctrl.isEnabled())): continue ctrl.toggled.connect(self.updateRadiobutton) for ctrl, info in self.Checkboxes.items(): if (not (ctrl.isEnabled())): continue ctrl.toggled.connect(self.updateCheckboxes) for ctrl, info in self.Gains.items(): if (not (ctrl.isEnabled())): continue ctrl.valueChanged.connect(self.updateGain) # Obtain control values from the Fireface and make the GUI reflect these def getValuesFromFF(self): for ctrl, info in self.Combos.items(): if (not (ctrl.isEnabled())): continue val = self.hw.getDiscrete(info[0]) log.debug("combo %s is %d" % (info[0], val)) ctrl.setCurrentIndex(val) # Set the bandwidth limit control to reflect the current device # setting, allowing for the additional "No ADAT-2" item which is # present on the FF800. val = self.hw.getDiscrete('/Control/Bandwidth_limit') if (self.model == RME_MODEL_FF400 and val > 1): val = val - 1 self.bandwidth_limit.setCurrentIndex(val) # Get current hardware values for ctrl, info in self.PhantomSwitches.items(): if (not (ctrl.isEnabled())): continue val = (self.hw.getDiscrete(info[0]) >> info[1]) & 0x01 log.debug("phantom switch %d is %d" % (info[1], val)) if val: ctrl.setChecked(True) else: ctrl.setChecked(False) for ctrl, info in self.Switches.items(): if (not (ctrl.isEnabled())): continue val = self.hw.getDiscrete(info[0]) log.debug("switch %s is %d" % (info[0], val)) if val: ctrl.setChecked(True) else: ctrl.setChecked(False) for ctrl, info in self.Radiobuttons.items(): if (not (ctrl.isEnabled())): continue # This is a touch wasteful since it means we retrieve the control # value once per radio button rather than once per radio button # group. In time we might introduce radiobutton groupings in the # self.* datastructures to avoid this, but for the moment this is # easy and it works. val = self.hw.getDiscrete(info[0]) if (val == info[1]): val = 1 else: val = 0 ctrl.setChecked(val) log.debug("Radiobutton %s[%d] is %d" % (info[0], info[1], val)) # Make sure the Limiter control can receive a value if (self.ff800_ch1_src.isEnabled()): self.ch1_instr_limiter.setEnabled(1) for ctrl, info in self.Checkboxes.items(): if (not (ctrl.isEnabled())): continue # This is a touch wasteful since it means we retrieve the control # value once per checkbox button rather than once per checkbox # group. In time we might introduce checkbox groupings in the # self.* datastructures to avoid this, but for the moment this is # easy and it works. val = self.hw.getDiscrete(info[0]) if (val & info[1]): val = 1 else: val = 0 ctrl.setChecked(val) log.debug("Checkbox %s[%d] is %d" % (info[0], info[1], val)) # The limiter (a checkbox) can only be controlled if the front # source is selected for channel 1. ch1_src = self.ff800_ch1_src.currentIndex() if (self.ff800_ch1_src.isEnabled()): self.ch1_instr_limiter.setEnabled(ch1_src == 0) for ctrl, info in self.Gains.items(): if (not (ctrl.isEnabled())): continue val = self.hw.getMatrixMixerValue(info[0], 0, info[1]) log.debug("gain %s[%d] is %d" % (info[0], info[1], val)) ctrl.setValue(val) def initValues(self): # print self.hw.servername # print self.hw.basepath self.inputmatrix = MatrixMixer( self.hw.servername, self.hw.basepath + "/Mixer/InputFaders", self, "Columns_are_inputs", 0x8000, self.hw.basepath + "/Mixer/InputMutes", self.hw.basepath + "/Mixer/InputInverts", True) layout = QVBoxLayout() layout.addWidget(self.inputmatrix) self.mixer.setLayout(layout) self.playbackmatrix = MatrixMixer( self.hw.servername, self.hw.basepath + "/Mixer/PlaybackFaders", self, "Columns_are_inputs", 0x8000, self.hw.basepath + "/Mixer/PlaybackMutes", self.hw.basepath + "/Mixer/PlaybackInverts", True) layout = QVBoxLayout() layout.addWidget(self.playbackmatrix) self.playbackmixer.setLayout(layout) self.outputmatrix = MatrixMixer( self.hw.servername, self.hw.basepath + "/Mixer/OutputFaders", self, "Columns_are_inputs", 0x8000, self.hw.basepath + "/Mixer/OutputMutes", None, True) layout = QVBoxLayout() # This is a bit of a hack, but it works to ensure this single-row # matrix mixer doesn't fill the entire screen but also doesn't end # up with a pointless scrollbar. The matrix mixer's minimum height # is 0 according to minimumHeight(), which is probably the # fundamental issue here; however, I've already wasted too much time # trying to get this to work so if the hack is effective we'll run # with it. self.outputmatrix.setMinimumHeight(150) layout.addWidget(self.outputmatrix, 0, Qt.AlignTop) self.outputmixer.setLayout(layout) self.is_streaming = False self.last_streaming_state = False # Disable the "load settings" button if streaming is active. Its # enable state will be kept up to date by updateStreamingState(). self.control_load.setEnabled(not (self.is_streaming)) # Also disable other controls which are not yet implemented. self.mixer_preset_ffado_default.setEnabled(False) # Retrieve other device settings as needed and customise the UI # based on these options. self.model = self.hw.getDiscrete('/Control/Model') log.debug("device model identifier: %d" % (self.model)) self.tco_present = self.hw.getDiscrete('/Control/TCO_present') log.debug("device has TCO: %d" % (self.tco_present)) #self.sample_rate = self.hw.getDiscrete('/Mixer/Info/SampleRate') #log.debug("device sample rate: %d" % (self.sample_rate)) # Assume the TCO options tab is the second from the left (index 1) if (not (self.tco_present)): self.disable_hide(self.tco_options) self.tabWidget.setTabEnabled(1, False) self.tabWidget.removeTab(1) # The Fireface-400 only has 2 phantom-capable channels if (self.model == RME_MODEL_FF400): self.disable_hide(self.phantom_2) self.disable_hide(self.phantom_3) else: self.phantom_0.setText("Mic 7") self.phantom_1.setText("Mic 8") self.phantom_2.setText("Mic 9") self.phantom_3.setText("Mic 10") # Instrument options, input jack selection controls and an ADAT2 # input are applicable only to the FF800 if (self.model != RME_MODEL_FF800): self.instrument_options_group.setEnabled(False) self.input_plug_select_group.setEnabled(False) self.sync_ref_adat2.setEnabled(False) self.sync_check_adat2_label.setEnabled(False) self.sync_check_adat2_status.setEnabled(False) self.spdif_output_optical.setText("ADAT optical") self.spdif_input_optical.setText("ADAT optical") if (not (self.tco_present)): self.sync_check_tco_label.setEnabled(False) self.sync_check_tco_status.setEnabled(False) self.sync_ref_tco.setEnabled(False) # Only the FF400 has specific channel 3/4 options, input gain # controls and switchable phones level if (self.model != RME_MODEL_FF400): # Hide the upper-level frame (and everything in it) to ensure it # requests no vertical space when its contents aren't needed. self.disable_hide(self.igains_chan34_opts_frame) self.phones_level_group.setEnabled(False) # Add the "No ADAT-2" item to the bandwidth limit control if the # device is not a FF400. if (self.model != RME_MODEL_FF400): self.bandwidth_limit.insertItem(1, "No ADAT-2") self.getValuesFromFF() self.setupSignals() # Ensure the limiter checkbox has a signal handler associated with # it. If getValuesFromFF() disabled it because the front input was # not selected, setupSignals() would not have configured a handler. if (not (self.ch1_instr_limiter.isEnabled())): self.ch1_instr_limiter.toggled.connect(self.updateCheckboxes) self.updateStreamingState() #log.debug("device streaming flag: %d" % (self.is_streaming)) self.update_timer = QTimer(self) self.update_timer.timeout.connect(self.status_update) self.update_timer.start(1000) def saveSettings(self, indent): saveString = [] idt = indent + " " saveString.append('%s<inputmatrix>\n' % indent) saveString.extend(self.inputmatrix.saveSettings(idt)) # Do not forget to mention the adopted rule for matrix columns mixer # This might be useful for future import function saveString.append("%s <col_rule>\n" % indent) saveString.append("%s Columns_are_inputs\n" % indent) saveString.append("%s </col_rule>\n" % indent) saveString.append('%s</inputmatrix>\n' % indent) saveString.append('%s<playbackmatrix>\n' % indent) saveString.extend(self.inputmatrix.saveSettings(idt)) # Do not forget to mention the adopted rule for matrix columns mixer # This might be useful for future import function saveString.append("%s <col_rule>\n" % indent) saveString.append("%s Columns_are_inputs\n" % indent) saveString.append("%s </col_rule>\n" % indent) saveString.append('%s</playbackmatrix>\n' % indent) saveString.append('%s<outputmatrix>\n' % indent) saveString.extend(self.inputmatrix.saveSettings(idt)) # Do not forget to mention the adopted rule for matrix columns mixer # This might be useful for future import function saveString.append("%s <col_rule>\n" % indent) saveString.append("%s Columns_are_inputs\n" % indent) saveString.append("%s </col_rule>\n" % indent) saveString.append('%s</outputmatrix>\n' % indent) return saveString def readSettings(self, readString): try: idxb = readString.index('<inputmatrix>') idxe = readString.index('</inputmatrix>') except Exception: log.debug("No Input matrix settings found") idxb = -1 idxe = -1 if idxb >= 0: if idxe > idxb + 1: stringMixer = [] for s in readString[idxb + 1:idxe]: stringMixer.append(s) # When trying to import from a different device, the rule for column interpretation is # not necessarily the same try: idx = stringMixer.index('<col_rule>') except Exception: log.debug( 'Do not know how to handle column versus input/output') idx = -1 transpose_coeff = False if idx >= 0: if stringMixer[idx + 1].find("Columns_are_inputs") == -1: log.debug( 'Transposing the matrix coefficient; you are importing, are not you ?' ) transpose_coeff = True if self.inputmatrix.readSettings(stringMixer, transpose_coeff): log.debug("Input matrix settings modified") del stringMixer try: idxb = readString.index('<playbackmatrix>') idxe = readString.index('</playbackmatrix>') except Exception: log.debug("No Plaback matrix settings found") idxb = -1 idxe = -1 if idxb >= 0: if idxe > idxb + 1: stringMixer = [] for s in readString[idxb + 1:idxe]: stringMixer.append(s) # When trying to import from a different device, the rule for column interpretation is # not necessarily the same try: idx = stringMixer.index('<col_rule>') except Exception: log.debug( 'Do not know how to handle column versus input/output') idx = -1 transpose_coeff = False if idx >= 0: if stringMixer[idx + 1].find("Columns_are_inputs") == -1: log.debug( 'Transposing the matrix coefficient; you are importing, are not you ?' ) transpose_coeff = True if self.playbackmatrix.readSettings(stringMixer, transpose_coeff): log.debug("Plaback matrix settings modified") del stringMixer try: idxb = readString.index('<outputmatrix>') idxe = readString.index('</outputmatrix>') except Exception: log.debug("No Output matrix settings found") idxb = -1 idxe = -1 if idxb >= 0: if idxe > idxb + 1: stringMixer = [] for s in readString[idxb + 1:idxe]: stringMixer.append(s) # When trying to import from a different device, the rule for column interpretation is # not necessarily the same try: idx = stringMixer.index('<col_rule>') except Exception: log.debug( 'Do not know how to handle column versus input/output') idx = -1 transpose_coeff = False if idx >= 0: if stringMixer[idx + 1].find("Columns_are_inputs") == -1: log.debug( 'Transposing the matrix coefficient; you are importing, are not you ?' ) transpose_coeff = True if self.outputmatrix.readSettings(stringMixer, transpose_coeff): log.debug("Output matrix settings modified") del stringMixer
class Generic_Dice_EAP(QWidget): def __init__(self, parent=None): QWidget.__init__(self, parent) self.layout = QGridLayout(self) self.setLayout(self.layout) self.tabs = QTabWidget(self) self.tabs.setTabPosition(QTabWidget.West) self.layout.addWidget(self.tabs) def buildMixer(self): #print( self.hw ) #print( self.hw.getText("/Generic/Nickname") ) self.mixer = MatrixMixer(self.hw.servername, self.hw.basepath + "/EAP/MatrixMixer", self, "Columns_are_outputs", -1, None, None, False, QTabWidget.North, QTabWidget.Rounded) self.tabs.addTab(self.mixer, "Mixer") self.router_scrollarea = self.buildRouter( self.hw.servername, self.hw.basepath + "/EAP/Router") self.tabs.addTab(self.router_scrollarea, "Crossbar Router") def buildRouter(self, servername, path): self.router = CrossbarRouter(servername, path, self) self.router.MixerRoutingChanged.connect(self.mixer.updateRouting) scrollarea = QScrollArea(self.tabs) scrollarea.setWidgetResizable(True) scrollarea.setWidget(self.router) return scrollarea def onSamplerateChange(self): # Router configuration is samplerate dependent for DICE EAP devices # Destroy and redraw the crossbar router view when called n = self.tabs.indexOf(self.router_scrollarea) self.tabs.removeTab(n) self.router.destroy() self.router_scrollarea.destroy() self.router_scrollarea = self.buildRouter( self.hw.servername, self.hw.basepath + "/EAP/Router") self.tabs.insertTab(n, self.router_scrollarea, "Crossbar Router") self.tabs.setCurrentWidget(self.router_scrollarea) self.mixer.updateRouting() def saveSettings(self, indent): saveString = [] idt = indent + " " saveString.append('%s<mixer>\n' % indent) saveString.extend(self.mixer.saveSettings(idt)) # Do not forget to mention the adopted rule for matrix columns mixer # This might be useful for future import function saveString.append("%s <col_rule>\n" % indent) saveString.append("%s Columns_are_outputs\n" % indent) saveString.append("%s </col_rule>\n" % indent) saveString.append('%s</mixer>\n' % indent) saveString.append('%s<router>\n' % indent) saveString.extend(self.router.saveSettings(idt)) saveString.append('%s</router>\n' % indent) return saveString def readSettings(self, readString): try: idxb = readString.index('<mixer>') idxe = readString.index('</mixer>') except Exception: log.debug("No mixer settings found") idxb = -1 idxe = -1 if idxb >= 0: if idxe > idxb + 1: stringMixer = [] for s in readString[idxb + 1:idxe]: stringMixer.append(s) # When trying to import from a different device, the rule for column interpretation is # not necessarily the same try: idx = stringMixer.index('<col_rule>') except Exception: log.debug( 'Do not know how to handle column versus input/output') idx = -1 transpose_coeff = False if idx >= 0: if stringMixer[idx + 1].find("Columns_are_outputs") == -1: log.debug( 'Transposing the matrix coefficient; you are importing, are not you ?' ) transpose_coeff = True if self.mixer.readSettings(stringMixer, transpose_coeff): log.debug("Mixer settings modified") del stringMixer try: idxb = readString.index('<router>') idxe = readString.index('</router>') except Exception: log.debug("No router settings found") idxb = -1 idxe = -1 if idxb >= 0: if idxe > idxb + 1: stringRouter = [] for s in readString[idxb + 1:idxe]: stringRouter.append(s) if self.router.readSettings(stringRouter): log.debug("Router settings modified") del stringRouter
class Generic_Dice_EAP(QWidget): def __init__(self, parent=None): QWidget.__init__(self, parent) self.layout = QGridLayout(self) self.setLayout(self.layout) self.tabs = QTabWidget(self) self.tabs.setTabPosition(QTabWidget.West) self.layout.addWidget(self.tabs) def buildMixer(self): #print( self.hw ) #print( self.hw.getText("/Generic/Nickname") ) self.mixer = MatrixMixer(self.hw.servername, self.hw.basepath+"/EAP/MatrixMixer", self, "Columns_are_outputs", -1, None, None, False, QTabWidget.North, QTabWidget.Rounded) self.tabs.addTab(self.mixer, "Mixer") self.router_scrollarea = self.buildRouter(self.hw.servername, self.hw.basepath+"/EAP/Router") self.tabs.addTab(self.router_scrollarea, "Crossbar Router") def buildRouter(self, servername, path): self.router = CrossbarRouter(servername, path, self) self.router.MixerRoutingChanged.connect(self.mixer.updateRouting) scrollarea = QScrollArea(self.tabs) scrollarea.setWidgetResizable(True) scrollarea.setWidget(self.router) return scrollarea def onSamplerateChange(self): # Router configuration is samplerate dependent for DICE EAP devices # Destroy and redraw the crossbar router view when called n = self.tabs.indexOf(self.router_scrollarea) self.tabs.removeTab(n) self.router.destroy() self.router_scrollarea.destroy() self.router_scrollarea = self.buildRouter(self.hw.servername, self.hw.basepath+"/EAP/Router") self.tabs.insertTab(n, self.router_scrollarea, "Crossbar Router") self.tabs.setCurrentWidget(self.router_scrollarea) self.mixer.updateRouting() def saveSettings(self, indent): saveString = [] idt = indent + " " saveString.append('%s<mixer>\n' % indent) saveString.extend(self.mixer.saveSettings(idt)) # Do not forget to mention the adopted rule for matrix columns mixer # This might be useful for future import function saveString.append("%s <col_rule>\n" % indent) saveString.append("%s Columns_are_outputs\n" % indent) saveString.append("%s </col_rule>\n" % indent) saveString.append('%s</mixer>\n' % indent) saveString.append('%s<router>\n' % indent) saveString.extend(self.router.saveSettings(idt)) saveString.append('%s</router>\n' % indent) return saveString def readSettings(self, readString): try: idxb = readString.index('<mixer>') idxe = readString.index('</mixer>') except Exception: log.debug("No mixer settings found") idxb = -1 idxe = -1 if idxb >= 0: if idxe > idxb + 1: stringMixer = [] for s in readString[idxb+1:idxe]: stringMixer.append(s) # When trying to import from a different device, the rule for column interpretation is # not necessarily the same try: idx = stringMixer.index('<col_rule>') except Exception: log.debug('Do not know how to handle column versus input/output') idx = -1 transpose_coeff = False if idx >=0: if stringMixer[idx+1].find("Columns_are_outputs") == -1: log.debug('Transposing the matrix coefficient; you are importing, are not you ?') transpose_coeff = True if self.mixer.readSettings(stringMixer, transpose_coeff): log.debug("Mixer settings modified") del stringMixer try: idxb = readString.index('<router>') idxe = readString.index('</router>') except Exception: log.debug("No router settings found") idxb = -1 idxe = -1 if idxb >= 0: if idxe > idxb + 1: stringRouter = [] for s in readString[idxb+1:idxe]: stringRouter.append(s) if self.router.readSettings(stringRouter): log.debug("Router settings modified") del stringRouter
class Rme(QWidget): def __init__(self,parent = None): QWidget.__init__(self,parent) uicLoad("ffado/mixer/rme", self) self.init() def init(self): self.PhantomSwitches={ self.phantom_0: ['/Control/Phantom', 0], self.phantom_1: ['/Control/Phantom', 1], self.phantom_2: ['/Control/Phantom', 2], self.phantom_3: ['/Control/Phantom', 3], } self.Switches={ self.ff400_chan3_opt_instr: ['/Control/Chan3_opt_instr'], self.ff400_chan3_opt_pad: ['/Control/Chan3_opt_pad'], self.ff400_chan4_opt_instr: ['/Control/Chan4_opt_instr'], self.ff400_chan4_opt_pad: ['/Control/Chan4_opt_pad'], self.spdif_output_optical: ['/Control/SPDIF_output_optical', 0], self.spdif_output_emphasis: ['/Control/SPDIF_output_emphasis', 0], self.spdif_output_pro: ['/Control/SPDIF_output_pro', 0], self.spdif_output_nonaudio: ['/Control/SPDIF_output_nonaudio', 0], } self.Radiobuttons={ self.level_in_lo_gain: ['/Control/Input_level', 0], self.level_in_p4dBu: ['/Control/Input_level', 2], self.level_in_m10dBV: ['/Control/Input_level', 1], self.level_out_hi_gain: ['/Control/Output_level', 2], self.level_out_p4dBu: ['/Control/Output_level', 1], self.level_out_m10dBV: ['/Control/Output_level', 0], self.spdif_input_coax: ['/Control/SPDIF_input_mode', 0], self.spdif_input_optical: ['/Control/SPDIF_input_mode', 1], self.phones_hi_gain: ['/Control/Phones_level', 0], self.phones_p4dBu: ['/Control/Phones_level', 1], self.phones_m10dBV: ['/Control/Phones_level', 2], self.clock_mode_autosync: ['/Control/Clock_mode', 1], self.clock_mode_master: ['/Control/Clock_mode', 0], self.sync_ref_wordclk: ['/Control/Sync_ref', 0], self.sync_ref_adat1: ['/Control/Sync_ref', 1], self.sync_ref_adat2: ['/Control/Sync_ref', 2], self.sync_ref_spdif: ['/Control/Sync_ref', 3], self.sync_ref_tco: ['/Control/Sync_ref', 4], } self.Checkboxes={ self.ch1_instr_fuzz: ['/Control/Chan1_instr_opts', 0x04], self.ch1_instr_limiter: ['/Control/Chan1_instr_opts', 0x08], self.ch1_instr_filter: ['/Control/Chan1_instr_opts', 0x02], } self.Gains={ self.gain_mic1: ['/Control/Gains', 0], self.gain_mic2: ['/Control/Gains', 1], self.gain_input3: ['/Control/Gains', 2], self.gain_input4: ['/Control/Gains', 3], } self.Combos={ self.ff800_ch1_src: ['/Control/Chan1_source'], self.ff800_ch7_src: ['/Control/Chan7_source'], self.ff800_ch8_src: ['/Control/Chan8_source'], } self.CommandButtons={ self.control_load: ['/Control/Flash_control', 0], self.control_save: ['/Control/Flash_control', 1], self.mixer_load: ['/Control/Flash_control', 2], self.mixer_save: ['/Control/Flash_control', 3], self.mixer_preset_ffado_default: ['/Control/Mixer_preset', 0], } # Other mixer variables self.is_streaming = 0 self.sample_rate = 0 self.model = 0 self.tco_present = 0 # Public slot: update phantom power hardware switches def updatePhantomSwitch(self, a0): sender = self.sender() # Value is the phantom switch value, with a corresponding enable # bit in the high 16 bit word val = (a0 << self.PhantomSwitches[sender][1]) | (0x00010000 << self.PhantomSwitches[sender][1]) log.debug("phantom switch %d set to %d" % (self.PhantomSwitches[sender][1], a0)) self.hw.setDiscrete(self.PhantomSwitches[sender][0], val) # Public slot: update generic switches def updateSwitch(self, a0): sender = self.sender() log.debug("switch %s set to %d" % (self.Switches[sender][0], a0)) self.hw.setDiscrete(self.Switches[sender][0], a0) # Public slot: update generic radiobuttons def updateRadiobutton(self, a0): sender = self.sender() if (a0 != 0): # Only change the control state on a button being "checked" log.debug("radiobutton group %s set to %d" % (self.Radiobuttons[sender][0], self.Radiobuttons[sender][1])) self.hw.setDiscrete(self.Radiobuttons[sender][0], self.Radiobuttons[sender][1]) def updateCheckboxes(self, a0): sender = self.sender() val = self.hw.getDiscrete(self.Checkboxes[sender][0]); if (a0 != 0): val = val | self.Checkboxes[sender][1] else: val = val & ~self.Checkboxes[sender][1] log.debug("checkbox group %s set to %d" % (self.Checkboxes[sender][0], val)); self.hw.setDiscrete(self.Checkboxes[sender][0], val) # Public slot: update gains def updateGain(self, a0): sender = self.sender() log.debug("gain %s[%d] set to %d" % (self.Gains[sender][0], self.Gains[sender][1], a0)) self.hw.setMatrixMixerValue(self.Gains[sender][0], 0, self.Gains[sender][1], a0) def updateBandwidthLimit(self, a0): # Account for the "No ADAT-2" item which will not be present on # a FF400. if (self.model==RME_MODEL_FF400 and a0>0): a0 = a0 + 1 # log.debug("limit update: %d" % (a0)); self.hw.setDiscrete('/Control/Bandwidth_limit', a0); # Public slot: send command def sendCommand(self, a0): sender = self.sender() log.debug("command %d sent to %s" % (self.CommandButtons[sender][1], self.CommandButtons[sender][0])) self.hw.setDiscrete(self.CommandButtons[sender][0], self.CommandButtons[sender][1]) # If mixer values have been reloaded, refresh the mixer GUI. This # will also commit the new values to the hardware via the "changed" # signal handlers of the mixer elements. if (self.CommandButtons[sender][1] == 2): self.inputmatrix.refreshValues() self.outputmatrix.refreshValues() self.playbackmatrix.refreshValues() # If settings have been reloaded from flash, refresh the GUI. The # settings will be made active in the hardware via the "changed" # signal handlers of the respective GUI control widgets. if (self.CommandButtons[sender][1] == 0): self.getValuesFromFF() def updateCombo(self, a0): sender = self.sender() log.debug("combo %s set to %d" % (self.Combos[sender][0], a0)) self.hw.setDiscrete(self.Combos[sender][0], a0) # Enable the limiter control only when the front source is active if (sender == self.ff800_ch1_src): self.ch1_instr_limiter.setEnabled(a0==0) def updateStreamingState(self): ss = self.streamingstatus.selected() ss_txt = self.streamingstatus.getEnumLabel(ss) if ss_txt != 'Idle': self.is_streaming = True else: self.is_streaming = False if (self.last_streaming_state != self.is_streaming): self.bandwidth_limit.setEnabled(not(self.is_streaming)); self.control_load.setEnabled(not(self.is_streaming)); self.last_streaming_state = self.is_streaming def status_update(self): # log.debug("timer event") self.updateStreamingState() clk_mode = ['Master', 'Slave'] src_str = ['None', 'ADAT 1', 'ADAT 2', 'SPDIF', 'Wordclock', 'TCO'] sync_stat = ['No lock', 'Locked', 'Synced'] sysclock_mode = self.hw.getDiscrete('/Control/sysclock_mode') sysclock_freq = self.hw.getDiscrete('/Control/sysclock_freq') autosync_freq = self.hw.getDiscrete('/Control/autosync_freq') autosync_src = self.hw.getDiscrete('/Control/autosync_src') sync_status = self.hw.getDiscrete('/Control/sync_status') spdif_freq = self.hw.getDiscrete('/Control/spdif_freq') self.sysclock_freq.setText("%d Hz" % (sysclock_freq)) self.sysclock_mode.setText(clk_mode[sysclock_mode]) self.autosync_freq.setText("%d Hz" % (autosync_freq)) self.autosync_src.setText(src_str[autosync_src]) self.sync_check_adat1_status.setText(sync_stat[sync_status & 0x03]) self.sync_check_adat2_status.setText(sync_stat[(sync_status >> 2) & 0x03]) self.sync_check_spdif_status.setText(sync_stat[(sync_status >> 4) & 0x03]) self.sync_check_wclk_status.setText(sync_stat[(sync_status >> 6) & 0x03]) self.sync_check_tco_status.setText(sync_stat[(sync_status >> 8) & 0x03]) self.spdif_freq.setText("%d Hz" % (spdif_freq)) # Hide and disable a control def disable_hide(self,widget): for w in widget.children(): if isinstance(w, QWidget): w.hide() w.setEnabled(False) widget.hide() widget.setEnabled(False) def setupSignals(self): # Connect signal handlers for all command buttons for ctrl, info in self.CommandButtons.iteritems(): if (not(ctrl.isEnabled())): continue QObject.connect(ctrl, SIGNAL('clicked(bool)'), self.sendCommand) for ctrl, info in self.Combos.iteritems(): if (not(ctrl.isEnabled())): continue; QObject.connect(ctrl, SIGNAL('currentIndexChanged(int)'), self.updateCombo) QObject.connect(self.bandwidth_limit, SIGNAL('currentIndexChanged(int)'), self.updateBandwidthLimit) # Get current hardware values and connect GUI element signals to # their respective slots for ctrl, info in self.PhantomSwitches.iteritems(): if (not(ctrl.isEnabled())): continue QObject.connect(ctrl, SIGNAL('toggled(bool)'), self.updatePhantomSwitch) for ctrl, info in self.Switches.iteritems(): if (not(ctrl.isEnabled())): continue QObject.connect(ctrl, SIGNAL('toggled(bool)'), self.updateSwitch) for ctrl, info in self.Radiobuttons.iteritems(): if (not(ctrl.isEnabled())): continue; QObject.connect(ctrl, SIGNAL('toggled(bool)'), self.updateRadiobutton) for ctrl, info in self.Checkboxes.iteritems(): if (not(ctrl.isEnabled())): continue; QObject.connect(ctrl, SIGNAL('toggled(bool)'), self.updateCheckboxes) for ctrl, info in self.Gains.iteritems(): if (not(ctrl.isEnabled())): continue QObject.connect(ctrl, SIGNAL('valueChanged(int)'), self.updateGain) # Obtain control values from the Fireface and make the GUI reflect these def getValuesFromFF(self): for ctrl, info in self.Combos.iteritems(): if (not(ctrl.isEnabled())): continue; val = self.hw.getDiscrete(info[0]) log.debug("combo %s is %d" % (info[0], val)); ctrl.setCurrentIndex(val); # Set the bandwidth limit control to reflect the current device # setting, allowing for the additional "No ADAT-2" item which is # present on the FF800. val = self.hw.getDiscrete('/Control/Bandwidth_limit') if (self.model==RME_MODEL_FF400 and val>1): val = val - 1 self.bandwidth_limit.setCurrentIndex(val); # Get current hardware values for ctrl, info in self.PhantomSwitches.iteritems(): if (not(ctrl.isEnabled())): continue val = (self.hw.getDiscrete(info[0]) >> info[1]) & 0x01 log.debug("phantom switch %d is %d" % (info[1], val)) if val: ctrl.setChecked(True) else: ctrl.setChecked(False) for ctrl, info in self.Switches.iteritems(): if (not(ctrl.isEnabled())): continue val = self.hw.getDiscrete(info[0]) log.debug("switch %s is %d" % (info[0], val)) if val: ctrl.setChecked(True) else: ctrl.setChecked(False) for ctrl, info in self.Radiobuttons.iteritems(): if (not(ctrl.isEnabled())): continue; # This is a touch wasteful since it means we retrieve the control # value once per radio button rather than once per radio button # group. In time we might introduce radiobutton groupings in the # self.* datastructures to avoid this, but for the moment this is # easy and it works. val = self.hw.getDiscrete(info[0]) if (val == info[1]): val = 1 else: val = 0 ctrl.setChecked(val) log.debug("Radiobutton %s[%d] is %d" % (info[0], info[1], val)) # Make sure the Limiter control can receive a value if (self.ff800_ch1_src.isEnabled()): self.ch1_instr_limiter.setEnabled(1) for ctrl, info in self.Checkboxes.iteritems(): if (not(ctrl.isEnabled())): continue; # This is a touch wasteful since it means we retrieve the control # value once per checkbox button rather than once per checkbox # group. In time we might introduce checkbox groupings in the # self.* datastructures to avoid this, but for the moment this is # easy and it works. val = self.hw.getDiscrete(info[0]) if (val & info[1]): val = 1 else: val = 0 ctrl.setChecked(val) log.debug("Checkbox %s[%d] is %d" % (info[0], info[1], val)) # The limiter (a checkbox) can only be controlled if the front # source is selected for channel 1. ch1_src = self.ff800_ch1_src.currentIndex() if (self.ff800_ch1_src.isEnabled()): self.ch1_instr_limiter.setEnabled(ch1_src==0) for ctrl, info in self.Gains.iteritems(): if (not(ctrl.isEnabled())): continue val = self.hw.getMatrixMixerValue(info[0], 0, info[1]) log.debug("gain %s[%d] is %d" % (info[0], info[1], val)) ctrl.setValue(val); def initValues(self): # print self.hw.servername # print self.hw.basepath self.inputmatrix = MatrixMixer(self.hw.servername, self.hw.basepath+"/Mixer/InputFaders", self, "Columns_are_inputs", 0x8000, self.hw.basepath+"/Mixer/InputMutes", self.hw.basepath+"/Mixer/InputInverts", True) layout = QtGui.QVBoxLayout() layout.addWidget(self.inputmatrix) self.mixer.setLayout(layout) self.playbackmatrix = MatrixMixer(self.hw.servername, self.hw.basepath+"/Mixer/PlaybackFaders", self, "Columns_are_inputs", 0x8000, self.hw.basepath+"/Mixer/PlaybackMutes", self.hw.basepath+"/Mixer/PlaybackInverts", True) layout = QtGui.QVBoxLayout() layout.addWidget(self.playbackmatrix) self.playbackmixer.setLayout(layout) self.outputmatrix = MatrixMixer(self.hw.servername, self.hw.basepath+"/Mixer/OutputFaders", self, "Columns_are_inputs", 0x8000, self.hw.basepath+"/Mixer/OutputMutes", None, True) layout = QtGui.QVBoxLayout() # This is a bit of a hack, but it works to ensure this single-row # matrix mixer doesn't fill the entire screen but also doesn't end # up with a pointless scrollbar. The matrix mixer's minimum height # is 0 according to minimumHeight(), which is probably the # fundamental issue here; however, I've already wasted too much time # trying to get this to work so if the hack is effective we'll run # with it. self.outputmatrix.setMinimumHeight(150) layout.addWidget(self.outputmatrix, 0, Qt.AlignTop) self.outputmixer.setLayout(layout) self.is_streaming = False self.last_streaming_state = False # Disable the "load settings" button if streaming is active. Its # enable state will be kept up to date by updateStreamingState(). self.control_load.setEnabled(not(self.is_streaming)) # Also disable other controls which are not yet implemented. self.mixer_preset_ffado_default.setEnabled(False) # Retrieve other device settings as needed and customise the UI # based on these options. self.model = self.hw.getDiscrete('/Control/Model') log.debug("device model identifier: %d" % (self.model)) self.tco_present = self.hw.getDiscrete('/Control/TCO_present') log.debug("device has TCO: %d" % (self.tco_present)) #self.sample_rate = self.hw.getDiscrete('/Mixer/Info/SampleRate') #log.debug("device sample rate: %d" % (self.sample_rate)) # The Fireface-400 only has 2 phantom-capable channels if (self.model == RME_MODEL_FF400): self.disable_hide(self.phantom_2) self.disable_hide(self.phantom_3) else: self.phantom_0.setText("Mic 7") self.phantom_1.setText("Mic 8") self.phantom_2.setText("Mic 9") self.phantom_3.setText("Mic 10") # Instrument options, input jack selection controls and an ADAT2 # input are applicable only to the FF800 if (self.model != RME_MODEL_FF800): self.instrument_options_group.setEnabled(False) self.input_plug_select_group.setEnabled(False) self.sync_ref_adat2.setEnabled(False) self.sync_check_adat2_label.setEnabled(False) self.sync_check_adat2_status.setEnabled(False) if (not(self.tco_present)): self.sync_check_tco_label.setEnabled(False) self.sync_check_tco_status.setEnabled(False) self.sync_ref_tco.setEnabled(False) # Only the FF400 has specific channel 3/4 options, input gain # controls and switchable phones level if (self.model != RME_MODEL_FF400): # Hide the upper-level frame (and everything in it) to ensure it # requests no vertical space when its contents aren't needed. self.disable_hide(self.igains_chan34_opts_frame) self.phones_level_group.setEnabled(False) # Add the "No ADAT-2" item to the bandwidth limit control if the # device is not a FF400. if (self.model != RME_MODEL_FF400): self.bandwidth_limit.insertItem(1, "No ADAT-2") self.getValuesFromFF() self.setupSignals() # Ensure the limiter checkbox has a signal handler associated with # it. If getValuesFromFF() disabled it because the front input was # not selected, setupSignals() would not have configured a handler. if (not(self.ch1_instr_limiter.isEnabled())): QObject.connect(self.ch1_instr_limiter, SIGNAL('toggled(bool)'), self.updateCheckboxes) self.updateStreamingState() #log.debug("device streaming flag: %d" % (self.is_streaming)) self.update_timer = QTimer(self) QObject.connect(self.update_timer, SIGNAL('timeout()'), self.status_update) self.update_timer.start(1000) def saveSettings(self, indent): saveString = [] idt = indent + " " saveString.append('%s<inputmatrix>\n' % indent) saveString.extend(self.inputmatrix.saveSettings(idt)) # Do not forget to mention the adopted rule for matrix columns mixer # This might be useful for future import function saveString.append("%s <col_rule>\n" % indent) saveString.append("%s Columns_are_inputs\n" % indent) saveString.append("%s </col_rule>\n" % indent) saveString.append('%s</inputmatrix>\n' % indent) saveString.append('%s<playbackmatrix>\n' % indent) saveString.extend(self.inputmatrix.saveSettings(idt)) # Do not forget to mention the adopted rule for matrix columns mixer # This might be useful for future import function saveString.append("%s <col_rule>\n" % indent) saveString.append("%s Columns_are_inputs\n" % indent) saveString.append("%s </col_rule>\n" % indent) saveString.append('%s</playbackmatrix>\n' % indent) saveString.append('%s<outputmatrix>\n' % indent) saveString.extend(self.inputmatrix.saveSettings(idt)) # Do not forget to mention the adopted rule for matrix columns mixer # This might be useful for future import function saveString.append("%s <col_rule>\n" % indent) saveString.append("%s Columns_are_inputs\n" % indent) saveString.append("%s </col_rule>\n" % indent) saveString.append('%s</outputmatrix>\n' % indent) return saveString def readSettings(self, readString): try: idxb = readString.index('<inputmatrix>') idxe = readString.index('</inputmatrix>') except Exception: log.debug("No Input matrix settings found") idxb = -1 idxe = -1 if idxb >= 0: if idxe > idxb + 1: stringMixer = [] for s in readString[idxb+1:idxe]: stringMixer.append(s) # When trying to import from a different device, the rule for column interpretation is # not necessarily the same try: idx = stringMixer.index('<col_rule>') except Exception: log.debug('Do not know how to handle column versus input/output') idx = -1 transpose_coeff = False if idx >=0: if stringMixer[idx+1].find("Columns_are_inputs") == -1: log.debug('Transposing the matrix coefficient; you are importing, are not you ?') transpose_coeff = True if self.inputmatrix.readSettings(stringMixer, transpose_coeff): log.debug("Input matrix settings modified") del stringMixer try: idxb = readString.index('<playbackmatrix>') idxe = readString.index('</playbackmatrix>') except Exception: log.debug("No Plaback matrix settings found") idxb = -1 idxe = -1 if idxb >= 0: if idxe > idxb + 1: stringMixer = [] for s in readString[idxb+1:idxe]: stringMixer.append(s) # When trying to import from a different device, the rule for column interpretation is # not necessarily the same try: idx = stringMixer.index('<col_rule>') except Exception: log.debug('Do not know how to handle column versus input/output') idx = -1 transpose_coeff = False if idx >=0: if stringMixer[idx+1].find("Columns_are_inputs") == -1: log.debug('Transposing the matrix coefficient; you are importing, are not you ?') transpose_coeff = True if self.playbackmatrix.readSettings(stringMixer, transpose_coeff): log.debug("Plaback matrix settings modified") del stringMixer try: idxb = readString.index('<outputmatrix>') idxe = readString.index('</outputmatrix>') except Exception: log.debug("No Output matrix settings found") idxb = -1 idxe = -1 if idxb >= 0: if idxe > idxb + 1: stringMixer = [] for s in readString[idxb+1:idxe]: stringMixer.append(s) # When trying to import from a different device, the rule for column interpretation is # not necessarily the same try: idx = stringMixer.index('<col_rule>') except Exception: log.debug('Do not know how to handle column versus input/output') idx = -1 transpose_coeff = False if idx >=0: if stringMixer[idx+1].find("Columns_are_inputs") == -1: log.debug('Transposing the matrix coefficient; you are importing, are not you ?') transpose_coeff = True if self.outputmatrix.readSettings(stringMixer, transpose_coeff): log.debug("Output matrix settings modified") del stringMixer
def initValues(self): # print self.hw.servername # print self.hw.basepath self.inputmatrix = MatrixMixer(self.hw.servername, self.hw.basepath+"/Mixer/InputFaders", self, "Columns_are_inputs", 0x8000, self.hw.basepath+"/Mixer/InputMutes", self.hw.basepath+"/Mixer/InputInverts", True) layout = QtGui.QVBoxLayout() layout.addWidget(self.inputmatrix) self.mixer.setLayout(layout) self.playbackmatrix = MatrixMixer(self.hw.servername, self.hw.basepath+"/Mixer/PlaybackFaders", self, "Columns_are_inputs", 0x8000, self.hw.basepath+"/Mixer/PlaybackMutes", self.hw.basepath+"/Mixer/PlaybackInverts", True) layout = QtGui.QVBoxLayout() layout.addWidget(self.playbackmatrix) self.playbackmixer.setLayout(layout) self.outputmatrix = MatrixMixer(self.hw.servername, self.hw.basepath+"/Mixer/OutputFaders", self, "Columns_are_inputs", 0x8000, self.hw.basepath+"/Mixer/OutputMutes", None, True) layout = QtGui.QVBoxLayout() # This is a bit of a hack, but it works to ensure this single-row # matrix mixer doesn't fill the entire screen but also doesn't end # up with a pointless scrollbar. The matrix mixer's minimum height # is 0 according to minimumHeight(), which is probably the # fundamental issue here; however, I've already wasted too much time # trying to get this to work so if the hack is effective we'll run # with it. self.outputmatrix.setMinimumHeight(150) layout.addWidget(self.outputmatrix, 0, Qt.AlignTop) self.outputmixer.setLayout(layout) self.is_streaming = False self.last_streaming_state = False # Disable the "load settings" button if streaming is active. Its # enable state will be kept up to date by updateStreamingState(). self.control_load.setEnabled(not(self.is_streaming)) # Also disable other controls which are not yet implemented. self.mixer_preset_ffado_default.setEnabled(False) # Retrieve other device settings as needed and customise the UI # based on these options. self.model = self.hw.getDiscrete('/Control/Model') log.debug("device model identifier: %d" % (self.model)) self.tco_present = self.hw.getDiscrete('/Control/TCO_present') log.debug("device has TCO: %d" % (self.tco_present)) #self.sample_rate = self.hw.getDiscrete('/Mixer/Info/SampleRate') #log.debug("device sample rate: %d" % (self.sample_rate)) # The Fireface-400 only has 2 phantom-capable channels if (self.model == RME_MODEL_FF400): self.disable_hide(self.phantom_2) self.disable_hide(self.phantom_3) else: self.phantom_0.setText("Mic 7") self.phantom_1.setText("Mic 8") self.phantom_2.setText("Mic 9") self.phantom_3.setText("Mic 10") # Instrument options, input jack selection controls and an ADAT2 # input are applicable only to the FF800 if (self.model != RME_MODEL_FF800): self.instrument_options_group.setEnabled(False) self.input_plug_select_group.setEnabled(False) self.sync_ref_adat2.setEnabled(False) self.sync_check_adat2_label.setEnabled(False) self.sync_check_adat2_status.setEnabled(False) if (not(self.tco_present)): self.sync_check_tco_label.setEnabled(False) self.sync_check_tco_status.setEnabled(False) self.sync_ref_tco.setEnabled(False) # Only the FF400 has specific channel 3/4 options, input gain # controls and switchable phones level if (self.model != RME_MODEL_FF400): # Hide the upper-level frame (and everything in it) to ensure it # requests no vertical space when its contents aren't needed. self.disable_hide(self.igains_chan34_opts_frame) self.phones_level_group.setEnabled(False) # Add the "No ADAT-2" item to the bandwidth limit control if the # device is not a FF400. if (self.model != RME_MODEL_FF400): self.bandwidth_limit.insertItem(1, "No ADAT-2") self.getValuesFromFF() self.setupSignals() # Ensure the limiter checkbox has a signal handler associated with # it. If getValuesFromFF() disabled it because the front input was # not selected, setupSignals() would not have configured a handler. if (not(self.ch1_instr_limiter.isEnabled())): QObject.connect(self.ch1_instr_limiter, SIGNAL('toggled(bool)'), self.updateCheckboxes) self.updateStreamingState() #log.debug("device streaming flag: %d" % (self.is_streaming)) self.update_timer = QTimer(self) QObject.connect(self.update_timer, SIGNAL('timeout()'), self.status_update) self.update_timer.start(1000)
def initValues(self): # print self.hw.servername # print self.hw.basepath self.inputmatrix = MatrixMixer( self.hw.servername, self.hw.basepath + "/Mixer/InputFaders", self, 0x8000, self.hw.basepath + "/Mixer/InputMutes", self.hw.basepath + "/Mixer/InputInverts", True) layout = QtGui.QVBoxLayout() scrollarea = QtGui.QScrollArea() scrollarea.setWidgetResizable(True) scrollarea.setWidget(self.inputmatrix) layout.addWidget(scrollarea) self.mixer.setLayout(layout) self.playbackmatrix = MatrixMixer( self.hw.servername, self.hw.basepath + "/Mixer/PlaybackFaders", self, 0x8000, self.hw.basepath + "/Mixer/PlaybackMutes", self.hw.basepath + "/Mixer/PlaybackInverts", True) layout = QtGui.QVBoxLayout() scrollarea = QtGui.QScrollArea() scrollarea.setWidgetResizable(True) scrollarea.setWidget(self.playbackmatrix) layout.addWidget(scrollarea) self.playbackmixer.setLayout(layout) self.outputmatrix = MatrixMixer( self.hw.servername, self.hw.basepath + "/Mixer/OutputFaders", self, 0x8000, self.hw.basepath + "/Mixer/OutputMutes", None, True) layout = QtGui.QVBoxLayout() scrollarea = QtGui.QScrollArea() scrollarea.setWidget(self.outputmatrix) scrollarea.setWidgetResizable(True) # This is a bit of a hack, but it works to ensure this single-row # matrix mixer doesn't fill the entire screen but also doesn't end # up with a pointless scrollbar. The matrix mixer's minimum height # is 0 according to minimumHeight(), which is probably the # fundamental issue here; however, I've already wasted too much time # trying to get this to work so if the hack is effective we'll run # with it. scrollarea.setMinimumHeight(150) layout.addWidget(scrollarea, 0, Qt.AlignTop) self.outputmixer.setLayout(layout) self.is_streaming = False self.last_streaming_state = False # Retrieve other device settings as needed and customise the UI # based on these options. self.model = self.hw.getDiscrete('/Control/Model') log.debug("device model identifier: %d" % (self.model)) self.tco_present = self.hw.getDiscrete('/Control/TCO_present') log.debug("device has TCO: %d" % (self.tco_present)) #self.sample_rate = self.hw.getDiscrete('/Mixer/Info/SampleRate') #log.debug("device sample rate: %d" % (self.sample_rate)) # The Fireface-400 only has 2 phantom-capable channels if (self.model == RME_MODEL_FF400): self.disable_hide(self.phantom_2) self.disable_hide(self.phantom_3) else: self.phantom_0.setText("Mic 7") self.phantom_1.setText("Mic 8") self.phantom_2.setText("Mic 9") self.phantom_3.setText("Mic 10") # Instrument options, input jack selection controls and an ADAT2 # input are applicable only to the FF800 if (self.model != RME_MODEL_FF800): self.instrument_options_group.setEnabled(False) self.input_plug_select_group.setEnabled(False) self.sync_ref_adat2.setEnabled(False) self.sync_check_adat2_label.setEnabled(False) self.sync_check_adat2_status.setEnabled(False) for ctrl, info in self.Combos.iteritems(): if (not (ctrl.isEnabled())): continue val = self.hw.getDiscrete(info[0]) log.debug("combo %s is %d" % (info[0], val)) ctrl.setCurrentIndex(val) QObject.connect(ctrl, SIGNAL('currentIndexChanged(int)'), self.updateCombo) if (not (self.tco_present)): self.sync_check_tco_label.setEnabled(False) self.sync_check_tco_status.setEnabled(False) self.sync_ref_tco.setEnabled(False) # Only the FF400 has specific channel 3/4 options, input gain # controls and switchable phones level if (self.model != RME_MODEL_FF400): self.disable_hide(self.input_gains_group) self.disable_hide(self.channel_3_4_options_group) self.phones_level_group.setEnabled(False) # Add the "No ADAT-2" item to the bandwidth limit control if the # device is not a FF400. Set the control to reflect the current # device setting and connect an update signal. if (self.model != RME_MODEL_FF400): self.bandwidth_limit.insertItem(1, "No ADAT-2") val = self.hw.getDiscrete('/Control/Bandwidth_limit') if (self.model == RME_MODEL_FF400 and val > 1): val = val - 1 self.bandwidth_limit.setCurrentIndex(val) QObject.connect(self.bandwidth_limit, SIGNAL('currentIndexChanged(int)'), self.updateBandwidthLimit) # Get current hardware values and connect GUI element signals to # their respective slots for ctrl, info in self.PhantomSwitches.iteritems(): if (not (ctrl.isEnabled())): continue val = (self.hw.getDiscrete(info[0]) >> info[1]) & 0x01 log.debug("phantom switch %d is %d" % (info[1], val)) if val: ctrl.setChecked(True) else: ctrl.setChecked(False) QObject.connect(ctrl, SIGNAL('toggled(bool)'), self.updatePhantomSwitch) for ctrl, info in self.Switches.iteritems(): if (not (ctrl.isEnabled())): continue val = self.hw.getDiscrete(info[0]) log.debug("switch %s is %d" % (info[0], val)) if val: ctrl.setChecked(True) else: ctrl.setChecked(False) QObject.connect(ctrl, SIGNAL('toggled(bool)'), self.updateSwitch) for ctrl, info in self.Radiobuttons.iteritems(): if (not (ctrl.isEnabled())): continue # This is a touch wasteful since it means we retrieve the control # value once per radio button rather than once per radio button # group. In time we might introduce radiobutton groupings in the # self.* datastructures to avoid this, but for the moment this is # easy and it works. val = self.hw.getDiscrete(info[0]) if (val == info[1]): val = 1 else: val = 0 ctrl.setChecked(val) log.debug("Radiobutton %s[%d] is %d" % (info[0], info[1], val)) QObject.connect(ctrl, SIGNAL('toggled(bool)'), self.updateRadiobutton) for ctrl, info in self.Checkboxes.iteritems(): if (not (ctrl.isEnabled())): continue # This is a touch wasteful since it means we retrieve the control # value once per checkbox button rather than once per checkbox # group. In time we might introduce checkbox groupings in the # self.* datastructures to avoid this, but for the moment this is # easy and it works. val = self.hw.getDiscrete(info[0]) if (val & info[1]): val = 1 else: val = 0 ctrl.setChecked(val) log.debug("Checkbox %s[%d] is %d" % (info[0], info[1], val)) QObject.connect(ctrl, SIGNAL('toggled(bool)'), self.updateCheckboxes) for ctrl, info in self.Gains.iteritems(): if (not (ctrl.isEnabled())): continue val = self.hw.getMatrixMixerValue(info[0], 0, info[1]) log.debug("gain %s[%d] is %d" % (info[0], info[1], val)) ctrl.setValue(val) QObject.connect(ctrl, SIGNAL('valueChanged(int)'), self.updateGain) self.updateStreamingState() #log.debug("device streaming flag: %d" % (self.is_streaming)) self.update_timer = QTimer(self) QObject.connect(self.update_timer, SIGNAL('timeout()'), self.status_update) self.update_timer.start(1000)