feat: basic support for OSC sending
Signed-off-by: Christopher Arndt <chris@chrisarndt.de>
This commit is contained in:
		
							parent
							
								
									4f0bb2fa93
								
							
						
					
					
						commit
						b7ef9bc01b
					
				
							
								
								
									
										35
									
								
								UI.gd
									
									
									
									
									
								
							
							
						
						
									
										35
									
								
								UI.gd
									
									
									
									
									
								
							@ -1,35 +0,0 @@
 | 
			
		||||
extends Control
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
func _ready():
 | 
			
		||||
	var scene = preload("res://osc_receiver.tscn")
 | 
			
		||||
	var osc_server = scene.instantiate()
 | 
			
		||||
	add_child(osc_server)
 | 
			
		||||
 | 
			
		||||
	# configure all sensors
 | 
			
		||||
	for i in range(4):
 | 
			
		||||
		var nodename = "VSlider%d" % (i + 1)
 | 
			
		||||
		var osc_addr = "/slider/%d/set" % i
 | 
			
		||||
		var slider_node = find_child(nodename)
 | 
			
		||||
		osc_server.register_callback(osc_addr, "f", slider_node.recv_osc)
 | 
			
		||||
 | 
			
		||||
	for i in range(4):
 | 
			
		||||
		var nodename = "Button%d" % (i + 1)
 | 
			
		||||
		var osc_addr = "/button/%d/set" % i
 | 
			
		||||
		var button_node = find_child(nodename)
 | 
			
		||||
		osc_server.register_callback(osc_addr, "i", button_node.recv_osc)
 | 
			
		||||
 | 
			
		||||
	osc_server.register_callback("/string", "s", recv_osc)
 | 
			
		||||
	osc_server.register_callback("/stringint", "si", recv_osc)
 | 
			
		||||
	osc_server.register_callback("/blob", "b", recv_osc)
 | 
			
		||||
	osc_server.register_callback("/blobint", "bi", recv_osc)
 | 
			
		||||
 | 
			
		||||
	# start listening for osc messages
 | 
			
		||||
	osc_server.start_server()
 | 
			
		||||
 | 
			
		||||
func recv_osc(msg_info, values):
 | 
			
		||||
	print("Sender IP: %s" % msg_info["ip"])
 | 
			
		||||
	print("Sender Port: %d" % msg_info["port"])
 | 
			
		||||
	print("Address: %s" % msg_info["address"])
 | 
			
		||||
	print("Types: %s" % msg_info["types"])
 | 
			
		||||
	print("Values:", values)
 | 
			
		||||
							
								
								
									
										24
									
								
								UI.tscn
									
									
									
									
									
								
							
							
						
						
									
										24
									
								
								UI.tscn
									
									
									
									
									
								
							@ -1,8 +1,8 @@
 | 
			
		||||
[gd_scene load_steps=8 format=3 uid="uid://8xyprd3yldfg"]
 | 
			
		||||
 | 
			
		||||
[ext_resource type="Script" path="res://UI.gd" id="1_ft657"]
 | 
			
		||||
[ext_resource type="Script" path="res://Slider.gd" id="2_310mb"]
 | 
			
		||||
[ext_resource type="Script" path="res://ToggleButton.gd" id="3_ct66k"]
 | 
			
		||||
[ext_resource type="Script" path="res://ui.gd" id="1_28t32"]
 | 
			
		||||
[ext_resource type="Script" path="res://slider.gd" id="2_7hpi4"]
 | 
			
		||||
[ext_resource type="Script" path="res://toggle_button.gd" id="3_ch7hh"]
 | 
			
		||||
 | 
			
		||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_y0b18"]
 | 
			
		||||
bg_color = Color(1, 0, 0, 1)
 | 
			
		||||
@ -23,7 +23,7 @@ anchor_right = 1.0
 | 
			
		||||
anchor_bottom = 1.0
 | 
			
		||||
grow_horizontal = 2
 | 
			
		||||
grow_vertical = 2
 | 
			
		||||
script = ExtResource("1_ft657")
 | 
			
		||||
script = ExtResource("1_28t32")
 | 
			
		||||
 | 
			
		||||
[node name="MarginContainer" type="MarginContainer" parent="."]
 | 
			
		||||
layout_mode = 1
 | 
			
		||||
@ -52,7 +52,7 @@ max_value = 1.0
 | 
			
		||||
step = 0.01
 | 
			
		||||
tick_count = 11
 | 
			
		||||
ticks_on_borders = true
 | 
			
		||||
script = ExtResource("2_310mb")
 | 
			
		||||
