root/trunk/libffado/support/mixer-qt4/ffado/widgets/crossbarrouter.py

Revision 2472, 8.4 kB (checked in by philippe, 10 years ago)

ffado-mixer/DICE EAP: file saving of settings. File is xml so as to be human readable. File version included (as 0.1). Guid included. Partial commit: only global mixer and router settings are saved.

Line 
1 #
2 # Copyright (C) 2009 by Arnold Krille
3 #
4 # This file is part of FFADO
5 # FFADO = Free Firewire (pro-)audio drivers for linux
6 #
7 # This program is free software: you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation, either version 2 of the License, or
10 # (at your option) version 3 of the License.
11 #
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 # GNU General Public License for more details.
16 #
17 # You should have received a copy of the GNU General Public License
18 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 #
20
21 from PyQt4 import QtGui, QtCore
22 import dbus, math
23
24 import logging
25 log = logging.getLogger("crossbarrouter")
26
27 class VuMeter(QtGui.QFrame):
28     def __init__(self, interface, output, input=None, parent=None):
29         QtGui.QFrame.__init__(self, parent)
30         self.setLineWidth(1)
31         self.setFrameStyle(QtGui.QFrame.Panel|QtGui.QFrame.Sunken)
32         self.setMinimumSize(20, 20)
33
34         self.level = 0
35
36         self.interface = interface
37
38         self.output = output
39
40     def updateLevel(self, value):
41         self.level = value
42         self.update()
43
44     def paintEvent(self, event):
45         p = QtGui.QPainter(self)
46         value = self.level/4096
47         r = self.rect()
48         r.setHeight(r.height() * math.sqrt(value))
49         r.moveBottom(self.rect().height())
50         p.fillRect(r, self.palette().highlight())
51
52 class OutputSwitcher(QtGui.QFrame):
53     """
54 The name is a bit misleading. This widget selectes sources for a specified
55 destination.
56
57 In mixer-usage this widget is at the top of the input-channel. Because the input
58 of the mixer is an available output from the routers point.
59 """
60     def __init__(self, interface, outname, parent):
61         QtGui.QFrame.__init__(self, parent)
62         self.interface = interface
63         self.outname = outname
64         self.lastin = ""
65
66         self.setLineWidth(1)
67         self.setFrameStyle(QtGui.QFrame.Sunken|QtGui.QFrame.Panel)
68
69         self.layout = QtGui.QGridLayout(self)
70         self.setLayout(self.layout)
71
72         self.lbl = QtGui.QLabel(self.outname, self)
73         self.lbl.setToolTip("The name of the destination that is to be controlled here.")
74         self.layout.addWidget(self.lbl, 0, 0)
75
76         self.vu = VuMeter(self.interface, outname, parent=self)
77         self.layout.addWidget(self.vu, 0, 1)
78
79         sources = self.interface.getSourceNames()
80
81         self.combo = QtGui.QComboBox(self)
82         self.combo.setToolTip("<qt>Select the source for this destination.<br>Each destination can only receive sound from one source at a time. But one source can send sound to multiple destinations.</qt>")
83         self.layout.addWidget(self.combo, 1, 0, 1, 2)
84         self.combo.addItem("Disconnected")
85         self.combo.addItems(sources)
86         src = self.interface.getSourceForDestination(self.outname)
87         self.lastin = str(src)
88         if src != "":
89             self.combo.setCurrentIndex(self.combo.findText(src))
90         else:
91             self.combo.setCurrentIndex(0)
92         self.connect(self.combo, QtCore.SIGNAL("activated(QString)"), self.comboCurrentChanged)
93
94
95     def peakValue(self, value):
96         self.vu.updateLevel(value)
97         pass
98
99     def comboCurrentChanged(self, inname):
100         #log.debug("comboCurrentChanged( %s )" % inname)
101         if inname == self.lastin:
102             return
103         if self.lastin != "":
104             self.interface.setConnectionState(self.lastin, self.outname, False)
105
106         if inname != "Disconnected":
107             if self.interface.setConnectionState(str(inname), self.outname, True):
108                 if self.outname[:5] == "Mixer" or self.lastin[:5] == "Mixer" or str(inname)[:5] == "Mixer":
109                     self.emit(QtCore.SIGNAL("MixerRoutingChanged"))
110                 self.lastin = str(inname)
111             else:
112                 log.warning(" Failed to connect %s to %s" % (inname, self.outname))
113         else:
114             self.lastin = ""
115
116
117 class CrossbarRouter(QtGui.QWidget):
118     def __init__(self, servername, basepath, parent=None):
119         QtGui.QWidget.__init__(self, parent);
120         self.bus = dbus.SessionBus()
121         self.dev = self.bus.get_object(servername, basepath)
122         self.interface = dbus.Interface(self.dev, dbus_interface="org.ffado.Control.Element.CrossbarRouter")
123
124         self.settings = QtCore.QSettings(self)
125
126         destinations = self.interface.getDestinationNames()
127         self.outgroups = []
128         for ch in destinations:
129             tmp = str(ch).split(":")[0]
130             if not tmp in self.outgroups:
131                 self.outgroups.append(tmp)
132
133         self.biglayout = QtGui.QVBoxLayout(self)
134         self.setLayout(self.biglayout)
135
136         self.toplayout = QtGui.QHBoxLayout()
137         self.biglayout.addLayout(self.toplayout)
138
139         self.vubtn = QtGui.QPushButton("Switch peak meters", self)
140         self.vubtn.setCheckable(True)
141         self.connect(self.vubtn, QtCore.SIGNAL("toggled(bool)"), self.runVu)
142         self.toplayout.addWidget(self.vubtn)
143
144         self.layout = QtGui.QGridLayout()
145         self.biglayout.addLayout(self.layout)
146
147         self.switchers = {}
148         for out in destinations:
149             btn = OutputSwitcher(self.interface, out, self)
150             self.layout.addWidget(btn, int(out.split(":")[-1]) + 1, self.outgroups.index(out.split(":")[0]))
151             self.switchers[out] = btn
152             self.connect(btn, QtCore.SIGNAL("MixerRoutingChanged"), self.updateMixerRouting)
153
154         self.timer = QtCore.QTimer(self)
155         self.timer.setInterval(200)
156         self.connect(self.timer, QtCore.SIGNAL("timeout()"), self.updateLevels)
157
158         self.vubtn.setChecked(self.settings.value("crossbarrouter/runvu", False).toBool())
159
160     def __del__(self):
161         print "CrossbarRouter.__del__()"
162         self.settings.setValue("crossbarrouter/runvu", self.vubtn.isChecked())
163
164     def runVu(self, run=True):
165         #log.debug("CrossbarRouter.runVu( %i )" % run)
166         if run:
167             self.timer.start()
168         else:
169             self.timer.stop()
170             for sw in self.switchers:
171                 self.switchers[sw].peakValue(0)
172
173     def updateLevels(self):
174         #log.debug("CrossbarRouter.updateLevels()")
175         peakvalues = self.interface.getPeakValues()
176         #log.debug("Got %i peaks" % len(peakvalues))
177         for peak in peakvalues:
178             #log.debug("peak = [%s,%s]" % (str(peak[0]),str(peak[1])))
179             if peak[0] >= 0:
180                 self.switchers[peak[0]].peakValue(peak[1])
181
182     def updateMixerRouting(self):
183         self.emit(QtCore.SIGNAL("MixerRoutingChanged"))
184
185     def saveSettings(self, indent):
186         destinations = self.interface.getDestinationNames()
187         routerSaveString = []
188         routerSaveString.append('%s<dimensions>\n' % indent)
189         routerSaveString.append('%s  %d 2\n' % (indent, len(destinations)))
190         routerSaveString.append('%s</dimensions>\n' % indent)
191         routerSaveString.append('%s<connections>\n' % indent)
192         for out in destinations:
193             routerSaveString.append('%s  ' % indent + out + ' ')
194             routerSaveString.append(self.interface.getSourceForDestination(out) + '\n')
195         routerSaveString.append('%s</connections>\n' % indent)
196         return routerSaveString       
197
198     def readSettings(self, routerReadString):
199         try:
200             idx = routerReadString.index('<dimensions>')
201         except Exception:
202             log.debug("Router dimensions must be specified\n")
203             return False
204         n_r = int(routerReadString[idx+1].split()[0])
205         n_c = int(routerReadString[idx+1].split()[1])
206         if n_c > 2:
207             print "Don't know how to handle more than one source for one destination"
208         try:
209             idxb = routerReadString.index('<connections>')
210             idxe = routerReadString.index('</connections>')
211         except Exception:
212             log.debug("Router connections not specified\n")
213             idxb = -1
214             idxe = -1
215             return False
216         if idxb > 0:
217             if idxe > idxb:
218                 for s in routerReadString[idxb+1:idxe]:
219                     destination = s.split()[0]
220                     source = s.split()[1]
221                     idx = self.switchers[destination].combo.findText(source)
222                     self.switchers[destination].combo.setCurrentIndex(idx)
223                     self.switchers[destination].comboCurrentChanged(source)
224         return True
225 #
226 # vim: sw=4 ts=4 et
Note: See TracBrowser for help on using the browser.