Files
@ 69ca2b2fc133
Branch filter:
Location: light9/bcf2000.py
69ca2b2fc133
4.0 KiB
text/x-python
overcomplicated attempt at persisting the pane layout in the rdf graph
this was hard because we have to somehow wait for the graph to load before config'ing the panes
this was hard because we have to somehow wait for the graph to load before config'ing the panes
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 | #!/usr/bin/python
import math
import twisted.internet.fdesc
from twisted.internet import reactor
from twisted.internet.task import LoopingCall
from typing import Dict
class BCF2000(object):
control = {81 : "slider1", 82 : "slider2", 83 : "slider3", 84 : "slider4",
85 : "slider5", 86 : "slider6", 87 : "slider7", 88 : "slider8",
1 : "knob1", 2 : "knob2", 3 : "knob3", 4 : "knob4",
5 : "knob5", 6 : "knob6", 7 : "knob7", 8 : "knob8",
33 : "button-knob1", 34 : "button-knob2",
35 : "button-knob3", 36 : "button-knob4",
37 : "button-knob5", 38 : "button-knob6",
39 : "button-knob7", 40 : "button-knob8",
65 : "button-upper1", 66 : "button-upper2",
67 : "button-upper3", 68 : "button-upper4",
69 : "button-upper5", 70 : "button-upper6",
71 : "button-upper7", 72 : "button-upper8",
73 : "button-lower1", 74 : "button-lower2",
75 : "button-lower3", 76 : "button-lower4",
77 : "button-lower5", 78 : "button-lower6",
79 : "button-lower7", 80 : "button-lower8",
89 : "button-corner1", 90 : "button-corner2",
91 : "button-corner3", 92 : "button-corner4",
}
def __init__(self, dev="/dev/snd/midiC2D0"):
"""device was usually /dev/snd/midiC1D0 but then it showed up
once as C0D0. It should be autodetected"""
self.devPath = dev
self.dev = None
self.lastValue: Dict[str, int] = {} # control name : value
self.reopen()
self.packet = b""
loop = LoopingCall(self.poll)
loop.start(.01)
def poll(self):
try:
newData = self.dev.read(3)
except (IOError, AttributeError):
return
if newData is None:
return
self.packet += newData
if len(self.packet) == 3:
p = self.packet
self.packet = b""
self.packetReceived(p)
def packetReceived(self, packet):
b0, which, value = packet
if b0 != 0xb0:
return
if which in self.control:
name = self.control[which]
if name.startswith("button-"):
value = value > 0
self.lastValue[name] = value
self.valueIn(name, value)
else:
print("unknown control %s to %s" % (which, value))
def reopen(self):
if self.dev is not None:
try:
self.dev.close()
except IOError:
pass
self.lastValue.clear()
self.dev = open(self.devPath, "rb+", buffering=0)
twisted.internet.fdesc.setNonBlocking(self.dev)
def valueIn(self, name, value):
"""override this with your handler for when events come in
from the hardware"""
print("slider %s to %s" % (name, value))
if name == 'slider1':
for x in range(2, 8 + 1):
v2 = int(64 + 64 * math.sin(x / 3 + value / 10))
self.valueOut('slider%d' % x, v2)
for x in range(1, 8 + 1):
self.valueOut('button-upper%s' % x, value > x * 15)
self.valueOut('button-lower%s' % x, value > (x * 15 + 7))
def valueOut(self, name, value):
"""call this to send an event to the hardware"""
if self.dev is None:
return
value = int(value)
if self.lastValue.get(name) == value:
return
self.lastValue[name] = value
which = [k for k, v in list(self.control.items()) if v == name]
assert len(which) == 1, "unknown control name %r" % name
if name.startswith('button-'):
value = value * 127
#print "bcf: write %s %s" % (name, value)
self.dev.write(bytes([0xb0, which[0], int(value)]))
def close(self):
self.dev.close()
self.dev = None
if __name__ == '__main__':
b = BCF2000()
reactor.run()
|