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

Revision 1668, 9.7 kB (checked in by arnonym, 12 years ago)
  • Use logging for the debug-output.
  • Add the ability to completely disconnect outputs from their input. This removes (should remove?) routes from the routing table.
  • Property svn:mergeinfo set to
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, Qt
22 import dbus
23
24 import logging
25 log = logging.getLogger("matrixmixer")
26
27 class MixerNode(QtGui.QFrame):
28     def __init__(self, inputs, outputs, parent):
29         """inputs  = list of input-channel numbers
30            outputs = list of output-channel numbers
31            """
32         QtGui.QFrame.__init__(self, parent)
33         self.setLineWidth(2)
34         self.setFrameStyle(QtGui.QFrame.Panel|QtGui.QFrame.Raised)
35
36         self.inputs = []
37         self.outputs = []
38
39         self.inputbalance = QtGui.QSlider(Qt.Qt.Horizontal, self)
40         self.inputbalance.setRange(-100, 100)
41         self.connect(self.inputbalance, QtCore.SIGNAL("valueChanged(int)"), self.valuesChanged)
42
43         self.outputbalance = QtGui.QSlider(Qt.Qt.Horizontal, self)
44         self.outputbalance.setRange(-100, 100)
45         self.connect(self.outputbalance, QtCore.SIGNAL("valueChanged(int)"), self.valuesChanged)
46
47         self.fader = QtGui.QDial(self)
48         self.fader.setRange(0,pow(2,16)-1)
49         self.connect(self.fader, QtCore.SIGNAL("valueChanged(int)"), self.valuesChanged)
50
51         self.layout = QtGui.QGridLayout(self)
52         self.setLayout(self.layout)
53
54         self.layout.addWidget(self.inputbalance, 0, 0)
55         self.layout.addWidget(self.fader, 1, 0)
56         self.layout.addWidget(self.outputbalance, 2, 0)
57
58         self.addInputs(inputs)
59         self.addOutputs(outputs)
60
61     def valuesChanged(self):
62         fader = self.fader.value()
63         values = []
64         while len(values) < len(self.inputs):
65             tmp = []
66             while len(tmp) < len(self.outputs):
67                 tmp.append(fader)
68             values.append(tmp)
69         if len(self.inputs) == len(self.outputs):
70             for i in range(len(self.inputs)):
71                 for j in range(len(self.outputs)):
72                     values[i][j] *= (i==j)
73         if len(self.outputs) == 2:
74             v = self.outputbalance.value() / 100.0
75             left = 1.0
76             right = 1.0
77             if v > 0:
78                 left = 1.0 - v
79             if v < 0:
80                 right = 1.0 + v
81             for row in values:
82                 row[0] *= left
83                 row[1] *= right
84         if len(self.inputs) == 2:
85             v = self.inputbalance.value() / 100.0
86             left = 1.0
87             right = 1.0
88             if v > 0:
89                 left = 1.0 - v
90             if v < 0:
91                 right = 1.0 + v
92             for i in range(len(self.outputs)):
93                 values[0][i] *= left
94                 values[1][i] *= right
95         ret = []
96         for i in range(len(self.inputs)):
97             for j in range(len(self.outputs)):
98                 ret.append( (self.inputs[i], self.outputs[j], values[i][j]) )
99         #print ret
100         self.emit(QtCore.SIGNAL("valueChanged"), ret)
101
102     def addInputs(self, inputs, add=True):
103         if not isinstance(inputs, list):
104             inputs = [inputs]
105         if add:
106             self.inputs += inputs
107         else:
108             for item in inputs:
109                 self.inputs.remove(item)
110         self.checkWidgets()
111     def removeInputs(self, inputs):
112         self.addInputs(inputs, False)
113
114     def addOutputs(self, outputs, add=True):
115         if not isinstance(outputs, list):
116             outputs = [outputs]
117         if add:
118             self.outputs += outputs
119         else:
120             for item in outputs:
121                 self.outputs.remove(item)
122         self.checkWidgets()
123     def removeOutputs(self, outputs):
124         self.addOutputs(outputs, False)
125
126     def checkWidgets(self):
127         if len(self.inputs)>1:
128             self.inputbalance.show()
129         else:
130             self.inputbalance.hide()
131         if len(self.outputs)>1:
132             self.outputbalance.show()
133         else:
134             self.outputbalance.hide()
135         if len(self.inputs) and len(self.outputs):
136             valuematrix = []
137             for row in self.outputs:
138                 valuematrix.append( [] )
139                 for col in self.inputs:
140                     valuematrix[self.outputs.index(row)] = self.parent().interface.getValue(row, col)
141             self.fader.setValue(max(valuematrix))
142
143
144 class MixerChannel(QtGui.QWidget):
145     def __init__(self, number, parent=None):
146         QtGui.QWidget.__init__(self, parent)
147         layout = QtGui.QGridLayout(self)
148         self.number = number
149         self.lbl = QtGui.QLabel("Ch. %i" % self.number, self)
150         layout.addWidget(self.lbl, 0, 0, 1, 2)
151
152         self.btnHide = QtGui.QToolButton(self)
153         self.btnHide.setText("Hide")
154         self.btnHide.setCheckable(True)
155         self.connect(self.btnHide, QtCore.SIGNAL("clicked(bool)"), self.hideChannel)
156         layout.addWidget(self.btnHide, 1, 0)
157
158         self.btnCouple = QtGui.QToolButton(self)
159         self.btnCouple.setText("Stereo")
160         self.btnCouple.setCheckable(True)
161         self.connect(self.btnCouple, QtCore.SIGNAL("toggled(bool)"), self.coupleWithNext)
162         layout.addWidget(self.btnCouple, 1, 1)
163
164     def hideChannel(self, hide):
165         self.btnCouple.setHidden(hide)
166         self.emit(QtCore.SIGNAL("hide"), self.number, hide)
167
168     def coupleWithNext(self, couple):
169         self.emit(QtCore.SIGNAL("couple"), self.number, couple)
170
171     def canCouple(self, cancouple):
172         #self.btnCouple.setEnabled(cancouple)
173         self.btnCouple.setHidden(not cancouple)
174
175 class MatrixMixer(QtGui.QWidget):
176     def __init__(self, servername, basepath, parent=None):
177         QtGui.QWidget.__init__(self, parent)
178         self.bus = dbus.SessionBus()
179         self.dev = self.bus.get_object(servername, basepath)
180         self.interface = dbus.Interface(self.dev, dbus_interface="org.ffado.Control.Element.MatrixMixer")
181
182         palette = self.palette()
183         palette.setColor(QtGui.QPalette.Window, palette.color(QtGui.QPalette.Window).darker());
184         self.setPalette(palette)
185
186         rows = self.interface.getColCount()
187         cols = self.interface.getRowCount()
188         log.debug("Mixer has %i rows and %i columns" % (rows, cols))
189
190         layout = QtGui.QGridLayout(self)
191         self.setLayout(layout)
192
193         self.rowHeaders = []
194         self.columnHeaders = []
195         self.items = []
196
197         # Add row/column headers
198         for i in range(cols):
199             ch = MixerChannel(i, self)
200             self.connect(ch, QtCore.SIGNAL("couple"), self.coupleColumn)
201             self.connect(ch, QtCore.SIGNAL("hide"), self.hideColumn)
202             ch.canCouple(i+1!=cols)
203             layout.addWidget(ch, 0, i+1)
204             self.columnHeaders.append( ch )
205         for i in range(rows):
206             ch = MixerChannel(i, self)
207             self.connect(ch, QtCore.SIGNAL("couple"), self.coupleRow)
208             self.connect(ch, QtCore.SIGNAL("hide"), self.hideRow)
209             ch.canCouple(i+1!=rows)
210             layout.addWidget(ch, i+1, 0)
211             self.rowHeaders.append( ch )
212
213         # Add node-widgets
214         for i in range(rows):
215             self.items.append([])
216             for j in range(cols):
217                 node = MixerNode(j, i, self)
218                 self.connect(node, QtCore.SIGNAL("valueChanged"), self.valueChanged)
219                 layout.addWidget(node, i+1, j+1)
220                 self.items[i].append(node)
221
222         self.hiddenRows = []
223         self.hiddenCols = []
224         self.coupledRows = []
225         self.coupledCols = []
226
227
228     def checkVisibilities(self):
229         for x in range(len(self.items)):
230             for y in range(len(self.items[x])):
231                 self.items[x][y].setHidden( (x in self.hiddenRows) | (x in self.coupledRows) | (y in self.hiddenCols) | (y in self.coupledCols) )
232
233     def coupleColumn(self, column, couple):
234         if column+1 < len(self.columnHeaders):
235             self.columnHeaders[column+1].setHidden(couple)
236         if column > 0:
237             self.columnHeaders[column-1].canCouple(not couple)
238         if couple:
239             self.coupledCols.append(column+1)
240         else:
241             self.coupledCols.remove(column+1)
242         for row in self.items:
243             row[column].addInputs(column+1,couple)
244             row[column+1].addInputs(column+1,not couple)
245         self.checkVisibilities()
246
247     def coupleRow(self, row, couple):
248         if row+1 < len(self.rowHeaders):
249             self.rowHeaders[row+1].setHidden(couple)
250         if row > 0:
251             self.rowHeaders[row-1].canCouple(not couple)
252         if couple:
253             self.coupledRows.append(row+1)
254         else:
255             self.coupledRows.remove(row+1)
256         for col in self.items[row]:
257             col.addOutputs(row+1,couple)
258         for col in self.items[row+1]:
259             col.addOutputs(row+1,not couple)
260         self.checkVisibilities()
261
262     def hideColumn(self, column, hide):
263         if hide:
264             self.hiddenCols.append(column)
265         else:
266             self.hiddenCols.remove(column)
267         self.checkVisibilities()
268     def hideRow(self, row, hide):
269         if hide:
270             self.hiddenRows.append(row)
271         else:
272             self.hiddenRows.remove(row)
273         self.checkVisibilities()
274
275     def valueChanged(self, n):
276         log.debug("MatrixNode.valueChanged( %s )" % str(n))
277         for tmp in n:
278             self.interface.setValue(tmp[1], tmp[0], tmp[2])
279
280
281 #
282 # vim: et ts=4 sw=4
Note: See TracBrowser for help on using the browser.