python-txosc-0.2.0/0000755000000000000000000000000011445141517012671 5ustar rootrootpython-txosc-0.2.0/setup.py0000644000000000000000000000373311445141512014404 0ustar rootroot#!/usr/bin/env python """ txosc installation script """ from setuptools import setup import os import sys import subprocess import txosc from twisted.python import procutils setup( name = "txosc", version = txosc.__version__, author = "Arjan Scherpenisse and Alexandre Quessy", author_email = "txosc@toonloop.com", url = "http://bitbucket.org/arjan/txosc", description = "Open Sound Control Protocol for Twisted", scripts = [ "scripts/osc-receive", "scripts/osc-send" ], license="MIT/X", packages = ["txosc", "txosc/test"], long_description = """Open Sound Control (OSC) is an open, transport-independent, message-based protocol developed for communication among computers, sound synthesizers, and other multimedia devices. This library implements OSC version 1.1 over both UDP and TCP for the Twisted Python framework. """, classifiers = [ "Framework :: Twisted", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Programming Language :: Python", "Topic :: Communications", "Topic :: Software Development :: Libraries :: Python Modules", "Topic :: Utilities" ] ) if sys.argv[1] == "build": commands = [ 'help2man --no-info --include=man-osc-send.txt --no-discard-stderr --name="sends an OSC message" ./scripts/osc-send --output=osc-send.1', 'help2man --no-info --include=man-osc-receive.txt --no-discard-stderr --name="receives OSC messages" ./scripts/osc-receive --output=osc-receive.1', ] if os.path.exists("man-osc-send.txt"): try: help2man = procutils.which("help2man")[0] except IndexError: print("Cannot build the man pages. help2man was not found.") else: for c in commands: print("$ %s" % (c)) retcode = subprocess.call(c, shell=True) print("The help2man command returned %s" % (retcode)) python-txosc-0.2.0/scripts/0000755000000000000000000000000011445141512014353 5ustar rootrootpython-txosc-0.2.0/scripts/osc-receive0000755000000000000000000000474511445141512016517 0ustar rootroot#!/usr/bin/env python # Copyright (c) 2009 Alexandre Quessy, Arjan Scherpenisse # See LICENSE for details. """ OSC receiver made with txosc """ import sys import optparse from twisted.internet import reactor import txosc # for __version__ from txosc import osc from txosc import dispatch from txosc import async VERBOSE = False def verb(txt): """ Prints a message if in verbose mode. """ global VERBOSE if VERBOSE: print(txt) def fallback(message, address): """ Fallback for any unhandled message """ print("%s from %s" % (message, address)) def _exit(txt): print(txt) sys.exit(1) class OscDumper(object): """ Prints OSC messages it receives. """ def __init__(self, protocol, port, multicast_group=None): self.receiver = dispatch.Receiver() if protocol == "UDP": if multicast_group is not None: self._server_port = reactor.listenMulticast(port, async.MulticastDatagramServerProtocol(self.receiver, multicast_group), listenMultiple=True) else: self._server_port = reactor.listenUDP(port, async.DatagramServerProtocol(self.receiver)) else: self._server_port = reactor.listenTCP(port, async.ServerFactory(self.receiver)) host = "localhost" if multicast_group is not None: host = multicast_group print("Listening on osc.%s://%s:%s" % (protocol.lower(), host, port)) # fallback: self.receiver.setFallback(fallback) if __name__ == "__main__": parser = optparse.OptionParser(usage="%prog", version=txosc.__version__.strip(), description=__doc__) parser.add_option("-p", "--port", type="int", default=31337, help="Port to listen on") parser.add_option("-g", "--multicast-group", type="string", help="Multicast group to listen on") parser.add_option("-v", "--verbose", action="store_true", help="Makes the output verbose") parser.add_option("-T", "--tcp", action="store_true", help="Uses TCP instead of UDP") (options, args) = parser.parse_args() app = None protocol = "UDP" multicast_group = None if options.tcp: protocol = "TCP" if options.multicast_group: if protocol != "UDP": _exit("Multicast groups are only supported with UDP.") else: multicast_group = options.multicast_group def _later(): app = OscDumper(protocol, options.port, multicast_group) reactor.callLater(0.01, _later) reactor.run() python-txosc-0.2.0/scripts/osc-send0000755000000000000000000002041311445141512016014 0ustar rootroot#!/usr/bin/env python # Copyright (c) 2009 Alexandre Quessy, Arjan Scherpenisse # See LICENSE for details. """ Sends OSC messages using txosc """ import exceptions import sys import optparse from twisted.internet import reactor import txosc # for __version__ from txosc import osc from txosc import dispatch from txosc import async from txosc import sync VERBOSE = False QUIET = False RETURN_VALUE = 0 def send_async_udp(message, port, host): """ Sends a message using UDP and stops the Reactor @param message: OSC message @type message: L{txosc.osc.Message} @type port: C{int} @type host: C{str} """ client = async.DatagramClientProtocol() _client_port = reactor.listenUDP(0, client) def actually_send_it(): # verb("Sending %s to %s:%d" % (message, host, port)) client.send(message, (host, port)) verb("Sent %s to %s:%d" % (message, host, port)) reactor.callLater(0.001, reactor.stop) reactor.callLater(0, actually_send_it) def send_sync_tcp(message, port, host): try: tcp_sender = sync.TcpSender(host, port) except socket.error, e: print(str(e)) else: tcp_sender.send(message) tcp_sender.close() verb("Sent %s to %s:%d" % (message, host, port)) def send_sync_udp(message, port, host): try: udp_sender = sync.UdpSender(host, port) except socket.error, e: print(str(e)) else: udp_sender.send(message) udp_sender.close() verb("Sent %s to %s:%d" % (message, host, port)) def send_async_tcp(message, port, host): """ Not yet implemented. """ client = async.ClientFactory() _client_port = None def _callback(result): verb("Connected.") client.send(message) verb("Sent %s to %s:%d" % (message, host, port)) reactor.callLater(0.001, reactor.stop) def _errback(reason): print("An error occurred: %s" % (reason.getErrorMessage())) _client_port = reactor.connectTCP(host, port, client) client.deferred.addCallback(_callback) client.deferred.addErrback(_errback) def create_message_auto(path, *args): """ Trying to guess the type tags. """ message = osc.Message(path) for arg in args: try: value = int(arg) except ValueError: try: value = float(arg) except ValueError: value = str(arg) message.add(value) return message def create_message_manually(path, types, *args): """ The used specified the type tags. """ def _exit_with_error(message): global RETURN_VALUE if reactor.running: reactor.stop() print(message) RETURN_VALUE = 1 # error if len(types) != len(args): _exit_with_error("The length of the type string must match the number of arguments.") return message = osc.Message(path) try: for value, typetag in zip(args, types): verb("Creating argument for %s with type tag %s" % (value, typetag)) cast = str if typetag == "i": cast = int elif typetag == "f": cast = float elif typetag in ["T", "F"]: cast = None elif typetag == "t": cast = None elif typetag == "N": cast = None elif typetag == "I": cast = None elif typetag == "": cast = None if cast is not None: try: casted = cast(value) except ValueError, e: _exit_with_error("Error converting an argument to type tag" + str(e)) return else: casted = value arg = osc.createArgument(casted, typetag) verb("Adding argument %s." % (arg)) message.add(arg) except osc.OscError, e: _exit_with_error(str(e)) return None return message def verb(txt): """ Prints a message if in verbose mode. """ global VERBOSE if VERBOSE: print(txt) class Config(object): def __init__(self): self.path = "/" self.host = "127.0.0.1" self.port = 31337 self.protocol = "UDP" self.type_tags = "" self.using_twisted = False if __name__ == "__main__": parser = optparse.OptionParser(usage="%prog [url] / [type tags] [arguments values]", version=txosc.__version__.strip(), description=__doc__) parser.add_option("-p", "--port", type="int", default=31337, help="Port to send to") parser.add_option("-H", "--host", type="string", default="127.0.0.1", help="IP address to send to") parser.add_option("-t", "--type-tags", type="string", help="Type tags as many letters concatenated") parser.add_option("-v", "--verbose", action="store_true", help="Makes the output verbose") parser.add_option("-T", "--tcp", action="store_true", help="Uses TCP instead of UDP") parser.add_option("-x", "--enable-twisted", action="store_true", help="Uses Twisted instead of blocking sockets") (options, args) = parser.parse_args() def _exit(txt): """ Exits right aways - The Twisted reactor must not be running """ print(txt) sys.exit(1) if len(args) == 0: _exit("You must specify an OSC path to send to") config = Config() config.path = None config.host = options.host config.port = options.port config.protocol = "UDP" config.type_tags = options.type_tags type_tag_arg_index = 1 args_index = 1 url = None if options.verbose: VERBOSE = True if options.enable_twisted: config.using_twisted = True verb("Using Twisted") else: verb("Using blocking socket networking") if options.tcp: config.protocol = "TCP" if args[0].startswith("/"): config.path = args[0] elif args[0].startswith("osc."): type_tag_arg_index += 1 args_index += 1 if len(args) == 1: _exit("You must specify an OSC path to send to") else: if args[1].startswith("/"): config.path = args[1] url = args[0] if url.startswith("osc.udp://"): config.protocol = "UDP" elif url.startswith("osc.tcp://"): config.protocol = "TCP" else: _exit("The URL must start with either osc.udp or osc.tcp") try: config.host = url.split("/")[2].split(":")[0] config.port = int(url.split(":")[2]) except IndexError, e: _exit(str(e)) except ValueError, e: _exit(str(e)) if len(args) > type_tag_arg_index: if args[type_tag_arg_index].startswith(","): config.type_tags = args[type_tag_arg_index][1:] args_index += 1 if config.path is None: _exit("You must specify an OSC path") # verb("protocol: %s" % (protocol)) # verb("host: %s" % (host)) # verb("port: %s" % (port)) # verb("path: %s" % (path)) # verb("type_tags: %s" % (type_tags)) # verb("type_tag_arg_index: %s" % (type_tag_arg_index)) # verb("args_index: %s" % (args_index)) def _later(): # verb("Sending to osc.%s://%s:%d" % (protocol.lower(), host, port)) if config.type_tags: message = create_message_manually(config.path, config.type_tags, *args[args_index:]) else: message = create_message_auto(config.path, *args[args_index:]) if config.using_twisted: if config.protocol == 'UDP': send_async_udp(message, config.port, config.host) else: send_async_tcp(message, config.port, config.host) else: if config.protocol == 'UDP': send_sync_udp(message, config.port, config.host) else: send_sync_tcp(message, config.port, config.host) if config.using_twisted: reactor.callLater(0.001, _later) # verb("Starting the Twisted reactor") try: reactor.run() except exceptions.SystemExit: pass else: _later() sys.exit(RETURN_VALUE) python-txosc-0.2.0/man-osc-receive.txt0000644000000000000000000000016411445141512016403 0ustar rootroot[SYNOPSIS] osc-receive [options] --port=port [HISTORY] Written by Arjan Scherpenisse and Alexandre Quessy in 2010. python-txosc-0.2.0/examples/0000755000000000000000000000000011445141512014502 5ustar rootrootpython-txosc-0.2.0/examples/pd_sender.pd0000644000000000000000000000165611445141512017002 0ustar rootroot#N canvas 309 105 461 481 10; #X text 24 13 Open this file with Pure Data. See www.puredata.info ; #X text 25 29 This example patch uses Pure Data's sendOSC external object.; #X text 238 127 Click on those to send OSC messages; #X obj 69 406 sendOSC; #X floatatom 69 433 5 0 0 0 - - -; #X msg 29 120 disconnect; #X msg 230 315 [; #X msg 230 342 ]; #X floatatom 123 435 5 0 0 0 - - -; #X text 172 438 bundleDepth; #X text 269 312 open / close bundles here.; #X msg 234 231 send /; #X msg 238 181 send /ham/egg pig 6; #X msg 236 156 send /ping 3.14159; #X msg 17 95 connect localhost 17779; #X obj 17 69 loadbang; #X msg 236 207 send /a/b/c/d/e xxxxx 2; #X msg 234 258 send /cheese/cheddar brie; #X connect 3 0 4 0; #X connect 3 1 8 0; #X connect 5 0 3 0; #X connect 6 0 3 0; #X connect 7 0 3 0; #X connect 11 0 3 0; #X connect 12 0 3 0; #X connect 13 0 3 0; #X connect 14 0 3 0; #X connect 15 0 14 0; #X connect 16 0 3 0; #X connect 17 0 3 0; python-txosc-0.2.0/examples/sync_udp_sender.py0000755000000000000000000000114511445141512020244 0ustar rootroot#!/usr/bin/env python """ Example of a TCP txosc sender without Twisted. This example is in the public domain. """ #FIXME: The txosc.sync.UdpSender is currently broken! import socket # only for the exception type from txosc import osc from txosc import sync if __name__ == "__main__": try: udp_sender = sync.UdpSender("localhost", 31337) except socket.error, e: print(str(e)) else: udp_sender.send(osc.Message("/hello", 2, "bar", 3.14159)) udp_sender.send(osc.Message("/ham/spam", "egg")) udp_sender.close() print("Successfully sent the messages.") python-txosc-0.2.0/examples/async_udp_sender.py0000755000000000000000000000270711445141512020412 0ustar rootroot#!/usr/bin/env python """ Example of a UDP txosc sender with Twisted. This example is in the public domain. """ from twisted.internet import reactor from txosc import osc from txosc import dispatch from txosc import async class UDPSenderApplication(object): """ Example that sends UDP messages. """ def __init__(self, port, host="127.0.0.1"): self.port = port self.host = host self.client = async.DatagramClientProtocol() self._client_port = reactor.listenUDP(0, self.client) reactor.callLater(0, self.send_messages) def _send(self, element): # This method is defined only to simplify the example self.client.send(element, (self.host, self.port)) print("Sent %s to %s:%d" % (element, self.host, self.port)) def send_messages(self): self._send(osc.Message("/ping")) self._send(osc.Message("/foo")) self._send(osc.Message("/ham/egg"))#, 3.14159)) self._send(osc.Message("/spam", "hello", 1)) self._send(osc.Message("/bacon", osc.TimeTagArgument())) self._send(osc.Message("/cheese")) self._send(osc.Message("/cheese/cheddar")) # of course, the /quit message has to be sent last! self._send(osc.Message("/quit")) print("Goodbye.") def _stop(): reactor.stop() reactor.callLater(0.1, _stop) if __name__ == "__main__": app = UDPSenderApplication(17779) reactor.run() python-txosc-0.2.0/examples/ping_pong.py0000755000000000000000000000506211445141512017042 0ustar rootroot#!/usr/bin/env python """ Example of a UDP txosc sender and receiver with Twisted. This example is in the public domain. Written by Alexandre Quessy in 2010. Usage: Start this script in a shell. Start it again with any argument in an other shell on the same computer. """ import sys from twisted.internet import reactor from txosc import osc from txosc import dispatch from txosc import async class PingPongApplication(object): """ Example that sends and receives UDP OSC messages. """ def __init__(self, is_initiator=True): self.delay = 1.0 self.send_host = "127.0.0.1" self.send_port = 17777 self.receive_port = 16666 if is_initiator: self.send_port = 16666 self.receive_port = 17777 self.receiver = dispatch.Receiver() self.sender = async.DatagramClientProtocol() self._sender_port = reactor.listenUDP(0, self.sender) self._server_port = reactor.listenUDP(self.receive_port, async.DatagramServerProtocol(self.receiver)) print("Listening on osc.udp://localhost:%s" % (self.receive_port)) self.receiver.addCallback("/ping", self.ping_handler) self.receiver.addCallback("/pong", self.pong_handler) self.receiver.fallback = self.fallback if is_initiator: reactor.callLater(0.1, self._start) def _start(self): """ Initiates the ping pong game. """ self._send_ping() def ping_handler(self, message, address): """ Method handler for /ping """ print("Got %s from %s" % (message, address)) reactor.callLater(self.delay, self._send_pong) def pong_handler(self, message, address): """ Method handler for /pong """ print("Got %s from %s" % (message, address)) reactor.callLater(self.delay, self._send_ping) def _send_ping(self): """ Sends /ping """ self.sender.send(osc.Message("/ping"), (self.send_host, self.send_port)) print("Sent /ping") def _send_pong(self): """ Sends /pong """ self.sender.send(osc.Message("/pong"), (self.send_host, self.send_port)) print("Sent /pong") def fallback(self, message, address): """ Fallback for everything else we get. """ print("Lost ball %s from %s" % (message, address)) if __name__ == "__main__": is_initiator = False if len(sys.argv) > 1: is_initiator = True app = PingPongApplication(is_initiator) reactor.run() python-txosc-0.2.0/examples/async_udp_receiver.py0000755000000000000000000000614211445141512020733 0ustar rootroot#!/usr/bin/env python """ Example of a UDP txosc receiver with Twisted. This example is in the public domain. """ from twisted.internet import reactor from txosc import osc from txosc import dispatch from txosc import async def foo_handler(message, address): """ Function handler for /foo """ print("foo_handler") print(" Got %s from %s" % (message, address)) class UDPReceiverApplication(object): """ Example that receives UDP OSC messages. """ def __init__(self, port): self.port = port self.receiver = dispatch.Receiver() self._server_port = reactor.listenUDP(self.port, async.DatagramServerProtocol(self.receiver)) print("Listening on osc.udp://localhost:%s" % (self.port)) self.receiver.addCallback("/foo", foo_handler) self.receiver.addCallback("/ping", self.ping_handler) self.receiver.addCallback("/quit", self.quit_handler) self.receiver.addCallback("/ham/egg", self.ham_egg_handler) self.receiver.addCallback("/*/egg", self.any_egg_handler) # Now, let's demonstrate how to use address nodes: # /cheese: self.cheese_node = dispatch.AddressNode("cheese") self.cheese_node.addCallback("*", self.cheese_handler) self.receiver.addNode("cheese", self.cheese_node) # /cheese/cheddar: self.cheddar_node = dispatch.AddressNode("cheddar") self.cheddar_node.addCallback("*", self.cheese_cheddar_handler) self.cheese_node.addNode("cheddar", self.cheddar_node) # fallback: self.receiver.fallback = self.fallback def cheese_handler(self, message, address): """ Method handler for /ping """ print("cheese_handler") print(" Got %s from %s" % (message, address)) def cheese_cheddar_handler(self, message, address): """ Method handler for /cheese/cheddar """ print("cheese_cheddar_handler") print(" Got %s from %s" % (message, address)) def any_egg_handler(self, message, address): """ Method handler for /*/egg """ print("any_egg_handler") print(" Got %s from %s" % (message, address)) def fallback(self, message, address): """ Fallback for any unhandled message """ print("Fallback:") print(" Got %s from %s" % (message, address)) def ping_handler(self, message, address): """ Method handler for /ping """ print("ping_handler") print(" Got %s from %s" % (message, address)) def ham_egg_handler(self, message, address): """ Method handler for /ham/egg """ print("ham_egg_handler") print(" Got %s from %s" % (message, address)) def quit_handler(self, message, address): """ Method handler for /quit Quits the application. """ print("quit_handler") print(" Got %s from %s" % (message, address)) reactor.stop() print("Goodbye.") if __name__ == "__main__": app = UDPReceiverApplication(17779) reactor.run() python-txosc-0.2.0/examples/async_tcp_sender.py0000755000000000000000000000252311445141512020404 0ustar rootroot#!/usr/bin/env python """ Example of a TCP txosc sender with Twisted. This example is in the public domain. """ from twisted.internet import reactor from txosc import osc from txosc import dispatch from txosc import async class TCPSenderApplication(object): """ Example that sends UDP messages. """ def __init__(self, port, host="127.0.0.1"): self.port = port self.host = host self.client = async.ClientFactory() self._client_port = None def _callback(result): print("Connected.") self.send_messages() def _errback(reason): print("An error occurred: %s" % (reason.getErrorMessage())) self._client_port = reactor.connectTCP(self.host, self.port, self.client) self.client.deferred.addCallback(_callback) self.client.deferred.addErrback(_errback) def _send(self, element): self.client.send(element) print("Sent %s to %s:%d" % (element, self.host, self.port)) def send_messages(self): self._send(osc.Message("/ping")) self._send(osc.Message("/foo")) self._send(osc.Message("/quit")) reactor.callLater(0.1, self.quit) def quit(self): reactor.stop() print("Goodbye.") if __name__ == "__main__": app = TCPSenderApplication(17779) reactor.run() python-txosc-0.2.0/examples/async_multicast_sender.py0000755000000000000000000000211511445141512021620 0ustar rootroot#!/usr/bin/env python """ Example of a UDP txosc sender with Twisted. This example is in the public domain. """ from twisted.internet import reactor from txosc import osc from txosc import dispatch from txosc import async class UDPSenderApplication(object): """ Example that sends UDP messages. """ def __init__(self, port, host="224.0.0.1"): self.port = port self.host = host self.client = async.DatagramClientProtocol() self._client_port = reactor.listenUDP(0, self.client) reactor.callLater(0, self.send_messages) def _send(self, element): # This method is defined only to simplify the example self.client.send(element, (self.host, self.port)) print("Sent %s to %s:%d" % (element, self.host, self.port)) def send_messages(self): self._send(osc.Message("/spam", "How are you?", 3.14159, True)) print("Goodbye.") def _stop(): reactor.stop() reactor.callLater(0.1, _stop) if __name__ == "__main__": app = UDPSenderApplication(18888) reactor.run() python-txosc-0.2.0/examples/async_multicast_receiver.py0000755000000000000000000000205211445141512022144 0ustar rootroot#!/usr/bin/env python """ Example of a multicast UDP txosc receiver with Twisted. You can run many of these on a single host. This example is in the public domain. """ from twisted.internet import reactor from txosc import osc from txosc import dispatch from txosc import async class MulticastUDPReceiverApplication(object): """ Example that receives multicast UDP OSC messages. """ def __init__(self, port): self.port = port self.receiver = dispatch.Receiver() self._server_port = reactor.listenMulticast(self.port, async.MulticastDatagramServerProtocol(self.receiver, "224.0.0.1"), listenMultiple=True) print("Listening on osc.udp://224.0.0.1:%s" % (self.port)) self.receiver.addCallback("/spam", self.spam_handler) def spam_handler(self, message, address): """ Method handler for /spam """ print("spam_handler") print(" Got %s from %s" % (message, address)) if __name__ == "__main__": app = MulticastUDPReceiverApplication(18888) reactor.run() python-txosc-0.2.0/examples/sync_tcp_sender.py0000755000000000000000000000105611445141512020243 0ustar rootroot#!/usr/bin/env python """ Example of a TCP txosc sender without Twisted. This example is in the public domain. """ import socket # only for the exception type from txosc import osc from txosc import sync if __name__ == "__main__": try: tcp_sender = sync.TcpSender("localhost", 31337) except socket.error, e: print(str(e)) else: tcp_sender.send(osc.Message("/hello", 2, "bar", 3.14159)) tcp_sender.send(osc.Message("/ham/spam", "egg")) tcp_sender.close() print("Successfully sent the messages.") python-txosc-0.2.0/examples/async_tcp_receiver.py0000755000000000000000000000270411445141512020731 0ustar rootroot#!/usr/bin/env python """ Example of a TCP txosc receiver with Twisted. This example is in the public domain. """ from twisted.internet import reactor from txosc import osc from txosc import dispatch from txosc import async def foo_handler(message, address): """ Single function handler. """ print("Got %s from %s" % (message, address)) class TCPReceiverApplication(object): """ Example that receives UDP OSC messages. """ def __init__(self, port): self.port = port self.receiver = dispatch.Receiver() self.receiver.addCallback("/foo", foo_handler) self.receiver.addCallback("/ping", self.ping_handler) self.receiver.addCallback("/quit", self.quit_handler) self.receiver.setFallback(self.fallback) self._server_port = reactor.listenTCP(self.port, async.ServerFactory(self.receiver)) print("Listening on osc.tcp://127.0.0.1:%s" % (self.port)) def ping_handler(self, message, address): """ Method handler. """ print("Got %s from %s" % (message, address)) def quit_handler(self, message, address): """ Quits the application. """ print("Got %s from %s" % (message, address)) reactor.stop() print("Goodbye.") def fallback(self, message, address): print("Got %s from %s" % (message, address)) if __name__ == "__main__": app = TCPReceiverApplication(17779) reactor.run() python-txosc-0.2.0/NEWS0000644000000000000000000000503011445141512013361 0ustar rootroot2010-09-15: txosc Release 0.2.0 This release of txosc is the first in the 0.2 stable branch. Its features and API will not change throughout the 0.2 series. Bugs fixed: * #12: Translate host names into IP addresses. * #27: removeAllCallbacks() set _childNodes as empty list, not dict. * #25: The blocking senders now packs messages with empty bytes. 2010-08-17: Release 0.1.6 This release provides an synchronous implementation that allows developers to use txosc in applications that do not use Twisted, just blocking socket network programming in Python. It also provides two new types of arguments: ColorArgument and MidiArgument. * sync: Added support for non-Twisted sending in txosc/sync.py * sync: Added the sync_tcp_sender example. * sync: Fixed the synchronous sender binary format. * sync: Catching socket errors in sync_tcp_sender * osc-send: Implemented sending using blocking socket. * osc-send: Now uses the blocking implementation by default. * osc: Improved doc for ColorArgument * osc: Improved doc for MidiArgument 2010-07-19: Release 0.1.5 * Implemented the MidiArgument class * Implemented the ColorArgument class * osc-send: validating arguments and returning 1 in case of error * osc-send: now requires a path 2010-06-30: Release 0.1.4 * Added the osc-send script, which support UDP and TCP * Added the osc-receive script, which support UDP, TCP and multicast UDP * Removed the "beta" classifier in setup.py * Created man pages for osc-send and osc-receive * Implemented OSC URL parsing in osc-send * Added txosc.osc.Argument._check_type, which does the type checking at instanciation time 2010-06-28: Release 0.1.3 * Added the txosc.osc.Message.getValues method * Added the txosc.osc.getAddressParts function * Added __float__ and __int__ cast operators to some subclasses of txosc.osc.Argument * Added some classifiers to setup.py * Renamed TxOSC for txosc, lowercase 2010-06-16: Release 0.1.2 * Fixed #5 Create a multicast group listener 2010-06-09: Release 0.1.1 * Improved examples * Fixed #1 Second argument to handlers in TCP should provide easily an OSC address 2010-06-08: Release 0.1.0 * First official release * This is the birth of the txosc library! 2010-06-07: Stripped into txosc by Alexandre Quessy * A self-contained Pure Python library for OSC was needed 2009-12-29: Started to be written by Arjan Scherpenisse and Alexandre Quessy * It was first aimed to be part of Twisted python-txosc-0.2.0/LICENSE0000644000000000000000000000207411445141512013674 0ustar rootrootCopyright (c) 2009-2010 Arjan Scherpenisse Alexandre Quessy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. python-txosc-0.2.0/RELEASE0000644000000000000000000000056411445141512013674 0ustar rootroot2010-09-15: txosc Release 0.2.0 This release of txosc is the first in the 0.2 stable branch. Its features and API will not change throughout the 0.2 series. Bugs fixed: * #12: Translate host names into IP addresses. * #27: removeAllCallbacks() set _childNodes as empty list, not dict. * #25: The blocking senders now packs messages with empty bytes. python-txosc-0.2.0/INSTALL0000644000000000000000000000117611445141512013722 0ustar rootrootRequirements ============ * Twisted 8.1.0 or later * help2man for building the man pages of osc-send and osc-receive Installation ============ * Debian and Ubuntu Packages will soon be included in the main distribution. * Other As with other Python packages, the standard way of installing from source is: python setup.py install Building the documentation ========================== You can build the HTML documentation using a tool such as Epydoc:: $ epydoc --html --output html --url \ http://bitbucket.org/arjan/txosc/ --name txosc --verbose \ --simple-term --css white txosc python-txosc-0.2.0/txosc/0000755000000000000000000000000011445141512014024 5ustar rootrootpython-txosc-0.2.0/txosc/test/0000755000000000000000000000000011445141512015003 5ustar rootrootpython-txosc-0.2.0/txosc/test/test_osc.py0000644000000000000000000003221411445141512017202 0ustar rootroot# Copyright (c) 2009 Alexandre Quessy, Arjan Scherpenisse # See LICENSE for details. """ Tests for txosc/osc.py Maintainer: Arjan Scherpenisse """ from twisted.trial import unittest from twisted.internet import reactor, defer, task from txosc import osc from txosc import async from txosc import dispatch class TestGetAddressParts(unittest.TestCase): """ Test the getAddressParts function. """ def testGetAddressParts(self): addresses = { "/foo": ["foo"], "/foo/bar": ["foo", "bar"], "/foo/bar/ham": ["foo", "bar", "ham"], "/egg/[1-2]": ["egg", "[1-2]"], "/egg/*": ["egg", "*"], "/egg/?": ["egg", "?"], } for k, v in addresses.iteritems(): self.failUnlessEqual(osc.getAddressParts(k), v) class TestArgumentCreation(unittest.TestCase): """ Test the L{osc.CreateArgument} function. """ def testCreateFromValue(self): self.assertEquals(type(osc.createArgument(True)), osc.BooleanArgument) self.assertEquals(type(osc.createArgument(False)), osc.BooleanArgument) self.assertEquals(type(osc.createArgument(None)), osc.NullArgument) self.assertEquals(type(osc.createArgument(123)), osc.IntArgument) self.assertEquals(type(osc.createArgument(3.14156)), osc.FloatArgument) # Unicode is not supported. self.assertRaises(osc.OscError, osc.createArgument, u'test') def testCreateFromTypeTag(self): self.assertEquals(type(osc.createArgument(123, "T")), osc.BooleanArgument) self.assertEquals(type(osc.createArgument(123, "F")), osc.BooleanArgument) self.assertEquals(type(osc.createArgument(123, "N")), osc.NullArgument) self.assertEquals(type(osc.createArgument(123, "I")), osc.ImpulseArgument) self.assertEquals(type(osc.createArgument(123, "i")), osc.IntArgument) self.assertEquals(type(osc.createArgument(123, "f")), osc.FloatArgument) self.assertRaises(osc.OscError, osc.createArgument, 123, "?") class TestArgument(unittest.TestCase): """ Encoding and decoding of a string argument. """ def testAbstractArgument(self): a = osc.Argument(None) self.assertRaises(NotImplementedError, a.toBinary) self.assertRaises(NotImplementedError, a.fromBinary, "") class TestBlobArgument(unittest.TestCase): """ Encoding and decoding of a string argument. """ def testToBinary(self): self.assertEquals(osc.BlobArgument("").toBinary(), "\0\0\0\0\0\0\0\0") self.assertEquals(osc.BlobArgument("a").toBinary(), "\0\0\0\1a\0\0\0") self.assertEquals(osc.BlobArgument("hi").toBinary(), "\0\0\0\2hi\0\0") self.assertEquals(osc.BlobArgument("hello").toBinary(), "\0\0\0\5hello\0\0\0") def testFromBinary(self): data = "\0\0\0\2hi\0\0\0\0\0\5hello\0\0\0" first, leftover = osc.BlobArgument.fromBinary(data) self.assertEquals(first.value, "hi") self.assertEquals(leftover, "\0\0\0\5hello\0\0\0") second, leftover = osc.BlobArgument.fromBinary(leftover) self.assertEquals(second.value, "hello") self.assertEquals(leftover, "") # invalid formatted self.assertRaises(osc.OscError, osc.BlobArgument.fromBinary, "\0\0\0") # invalid length packet self.assertRaises(osc.OscError, osc.BlobArgument.fromBinary, "\0\0\0\99") class TestStringArgument(unittest.TestCase): """ Encoding and decoding of a string argument. """ def testToBinary(self): self.assertEquals(osc.StringArgument("").toBinary(), "\0\0\0\0") self.assertEquals(osc.StringArgument("OSC").toBinary(), "OSC\0") self.assertEquals(osc.StringArgument("Hello").toBinary(), "Hello\0\0\0") def testFromBinary(self): data = "aaa\0bb\0\0c\0\0\0dddd" first, leftover = osc.StringArgument.fromBinary(data) #padding with 0 to make strings length multiples of 4 chars self.assertEquals(first.value, "aaa") self.assertEquals(leftover, "bb\0\0c\0\0\0dddd") second, leftover = osc.StringArgument.fromBinary(leftover) self.assertEquals(second.value, "bb") self.assertEquals(leftover, "c\0\0\0dddd") third, leftover = osc.StringArgument.fromBinary(leftover) self.assertEquals(third.value, "c") self.assertEquals(leftover, "dddd") class TestFloatArgument(unittest.TestCase): def testToAndFromBinary(self): binary = osc.FloatArgument(3.14159).toBinary() float_arg = osc.FloatArgument.fromBinary(binary)[0] #FIXME: how should we compare floats? use decimal? if float_arg.value < 3.1415: self.fail("value is too small") if float_arg.value > 3.1416: self.fail("value is too big") self.assertRaises(osc.OscError, osc.FloatArgument.fromBinary, "\0\0\0") # invalid value def testCasting(self): # we should be able to cast the argument to float to get its float value value = 3.14159 float_arg = osc.FloatArgument(value) if float(float_arg) < 3.1415: self.fail("value is too small") if float(float_arg) > 3.1416: self.fail("value is too big") class TestIntArgument(unittest.TestCase): def testToAndFromBinary(self): def test(value): int_arg = osc.IntArgument.fromBinary(osc.IntArgument(value).toBinary())[0] self.assertEquals(int_arg.value, value) test(0) test(1) test(-1) test(1<<31-1) test(-1<<31) self.assertRaises(osc.OscError, osc.IntArgument.fromBinary, "\0\0\0") # invalid value def testIntOverflow(self): self.assertRaises(OverflowError, osc.IntArgument(1<<31).toBinary) self.assertRaises(OverflowError, osc.IntArgument((-1<<31) - 1).toBinary) class TestColorArgument(unittest.TestCase): def testToAndFromBinary(self): def _test(value): color_arg = osc.ColorArgument.fromBinary(osc.ColorArgument(value).toBinary())[0] self.assertEquals(color_arg.value, value) _test((255, 255, 255, 255)) _test((0, 0, 0, 0)) self.assertRaises(osc.OscError, osc.ColorArgument.fromBinary, "\0\0\0") # invalid value self.assertRaises(TypeError, osc.ColorArgument.toBinary, (-244, 0, 0, 0)) # invalid value self.assertRaises(TypeError, osc.ColorArgument.toBinary, ()) # invalid value class TestMidiArgument(unittest.TestCase): def testToAndFromBinary(self): def _test(value): midi_arg = osc.MidiArgument.fromBinary(osc.MidiArgument(value).toBinary())[0] self.assertEquals(midi_arg.value, value) _test((255, 255, 255, 255)) _test((0, 0, 0, 0)) self.assertRaises(osc.OscError, osc.MidiArgument.fromBinary, "\0\0\0") # invalid value self.assertRaises(TypeError, osc.MidiArgument.toBinary, (-244, 0, 0, 0)) # invalid value self.assertRaises(TypeError, osc.MidiArgument.toBinary, ()) # invalid value class TestTimeTagArgument(unittest.TestCase): def testToBinary(self): # 1 second since Jan 1, 1900 arg = osc.TimeTagArgument(1) binary = arg.toBinary() self.assertEquals(binary, "\0\0\0\1\0\0\0\0") def testFromBinary(self): # 1 second since Jan 1, 1900 self.assertEquals(1.0, osc.TimeTagArgument.fromBinary("\0\0\0\1\0\0\0\0")[0].value) # immediately self.assertEquals(True, osc.TimeTagArgument.fromBinary("\0\0\0\0\0\0\0\1")[0].value) # error self.assertRaises(osc.OscError, osc.TimeTagArgument.fromBinary, "\0\0\0\0\0\0") def testToAndFromBinary(self): # 1 second since Jan 1, 1900 def test(value): timetag_arg, leftover = osc.TimeTagArgument.fromBinary(osc.TimeTagArgument(value).toBinary()) self.assertEquals(leftover, "") self.assertTrue(abs(timetag_arg.value - value) < 1e-6) test(1.0) test(1.1331) class TestMessage(unittest.TestCase): def testMessageStringRepresentation(self): self.assertEquals("/hello", str(osc.Message("/hello"))) self.assertEquals("/hello ,i i:1 ", str(osc.Message("/hello", 1))) self.assertEquals("/hello ,T T:True ", str(osc.Message("/hello", True))) def testAddMessageArguments(self): """ Test adding arguments to a message """ m = osc.Message("/example", osc.IntArgument(33), osc.BooleanArgument(True)) self.assertEquals(m.arguments[0].value, 33) self.assertEquals(m.arguments[1].value, True) m = osc.Message("/example", 33, True) self.assertEquals(m.arguments[0].value, 33) self.assertEquals(m.arguments[1].value, True) m = osc.Message("/example") m.add(33) self.assertEquals(m.arguments[0].value, 33) self.assertEquals(m.arguments[0].typeTag, "i") m.add(True) self.assertEquals(m.arguments[1].typeTag, "T") def testEquality(self): self.assertEquals(osc.Message("/example"), osc.Message("/example")) self.assertNotEqual(osc.Message("/example"), osc.Message("/example2")) self.assertEquals(osc.Message("/example", 33), osc.Message("/example", 33)) self.assertNotEqual(osc.Message("/example", 33), osc.Message("/example", 34)) self.assertNotEqual(osc.Message("/example", 33), osc.Message("/example", 33.0)) self.assertNotEqual(osc.Message("/example", 33), osc.Message("/example", 33, True)) self.assertEquals(osc.Message("/example", 33, True), osc.Message("/example", 33, True)) def testGetTypeTag(self): m = osc.Message("/example") self.assertEquals(m.getTypeTags(), "") m.arguments.append(osc.StringArgument("egg")) self.assertEquals(m.getTypeTags(), "s") m.arguments.append(osc.StringArgument("spam")) self.assertEquals(m.getTypeTags(), "ss") def testToAndFromBinary(self): self.assertRaises(osc.OscError, osc.Message.fromBinary, "invalidbinarydata..") self.assertRaises(osc.OscError, osc.Message.fromBinary, "/example,invalidbinarydata..") self.assertRaises(osc.OscError, osc.Message.fromBinary, "/hello\0\0,xxx\0") def test(m): binary = m.toBinary() m2, leftover = osc.Message.fromBinary(binary) self.assertEquals(leftover, "") self.assertEquals(m, m2) test(osc.Message("/example")) test(osc.Message("/example", osc.StringArgument("hello"))) test(osc.Message("/example", osc.IntArgument(1), osc.IntArgument(2), osc.IntArgument(-1))) test(osc.Message("/example", osc.BooleanArgument(True))) test(osc.Message("/example", osc.BooleanArgument(False), osc.NullArgument(), osc.StringArgument("hello"))) test(osc.Message("/example", osc.ImpulseArgument())) def testGetValues(self): # tests calling txosc.osc.Message.getValues() message = osc.Message("/foo", 2, True, 3.14159) values = message.getValues() self.failUnlessEqual(values[0], 2) self.failUnlessEqual(values[1], True) self.failUnlessEqual(values[2], 3.14159) class TestBundle(unittest.TestCase): def testEquality(self): self.assertEquals(osc.Bundle(), osc.Bundle()) self.assertNotEqual(osc.Bundle([osc.Message("/hello")]), osc.Bundle()) self.assertEquals(osc.Bundle([osc.Message("/hello")]), osc.Bundle([osc.Message("/hello")])) self.assertNotEqual(osc.Bundle([osc.Message("/hello")]), osc.Bundle([osc.Message("/hello2")])) def testToAndFromBinary(self): self.assertRaises(osc.OscError, osc.Bundle.fromBinary, "invalidbinarydata..") self.assertRaises(osc.OscError, osc.Bundle.fromBinary, "#bundle|invalidbinarydata..") self.assertRaises(osc.OscError, osc.Bundle.fromBinary, "#bundle\0\0\0\0\1\0\0\0\0hello") self.assertRaises(osc.OscError, osc.Bundle.fromBinary, "#bundle\0\0\0\0\1\0\0\0\0\0\0\0\5hellofdsfds") def test(b): binary = b.toBinary() b2, leftover = osc.Bundle.fromBinary(binary) self.assertEquals(leftover, "") self.assertEquals(b, b2) test(osc.Bundle()) test(osc.Bundle([osc.Message("/foo")])) test(osc.Bundle([osc.Message("/foo"), osc.Message("/bar")])) test(osc.Bundle([osc.Message("/foo"), osc.Message("/bar", osc.StringArgument("hello"))])) nested = osc.Bundle([osc.Message("/hello")]) test(osc.Bundle([nested, osc.Message("/foo")])) def testGetMessages(self): m1 = osc.Message("/foo") m2 = osc.Message("/bar") m3 = osc.Message("/foo/baz") b = osc.Bundle() b.add(m1) self.assertEquals(b.getMessages(), set([m1])) b = osc.Bundle() b.add(m1) b.add(m2) self.assertEquals(b.getMessages(), set([m1, m2])) b = osc.Bundle() b.add(m1) b.add(osc.Bundle([m2])) b.add(osc.Bundle([m3])) self.assertEquals(b.getMessages(), set([m1, m2, m3])) python-txosc-0.2.0/txosc/test/__init__.py0000644000000000000000000000010011445141512017103 0ustar rootroot#!/usr/bin/env python """ Unit tests for the txosc library. """ python-txosc-0.2.0/txosc/test/test_dispatch.py0000644000000000000000000003551711445141512020226 0ustar rootroot# Copyright (c) 2009 Alexandre Quessy, Arjan Scherpenisse # See LICENSE for details. """ Tests for txosc/dispatch.py Maintainer: Arjan Scherpenisse """ from twisted.trial import unittest from twisted.internet import reactor, defer, task from txosc import osc from txosc import async from txosc import dispatch class TestAddressNode(unittest.TestCase): """ Test the L{dispatch.AddressNode}; adding/removing/dispatching callbacks, wildcard matching. """ def testName(self): n = dispatch.AddressNode() n.setName("the_name") self.assertEquals("the_name", n.getName()) n = dispatch.AddressNode("the_name") self.assertEquals("the_name", n.getName()) def testAddRemoveCallback(self): def callback(m): pass n = dispatch.AddressNode() n.addCallback("/foo", callback) self.assertEquals(n.getCallbacks("/foo"), set([callback])) n.removeCallback("/foo", callback) self.assertEquals(n.getCallbacks("/foo"), set()) n.addCallback("/*", callback) self.assertEquals(n.getCallbacks("/foo"), set([callback])) n.removeCallback("/*", callback) self.assertEquals(n.getCallbacks("/foo"), set()) def testRemoveAllCallbacks(self): def callback(m): pass def callback2(m): pass def callback3(m): pass n = dispatch.AddressNode() n.addCallback("/foo", callback) self.assertEquals(n.getCallbacks("/*"), set([callback])) n.removeAllCallbacks() self.assertEquals(n.getCallbacks("/*"), set()) n = dispatch.AddressNode() n.addCallback("/foo", callback) n.addCallback("/foo/bar", callback2) n.removeAllCallbacks() self.assertEquals(n.getCallbacks("/*"), set([])) def testAddInvalidCallback(self): n = dispatch.AddressNode() self.assertRaises(ValueError, n.addCallback, "/foo bar/baz", lambda m: m) self.assertEquals(n.addCallback("/foo/*/baz", lambda m: m), None) def testRemoveCallbacksByPattern(self): raise NotImplementedError("The feature is not implemented yet.") def testRemoveNonExistingCallback(self): n = dispatch.AddressNode() self.assertRaises(KeyError, n.removeCallback, "/foo", lambda m: m) def testMatchExact(self): def callback(m): pass n = dispatch.AddressNode() n.addCallback("/foo", callback) self.assertEquals(n.matchCallbacks(osc.Message("/foo")), set([callback])) self.assertEquals(n.matchCallbacks(osc.Message("/bar")), set()) def testMatchCallbackWildcards(self): def callback(m): pass n = dispatch.AddressNode() n.addCallback("/foo/*", callback) self.assertEquals(n.matchCallbacks(osc.Message("/foo")), set()) self.assertEquals(n.matchCallbacks(osc.Message("/foo/bar")), set([callback])) self.assertEquals(n.matchCallbacks(osc.Message("/bar")), set()) self.assertEquals(n.matchCallbacks(osc.Message("/foo/bar/baz")), set([])) self.assertEquals(n.matchCallbacks(osc.Message("/foo/bar")), set([callback])) n = dispatch.AddressNode() n.addCallback("/*", callback) self.assertEquals(n.matchCallbacks(osc.Message("/")), set([callback])) self.assertEquals(n.matchCallbacks(osc.Message("/foo/bar")), set([])) n = dispatch.AddressNode() n.addCallback("/*/baz", callback) self.assertEquals(n.matchCallbacks(osc.Message("/foo/bar")), set()) self.assertEquals(n.matchCallbacks(osc.Message("/foo/baz")), set([callback])) n = dispatch.AddressNode() n.addCallback("/*/*", callback) self.assertEquals(n.matchCallbacks(osc.Message("/foo/baz")), set([callback])) self.assertEquals(n.matchCallbacks(osc.Message("/foo/bar/baz")), set([])) def testMatchCallbackRangeWildcards(self): def callback1(m): pass def callback2(m): pass n = dispatch.AddressNode() n.addCallback("/foo1", callback1) n.addCallback("/foo2", callback2) self.assertEquals(n.matchCallbacks(osc.Message("/foo[1]")), set([callback1])) self.assertEquals(n.matchCallbacks(osc.Message("/foo[1-9]")), set([callback1, callback2])) self.assertEquals(n.matchCallbacks(osc.Message("/foo[4-6]")), set([])) def testMatchMessageWithWildcards(self): def fooCallback(m): pass def barCallback(m): pass def bazCallback(m): pass def foobarCallback(m): pass n = dispatch.AddressNode() n.addCallback("/foo", fooCallback) n.addCallback("/bar", barCallback) n.addCallback("/baz", bazCallback) n.addCallback("/foo/bar", foobarCallback) self.assertEquals(n.matchCallbacks(osc.Message("/*")), set([fooCallback, barCallback, bazCallback])) self.assertEquals(n.matchCallbacks(osc.Message("/spam")), set()) self.assertEquals(n.matchCallbacks(osc.Message("/ba*")), set([barCallback, bazCallback])) self.assertEquals(n.matchCallbacks(osc.Message("/b*r")), set([barCallback])) self.assertEquals(n.matchCallbacks(osc.Message("/ba?")), set([barCallback, bazCallback])) def testMatchMessageWithRange(self): def firstCallback(m): pass def secondCallback(m): pass n = dispatch.AddressNode() n.addCallback("/foo/1", firstCallback) n.addCallback("/foo/2", secondCallback) self.assertEquals(n.matchCallbacks(osc.Message("/baz")), set()) self.assertEquals(n.matchCallbacks(osc.Message("/foo/[1-3]")), set([firstCallback, secondCallback])) self.assertEquals(n.matchCallbacks(osc.Message("/foo/[!1]")), set([secondCallback])) def testWildcardMatching(self): self.assertFalse(dispatch.AddressNode.matchesWildcard("foo", "bar")) self.assertTrue(dispatch.AddressNode.matchesWildcard("", "?")) self.assertTrue(dispatch.AddressNode.matchesWildcard("f", "?")) self.assertFalse(dispatch.AddressNode.matchesWildcard("fo", "?")) self.assertTrue(dispatch.AddressNode.matchesWildcard("foo", "f?o")) self.assertTrue(dispatch.AddressNode.matchesWildcard("fo", "f?o")) self.assertFalse(dispatch.AddressNode.matchesWildcard("fooo", "f?o")) self.assertTrue(dispatch.AddressNode.matchesWildcard("foo", "f??o")) self.assertTrue(dispatch.AddressNode.matchesWildcard("foo", "*")) self.assertTrue(dispatch.AddressNode.matchesWildcard("foo", "f*")) self.assertTrue(dispatch.AddressNode.matchesWildcard("fo", "f*o")) self.assertTrue(dispatch.AddressNode.matchesWildcard("foo", "f*o")) self.assertFalse(dispatch.AddressNode.matchesWildcard("foo", "f*bar")) self.assertFalse(dispatch.AddressNode.matchesWildcard("foo", "*bar")) self.assertTrue(dispatch.AddressNode.matchesWildcard("foobar", "*bar")) self.assertTrue(dispatch.AddressNode.matchesWildcard("foobar", "f?ob*r")) def testWildcardCharMatching(self): self.assertTrue(dispatch.AddressNode.matchesWildcard("abc", "a[b]c")) self.assertTrue(dispatch.AddressNode.matchesWildcard("abc", "a[bc]c")) self.assertTrue(dispatch.AddressNode.matchesWildcard("abc", "a[abcdefg][abc]")) self.assertFalse(dispatch.AddressNode.matchesWildcard("abc", "a[abcdefg][def]")) self.assertRaises(osc.OscError, dispatch.AddressNode.matchesWildcard, "abc", "a[abcdefg][def") def testWildcardRangeMatching(self): self.assertTrue(dispatch.AddressNode.matchesWildcard("bar1", "bar[1-3]")) self.assertTrue(dispatch.AddressNode.matchesWildcard("bar23", "bar[1-3]3")) self.assertTrue(dispatch.AddressNode.matchesWildcard("bar23", "bar[1-3][1-9]")) self.assertFalse(dispatch.AddressNode.matchesWildcard("bar2", "bar[a-z]")) self.assertFalse(dispatch.AddressNode.matchesWildcard("bar20", "bar[10-30]")) self.assertTrue(dispatch.AddressNode.matchesWildcard("a-c", "a[x-]c")) self.assertFalse(dispatch.AddressNode.matchesWildcard("a-c", "a[x-z]c")) def testWildcardRangeNegateMatching(self): self.assertTrue(dispatch.AddressNode.matchesWildcard("bar", "b[!b]r")) self.assertFalse(dispatch.AddressNode.matchesWildcard("bar", "b[!b][!a-z]")) self.assertFalse(dispatch.AddressNode.matchesWildcard("bar23", "bar[!1-3]3")) self.assertTrue(dispatch.AddressNode.matchesWildcard("bar2", "bar[!a-z]")) self.assertTrue(dispatch.AddressNode.matchesWildcard("abc", "a[b!]c")) self.assertTrue(dispatch.AddressNode.matchesWildcard("a!c", "a[b!]c")) self.assertFalse(dispatch.AddressNode.matchesWildcard("a!c", "a[!!]c")) def testWildcardAnyStringsMatching(self): self.assertTrue(dispatch.AddressNode.matchesWildcard("foo", "{foo,bar}")) self.assertTrue(dispatch.AddressNode.matchesWildcard("bar", "{foo,bar}")) self.assertTrue(dispatch.AddressNode.matchesWildcard("bar", "{foo,bar,baz}")) self.assertTrue(dispatch.AddressNode.matchesWildcard("foobar", "foo{bar}")) self.assertTrue(dispatch.AddressNode.matchesWildcard("foobar", "foo{bar}")) self.assertFalse(dispatch.AddressNode.matchesWildcard("bar", "{foo,bar,baz}bar")) self.assertTrue(dispatch.AddressNode.matchesWildcard("foobar", "{foo,bar,baz}bar")) self.assertTrue(dispatch.AddressNode.matchesWildcard("barbar", "{foo,bar,baz}bar")) def testWildcardCombined(self): self.assertTrue(dispatch.AddressNode.matchesWildcard("foobar", "f??{abc,ba}[o-s]")) def testAddressNodeNesting(self): def cb(): pass child = dispatch.AddressNode() child.addCallback("/bar", cb) parent = dispatch.AddressNode() parent.addNode("foo", child) self.assertEquals(parent.getCallbacks("/foo/bar"), set([cb])) self.assertEquals(parent.getCallbacks("/foo/b*"), set([cb])) self.assertEquals(parent.getCallbacks("/foo/baz"), set()) def testAddressNodeNestingMultiple(self): class MyNode(dispatch.AddressNode): def __init__(self): dispatch.AddressNode.__init__(self) self.addCallback("/trigger", self.trigger) def trigger(self): pass c1 = MyNode() c2 = MyNode() parent = dispatch.AddressNode() parent.addNode("foo", c1) parent.addNode("bar", c2) self.assertEquals(parent.getCallbacks("/foo/*"), set([c1.trigger])) self.assertEquals(parent.getCallbacks("/bar/*"), set([c2.trigger])) self.assertEquals(parent.getCallbacks("/*/trigger"), set([c1.trigger, c2.trigger])) def testAddressNodeRenaming(self): def cb(): pass child = dispatch.AddressNode() child.addCallback("/bar", cb) parent = dispatch.AddressNode() parent.addNode("foo", child) self.assertEquals(parent.getCallbacks("/foo/bar"), set([cb])) child.setName("bar") self.assertEquals(parent.getCallbacks("/bar/bar"), set([cb])) def testAddressNodeReparenting(self): def cb(): pass child = dispatch.AddressNode() child.addCallback("/bar", cb) baz = dispatch.AddressNode() parent = dispatch.AddressNode() parent.addNode("foo", child) parent.addNode("baz", baz) # empty node self.assertEquals(parent.getCallbacks("/foo/bar"), set([cb])) child.setParent(baz) self.assertEquals(parent.getCallbacks("/foo/bar"), set([])) self.assertEquals(parent.getCallbacks("/baz/foo/bar"), set([cb])) testRemoveCallbacksByPattern.skip = "This feature is not implemented." class TestReceiver(unittest.TestCase): """ Test the L{dispatch.Receiver} class. """ def testDispatching(self): hello = osc.Message("/hello") there = osc.Message("/there") addr = ("0.0.0.0", 17778) def cb(message, a): self.assertEquals(message, hello) self.assertEquals(addr, a) state['cb'] = True def cb2(message, a): self.assertEquals(message, there) self.assertEquals(addr, a) state['cb2'] = True recv = dispatch.Receiver() recv.addCallback("/hello", cb) recv.addCallback("/there", cb2) state = {} recv.dispatch(hello, addr) self.assertEquals(state, {'cb': True}) state = {} recv.dispatch(osc.Bundle([hello, there]), addr) self.assertEquals(state, {'cb': True, 'cb2': True}) def testFunctionFallback(self): hello = osc.Message("/hello") addr = ("0.0.0.0", 17778) def fb(message, address): self.assertEquals(message, hello) recv = dispatch.Receiver() recv.setFallback(fb) recv.dispatch(hello, addr) def testClassFallback(self): hello = osc.Message("/hello") addr = ("0.0.0.0", 17778) class Dummy(object): def __init__(self, test_case): self.x = 3 self.test_case = test_case def fb(self, message, address): self.test_case.assertEquals(message, hello) self.test_case.assertEquals(self.x, 3) recv = dispatch.Receiver() dummy = Dummy(self) recv.fallback = dummy.fb recv.dispatch(hello, addr) class TestAddressNodeAndReceiver(unittest.TestCase): """ Test both L{txosc.dispatch.Receiver} and L{txosc.dispatch.AddressNode}, the first nested in the latter. """ def testFallback(self): """ Tests how fallbacks are handled. """ foo = osc.Message("/foo") egg_spam = osc.Message("/egg/spam") egg_ham = osc.Message("/egg/ham") addr = ("0.0.0.0", 17778) called = { 'foo': False, 'egg_spam': False, 'fallback': False } def foo_cb(message, a): self.assertEquals(message, foo) self.assertEquals(addr, a) called['foo'] = True def egg_spam_cb(message, a): self.assertEquals(message, egg_spam) self.assertEquals(addr, a) called['egg_spam'] = True def fallback(message, a): self.assertEquals(message, egg_ham) self.assertEquals(addr, a) called['fallback'] = True recv = dispatch.Receiver() recv.addCallback("/foo", foo_cb) child = dispatch.AddressNode() child.addCallback("/spam", egg_spam_cb) recv.addNode("egg", child) recv.fallback = fallback # now, dispatch messages recv.dispatch(foo, addr) recv.dispatch(egg_spam, addr) recv.dispatch(egg_ham, addr) self.assertTrue(called['foo']) self.assertTrue(called['egg_spam']) self.assertTrue(called['fallback']) python-txosc-0.2.0/txosc/test/test_async.py0000644000000000000000000001467611445141512017547 0ustar rootroot# Copyright (c) 2009 Alexandre Quessy, Arjan Scherpenisse # See LICENSE for details. """ Tests for txosc/async.py Maintainer: Arjan Scherpenisse """ from twisted.trial import unittest from twisted.internet import reactor, defer, task from txosc import osc from txosc import async from txosc import dispatch class ClientServerTests(object): """ Common class for the L{TestUDPClientServer} and L{TestTCPClientServer} for shared test functions. """ def testSingleMessage(self): pingMsg = osc.Message("/ping") d = defer.Deferred() def ping(m, addr): self.assertEquals(m, pingMsg) d.callback(True) self.receiver.addCallback("/ping", ping) self._send(pingMsg) return d def testBundle(self): pingMsg = osc.Message("/ping") bundle = osc.Bundle() bundle.add(osc.Message("/pong")) bundle.add(pingMsg) bundle.add(osc.Message("/foo/bar", 1, 2)) d = defer.Deferred() def ping(m, addr): self.assertEquals(m, pingMsg) d.callback(True) d2 = defer.Deferred() def foo(m, addr): self.assertEquals(m, osc.Message("/foo/bar", 1, 2)) d2.callback(True) self.receiver.addCallback("/ping", ping) self.receiver.addCallback("/foo/*", foo) self._send(bundle) return defer.DeferredList([d, d2]) class TestUDPClientServer(unittest.TestCase, ClientServerTests): """ Test the L{osc.Sender} and L{dispatch.Receiver} over UDP via localhost. """ timeout = 1 def setUp(self): self.receiver = dispatch.Receiver() self.serverPort = reactor.listenUDP(17778, async.DatagramServerProtocol(self.receiver)) self.client = async.DatagramClientProtocol() self.clientPort = reactor.listenUDP(0, self.client) def tearDown(self): return defer.DeferredList([self.serverPort.stopListening(), self.clientPort.stopListening()]) def _send(self, element): self.client.send(element, ("127.0.0.1", 17778)) class TestMulticastClientServer(unittest.TestCase): """ Test the L{osc.Sender} and two L{dispatch.Receiver} over Multicast UDP via 224.0.0.1. """ timeout = 1 def setUp(self): self.receiver = dispatch.Receiver() self.serverPort = reactor.listenMulticast(17778, async.MulticastDatagramServerProtocol(self.receiver, "224.0.0.1"), listenMultiple=True) self.receiver2 = dispatch.Receiver() self.serverPort2 = reactor.listenMulticast(17778, async.MulticastDatagramServerProtocol(self.receiver2, "224.0.0.1"), listenMultiple=True) self.client = async.DatagramClientProtocol() self.clientPort = reactor.listenUDP(0, self.client) def testSingleMessage(self): pingMsg = osc.Message("/ping") d = defer.Deferred() d2 = defer.Deferred() def ping(m, addr): self.assertEquals(m, pingMsg) d.callback(True) def ping2(m, addr): self.assertEquals(m, pingMsg) d2.callback(True) self.receiver.addCallback("/ping", ping) self.receiver2.addCallback("/ping", ping2) self._send(pingMsg) return defer.DeferredList([d, d2]) def tearDown(self): return defer.DeferredList([self.serverPort.stopListening(), self.serverPort2.stopListening(), self.clientPort.stopListening()]) def _send(self, element): self.client.send(element, ("224.0.0.1", 17778)) class TestTCPClientServer(unittest.TestCase, ClientServerTests): """ Test the L{osc.Sender} and L{dispatch.Receiver} over UDP via localhost. """ timeout = 1 def setUp(self): self.receiver = dispatch.Receiver() self.serverPort = reactor.listenTCP(17778, async.ServerFactory(self.receiver)) self.client = async.ClientFactory() self.clientPort = reactor.connectTCP("localhost", 17778, self.client) return self.client.deferred def tearDown(self): self.clientPort.transport.loseConnection() return defer.DeferredList([self.serverPort.stopListening()]) def _send(self, element): self.client.send(element) class TestReceiverWithExternalClient(unittest.TestCase): """ This test needs python-liblo. """ timeout = 1 def setUp(self): self.receiver = dispatch.Receiver() self.serverPort = reactor.listenUDP(17778, async.DatagramServerProtocol(self.receiver)) self.target = liblo.Address(17778) def tearDown(self): return defer.DeferredList([self.serverPort.stopListening()]) def testSingleMessage(self): d = defer.Deferred() def ping(m, addr): self.assertEquals(m, osc.Message("/ping")) d.callback(True) self.receiver.addCallback("/ping", ping) liblo.send(self.target, "/ping") return d def testBundle(self): d = defer.Deferred() d2 = defer.Deferred() def ping(m, addr): self.assertEquals(m, osc.Message("/ping")) d.callback(True) def pong(m, addr): self.assertEquals(m, osc.Message("/pong", 1, 2, "string")) d2.callback(True) self.receiver.addCallback("/ping", ping) self.receiver.addCallback("/po*", pong) b = liblo.Bundle() b.add("/ping") b.add("/pong", 1, 2, "string") liblo.send(self.target, b) return defer.DeferredList([d, d2]) class TestClientWithExternalReceiver(unittest.TestCase): """ This test needs python-liblo. """ timeout = 1 def setUp(self): self.client = async.DatagramClientProtocol() self.clientPort = reactor.listenUDP(0, self.client) def tearDown(self): return defer.DeferredList([self.clientPort.stopListening()]) def _send(self, element): self.client.send(element, ("127.0.0.1", 17778)) def testSingleMessage(self): server = liblo.Server(17779) server.start() received = False def ping_callback(path, args): received = True server.add_method("/ping", '', ping_callback) self._send(osc.Message("/ping")) while not received: print 11 server.recv(100) try: import liblo except ImportError: TestReceiverWithExternalClient.skip = "pyliblo not installed" TestClientWithExternalReceiver.skip = "FIXME: liblo server does not run with twisted" #FIXME: yes it does. see rats.osc in Toonloop 1.2 python-txosc-0.2.0/txosc/dispatch.py0000644000000000000000000002551311445141512016203 0ustar rootroot#!/usr/bin/env python # -*- test-case-name: txosc.test.test_dispatch -*- # Copyright (c) 2009 Alexandre Quessy, Arjan Scherpenisse # See LICENSE for details. """ OSC message address dispatching to callbacks """ import string import math import struct import re from txosc.osc import * class AddressNode(object): """ A node in the tree of OSC addresses. This node can be either a container branch or a leaf. An OSC address is a series of names separated by forward slash characters. ('/') We say that a node is a branch when it has one or more child nodes. This class is provided so that the programmer can separate the handling of an address sub-tree in the OSC addresses. For example, an AddressNode can be added to a receiver in order to handle all the messages starting with "/egg/spam/". AddressNode classes can be nested. @ivar _name: the name of this node. @ivar _parent: the parent node. """ def __init__(self, name=None, parent=None): """ @type name: C{str} @param parent: L{Receiver} or L{AddressNode} """ self._name = name self._parent = parent self._childNodes = {} self._callbacks = set() self._parent = None self._wildcardNodes = set() def removeCallbacks(self): """ Remove all callbacks from this node. """ self._callbacks = set() self._checkRemove() def setName(self, newname): """ Give this node a new name. @type newname: C{str} """ if self._parent: del self._parent._childNodes[self._name] self._name = newname if self._parent: self._parent._childNodes[self._name] = self def setParent(self, newparent): """ Reparent this node to another parent. @param newparent: L{Receiver} or L{AddressNode} """ if self._parent: del self._parent._childNodes[self._name] self._parent._checkRemove() self._parent = newparent self._parent._childNodes[self._name] = self # def getParent(self): # """ # Returns the parent node or None. # """ # return self._parent # # def getChildren(self): # """ # Returns a set of children nodes. # """ # return set(self._childNodes) def _checkRemove(self): if not self._parent: return if not self._callbacks and not self._childNodes: del self._parent._childNodes[self._name] self._parent._checkRemove() def addNode(self, name, instance): """ Add a child node. @type name: C{str} @type instance: L{AddressNode} """ #FIXME: We should document the name. # Is it /foo or foo? # Does it redirect all messages prefixed with "/foo" to the child? instance.setName(name) instance.setParent(self) def getName(self): """ Returns the name of this address node. """ return self._name def match(self, pattern): """ Match a pattern to return a set of nodes. @param pattern: A C{str} with an address pattern. @return a C{set()} of matched AddressNode instances. """ path = self._patternPath(pattern) if not len(path): return set([self]) matchedNodes = set() part = path[0] if AddressNode.isWildcard(part): for c in self._childNodes: if AddressNode.matchesWildcard(c, part): matchedNodes.add( self._childNodes[c] ) # FIXME - what if both the part and some of my childs have wildcards? elif self._wildcardNodes: matches = set() for c in self._wildcardNodes: if AddressNode.matchesWildcard(part, c): matchedNodes.add( self._childNodes[c] ) break if part in self._childNodes: matchedNodes.add( self._childNodes[part] ) if not matchedNodes: return matchedNodes return reduce(lambda a, b: a.union(b), [n.match(path[1:]) for n in matchedNodes]) def addCallback(self, pattern, cb): """ Adds a callback for L{txosc.osc.Message} instances received for a given OSC path, relative to this node's address as its root. In the OSC protocol, only leaf nodes can have callbacks, though this implementation allows also branch nodes to have callbacks. @param path: OSC address in the form C{/egg/spam/ham}, or list C{['egg', 'spam', 'ham']}. @type pattern: C{str} or C{list}. @param cb: Callback that will receive L{Message} as an argument when received. @type cb: Function or method. @return: None """ path = self._patternPath(pattern) if not len(path): self._callbacks.add(cb) else: part = path[0] if part not in self._childNodes: if not AddressNode.isValidAddressPart(part): raise ValueError("Invalid address part: '%s'" % part) self.addNode(part, AddressNode()) if AddressNode.isWildcard(part): self._wildcardNodes.add(part) self._childNodes[part].addCallback(path[1:], cb) def removeCallback(self, pattern, cb): """ Removes a callback for L{Message} instances received for a given OSC path. @param path: OSC address in the form C{/egg/spam/ham}, or list C{['egg', 'spam', 'ham']}. @type pattern: C{str} or C{list}. @param cb: Callback that will receive L{txosc.osc.Message} as an argument when received. @type cb: A callable object. """ path = self._patternPath(pattern) if not len(path): self._callbacks.remove(cb) else: part = path[0] if part not in self._childNodes: raise KeyError("No such address part: " + part) self._childNodes[part].removeCallback(path[1:], cb) if not self._childNodes[part]._callbacks and not self._childNodes[part]._childNodes: # remove child if part in self._wildcardNodes: self._wildcardNodes.remove(part) del self._childNodes[part] @staticmethod def isWildcard(name): """ Given a name, returns whether it contains wildcard characters. """ wildcardChars = set("*?[]{}") return len(set(name).intersection(wildcardChars)) > 0 @staticmethod def isValidAddressPart(part): """ Check whether the address part can be used as an L{AddressNode} name. @rtype bool """ invalidChars = set(" #,/") return len(set(part).intersection(invalidChars)) == 0 @staticmethod def matchesWildcard(value, wildcard): """ Match a value to a wildcard. """ if value == wildcard and not AddressNode.isWildcard(wildcard): return True if wildcard == "*": return True wildcard = wildcard.replace("*", ".*") wildcard = wildcard.replace("?", ".?") wildcard = wildcard.replace("[!", "[^") wildcard = wildcard.replace("(", "\(") wildcard = wildcard.replace(")", "\)") wildcard = wildcard.replace("|", "\|") wildcard = wildcard.replace("{", "(") wildcard = wildcard.replace("}", ")") wildcard = wildcard.replace(",", "|") wildcard = "^" + wildcard + "$" try: r = re.compile(wildcard) return re.match(wildcard, value) is not None except: raise OscError("Invalid character in wildcard.") def _patternPath(self, pattern): """ Given a OSC address path like /foo/bar, return a list of ['foo', 'bar']. Note that an OSC address always starts with a slash. If a list is input, it is output directly. @param pattern: A L{str} OSC address. @return: A L{list} of L{str}. Each part of an OSC path. """ if type(pattern) == list: return pattern return pattern.split("/")[1:] def removeCallbacksByPattern(self, pattern): """ Remove all callbacks with the given pattern. @param pattern: The pattern to match the callbacks. When ommited, removes all callbacks. """ raise NotImplementedError("Implement removeCallbacks") def removeAllCallbacks(self): """ Remove all callbacks from this node. """ self._childNodes = {} self._wildcardNodes = set() self._callbacks = set() self._checkRemove() def matchCallbacks(self, message): """ Get all callbacks for a given message """ pattern = message.address return self.getCallbacks(pattern) def getCallbacks(self, pattern): """ Retrieve all callbacks which are bound to given pattern. Returns a set() of callables. @return: L{set} of callbables. """ path = self._patternPath(pattern) nodes = self.match(path) if not nodes: return nodes return reduce(lambda a, b: a.union(b), [n._callbacks for n in nodes]) class Receiver(AddressNode): """ Receive OSC elements (L{Bundle}s and L{Message}s) from the server protocol and handles the matching and dispatching of these to the registered callbacks. Callbacks are stored in a tree-like structure, using L{AddressNode} objects. """ def dispatch(self, element, client): """ Dispatch an element to all matching callbacks. Executes every callback matching the message address with element as argument. The order in which the callbacks are called is undefined. @param element: A L{Message} or L{Bundle}. @param client: Either a (host, port) tuple with the originator's address, or an instance of L{StreamBasedFactory} whose C{send()} method can be used to send a message back. """ if isinstance(element, Bundle): messages = element.getMessages() else: messages = [element] for m in messages: matched = False for c in self.getCallbacks(m.address): c(m, client) matched = True if not matched: self.fallback(m, client) #TODO: add a addFallback or setFallback method def fallback(self, message, client): """ The default fallback handler. """ from twisted.python import log log.msg("Unhandled message from %s): %s" % (repr(client), str(message))) def setFallback(self, fallback): """ Sets the fallback. @param fallback: callable function or method. """ self.fallback = fallback python-txosc-0.2.0/txosc/osc.py0000644000000000000000000005025611445141512015172 0ustar rootroot#!/usr/bin/env python # -*- test-case-name: txosc.test.test_osc -*- # Copyright (c) 2009 Alexandre Quessy, Arjan Scherpenisse # See LICENSE for details. """ Open Sound Control 1.1 protocol message generation and parsing This file is not Twisted-specific. Thoses classes implement OSC message generation and parsing. Each message has an address and might have some arguments. Messages can be grouped in bundles. The protocol is specified in OSC 1.0 specification at U{http://opensoundcontrol.org/spec-1_0} and has been further extended in the paper which can be found at U{http://opensoundcontrol.org/spec-1_1}. """ import string import math import struct import re class OscError(Exception): """ Any error raised by this module. """ pass def getAddressParts(address): """ Returns the list of the parts of an address. @rtype: C{list} @return: List of strings. @param address: An OSC address @type address: C{str} """ return address.strip("/").split("/") class Message(object): """ An OSC Message element. @ivar address: The OSC address string, e.g. C{"/foo/bar"}. @type address: C{str} @ivar arguments: The L{Argument} instances for the message. @type argument: C{list} """ def __init__(self, address, *args): self.address = address self.arguments = [] for arg in args: self.add(arg) def toBinary(self): """ Encodes the L{Message} to binary form, ready to send over the wire. @return: A string with the binary presentation of this L{Message}. """ return StringArgument(self.address).toBinary() + StringArgument("," + self.getTypeTags()).toBinary() + "".join([a.toBinary() for a in self.arguments]) def getTypeTags(self): """ Return the OSC type tags for this message. @return: A string with this message's OSC type tag, e.g. C{"ii"} when there are 2 int arguments. """ return "".join([a.typeTag for a in self.arguments]) def add(self, value): """ Adds an argument to this message with given value, using L{createArgument}. @param value: Argument to add to this message. Can be any Python type, or an L{Argument} instance. """ if not isinstance(value, Argument): value = createArgument(value) self.arguments.append(value) @staticmethod def fromBinary(data): """ Creates a L{Message} object from binary data that is passed to it. This static method is a factory for L{Message} objects. It checks the type tags of the message, and parses each of its arguments, calling each of the proper factory. @param data: String of bytes/characters formatted following the OSC protocol. @type data: C{str} @return: Two-item tuple with L{Message} as the first item, and the leftover binary data, as a L{str}. """ osc_address, leftover = _stringFromBinary(data) message = Message(osc_address) type_tags, leftover = _stringFromBinary(leftover) if type_tags[0] != ",": # invalid type tag string raise OscError("Invalid typetag string: %s" % type_tags) for type_tag in type_tags[1:]: arg, leftover = _argumentFromBinary(type_tag, leftover) message.arguments.append(arg) return message, leftover def __str__(self): s = self.address if self.arguments: args = " ".join([str(a) for a in self.arguments]) s += " ,%s %s" % (self.getTypeTags(), args) return s def getValues(self): """ Returns a list of each argument's value. @rtype: C{list} """ return [arg.value for arg in self.arguments] def __eq__(self, other): if self.address != other.address: return False if len(self.arguments) != len(other.arguments): return False if self.getTypeTags() != other.getTypeTags(): return False for i in range(len(self.arguments)): if self.arguments[i].value != other.arguments[i].value: return False return True def __ne__(self, other): return not (self == other) class Bundle(object): """ An OSC Bundle element. @ivar timeTag: A L{TimeTagArgument}, representing the time for this bundle. @ivar elements: A C{list} of OSC elements (L{Message} or L{Bundle}s). """ timeTag = None elements = None def __init__(self, elements=None, timeTag=True): if elements: self.elements = elements else: self.elements = [] self.timeTag = timeTag def toBinary(self): """ Encodes the L{Bundle} to binary form, ready to send over the wire. @return: A string with the binary presentation of this L{Bundle}. """ data = StringArgument("#bundle").toBinary() data += TimeTagArgument(self.timeTag).toBinary() for msg in self.elements: binary = msg.toBinary() data += IntArgument(len(binary)).toBinary() data += binary return data def add(self, element): """ Add an element to this bundle. @param element: A L{Message} or a L{Bundle}. """ self.elements.append(element) def __eq__(self, other): if len(self.elements) != len(other.elements): return False for i in range(len(self.elements)): if self.elements[i] != other.elements[i]: return False return True def __ne__(self, other): return not (self == other) @staticmethod def fromBinary(data): """ Creates a L{Bundle} object from binary data that is passed to it. This static method is a factory for L{Bundle} objects. @param data: String of bytes formatted following the OSC protocol. @return: Two-item tuple with L{Bundle} as the first item, and the leftover binary data, as a L{str}. That leftover should be an empty string. """ bundleStart, data = _stringFromBinary(data) if bundleStart != "#bundle": raise OscError("Error parsing bundle string") bundle = Bundle() bundle.timeTag, data = TimeTagArgument.fromBinary(data) while data: size, data = IntArgument.fromBinary(data) size = size.value if len(data) < size: raise OscError("Unexpected end of bundle: need %d bytes of data" % size) payload = data[:size] bundle.elements.append(_elementFromBinary(payload)) data = data[size:] return bundle, "" def getMessages(self): """ Retrieve all L{Message} elements from this bundle, recursively. @return: L{set} of L{Message} instances. """ r = set() for m in self.elements: if isinstance(m, Bundle): r = r.union(m.getMessages()) else: r.add(m) return r class Argument(object): """ Base OSC argument class. @ivar typeTag: A 1-character C{str} which represents the OSC type of this argument. Every subclass must define its own typeTag. """ typeTag = None def __init__(self, value): self.value = value self._check_type() def _check_type(self): """ Does the type checking for the value. """ pass def toBinary(self): """ Encodes the L{Argument} to binary form, ready to send over the wire. @return: A string with the binary presentation of this L{Message}. """ raise NotImplementedError('Override this method') @staticmethod def fromBinary(data): """ Creates a L{Message} object from binary data that is passed to it. This static method is a factory for L{Argument} objects. Each subclass of the L{Argument} class implements it to create an instance of its own type, parsing the data given as an argument. @param data: C{str} of bytes formatted following the OSC protocol. @return: Two-item tuple with L{Argument} as the first item, and the leftover binary data, as a L{str}. """ raise NotImplementedError('Override this method') def __str__(self): return "%s:%s " % (self.typeTag, self.value) # # OSC 1.1 required arguments # class BlobArgument(Argument): """ An L{Argument} representing arbitrary binary data. """ typeTag = "b" def toBinary(self): """ See L{Argument.toBinary}. """ sz = len(self.value) #length = math.ceil((sz+1) / 4.0) * 4 length = _ceilToMultipleOfFour(sz) return struct.pack(">i%ds" % (length), sz, str(self.value)) @staticmethod def fromBinary(data): """ See L{Argument.fromBinary}. """ try: length = struct.unpack(">i", data[0:4])[0] index_of_leftover = _ceilToMultipleOfFour(length) + 4 if len(data)+4 < length: raise OscError("Not enough bytes to find size of a blob of size %s in %s." % (length, data)) blob_data = data[4:length + 4] except struct.error: raise OscError("Not enough bytes to find size of a blob argument in %s." % (data)) leftover = data[index_of_leftover:] return BlobArgument(blob_data), leftover class StringArgument(Argument): """ An argument representing a C{str}. """ typeTag = "s" def toBinary(self): length = math.ceil((len(self.value)+1) / 4.0) * 4 return struct.pack(">%ds" % (length), str(self.value)) @staticmethod def fromBinary(data): """ Creates a L{StringArgument} object from binary data that is passed to it. This static method is a factory for L{StringArgument} objects. OSC-string A sequence of non-null ASCII characters followed by a null, followed by 0-3 additional null characters to make the total number of bits a multiple of 32. @param data: String of bytes/characters formatted following the OSC protocol. @return: Two-item tuple with L{StringArgument} as the first item, and the leftover binary data, as a L{str}. """ value, leftover = _stringFromBinary(data) return StringArgument(value), leftover class IntArgument(Argument): """ An L{Argument} representing a 32-bit signed integer. """ typeTag = "i" def _check_type(self): if type(self.value) not in [int, long]: raise TypeError("Value %s must be an integer or a long, not a %s." % (self.value, type(self.value).__name__)) def toBinary(self): if self.value >= 1<<31: raise OverflowError("Integer too large: %d" % self.value) if self.value < -1<<31: raise OverflowError("Integer too small: %d" % self.value) return struct.pack(">i", int(self.value)) @staticmethod def fromBinary(data): try: i = struct.unpack(">i", data[:4])[0] leftover = data[4:] except struct.error: raise OscError("Too few bytes left to get an int from %s." % (data)) #FIXME: do not raise error and return leftover anyways ? return IntArgument(i), leftover def __int__(self): return int(self.value) class FloatArgument(Argument): """ An L{Argument} representing a 32-bit floating-point value. """ typeTag = "f" def _check_type(self): if type(self.value) not in [float, int, long]: raise TypeError("Value %s must be a float, an int or a long, not a %s." % (self.value, type(self.value).__name__)) def toBinary(self): return struct.pack(">f", float(self.value)) @staticmethod def fromBinary(data): try: f = struct.unpack(">f", data[:4])[0] leftover = data[4:] except struct.error: raise OscError("Too few bytes left to get a float from %s." % (data)) #FIXME: do not raise error and return leftover anyways ? return FloatArgument(f), leftover def __float__(self): return float(self.value) class TimeTagArgument(Argument): """ An L{Argument} representing an OSC time tag. Like NTP timestamps, the binary representation of a time tag is a 64 bit fixed point number. The first 32 bits specify the number of seconds since midnight on January 1, 1900, and the last 32 bits specify fractional parts of a second to a precision of about 200 picoseconds. The time tag value consisting of 63 zero bits followed by a one in the least signifigant bit is a special case meaning "immediately." In the L{TimeTagArgument} class, the timetag value is a float, or 'True' when 'Immediately' is meant. """ typeTag = "t" def __init__(self, value=True): Argument.__init__(self, value) def toBinary(self): if self.value is True: return struct.pack('>ll', 0, 1) fr, sec = math.modf(self.value) return struct.pack('>ll', long(sec), long(fr * 1e9)) @staticmethod def fromBinary(data): binary = data[0:8] if len(binary) != 8: raise OscError("Too few bytes left to get a timetag from %s." % (data)) leftover = data[8:] if binary == '\0\0\0\0\0\0\0\1': # immediately time = True else: high, low = struct.unpack(">ll", data[0:8]) time = float(int(high) + low / float(1e9)) return TimeTagArgument(time), leftover class BooleanArgument(Argument): """ An L{Argument} representing C{True} or C{False}. """ def __init__(self, value): Argument.__init__(self, value) if self.value: self.typeTag = "T" else: self.typeTag = "F" def toBinary(self): return "" # bool args do not have data, just a type tag def __bool__(self): return bool(self.value) class _DatalessArgument(Argument): """ Abstract L{Argument} class for defining arguments whose value is defined just by its type tag. This class should not be used directly. It is intended to gather common behaviour of L{NullArgument} and L{ImpulseArgument}. """ def __init__(self, ignoreValue=None): Argument.__init__(self, self.value) def toBinary(self): return "" class NullArgument(_DatalessArgument): """ An L{Argument} representing C{None}. """ typeTag = "N" value = None class ImpulseArgument(_DatalessArgument): """ An L{Argument} representing the C{"bang"} impulse. """ typeTag = "I" value = True # # Optional arguments # # Should we implement all types that are listed "optional" in # http://opensoundcontrol.org/spec-1_0 ? class _FourByteArgument(Argument): """ An abstract 32-bit L{Argument} whose data is a tuple of four integers in the range [0,255]. """ def __init__(self, value=(0, 0, 0, 0)): """ @param value: A tuple of four integers in the range [0,255]. @type value: C{tuple} """ Argument.__init__(self, value) def _check_type(self): if type(self.value) not in [list, tuple]: raise TypeError("Value %s must be a list of integers, not a %s." % (self.value, type(self.value).__name__)) if len(self.value) != 4: raise TypeError("Value %s must contain 4 elements." % (self.value)) for element in self.value: if type(element) not in [int, long]: raise TypeError("Element value %s must be an int, not a %s." % (element, type(element).__name__)) if element > 255 or element < 0: raise TypeError("Element value %s must be between 0 and 255." % (element)) def toBinary(self): """ See L{Argument.toBinary}. """ # self.value must be a list of 4 int in range [0, 255] return struct.pack(">4B", *self.value) @staticmethod def fromBinary(data): """ See L{Argument.fromBinary}. """ binary = data[0:4] if len(binary) != 4: raise OscError("Too few bytes left to get four from %s." % (data)) leftover = data[4:] try: values = struct.unpack(">4B", binary) except struct.error: raise OscError("Error trying to find four bytes of data in %s." % (binary)) return _FourByteArgument(values), leftover class ColorArgument(_FourByteArgument): """ An L{Argument} representing a 32-bit RGBA color. Color arguments are represented as a four-int tuple in the range [0,255]. Each of the color channels are in this order: red, green, blue, alpha. """ typeTag = "r" @staticmethod def fromBinary(data): tmp, leftover = _FourByteArgument.fromBinary(data) return ColorArgument(tmp.value), leftover class MidiArgument(_FourByteArgument): """ An L{Argument} representing a 32-bit MIDI message. MIDI "message" arguments contain 4 bytes and is represented as a four-int tuple. Bytes from most significant (left) to least significant (right) are: port id, status byte, data1, data2. """ typeTag = "m" @staticmethod def fromBinary(data): tmp, leftover = _FourByteArgument.fromBinary(data) return MidiArgument(tmp.value), leftover #class SymbolArgument(StringArgument): # typeTag = "S" #global dicts _types = { float: FloatArgument, str: StringArgument, int: IntArgument, bool: BooleanArgument, type(None): NullArgument, } _tags = { "b": BlobArgument, "f": FloatArgument, "i": IntArgument, "s": StringArgument, "t": TimeTagArgument, } def createArgument(value, type_tag=None): """ Creates an OSC argument, trying to guess its type if no type is given. Factory of *Attribute objects. @param value: Any Python base type. @param type_tag: One-letter string. One of C{"sifbTFNI"}. @type type_tag: One-letter string. @return: Returns an instance of one of the subclasses of the L{Argument} class. @rtype: L{Argument} subclass. """ global _types global _tags kind = type(value) if type_tag: # Get the argument type based on given type tag if type_tag == "T": return BooleanArgument(True) if type_tag == "F": return BooleanArgument(False) if type_tag == "N": return NullArgument() if type_tag == "I": return ImpulseArgument() if type_tag in _tags.keys(): return _tags[type_tag](value) raise OscError("Unknown type tag: %s" % type) else: # Guess the argument type based on the type of the value if kind in _types.keys(): return _types[kind](value) raise OscError("No OSC argument type for %s (value = %s)" % (kind, value)) # # private functions # def _ceilToMultipleOfFour(num): """ Rounds a number to the closest higher number that is a mulitple of four. That is for data that need to be padded with zeros so that the length of their data must be a multiple of 32 bits. """ return num + (4 - (num % 4)) def _argumentFromBinary(type_tag, data): if type_tag == "T": return BooleanArgument(True), data if type_tag == "F": return BooleanArgument(False), data if type_tag == "N": return NullArgument(), data if type_tag == "I": return ImpulseArgument(), data global _tags if type_tag not in _tags: raise OscError("Invalid typetag: %s" % type_tag) return _tags[type_tag].fromBinary(data) def _stringFromBinary(data): null_pos = string.find(data, "\0") # find the first null char value = data[0:null_pos] # get the first string out of data # find the position of the beginning of the next data leftover = data[_ceilToMultipleOfFour(null_pos):] return value, leftover def _elementFromBinary(data): if data[0] == "/": element, data = Message.fromBinary(data) elif data[0] == "#": element, data = Bundle.fromBinary(data) else: raise OscError("Error parsing OSC data: " + data) return element python-txosc-0.2.0/txosc/__init__.py0000644000000000000000000000020111445141512016126 0ustar rootroot#!/usr/bin/env python """ txosc: Open Sound Control for Twisted """ __all__ = ["async", "dispatch", "osc"] __version__ = "0.2.0" python-txosc-0.2.0/txosc/sync.py0000644000000000000000000000714211445141512015356 0ustar rootroot #!/usr/bin/env python # Copyright (c) 2009 Alexandre Quessy, Arjan Scherpenisse # See LICENSE for details. # TODO: # -*- test-case-name: txosc.test.test_sync -*- """ Synchronous blocking OSC sender without Twisted. Twisted is not used in this file. You don't even need to repy on Twisted to use it and the txosc.osc module. That is enough to send OSC messages in a simple script. """ import socket import struct #TODO: receiver #TODO: bidirectional sender-receiver # self._socket.recv(self.buffer_size) # self.buffer_size = 1024 class _Sender(object): def __init__(self): self._socket = None def send(self, element): binary = element.toBinary() self._actually_send(binary) def _actually_send(self, binary_data): """ @param binary_data: Binary blob of an element to send. """ raise NotImplementedError("This method must be overriden in child classes.") def close(self): raise NotImplementedError("This method must be overriden in child classes.") class TcpSender(_Sender): """ Send OSC over TCP using low-level Python socket tools. """ def __init__(self, address, port): _Sender.__init__(self) self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.address = address self.port = port self._socket.connect((self.address, self.port)) def _actually_send(self, binary_data): #For TCP, we need to pack the data with its size first data = struct.pack(">i", len(binary_data)) + binary_data self._socket.send(data) def close(self): self._socket.close() UDP_MODE_MULTICAST = "multicast" UDP_MODE_BROADCAST = "broadcast" class UdpSender(_Sender): """ Uses UDP. Mode can be either UDP_MODE_BROADCAST or UDP_MODE_MULTICAST or None. If using UDP_MODE_MULTICAST, you must set the multicast_group. FIXME: Right now, the data it sends is badly formatted. """ def __init__(self, address, port, mode=None, multicast_group=None): """ @param multicast_group: IP of the multicast group. @type multicast_group: C{str} """ _Sender.__init__(self) self._socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self.address = socket.gethostbyname(address) self.port = port self._socket.bind(('', 0)) self.mode = mode self.multicast_group = None if self.mode == UDP_MODE_MULTICAST: if multicast_group is None: raise RuntimeError("You must set the multicast group.") self.multicast_group = multicast_group ttl = struct.pack('b', 1) self._socket.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, ttl) # TODO elif self.mode == UDP_MODE_BROADCAST: if multicast_group is not None: raise RuntimeError("Not using the multicast mode.") self._socket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) else: if multicast_group is not None: raise RuntimeError("Not using the multicast mode.") def _actually_send(self, binary_data): # For UDP, we just send the data. # No need to pack it with its size. if self.mode == UDP_MODE_BROADCAST: self._socket.sendto(binary_data, ('', self.port)) elif self.mode == UDP_MODE_MULTICAST: self._socket.sendto(binary_data, (self.multicast_group, self.port)) else: self._socket.sendto(binary_data, (self.address, self.port)) def close(self): self._socket.close() python-txosc-0.2.0/txosc/async.py0000644000000000000000000001244011445141512015514 0ustar rootroot#!/usr/bin/env python # -*- test-case-name: txosc.test.test_async -*- # Copyright (c) 2009 Alexandre Quessy, Arjan Scherpenisse # See LICENSE for details. """ Asynchronous OSC sender and receiver using Twisted """ import struct import socket from twisted.internet import defer, protocol from twisted.application.internet import MulticastServer from txosc.osc import * from txosc.osc import _elementFromBinary # # Stream based client/server protocols # class StreamBasedProtocol(protocol.Protocol): """ OSC over TCP sending and receiving protocol. """ def connectionMade(self): self.factory.connectedProtocol = self if hasattr(self.factory, 'deferred'): self.factory.deferred.callback(True) self._buffer = "" self._pkgLen = None def dataReceived(self, data): """ Called whenever data is received. In a stream-based protocol such as TCP, the stream should begin with an int32 giving the size of the first packet, followed by the contents of the first packet, followed by the size of the second packet, etc. @type data: L{str} """ self._buffer += data if len(self._buffer) < 4: return if self._pkgLen is None: self._pkgLen = struct.unpack(">i", self._buffer[:4])[0] if len(self._buffer) < self._pkgLen + 4: print "waiting for %d more bytes" % (self._pkgLen + 4 - len(self._buffer)) return payload = self._buffer[4:4 + self._pkgLen] self._buffer = self._buffer[4 + self._pkgLen:] self._pkgLen = None if payload: element = _elementFromBinary(payload) self.factory.gotElement(element) if len(self._buffer): self.dataReceived("") def send(self, element): """ Send an OSC element over the TCP wire. @param element: L{txosc.osc.Message} or L{txosc.osc.Bundle} """ binary = element.toBinary() self.transport.write(struct.pack(">i", len(binary)) + binary) #TODO: return a Deferred class StreamBasedFactory(object): """ Factory object for the sending and receiving of elements in a stream-based protocol (e.g. TCP, serial). @ivar receiver: A L{Receiver} object which is used to dispatch incoming messages to. @ivar connectedProtocol: An instance of L{StreamBasedProtocol} representing the current connection. """ receiver = None connectedProtocol = None def __init__(self, receiver=None): if receiver: self.receiver = receiver def send(self, element): self.connectedProtocol.send(element) def gotElement(self, element): if self.receiver: self.receiver.dispatch(element, self) else: raise OscError("Element received, but no Receiver in place: " + str(element)) def __str__(self): return str(self.connectedProtocol.transport.client) class ClientFactory(protocol.ClientFactory, StreamBasedFactory): """ TCP client factory """ protocol = StreamBasedProtocol def __init__(self, receiver=None): StreamBasedFactory.__init__(self, receiver) self.deferred = defer.Deferred() class ServerFactory(protocol.ServerFactory, StreamBasedFactory): """ TCP server factory """ protocol = StreamBasedProtocol # # Datagram client/server protocols # class DatagramServerProtocol(protocol.DatagramProtocol): """ The UDP OSC server protocol. @ivar receiver: The L{Receiver} instance to dispatch received elements to. """ def __init__(self, receiver): """ @param receiver: L{Receiver} instance. """ self.receiver = receiver def datagramReceived(self, data, (host, port)): element = _elementFromBinary(data) self.receiver.dispatch(element, (host, port)) class MulticastDatagramServerProtocol(DatagramServerProtocol): """ UDP OSC server protocol that can listen to multicast. Here is an example on how to use it: reactor.listenMulticast(8005, MulticastServerUDP(receiver, "224.0.0.1"), listenMultiple=True) This way, many listeners can listen on the same port, same host, to the same multicast group. (in this case, the 224.0.0.1 multicast group) """ def __init__(self, receiver, multicast_addr="224.0.0.1"): """ @param multicast_addr: IP address of the multicast group. @param receiver: L{txosc.dispatch.Receiver} instance. @type multicast_addr: str @type receiver: L{txosc.dispatch.Receiver} """ self.multicast_addr = multicast_addr DatagramServerProtocol.__init__(self, receiver) def startProtocol(self): """ Join a specific multicast group, which is the IP we will respond to """ self.transport.joinGroup(self.multicast_addr) class DatagramClientProtocol(protocol.DatagramProtocol): """ The UDP OSC client protocol. """ def send(self, element, (host, port)): """ Send a L{txosc.osc.Message} or L{txosc.osc.Bundle} to the address specified. @type element: L{txosc.osc.Message} """ data = element.toBinary() self.transport.write(data, (socket.gethostbyname(host), port)) python-txosc-0.2.0/ChangeLog0000644000000000000000000013175611445141512014453 0ustar rootrootchangeset: 233:8fb65b3cb75c branch: 0.1 tag: tip user: Alexandre Quessy date: Tue Aug 17 17:20:13 2010 -0400 summary: updated RELEASE notes changeset: 232:2d63e034bdcc branch: 0.1 user: Alexandre Quessy date: Tue Aug 17 12:34:14 2010 -0400 summary: updated RELEASE notes changeset: 231:f3edd2f29859 branch: 0.1 user: Alexandre Quessy date: Tue Aug 17 12:17:08 2010 -0400 summary: osc-send now support not using twisted. changeset: 230:7d75bf57b806 branch: 0.1 user: Alexandre Quessy date: Tue Aug 17 11:13:04 2010 -0400 summary: osc-send: separated the message generation from actually sending it changeset: 229:70acc42a37e7 branch: 0.1 user: Alexandre Quessy date: Tue Aug 17 11:03:43 2010 -0400 summary: Moved the options into a small struct/class changeset: 228:d47a44475f5d branch: 0.1 user: Alexandre Quessy date: Tue Aug 03 15:04:55 2010 -0400 summary: renamed some stuff in osc-send, since I plan to implement it without twisted as well... changeset: 227:84910ba41eb6 branch: 0.1 user: Alexandre Quessy date: Fri Jul 30 13:13:46 2010 -0400 summary: Fixed the synchronous sender binary format. changeset: 226:25b10f2335d6 branch: 0.1 user: Alexandre Quessy date: Fri Jul 30 13:02:29 2010 -0400 summary: some spacing changeset: 225:8b525fb69985 branch: 0.1 user: Alexandre Quessy date: Fri Jul 30 12:53:13 2010 -0400 summary: made osc-send less verbose changeset: 224:38a0aba5b76a branch: 0.1 user: Alexandre Quessy date: Fri Jul 23 12:14:05 2010 -0400 summary: Addin a non-wroking blocking UDP sender. (it doesn't work!!) changeset: 223:0f304c253ee7 branch: 0.1 user: Alexandre Quessy date: Fri Jul 23 10:06:58 2010 -0400 summary: indented some lines in README changeset: 222:f3cec2e8d443 branch: 0.1 user: Alexandre Quessy date: Fri Jul 23 09:30:07 2010 -0400 summary: updated RELEASE notes changeset: 221:a7bd63d7a6e5 branch: 0.1 user: Alexandre Quessy date: Fri Jul 23 08:17:25 2010 -0400 summary: updated README for the sync_ examples. changeset: 220:aa45338ccb42 branch: 0.1 user: Alexandre Quessy date: Fri Jul 23 08:15:22 2010 -0400 summary: made an example executable changeset: 219:55511bea6957 branch: 0.1 user: Alexandre Quessy date: Fri Jul 23 08:14:26 2010 -0400 summary: catching socket errors in sync_tcp_sender changeset: 218:99f827dc7b3a branch: 0.1 user: Alexandre Quessy date: Fri Jul 23 08:08:46 2010 -0400 summary: added txosc/sync.py and the sync_tcp_sender example. changeset: 217:2ebf9d710e9a branch: 0.1 user: Alexandre Quessy date: Mon Jul 19 11:43:01 2010 -0400 summary: improved doc for ColorArgument changeset: 216:99a0eef582e2 branch: 0.1 user: Alexandre Quessy date: Mon Jul 19 11:41:33 2010 -0400 summary: improved doc for MidiArgument changeset: 215:da5a5f86e3fe branch: 0.1 user: Alexandre Quessy date: Mon Jul 19 11:38:01 2010 -0400 summary: updated version to 0.1.6 - not yet released changeset: 214:edaf6316f624 branch: 0.1 user: Alexandre Quessy date: Mon Jul 19 11:36:47 2010 -0400 summary: Added tag 0.1.5 for changeset dca38c8dbe9c changeset: 213:dca38c8dbe9c branch: 0.1 tag: 0.1.5 user: Alexandre Quessy date: Mon Jul 19 11:28:20 2010 -0400 summary: update man page for osc-send changeset: 212:4f585f63ac7e branch: 0.1 user: Alexandre Quessy date: Mon Jul 19 11:22:58 2010 -0400 summary: updated RELEASE notes changeset: 211:b22c9ddea712 branch: 0.1 user: Alexandre Quessy date: Mon Jul 19 11:18:48 2010 -0400 summary: implemented the MidiArgument class changeset: 210:126f37b9927a branch: 0.1 user: Alexandre Quessy date: Mon Jul 19 10:46:23 2010 -0400 summary: validating arguments and returning 1 in case of error changeset: 209:d5119e294c65 branch: 0.1 user: Alexandre Quessy date: Mon Jul 19 10:22:53 2010 -0400 summary: osc-send now requires a path changeset: 208:3905e58dc375 branch: 0.1 user: Alexandre Quessy date: Tue Jul 13 12:43:57 2010 -0400 summary: Implemented the ColorArgument class changeset: 207:5a8f9af77628 branch: 0.1 user: Alexandre Quessy date: Wed Jun 30 15:54:27 2010 -0400 summary: updated to 0.1.5 - not yet released changeset: 206:45eeb4bf8ed4 branch: 0.1 user: Alexandre Quessy date: Wed Jun 30 15:53:06 2010 -0400 summary: Added tag 0.1.4 for changeset 039fe3995600 changeset: 205:039fe3995600 branch: 0.1 tag: 0.1.4 user: Alexandre Quessy date: Wed Jun 30 15:46:56 2010 -0400 summary: added --no-discard-stderr to the help2man command call changeset: 204:9592eed30e4c branch: 0.1 user: Alexandre Quessy date: Wed Jun 30 14:49:13 2010 -0400 summary: updated date in ChangeLog changeset: 203:451186d4cac7 branch: 0.1 user: Alexandre Quessy date: Wed Jun 30 14:47:30 2010 -0400 summary: added the _check_type method, which does type checking when instanciating the arguments. changeset: 202:91dbaa35f007 branch: 0.1 user: Alexandre Quessy date: Wed Jun 30 14:42:04 2010 -0400 summary: Implemented TCP and multicast UDP in osc-receive changeset: 201:b9657a7d85cc branch: 0.1 user: Alexandre Quessy date: Wed Jun 30 14:29:24 2010 -0400 summary: fixed typo changeset: 200:760ccfae89e0 branch: 0.1 user: Alexandre Quessy date: Wed Jun 30 14:13:14 2010 -0400 summary: Improved the synopsis in the man pages. changeset: 199:d9e0c6324600 branch: 0.1 user: Alexandre Quessy date: Wed Jun 30 14:06:17 2010 -0400 summary: Implemented osc URL and comma-prefixed type tag support in osc-send. changeset: 198:668e1ea56d5a branch: 0.1 user: Alexandre Quessy date: Wed Jun 30 13:46:30 2010 -0400 summary: Implemented TCP in osc-send + added a fallback to examples/async_tcp_receiver.py changeset: 197:d1446066dba9 branch: 0.1 user: Alexandre Quessy date: Wed Jun 30 13:39:19 2010 -0400 summary: Now checking for help2man prior to call it. changeset: 196:d32d3b60f547 branch: 0.1 user: Alexandre Quessy date: Wed Jun 30 13:35:46 2010 -0400 summary: making sure the man page text file exist prior to call help2man changeset: 195:71e0b2120059 branch: 0.1 user: Alexandre Quessy date: Wed Jun 30 13:34:20 2010 -0400 summary: Now creating the man pages changeset: 194:0812fcbdaaaf branch: 0.1 user: Alexandre Quessy date: Tue Jun 29 09:15:40 2010 -0400 summary: adding the OSC site URL. changeset: 193:9099a9b8f5e0 branch: 0.1 user: Alexandre Quessy date: Tue Jun 29 09:14:30 2010 -0400 summary: adding man-osc-send.txt for a nice man page changeset: 192:09ea090302a2 branch: 0.1 user: Alexandre Quessy date: Tue Jun 29 08:30:23 2010 -0400 summary: Renamed osc-recv to osc-receive. Made osc-send faster. changeset: 191:81f1fb9285cb branch: 0.1 user: Alexandre Quessy date: Tue Jun 29 03:53:09 2010 -0400 summary: updated RELEASE notes changeset: 190:bdd88d2b5ea2 branch: 0.1 user: Alexandre Quessy date: Tue Jun 29 03:51:38 2010 -0400 summary: added the scripts to the setup.py install script changeset: 189:72c4984a9e50 branch: 0.1 user: Alexandre Quessy date: Tue Jun 29 03:49:50 2010 -0400 summary: added osc-recv changeset: 188:ce78693e492b branch: 0.1 user: Alexandre Quessy date: Tue Jun 29 03:39:28 2010 -0400 summary: Fixed type checking in the IntArgument.toBinary method changeset: 187:2337b87939ea branch: 0.1 user: Alexandre Quessy date: Tue Jun 29 03:38:21 2010 -0400 summary: Fixed the manual mode when using int or float types in osc-send changeset: 186:46ec448f364d branch: 0.1 user: Alexandre Quessy date: Tue Jun 29 03:14:53 2010 -0400 summary: added the osc-send script changeset: 185:4e5cd902f419 branch: 0.1 user: Alexandre Quessy date: Mon Jun 28 14:06:57 2010 -0400 summary: removed the Beta classifier changeset: 184:3b5ad5ddaf6d branch: 0.1 user: Alexandre Quessy date: Mon Jun 28 13:01:37 2010 -0400 summary: updated version number to 0.1.4 - not yet released changeset: 183:0c8bf1c7c264 branch: 0.1 user: Alexandre Quessy date: Mon Jun 28 13:00:08 2010 -0400 summary: Added tag 0.1.3 for changeset 34713e095128 changeset: 182:34713e095128 branch: 0.1 tag: 0.1.3 user: Alexandre Quessy date: Mon Jun 28 12:50:42 2010 -0400 summary: updated RELEASE and NEWS changeset: 181:e2c68904e875 branch: 0.1 user: Alexandre Quessy date: Mon Jun 28 12:48:55 2010 -0400 summary: updated ChangeLog changeset: 180:7a713c9e8511 branch: 0.1 user: Alexandre Quessy date: Mon Jun 28 12:46:53 2010 -0400 summary: updated RELEASE changeset: 179:665eff0bf3fe branch: 0.1 user: Alexandre Quessy date: Mon Jun 28 12:41:49 2010 -0400 summary: updated README changeset: 178:d57874f87fea branch: 0.1 user: Alexandre Quessy date: Mon Jun 28 12:40:08 2010 -0400 summary: renamed TxOSC for txosc, lowercase changeset: 177:b08d66232166 branch: 0.1 user: Alexandre Quessy date: Mon Jun 28 12:21:25 2010 -0400 summary: added osc.getAddressParts changeset: 176:5d063ba580ce branch: 0.1 user: Alexandre Quessy date: Mon Jun 28 11:59:19 2010 -0400 summary: added Message.getValues and __float__ and __int__ cast operators. changeset: 175:763c56d7f94f branch: 0.1 user: Alexandre Quessy date: Wed Jun 16 09:51:36 2010 -0400 summary: added classifier to setup.py changeset: 174:cbda02700875 branch: 0.1 user: Alexandre Quessy date: Wed Jun 16 09:20:20 2010 -0400 summary: updated version to 0.1.3 - not yet released changeset: 173:864ff49e53bd branch: 0.1 user: Alexandre Quessy date: Wed Jun 16 09:05:39 2010 -0400 summary: Added tag 0.1.2 for changeset d78785d76287 changeset: 172:d78785d76287 branch: 0.1 tag: 0.1.2 user: Alexandre Quessy date: Wed Jun 16 09:05:36 2010 -0400 summary: removed tag 0.1.2. Redoing it. changeset: 171:3d2c42e98f97 branch: 0.1 user: Alexandre Quessy date: Wed Jun 16 09:05:01 2010 -0400 summary: updated NEWS and RELEASE for 0.1.2 changeset: 170:6152c7080ef3 branch: 0.1 user: Alexandre Quessy date: Wed Jun 16 09:03:43 2010 -0400 summary: Added tag 0.1.2 for changeset 25c6e53f87d1 changeset: 169:25c6e53f87d1 branch: 0.1 user: Alexandre Quessy date: Tue Jun 15 21:52:30 2010 -0400 summary: added setFallback to Receiver changeset: 168:2dc0180d40a6 branch: 0.1 user: Alexandre Quessy date: Tue Jun 15 21:44:04 2010 -0400 summary: added a test for fallbacks when an address node is nested in a receiver. changeset: 167:48c48b368b79 branch: 0.1 user: Alexandre Quessy date: Tue Jun 15 12:41:05 2010 -0400 summary: added tests for fallbacks and improved doc strings a lot. changeset: 166:3ef9aec6812b branch: 0.1 user: Alexandre Quessy date: Tue Jun 15 11:40:59 2010 -0400 summary: Added TestMulticastClientServer in test_async.py changeset: 165:48373206cae1 branch: 0.1 parent: 164:81cd0eefdcf4 parent: 142:f107627930d8 user: Alexandre Quessy date: Mon Jun 14 21:23:14 2010 -0400 summary: Merged and applied as a comment changeset: 164:81cd0eefdcf4 branch: 0.1 user: Alexandre Quessy date: Mon Jun 14 17:54:16 2010 -0400 summary: added a comment. changeset: 163:3880386ec14d branch: 0.1 parent: 157:b23c2b11f8c4 user: Alexandre Quessy date: Mon Jun 14 17:45:02 2010 -0400 summary: Added a Multicast UDP server class and examples. changeset: 162:673e58b4e768 branch: debian user: Alexandre Quessy date: Wed Jun 09 22:32:59 2010 -0400 summary: improved debian/copyright file a lot changeset: 161:7d2860a51515 branch: debian user: Alexandre Quessy date: Wed Jun 09 22:24:21 2010 -0400 summary: Must remove LICENSE from Debian docs. changeset: 160:a43ef8a3b6f3 branch: debian user: Alexandre Quessy date: Wed Jun 09 22:23:00 2010 -0400 summary: got to remove INSTALL file from Debian docs changeset: 159:f9a1356c5c27 branch: debian user: Alexandre Quessy date: Wed Jun 09 22:18:14 2010 -0400 summary: Adding quilt format and watch file to satisfy lintian. changeset: 158:2a1f7d866927 branch: debian parent: 153:1683ecdaa2f3 user: Alexandre Quessy date: Wed Jun 09 22:13:55 2010 -0400 summary: update in the debian packaging changeset: 157:b23c2b11f8c4 branch: 0.1 user: Alexandre Quessy date: Wed Jun 09 22:05:45 2010 -0400 summary: updated version to 0.1.2 - not yet released changeset: 156:b06fc0a7ea72 branch: 0.1 user: Alexandre Quessy date: Wed Jun 09 22:04:49 2010 -0400 summary: Added tag 0.1.1 for changeset 3cfcf12a1649 changeset: 155:3cfcf12a1649 branch: 0.1 tag: 0.1.1 user: Alexandre Quessy date: Wed Jun 09 22:04:39 2010 -0400 summary: updated ChangeLog changeset: 154:cc43504145b8 branch: 0.1 parent: 152:2f9b07e29a6c user: Alexandre Quessy date: Wed Jun 09 22:03:01 2010 -0400 summary: updated NEWS and RELEASE changeset: 153:1683ecdaa2f3 branch: debian parent: 141:c09b50d451a3 user: Alexandre Quessy date: Wed Jun 09 22:01:19 2010 -0400 summary: put the ITP bug number in changelog changeset: 152:2f9b07e29a6c branch: 0.1 user: Alexandre Quessy date: Wed Jun 09 21:59:15 2010 -0400 summary: It's better to give the whole connected protocol to the user when he receives a TCP message. changeset: 151:9c16b131b142 branch: 0.1 user: Alexandre Quessy date: Wed Jun 09 21:52:18 2010 -0400 summary: Getting a tuple of (host, address) as a second arg when using a TCP receiver. changeset: 150:dac1e886631e branch: 0.1 user: Alexandre Quessy date: Wed Jun 09 01:13:52 2010 -0400 summary: added a wildcard in udp receive example changeset: 149:b3a35deb9114 branch: 0.1 user: Alexandre Quessy date: Wed Jun 09 01:07:50 2010 -0400 summary: adding example/ping_pong.py: an example that sends+receives! changeset: 148:cca910590709 branch: 0.1 user: Alexandre Quessy date: Wed Jun 09 00:49:41 2010 -0400 summary: Small style correction in library files. changeset: 147:5cce1db0edba branch: 0.1 user: Alexandre Quessy date: Wed Jun 09 00:42:30 2010 -0400 summary: updated RELEASE file. changeset: 146:7e23b79e4b9e branch: 0.1 user: Alexandre Quessy date: Wed Jun 09 00:40:50 2010 -0400 summary: updated version number to 0.1.1... not yet released it though changeset: 145:9868007d114e branch: 0.1 user: Alexandre Quessy date: Wed Jun 09 00:38:28 2010 -0400 summary: Improved comments in the .pd patch. changeset: 144:1ff8b2f3bd10 branch: 0.1 user: Alexandre Quessy date: Wed Jun 09 00:35:37 2010 -0400 summary: added pd_sender.pd in the examples changeset: 143:19b1a17490c8 branch: 0.1 parent: 138:891840611653 user: Alexandre Quessy date: Wed Jun 09 00:31:04 2010 -0400 summary: Merged the async_udp examples with the former oscclient and oscserver examples. changeset: 142:f107627930d8 branch: 0.1 parent: 138:891840611653 user: Alexandre Quessy date: Tue Jun 08 17:41:15 2010 -0400 summary: Don't know if this is right: added getParent and getChildren changeset: 141:c09b50d451a3 branch: debian user: Alexandre Quessy date: Tue Jun 08 15:11:46 2010 -0400 summary: using lucid changelog for now. changeset: 140:20aeb255c78a branch: debian user: Alexandre Quessy date: Tue Jun 08 15:08:21 2010 -0400 summary: Fin in rules (bad package name!) changeset: 139:21b7fa31233f branch: debian parent: 130:2058c60c6ca2 user: Alexandre Quessy date: Tue Jun 08 15:03:18 2010 -0400 summary: added missing dep changeset: 138:891840611653 branch: 0.1 user: Alexandre Quessy date: Tue Jun 08 14:51:13 2010 -0400 summary: Added tag 0.1.0 for changeset eb22777a3dc3 changeset: 137:eb22777a3dc3 branch: 0.1 tag: 0.1.0 user: Alexandre Quessy date: Tue Jun 08 14:50:42 2010 -0400 summary: Moved ChangeLog to NEWS. Added RELEASE changeset: 136:18894a433289 branch: 0.1 user: Alexandre Quessy date: Tue Jun 08 14:41:54 2010 -0400 summary: updated ChangeLog and added __all__ in __init__.py changeset: 135:b09c5845db67 branch: 0.1 parent: 134:855167d5c155 parent: 133:daee842dc056 user: Arjan Scherpenisse date: Tue Jun 08 17:36:46 2010 +0200 summary: merged changeset: 134:855167d5c155 branch: 0.1 parent: 129:ae3db60a0753 user: Arjan Scherpenisse date: Tue Jun 08 17:34:05 2010 +0200 summary: Removed 2 ugly examples. changeset: 133:daee842dc056 branch: 0.1 user: Alexandre Quessy date: Tue Jun 08 11:25:29 2010 -0400 summary: revert my tag changeset: 132:08e71ee33113 branch: 0.1 parent: 131:46fff436f81e parent: 129:ae3db60a0753 user: Alexandre Quessy date: Tue Jun 08 11:25:05 2010 -0400 summary: merged changeset: 131:46fff436f81e branch: 0.1 parent: 128:fdba9b50c346 user: Alexandre Quessy date: Tue Jun 08 11:24:30 2010 -0400 summary: Added tag 0.1.0 for changeset fdba9b50c346 changeset: 130:2058c60c6ca2 branch: debian parent: 127:66ae2f1fbde2 user: Alexandre Quessy date: Tue Jun 08 11:10:06 2010 -0400 summary: fix in Debian packaging changeset: 129:ae3db60a0753 branch: 0.1 user: Arjan Scherpenisse date: Tue Jun 08 17:18:36 2010 +0200 summary: Updated examples/osc{server,client}.py to work again with new modules. changeset: 128:fdba9b50c346 branch: 0.1 parent: 124:1339c7174104 user: Alexandre Quessy date: Tue Jun 08 10:57:38 2010 -0400 summary: I like when tags have major.minor.micro version. changeset: 127:66ae2f1fbde2 branch: debian user: Alexandre Quessy date: Tue Jun 08 10:56:31 2010 -0400 summary: added ChangeLog in doc changeset: 126:eeedac67ba08 branch: debian user: Alexandre Quessy date: Tue Jun 08 10:55:21 2010 -0400 summary: initial packaging - maybe not working yet changeset: 125:f9bf5ff6eed6 branch: debian user: Alexandre Quessy date: Tue Jun 08 10:32:42 2010 -0400 summary: removed everything from the debian branch changeset: 124:1339c7174104 branch: 0.1 user: Alexandre Quessy date: Tue Jun 08 10:27:49 2010 -0400 summary: made examples executable changeset: 123:706d093bcd08 branch: 0.1 user: Alexandre Quessy date: Tue Jun 08 10:27:28 2010 -0400 summary: Re-adding oscclient.py and oscserver.py examples. changeset: 122:fe803bdc3e44 branch: 0.1 user: Alexandre Quessy date: Tue Jun 08 10:16:27 2010 -0400 summary: updated project URL and added mailing list changeset: 121:a5b5a807da86 branch: 0.1 user: Alexandre Quessy date: Tue Jun 08 10:00:55 2010 -0400 summary: added a TODO changeset: 120:75d1915dd93e branch: 0.1 user: Alexandre Quessy date: Tue Jun 08 10:00:05 2010 -0400 summary: Added working TCP examples changeset: 119:15b2f6d708cd branch: 0.1 user: Alexandre Quessy date: Tue Jun 08 09:37:32 2010 -0400 summary: added async UDP examples. changeset: 118:46e24edcaa7d branch: 0.1 user: Alexandre Quessy date: Tue Jun 08 09:00:03 2010 -0400 summary: adding ChangeLog changeset: 117:cbd89d2c3c3c branch: 0.1 user: Alexandre Quessy date: Tue Jun 08 08:57:00 2010 -0400 summary: fixed comments changeset: 116:886ebf7a78f2 branch: 0.1 user: Alexandre Quessy date: Tue Jun 08 08:51:33 2010 -0400 summary: splitted the tests as well changeset: 115:47066478f48f branch: 0.1 user: Alexandre Quessy date: Tue Jun 08 08:47:07 2010 -0400 summary: splitted osc.py into dispatch.py and async.py changeset: 114:0ebd6ed7ecab branch: 0.1 user: Alexandre Quessy date: Tue Jun 08 08:33:20 2010 -0400 summary: better comments changeset: 113:2aac5e83629e branch: 0.1 user: Alexandre Quessy date: Tue Jun 08 08:31:29 2010 -0400 summary: fixes in the epydoc command line changeset: 112:862336fb58f0 branch: 0.1 user: Alexandre Quessy date: Tue Jun 08 08:26:35 2010 -0400 summary: added README and INSTALL changeset: 111:ad3023757e8e branch: 0.1 user: Alexandre Quessy date: Mon Jun 07 18:19:54 2010 -0400 summary: modif ignored files changeset: 110:82ae304a2528 branch: 0.1 parent: 108:bca7c6899af9 user: Alexandre Quessy date: Mon Jun 07 18:06:06 2010 -0400 summary: added setup.py for txosc changeset: 109:44620d2f984d branch: twisted-osc parent: 106:3d84a3dcac42 user: Alexandre Quessy date: Mon Jun 07 18:01:14 2010 -0400 summary: Dummy commit, just to create a new head. changeset: 108:bca7c6899af9 branch: 0.1 user: Alexandre Quessy date: Mon Jun 07 18:00:06 2010 -0400 summary: fixed text-case-name changeset: 107:4a6fce0be214 branch: twosc user: Alexandre Quessy date: Mon Jun 07 17:56:10 2010 -0400 summary: Removed all the Twisted library and made txosc standalone. changeset: 106:3d84a3dcac42 parent: 104:40c0ad69b3ff parent: 105:f2483f0639d8 user: Alexandre Quessy date: Wed Mar 24 01:53:50 2010 -0400 summary: merged changeset: 105:f2483f0639d8 parent: 103:a26c476a005e user: Arjan Scherpenisse date: Fri Jan 22 11:39:55 2010 +0100 summary: Added test with liblo sender. changeset: 104:40c0ad69b3ff parent: 68:5af56b61e753 parent: 103:a26c476a005e user: Alexandre Quessy date: Thu Jan 21 22:13:26 2010 -0500 summary: merged changeset: 103:a26c476a005e parent: 102:1083c70eab59 parent: 98:4c4a005f4de6 user: Arjan Scherpenisse date: Thu Jan 21 21:54:41 2010 +0100 summary: Merged changeset: 102:1083c70eab59 user: Arjan Scherpenisse date: Thu Jan 21 21:44:33 2010 +0100 summary: Added TCP server and client tests. changeset: 101:2756083ef5ee user: Arjan Scherpenisse date: Thu Jan 21 21:16:12 2010 +0100 summary: Added stream-based OSC support (TCP). changeset: 100:73604e775e70 user: Arjan Scherpenisse date: Tue Jan 19 20:10:01 2010 +0100 summary: Fixed duplicate method name changeset: 99:1e9da21fff3a parent: 97:5a2df6c58542 user: Arjan Scherpenisse date: Tue Jan 19 20:09:07 2010 +0100 summary: Rewrite of pattern matching according to regex; removeCallbacks rewrite (start) changeset: 98:4c4a005f4de6 user: Alexandre Quessy date: Tue Jan 19 22:06:55 2010 -0500 summary: TCP implementation not working. Skipping test. More to do later. changeset: 97:5a2df6c58542 user: Alexandre Quessy date: Tue Jan 19 08:34:45 2010 -0500 summary: Starting to code a TCP sender/receiver. Added the skipped unit test to test it. changeset: 96:ea354a4dc3a1 user: Arjan Scherpenisse date: Mon Jan 18 15:03:26 2010 +0100 summary: Prefer `assertEquals` over `assertEqual`. See twisted #4204. changeset: 95:dea0986f164f user: Arjan Scherpenisse date: Sun Jan 17 15:34:08 2010 +0100 summary: 100% code coverage in test. changeset: 94:850cf949f573 parent: 93:1618f013426a parent: 92:f720e6684d9f user: Arjan Scherpenisse date: Sun Jan 17 14:50:54 2010 +0100 summary: Merged changeset: 93:1618f013426a parent: 88:b9f1b74c3159 user: Arjan Scherpenisse date: Sun Jan 17 14:47:34 2010 +0100 summary: Implemented range matching for address nodes. changeset: 92:f720e6684d9f user: Alexandre Quessy date: Mon Jan 11 02:49:30 2010 -0500 summary: Updated AddressNode's doc so that I can understand it. changeset: 91:7d7eb5c5b701 user: Alexandre Quessy date: Mon Jan 11 02:33:14 2010 -0500 summary: Improved examples by adding sub-nodes and arguments. changeset: 90:2d34356b38a1 user: Alexandre Quessy date: Mon Jan 11 02:14:17 2010 -0500 summary: Fixed what I assumed to be a typo in a comment. changeset: 89:6e4c37416cb5 user: Alexandre Quessy date: Mon Jan 11 02:11:55 2010 -0500 summary: Fixed timetag arg parsing. Improved examples. Changes testing UDP port number. changeset: 88:b9f1b74c3159 user: Arjan Scherpenisse date: Thu Jan 07 13:54:03 2010 +0100 summary: Cleaned up the OSC client/server examples. changeset: 87:c11018f22f85 user: Arjan Scherpenisse date: Thu Jan 07 12:17:27 2010 +0100 summary: More test coverage, now at 99%. changeset: 86:ef637559c7eb user: Arjan Scherpenisse date: Thu Jan 07 10:16:28 2010 +0100 summary: Added Bundle.add function; tweaked docstrings and whitespaces some more. changeset: 85:a9f209986c1d user: Arjan Scherpenisse date: Sun Jan 03 19:01:33 2010 +0100 summary: Variable renaming; cleanups changeset: 84:8956b638f03d user: Arjan Scherpenisse date: Sun Jan 03 18:53:04 2010 +0100 summary: Reworked Receiver to be a subclass of AddressNode. changeset: 83:77938f8971e9 user: Arjan Scherpenisse date: Sat Jan 02 20:09:47 2010 +0100 summary: Docstrings and implemented removeAllCallbacks. changeset: 82:1db87e0e1cea user: Alexandre Quessy on plouf date: Sat Jan 02 09:17:58 2010 -0500 summary: added html/ to .hgignore changeset: 81:a0e279dfbcf6 user: Alexandre Quessy on plouf date: Sat Jan 02 09:16:44 2010 -0500 summary: Corrected doc string in the epydoc style. changeset: 80:6ce80ddc1a53 user: Alexandre Quessy on plouf date: Sat Jan 02 09:09:33 2010 -0500 summary: Added doc to osc.py changeset: 79:158336969577 user: Arjan Scherpenisse date: Sat Jan 02 13:21:32 2010 +0100 summary: Test sending/receiving of simple message changeset: 78:f8b80734d04e user: Arjan Scherpenisse date: Sat Jan 02 13:01:19 2010 +0100 summary: OscSender -> Sender, and started with client/server unit tests. changeset: 77:018bbc4068e9 user: Arjan Scherpenisse date: Sat Jan 02 12:45:33 2010 +0100 summary: Documentation cleanups; rename AddressSpace to Receiver, fix examples. changeset: 76:4f5e0a0532d2 user: Arjan Scherpenisse date: Fri Jan 01 23:26:28 2010 +0100 summary: Fixed copyright in files changeset: 75:18f5922d4c09 user: Arjan Scherpenisse date: Fri Jan 01 18:37:54 2010 +0100 summary: More testing changeset: 74:6f74aab2be60 user: Arjan Scherpenisse date: Fri Jan 01 18:31:52 2010 +0100 summary: Implemented dispatching changeset: 73:6345eda9c78f user: Arjan Scherpenisse date: Fri Jan 01 18:17:47 2010 +0100 summary: Unittest cleanups changeset: 72:d1ecc3e57dc6 user: Arjan Scherpenisse date: Fri Jan 01 17:09:09 2010 +0100 summary: Added OSC client and server examples. changeset: 71:1a24f33151a9 user: Arjan Scherpenisse date: Fri Jan 01 16:48:52 2010 +0100 summary: Added test with nested bundle changeset: 70:eab4030250d2 user: Arjan Scherpenisse date: Fri Jan 01 16:37:05 2010 +0100 summary: Implemented Bundle.fromBinary and added tests changeset: 69:24c6713e1056 parent: 67:8bbf0c46c35b user: Arjan Scherpenisse date: Fri Jan 01 15:42:34 2010 +0100 summary: More matching; equality functions in Bundle and Message. changeset: 68:5af56b61e753 parent: 64:ca30ae0819d6 parent: 67:8bbf0c46c35b user: Alexandre Quessy date: Thu Dec 31 10:58:31 2009 -0500 summary: Merged with Arjan's changes for callbacks management, which looks better. changeset: 67:8bbf0c46c35b user: Arjan Scherpenisse date: Thu Dec 31 16:23:41 2009 +0100 summary: More matching magic; using fnmatch module. changeset: 66:f9ca4b0752fa user: Arjan Scherpenisse date: Thu Dec 31 16:05:31 2009 +0100 summary: Wildcard matching stuff changeset: 65:e944cebd1b35 parent: 63:a0528f561b4c user: Arjan Scherpenisse date: Thu Dec 31 13:32:14 2009 +0100 summary: Fix AddressSpace tests; implement add/remove callbacks. changeset: 64:ca30ae0819d6 user: Alexandre Quessy date: Thu Dec 31 10:54:56 2009 -0500 summary: Added CallbacksDict and its tests. changeset: 63:a0528f561b4c user: Alexandre Quessy date: Wed Dec 30 12:21:38 2009 -0500 summary: fixed syntax error in previous commit changeset: 62:765e935fbf7c user: Alexandre Quessy date: Wed Dec 30 12:20:21 2009 -0500 summary: Added AddressSpace class. Not yet implemented. changeset: 61:1334d7254134 user: Alexandre Quessy date: Wed Dec 30 12:10:51 2009 -0500 summary: more wildcard tests. changeset: 60:d5d8662779d5 user: Alexandre Quessy date: Wed Dec 30 12:06:19 2009 -0500 summary: added test with wildcard in the middle of a word changeset: 59:9a4b9e5c856e user: Arjan Scherpenisse date: Wed Dec 30 17:56:54 2009 +0100 summary: Wildcard matches into own functions changeset: 58:994e1a23a5e8 user: Arjan Scherpenisse date: Wed Dec 30 17:53:19 2009 +0100 summary: AddressSpace unit tests changeset: 57:b882cd12f63e user: Arjan Scherpenisse date: Wed Dec 30 17:11:27 2009 +0100 summary: Move stringFromBinary out StringArgument; changeset: 56:2ca8251a7339 user: Arjan Scherpenisse date: Wed Dec 30 16:57:19 2009 +0100 summary: Resurrected int unit tests; removed print from message testcase changeset: 55:fe1b57588a6e user: Arjan Scherpenisse date: Wed Dec 30 16:52:48 2009 +0100 summary: TimeTagArgument - fromBinary changeset: 54:9730c5faca8e parent: 52:30caa3ab3148 parent: 53:cc98bdc92960 user: Alexandre Quessy date: Wed Dec 30 10:45:19 2009 -0500 summary: Merged with more changes from arjan changeset: 53:cc98bdc92960 parent: 50:0a7a8cc5bd0a user: Arjan Scherpenisse date: Wed Dec 30 16:27:21 2009 +0100 summary: Overflow checking on IntegerArgument changeset: 52:30caa3ab3148 user: Alexandre Quessy date: Wed Dec 30 10:41:19 2009 -0500 summary: added __str__ again changeset: 51:cde1107b2c84 parent: 48:b5a5e4ab1992 parent: 50:0a7a8cc5bd0a user: Alexandre Quessy date: Wed Dec 30 10:36:39 2009 -0500 summary: I think I am merging with verion 50 changeset: 50:0a7a8cc5bd0a user: Arjan Scherpenisse date: Wed Dec 30 16:04:53 2009 +0100 summary: Fixed Message.fromBinary and test changeset: 49:74cb572743e8 parent: 47:f8ac3466705a user: Arjan Scherpenisse date: Wed Dec 30 11:04:06 2009 +0100 summary: Tweaks in createArgument. changeset: 48:b5a5e4ab1992 user: Alexandre Quessy date: Wed Dec 30 10:26:17 2009 -0500 summary: Added __str__ to Message and Argument classes. Created the strFromBinary, since it is used al over in the module. changeset: 47:f8ac3466705a user: Alexandre Quessy date: Tue Dec 29 19:39:08 2009 -0500 summary: Fixed error in Message.fromBinary changeset: 46:b50f54e96bbe user: Alexandre Quessy date: Tue Dec 29 19:10:51 2009 -0500 summary: Type tags must be padded with zeros changeset: 45:ea50c0c9ebaf user: Alexandre Quessy date: Tue Dec 29 18:48:33 2009 -0500 summary: skipping the timetag fromBinary test changeset: 44:28e25220b1b9 user: Alexandre Quessy date: Tue Dec 29 18:46:55 2009 -0500 summary: added test from time tag from binary changeset: 43:00b1c69b94b6 user: Alexandre Quessy date: Tue Dec 29 18:41:30 2009 -0500 summary: testing TimeTag.toBinary changeset: 42:7f499514e7be user: Alexandre Quessy date: Tue Dec 29 18:25:14 2009 -0500 summary: fixed test for binary arg changeset: 41:b1befe3e39c9 user: Alexandre Quessy date: Tue Dec 29 18:22:48 2009 -0500 summary: Implemented BlobArgument.fromBinary. Test not passed. changeset: 40:2e8f91468029 user: Alexandre Quessy date: Tue Dec 29 18:13:39 2009 -0500 summary: Added _ceilToMultipleOfFour changeset: 39:711e60d4f3ad user: Alexandre Quessy date: Tue Dec 29 18:05:32 2009 -0500 summary: fixed imports to comply with pep8 changeset: 38:9e7606be2246 parent: 35:3cb3aadd147c parent: 37:9cb25dffc089 user: Alexandre Quessy date: Tue Dec 29 18:04:37 2009 -0500 summary: Merged with blobs changes changeset: 37:9cb25dffc089 user: Arjan Scherpenisse date: Tue Dec 29 23:46:55 2009 +0100 summary: classmethod -> staticmethod changeset: 36:a079b84c5c0b parent: 30:d42eecdcdd7d user: Arjan Scherpenisse date: Tue Dec 29 23:45:12 2009 +0100 summary: BlobArgument changeset: 35:3cb3aadd147c user: Alexandre Quessy date: Tue Dec 29 18:03:24 2009 -0500 summary: added Int.fromBinary and its test changeset: 34:26148c7fa327 user: Alexandre Quessy date: Tue Dec 29 18:00:33 2009 -0500 summary: added test for Float.fromBinary changeset: 33:7d7a0e496210 user: Alexandre Quessy date: Tue Dec 29 17:54:12 2009 -0500 summary: Added FloatArgument.fromBinary changeset: 32:b97d9ec5eea9 user: Alexandre Quessy date: Tue Dec 29 17:45:08 2009 -0500 summary: fix in tabulation changeset: 31:ddb0915320e5 parent: 29:8b91059154c7 parent: 30:d42eecdcdd7d user: Alexandre Quessy date: Tue Dec 29 17:40:48 2009 -0500 summary: Merged with remote branch again changeset: 30:d42eecdcdd7d parent: 28:a94c6888d2c0 user: Arjan Scherpenisse date: Tue Dec 29 23:32:22 2009 +0100 summary: Refactor _readString into StringArgument.fromBinary changeset: 29:8b91059154c7 parent: 27:76a21fd8c14b parent: 28:a94c6888d2c0 user: Alexandre Quessy date: Tue Dec 29 17:40:08 2009 -0500 summary: I guessed I merged something changeset: 28:a94c6888d2c0 parent: 26:74cdae5f73a4 user: Arjan Scherpenisse date: Tue Dec 29 23:20:02 2009 +0100 summary: Removed getTypeTags() changeset: 27:76a21fd8c14b user: Alexandre Quessy date: Tue Dec 29 17:25:04 2009 -0500 summary: commented out unicode to Str changeset: 26:74cdae5f73a4 parent: 25:08fea07399dc parent: 24:01f8b6e940c8 user: Arjan Scherpenisse date: Tue Dec 29 23:17:55 2009 +0100 summary: merged changeset: 25:08fea07399dc parent: 22:19ac4d334005 user: Arjan Scherpenisse date: Tue Dec 29 23:15:13 2009 +0100 summary: Arguments now named and specced according to OSC 1.1. Added NulLArgument, BooleanArgument, ImpulseArgument. changeset: 24:01f8b6e940c8 user: Alexandre Quessy date: Tue Dec 29 17:14:27 2009 -0500 summary: added test for getTypeTags() changeset: 23:045096727670 user: Alexandre Quessy date: Tue Dec 29 17:10:52 2009 -0500 summary: added Message.getTypeTags() changeset: 22:19ac4d334005 user: Arjan Scherpenisse date: Tue Dec 29 22:58:01 2009 +0100 summary: Fixed string reading, started with adding typeTags to Argument classes. changeset: 21:875621b94e93 user: Alexandre Quessy date: Tue Dec 29 16:49:44 2009 -0500 summary: Improved the string parsing, but my test do not work changeset: 20:776dd2b98cb3 user: Arjan Scherpenisse date: Tue Dec 29 22:45:18 2009 +0100 summary: TimeTag argument encoding changeset: 19:5f7824fc1dbe user: Arjan Scherpenisse date: Tue Dec 29 22:42:47 2009 +0100 summary: Added OscSender class changeset: 18:cfd1807f829e user: Alexandre Quessy date: Tue Dec 29 16:10:55 2009 -0500 summary: Fixed error in testing _readString changeset: 17:613d60ed3ac2 parent: 12:445839d8c594 parent: 16:59e621b9d35a user: Alexandre Quessy date: Tue Dec 29 16:08:52 2009 -0500 summary: Merged with progress in ecoding args from Arjan changeset: 16:59e621b9d35a parent: 11:4c1dcb132568 parent: 15:56d46658c533 user: Arjan Scherpenisse date: Tue Dec 29 21:59:25 2009 +0100 summary: Merged tip with encoding of arguments changeset: 15:56d46658c533 user: Arjan Scherpenisse date: Tue Dec 29 21:36:25 2009 +0100 summary: Encoding of arguments changeset: 14:b79ded013aaa user: Arjan Scherpenisse date: Tue Dec 29 21:21:36 2009 +0100 summary: Added blob typetag; added encode function. changeset: 13:36ce709fd4b0 parent: 8:3d8f86b8f150 user: Arjan Scherpenisse date: Tue Dec 29 21:11:53 2009 +0100 summary: Added to type map changeset: 12:445839d8c594 user: Alexandre Quessy date: Tue Dec 29 16:06:21 2009 -0500 summary: Progess in parsing test changeset: 11:4c1dcb132568 user: Alexandre Quessy date: Tue Dec 29 15:47:12 2009 -0500 summary: Added OscProtocol (receiver) changeset: 10:6fc9478be29c user: Alexandre Quessy date: Tue Dec 29 15:32:02 2009 -0500 summary: added padding changeset: 9:7559b226754c user: aalex@ding date: Tue Dec 29 15:20:54 2009 -0500 summary: merged with adding spaces changes changeset: 8:3d8f86b8f150 user: Arjan Scherpenisse date: Tue Dec 29 21:08:56 2009 +0100 summary: Twisted compliant header changeset: 7:02fd5dc325ab user: Arjan Scherpenisse date: Tue Dec 29 21:07:09 2009 +0100 summary: Added more whitespace changeset: 6:7298f0d94cdd user: aalex@ding date: Tue Dec 29 15:04:41 2009 -0500 summary: Added vim files to ignores changeset: 5:3b3d63f12a13 parent: 4:eb4803ba7d34 parent: 3:93755606c553 user: aalex@ding date: Tue Dec 29 15:04:03 2009 -0500 summary: merged with arjan changes. changeset: 4:eb4803ba7d34 parent: 1:926ee709d642 user: aalex@ding date: Tue Dec 29 15:03:39 2009 -0500 summary: progress in casting types in osc.py changeset: 3:93755606c553 user: Arjan Scherpenisse date: Tue Dec 29 20:56:56 2009 +0100 summary: Added unit test for OSC. changeset: 2:b9387520f947 parent: 0:79136855c835 user: Arjan Scherpenisse date: Tue Dec 29 20:56:00 2009 +0100 summary: Added .hgignore file. changeset: 1:926ee709d642 user: aalex@ding date: Tue Dec 29 14:50:24 2009 -0500 summary: added osc.py changeset: 0:79136855c835 user: Arjan Scherpenisse date: Tue Dec 29 19:57:19 2009 +0100 summary: Import of twisted r27896 from svn://svn.twistedmatrix.com/svn/Twisted/trunk python-txosc-0.2.0/man-osc-send.txt0000644000000000000000000000272611445141512015720 0ustar rootroot[SYNOPSIS] osc-send [options] [url] osc-address [,typetags] [osc arguments] [OSC MESSAGES] An OSC message consists of an OSC Address Pattern followed by an OSC Type Tag String followed by zero or more OSC Arguments. [OSC ADDRESSES] An OSC Address Pattern is a string beginning with the character '/' (forward slash). It is mandatory to provide one. [OSC TYPE TAGS] An OSC Type Tag String is a string (beginning with the character ',' (comma)) followed by a sequence of characters corresponding exactly to the sequence of OSC Arguments in the given message. Each character after the comma is called an OSC Type Tag and represents the type of the corresponding OSC Argument. Here is the list of supported type tags: i - 32bit integer h - 64bit integer f - 32bit floating point number d - 64bit (double) floating point number s - string S - symbol c - char m - 4 byte midi packet (8 digits hexadecimal) T - TRUE F - FALSE N - NIL I - INFINITUM [VALUES] Values are space separated. Quoting strings might be handy. The full Open Sound Control specification can be found at http://opensoundcontrol.org/specification [EXAMPLES] The following examples are equivalent: osc-send osc.tcp://127.0.0.1:17779 /ham/spam ,sif egg 2 3.14159 osc-send --tcp --host=127.0.0.1 --port=17779 --type-tags=sif /ham/spam egg 2 3.14159 osc-send -T -P 17779 /ham/spam egg 2 3.14159 [HISTORY] Written by Arjan Scherpenisse and Alexandre Quessy in 2010. python-txosc-0.2.0/README0000644000000000000000000000340011445141512013541 0ustar rootroot _ | |___ _____ ___ ___ | __\ \/ / _ \/ __|/ __| | |_ > < (_) \__ \ (__ \__/_/\_\___/|___/\___| txosc : Open Sound Control (OSC) protocol for Twisted ===================================================== Open Sound Control (OSC) is an open, transport-independent, message-based protocol developed for communication among computers, sound synthesizers, and other multimedia devices. This library implements OSC version 1.1 over both UDP and TCP for the Twisted Python framework. Twisted is an event-based framework for internet applications which works on Python 2.3 through 2.6. Note that this library does not support messages without OSC type tags. This library also implement a synchronous sender that doesn't require the whole Twisted framework. It should be easy to create OSC receivers with any Python network tools from this library. Installing ========== Instructions for installing this software are in INSTALL. Unit Tests ========== See our unit tests run proving that the software is bug free:: $ trial txosc Project Informations ==================== URL : http://bitbucket.org/arjan/txosc Mailing list: https://listes.koumbit.net/cgi-bin/mailman/listinfo/txosc-toonloop.com Examples ======== The examples starting with the "async_" prefix use Twisted. The examples starting with the "sync_" prefix don't use it. Requirements ============ * Twisted 8.1.0 or later * help2man for building the man pages of osc-send and osc-receive Authors ======= Arjan Scherpenisse Alexandre Quessy History ======= 2009 - Written by Arjan Scherpenisse and Alexandre Quessy 2010 - Stable release 0.2