#!/usr/bin/python # # Copyright (C) 2005-2007 by Pieter Palmers # 2007-2008 by Arnold Krille # # This file is part of FFADO # FFADO = Free Firewire (pro-)audio drivers for linux # # FFADO is based upon FreeBoB. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # import sys # Add the path of the installed ffado-mixer-modules sys.path.append( "$PYTHONDIR" ) from ffadomixer_config import FFADO_VERSION import os import time import dbus from qt import * from ffado_registration import * from mixer_phase88 import * from mixer_phase24 import * from mixer_saffire import * from mixer_saffirele import * from mixer_saffirepro import * from mixer_audiofire import * from mixer_bcoaudio5 import * from mixer_edirolfa66 import * from mixer_edirolfa101 import * from mixer_mackie_generic import * from mixer_quatafire import * from mixer_motu import * from mixer_dummy import * from mixer_global import * use_generic = False try: from mixer_generic import * print "The generic mixer is found, seems to be a developer using ffadomixer..." except ImportError: pass else: use_generic = True SupportedDevices=[ [(0x000aac, 0x00000003),'Phase88Control'], [(0x000aac, 0x00000004),'Phase24Control'], [(0x000aac, 0x00000007),'Phase24Control'], [(0x00130e, 0x00000003),'SaffireProMixer'], [(0x00130e, 0x00000006),'SaffireProMixer'], [(0x00130e, 0x00000000),'SaffireMixer'], [(0x001486, 0x00000af2),'AudioFireMixer'], [(0x001486, 0x00000af4),'AudioFireMixer'], [(0x001486, 0x00000af8),'AudioFireMixer'], [(0x001486, 0x0000af12),'AudioFireMixer'], [(0x0007f5, 0x00010049),'BCoAudio5Control'], [(0x0040AB, 0x00010049),'EdirolFa66Control'], [(0x0040AB, 0x00010048),'EdirolFa101Control'], [(0x00000f, 0x00010067),'MackieGenericControl'], [(0x000f1b, 0x00010064),'QuataFireMixer'], [(0x0001f2, 0x00000000),'MotuMixer'], ] POLL_SLEEP_TIME_MSEC = 100 # 100ms class ControlInterface: def __init__(self, servername, basepath): self.basepath=basepath self.servername=servername self.bus=dbus.SessionBus() def setContignuous(self, subpath, v, idx=None): try: path = self.basepath + subpath dev = self.bus.get_object(self.servername, path) dev_cont = dbus.Interface(dev, dbus_interface='org.ffado.Control.Element.Continuous') if idx == None: dev_cont.setValue(v) else: dev_cont.setValueIdx(idx,v) except: print "Failed to set Continuous %s on server %s" % (path, self.servername) def getContignuous(self, subpath, idx=None): try: path = self.basepath + subpath dev = self.bus.get_object(self.servername, path) dev_cont = dbus.Interface(dev, dbus_interface='org.ffado.Control.Element.Continuous') if idx == None: return dev_cont.getValue() else: return dev_cont.getValueIdx(idx) except: print "Failed to get Continuous %s on server %s" % (path, self.servername) return 0 def setDiscrete(self, subpath, v): try: path = self.basepath + subpath dev = self.bus.get_object(self.servername, path) dev_cont = dbus.Interface(dev, dbus_interface='org.ffado.Control.Element.Discrete') dev_cont.setValue(v) except: print "Failed to set Discrete %s on server %s" % (path, self.servername) def getDiscrete(self, subpath): try: path = self.basepath + subpath dev = self.bus.get_object(self.servername, path) dev_cont = dbus.Interface(dev, dbus_interface='org.ffado.Control.Element.Discrete') return dev_cont.getValue() except: print "Failed to get Discrete %s on server %s" % (path, self.servername) return 0 def setText(self, subpath, v): try: path = self.basepath + subpath dev = self.bus.get_object(self.servername, path) dev_cont = dbus.Interface(dev, dbus_interface='org.ffado.Control.Element.Text') dev_cont.setValue(v) except: print "Failed to set Text %s on server %s" % (path, self.servername) def getText(self, subpath): try: path = self.basepath + subpath dev = self.bus.get_object(self.servername, path) dev_cont = dbus.Interface(dev, dbus_interface='org.ffado.Control.Element.Text') return dev_cont.getValue() except: print "Failed to get Text %s on server %s" % (path, self.servername) return 0 def setMatrixMixerValue(self, subpath, row, col, v): try: path = self.basepath + subpath dev = self.bus.get_object(self.servername, path) dev_cont = dbus.Interface(dev, dbus_interface='org.ffado.Control.Element.MatrixMixer') dev_cont.setValue(row, col, v) except: print "Failed to set MatrixMixer %s on server %s" % (path, self.servername) def getMatrixMixerValue(self, subpath, row, col): try: path = self.basepath + subpath dev = self.bus.get_object(self.servername, path) dev_cont = dbus.Interface(dev, dbus_interface='org.ffado.Control.Element.MatrixMixer') return dev_cont.getValue(row, col) except: print "Failed to get MatrixMixer %s on server %s" % (path, self.servername) return 0 def enumSelect(self, subpath, v): try: path = self.basepath + subpath dev = self.bus.get_object(self.servername, path) dev_cont = dbus.Interface(dev, dbus_interface='org.ffado.Control.Element.Enum') dev_cont.select(v) except: print "Failed to select %s on server %s" % (path, self.servername) def enumSelected(self, subpath): try: path = self.basepath + subpath dev = self.bus.get_object(self.servername, path) dev_cont = dbus.Interface(dev, dbus_interface='org.ffado.Control.Element.Enum') return dev_cont.selected() except: print "Failed to get selected enum %s on server %s" % (path, self.servername) return 0 def enumGetLabel(self, subpath, v): try: path = self.basepath + subpath dev = self.bus.get_object(self.servername, path) dev_cont = dbus.Interface(dev, dbus_interface='org.ffado.Control.Element.Enum') return dev_cont.getEnumLabel(v) except: print "Failed to get enum label %s on server %s" % (path, self.servername) return 0 def enumCount(self, subpath): try: path = self.basepath + subpath dev = self.bus.get_object(self.servername, path) dev_cont = dbus.Interface(dev, dbus_interface='org.ffado.Control.Element.Enum') return dev_cont.count() except: print "Failed to get enum count %s on server %s" % (path, self.servername) return 0 class DeviceManagerInterface: def __init__(self, servername, basepath): self.basepath=basepath + '/DeviceManager' self.servername=servername self.bus=dbus.SessionBus() self.dev = self.bus.get_object(self.servername, self.basepath) self.iface = dbus.Interface(self.dev, dbus_interface='org.ffado.Control.Element.Container') # signal reception does not work yet since we need a mainloop for that # and qt3 doesn't provide one for python/dbus #try: #self.dev.connect_to_signal("Updated", self.updateSignal, \ #dbus_interface="org.ffado.Control.Element.Container", arg0=self) #except dbus.DBusException: #traceback.print_exc() #def updateSignal(self): #print ("Received update signal") def getNbDevices(self): return self.iface.getNbElements() def getDeviceName(self, idx): return self.iface.getElementName(idx) class ConfigRomInterface: def __init__(self, servername, devicepath): self.basepath=devicepath + '/ConfigRom' self.servername=servername self.bus=dbus.SessionBus() self.dev = self.bus.get_object(self.servername, self.basepath) self.iface = dbus.Interface(self.dev, dbus_interface='org.ffado.Control.Element.ConfigRomX') def getGUID(self): return self.iface.getGUID() def getVendorName(self): return self.iface.getVendorName() def getModelName(self): return self.iface.getModelName() def getVendorId(self): return self.iface.getVendorId() def getModelId(self): return self.iface.getModelId() def getUnitVersion(self): return self.iface.getUnitVersion() class ClockSelectInterface: def __init__(self, servername, devicepath): self.basepath=devicepath + '/Generic/ClockSelect' self.servername=servername self.bus=dbus.SessionBus() self.dev = self.bus.get_object(self.servername, self.basepath) self.iface = dbus.Interface(self.dev, dbus_interface='org.ffado.Control.Element.AttributeEnum') def count(self): return self.iface.count() def select(self, idx): return self.iface.select(idx) def selected(self): return self.iface.selected() def getEnumLabel(self, idx): return self.iface.getEnumLabel(idx) def attributeCount(self): return self.iface.attributeCount() def getAttributeValue(self, idx): return self.iface.getAttributeValue(idx) def getAttributeName(self, idx): return self.iface.getAttributeName(idx) class SamplerateSelectInterface: def __init__(self, servername, devicepath): self.basepath=devicepath + '/Generic/SamplerateSelect' self.servername=servername self.bus=dbus.SessionBus() self.dev = self.bus.get_object(self.servername, self.basepath) self.iface = dbus.Interface(self.dev, dbus_interface='org.ffado.Control.Element.Enum') def count(self): return self.iface.count() def select(self, idx): return self.iface.select(idx) def selected(self): return self.iface.selected() def getEnumLabel(self, idx): return self.iface.getEnumLabel(idx) class TextInterface: def __init__(self, servername, basepath): self.basepath=basepath self.servername=servername self.bus=dbus.SessionBus() self.dev = self.bus.get_object( self.servername, self.basepath ) self.iface = dbus.Interface( self.dev, dbus_interface="org.ffado.Control.Element.Text" ) def text(self): return self.iface.getValue() def setText(self,text): self.iface.setValue(text) class HLine( QFrame ): def __init__( self, parent ): QFrame.__init__( self, parent ) self.setFrameShape( QFrame.HLine ) self.setLineWidth( 2 ) self.setMinimumHeight( 10 ) class PollUpdateWidgets(QObject): def __init__(self, widgets): QObject.__init__(self) self.widgets = widgets def updateWidgets(self): for w in self.widgets: if 'polledUpdate' in dir(w): try: w.polledUpdate() except: print "error in polled update" if __name__ == "__main__": server='org.ffado.Control' basepath='/org/ffado/Control' app = QApplication(sys.argv) msg = QMessageBox() repeat = 1 while repeat > 0: try: devmgr=DeviceManagerInterface(server, basepath) nbDevices=devmgr.getNbDevices() repeat -= 1 except dbus.DBusException, ex: print "\n" print "===========================================================" print "ERROR: Could not communicate with the FFADO DBus service..." print "===========================================================" print "\n" tmp = msg.question( msg, "FFADO-DBus not found", "The connection to FFADOs DBus service could not be established.

