423 lines
9.4 KiB
C#
423 lines
9.4 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.Xml;
|
|
|
|
namespace DMX2
|
|
{
|
|
|
|
// TODO : Sauvegarde et chargement
|
|
|
|
public class SequenceurSon : Sequenceur
|
|
{
|
|
~SequenceurSon()
|
|
{
|
|
if(element!=null)
|
|
Stop();
|
|
element=null;
|
|
}
|
|
|
|
SeqSonUI ui=null;
|
|
|
|
static bool gsinit=false;
|
|
|
|
List<string> files = new List<string>();
|
|
|
|
string curfile = string.Empty;
|
|
|
|
uint volume=100;
|
|
|
|
delegate void Task ();
|
|
|
|
Queue<Task> taskQueue = new Queue<Task>();
|
|
|
|
TimeSpan fading=TimeSpan.Zero;
|
|
TimeSpan fadeLen;
|
|
int fadeVStart;
|
|
int fadeVEnd;
|
|
|
|
Gst.Element element = null;
|
|
|
|
public ReadOnlyCollection<string> Files {
|
|
get {
|
|
return files.AsReadOnly();
|
|
}
|
|
}
|
|
|
|
public string CurFile {
|
|
get{return curfile; }
|
|
}
|
|
|
|
public int Index {
|
|
get {
|
|
return files.IndexOf (curfile);
|
|
}
|
|
set {
|
|
if(value>=0 && value< files.Count)
|
|
LoadFile(value);
|
|
}
|
|
}
|
|
|
|
public int AddFile (int pos, string file)
|
|
{
|
|
lock (this) {
|
|
files.Insert (pos, file);
|
|
CommandAdd(pos);
|
|
return pos;
|
|
}
|
|
}
|
|
|
|
public uint Volume {
|
|
get{ return volume;}
|
|
set {
|
|
volume=value;
|
|
if(element!=null)
|
|
element["volume"] = (double)volume / 100.0d ;
|
|
}
|
|
}
|
|
|
|
public TimeSpan PlayTime {
|
|
get{
|
|
if(element==null) return TimeSpan.Zero;
|
|
Gst.Format format = Gst.Format.Time ;
|
|
long cur;
|
|
element.QueryPosition(ref format, out cur);
|
|
return TimeSpan.FromMilliseconds(cur/1000000);
|
|
}
|
|
set{
|
|
if(element==null) return;
|
|
if(element.CurrentState != Gst.State.Paused && element.CurrentState != Gst.State.Playing){
|
|
lock(taskQueue)taskQueue.Enqueue(delegate(){
|
|
PlayTime = value;
|
|
});
|
|
return;
|
|
}
|
|
long pos = (long)(value.TotalMilliseconds) * 1000000;
|
|
element.Seek (Gst.Format.Time,Gst.SeekFlags.Flush|Gst.SeekFlags.Accurate,pos);
|
|
}
|
|
}
|
|
|
|
TimeSpan duration = TimeSpan.Zero;
|
|
|
|
public TimeSpan Duration {
|
|
get {
|
|
if(element==null) return TimeSpan.Zero;
|
|
if(duration == TimeSpan.Zero) {
|
|
Gst.Format format = Gst.Format.Time ;
|
|
long dur;
|
|
element.QueryDuration(ref format, out dur);
|
|
duration = TimeSpan.FromMilliseconds(dur/1000000);
|
|
}
|
|
return duration;
|
|
}
|
|
}
|
|
|
|
public void DelFile (int pos)
|
|
{
|
|
lock (this) {
|
|
|
|
files.RemoveAt (pos);
|
|
CommandRemove(pos);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void LoadFile (int pos)
|
|
{
|
|
curfile = files[pos];
|
|
Stop();
|
|
|
|
duration = TimeSpan.Zero;
|
|
|
|
Uri uri = new Uri(curfile);
|
|
|
|
element = Gst.ElementFactory.Make("playbin");
|
|
element["uri"] = uri.AbsoluteUri;
|
|
element.SetState(Gst.State.Paused);
|
|
element["volume"] = (double)volume / 100.0d ;
|
|
}
|
|
|
|
public void Play ()
|
|
{
|
|
if(element == null)return;
|
|
if(element.CurrentState != Gst.State.Paused && element.CurrentState != Gst.State.Playing){
|
|
lock(taskQueue)taskQueue.Enqueue(delegate(){
|
|
Play();
|
|
});
|
|
return;
|
|
}
|
|
|
|
element.SetState(Gst.State.Playing);
|
|
}
|
|
public void Pause ()
|
|
{
|
|
if(element == null)return;
|
|
element.SetState(Gst.State.Paused);
|
|
}
|
|
public void Stop ()
|
|
{
|
|
if(element == null)return;
|
|
element.SetState(Gst.State.Null);
|
|
element.Dispose();
|
|
element=null;
|
|
taskQueue.Clear();
|
|
}
|
|
|
|
static void GstInit ()
|
|
{
|
|
if(gsinit) return;
|
|
gsinit=true;
|
|
string[] args = new string[] {"--gst-disable-segtrap"};
|
|
Gst.Application.Init("dmx2", ref args );
|
|
|
|
}
|
|
|
|
public SequenceurSon ()
|
|
{
|
|
GstInit();
|
|
}
|
|
#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)
|
|
{
|
|
//throw new NotImplementedException ();
|
|
}
|
|
public override int ValeurCircuit (Circuit c)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
public override void Tick (TimeSpan time)
|
|
{
|
|
if(element!=null && taskQueue.Count>0)
|
|
lock(taskQueue)taskQueue.Dequeue()();
|
|
|
|
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);
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
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");
|
|
|
|
XmlElement xmlE;
|
|
|
|
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))?",
|
|
System.Text.RegularExpressions.RegexOptions.Compiled);
|
|
|
|
static System.Text.RegularExpressions.Regex regexCommand2 = new System.Text.RegularExpressions.Regex(
|
|
@"(?<file>\d+)(?<params>[gvp](.+)?)?",
|
|
System.Text.RegularExpressions.RegexOptions.Compiled);
|
|
|
|
|
|
public override void Command (string 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{
|
|
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;
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
}
|
|
}
|
|
|