2023-11-04 16:06:33 +01:00
|
|
|
extends Node
|
|
|
|
|
|
|
|
class_name OSCSender
|
|
|
|
|
|
|
|
|
2023-11-04 23:45:43 +01:00
|
|
|
@export var default_address:String = "127.0.0.1"
|
|
|
|
@export var default_port: int = 9000
|
2023-11-04 16:06:33 +01:00
|
|
|
@export var debug: bool = false
|
|
|
|
var _address: String
|
|
|
|
var _port: int
|
2023-11-04 23:45:43 +01:00
|
|
|
var _socket = PacketPeerUDP.new()
|
2023-11-04 16:06:33 +01:00
|
|
|
|
|
|
|
|
|
|
|
func _init():
|
|
|
|
_address = default_address
|
|
|
|
_port = default_port
|
2023-11-04 23:45:43 +01:00
|
|
|
_socket.set_dest_address(_address, _port)
|
2023-11-04 16:06:33 +01:00
|
|
|
|
|
|
|
|
2023-11-06 17:22:18 +01:00
|
|
|
func _debug(msg) -> void:
|
2023-11-04 16:06:33 +01:00
|
|
|
if debug:
|
|
|
|
print(msg)
|
|
|
|
|
|
|
|
|
2023-11-06 17:22:18 +01:00
|
|
|
func set_destination(dest) -> void:
|
2023-11-04 16:06:33 +01:00
|
|
|
if dest is int:
|
2023-11-04 23:45:43 +01:00
|
|
|
_socket.set_dest_address(_address, dest)
|
2023-11-04 16:06:33 +01:00
|
|
|
_port = dest
|
|
|
|
elif dest is String:
|
2023-11-04 23:45:43 +01:00
|
|
|
_socket.set_dest_address(dest, _port)
|
2023-11-04 16:06:33 +01:00
|
|
|
_address = dest
|
|
|
|
elif dest is Array:
|
2023-11-04 23:45:43 +01:00
|
|
|
_socket.set_dest_address(dest[0], dest[1])
|
2023-11-04 16:06:33 +01:00
|
|
|
_address = dest[0]
|
|
|
|
_port = dest[1]
|
|
|
|
|
|
|
|
|
2023-11-06 17:22:18 +01:00
|
|
|
func create_message(osc_address: String, arg_types: String, values: Array) -> Array:
|
|
|
|
if not osc_address.begins_with("/"):
|
|
|
|
return [ERR_INVALID_DATA]
|
|
|
|
|
2023-11-04 16:06:33 +01:00
|
|
|
var buf = StreamPeerBuffer.new()
|
|
|
|
buf.set_big_endian(true)
|
2023-11-06 17:22:18 +01:00
|
|
|
_pack_string(buf, osc_address)
|
|
|
|
_pack_string(buf, "," + arg_types)
|
2023-11-04 16:06:33 +01:00
|
|
|
var vidx: int = 0
|
|
|
|
|
2023-11-06 17:22:18 +01:00
|
|
|
for i in arg_types.length():
|
|
|
|
var typetag = arg_types[i]
|
2023-11-04 16:06:33 +01:00
|
|
|
var inc_vidx = true
|
|
|
|
|
|
|
|
match typetag:
|
|
|
|
"i":
|
|
|
|
buf.put_32(values[vidx])
|
|
|
|
"h":
|
|
|
|
buf.put_64(values[vidx])
|
|
|
|
"f":
|
|
|
|
buf.put_float(values[vidx])
|
|
|
|
"d":
|
|
|
|
buf.put_double(values[vidx])
|
|
|
|
"c":
|
|
|
|
buf.put_32(values[vidx])
|
|
|
|
"s", "S":
|
|
|
|
_pack_string(buf, values[vidx])
|
|
|
|
"b":
|
|
|
|
_pack_blob(buf, values[vidx])
|
|
|
|
"t":
|
|
|
|
assert(values[i].size() == 8)
|
|
|
|
buf.put_data(values[vidx])
|
|
|
|
"m", "r":
|
|
|
|
assert(values[vidx].size() == 4)
|
|
|
|
buf.put_data(PackedByteArray(values[vidx]))
|
|
|
|
"TFI":
|
|
|
|
inc_vidx = false # no argument value sent
|
|
|
|
_:
|
|
|
|
_debug("Argument type '%s' not supported." % typetag)
|
2023-11-06 17:22:18 +01:00
|
|
|
return [ERR_INVALID_PARAMETER]
|
2023-11-04 16:06:33 +01:00
|
|
|
|
|
|
|
if inc_vidx:
|
|
|
|
vidx += 1
|
|
|
|
|
2023-11-06 17:22:18 +01:00
|
|
|
return [OK, buf.get_data_array()]
|
|
|
|
|
|
|
|
|
|
|
|
func send_osc(osc_address: String, arg_types: String, values: Array, dest = null) -> Error:
|
|
|
|
var res = create_message(osc_address, arg_types, values)
|
|
|
|
|
|
|
|
if res[0] != OK:
|
|
|
|
return res[0]
|
|
|
|
|
2023-11-04 16:06:33 +01:00
|
|
|
if dest != null:
|
|
|
|
set_destination(dest)
|
|
|
|
|
2023-11-06 17:22:18 +01:00
|
|
|
_socket.put_packet(res[1])
|
2023-11-04 16:06:33 +01:00
|
|
|
return OK
|
|
|
|
|
|
|
|
|
2023-11-06 17:22:18 +01:00
|
|
|
func _pack_string(buf: StreamPeerBuffer, s: String) -> void:
|
2023-11-04 16:06:33 +01:00
|
|
|
## Pack a string into a binary OSC buffer
|
|
|
|
buf.put_data(s.to_ascii_buffer())
|
|
|
|
|
|
|
|
# pad to next 32-bit offset
|
|
|
|
while buf.get_position() % 4:
|
|
|
|
buf.put_u8(0)
|
|
|
|
|
|
|
|
|
2023-11-06 17:22:18 +01:00
|
|
|
func _pack_blob(buf, blob) -> void:
|
2023-11-04 16:06:33 +01:00
|
|
|
## Pack a PackedByteArray, Array or String into a binary OSC buffer
|
|
|
|
if blob is String:
|
|
|
|
blob = blob.to_utf8_buffer()
|
|
|
|
elif blob is Array:
|
|
|
|
blob = PackedByteArray(blob)
|
|
|
|
|
|
|
|
assert(blob.size() < 2 ** 31) # blob size per spec is _signed_ 32-bit int
|
|
|
|
buf.put_32(blob.size())
|
|
|
|
buf.put_data(blob)
|
|
|
|
|
|
|
|
# pad to next 32-bit offset
|
|
|
|
while buf.get_position() % 4:
|
|
|
|
buf.put_u8(0)
|