Skip to content

Commit

Permalink
Add tcp support
Browse files Browse the repository at this point in the history
  • Loading branch information
Bob Haddleton authored and Bob Haddleton committed Aug 3, 2024
1 parent d9a29a0 commit d89c241
Show file tree
Hide file tree
Showing 12 changed files with 1,220 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,6 @@ bin/

# PyBuilder
target/

# PyCharm
.idea/
49 changes: 49 additions & 0 deletions examples/async_simple_tcp_client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
"""Small example Asynchronous OSC TCP client
This program listens for incoming messages in one task, and
sends 10 random values between 0.0 and 1.0 to the /filter address,
waiting for 1 seconds between each value in a second task.
"""
import argparse
import asyncio
import random
import sys

from pythonosc import tcp_client


async def get_messages(client):
async for msg in client.get_messages(60):
print(msg)


async def send_messages(client):
for x in range(10):
r = random.random()
print(f"Sending /filter {r}")
await client.send_message("/filter", r)
await asyncio.sleep(1)


async def init_main():
parser = argparse.ArgumentParser()
parser.add_argument("--ip", default="127.0.0.1",
help="The ip of the OSC server")
parser.add_argument("--port", type=int, default=5005,
help="The port the OSC server is listening on")
parser.add_argument("--mode", default="1.1",
help="The OSC protocol version of the server (default is 1.1)")
args = parser.parse_args()

async with tcp_client.AsyncSimpleTCPClient(args.ip, args.port, mode=args.mode) as client:
async with asyncio.TaskGroup() as tg:
tg.create_task(get_messages(client))
tg.create_task(send_messages(client))

if sys.version_info >= (3, 7):
asyncio.run(init_main())
else:
# TODO(python-upgrade): drop this once 3.6 is no longer supported
event_loop = asyncio.get_event_loop()
event_loop.run_until_complete(init_main())
event_loop.close()
46 changes: 46 additions & 0 deletions examples/async_tcp_server.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import argparse
import asyncio
import sys

from pythonosc.dispatcher import Dispatcher
from pythonosc.osc_tcp_server import AsyncOSCTCPServer


def filter_handler(address, *args):
print(f"{address}: {args}")


dispatcher = Dispatcher()
dispatcher.map("/filter", filter_handler)


async def loop():
"""Example main loop that only runs for 10 iterations before finishing"""
for i in range(10):
print(f"Loop {i}")
await asyncio.sleep(10)


async def init_main():
parser = argparse.ArgumentParser()
parser.add_argument("--ip", default="127.0.0.1",
help="The ip of the OSC server")
parser.add_argument("--port", type=int, default=5005,
help="The port the OSC server is listening on")
parser.add_argument("--mode", default="1.1",
help="The OSC protocol version of the server (default is 1.1)")
args = parser.parse_args()

async with AsyncOSCTCPServer(args.ip, args.port, dispatcher, mode=args.mode) as server:
async with asyncio.TaskGroup() as tg:
tg.create_task(server.start())
tg.create_task(loop())


if sys.version_info >= (3, 7):
asyncio.run(init_main())
else:
# TODO(python-upgrade): drop this once 3.6 is no longer supported
event_loop = asyncio.get_event_loop()
event_loop.run_until_complete(init_main())
event_loop.close()
31 changes: 31 additions & 0 deletions examples/simple_tcp_client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
"""Small example OSC client
This program sends 10 random values between 0.0 and 1.0 to the /filter address,
and listens for incoming messages for 1 second between each value.
"""
import argparse
import random

from pythonosc import tcp_client

if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("--ip", default="127.0.0.1",
help="The ip of the OSC server")
parser.add_argument("--port", type=int, default=5005,
help="The port the OSC server is listening on")
parser.add_argument("--mode", default="1.1",
help="The OSC protocol version of the server (default is 1.1)")
args = parser.parse_args()

with tcp_client.SimpleTCPClient(args.ip, args.port, mode=args.mode) as client:
for x in range(10):
n = random.random()
print(f"Sending /filter {n}")
client.send_message("/filter", n)
resp = client.get_messages(1)
for r in resp:
try:
print(r)
except Exception as e:
print(f"oops {str(e)}: {r}")
43 changes: 43 additions & 0 deletions examples/simple_tcp_server.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
"""Small example OSC server
This program listens to the specified address and port, and prints some information about
received packets.
"""
import argparse
import math

from pythonosc import osc_tcp_server
from pythonosc.dispatcher import Dispatcher


def print_volume_handler(unused_addr, args, volume):
print("[{0}] ~ {1}".format(args[0], volume))


def print_compute_handler(unused_addr, args, volume):
try:
print("[{0}] ~ {1}".format(args[0], args[1](volume)))
except ValueError:
pass


if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("--ip",
default="127.0.0.1", help="The ip to listen on")
parser.add_argument("--port",
type=int, default=5005, help="The port to listen on")
parser.add_argument("--mode", default="1.1",
help="The OSC protocol version of the server (default is 1.1)")

args = parser.parse_args()

dispatcher = Dispatcher()
dispatcher.map("/filter", print)
dispatcher.map("/volume", print_volume_handler, "Volume")
dispatcher.map("/logvolume", print_compute_handler, "Log volume", math.log)

server = osc_tcp_server.ThreadingOSCTCPServer(
(args.ip, args.port), dispatcher, mode=args.mode)
print("Serving on {}".format(server.server_address))
server.serve_forever()
3 changes: 3 additions & 0 deletions pythonosc/osc_message.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ def __init__(self, dgram: bytes) -> None:
self._parameters = [] # type: List[Any]
self._parse_datagram()

def __str__(self):
return f"{self.address} {' '.join(str(p) for p in self.params)}"

def _parse_datagram(self) -> None:
try:
self._address_regexp, index = osc_types.get_string(self._dgram, 0)
Expand Down
14 changes: 14 additions & 0 deletions pythonosc/osc_message_builder.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Build OSC messages for client applications."""
from typing import Iterable

from pythonosc import osc_message
from pythonosc.parsing import osc_types
Expand Down Expand Up @@ -195,3 +196,16 @@ def build(self) -> osc_message.OscMessage:
return osc_message.OscMessage(dgram)
except osc_types.BuildError as be:
raise BuildError("Could not build the message: {}".format(be))


def build_msg(address: str, value: ArgValue):
builder = OscMessageBuilder(address=address)
if value is None:
values = []
elif not isinstance(value, Iterable) or isinstance(value, (str, bytes)):
values = [value]
else:
values = value
for val in values:
builder.add_arg(val)
return builder.build()
Loading

0 comments on commit d89c241

Please sign in to comment.