Socket connection: Python/Supercollider communication

I would like to use a script I’ve created in Python to open a socket towards SuperCollider on a specific port in order to send a particular message under the form of a string, in order for the SC language to do something. I would like not to use OSC in that scenario cause I’m already using this method to do the same thing with other servers and I don’t want to modify the system.

My Python client code (the component which will send the message over the socket) will be something like that:

#!/usr/bin/env python3

import socket, sys, time, getopt

PORT = 1234
timetowait = 0.5
message = 'shutdown'

def usage():
	print("Usage: 'main.py -i <computer/raspberry ip>'")
	
if __name__ == "__main__":
	print("Main program start")
	ip = "" # to be passed as a command line argument
	
	# parse the arguments	
	try:
		opts, args = getopt.getopt(sys.argv[1:], "hi:", ["help", "ip="])
	except getopt.GetoptError as err:
		#print help info and exit
		print(err)
		usage()
		sys.exit(2)
		
	if len(opts) < 1 or len(opts) > 1:
		print("too many/few arguments")
		usage()
		sys.exit(2)
	
	
	for o, a in opts:
		if o in ("-h", "--help"):
			usage()
			sys.exit(2)
		elif o in ("-i", "--ip"):
			ip = a
		else:
			usage()
			sys.exit(2)
	
	print("creating socket")
	try:
		# SOCK_STREAM means TCP (not UDP)
		mysock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
	except socket.error:
		print("\tFailed to create socket")
		sys.exit()
	
	time.sleep( timetowait )

	print("connecting")
	try:
		print("using {} as destination IP and {} as port".format(ip, PORT) )
		mysock.connect( (ip, PORT) )
	except socket.error:
		print("\tUnable to connect")
		sys.exit()
		
	time.sleep( timetowait )

	try:
		print("sending")
		mysock.sendall( message.encode() )
	except socket.error:
		print("Failed to send data")
		sys.exit()

	print("closing socket")

	time.sleep( timetowait )

	mysock.close()
	
	time.sleep( timetowait )

What the socket server code to use inside SuperCollider in order to listen for socket connection and messages on a specific port?
thank you all for your replies.

I could be wrong but I believe it isn’t currently supported for SC to open a TCP socket for listening. SC can connect to another process’s open TCP socket but but not the other way around.

If it were supported, there would have to be a primitive for it, and in https://github.com/supercollider/supercollider/blob/develop/lang/LangPrimSource/OSCData.cpp#L1354 ff., there isn’t one.

hjh

1 Like

FWIW, I wrote a little howto TCP on my website since I could not find any documentation on tcp-related implementations… you can find it here: https://tai-studio.org/2020/02/14/tcp-mode-in-supercollider.html

If having the OSC ports conflict is what you are trying to avoid, you can make your own version of UniqueID that allocates OSC ports, then use this to assign all the OSC ports that Python sends to. This way, you will not have any conflicts from different instances.

I made this class:

NN_Synth_ID {

classvar <id=5000;

*initClass { id = 5000; }

*next  { ^id = id + 1; }

*path {this.filenameSymbol.postln}

}

then I use this to allocate NetAddr receive ports. Since each port has a unique port number, the messages (coming from 32+ different Python instances) don’t interfere with one another. You would need to modify your older code to use this, but since you are already doing this kind of work, it shouldn’t be too difficult.

Sam