root/trunk/libffado/support/mixer/ffadomixer.in

Revision 1326, 17.2 kB (checked in by wagi, 16 years ago)

Merge r1325 back to trunk.

  • Property svn:executable set to *
Line 
1 #!/usr/bin/python
2 #
3 # Copyright (C) 2005-2007 by Pieter Palmers
4 #               2007-2008 by Arnold Krille
5 #
6 # This file is part of FFADO
7 # FFADO = Free Firewire (pro-)audio drivers for linux
8 #
9 # FFADO is based upon FreeBoB.
10 #
11 # This program is free software: you can redistribute it and/or modify
12 # it under the terms of the GNU General Public License as published by
13 # the Free Software Foundation, either version 3 of the License, or
14 # (at your option) any later version.
15 #
16 # This program is distributed in the hope that it will be useful,
17 # but WITHOUT ANY WARRANTY; without even the implied warranty of
18 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 # GNU General Public License for more details.
20 #
21 # You should have received a copy of the GNU General Public License
22 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
23 #
24
25 import sys
26
27 # Add the path of the installed ffado-mixer-modules
28 sys.path.append( "$PYTHONDIR" )
29
30 from ffadomixer_config import FFADO_VERSION
31
32 import os
33 import time
34 import dbus
35
36 from qt import *
37
38 from ffado_registration import *
39
40 from mixer_phase88 import *
41 from mixer_phase24 import *
42 from mixer_saffire import *
43 from mixer_saffirele import *
44 from mixer_saffirepro import *
45 from mixer_af2 import *
46 from mixer_bcoaudio5 import *
47 from mixer_edirolfa66 import *
48 from mixer_edirolfa101 import *
49 from mixer_mackie_generic import *
50 from mixer_quatafire import *
51 from mixer_motu import *
52 from mixer_dummy import *
53 from mixer_global import *
54
55 use_generic = False
56 try:
57     from mixer_generic import *
58     print "The generic mixer is found, seems to be a developer using ffadomixer..."
59 except ImportError:
60     pass
61 else:
62     use_generic = True
63
64 SupportedDevices=[
65     [(0x000aac, 0x00000003),'Phase88Control'],
66     [(0x000aac, 0x00000004),'Phase24Control'],
67     [(0x000aac, 0x00000007),'Phase24Control'],
68     [(0x00130e, 0x00000003),'SaffireProMixer'],
69     [(0x00130e, 0x00000006),'SaffireProMixer'],
70     [(0x00130e, 0x00000000),'SaffireMixer'],
71     [(0x001486, 0x00000af2),'AudioFire2Mixer'],
72     [(0x0007f5, 0x00010049),'BCoAudio5Control'],
73     [(0x0040AB, 0x00010049),'EdirolFa66Control'],
74     [(0x0040AB, 0x00010048),'EdirolFa101Control'],
75     [(0x00000f, 0x00010067),'MackieGenericControl'],
76     [(0x000f1b, 0x00010064),'QuataFireMixer'],
77     [(0x0001f2, 0x00000000),'MotuMixer'],
78     ]
79
80 class ControlInterface:
81     def __init__(self, servername, basepath):
82         self.basepath=basepath
83         self.servername=servername
84         self.bus=dbus.SessionBus()
85
86     def setContignuous(self, subpath, v, idx=None):
87         try:
88             path = self.basepath + subpath
89             dev = self.bus.get_object(self.servername, path)
90             dev_cont = dbus.Interface(dev, dbus_interface='org.ffado.Control.Element.Continuous')
91             if idx == None:
92                 dev_cont.setValue(v)
93             else:
94                 dev_cont.setValueIdx(idx,v)
95         except:
96             print "Failed to set Continuous %s on server %s" % (path, self.servername)
97
98     def getContignuous(self, subpath, idx=None):
99         try:
100             path = self.basepath + subpath
101             dev = self.bus.get_object(self.servername, path)
102             dev_cont = dbus.Interface(dev, dbus_interface='org.ffado.Control.Element.Continuous')
103             if idx == None:
104                 return dev_cont.getValue()
105             else:
106                 return dev_cont.getValueIdx(idx)
107         except:
108             print "Failed to get Continuous %s on server %s" % (path, self.servername)
109             return 0
110
111     def setDiscrete(self, subpath, v):
112         try:
113             path = self.basepath + subpath
114             dev = self.bus.get_object(self.servername, path)
115             dev_cont = dbus.Interface(dev, dbus_interface='org.ffado.Control.Element.Discrete')
116             dev_cont.setValue(v)
117         except:
118             print "Failed to set Discrete %s on server %s" % (path, self.servername)
119
120     def getDiscrete(self, subpath):
121         try:
122             path = self.basepath + subpath
123             dev = self.bus.get_object(self.servername, path)
124             dev_cont = dbus.Interface(dev, dbus_interface='org.ffado.Control.Element.Discrete')
125             return dev_cont.getValue()
126         except:
127             print "Failed to get Discrete %s on server %s" % (path, self.servername)
128             return 0
129
130     def setText(self, subpath, v):
131         try:
132             path = self.basepath + subpath
133             dev = self.bus.get_object(self.servername, path)
134             dev_cont = dbus.Interface(dev, dbus_interface='org.ffado.Control.Element.Text')
135             dev_cont.setValue(v)
136         except:
137             print "Failed to set Text %s on server %s" % (path, self.servername)
138
139     def getText(self, subpath):
140         try:
141             path = self.basepath + subpath
142             dev = self.bus.get_object(self.servername, path)
143             dev_cont = dbus.Interface(dev, dbus_interface='org.ffado.Control.Element.Text')
144             return dev_cont.getValue()
145         except:
146             print "Failed to get Text %s on server %s" % (path, self.servername)
147             return 0
148
149     def setMatrixMixerValue(self, subpath, row, col, v):
150         try:
151             path = self.basepath + subpath
152             dev = self.bus.get_object(self.servername, path)
153             dev_cont = dbus.Interface(dev, dbus_interface='org.ffado.Control.Element.MatrixMixer')
154             dev_cont.setValue(row, col, v)
155         except:
156             print "Failed to set MatrixMixer %s on server %s" % (path, self.servername)
157
158     def getMatrixMixerValue(self, subpath, row, col):
159         try:
160             path = self.basepath + subpath
161             dev = self.bus.get_object(self.servername, path)
162             dev_cont = dbus.Interface(dev, dbus_interface='org.ffado.Control.Element.MatrixMixer')
163             return dev_cont.getValue(row, col)
164         except:
165             print "Failed to get MatrixMixer %s on server %s" % (path, self.servername)
166             return 0
167
168     def enumSelect(self, subpath, v):
169         try:
170             path = self.basepath + subpath
171             dev = self.bus.get_object(self.servername, path)
172             dev_cont = dbus.Interface(dev, dbus_interface='org.ffado.Control.Element.Enum')
173             dev_cont.select(v)
174         except:
175             print "Failed to select %s on server %s" % (path, self.servername)
176
177     def enumSelected(self, subpath):
178         try:
179             path = self.basepath + subpath
180             dev = self.bus.get_object(self.servername, path)
181             dev_cont = dbus.Interface(dev, dbus_interface='org.ffado.Control.Element.Enum')
182             return dev_cont.selected()
183         except:
184             print "Failed to get selected enum %s on server %s" % (path, self.servername)
185             return 0
186
187     def enumGetLabel(self, subpath, v):
188         try:
189             path = self.basepath + subpath
190             dev = self.bus.get_object(self.servername, path)
191             dev_cont = dbus.Interface(dev, dbus_interface='org.ffado.Control.Element.Enum')
192             return dev_cont.getEnumLabel(v)
193         except:
194             print "Failed to get enum label %s on server %s" % (path, self.servername)
195             return 0
196
197     def enumCount(self, subpath):
198         try:
199             path = self.basepath + subpath
200             dev = self.bus.get_object(self.servername, path)
201             dev_cont = dbus.Interface(dev, dbus_interface='org.ffado.Control.Element.Enum')
202             return dev_cont.count()
203         except:
204             print "Failed to get enum count %s on server %s" % (path, self.servername)
205             return 0
206
207 class DeviceManagerInterface:
208     def __init__(self, servername, basepath):
209         self.basepath=basepath + '/DeviceManager'
210         self.servername=servername
211         self.bus=dbus.SessionBus()
212         self.dev = self.bus.get_object(self.servername, self.basepath)
213         self.iface = dbus.Interface(self.dev, dbus_interface='org.ffado.Control.Element.Container')
214         # signal reception does not work yet since we need a mainloop for that
215         # and qt3 doesn't provide one for python/dbus
216         #try:
217             #self.dev.connect_to_signal("Updated", self.updateSignal, \
218                                        #dbus_interface="org.ffado.Control.Element.Container", arg0=self)
219         #except dbus.DBusException:
220             #traceback.print_exc()
221
222     #def updateSignal(self):
223         #print ("Received update signal")
224
225     def getNbDevices(self):
226         return self.iface.getNbElements()
227     def getDeviceName(self, idx):
228         return self.iface.getElementName(idx)
229
230
231 class ConfigRomInterface:
232     def __init__(self, servername, devicepath):
233         self.basepath=devicepath + '/ConfigRom'
234         self.servername=servername
235         self.bus=dbus.SessionBus()
236         self.dev = self.bus.get_object(self.servername, self.basepath)
237         self.iface = dbus.Interface(self.dev, dbus_interface='org.ffado.Control.Element.ConfigRomX')
238     def getGUID(self):
239         return self.iface.getGUID()
240     def getVendorName(self):
241         return self.iface.getVendorName()
242     def getModelName(self):
243         return self.iface.getModelName()
244     def getVendorId(self):
245         return self.iface.getVendorId()
246     def getModelId(self):
247         return self.iface.getModelId()
248     def getUnitVersion(self):
249         return self.iface.getUnitVersion()
250
251 class ClockSelectInterface:
252     def __init__(self, servername, devicepath):
253         self.basepath=devicepath + '/Generic/ClockSelect'
254         self.servername=servername
255         self.bus=dbus.SessionBus()
256         self.dev = self.bus.get_object(self.servername, self.basepath)
257         self.iface = dbus.Interface(self.dev, dbus_interface='org.ffado.Control.Element.AttributeEnum')
258     def count(self):
259         return self.iface.count()
260     def select(self, idx):
261         return self.iface.select(idx)
262     def selected(self):
263         return self.iface.selected()
264     def getEnumLabel(self, idx):
265         return self.iface.getEnumLabel(idx)
266     def attributeCount(self):
267         return self.iface.attributeCount()
268     def getAttributeValue(self, idx):
269         return self.iface.getAttributeValue(idx)
270     def getAttributeName(self, idx):
271         return self.iface.getAttributeName(idx)
272
273 class TextInterface:
274     def __init__(self, servername, basepath):
275         self.basepath=basepath
276         self.servername=servername
277         self.bus=dbus.SessionBus()
278         self.dev = self.bus.get_object( self.servername, self.basepath )
279         self.iface = dbus.Interface( self.dev, dbus_interface="org.ffado.Control.Element.Text" )
280
281     def text(self):
282         return self.iface.getValue()
283
284     def setText(self,text):
285         self.iface.setValue(text)
286
287 class HLine( QFrame ):
288     def __init__( self, parent ):
289         QFrame.__init__( self, parent )
290         self.setFrameShape( QFrame.HLine )
291         self.setLineWidth( 2 )
292         self.setMinimumHeight( 10 )
293
294 if __name__ == "__main__":
295
296     server='org.ffado.Control'
297     basepath='/org/ffado/Control'
298
299     app = QApplication(sys.argv)
300
301     msg = QMessageBox()
302
303     repeat = 1
304     while repeat > 0:
305         try:
306             devmgr=DeviceManagerInterface(server, basepath)
307             nbDevices=devmgr.getNbDevices()
308             repeat -= 1
309         except dbus.DBusException, ex:
310             print "\n"
311             print "==========================================================="
312             print "ERROR: Could not communicate with the FFADO DBus service..."
313             print "==========================================================="
314             print "\n"
315             tmp = msg.question( msg, "FFADO-DBus not found", "<qt><b>The connection to FFADOs DBus service could not be established.</b><p>Probably you didn't start the ffado-dbus-server. Should I try this now?</qt>", QMessageBox.Yes, QMessageBox.No )
316             if tmp == 4:
317                 sys.exit(-1)
318             else:
319                 os.spawnlp( os.P_NOWAIT, "ffado-dbus-server" )
320                 nb_checks = 20
321                 while nb_checks > 0:
322                     nb_checks = nb_checks - 1
323                     try:
324                         devmgr=DeviceManagerInterface(server, basepath)
325                         nbDevices=devmgr.getNbDevices()
326                         nb_checks = 0
327                         repeat = 0
328                     except dbus.DBusException, ex:
329                         time.sleep( 2 )
330
331     if nbDevices == 0:
332         print "No supported device found..."
333         msg.information( msg, "No mixer found", "No devices with mixer support discovered." )
334         sys.exit( -1 )
335
336     mw = QTabWidget()
337
338     for idx in range(nbDevices):
339         path=devmgr.getDeviceName(idx)
340         print "Found device %d: %s" % (idx, path)
341
342         cfgrom = ConfigRomInterface(server, basepath+'/DeviceManager/'+path)
343         vendorId = cfgrom.getVendorId()
344         modelId = cfgrom.getModelId()
345         unitVersion = cfgrom.getUnitVersion()
346         GUID = cfgrom.getGUID()
347         vendorName = cfgrom.getVendorName()
348         modelName = cfgrom.getModelName()
349         print " Found (%s, %X, %X) %s %s" % (str(GUID), vendorId, modelId, vendorName, modelName)
350
351         # check whether this has already been registered at ffado.org
352         reg = ffado_registration(FFADO_VERSION, int(GUID, 16),
353                                  vendorId, modelId,
354                                  vendorName, modelName)
355         reg.check_for_registration()
356
357         thisdev=(vendorId, modelId);
358         # The MOTU devices use unitVersion to differentiate models.  For the
359         # moment thought we don't need to know precisely which model we're
360         # using.
361         if vendorId == 0x1f2:
362             thisdev=(vendorId, 0x00000000)
363
364         dev = None
365         for d in SupportedDevices:
366             if d[0] == thisdev:
367                 dev = d
368
369         w = QWidget( mw )
370         l = QVBoxLayout( w )
371
372         # create a control object
373         hw = ControlInterface(server, basepath+'/DeviceManager/'+path)
374
375         #
376         # Generic elements for all mixers follow here:
377         #
378         tmp = GlobalMixer( w )
379         tmp.clockselect = ClockSelectInterface( server, basepath+"/DeviceManager/"+path )
380         tmp.nickname = TextInterface( server, basepath+"/DeviceManager/"+path+"/Generic/Nickname" )
381         tmp.hw = hw
382         tmp.initValues()
383         l.addWidget( tmp, 1 )
384
385         #
386         # Line to separate
387         #
388         l.addWidget( HLine( w ) )
389
390         #
391         # Specific (or dummy) mixer widgets get loaded in the following
392         #
393         if dev != None:
394             mixerapp = dev[1]
395             if vendorId == 0x00130e:
396                 is_saffirele = False
397                 is_saffirepro = False
398
399                 # hack for the focusrite devices
400                 # Saffire:        0x130e010001????
401                 # SaffireLE:    0x130e010004????
402                 if modelId == 0x00000000:
403                     if int(GUID, 16) >= 0x130e0100040000:
404                         is_saffirele = True
405                         print "Found SaffireLE GUID"
406                     else:
407                         is_saffirele = False
408                         print "Found Saffire GUID"
409
410                 # different panel for different clock frequency
411                 samplerate = hw.getDiscrete('/Generic/SamplerateSelect')
412
413                 # adat on PRO26 makes a difference
414                 have_adat = False
415                 if modelId == 0x00000003: # PRO26
416                     is_saffirepro = True
417                     state = hw.getDiscrete('/Control/ADATDisable')
418                     if state:
419                         have_adat = False
420                         print "detected PRO26, ADAT disabled"
421                     else:
422                         have_adat = True
423                         print "detected PRO26, ADAT enabled"
424                 elif modelId == 0x00000006: # PRO10
425                     is_saffirepro = True
426
427                 suffix = ''
428                 if samplerate <= 48000:
429                     suffix = "Large"
430                 # on the saffire pro 26, the large panel can be used
431                 # at 96k when adat is disabled. pro10 = pro26 w/o ADAT
432                 elif samplerate <= 96000 and is_saffirepro and have_adat:
433                     suffix = "Small"
434                 elif samplerate <= 96000 and is_saffirepro:
435                     suffix = "Large"
436                 # higher samplerates need the small panel
437                 else:
438                     suffix = "Small"
439
440                 if is_saffirepro:
441                     mixerapp = "SaffireProMixer" + suffix
442                 elif is_saffirele:
443                     mixerapp = "SaffireLEMixer" + suffix
444                 else:
445                     mixerapp = "SaffireMixer"
446
447             exec( "mixerwidget = "+mixerapp+"( w )" )
448
449         else:
450             mixerwidget = DummyMixer( w )
451             mixerapp = modelName+" (Dummy)"
452
453         #
454         # The same for all mixers
455         #
456         l.addWidget( mixerwidget, 10 )
457         mixerwidget.hw = hw
458         mixerwidget.configrom = cfgrom
459         mixerwidget.clockselect = ClockSelectInterface(server, basepath+'/DeviceManager/'+path)
460         mixerwidget.initValues()
461         mw.addTab( w, mixerapp )
462
463     #
464     # Show the generic (development) mixer if it is available
465     #
466     if nbDevices > 0 and use_generic:
467         mw.addTab( GenericMixer( devmgr.bus, server, mw ), "Generic Mixer" )
468
469     #
470     # Only really show the mainwindow and start the mixer when at least on mixer is shown
471     #
472     if mw.count() > 0:
473         mw.show()
474
475         QObject.connect(app,SIGNAL("lastWindowClosed()"),app,SLOT("quit()"))
476
477         app.exec_loop()
478
Note: See TracBrowser for help on using the browser.