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
|
|
@ -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))
|
|
@ -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
|
|
@ -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…
Reference in New Issue