Changeset - c7478a778992
[Not reviewed]
default
0 1 1
Drew Perttula - 18 years ago 2007-06-10 07:41:48
drewp@bigasterisk.com
junky first pass at bcf2000 for keyboardcomposer
2 files changed with 138 insertions and 1 deletions:
0 comments (0 inline, 0 general)
bcf2000.py
Show inline comments
 
new file 100644
 
#!/usr/bin/python
 
from __future__ import division
 
import math
 
import twisted.internet.fdesc
 
from twisted.internet import reactor
 
from twisted.internet.task import LoopingCall
 

	
 
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/midiC1D0"):
 
        self.devPath = dev
 
        self.dev = None
 
        self.reopen()
 
        self.lastValue = {} # control name : value
 
        self.packet = ""
 
        loop = LoopingCall(self.poll)
 
        loop.start(.02)
 

	
 
    def poll(self):
 
        try:
 
            bytes = self.dev.read(3)
 
        except IOError, e:
 
            return
 
        if len(bytes) == 0:
 
            print "midi stall, reopen slider device"
 
            self.reopen()
 
            return
 
        self.packet += bytes
 
        if len(self.packet) == 3:
 
            p = self.packet
 
            self.packet = ""
 
            self.packetReceived(p)
 

	
 
        return
 
        
 
        while 1:
 
            packet = self.dev.read(3)
 
            while len(packet) < 3:
 
                if len(packet) == 0:
 
                    self.reopen()
 
                packet += self.dev.read(3 - len(packet))
 

	
 
    def packetReceived(self, packet):
 
        b0, which, value = [ord(b) for b in 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.dev = open(self.devPath, "r+")
 
        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"""
 
        value = int(value)
 
        if self.lastValue.get(name) == value:
 
            return
 
        self.lastValue[name] = value
 
        which = [k for k,v in self.control.items() if v == name]
 
        assert len(which) == 1, "unknown control name %r" % name
 
        if isinstance(value, bool):
 
            value = value * 127
 
        self.dev.write(chr(0xb0) + chr(which[0]) + chr(int(value)))
 
        
 

	
 
if __name__ == '__main__':
 
    b = BCF2000()
 
    reactor.run()
bin/keyboardcomposer
Show inline comments
 
@@ -16,6 +16,7 @@ from light9.Submaster import Submasters,
 
from light9.subclient import SubClient
 
from light9 import dmxclient, showconfig, networking
 
from light9.uihelpers import toplevelat, bindkeys
 
from bcf2000 import BCF2000
 

	
 
nudge_keys = {
 
    'up' : list('qwertyuiop'),
 
@@ -106,6 +107,9 @@ class KeyboardComposer(Frame, SubClient)
 
        self.sub_name = Entry(self.buttonframe, bg='black', fg='white')
 
        self.sub_name.pack(side=LEFT)
 
        self.stop_frequent_update_time = 0
 

	
 
        self.sliders = Sliders(self.hw_slider_moved)
 

	
 
    def make_key_hints(self):
 
        keyhintrow = Frame(self)
 

	
 
@@ -171,6 +175,11 @@ class KeyboardComposer(Frame, SubClient)
 
                subtk.scale.fade(0)
 
            else:
 
                subtk.scale.decrease()
 

	
 
    def hw_slider_moved(self, col, value):
 
        subtk = self.slider_table[(self.current_row, col)]
 
        subtk.scale.set(value)
 
                
 
    def draw_sliders(self):
 
        self.tk_focusFollowsMouse()
 

	
 
@@ -187,9 +196,12 @@ class KeyboardComposer(Frame, SubClient)
 
            col += 1
 
            col %= 10
 

	
 
            def slider_changed(x, y, z, subtk=subtk):
 
            def slider_changed(x, y, z, subtk=subtk, col=col, sub=sub):
 
                subtk.scale.draw_indicator_colors()
 
                self.send_levels()
 
                v = 127 * self.get_levels()[sub.name]
 
                self.sliders.valueOut("slider%s" % (col), v)
 
                    
 

	
 
            subtk.slider_var.trace('w', slider_changed)
 
    def make_row(self):
 
@@ -265,6 +277,15 @@ class LevelServer(xmlrpc.XMLRPC):
 
            ret=str(e)
 
        return ret
 

	
 
class Sliders(BCF2000):
 
    def __init__(self, cb):
 
        BCF2000.__init__(self)
 
        self.cb = cb
 
    def valueIn(self, name, value):
 
        print "in", name, value
 
        if name.startswith("slider"):
 
            self.cb(int(name[6:]) - 1, value / 127)
 

	
 
if __name__ == "__main__":
 
    parser = OptionParser()
 
    parser.add_option('--nonpersistent', action="store_true",
0 comments (0 inline, 0 general)