Show
Ignore:
Timestamp:
11/14/09 13:15:10 (11 years ago)
Author:
arnonym
Message:

Panning multiple channels to multiple channels is rather complicated. Probably more complicated then what is needed for ffado-mixer. So go back to individual controls for each junction. They look like colored labels but are in fact sliders. A context-menu with predefined values and a direct input for numbers will come soon...

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/libffado/support/mixer-qt4/ffado/widgets/matrixmixer.py

    r1695 r1706  
    2020 
    2121from PyQt4 import QtGui, QtCore, Qt 
    22 import dbus, numpy 
    23  
    24 from ffado.widgets.ntompanner import N2MPanner 
     22import dbus, math 
    2523 
    2624import logging 
    2725log = logging.getLogger("matrixmixer") 
    2826 
    29 class MixerNode(QtGui.QFrame): 
    30     def __init__(self, inputs, outputs, parent): 
    31         """inputs  = list of input-channel numbers 
    32            outputs = list of output-channel numbers 
    33            """ 
    34         QtGui.QFrame.__init__(self, parent) 
    35         self.setLineWidth(2) 
    36         self.setFrameStyle(QtGui.QFrame.Panel|QtGui.QFrame.Raised) 
    37  
    38         self.inputs = [] 
    39         self.outputs = [] 
    40  
    41         self.fader = QtGui.QDial(self) 
    42         self.fader.setRange(0,pow(2,16)-1) 
    43         self.connect(self.fader, QtCore.SIGNAL("valueChanged(int)"), self.valuesChanged) 
    44  
    45         self.layout = QtGui.QGridLayout(self) 
    46         self.setLayout(self.layout) 
    47  
    48         self.layout.addWidget(self.fader, 0, 0) 
    49  
    50         self.addInputs(inputs) 
    51         self.addOutputs(outputs) 
    52  
    53     def valuesChanged(self): 
    54         #log.debug("MixerNode.valuesChanged") 
    55         fader = self.fader.value() 
    56         values = numpy.ones((len(self.inputs), 1)) 
    57         if len(self.outputs) > 1: 
    58             values = self.panner.values 
    59             if values.size == 0: 
    60                 return 
    61             values = numpy.minimum(values, 2) 
    62             values = 1 - numpy.power(values/2, 2) 
    63         #print values 
    64         #print numpy.exp(-values) 
    65         values = values * fader 
    66         #print values 
    67         ret = [] 
    68         #print "i will be in %s" % str(range(len(self.inputs))) 
    69         #print "j will be in %s" % str(range(len(self.outputs))) 
    70         #print "values.shape: %s" % str(values.shape) 
    71         for i in range(len(self.inputs)): 
    72             for j in range(len(self.outputs)): 
    73                 #print "%i,%i : %s" % (i, j, str(values[i,j])) 
    74                 ret.append( (self.inputs[i], self.outputs[j], values[i,j]) ) 
    75         #print ret 
    76         self.emit(QtCore.SIGNAL("valueChanged"), ret) 
    77  
    78     def addInputs(self, inputs, add=True): 
    79         if not isinstance(inputs, list): 
    80             inputs = [inputs] 
    81         if add: 
    82             self.inputs += inputs 
     27class ColorForNumber: 
     28    def __init__(self): 
     29        self.colors = dict() 
     30 
     31    def addColor(self, n, color): 
     32        self.colors[n] = color 
     33 
     34    def getColor(self, n): 
     35        #print "ColorForNumber.getColor( %g )" % (n) 
     36        keys = self.colors.keys() 
     37        low = keys[-1] 
     38        high = keys[-1] 
     39        for i in range(len(keys)-1): 
     40            if keys[i] <= n and keys[i+1] > n: 
     41                low = keys[i] 
     42                high = keys[i+1] 
     43        #print "%g is between %g and %g" % (n, low, high) 
     44        f = 0 
     45        if high != low: 
     46            f = (n-low) / (high-low) 
     47        lc = self.colors[low] 
     48        hc = self.colors[high] 
     49        return QtGui.QColor( 
     50                (1-f)*lc.red()   + f*hc.red(), 
     51                (1-f)*lc.green() + f*hc.green(), 
     52                (1-f)*lc.blue()  + f*hc.blue() ) 
     53 
     54class MixerNode(QtGui.QAbstractSlider): 
     55    def __init__(self, input, output, value, parent): 
     56        QtGui.QAbstractSlider.__init__(self, parent) 
     57        log.debug("MixerNode.__init__( %i, %i, %i, %s )" % (input, output, value, str(parent)) ) 
     58 
     59        self.pos = QtCore.QPointF(0, 0) 
     60        self.input = input 
     61        self.output = output 
     62        self.setOrientation(Qt.Qt.Vertical) 
     63        self.setRange(0, pow(2, 16)-1) 
     64        self.setValue(value) 
     65        self.connect(self, QtCore.SIGNAL("valueChanged(int)"), self.internalValueChanged) 
     66 
     67        self.bgcolors = ColorForNumber() 
     68        self.bgcolors.addColor(0.0*65535, QtGui.QColor(  0,   0,   0)) 
     69        self.bgcolors.addColor(0.1*65535, QtGui.QColor(  0,   0, 128)) 
     70        self.bgcolors.addColor(0.8*65535, QtGui.QColor(255, 255,   0)) 
     71        self.bgcolors.addColor(1.0*65535, QtGui.QColor(255,   0,   0)) 
     72 
     73    def mousePressEvent(self, ev): 
     74        if ev.buttons() & Qt.Qt.LeftButton: 
     75            self.pos = ev.posF() 
     76            self.tmpvalue = self.value() 
     77            ev.accept() 
     78            #log.debug("MixerNode.mousePressEvent() %s" % str(self.pos)) 
     79 
     80    def mouseMoveEvent(self, ev): 
     81        if hasattr(self, "tmpvalue") and self.pos is not QtCore.QPointF(0, 0): 
     82            newpos = ev.posF() 
     83            change = newpos.y() - self.pos.y() 
     84            #log.debug("MixerNode.mouseReleaseEvent() change %s" % (str(change))) 
     85            self.setValue( self.tmpvalue - math.copysign(pow(abs(change), 2), change) ) 
     86            ev.accept() 
     87        pass 
     88 
     89    def mouseReleaseEvent(self, ev): 
     90        if hasattr(self, "tmpvalue") and self.pos is not QtCore.QPointF(0, 0): 
     91            newpos = ev.posF() 
     92            change = newpos.y() - self.pos.y() 
     93            #log.debug("MixerNode.mouseReleaseEvent() change %s" % (str(change))) 
     94            self.setValue( self.tmpvalue - math.copysign(pow(abs(change), 2), change) ) 
     95            self.pos = QtCore.QPointF(0, 0) 
     96            del self.tmpvalue 
     97            ev.accept() 
     98 
     99    def paintEvent(self, ev): 
     100        p = QtGui.QPainter(self) 
     101        rect = self.rect() 
     102        v = self.value() 
     103        color = self.bgcolors.getColor(v) 
     104        p.fillRect(rect, color) 
     105        if color.valueF() < 0.5: 
     106            p.setPen(QtGui.QColor(255, 255, 255)) 
    83107        else: 
    84             for item in inputs: 
    85                 self.inputs.remove(item) 
    86         self.checkWidgets() 
    87     def removeInputs(self, inputs): 
    88         self.addInputs(inputs, False) 
    89  
    90     def addOutputs(self, outputs, add=True): 
    91         if not isinstance(outputs, list): 
    92             outputs = [outputs] 
    93         if add: 
    94             self.outputs += outputs 
    95         else: 
    96             for item in outputs: 
    97                 self.outputs.remove(item) 
    98         self.checkWidgets() 
    99     def removeOutputs(self, outputs): 
    100         self.addOutputs(outputs, False) 
    101  
    102     def checkWidgets(self): 
    103         if not hasattr(self, "panner") and len(self.outputs)>1: 
    104             self.panner = N2MPanner(self) 
    105             self.layout.addWidget(self.panner, 1, 0) 
    106             self.connect(self.panner, QtCore.SIGNAL("valuesChanged"), self.valuesChanged) 
    107         if hasattr(self, "panner"): 
    108             self.panner.setVisible(len(self.outputs)>1) 
    109             self.panner.setNumberOfSources(len(self.inputs)) 
    110             self.panner.setNumberOfSinks(len(self.outputs)) 
    111         if len(self.inputs) and len(self.outputs): 
    112             valuematrix = [] 
    113             for row in self.outputs: 
    114                 valuematrix.append( [] ) 
    115                 for col in self.inputs: 
    116                     valuematrix[self.outputs.index(row)] = self.parent().interface.getValue(row, col) 
    117             self.fader.setValue(max(valuematrix)) 
     108            p.setPen(QtGui.QColor(0, 0, 0)) 
     109        p.drawText(rect, Qt.Qt.AlignCenter, str(self.value())) 
     110 
     111    def internalValueChanged(self, value): 
     112        #log.debug("MixerNode.internalValueChanged( %i )" % value) 
     113        self.emit(QtCore.SIGNAL("valueChanged"), (self.input, self.output, value) ) 
     114 
    118115 
    119116 
     
    125122        if name is not "": 
    126123            name = " (%s)" % name 
    127         self.lbl = QtGui.QLabel("Ch. %i%s" % (self.number, name), self) 
     124        self.lbl = QtGui.QLabel("Ch. %i\n%s" % (self.number, name), self) 
    128125        layout.addWidget(self.lbl, 0, 0, 1, 2) 
    129126 
     
    134131        layout.addWidget(self.btnHide, 1, 0) 
    135132 
    136         self.btnCouple = QtGui.QToolButton(self) 
    137         self.btnCouple.setText("Stereo") 
    138         self.btnCouple.setCheckable(True) 
    139         self.connect(self.btnCouple, QtCore.SIGNAL("toggled(bool)"), self.coupleWithNext) 
    140         layout.addWidget(self.btnCouple, 1, 1) 
    141  
    142133    def hideChannel(self, hide): 
    143         self.btnCouple.setHidden(hide) 
    144134        self.emit(QtCore.SIGNAL("hide"), self.number, hide) 
    145135 
    146     def coupleWithNext(self, couple): 
    147         self.emit(QtCore.SIGNAL("couple"), self.number, couple) 
    148  
    149     def canCouple(self, cancouple): 
    150         #self.btnCouple.setEnabled(cancouple) 
    151         self.btnCouple.setHidden(not cancouple) 
     136 
    152137 
    153138class MatrixMixer(QtGui.QWidget): 
     
    176161        for i in range(cols): 
    177162            ch = MixerChannel(i, self, self.interface.getColName(i)) 
    178             self.connect(ch, QtCore.SIGNAL("couple"), self.coupleColumn) 
    179163            self.connect(ch, QtCore.SIGNAL("hide"), self.hideColumn) 
    180             ch.canCouple(i+1!=cols) 
    181164            layout.addWidget(ch, 0, i+1) 
    182165            self.columnHeaders.append( ch ) 
    183166        for i in range(rows): 
    184167            ch = MixerChannel(i, self, self.interface.getRowName(i)) 
    185             self.connect(ch, QtCore.SIGNAL("couple"), self.coupleRow) 
    186168            self.connect(ch, QtCore.SIGNAL("hide"), self.hideRow) 
    187             ch.canCouple(i+1!=rows) 
    188169            layout.addWidget(ch, i+1, 0) 
    189170            self.rowHeaders.append( ch ) 
     
    193174            self.items.append([]) 
    194175            for j in range(cols): 
    195                 node = MixerNode(j, i, self
     176                node = MixerNode(j, i, self.interface.getValue(i,j), self
    196177                self.connect(node, QtCore.SIGNAL("valueChanged"), self.valueChanged) 
    197178                layout.addWidget(node, i+1, j+1) 
     
    200181        self.hiddenRows = [] 
    201182        self.hiddenCols = [] 
    202         self.coupledRows = [] 
    203         self.coupledCols = [] 
    204183 
    205184 
     
    207186        for x in range(len(self.items)): 
    208187            for y in range(len(self.items[x])): 
    209                 self.items[x][y].setHidden( (x in self.hiddenRows) | (x in self.coupledRows) | (y in self.hiddenCols) | (y in self.coupledCols) ) 
    210  
    211     def coupleColumn(self, column, couple): 
    212         if column+1 < len(self.columnHeaders): 
    213             self.columnHeaders[column+1].setHidden(couple) 
    214         if column > 0: 
    215             self.columnHeaders[column-1].canCouple(not couple) 
    216         if couple: 
    217             self.coupledCols.append(column+1) 
    218         else: 
    219             self.coupledCols.remove(column+1) 
    220         for row in self.items: 
    221             row[column].addInputs(column+1,couple) 
    222             row[column+1].addInputs(column+1,not couple) 
    223         self.checkVisibilities() 
    224  
    225     def coupleRow(self, row, couple): 
    226         if row+1 < len(self.rowHeaders): 
    227             self.rowHeaders[row+1].setHidden(couple) 
    228         if row > 0: 
    229             self.rowHeaders[row-1].canCouple(not couple) 
    230         if couple: 
    231             self.coupledRows.append(row+1) 
    232         else: 
    233             self.coupledRows.remove(row+1) 
    234         for col in self.items[row]: 
    235             col.addOutputs(row+1,couple) 
    236         for col in self.items[row+1]: 
    237             col.addOutputs(row+1,not couple) 
    238         self.checkVisibilities() 
     188                self.items[x][y].setHidden( 
     189                        (x in self.hiddenRows) 
     190                        | (y in self.hiddenCols) 
     191                        ) 
     192 
    239193 
    240194    def hideColumn(self, column, hide): 
     
    252206 
    253207    def valueChanged(self, n): 
    254         #log.debug("MatrixNode.valueChanged( %s )" % str(n)) 
    255         for tmp in n: 
    256             self.interface.setValue(tmp[1], tmp[0], tmp[2]) 
     208        log.debug("MatrixNode.valueChanged( %s )" % str(n)) 
     209        self.interface.setValue(n[1], n[0], n[2]) 
    257210 
    258211