script = ExtResource("2_7hpi4")
 | 
			
		||||
 | 
			
		||||
[node name="VSlider2" type="VSlider" parent="MarginContainer/GridContainer"]
 | 
			
		||||
custom_minimum_size = Vector2(50, 300)
 | 
			
		||||
@ -63,7 +63,7 @@ max_value = 1.0
 | 
			
		||||
step = 0.01
 | 
			
		||||
tick_count = 11
 | 
			
		||||
ticks_on_borders = true
 | 
			
		||||
script = ExtResource("2_310mb")
 | 
			
		||||
script = ExtResource("2_7hpi4")
 | 
			
		||||
 | 
			
		||||
[node name="VSlider3" type="VSlider" parent="MarginContainer/GridContainer"]
 | 
			
		||||
custom_minimum_size = Vector2(50, 300)
 | 
			
		||||
@ -74,7 +74,7 @@ max_value = 1.0
 | 
			
		||||
step = 0.01
 | 
			
		||||
tick_count = 11
 | 
			
		||||
ticks_on_borders = true
 | 
			
		||||
script = ExtResource("2_310mb")
 | 
			
		||||
script = ExtResource("2_7hpi4")
 | 
			
		||||
 | 
			
		||||
[node name="VSlider4" type="VSlider" parent="MarginContainer/GridContainer"]
 | 
			
		||||
custom_minimum_size = Vector2(50, 300)
 | 
			
		||||
@ -85,32 +85,32 @@ max_value = 1.0
 | 
			
		||||
step = 0.01
 | 
			
		||||
tick_count = 11
 | 
			
		||||
ticks_on_borders = true
 | 
			
		||||
script = ExtResource("2_310mb")
 | 
			
		||||
script = ExtResource("2_7hpi4")
 | 
			
		||||
 | 
			
		||||
[node name="Button1" type="Button" parent="MarginContainer/GridContainer"]
 | 
			
		||||
layout_mode = 2
 | 
			
		||||
theme_override_styles/pressed = SubResource("StyleBoxFlat_y0b18")
 | 
			
		||||
toggle_mode = true
 | 
			
		||||
text = "1"
 | 
			
		||||
script = ExtResource("3_ct66k")
 | 
			
		||||
script = ExtResource("3_ch7hh")
 | 
			
		||||
 | 
			
		||||
[node name="Button2" type="Button" parent="MarginContainer/GridContainer"]
 | 
			
		||||
layout_mode = 2
 | 
			
		||||
theme_override_styles/pressed = SubResource("StyleBoxFlat_iu8u7")
 | 
			
		||||
toggle_mode = true
 | 
			
		||||
text = "2"
 | 
			
		||||
script = ExtResource("3_ct66k")
 | 
			
		||||
script = ExtResource("3_ch7hh")
 | 
			
		||||
 | 
			
		||||
[node name="Button3" type="Button" parent="MarginContainer/GridContainer"]
 | 
			
		||||
layout_mode = 2
 | 
			
		||||
theme_override_styles/pressed = SubResource("StyleBoxFlat_7e33t")
 | 
			
		||||
toggle_mode = true
 | 
			
		||||
text = "3"
 | 
			
		||||
script = ExtResource("3_ct66k")
 | 
			
		||||
script = ExtResource("3_ch7hh")
 | 
			
		||||
 | 
			
		||||
[node name="Button4" type="Button" parent="MarginContainer/GridContainer"]
 | 
			
		||||
layout_mode = 2
 | 
			
		||||
theme_override_styles/pressed = SubResource("StyleBoxFlat_eeife")
 | 
			
		||||
toggle_mode = true
 | 
			
		||||
text = "4	"
 | 
			
		||||
script = ExtResource("3_ct66k")
 | 
			
		||||
script = ExtResource("3_ch7hh")
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,7 @@
 | 
			
		||||
extends Node
 | 
			
		||||
 | 
			
		||||
class_name OSCReceiver
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@export var default_address:String = "0.0.0.0"
 | 
			
		||||
@export var default_port: int = 9001
 | 
			
		||||
@ -51,6 +53,11 @@ func stop_server():
 | 
			
		||||
		_server.stop()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
func _debug(msg):
 | 
			
		||||
	if debug:
 | 
			
		||||
		print(msg)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
func _poll():
 | 
			
		||||
	if not _server.is_listening():
 | 
			
		||||
		return
 | 
			
		||||
@ -91,7 +98,7 @@ func _poll():
 | 
			
		||||
				for callback in _observers[[address, types]]:
 | 
			
		||||
					callback.call(msg_info, values)
 | 
			
		||||
 | 
			
		||||
