Max to python-osc
I am trying to help a friend with python. I am a fairly experienced python user, he is a fairly experienced Max user.
The aim of my code is:
receive a message from max over a local IP 127.0.0.1 on a specified port (5005)
elaborate the message in python
send the message to super collider over the same IP but on another port
So far, I have successfully set up a server/client (basically a "proxy") with python-osc and I can comunicate with its server (tested it with a python-osc client) and get messages from its client.
I am not able to make max communicate with it. My friend set up a patch for me to test the code, but I think I am missing something: is there a default handler (URI path) in Max? If i click on the messages in Max, which are connected to the udpsend part shouldn't I get see those messages on the 5005 port?
If I fire up the server it listens to my python-client but it gets nothing from max. I do not get even a message concerning the default handler.
I am working on a 2020 macbook pro
Just to help you all understand a bit better, here's my python code
import argparse
from pythonosc import dispatcher
from pythonosc import osc_server
from pythonosc import udp_client
def main(path: str, *osc_arguments):
msg = osc_arguments[-1]
print("input message: {}".format(msg))
msgOUT = msg+'out'
# output
print("output message: {}".format(msgOUT))
ipOUT = osc_arguments[0][0]
portOUT = osc_arguments[0][1]
pathOUT= osc_arguments[0][2]
talk2SC(ipOUT,portOUT,pathOUT,msgOUT)
def listen2Max(addrIN,addrOUT):
'''
set up server
'''
# input address
ipIN = addrIN[0]
portIN = addrIN[1]
pathIN = addrIN[2]
# output address
portOUT = addrOUT[0]
pathOUT = addrOUT[1]
# dispatcher to receive message
disp = dispatcher.Dispatcher()
disp.map(pathIN, main, ipIN, portOUT, pathOUT)
# server to listen
server = osc_server.ThreadingOSCUDPServer((ipIN,portIN), disp)
print("Serving on {}".format(server.server_address))
server.serve_forever()
def talk2SC(ip,port,path,mymove):
'''
set up client
'''
client = udp_client.SimpleUDPClient(ip,port)
client.send_message(path, mymove)
if __name__ == "__main__":
# generate parser
parser = argparse.ArgumentParser(prog='scacchiOSC', formatter_class=argparse.RawDescriptionHelpFormatter, description='Interprete di messaggi OSC da Max\n')
parser.add_argument("-II","--ipIN", type=str, default="127.0.0.1", help="The ip to listen on")
parser.add_argument("-PI", "--portIN", type=int, default=5005, help="The port to listen on")
parser.add_argument("-UI", "--uripathIN", type=str, default="/filter", help="MAX's URI path")
parser.add_argument("-PO", "--portOUT", type=int, default=5006, help="The port to send messages to")
parser.add_argument("-UO", "--uripathOUT", type=str, default="/filter", help="output URI path")
args = parser.parse_args()
# wrap up inputs
outputAddress = [args.portOUT, args.uripathOUT]
inputAddress = [args.ipIN, args.portIN, args.uripathIN]
# listen to max
listen2Max(inputAddress, outputAddress)
you set parser to listen to /filter

msgOUT = msg+'out' ????

once removed + 'out' it started working, but with
server set to Thread type printout is miserable and disrupted
set to
server = osc_server.OSCUDPServer((ipIN,portIN), disp)
kind of works, but still very slow.
after all printout were removed
looping from max to pyton-osc - and back works ok
Cool, thank you.
The part that gives you an error is actually just an example, in your case you could try msgOUT = msg+1
In my case, I am getting string messages, thus your example does not apply.
Could you please elaborate a bit the /filter $1 message on Max? What if I am sending strings with spaces (like in my case)? The $1 sends only the first part of the string, which is split at each space.
sure i could add any kind of math operation to msg , but it is not my point of interest.
Max is not limiting what it sends.
I used filter $1 in max , because in that code you posted only single item gets parsed.
you can send
/filter bla bla 33 77 12.55555 message from max
but .... then you have to parse that message on the receiver side.
sending same message to your python code (blue), or direct loopback to max

Great, basically if I parse
/filter "bla bla 33 77 12.55555"
everything (all the strings within quote marks) goes directly to my python code.
What if I wanted to make my python code listen to every message coming from 127.0.0.1 port 5005 regardless of the path (i.e. without /filter)?
parser.add_argument("-UI", "--uripathIN", type=str, default="*")
i think would allow any / prepended message
like /ha/ho/hi 33
I am not really into python-osc.
probably there is a way to route anthing from input ,
you can try reading dispatcher docs
That is awesome!!!
I just wonder why with python-osc I have to specify a path. I would really love to send a message with just ip and port...
(see the following pictures)


You are forgetting that poblem is not Max and udpsend or udpreceive,
which can send and receive anything,
but OSC specification which defines
that OSC message has to start with "/" slash.
Means max is sending that messages but your script is filtering them out,
because of missing slash.
You could avoid using OSC at all
and capture use python udp instead if that is possible in your environment.
Or modify python-osc libary
have a look into dispatcher.py
That's actually great.
I set-up my code to receive and send with UDP, but the problem now is dealing with bytes.
I was expecting that, seeing that you want to send list as symbol
form max in order to keep it single item, but as you are
fairly experienced python user, I am sure you will find your way through all this.
I did: osc objects sent from max (as i stated before I AM NOT an experienced Max user) are not pure bytes object that can be easily decoded as bytes in python.
Thus, I used the _parse_datagram method of the OSCMessage class inside osc_message.py (in the python-osc library) to translate OSC messages and I am using "pure" udp protocol with socket to send and receive messages.
There are also alternative objects in sadam's library for udp communication.
sadam.udpSender for example
It is available through max package manager
P.S: sends "pure" bytes or lists of bytes