pyzmqとpyOSCでOSC over ZeroMQっぽいもの
普段はc++ばかりなのですが、少しだけpythonで書く必要ができました。
極力、普段と同じようにぬるく書きたいので、使い慣れたZeroMQとOSCを使えるようにしたいと思います。
2.テストプログラム
[2][3]のexamplesと[1]のpyOSCの実装を参考に、OSCMessageのbinaryをzeroMQを通して送受信するサンプルを書きたいと思います。
実装のポイント
OSCMessageをバイナリ形式で送受信することだけを考えます。
どの環境の、どのOSCの実装でもネットワーク上を飛び交うパケットは同じバイナリのはず、なので。
OSCMessageのバイナリを取得する方法は、普通に書くだけです。
送られてきたバイナリ形式のOSCMessageを、OSCMessageに戻すには(効率悪いですが、手を抜いて)
recv = decodeOSC(recv_binary)
で文字列や数値にデコードした結果を元に、
recv_osc = OSCMessage(recv[0])
recv_osc += recv[2:]
OSCMessageを作り直しているだけです。イベントハンドラ等は自分で好きに書いてください。
ソースコード
req.py
import zmq from OSC import decodeOSC, OSCMessage ctx = zmq.Context() sock = ctx.socket(zmq.REQ) sock.connect('tcp://127.0.0.1:5555') # Prepairing an OSCMessage msg = OSCMessage("/my/osc/address") msg.append('something') msg.insert(0, 'something else') msg[1] = 'entirely' msg.extend([1,2,3.]) msg += [4,5,6] del msg[3:6] msg.pop(-2) print 'send' print 'OSCMessage:\t', msg print 'OSCMessage(binary):\t', msg.getBinary() # Send the OSCMessage sock.send(msg.getBinary()) # Receive the echo recv_binary = sock.recv() print 'echo' print 'binary:\t', recv_binary recv = decodeOSC(recv_binary) print 'string:\t', recv recv_osc = OSCMessage(recv[0]) recv_osc += recv[2:] print 'OSCMessage:\t', recv_osc print 'OSCMessage(binary):\t', recv_osc.getBinary()
rep.py
import zmq from zmq.eventloop import ioloop from OSC import decodeOSC, OSCMessage loop = ioloop.IOLoop.instance() ctx = zmq.Context() sock = ctx.socket(zmq.REP) sock.bind('tcp://127.0.0.1:5555') def rep_handler(sock, events): # Receive an OSC packet osc_binary = sock.recv() print 'received' print 'binary:\t', osc_binary # Decode the binary to OSCMessage msg = decodeOSC(osc_binary) osc_msg = OSCMessage(msg[0]) osc_msg += msg[2:] print 'OSCMessage:\t', osc_msg # Reply the decoded OSCMessage sock.send(osc_msg.getBinary()) loop.add_handler(sock, rep_handler, zmq.POLLIN) loop.start()
実行結果
> E:\workspace\python\req.py
send
OSCMessage: /my/osc/address ['something else', 'entirely', 1, 6]
OSCMessage(binary): /my/osc/address ,ssii something else entirely
echo
binary: /my/osc/address ,ssii something else entirely
string: ['/my/osc/address', ',ssii', 'something else', 'entirely', 1, 6]
OSCMessage: /my/osc/address ['something else', 'entirely', 1, 6]
OSCMessage(binary): /my/osc/address ,ssii something else entirely
> E:\workspace\python\rep.py
received
binary: /my/osc/address ,ssii something else entirely
OSCMessage: /my/osc/address ['something else', 'entirely', 1, 6]
c++の実装と繋いでみる
cvl-robot.hateblo.jp
ここで昔書いたテストプログラムのpub,subと、pythonで書いたpub,subとを繋いでみます。
sub.py
import zmq from zmq.eventloop import ioloop from OSC import decodeOSC, OSCMessage loop = ioloop.IOLoop.instance() ctx = zmq.Context() sock = ctx.socket(zmq.SUB) sock.connect('tcp://127.0.0.1:5555') sock.setsockopt(zmq.SUBSCRIBE, '') def sub_handler(sock, events): # Receive an OSC packet osc_binary = sock.recv() print 'received' print 'binary:\t', osc_binary # Decode the binary to OSCMessage msg = decodeOSC(osc_binary) osc_msg = OSCMessage(msg[0]) osc_msg += msg[2:] print 'OSCMessage:\t', osc_msg loop.add_handler(sock, sub_handler, zmq.POLLIN) loop.start()
pub.py
import time import zmq from OSC import decodeOSC, OSCMessage ctx = zmq.Context() sock = ctx.socket(zmq.PUB) sock.bind('tcp://127.0.0.1:9999') # Prepairing an OSCMessage msg = OSCMessage("/my/osc/address") msg.append('something') msg.insert(0, 'something else') msg[1] = 'entirely' msg.extend([1,2,3.]) msg += [4,5,6] del msg[3:6] msg.pop(-2) print 'send' print 'OSCMessage:\t', msg print 'OSCMessage(binary):\t', msg.getBinary() # Send the OSCMessage time.sleep(1.0) sock.send(msg.getBinary())
c++の方も,送受信先のフィルタを
publisher->bind("tcp://*:5555");
subscriber->connect("tcp://127.0.0.1:9999");
適当に調整してください。
実行結果
received
binary: /mouse/button ,siii pressed $ [
OSCMessage: /mouse/button ['pressed', 548, 347, 2]
received
binary: /mouse/button ,siii pressed ( _
OSCMessage: /mouse/button ['pressed', 296, 351, 0]
received
binary: /mouse/button ,siii pressed \
OSCMessage: /mouse/button ['pressed', 260, 604, 0]
received
binary: /key/pressed ,i c
OSCMessage: /key/pressed [99]
received
binary: /key/pressed ,i v
OSCMessage: /key/pressed [118]
received
binary: /key/pressed ,i l
OSCMessage: /key/pressed [108]
Received: /my/osc/address something else entirely 1 6
Received: /my/osc/address something else entirely 1 6
問題なく動きますね。
[1] pythonでOSC Messageのデコード
https://github.com/ptone/pyosc/blob/master/OSC.py
[2] pyzmqのreq,repのexample
zmq の python binding で echo テスト - Twisted Mind
[3] pyOSCのexample
pyosc/examples at master · ptone/pyosc · GitHub
[4] pyzmqのpub, subのexample
pyzmqでZeroMQを触ってみる (PUB/SUB) - YAMAGUCHI::weblog
[5] int64を送受信したいとき
pyOSCでint64が受け取れなくてはまったメモ - Qiita