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

Revision 1683, 5.3 kB (checked in by arnonym, 14 years ago)

Kind of a usable panner. In theory this should allow panning several sources to several sinks. In practice only mono-to-stereo and stereo-to-stereo is currently possible. Not because of the panner but because of the way it works in the matrixmixer. Will change that soon.

One of the current draw-backs is that I am using numpy. Standard pythons matrix handling doesn't seem so good.

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, math, numpy
23
24 import logging
25 log = logging.getLogger("widgets")
26
27 percentage = 0.3
28 circlerect = QtCore.QRectF(-percentage/2, -percentage/2, percentage, percentage)
29
30 class PannerSource(QtGui.QGraphicsEllipseItem):
31     def __init__(self, number, parent):
32         QtGui.QGraphicsEllipseItem.__init__(self)
33         self.setRect(circlerect)
34
35         self.number = number
36         self.parent = parent
37
38         self.setBrush(QtGui.QColor(255, 0, 0))
39         self.setPen(QtGui.QPen(Qt.Qt.NoPen))
40
41         self.setFlags(QtGui.QGraphicsItem.ItemIsMovable | QtGui.QGraphicsItem.ItemIsFocusable)
42
43     def focusInEvent(self, ev):
44         QtGui.QGraphicsEllipseItem.focusInEvent(self, ev)
45
46     def itemChange(self, change, value):
47         if change == QtGui.QGraphicsItem.ItemPositionChange:
48             value = self.parent.nearestSink(value.toPointF())
49         if change == QtGui.QGraphicsItem.ItemPositionHasChanged:
50             self.parent.sourcePositionChanged(self.number)
51         return QtGui.QGraphicsEllipseItem.itemChange(self, change, value)
52
53 class N2MPanner(QtGui.QFrame):
54     def __init__(self, parent):
55         QtGui.QFrame.__init__(self, parent)
56
57         layout = QtGui.QGridLayout(self)
58         self.setLayout(layout)
59
60         self.view = QtGui.QGraphicsView(self)
61         layout.addWidget(self.view, 0, 0)
62
63         self.scene = QtGui.QGraphicsScene(QtCore.QRectF(-1, -1, 2, 2), self)
64         self.view.setScene(self.scene)
65
66         self.scene.addEllipse( QtCore.QRectF(-1,-1,2,2), QtGui.QPen(self.palette().color(QtGui.QPalette.Window).darker() ) ).setZValue(-1)
67
68         self.pen = QtGui.QPen(self.palette().color(QtGui.QPalette.Window).darker())
69         #pen.setWidthF(0.01)
70
71         self.sources = []
72         self.sinks = []
73         self.values = numpy.array(numpy.float)
74         #print self.values.flags
75         #print self.values
76
77         #self.updateGeometry()
78         QtCore.QTimer.singleShot(10, self.resizeEvent)
79
80     def setNumberOfSinks(self, sinknr):
81         while len(self.sinks) > sinknr:
82             self.sinks[-1].setParentItem(None)
83             del self.sinks[-1]
84         while len(self.sinks) < sinknr:
85             c = self.scene.addEllipse(circlerect, self.pen)
86             c.setZValue(1)
87             self.sinks.append(c)
88         for i in range(sinknr):
89             degree = 2*math.pi/sinknr
90             self.sinks[i].setPos(math.cos(degree), math.sin(degree))
91         self.update()
92         self.values.resize((len(self.sources), len(self.sinks)))
93         self.sourcePositionChanged(range(len(self.sources)))
94
95     def setNumberOfSources(self, sourcenr):
96         while len(self.sources) > sourcenr:
97             self.sources[-1].setParentItem(None)
98             del self.sources[-1]
99         while len(self.sources) < sourcenr:
100             s = PannerSource(len(self.sources), self)
101             self.scene.addItem(s)
102             self.sources.append(s)
103         self.values.resize((len(self.sources), len(self.sinks)))
104         self.sourcePositionChanged(range(len(self.sources)))
105
106     def distance(self, p1, p2):
107         return math.sqrt( math.pow(p1.x()-p2.x(), 2) + math.pow(p1.y()-p2.y(), 2) )
108
109     def sourcePositionChanged(self, number):
110         if not isinstance(number, list):
111             number = [number]
112         #print "N2MPanner.sourcePositionChanged( %s )" % str(number)
113         for i in number:
114             for sink in self.sinks:
115                 j = self.sinks.index(sink)
116                 self.values[i,j] = self.distance(self.sources[i].pos(), sink.pos())
117                 #print " distance to sink(%g, %g) is %g" % (sink.x(), sink.y(), self.distance(self.sources[number].pos(), sink.pos()))
118         #print self.values
119         self.emit(QtCore.SIGNAL("valuesChanged"))
120
121     def nearestSink(self, point):
122         for sink in self.sinks:
123             if sink.contains(sink.mapFromParent(point)):
124                 return sink.pos()
125         return point
126
127     def resizeEvent(self, event=None):
128         self.view.fitInView(QtCore.QRectF(-1.2, -1.2, 2.4, 2.4), Qt.Qt.KeepAspectRatio)
129
130
131 if __name__ == "__main__":
132
133     import sys
134
135     app = QtGui.QApplication(sys.argv)
136
137     w = QtGui.QWidget(None)
138     l = QtGui.QVBoxLayout(w)
139
140     s1 = QtGui.QSpinBox(w)
141     s1.setRange(1,10)
142     l.addWidget(s1)
143
144     s2 = QtGui.QSpinBox(w)
145     s2.setRange(1,10)
146     l.addWidget(s2)
147
148     p = N2MPanner(w)
149     p.setNumberOfSinks(1)
150     p.setNumberOfSources(1)
151     QtCore.QObject.connect(s1, QtCore.SIGNAL("valueChanged(int)"), p.setNumberOfSinks)
152     QtCore.QObject.connect(s2, QtCore.SIGNAL("valueChanged(int)"), p.setNumberOfSources)
153     l.addWidget(p)
154
155     w.show()
156
157     app.exec_()
158
159
160 #
161 # vim: et ts=4 sw=4
Note: See TracBrowser for help on using the browser.