dual socket bridge for puredata & python

a basic socket setup connecting the two via localhost. one quirk – i have trouble sending & receiving on the same socket in puredata (not even sure if that’s the normal way to do it). the quickest solution is to use two sockets, one for pd->py and another for pd<-py. bridge.py strips & reapplies the EOL ";" on messages. simply plug in a message handler and run the script. an empty message will trigger bridge.py to close, giving us a simple off switch in pd. default sockets are 8888:pd->py, 8889:pd<-py.

here's the python script:

import socket, sys

class Bridge:
    def __init__(self, port_l, port_s, handler=None):
        self.host = ‘localhost’
        self.port_l = port_l
        self.port_s = port_s
        if handler == None:
            self.handler = self._empty_handler
        else:
            self.handler = handler
        self.listener = self._create()
        self.speaker = self._create()
        self.limit = 1
        
    def _empty_handler(self, msg):
        print “   : message handler not defined”
        print “   : sending dummy reply”
        return “hello from python”
        
    def _create(self):
        try:
            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        except socket.error, e:
            print “failed to create socket”
            print “error code: %s” % str(e[0])
            print “message: %s” % str(e[1])
            sys.exit()
        return sock
        
    def _bind_listener(self):
        try:
            self.listener.bind((self.host, self.port_l))
        except socket.error, e:
            print “listener %s failed to bind” % self.port_l
            print “error code: %s” % str(e[0])
            print “message: %s” % str(e[1])
            sys.exit()
        print “   : listener active on port %s” % self.port_l
        
    def _connect_speaker(self):
        try:
            self.speaker.connect((self.host, self.port_s))
        except socket.error, e:
            print “speaker %s failed to connect” % self.port_s
            print “error code: %s” % str(e[0])
            print “message: %s” % str(e[1])
            sys.exit()
        print “   : speaker active on port %s” % self.port_s
        
    def listen(self):
        self._bind_listener()
        self._connect_speaker()
        self.listener.listen(self.limit)
        while 1:
            conn, addr = self.listener.accept()
            data = conn.recv(1024)[:-2]
            #print “   : incoming %s:%s” % (addr[0], addr[1])
            print “-> %s” % data
            if not data:
                print “   : empty message received”
                print “   : shutting down”
                break
            reply = self.handler(data)
            if reply:
                print “<- %s" % reply
                self.speaker.sendall("%s;" % reply)
        conn.close()
        self.listener.close()
        self.speaker.close()

if __name__ == "__main__":
    def test_handler(msg):
        reply = "msg ignored, hello from the python test handler"
        return reply
        
    test = Bridge(8888, 8889, test_handler)
    test.listen()
    sys.exit()

and here’s a tempory placeholder for the pd side (this will be expanded upon):

#N canvas 600 31 512 420 10;
#X msg 221 144 connect localhost 8888;
#X obj 182 201 netsend;
#X floatatom 269 239 5 0 0 0 status - -;
#X msg 182 182 disconnect;
#X obj 182 220 netreceive 8889;
#X obj 182 125 t b a b;
#X msg 182 106 hello from puredata;
#X obj 106 127 t b b;
#X msg 106 108 shut down;
#X obj 201 163 prepend send;
#X obj 182 239 t b a;
#X obj 209 258 prepend set;
#X obj 182 258 bng 15 50 10 0 empty empty empty 17 7 0 10 -262144 -1
-1;
#X msg 209 277;
#X connect 0 0 1 0;
#X connect 3 0 1 0;
#X connect 4 0 10 0;
#X connect 4 1 2 0;
#X connect 5 0 3 0;
#X connect 5 1 9 0;
#X connect 5 2 0 0;
#X connect 6 0 5 0;
#X connect 7 0 3 0;
#X connect 7 1 0 0;
#X connect 8 0 7 0;
#X connect 9 0 1 0;
#X connect 10 0 12 0;
#X connect 10 1 11 0;
#X connect 11 0 13 0;

run the script, send the test msg from pd, then the shut down msg:

D:\projects\py\mods> python bridge.py
   : listener active on port 8888
   : speaker active on port 8889
-> hello from puredata
<- msg ignored, hello from the python test handler
->
   : empty message received
   : shutting down

gratz

bjorklund.py

the bjorklund algorithm. here’s a paper on it’s relation to traditional rhythms across the world [91.2kb pdf].

def bjorklund(k, n, r=0):
    A_val = 1
    B_val = 0
    reverse = False
    if k < 0:
        k = abs(k)
        reverse = True
    if n <= 0:
        if n == 0:
            # lazy error handling
            return []
        n = abs(n)
        A_val = 0
        B_val = 1
    A = [[A_val]] * k
    B = [[B_val]] * (n-k)
    A_groups = len(A)
    least = min(A_groups, len(B))
    while least > 1:
        for x in xrange(least):
            A[x] = A[x] + B[x]
        if least == A_groups:
            B = B[least:]
        else:
            A, B = A[:least], A[least:]
        A_groups = len(A)
        least = min(A_groups, len(B))
    output = []
    for group in A:
        output = output + group
    for group in B:
        output = output + group
    if reverse:
        output.reverse()
    if r != 0:
        output = output[r:] + output[:r]
    return output

if __name__ == "__main__":
    import sys
    k, n, r = int(sys.argv[1]), int(sys.argv[2]), 0
    if len(sys.argv) > 3:
        r = int(sys.argv[3])
    print bjorklund(k, n, r)

it’s application extends beyond rhythms. for example, to generate the pattern of the western major key:

> python bjorklund.py 7 12 3
[1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1]