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();
}
}