536 lines
11 KiB
C#
536 lines
11 KiB
C#
/*
|
|
|
|
Copyright (C) Arnaud Houdelette 2012-2014
|
|
Copyright (C) Emmanuel Langlois 2012-2014
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Xml;
|
|
using System.Collections.ObjectModel;
|
|
using System.Threading;
|
|
using System.Net.Sockets;
|
|
using System.Net;
|
|
|
|
namespace DMX2
|
|
{
|
|
public class SequenceurOSC : Sequenceur
|
|
{
|
|
public class Ligne {
|
|
public Ligne(){}
|
|
string nom = string.Empty;
|
|
TimeSpan top = TimeSpan.MinValue;
|
|
|
|
string commande =null;
|
|
|
|
public string Nom {
|
|
get {
|
|
return nom;
|
|
}
|
|
set {
|
|
nom = value;
|
|
}
|
|
}
|
|
|
|
public TimeSpan Top {
|
|
get {
|
|
return top;
|
|
}
|
|
set {
|
|
top = value;
|
|
}
|
|
}
|
|
|
|
public string Commande {
|
|
get {
|
|
return commande;
|
|
}
|
|
set{
|
|
commande = value;
|
|
}
|
|
}
|
|
|
|
public void Save (XmlElement parent)
|
|
{
|
|
XmlElement el = parent.OwnerDocument.CreateElement ("Ligne");
|
|
parent.AppendChild (el);
|
|
|
|
el.SetAttribute ("nom", nom);
|
|
el.SetAttribute ("top", top.ToString ());
|
|
|
|
el.SetAttribute ("cmd", commande);
|
|
|
|
}
|
|
|
|
public static Ligne Load (Conduite c, XmlElement el)
|
|
{
|
|
Ligne l = new Ligne();
|
|
l.nom = el.GetAttribute ("nom");
|
|
l.top = TimeSpan.Parse(el.GetAttribute("top"));
|
|
l.commande = el.GetAttribute ("cmd");
|
|
|
|
return l;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
List<Ligne> lignes = new List<Ligne>();
|
|
|
|
Ligne aSuivre = null;
|
|
Ligne enCours = null;
|
|
Ligne ligneMaitre = null;
|
|
|
|
TimeSpan timeStamp = TimeSpan.Zero;
|
|
TimeSpan topSuivant = TimeSpan.Zero;
|
|
bool topPresent = false;
|
|
|
|
actionEventTarget goNextEventTarget=null;
|
|
actionEventTarget goBackEventTarget=null;
|
|
|
|
string destination="";
|
|
|
|
SeqOscUI ui = null;
|
|
bool change = false;
|
|
|
|
UdpClient udpClient = new UdpClient();
|
|
IPEndPoint iPEndPoint = null;
|
|
|
|
|
|
bool paused=false;
|
|
|
|
public bool Paused {
|
|
get {
|
|
return paused;
|
|
}
|
|
set {
|
|
paused = value;
|
|
}
|
|
}
|
|
|
|
public string Destination
|
|
{
|
|
get
|
|
{
|
|
return destination;
|
|
}
|
|
set
|
|
{
|
|
destination = value;
|
|
SetEndpoint();
|
|
}
|
|
}
|
|
|
|
private void SetEndpoint()
|
|
{
|
|
IPAddress iPAddress;
|
|
int port;
|
|
string[] st = destination.Split(':');
|
|
iPEndPoint = null;
|
|
if (st.Length != 2) return;
|
|
if (!IPAddress.TryParse(st[0], out iPAddress)) return;
|
|
if (!int.TryParse(st[1], out port)) return;
|
|
iPEndPoint = new IPEndPoint(iPAddress, port);
|
|
udpClient.Connect(iPEndPoint);
|
|
}
|
|
|
|
public SequenceurOSC ()
|
|
{
|
|
|
|
goNextEventTarget = new actionEventTarget (
|
|
delegate(EventData data) {
|
|
if(data.value==255) LigneSuivante();
|
|
return true;
|
|
}
|
|
);
|
|
|
|
goBackEventTarget = new actionEventTarget (
|
|
delegate(EventData data) {
|
|
if(data.value==255){
|
|
if (IndexLigneEnCours > 0) {
|
|
IndexLigneaSuivre = IndexLigneEnCours - 1;
|
|
LigneSuivante ();
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
);
|
|
}
|
|
|
|
|
|
public int IndexLigneEnCours
|
|
{
|
|
get {
|
|
if (enCours == null) return -1;
|
|
return lignes.IndexOf(enCours);
|
|
}
|
|
}
|
|
|
|
|
|
public int IndexLigneaSuivre
|
|
{
|
|
get {
|
|
if (aSuivre == null)
|
|
return -1;
|
|
return lignes.IndexOf (aSuivre);
|
|
}
|
|
set {
|
|
aSuivre = lignes[value];
|
|
}
|
|
}
|
|
|
|
public int AjoutLigne (int pos)
|
|
{
|
|
lock (this) {
|
|
lignes.Insert (pos, new Ligne ());
|
|
CommandAdd(pos);
|
|
return pos;
|
|
}
|
|
}
|
|
|
|
public void RetireLigne (int pos)
|
|
{
|
|
lock (this) {
|
|
if (lignes [pos] == enCours) {
|
|
enCours = null;
|
|
if (pos + 1 < lignes.Count)
|
|
aSuivre = lignes [pos + 1];
|
|
}
|
|
if (lignes [pos] == aSuivre)
|
|
aSuivre = null;
|
|
lignes.RemoveAt (pos);
|
|
CommandRemove(pos);
|
|
}
|
|
}
|
|
|
|
public TimeSpan TimeStamp {
|
|
get {
|
|
return timeStamp;
|
|
}
|
|
}
|
|
|
|
|
|
public ReadOnlyCollection<Ligne> Lignes {
|
|
get {
|
|
return lignes.AsReadOnly();
|
|
}
|
|
}
|
|
|
|
public override int ValeurCircuit (Circuit c)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
public override void Tick (TimeSpan time)
|
|
{
|
|
if (paused)
|
|
return;
|
|
timeStamp += time;
|
|
|
|
if (Monitor.TryEnter (this)) {
|
|
try {
|
|
while (topPresent&&(timeStamp >= topSuivant)) {
|
|
LigneSuivante ();
|
|
}
|
|
} finally {
|
|
Monitor.Exit (this);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void LigneSuivante ()
|
|
{
|
|
lock (this) {
|
|
if(lignes.Count==0) return;
|
|
int index;
|
|
change = true; topPresent = false;
|
|
if(aSuivre==null) // selection souris
|
|
{
|
|
index = IndexLigneEnCours +1; // Premier effet si aucun précédement
|
|
if(index>= lignes.Count) index = 0; // Boucle si arrivé à la fin
|
|
|
|
enCours = lignes[index];
|
|
|
|
// Gestion de la Reprise
|
|
// if(enCours.Circuits.ToLower().Equals("r") && ligneMaitre != null)
|
|
// enCours = ligneMaitre;
|
|
|
|
if(enCours.Nom.Length!=0)
|
|
{
|
|
ligneMaitre = enCours;
|
|
timeStamp = TimeSpan.Zero;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
enCours = aSuivre;
|
|
ligneMaitre = enCours;
|
|
timeStamp = TimeSpan.Zero;
|
|
|
|
}
|
|
index = IndexLigneEnCours+1;
|
|
if(index<lignes.Count)
|
|
{
|
|
// Si top présent - non negatif
|
|
if(lignes[index].Top>= TimeSpan.Zero)
|
|
{
|
|
topPresent = true;
|
|
topSuivant= lignes[index].Top;
|
|
}
|
|
}
|
|
aSuivre = null;
|
|
LanceCommandeOSC();
|
|
if(ui!=null)
|
|
ui.EffetChange();
|
|
}
|
|
}
|
|
|
|
void LanceCommandeOSC()
|
|
{
|
|
|
|
Console.WriteLine(enCours.Commande);
|
|
|
|
string[] data = enCours.Commande.Split(' ');
|
|
|
|
int di;
|
|
float df;
|
|
|
|
OSCMessage message = new OSCMessage(data[0]);
|
|
for (int i = 1; i < data.Length; i++)
|
|
{
|
|
if (int.TryParse(data[i], out di))
|
|
message.AddInt(di);
|
|
else if (float.TryParse(data[i], out df))
|
|
message.AddFloat(df);
|
|
else message.AddString(data[i]);
|
|
}
|
|
|
|
|
|
var buff = message.Encode();
|
|
udpClient.Send(buff, buff.Length);
|
|
}
|
|
|
|
|
|
|
|
public bool LigneChange ()
|
|
{
|
|
if (change) {
|
|
change = false;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public override void Save (System.Xml.XmlElement parent)
|
|
{
|
|
System.Xml.XmlElement el = parent.OwnerDocument.CreateElement ("SequenceurOSC");
|
|
System.Xml.XmlElement xmlEl;
|
|
|
|
parent.AppendChild (el);
|
|
el.SetAttribute ("id", ID.ToString ());
|
|
el.SetAttribute ("name", Name);
|
|
el.SetAttribute ("destination", Destination);
|
|
//el.SetAttribute ("master", master.ToString ());
|
|
|
|
xmlEl = parent.OwnerDocument.CreateElement ("EffetSuivant");
|
|
if(Conduite.Courante.EventManager.SaveBindings(xmlEl,goNextEventTarget )) el.AppendChild(xmlEl);
|
|
|
|
xmlEl = parent.OwnerDocument.CreateElement ("EffetPrecedent");
|
|
if(Conduite.Courante.EventManager.SaveBindings(xmlEl,goBackEventTarget )) el.AppendChild(xmlEl);
|
|
|
|
foreach (Ligne li in lignes) {
|
|
li.Save(el);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
public override SequenceurUI GetUI ()
|
|
{
|
|
|
|
if (ui == null) {
|
|
ui = new SeqOscUI (this);
|
|
ui.Destroyed += UiDestroyed;
|
|
}
|
|
|
|
return ui;
|
|
}
|
|
|
|
void UiDestroyed (object sender, EventArgs e)
|
|
{
|
|
ui = null;
|
|
}
|
|
|
|
public void BindEffetSuivantEvent (string eventId)
|
|
{
|
|
if (eventId.Length == 0) {
|
|
Conduite.Courante.EventManager.Unbind (goNextEventTarget);
|
|
return;
|
|
}
|
|
Conduite.Courante.EventManager.Bind(eventId,goNextEventTarget);
|
|
}
|
|
|
|
public void BindEffetPrecedentEvent (string eventId)
|
|
{
|
|
if (eventId.Length == 0) {
|
|
Conduite.Courante.EventManager.Unbind (goBackEventTarget);
|
|
return;
|
|
}
|
|
Conduite.Courante.EventManager.Bind(eventId,goBackEventTarget);
|
|
}
|
|
|
|
|
|
public static new SequenceurOSC Load (Conduite conduite, System.Xml.XmlElement el)
|
|
{
|
|
SequenceurOSC seq = new SequenceurOSC();
|
|
seq.LoadSeq(conduite,el);
|
|
return seq;
|
|
}
|
|
|
|
private void LoadSeq (Conduite conduite, System.Xml.XmlElement el)
|
|
{
|
|
ID = int.Parse (el.GetAttribute ("id"));
|
|
Name = el.GetAttribute ("name");
|
|
Destination = el.TryGetAttribute("destination", "224.0.0.3:8888");
|
|
|
|
XmlElement xmlE;
|
|
|
|
|
|
if ((xmlE = el["EffetSuivant"])!= null)
|
|
foreach(string id in EventManager.LoadBindings(xmlE))
|
|
BindEffetSuivantEvent(id);
|
|
|
|
if ((xmlE = el["EffetPrecedent"])!= null)
|
|
foreach(string id in EventManager.LoadBindings(xmlE))
|
|
BindEffetPrecedentEvent(id);
|
|
|
|
|
|
foreach (var xe in el.GetElementsByTagName("Ligne"))
|
|
lignes.Add(Ligne.Load(conduite,xe as System.Xml.XmlElement));
|
|
}
|
|
|
|
|
|
static System.Text.RegularExpressions.Regex regexCommand1 = new System.Text.RegularExpressions.Regex(
|
|
@"(?<effet>\d+)",
|
|
System.Text.RegularExpressions.RegexOptions.Compiled);
|
|
|
|
static System.Text.RegularExpressions.Regex regexCommand2 = new System.Text.RegularExpressions.Regex(
|
|
@"(?<effet>\d+)(?<params>(t\d+)?)?",
|
|
System.Text.RegularExpressions.RegexOptions.Compiled);
|
|
|
|
|
|
|
|
public override void Command (string command)
|
|
{
|
|
lock (this) {
|
|
var cmd = regexCommand1.Match(command);
|
|
|
|
if (cmd.Success) {
|
|
if (cmd.Groups ["effet"].Success) {
|
|
int effet = int.Parse (cmd.Groups ["effet"].Value) - 1;
|
|
|
|
if(effet>=lignes.Count) return;
|
|
enCours = lignes[effet];
|
|
ligneMaitre = enCours;
|
|
timeStamp = TimeSpan.Zero;
|
|
|
|
topPresent = false;
|
|
int index = IndexLigneEnCours+1;
|
|
if(index<lignes.Count)
|
|
{
|
|
// Si top présent - non negatif
|
|
if(lignes[index].Top>= TimeSpan.Zero)
|
|
{
|
|
topPresent = true;
|
|
topSuivant= lignes[index].Top;
|
|
}
|
|
}
|
|
aSuivre = null;
|
|
|
|
LanceCommandeOSC();
|
|
|
|
if(ui!=null) ui.EffetChange();
|
|
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
void CommandAdd (int index)
|
|
{
|
|
lock (Conduite.Courante.SequenceurMaitre) {
|
|
string[] commands = Conduite.Courante.SequenceurMaitre.GetCommands (this);
|
|
|
|
for (int i = 0; i < commands.Length; i++) {
|
|
var cmd = regexCommand2.Match(commands[i]);
|
|
if(cmd.Success){
|
|
int ef = int.Parse(cmd.Groups["effet"].Value);
|
|
if (ef-1>index) {
|
|
ef++;
|
|
commands[i] = ef.ToString() + cmd.Groups["params"].Value;
|
|
}
|
|
}
|
|
}
|
|
Conduite.Courante.SequenceurMaitre.SetCommands(this,commands);
|
|
}
|
|
}
|
|
|
|
void CommandRemove (int index)
|
|
{
|
|
lock (Conduite.Courante.SequenceurMaitre) {
|
|
string[] commands = Conduite.Courante.SequenceurMaitre.GetCommands (this);
|
|
|
|
for (int i = 0; i < commands.Length; i++) {
|
|
var cmd = regexCommand2.Match(commands[i]);
|
|
if(cmd.Success){
|
|
int ef = int.Parse(cmd.Groups["effet"].Value);
|
|
if (ef-1 == index)
|
|
commands[i] = string.Empty;
|
|
else if (ef-1>index) {
|
|
ef--;
|
|
commands[i] = ef.ToString() + cmd.Groups["params"].Value;
|
|
}
|
|
}
|
|
}
|
|
Conduite.Courante.SequenceurMaitre.SetCommands(this,commands);
|
|
}
|
|
}
|
|
|
|
void CommandSwap (int index)
|
|
{
|
|
lock (Conduite.Courante.SequenceurMaitre) {
|
|
string[] commands = Conduite.Courante.SequenceurMaitre.GetCommands (this);
|
|
|
|
// numeros a swapper
|
|
int a = index+1;
|
|
int b = index+2;
|
|
|
|
for (int i = 0; i < commands.Length; i++) {
|
|
var cmd = regexCommand2.Match(commands[i]);
|
|
if(cmd.Success){
|
|
int ef = int.Parse(cmd.Groups["effet"].Value);
|
|
if (ef == a)
|
|
commands[i] = b.ToString() + cmd.Groups["params"].Value;
|
|
if (ef == b)
|
|
commands[i] = a.ToString() + cmd.Groups["params"].Value;
|
|
}
|
|
}
|
|
Conduite.Courante.SequenceurMaitre.SetCommands(this,commands);
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|