root/branches/libffado-2.0/support/mixer/ffado-mixer.in

Revision 1394, 19.2 kB (checked in by ppalmers, 12 years ago)

rename all debug and mixer tools to start with ffado-*

  • 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_audiofire 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),'AudioFireMixer'],
72     [(0x001486, 0x00000af4),'AudioFireMixer'],
73     [(0x001486, 0x00000af8),'AudioFireMixer'],
74     [(0x001486, 0x0000af12),'AudioFireMixer'],
75     [(0x0007f5, 0x00010049),'BCoAudio5Control'],
76     [(0x0040AB, 0x00010049),'EdirolFa66Control'],
77     [(0x0040AB, 0x00010048),'EdirolFa101Control'],
78     [(0x00000f, 0x00010067),'MackieGenericControl'],
79     [(0x000f1b, 0x00010064),'QuataFireMixer'],
80     [(0x0001f2, 0x00000000),'MotuMixer'],
81     ]
82
83 POLL_SLEEP_TIME_MSEC = 100 # 100ms
84
85 class ControlInterface:
86     def __init__(self, servername, basepath):
87         self.basepath=basepath
88         self.servername=servername
89         self.bus=dbus.SessionBus()
90
91     def setContignuous(self, subpath, v, idx=None):
92         try:
93             path = self.basepath + subpath
94             dev = self.bus.get_object(self.servername, path)
95             dev_cont = dbus.Interface(dev, dbus_interface='org.ffado.Control.Element.Continuous')
96             if idx == None:
97                 dev_cont.setValue(v)
98             else:
99                 dev_cont.setValueIdx(idx,v)
100         except:
101             print "Failed to set Continuous %s on server %s" % (path, self.servername)
102
103     def getContignuous(self, subpath, idx=None):
104         try:
105             path = self.basepath + subpath
106             dev = self.bus.get_object(self.servername, path)
107             dev_cont = dbus.Interface(dev, dbus_interface='org.ffado.Control.Element.Continuous')
108             if idx == None:
109                 return dev_cont.getValue()
110             else:
111                 return dev_cont.getValueIdx(idx)
112         except:
113             print "Failed to get Continuous %s on server %s" % (path, self.servername)
114             return 0
115
116     def setDiscrete(self, subpath, v):
117         try:
118             path = self.basepath + subpath
119             dev = self.bus.get_object(self.servername, path)
120             dev_cont = dbus.Interface(dev, dbus_interface='org.ffado.Control.Element.Discrete')
121             dev_cont.setValue(v)
122         except:
123             print "Failed to set Discrete %s on server %s" % (path, self.servername)
124
125     def getDiscrete(self, subpath):
126         try:
127             path = self.basepath + subpath
128             dev = self.bus.get_object(self.servername, path)
129             dev_cont = dbus.Interface(dev, dbus_interface='org.ffado.Control.Element.Discrete')
130             return dev_cont.getValue()
131         except:
132             print "Failed to get Discrete %s on server %s" % (path, self.servername)
133             return 0
134
135     def setText(self, subpath, v):
136         try:
137             path = self.basepath + subpath
138             dev = self.bus.get_object(self.servername, path)
139             dev_cont = dbus.Interface(dev, dbus_interface='org.ffado.Control.Element.Text')
140             dev_cont.setValue(v)
141         except:
142             print "Failed to set Text %s on server %s" % (path, self.servername)
143
144     def getText(self, subpath):
145         try:
146             path = self.basepath + subpath
147             dev = self.bus.get_object(self.servername, path)
148             dev_cont = dbus.Interface(dev, dbus_interface='org.ffado.Control.Element.Text')
149             return dev_cont.getValue()
150         except:
151             print "Failed to get Text %s on server %s" % (path, self.servername)
152             return 0
153
154     def setMatrixMixerValue(self, subpath, row, col, v):
155         try:
156             path = self.basepath + subpath
157             dev = self.bus.get_object(self.servername, path)
158             dev_cont = dbus.Interface(dev, dbus_interface='org.ffado.Control.Element.MatrixMixer')
159             dev_cont.setValue(row, col, v)
160         except:
161             print "Failed to set MatrixMixer %s on server %s" % (path, self.servername)
162
163     def getMatrixMixerValue(self, subpath, row, col):
164         try:
165             path = self.basepath + subpath
166             dev = self.bus.get_object(self.servername, path)
167             dev_cont = dbus.Interface(dev, dbus_interface='org.ffado.Control.Element.MatrixMixer')
168             return dev_cont.getValue(row, col)
169         except:
170             print "Failed to get MatrixMixer %s on server %s" % (path, self.servername)
171             return 0
172
173     def enumSelect(self, subpath, v):
174         try:
175             path = self.basepath + subpath
176             dev = self.bus.get_object(self.servername, path)
177             dev_cont = dbus.Interface(dev, dbus_interface='org.ffado.Control.Element.Enum')
178             dev_cont.select(v)
179         except:
180             print "Failed to select %s on server %s" % (path, self.servername)
181
182     def enumSelected(self, subpath):
183         try:
184             path = self.basepath + subpath
185             dev = self.bus.get_object(self.servername, path)
186             dev_cont = dbus.Interface(dev, dbus_interface='org.ffado.Control.Element.Enum')
187             return dev_cont.selected()
188         except:
189             print "Failed to get selected enum %s on server %s" % (path, self.servername)
190             return 0
191
192     def enumGetLabel(self, subpath, v):
193         try:
194             path = self.basepath + subpath
195             dev = self.bus.get_object(self.servername, path)
196             dev_cont = dbus.Interface(dev, dbus_interface='org.ffado.Control.Element.Enum')
197             return dev_cont.getEnumLabel(v)
198         except:
199             print "Failed to get enum label %s on server %s" % (path, self.servername)
200             return 0
201
202     def enumCount(self, subpath):
203         try:
204             path = self.basepath + subpath
205             dev = self.bus.get_object(self.servername, path)
206             dev_cont = dbus.Interface(dev, dbus_interface='org.ffado.Control.Element.Enum')
207             return dev_cont.count()
208         except:
209             print "Failed to get enum count %s on server %s" % (path, self.servername)
210             return 0
211
212 class DeviceManagerInterface:
213     def __init__(self, servername, basepath):
214         self.basepath=basepath + '/DeviceManager'
215         self.servername=servername
216         self.bus=dbus.SessionBus()
217         self.dev = self.bus.get_object(self.servername, self.basepath)
218         self.iface = dbus.Interface(self.dev, dbus_interface='org.ffado.Control.Element.Container')
219         # signal reception does not work yet since we need a mainloop for that
220         # and qt3 doesn't provide one for python/dbus
221         #try:
222             #self.dev.connect_to_signal("Updated", self.updateSignal, \
223                                        #dbus_interface="org.ffado.Control.Element.Container", arg0=self)
224         #except dbus.DBusException:
225             #traceback.print_exc()
226
227     #def updateSignal(self):
228         #print ("Received update signal")
229
230     def getNbDevices(self):
231         return self.iface.getNbElements()
232     def getDeviceName(self, idx):
233         return self.iface.getElementName(idx)
234
235
236 class ConfigRomInterface:
237     def __init__(self, servername, devicepath):
238         self.basepath=devicepath + '/ConfigRom'
239         self.servername=servername
240         self.bus=dbus.SessionBus()
241         self.dev = self.bus.get_object(self.servername, self.basepath)
242         self.iface = dbus.Interface(self.dev, dbus_interface='org.ffado.Control.Element.ConfigRomX')
243     def getGUID(self):
244         return self.iface.getGUID()
245     def getVendorName(self):
246         return self.iface.getVendorName()
247     def getModelName(self):
248         return self.iface.getModelName()
249     def getVendorId(self):
250         return self.iface.getVendorId()
251     def getModelId(self):
252         return self.iface.getModelId()
253     def getUnitVersion(self):
254         return self.iface.getUnitVersion()
255
256 class ClockSelectInterface:
257     def __init__(self, servername, devicepath):
258         self.basepath=devicepath + '/Generic/ClockSelect'
259         self.servername=servername
260         self.bus=dbus.SessionBus()
261         self.dev = self.bus.get_object(self.servername, self.basepath)
262         self.iface = dbus.Interface(self.dev, dbus_interface='org.ffado.Control.Element.AttributeEnum')
263     def count(self):
264         return self.iface.count()
265     def select(self, idx):
266         return self.iface.select(idx)
267     def selected(self):
268         return self.iface.selected()
269     def getEnumLabel(self, idx):
270         return self.iface.getEnumLabel(idx)
271     def attributeCount(self):
272         return self.iface.attributeCount()
273     def getAttributeValue(self, idx):
274         return self.iface.getAttributeValue(idx)
275     def getAttributeName(self, idx):
276         return self.iface.getAttributeName(idx)
277
278 class SamplerateSelectInterface:
279     def __init__(self, servername, devicepath):
280         self.basepath=devicepath + '/Generic/SamplerateSelect'
281         self.servername=servername
282         self.bus=dbus.SessionBus()
283         self.dev = self.bus.get_object(self.servername, self.basepath)
284         self.iface = dbus.Interface(self.dev, dbus_interface='org.ffado.Control.Element.Enum')
285     def count(self):
286         return self.iface.count()
287     def select(self, idx):
288         return self.iface.select(idx)
289     def selected(self):
290         return self.iface.selected()
291     def getEnumLabel(self, idx):
292         return self.iface.getEnumLabel(idx)
293
294 class TextInterface:
295     def __init__(self, servername, basepath):
296         self.basepath=basepath
297         self.servername=servername
298         self.bus=dbus.SessionBus()
299         self.dev = self.bus.get_object( self.servername, self.basepath )
300         self.iface = dbus.Interface( self.dev, dbus_interface="org.ffado.Control.Element.Text" )
301
302     def text(self):
303         return self.iface.getValue()
304
305     def setText(self,text):
306         self.iface.setValue(text)
307
308 class HLine( QFrame ):
309     def __init__( self, parent ):
310         QFrame.__init__( self, parent )
311         self.setFrameShape( QFrame.HLine )
312         self.setLineWidth( 2 )
313         self.setMinimumHeight( 10 )
314
315 class PollUpdateWidgets(QObject):
316     def __init__(self, widgets):
317         QObject.__init__(self)
318         self.widgets = widgets
319
320     def updateWidgets(self):
321         for w in self.widgets:
322             if 'polledUpdate' in dir(w):
323                 try:
324                     w.polledUpdate()
325                 except:
326                     print "error in polled update"
327
328 if __name__ == "__main__":
329
330     server='org.ffado.Control'
331     basepath='/org/ffado/Control'
332
333     app = QApplication(sys.argv)
334
335     msg = QMessageBox()
336
337     repeat = 1
338     while repeat > 0:
339         try:
340             devmgr=DeviceManagerInterface(server, basepath)
341             nbDevices=devmgr.getNbDevices()
342             repeat -= 1
343         except dbus.DBusException, ex:
344             print "\n"
345             print "==========================================================="
346             print "ERROR: Could not communicate with the FFADO DBus service..."
347             print "==========================================================="
348             print "\n"
349             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 )
350             if tmp == 4:
351                 sys.exit(-1)
352             else:
353                 os.spawnlp( os.P_NOWAIT, "ffado-dbus-server" )
354                 nb_checks = 20
355                 while nb_checks > 0:
356                     nb_checks = nb_checks - 1
357                     try:
358                         devmgr=DeviceManagerInterface(server, basepath)
359                         nbDevices=devmgr.getNbDevices()
360                         nb_checks = 0
361                         repeat = 0
362                     except dbus.DBusException, ex:
363                         time.sleep( 1 )
364
365     if nbDevices == 0:
366         print "No supported device found..."
367         msg.information( msg, "No mixer found", "No devices with mixer support discovered." )
368         sys.exit( -1 )
369
370     mw = QTabWidget()
371
372     mixerwidgets = []
373
374     for idx in range(nbDevices):
375         path=devmgr.getDeviceName(idx)
376         print "Found device %d: %s" % (idx, path)
377
378         cfgrom = ConfigRomInterface(server, basepath+'/DeviceManager/'+path)
379         vendorId = cfgrom.getVendorId()
380         modelId = cfgrom.getModelId()
381         unitVersion = cfgrom.getUnitVersion()
382         GUID = cfgrom.getGUID()
383         vendorName = cfgrom.getVendorName()
384         modelName = cfgrom.getModelName()
385         print " Found (%s, %X, %X) %s %s" % (str(GUID), vendorId, modelId, vendorName, modelName)
386
387         # check whether this has already been registered at ffado.org
388         reg = ffado_registration(FFADO_VERSION, int(GUID, 16),
389                                  vendorId, modelId,
390                                  vendorName, modelName)
391         reg.check_for_registration()
392
393         thisdev=(vendorId, modelId);
394         # The MOTU devices use unitVersion to differentiate models.  For the
395         # moment thought we don't need to know precisely which model we're
396         # using.
397         if vendorId == 0x1f2:
398             thisdev=(vendorId, 0x00000000)
399
400         dev = None
401         for d in SupportedDevices:
402             if d[0] == thisdev:
403                 dev = d
404
405         w = QWidget( mw )
406         l = QVBoxLayout( w )
407
408         # create a control object
409         hw = ControlInterface(server, basepath+'/DeviceManager/'+path)
410         clockselect = ClockSelectInterface( server, basepath+"/DeviceManager/"+path )
411         samplerateselect = SamplerateSelectInterface( server, basepath+"/DeviceManager/"+path )
412         nickname = TextInterface( server, basepath+"/DeviceManager/"+path+"/Generic/Nickname" )
413
414         #
415         # Generic elements for all mixers follow here:
416         #
417         tmp = GlobalMixer( w )
418         tmp.configrom = cfgrom
419         tmp.clockselect = clockselect
420         tmp.samplerateselect = samplerateselect
421         tmp.nickname = nickname
422         tmp.hw = hw
423         tmp.initValues()
424         l.addWidget( tmp, 1 )
425
426         #
427         # Line to separate
428         #
429         l.addWidget( HLine( w ) )
430
431         #
432         # Specific (or dummy) mixer widgets get loaded in the following
433         #
434         if dev != None:
435             mixerapp = dev[1]
436             if vendorId == 0x00130e:
437                 is_saffirele = False
438                 is_saffirepro = False
439
440                 # hack for the focusrite devices
441                 # Saffire:        0x130e010001????
442                 # SaffireLE:    0x130e010004????
443                 if modelId == 0x00000000:
444                     if int(GUID, 16) >= 0x130e0100040000:
445                         is_saffirele = True
446                         print "Found SaffireLE GUID"
447                     else:
448                         is_saffirele = False
449                         print "Found Saffire GUID"
450
451                 # different panel for different clock frequency
452                 selected = samplerateselect.selected()
453                 samplerate = int(samplerateselect.getEnumLabel( selected ))
454
455                 # adat on PRO26 makes a difference
456                 have_adat = False
457                 if modelId == 0x00000003: # PRO26
458                     is_saffirepro = True
459                     state = hw.getDiscrete('/Control/ADATDisable')
460                     if state:
461                         have_adat = False
462                         print "detected PRO26, ADAT disabled"
463                     else:
464                         have_adat = True
465                         print "detected PRO26, ADAT enabled"
466                 elif modelId == 0x00000006: # PRO10
467                     is_saffirepro = True
468
469                 suffix = ''
470                 if samplerate <= 48000:
471                     suffix = "Large"
472                 # on the saffire pro 26, the large panel can be used
473                 # at 96k when adat is disabled. pro10 = pro26 w/o ADAT
474                 elif samplerate <= 96000 and is_saffirepro and have_adat:
475                     suffix = "Small"
476                 elif samplerate <= 96000 and is_saffirepro:
477                     suffix = "Large"
478                 # higher samplerates need the small panel
479                 else:
480                     suffix = "Small"
481
482                 if is_saffirepro:
483                     mixerapp = "SaffireProMixer" + suffix
484                 elif is_saffirele:
485                     mixerapp = "SaffireLEMixer" + suffix
486                 else:
487                     mixerapp = "SaffireMixer"
488
489             exec( "mixerwidget = "+mixerapp+"( w )" )
490
491         else:
492             mixerwidget = DummyMixer( w )
493             mixerapp = modelName+" (Dummy)"
494
495         #
496         # The same for all mixers
497         #
498         l.addWidget( mixerwidget, 10 )
499         mixerwidget.configrom = cfgrom
500         mixerwidget.clockselect = clockselect
501         mixerwidget.samplerateselect = samplerateselect
502         mixerwidget.nickname = nickname
503         mixerwidget.hw = hw
504         if 'buildMixer' in dir(mixerwidget):
505             mixerwidget.buildMixer()
506         if 'initValues' in dir(mixerwidget):
507             mixerwidget.initValues()
508         mixerwidgets.append(mixerwidget)
509         mw.addTab( w, mixerapp )
510
511     #
512     # Show the generic (development) mixer if it is available
513     #
514     if nbDevices > 0 and use_generic:
515         mw.addTab( GenericMixer( devmgr.bus, server, mw ), "Generic Mixer" )
516
517     #
518     # Only really show the mainwindow and start the mixer when at least on mixer is shown
519     #
520     if mw.count() > 0:
521         puw = PollUpdateWidgets(mixerwidgets)
522         timer = QTimer(puw)
523         QObject.connect( timer, SIGNAL('timeout()'), puw.updateWidgets );
524         timer.start( POLL_SLEEP_TIME_MSEC );
525
526         # Adjust size of mixer window to the requirements of the selected device mixer(s)
527         mw.adjustSize()
528
529         mw.show()
530
531         QObject.connect(app,SIGNAL("lastWindowClosed()"),app,SLOT("quit()"))
532
533         app.exec_loop()
Note: See TracBrowser for help on using the browser.