loupiottes/DMX-2.0/OSCMessage.cs
2018-10-04 17:12:24 +02:00

323 lines
8.5 KiB
C#

using System;
namespace DMX2
{
public class OSCMessage
{
public enum OSCType
{
Int32,
Float32,
String,
Blob
}
public abstract class OSCArg
{
protected OSCArg() { }
public abstract OSCType Type { get; }
public virtual string GetString() { throw new System.NotImplementedException(); }
public virtual float GetFloat() { throw new System.NotImplementedException(); }
public virtual int GetInt() { throw new System.NotImplementedException(); }
public virtual byte[] GetBlob() { throw new System.NotImplementedException(); }
}
private class OSCStringArg : OSCArg
{
string _s;
public override OSCType Type
{
get
{
return OSCType.String;
}
}
public OSCStringArg(string s)
{
_s = s;
}
public override string GetString()
{
return _s;
}
public override float GetFloat()
{
float f;
if (float.TryParse(_s, out f)) return f;
return 0.0f;
}
public override int GetInt()
{
return (int)GetFloat();
}
}
private class OSCIntArg : OSCArg
{
int _i;
public override OSCType Type
{
get
{
return OSCType.Int32;
}
}
public OSCIntArg(int i)
{
_i = i;
}
public override int GetInt()
{
return _i;
}
public override float GetFloat()
{
return (float)_i;
}
public override string GetString()
{
return _i.ToString();
}
}
private class OSCFloatArg : OSCArg
{
float _f;
public override OSCType Type
{
get
{
return OSCType.Float32;
}
}
public OSCFloatArg(float f)
{
_f = f;
}
public override int GetInt()
{
return (int)(_f);
}
public override float GetFloat()
{
return _f;
}
public override string GetString()
{
return _f.ToString();
}
}
private class OSCBlobArg : OSCArg
{
byte[] _b;
public override OSCType Type
{
get
{
return OSCType.Blob;
}
}
public OSCBlobArg(byte[] b)
{
_b = b;
}
public override byte[] GetBlob()
{
return _b;
}
}
static string DecodeString(byte[] b, ref int pos)
{
int end = Array.IndexOf<byte>(b, 0, pos);
if (end == -1) end = b.Length;
string ret = System.Text.Encoding.ASCII.GetString(b, pos, end - pos);
pos = (end / 4 + 1) * 4;
return ret;
}
static float DecodeFloat(byte[] b, ref int pos)
{
if (BitConverter.IsLittleEndian)
Array.Reverse(b, pos, 4);
float ret = BitConverter.ToSingle(b, pos);
pos += 4;
return ret;
}
static int DecodeInt(byte[] b, ref int pos)
{
if (BitConverter.IsLittleEndian)
Array.Reverse(b, pos, 4);
int ret = BitConverter.ToInt32(b, pos);
pos += 4;
return ret;
}
public OSCMessage(byte[] bmsg)
{
int pos = 0;
Address = DecodeString(bmsg, ref pos);
string typestring = DecodeString(bmsg, ref pos);
args = new OSCArg[typestring.Length - 1];
int idx = 0;
foreach (char c in typestring)
{
switch (c)
{
case 'f':
args[idx++] = new OSCFloatArg(DecodeFloat(bmsg, ref pos));
break;
case 's':
args[idx++] = new OSCStringArg(DecodeString(bmsg, ref pos));
break;
case 'i':
args[idx++] = new OSCIntArg(DecodeInt(bmsg, ref pos));
break;
case 'b':
int len = DecodeInt(bmsg, ref pos) * 4;
byte[] b = new byte[len];
bmsg.CopyTo(b, 0);
pos += len;
args[idx++] = new OSCBlobArg(b);
break;
}
}
}
public string Address
{
get;
private set;
}
OSCArg[] args;
public OSCArg[] Args
{
get
{
return args;
}
}
// Construction de message
public OSCMessage(string _address)
{
Address = _address;
}
void AddArg(OSCArg arg)
{
if (args == null)
{
args = new OSCArg[1];
}
else
{
OSCArg[] na = new OSCArg[args.Length + 1];
args.CopyTo(na, 0);
args = na;
}
args[args.Length - 1] = arg;
}
public void AddString(string arg)
{
AddArg(new OSCStringArg(arg));
}
public void AddInt(int arg)
{
AddArg(new OSCIntArg(arg));
}
public void AddFloat(float arg)
{
AddArg(new OSCFloatArg(arg));
}
public byte[] Encode()
{
int len = System.Text.ASCIIEncoding.ASCII.GetByteCount(Address) / 4 + 1;
string typestring = ",";
foreach (var arg in args)
{
switch (arg.Type)
{
case OSCType.Int32:
len += 1;
typestring += "i";
break;
case OSCType.Float32:
len += 1;
typestring += "f";
break;
case OSCType.String:
len += System.Text.ASCIIEncoding.ASCII.GetByteCount(arg.GetString()) / 4 + 1;
typestring += "s";
break;
}
}
len += typestring.Length / 4 + 1;
byte[] res = new byte[len * 4];
int pos = 0;
EncodeString(res, ref pos, Address);
EncodeString(res, ref pos, typestring);
foreach (var arg in args)
{
switch (arg.Type)
{
case OSCType.Int32:
EncodeInt(res, ref pos, arg.GetInt());
break;
case OSCType.Float32:
EncodeFloat(res, ref pos, arg.GetFloat());
break;
case OSCType.String:
EncodeString(res, ref pos, arg.GetString());
break;
}
}
return res;
}
void EncodeString(byte[] buff, ref int pos, string s)
{
pos +=
System.Text.ASCIIEncoding.ASCII.GetBytes(
s, 0, s.Length, buff, pos);
do
{
buff[pos++] = 0;
} while (pos % 4 != 0);
}
void EncodeInt(byte[] res, ref int pos, int i)
{
byte[] buff = BitConverter.GetBytes(i);
if (BitConverter.IsLittleEndian)
Array.Reverse(buff);
buff.CopyTo(res, pos);
pos += 4;
}
void EncodeFloat(byte[] res, ref int pos, float f)
{
byte[] buff = BitConverter.GetBytes(f);
if (BitConverter.IsLittleEndian)
Array.Reverse(buff);
buff.CopyTo(res, pos);
pos += 4;
}
}
}