using Godot; using System; using System.Collections.Generic; using System.Net; using System.Net.Sockets; using System.Text; /// /// Simple OSC (Open Sound Control) client for sending messages via UDP /// public class OscClient { private readonly UdpClient _client; private readonly IPEndPoint _endpoint; /// /// Initializes a new instance of the OscClient class /// /// IP address to send to /// Port to send to public OscClient(string ip, int port) { _client = new UdpClient(); _endpoint = new IPEndPoint(IPAddress.Parse(ip), port); } /// /// Send a float message /// /// OSC path /// Float value public void SendMessage(string path, float value) { try { byte[] addressBytes = Encoding.ASCII.GetBytes(path); byte[] typeTagBytes = Encoding.ASCII.GetBytes(",f"); // OSC message format: address, type tag, data byte[] message = new byte[ 4 * ((addressBytes.Length / 4) + 1) + // Address padded to multiple of 4 4 * ((typeTagBytes.Length / 4) + 1) + // Type tag padded to multiple of 4 4]; // Float value (4 bytes) int index = 0; // Copy address and pad with zeros Array.Copy(addressBytes, 0, message, index, addressBytes.Length); index += 4 * ((addressBytes.Length / 4) + 1); // Copy type tag and pad with zeros Array.Copy(typeTagBytes, 0, message, index, typeTagBytes.Length); index += 4 * ((typeTagBytes.Length / 4) + 1); // Convert float to big-endian bytes byte[] valueBytes = BitConverter.GetBytes(value); if (BitConverter.IsLittleEndian) Array.Reverse(valueBytes); Array.Copy(valueBytes, 0, message, index, 4); _client.Send(message, message.Length, _endpoint); } catch (Exception ex) { GD.PrintErr($"Error sending OSC message: {ex.Message}"); } } /// /// Send a vector message /// /// OSC path /// Array of float values public void SendMessage(string path, float[] values) { try { byte[] addressBytes = Encoding.ASCII.GetBytes(path); // Create type tag string with a 'f' for each float StringBuilder typeTagBuilder = new StringBuilder(","); for (int i = 0; i < values.Length; i++) typeTagBuilder.Append('f'); byte[] typeTagBytes = Encoding.ASCII.GetBytes(typeTagBuilder.ToString()); // OSC message format: address, type tag, data byte[] message = new byte[ 4 * ((addressBytes.Length / 4) + 1) + // Address padded to multiple of 4 4 * ((typeTagBytes.Length / 4) + 1) + // Type tag padded to multiple of 4 4 * values.Length]; // Float values (4 bytes each) int index = 0; // Copy address and pad with zeros Array.Copy(addressBytes, 0, message, index, addressBytes.Length); index += 4 * ((addressBytes.Length / 4) + 1); // Copy type tag and pad with zeros Array.Copy(typeTagBytes, 0, message, index, typeTagBytes.Length); index += 4 * ((typeTagBytes.Length / 4) + 1); // Convert floats to big-endian bytes for (int i = 0; i < values.Length; i++) { byte[] valueBytes = BitConverter.GetBytes(values[i]); if (BitConverter.IsLittleEndian) Array.Reverse(valueBytes); Array.Copy(valueBytes, 0, message, index, 4); index += 4; } _client.Send(message, message.Length, _endpoint); } catch (Exception ex) { GD.PrintErr($"Error sending OSC message: {ex.Message}"); } } /// /// Send a Vector3 message /// /// OSC path /// Vector3 value public void SendMessage(string path, Vector3 vector) { SendMessage(path, new float[] { vector.X, vector.Y, vector.Z }); } /// /// Close the UDP client /// public void Close() { _client.Close(); } }