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