using System; using System.Net; using System.Net.Sockets; using System.Threading; using System.Collections.Generic; namespace DMX2 { public class OSCServer : IDisposable { UdpClient udpCli=null; Thread pollThread = null; bool running=true; enum OSCType { Int32, Float32, String, Blob } class OSCMessage { 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; } } public OSCServer () { pollThread = new Thread(new ThreadStart(Loop)); pollThread.Start(); } void Loop () { udpCli = new UdpClient (7772); byte[] recv; IPEndPoint remep = new IPEndPoint (IPAddress.Any, 0); try { while (running) { recv = udpCli.Receive (ref remep); //Console.WriteLine(remep); OSCMessage msg = new OSCMessage(recv); #if DEBUG Console.Write(msg.Address); Console.Write(" "); foreach(var arg in msg.Args) Console.WriteLine(arg.GetString()); #endif try{ ProcessMessage(msg,remep); }catch{} } } catch (SocketException ex) { } finally { } } /// /// /master void ProcessMessage (OSCMessage msg,IPEndPoint remep) { if(Conduite.Courante == null) return; string[] toks = msg.Address.Split (new char[]{'/'},StringSplitOptions.RemoveEmptyEntries); int arg; switch (toks [0]) { case "refresh": IPEndPoint ep = new IPEndPoint(remep.Address,msg.Args[0].GetInt()); SendRefresh(ep); break; case "master": arg = msg.Args[0].GetInt(); if (arg<0) arg=0; if (arg>100)arg=100; Conduite.Courante.Master = arg; break; case "masterseq": switch(toks[1]){ case "go": if( msg.Args[0].GetInt() !=0) Conduite.Courante.SequenceurMaitre.EffetSuivant(); break; case "goback": if( msg.Args[0].GetInt() !=0) Conduite.Courante.SequenceurMaitre.EffetPrecedent(); break; case "next": arg = msg.Args[0].GetInt(); Conduite.Courante.SequenceurMaitre.IndexLigneaSuivre = arg; break; case "goto": arg = msg.Args[0].GetInt(); Conduite.Courante.SequenceurMaitre.IndexLigneaSuivre = arg; Conduite.Courante.SequenceurMaitre.EffetSuivant(); break; } break; case "seq": ProcessMessageSeq(msg,toks); break; case "universe": ProcessMessageUniv(msg,toks); break; case "circuitTel": ProcessMessageCircuit(msg,toks); break; } } void ProcessMessageSeq (OSCMessage msg, string[] toks) { int seqId; Sequenceur seq = null; if (int.TryParse (toks [1], out seqId)) { if (seqId < 0 || seqId > Conduite.Courante.Sequenceurs.Count) return; seq = Conduite.Courante.Sequenceurs [seqId-1]; } if (seq is SequenceurLineaire) { SequenceurLineaire seql = seq as SequenceurLineaire; switch(toks[2]){ case "go": if( msg.Args[0].GetInt() !=0) seql.IndexEffetCourrant++; break; case "goback": if( msg.Args[0].GetInt() !=0) seql.IndexEffetCourrant--; break; case "goto": int arg = msg.Args[0].GetInt(); seql.IndexEffetCourrant = arg; break; case "master": arg = msg.Args[0].GetInt(); if (arg<0) arg=0; if (arg>100)arg=100; seql.Master = arg; break; case "circuit": int cirId; arg = msg.Args[0].GetInt(); arg = Math.Max(0,arg); arg = Math.Min(255,arg); if(!int.TryParse(toks[3],out cirId)) return; Circuit c = Conduite.Courante.GetCircuitByID (cirId); if(seql.Circuits.Contains(c)) seql.ChangeValeur(c,arg); break; } } if (seq is SequenceurMacro) { SequenceurMacro seqm = seq as SequenceurMacro; switch(toks[2]){ case "go": if( msg.Args[0].GetInt() !=0) seqm.LigneSuivante(); break; case "goto": int arg = msg.Args[0].GetInt(); seqm.IndexLigneaSuivre = arg; seqm.LigneSuivante(); break; case "next": arg = msg.Args[0].GetInt(); seqm.IndexLigneaSuivre = arg; break; case "master": arg = msg.Args[0].GetInt(); if (arg<0) arg=0; if (arg>100)arg=100; seqm.Master = arg; break; } } if (seq is SequenceurSon) { SequenceurSon seqs = seq as SequenceurSon; switch(toks[2]){ case "master": int arg = msg.Args[0].GetInt(); if (arg<0) arg=0; if (arg>100)arg=100; seqs.Volume = (uint)arg; break; } } } void ProcessMessageUniv (OSCMessage msg, string[] toks) { int univId; if (!int.TryParse (toks [1], out univId)) return; if (univId <= 0 || univId > Conduite.Courante.Patches.Count) return; UniversDMX univ = Conduite.Courante.Patches [univId-1]; switch (toks [2]) { case "on": int dimId; if(!int.TryParse(toks[3],out dimId))return; if( msg.Args[0].GetInt() !=0) if(!univ.AllumageForce.Contains(dimId)) univ.AllumageForce.Add(dimId); break; case "off": if(!int.TryParse(toks[3],out dimId))return; if( msg.Args[0].GetInt() !=0) if(univ.AllumageForce.Contains(dimId)) univ.AllumageForce.Remove(dimId); break; case "alloff": univ.AllumageForce.Clear(); break; case "onval": int val = msg.Args[0].GetInt(); if(val<0) val=0; if(val>255) val=255; univ.AllumageForceVal = val; break; } } void ProcessMessageCircuit (OSCMessage msg, string[] toks) { switch (toks [1]) { case "on": { int cirId; if (!int.TryParse (toks [2], out cirId)) return; if (msg.Args [0].GetInt () != 0) { if (cirId > 0 && cirId <= Conduite.Courante.Circuits.Count) { Circuit c = Conduite.Courante.Circuits [cirId - 1]; if (!Conduite.Courante.CircuitTelecomande.Contains (c)) Conduite.Courante.CircuitTelecomande.Add (c); } } } break; case "off": { int cirId; if (!int.TryParse (toks [2], out cirId)) return; if (msg.Args [0].GetInt () != 0) { if (cirId > 0 && cirId <= Conduite.Courante.Circuits.Count) { Circuit c = Conduite.Courante.Circuits [cirId - 1]; if (Conduite.Courante.CircuitTelecomande.Contains (c)) Conduite.Courante.CircuitTelecomande.Remove (c); } } } break; case "alloff": Conduite.Courante.CircuitTelecomande.Clear(); break; case "onval": int val = msg.Args[0].GetInt(); if(val<0) val=0; if(val>255) val=255; Conduite.Courante.CircuitTelecomandeVal = val; break; } } void SendRefresh (IPEndPoint ep) { OSCMessage msg = new OSCMessage ("/master"); msg.AddFloat (Conduite.Courante.Master); byte[] buff = msg.Encode (); udpCli.Send (buff, buff.Length, ep); var id = Conduite.Courante.SequenceurMaitre.IndexLigneEnCours - 1; msg = new OSCMessage ("/masterseq/prevstep"); if (id >= 0) { msg.AddString ( string.Format ("{0}. {1}", id + 1, Conduite.Courante.SequenceurMaitre.Lignes [id].Nom) ); } else { msg.AddString ("---"); } buff = msg.Encode (); udpCli.Send (buff, buff.Length, ep); id = Conduite.Courante.SequenceurMaitre.IndexLigneEnCours; string auto = string.Empty; msg = new OSCMessage ("/masterseq/curstep"); if (id >= 0) { msg.AddString ( string.Format ("{0}. {1}", id + 1, Conduite.Courante.SequenceurMaitre.Lignes [id].Nom) ); if(Conduite.Courante.SequenceurMaitre.Lignes[id].Duree!= TimeSpan.Zero) auto = string.Format(" (AUTO {0})",Conduite.Courante.SequenceurMaitre.Lignes[id].Duree.TotalMilliseconds/100); } else { msg.AddString ("---"); } buff = msg.Encode(); udpCli.Send (buff, buff.Length, ep); id = Conduite.Courante.SequenceurMaitre.IndexLigneaSuivre; if (id == -1) id = Conduite.Courante.SequenceurMaitre.IndexLigneEnCours + 1; msg = new OSCMessage ("/masterseq/nextstep"); if (id >= 0 && id < Conduite.Courante.SequenceurMaitre.Lignes.Count) { msg.AddString ( string.Format ("{0}. {1}{2}", id + 1, Conduite.Courante.SequenceurMaitre.Lignes [id].Nom,auto) ); } else { msg.AddString ("---"); } buff = msg.Encode (); udpCli.Send (buff, buff.Length, ep); msg = new OSCMessage("/masterseq/time"); msg.AddFloat(((float) Conduite.Courante.SequenceurMaitre.TimeStamp.TotalMilliseconds/1000 )); buff = msg.Encode(); udpCli.Send (buff, buff.Length, ep); } #region IDisposable implementation public void Dispose () { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose (bool disposing) { if (disposing) { running=false; if(udpCli!=null) udpCli.Close(); if(pollThread!=null) { if(!pollThread.Join(100)) pollThread.Abort(); pollThread=null; } } } #endregion } }