Probably you didn't start the ffado-dbus-server. Should I try this now?", QMessageBox.Yes, QMessageBox.No ) if tmp == 4: sys.exit(-1) else: os.spawnlp( os.P_NOWAIT, "ffado-dbus-server" ) nb_checks = 20 while nb_checks > 0: nb_checks = nb_checks - 1 try: devmgr=DeviceManagerInterface(server, basepath) nbDevices=devmgr.getNbDevices() nb_checks = 0 repeat = 0 except dbus.DBusException, ex: time.sleep( 1 ) if nbDevices == 0: print "No supported device found..." msg.information( msg, "No mixer found", "No devices with mixer support discovered." ) sys.exit( -1 ) mw = QTabWidget() mixerwidgets = [] for idx in range(nbDevices): path=devmgr.getDeviceName(idx) print "Found device %d: %s" % (idx, path) cfgrom = ConfigRomInterface(server, basepath+'/DeviceManager/'+path) vendorId = cfgrom.getVendorId() modelId = cfgrom.getModelId() unitVersion = cfgrom.getUnitVersion() GUID = cfgrom.getGUID() vendorName = cfgrom.getVendorName() modelName = cfgrom.getModelName() print " Found (%s, %X, %X) %s %s" % (str(GUID), vendorId, modelId, vendorName, modelName) # check whether this has already been registered at ffado.org reg = ffado_registration(FFADO_VERSION, int(GUID, 16), vendorId, modelId, vendorName, modelName) reg.check_for_registration() thisdev=(vendorId, modelId); # The MOTU devices use unitVersion to differentiate models. For the # moment thought we don't need to know precisely which model we're # using. if vendorId == 0x1f2: thisdev=(vendorId, 0x00000000) dev = None for d in SupportedDevices: if d[0] == thisdev: dev = d w = QWidget( mw ) l = QVBoxLayout( w ) # create a control object hw = ControlInterface(server, basepath+'/DeviceManager/'+path) clockselect = ClockSelectInterface( server, basepath+"/DeviceManager/"+path ) samplerateselect = SamplerateSelectInterface( server, basepath+"/DeviceManager/"+path ) nickname = TextInterface( server, basepath+"/DeviceManager/"+path+"/Generic/Nickname" ) # # Generic elements for all mixers follow here: # tmp = GlobalMixer( w ) tmp.configrom = cfgrom tmp.clockselect = clockselect tmp.samplerateselect = samplerateselect tmp.nickname = nickname tmp.hw = hw tmp.initValues() l.addWidget( tmp, 1 ) # # Line to separate # l.addWidget( HLine( w ) ) # # Specific (or dummy) mixer widgets get loaded in the following # if dev != None: mixerapp = dev[1] if vendorId == 0x00130e: is_saffirele = False is_saffirepro = False # hack for the focusrite devices # Saffire: 0x130e010001???? # SaffireLE: 0x130e010004???? if modelId == 0x00000000: if int(GUID, 16) >= 0x130e0100040000: is_saffirele = True print "Found SaffireLE GUID" else: is_saffirele = False print "Found Saffire GUID" # different panel for different clock frequency selected = samplerateselect.selected() samplerate = int(samplerateselect.getEnumLabel( selected )) # adat on PRO26 makes a difference have_adat = False if modelId == 0x00000003: # PRO26 is_saffirepro = True state = hw.getDiscrete('/Control/ADATDisable') if state: have_adat = False print "detected PRO26, ADAT disabled" else: have_adat = True print "detected PRO26, ADAT enabled" elif modelId == 0x00000006: # PRO10 is_saffirepro = True suffix = '' if samplerate <= 48000: suffix = "Large" # on the saffire pro 26, the large panel can be used # at 96k when adat is disabled. pro10 = pro26 w/o ADAT elif samplerate <= 96000 and is_saffirepro and have_adat: suffix = "Small" elif samplerate <= 96000 and is_saffirepro: suffix = "Large" # higher samplerates need the small panel else: suffix = "Small" if is_saffirepro: mixerapp = "SaffireProMixer" + suffix elif is_saffirele: mixerapp = "SaffireLEMixer" + suffix else: mixerapp = "SaffireMixer" exec( "mixerwidget = "+mixerapp+"( w )" ) else: mixerwidget = DummyMixer( w ) mixerapp = modelName+" (Dummy)" # # The same for all mixers # l.addWidget( mixerwidget, 10 ) mixerwidget.configrom = cfgrom mixerwidget.clockselect = clockselect mixerwidget.samplerateselect = samplerateselect mixerwidget.nickname = nickname mixerwidget.hw = hw if 'buildMixer' in dir(mixerwidget): mixerwidget.buildMixer() if 'initValues' in dir(mixerwidget): mixerwidget.initValues() mixerwidgets.append(mixerwidget) mw.addTab( w, mixerapp ) # # Show the generic (development) mixer if it is available # if nbDevices > 0 and use_generic: mw.addTab( GenericMixer( devmgr.bus, server, mw ), "Generic Mixer" ) # # Only really show the mainwindow and start the mixer when at least on mixer is shown # if mw.count() > 0: puw = PollUpdateWidgets(mixerwidgets) timer = QTimer(puw) QObject.connect( timer, SIGNAL('timeout()'), puw.updateWidgets ); timer.start( POLL_SLEEP_TIME_MSEC ); # Adjust size of mixer window to the requirements of the selected device mixer(s) mw.adjustSize() mw.show() QObject.connect(app,SIGNAL("lastWindowClosed()"),app,SLOT("quit()")) app.exec_loop()