loupiottes/DMX-2.0/SequenceurSon.cs
2017-04-02 20:43:58 +02:00

462 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.Collections.ObjectModel;
using System.Linq;
using System.Threading;
using System.Diagnostics;
using System.Xml;
using System.Globalization;
namespace DMX2
{
public class SequenceurSon : Sequenceur, IDisposable
{
SeqSonUI ui=null;
Process mplayerProcess = null;
List<string> files = new List<string>();
string curfile = string.Empty;
uint volume=100;
TimeSpan fading=TimeSpan.Zero;
TimeSpan fadeLen;
int fadeVStart;
int fadeVEnd;
TimeSpan duration = TimeSpan.Zero;
TimeSpan position = TimeSpan.Zero;
bool repeat = false;
actionEventTargetEx volumeEventTarget=null;
public ReadOnlyCollection<string> Files {
get {
return files.AsReadOnly();
}
}
public string CurFile {
get{return curfile; }
}
public int Index {
get {
return files.IndexOf (curfile);
}
set {
repeat = false;
if(value>=0 && value< files.Count)
lock(this)
LoadFile(value);
}
}
bool Paused{ get; set;}
bool CheckMplayer(){
if (mplayerProcess == null || mplayerProcess.HasExited) {
if (mplayerProcess != null)
mplayerProcess.Dispose ();
ProcessStartInfo startinfo = new ProcessStartInfo ();
startinfo.FileName = "mplayer";
startinfo.Arguments = "-quiet -idle -slave";
startinfo.RedirectStandardInput = true;
startinfo.RedirectStandardOutput = true;
startinfo.UseShellExecute = false;
mplayerProcess = Process.Start (startinfo);
mplayerProcess.OutputDataReceived += ProcessMplayerOut;
mplayerProcess.BeginOutputReadLine ();
return !mplayerProcess.HasExited;
}
return true;
}
void ProcessMplayerOut (object sender, DataReceivedEventArgs e)
{
string data = e.Data;
if (data == null)
return;
if (data.StartsWith ("ANS_LENGTH")) {
string d = data.Substring (11);
double dData;
if(double.TryParse(d,NumberStyles.Number,CultureInfo.InvariantCulture,out dData))
duration = TimeSpan.FromSeconds( dData );
}
if (data.StartsWith ("ANS_TIME_POSITION")) {
string d = data.Substring (18);
double dData;
if(double.TryParse(d,NumberStyles.Number,CultureInfo.InvariantCulture,out dData))
position = TimeSpan.FromSeconds( dData );
}
Console.WriteLine ("data => {0}", data);
}
public int AddFile (int pos, string file)
{
lock (this) {
if(files.Contains(file)) return -1;
files.Insert (pos, file);
CommandAdd(pos);
return pos;
}
}
public uint Volume {
get{ return volume;}
set {
volume=value;
mplayerProcess.StandardInput.WriteLine ("volume {0} 1", volume);
volumeEventTarget.FeedBack ();
}
}
public TimeSpan PlayTime {
get{
if(mplayerProcess!=null && !mplayerProcess.HasExited)
mplayerProcess.StandardInput.WriteLine ("get_time_pos");
return position;
}
set{
if (CheckMplayer ()) {
mplayerProcess.StandardInput.WriteLine ("seek {0} 2", value.TotalMilliseconds / 1000);
}
}
}
public TimeSpan Duration {
get {
return duration;
}
}
public void DelFile (int pos)
{
lock (this) {
files.RemoveAt (pos);
CommandRemove(pos);
}
}
void LoadFile (int pos)
{
//Console.WriteLine("LoadFile");
curfile = files[pos];
Stop();
mplayerProcess.StandardInput.WriteLine ("volume 0 1");
mplayerProcess.StandardInput.WriteLine ("loadfile \"{0}\" 0", curfile);
mplayerProcess.StandardInput.WriteLine ("get_time_length");
mplayerProcess.StandardInput.WriteLine ("pausing seek 0 2");
mplayerProcess.StandardInput.WriteLine ("volume {0} 1", volume);
Paused = true;
}
public void Play ()
{
if (curfile==null || !Paused)
return;
if (!CheckMplayer ())
return;
mplayerProcess.StandardInput.WriteLine ("pause");
Paused = false;
}
public void Pause ()
{
if (curfile==null || Paused)
return;
if (!CheckMplayer ())
return;
mplayerProcess.StandardInput.WriteLine ("pause");
Paused = true;
}
public void Stop ()
{
CheckMplayer ();
mplayerProcess.StandardInput.WriteLine ("stop");
}
public SequenceurSon ()
{
volumeEventTarget = new actionEventTargetEx (
delegate(EventData data) {
Volume = (uint)(100 * data.value / 255);
return true;
},
delegate{
return (int)(Volume * 255 /100);
},
true
);
}
#region implemented abstract members of DMX2.Sequenceur
public override SequenceurUI GetUI ()
{
if (ui == null) {
ui = new SeqSonUI (this);
ui.Destroyed += UiDestroyed;
}
return ui;
}
void UiDestroyed (object sender, EventArgs e)
{
ui=null;
}
public override int ValeurCircuit (Circuit c)
{
return 0;
}
public string State {
get {
return string.Empty;
}
}
void UpdateState ()
{
}
public override void Tick (TimeSpan time)
{
if (fading != TimeSpan.Zero) {
fading-=time;
if(fading<=TimeSpan.Zero){
Volume = (uint)fadeVEnd;
fading=TimeSpan.Zero;
}
else{
Volume = (uint)(
fadeVEnd + (fadeVStart-fadeVEnd) *
fading.TotalMilliseconds / fadeLen.TotalMilliseconds);
}
}
if (repeat) {
}
}
public override void Save (System.Xml.XmlElement parent)
{
System.Xml.XmlElement el = parent.OwnerDocument.CreateElement ("SequenceurSon");
System.Xml.XmlElement xmlEl;
parent.AppendChild (el);
el.SetAttribute ("id", ID.ToString ());
el.SetAttribute ("name", Name);
foreach (string file in files) {
el.AppendChild(xmlEl = parent.OwnerDocument.CreateElement ("File"));
xmlEl.SetAttribute("path",file);
}
}
public static new SequenceurSon Load (Conduite conduite, System.Xml.XmlElement el)
{
SequenceurSon seq = new SequenceurSon();
seq.LoadSeq(conduite,el);
return seq;
}
void LoadSeq (Conduite conduite, System.Xml.XmlElement el)
{
ID = int.Parse (el.GetAttribute ("id"));
Name = el.GetAttribute ("name");
foreach (var xf in el.GetElementsByTagName("File")) {
System.Xml.XmlElement xfil = xf as System.Xml.XmlElement;
string file = xfil.GetAttribute ("path");
files.Add(file);
}
}
static System.Text.RegularExpressions.Regex regexCommand1 = new System.Text.RegularExpressions.Regex(
@"(?<file>\d+)?(g(?<goto>[\d\.:]+))?(v(?<volume>\d+)(,(?<fade>\d+))?)?(?<play>(ps|p|s))?(?<repeat>(r))?",
System.Text.RegularExpressions.RegexOptions.Compiled);
static System.Text.RegularExpressions.Regex regexCommand2 = new System.Text.RegularExpressions.Regex(
@"^(?<file>\d+)(?<params>[gvpsr](.+)?)?",
System.Text.RegularExpressions.RegexOptions.Compiled);
public override void Command (string command)
{
//Console.WriteLine("Command");
lock (this) {
var cmd = regexCommand1.Match (command);
if (cmd.Success) {
if (cmd.Groups ["file"].Success) {
int filen = int.Parse (cmd.Groups ["file"].Value) - 1;
if (filen >= files.Count)
return;
Index = filen;
if (ui != null)
ui.updateflag = true;
}
if (cmd.Groups ["goto"].Success) {
string[] formats = new string[]{
@"m\:s\.f", @"m\:s", @"h\:m\:s",@"h\:m\:s\.f"
};
TimeSpan ts;
if(TimeSpan.TryParseExact(
cmd.Groups ["goto"].Value,formats,null,out ts)) {
PlayTime = ts;
}
}
if (cmd.Groups ["volume"].Success) {
uint vol = uint.Parse (cmd.Groups ["volume"].Value);
if(vol>100) vol=100;
if(cmd.Groups ["fade"].Success) {
fadeLen = fading = TimeSpan.FromMilliseconds (100*int.Parse (cmd.Groups ["fade"].Value));
fadeVStart = (int)volume;
fadeVEnd = (int)vol;
}
else{
fading = TimeSpan.Zero;
Volume = vol;
if (ui != null)
ui.updateflag = true;
}
}
if (cmd.Groups ["play"].Success) {
switch(cmd.Groups ["play"].Value)
{
case "p":
Play();
break;
case "ps":
Pause();
break;
case "s":
Stop();
break;
}
}
if (cmd.Groups ["repeat"].Success) {
repeat = true;
}
}
}
}
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["file"].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["file"].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["file"].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);
}
}
#endregion
#region IDisposable implementation
void IDisposable.Dispose ()
{
if (mplayerProcess != null && !mplayerProcess.HasExited) {
mplayerProcess.StandardInput.WriteLine ("quit");
if (!mplayerProcess.WaitForExit (1000))
mplayerProcess.Kill ();
}
}
#endregion
}
}