func _parse_osc_addr_and_types(packet):
 | 
			
		||||
func _parse_osc_addr_and_types(packet: PackedByteArray):
 | 
			
		||||
	var asep = packet.find(0)
 | 
			
		||||
	var address = packet.slice(0, asep).get_string_from_ascii() 
 | 
			
		||||
	
 | 
			
		||||
@ -103,7 +110,7 @@ func _parse_osc_addr_and_types(packet):
 | 
			
		||||
	return [address, types, tsep + (4 - tsep % 4)]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
func _parse_osc_values(packet, types):
 | 
			
		||||
func _parse_osc_values(packet: PackedByteArray, types: String):
 | 
			
		||||
	var result
 | 
			
		||||
	var values = []
 | 
			
		||||
	var stream = StreamPeerBuffer.new()
 | 
			
		||||
@ -173,8 +180,3 @@ func _parse_osc_values(packet, types):
 | 
			
		||||
				return
 | 
			
		||||
 | 
			
		||||
	return values
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
func _debug(msg):
 | 
			
		||||
	if debug:
 | 
			
		||||
		print(msg)
 | 
			
		||||
@ -1,7 +0,0 @@
 | 
			
		||||
[gd_scene load_steps=2 format=3 uid="uid://bqci5bw1h0lh7"]
 | 
			
		||||
 | 
			
		||||
[ext_resource type="Script" path="res://OSCReceiver.gd" id="1_ujyu5"]
 | 
			
		||||
 | 
			
		||||
[node name="OSCReceiver" type="Node"]
 | 
			
		||||
script = ExtResource("1_ujyu5")
 | 
			
		||||
debug = true
 | 
			
		||||
							
								
								
									
										108
									
								
								osc_sender.gd
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										108
									
								
								osc_sender.gd
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,108 @@
 | 
			
		||||
extends Node
 | 
			
		||||
 | 
			
		||||
class_name OSCSender
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@export var default_address:String = "0.0.0.0"
 | 
			
		||||
@export var default_port: int = 9001
 | 
			
		||||
@export var debug: bool = false
 | 
			
		||||
var _address: String
 | 
			
		||||
var _port: int
 | 
			
		||||
var socket = PacketPeerUDP.new()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
func _init():
 | 
			
		||||
	_address = default_address
 | 
			
		||||
	_port = default_port
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
func _debug(msg):
 | 
			
		||||
	if debug:
 | 
			
		||||
		print(msg)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
func set_destination(dest):
 | 
			
		||||
	if dest is int:
 | 
			
		||||
		socket.set_dest_address(_address, dest)
 | 
			
		||||
		_port = dest
 | 
			
		||||
	elif dest is String:
 | 
			
		||||
		socket.set_dest_address(dest, _port)
 | 
			
		||||
		_address = dest
 | 
			
		||||
	elif dest is Array:
 | 
			
		||||
		socket.set_dest_address(dest[0], dest[1])
 | 
			
		||||
		_address = dest[0]
 | 
			
		||||
		_port = dest[1]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
func send_osc(dest, oscaddress: String, argtypes: String, values: Array):
 | 
			
		||||
	assert(oscaddress.begins_with("/"))
 | 
			
		||||
	var buf = StreamPeerBuffer.new()
 | 
			
		||||
	buf.set_big_endian(true)
 | 
			
		||||
	_pack_string(buf, oscaddress)
 | 
			
		||||
	_pack_string(buf, "," + argtypes)
 | 
			
		||||
	var vidx: int = 0
 | 
			
		||||
 | 
			
		||||
	for i in argtypes.length():
 | 
			
		||||
		var typetag = argtypes[i]
 | 
			
		||||
		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)
 | 
			
		||||
				return FAILED
 | 
			
		||||
 | 
			
		||||
		if inc_vidx:
 | 
			
		||||
			vidx += 1
 | 
			
		||||
 | 
			
		||||
	if dest != null:
 | 
			
		||||
		set_destination(dest)
 | 
			
		||||
 | 
			
		||||
	socket.put_packet(buf.get_data_array())
 | 
			
		||||
	return OK
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
func _pack_string(buf: StreamPeerBuffer, s: String):
 | 
			
		||||
	## 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)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
func _pack_blob(buf, blob):
 | 
			
		||||
	## 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)
 | 
			
		||||
@ -10,7 +10,7 @@ config_version=5
 | 
			
		||||
 | 
			
		||||
[application]
 | 
			
		||||
 | 
			
		||||
config/name="OSCReceiver Demo"
 | 
			
		||||
