loupiottes/DMX-2.0/OSCServer.cs
2014-12-30 18:11:34 +00:00

625 lines
14 KiB
C#

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<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;
}
}
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);
Console.WriteLine(msg.Address);
foreach(var arg in msg.Args)
Console.WriteLine(arg.GetString());
ProcessMessage(msg,remep);
}
} catch (SocketException ex) {
}
finally {
}
}
/// <summary>
/// /master <X---
/// /masterseq/
/// go
/// goback
/// next <X---
/// goto
///
/// /seq/X/
/// go
/// goback
/// goto
/// master <X---
/// circuit/X <X---
///
/// /universe/X/
/// on/D
/// off
/// onval
///
///
/// </summary>
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)
univ.AllumageForce = dimId;
break;
case "off":
univ.AllumageForce = -1;
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)
{
Conduite.Courante.CircuitTelecomande =
Conduite.Courante.Circuits[cirId-1];
}
}
break;
case "off":
Conduite.Courante.CircuitTelecomande= null;
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
}
}