config/name="OSC Demo"
 | 
			
		||||
run/main_scene="res://UI.tscn"
 | 
			
		||||
config/features=PackedStringArray("4.1")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -6,4 +6,4 @@ func recv_osc(msg_info, values):
 | 
			
		||||
	print("Sender Port: %d" % msg_info["port"])
 | 
			
		||||
	print("Address: %s" % msg_info["address"])
 | 
			
		||||
	print("Types: %s" % msg_info["types"])
 | 
			
		||||
	set_value(clampf(values[0], 0.0, 1.0))
 | 
			
		||||
	set_value_no_signal(clampf(values[0], 0.0, 1.0))
 | 
			
		||||
							
								
								
									
										13
									
								
								testosc.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										13
									
								
								testosc.sh
									
									
									
									
									
										Executable file
									
								
							@ -0,0 +1,13 @@
 | 
			
		||||
HOST=localhost
 | 
			
		||||
PORT=9001
 | 
			
		||||
 | 
			
		||||
for ctrl in 0 1 2 3; do
 | 
			
		||||
    for value in `LC_ALL=C seq 0.1 0.1 1.0`; do
 | 
			
		||||
        oscsend $HOST $PORT /slider/$ctrl/set f $value
 | 
			
		||||
        sleep 0.1
 | 
			
		||||
    done
 | 
			
		||||
 | 
			
		||||
    oscsend $HOST $PORT /button/$ctrl/set i 1
 | 
			
		||||
    sleep 1
 | 
			
		||||
    oscsend $HOST $PORT /button/$ctrl/set i 0
 | 
			
		||||
done
 | 
			
		||||
							
								
								
									
										49
									
								
								ui.gd
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								ui.gd
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,49 @@
 | 
			
		||||
extends Control
 | 
			
		||||
 | 
			
		||||
const OSCReceiver = preload("res://osc_receiver.gd")
 | 
			
		||||
var osc_server: OSCReceiver
 | 
			
		||||
const OSCSender = preload("res://osc_sender.gd")
 | 
			
		||||
var osc_client: OSCSender
 | 
			
		||||
 | 
			
		||||
func _ready():
 | 
			
		||||
	osc_client = OSCSender.new()
 | 
			
		||||
	osc_server = OSCReceiver.new()
 | 
			
		||||
	add_child(osc_server)
 | 
			
		||||
	var button_callback = Callable(self, "_button_pressed")
 | 
			
		||||
	var slider_callback = Callable(self, "_slider_moved")
 | 
			
		||||
 | 
			
		||||
	# configure all sensors
 | 
			
		||||
	for i in range(4):
 | 
			
		||||
		var nodename = "VSlider%d" % (i + 1)
 | 
			
		||||
		var osc_addr = "/slider/%d/set" % i
 | 
			
		||||
		var slider_node = find_child(nodename)
 | 
			
		||||
		osc_server.register_callback(osc_addr, "f", slider_node.recv_osc)
 | 
			
		||||
		slider_node.value_changed.connect(slider_callback.bind(i))
 | 
			
		||||
	
 | 
			
		||||
	for i in range(4):
 | 
			
		||||
		var nodename = "Button%d" % (i + 1)
 | 
			
		||||
		var osc_addr = "/button/%d/set" % i
 | 
			
		||||
		var button_node = find_child(nodename)
 | 
			
		||||
		osc_server.register_callback(osc_addr, "i", button_node.recv_osc)
 | 
			
		||||
		button_node.pressed.connect(button_callback.bind(button_node, i))
 | 
			
		||||
 | 
			
		||||
	# start listening for osc messages
 | 
			
		||||
	osc_server.start_server()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
func _button_pressed(btn: Button, idx: int):
 | 
			
		||||
	print("Button %s pressed: state = %s" % [idx, btn.button_pressed])
 | 
			
		||||
	osc_client.send_osc(9000, "/button/%d" % idx, "i", [1 if btn.button_pressed else 0])
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
func _slider_moved(value: float, idx: int):
 | 
			
		||||
	print("Slider %d moved: value = %f" % [idx, value])
 | 
			
		||||
	osc_client.send_osc(9000, "/slider/%d" % idx, "f", [value])
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
func recv_osc(msg_info, values):
 | 
			
		||||
	print("Sender IP: %s" % msg_info["ip"])
 | 
			
		||||
	print("Sender Port: %d" % msg_info["port"])
 | 
			
		||||
	print("Address: %s" % msg_info["address"])
 | 
			
		||||
	print("Types: %s" % msg_info["types"])
 | 
			
		||||
	print("Values:", values)
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user