From 5260f8f2be4425079d8a54a5dd83a0d0c0e7f8dd Mon Sep 17 00:00:00 2001 From: tzim Date: Wed, 21 May 2014 14:26:44 +0000 Subject: [PATCH] =?UTF-8?q?Grosses=20am=C3=A9liorations=20sur=20la=20gesti?= =?UTF-8?q?on=20des=20evenements,=20notament=20sur=20l'accroche=20et=20la?= =?UTF-8?q?=20pagination=20midi?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DMX-2.0/AlsaSeqLib.cs | 17 +- DMX-2.0/DriverBoitierV1.cs | 2 +- DMX-2.0/DriverBoitierV2.cs | 9 +- DMX-2.0/DriverBoitierV3.cs | 9 +- DMX-2.0/EventManager.cs | 3 +- DMX-2.0/MidiEventProvider.cs | 306 ++++++++++++++++++++++++++++++---- DMX-2.0/SequenceurLineaire.cs | 34 ++-- 7 files changed, 310 insertions(+), 70 deletions(-) diff --git a/DMX-2.0/AlsaSeqLib.cs b/DMX-2.0/AlsaSeqLib.cs index 1705b52..abd4d92 100644 --- a/DMX-2.0/AlsaSeqLib.cs +++ b/DMX-2.0/AlsaSeqLib.cs @@ -155,18 +155,23 @@ namespace DMX2 static PointerWrapper evOutPtr = new PointerWrapper(32); + public static void SendEvent (snd_seq_event_t ev) + { + if(seq_handle==null) throw new InvalidOperationException(); + ev.queue = SND_SEQ_QUEUE_DIRECT; + ev.source.client = (byte)clientId; + ev.source.port = (byte) outport; + Marshal.StructureToPtr(ev,evOutPtr.Pointer,false); + Invoke.snd_seq_event_output(seq_handle.Handle,evOutPtr.Pointer); + Invoke.snd_seq_drain_output(seq_handle.Handle); + } public static void SendEventToSubscribers (snd_seq_event_t ev) { if(seq_handle==null) throw new InvalidOperationException(); - - ev.queue = SND_SEQ_QUEUE_DIRECT; - ev.source.port = (byte) outport; ev.dest.client=SND_SEQ_ADDRESS_SUBSCRIBERS; ev.dest.port= SND_SEQ_ADDRESS_UNKNOWN; - Marshal.StructureToPtr(ev,evOutPtr.Pointer,false); - Invoke.snd_seq_event_output(seq_handle.Handle,evOutPtr.Pointer); - Invoke.snd_seq_drain_output(seq_handle.Handle); + SendEvent(ev); } public static IEnumerable EnumClients () diff --git a/DMX-2.0/DriverBoitierV1.cs b/DMX-2.0/DriverBoitierV1.cs index d9ca806..bd5d2bb 100644 --- a/DMX-2.0/DriverBoitierV1.cs +++ b/DMX-2.0/DriverBoitierV1.cs @@ -216,7 +216,6 @@ namespace DMX2 loopthread.Join (); loopthread = null; } - //TODO : Close Port if(serial != null) serial.Dispose(); @@ -289,6 +288,7 @@ namespace DMX2 while (eventsPending.TryDequeue(out bt)) { evd.id= string.Format("BV1-B{0}",bt.button ); evd.value = bt.pressed?(byte)0xFF:(byte)0x00; + evd.prev_value = (!bt.pressed)?(byte)0xFF:(byte)0x00; callback(evd); } } diff --git a/DMX-2.0/DriverBoitierV2.cs b/DMX-2.0/DriverBoitierV2.cs index ca47018..e5c9fad 100644 --- a/DMX-2.0/DriverBoitierV2.cs +++ b/DMX-2.0/DriverBoitierV2.cs @@ -28,11 +28,12 @@ namespace DMX2 { struct dmxState { - public dmxState(int _dmx, byte _value){ - value=_value; dmx=_dmx; + public dmxState(int _dmx, byte _value, byte _lastvalue){ + value=_value; dmx=_dmx; lastvalue = _lastvalue; } public int dmx; public byte value; + public byte lastvalue; } enum etatAutomate { @@ -409,8 +410,8 @@ namespace DMX2 lock(watchdmx) foreach (int dmx in watchdmx) { if( inputbuffer[dmx-1]!= lastVal[dmx]){ + eventsPending.Enqueue(new dmxState(dmx,inputbuffer[dmx-1],lastVal[dmx])); lastVal[dmx] = inputbuffer[dmx-1]; - eventsPending.Enqueue(new dmxState(dmx,inputbuffer[dmx-1])); } } } @@ -423,7 +424,6 @@ namespace DMX2 loopthread.Join (); loopthread = null; } - //TODO : Close Port if(serial != null) serial.Dispose(); @@ -524,6 +524,7 @@ namespace DMX2 while (eventsPending.TryDequeue(out dmxs)) { evd.id= string.Format("BV2-D{0}",dmxs.dmx ); evd.value = dmxs.value; + evd.prev_value = dmxs.lastvalue; callback(evd); } } diff --git a/DMX-2.0/DriverBoitierV3.cs b/DMX-2.0/DriverBoitierV3.cs index 999ff8b..6bcd9e0 100644 --- a/DMX-2.0/DriverBoitierV3.cs +++ b/DMX-2.0/DriverBoitierV3.cs @@ -28,11 +28,12 @@ namespace DMX2 { struct dmxState { - public dmxState(int _dmx, byte _value){ - value=_value; dmx=_dmx; + public dmxState(int _dmx, byte _value, byte _lastvalue){ + value=_value; dmx=_dmx; lastvalue = _lastvalue; } public int dmx; public byte value; + public byte lastvalue; } enum etatAutomate { @@ -466,8 +467,8 @@ namespace DMX2 lock(watchdmx) foreach (int dmx in watchdmx) { if( inputbuffer[dmx]!= lastVal[dmx]){ + eventsPending.Enqueue(new dmxState(dmx,inputbuffer[dmx],lastVal[dmx])); lastVal[dmx] = inputbuffer[dmx]; - eventsPending.Enqueue(new dmxState(dmx,inputbuffer[dmx])); } } } @@ -480,7 +481,6 @@ namespace DMX2 loopthread.Join (); loopthread = null; } - //TODO : Close Port if(serial != null) serial.Dispose(); @@ -581,6 +581,7 @@ namespace DMX2 while (eventsPending.TryDequeue(out dmxs)) { evd.id= string.Format("BV3-D{0}",dmxs.dmx ); evd.value = dmxs.value; + evd.prev_value = dmxs.lastvalue; callback(evd); } } diff --git a/DMX-2.0/EventManager.cs b/DMX-2.0/EventManager.cs index 8ee6cfb..e320350 100644 --- a/DMX-2.0/EventManager.cs +++ b/DMX-2.0/EventManager.cs @@ -29,6 +29,7 @@ namespace DMX2 { public string id; public byte value; + public byte prev_value ; } /// @@ -280,7 +281,7 @@ namespace DMX2 /// Fonction appelee sur evenement public void EventCallBack (EventData data) { - Console.WriteLine("Event {0} => {1}",data.id,data.value); + Console.WriteLine("Event {0} => {1} (last = {2})",data.id,data.value,data.prev_value); if (bindings.ContainsKey (data.id)) { foreach (IEventTarget target in bindings[data.id].Targets) { target.FireEvent(data); diff --git a/DMX-2.0/MidiEventProvider.cs b/DMX-2.0/MidiEventProvider.cs index 9de3e0b..65ca555 100644 --- a/DMX-2.0/MidiEventProvider.cs +++ b/DMX-2.0/MidiEventProvider.cs @@ -27,58 +27,209 @@ namespace DMX2 { class internalEvent { - public string internalName; - public string description; - public internalEvent(string _id, string _desc) + + public string InternalName{ get; set; } + bool bound=false; + + public bool Bound { + get { + return bound; + } + set { + bound = value; + } + } + + public internalEvent(string _id) { - internalName=_id; - description=_desc; + InternalName=_id; + } + + + int[] sources=null; + public IEnumerable Sources { + get { + if(sources == null || sources.Length!=lastknownvalues.Count) sources = lastknownvalues.Keys.ToArray(); + return sources; + } + } + + + readonly Dictionary lastknownvalues = new Dictionary(); + + public Dictionary LastKnownValues { + get { + return lastknownvalues; + } + } + + AlsaSeqLib.snd_seq_event_t storedevent; + public AlsaSeqLib.snd_seq_event_t StoredEvent { + get { + return storedevent; + } + set { + storedevent = value; + } } } - class feedbackinfo : IFeedbackInfo { + abstract class feedbackinfo : IFeedbackInfo { MidiEventProvider prov; - AlsaSeqLib.snd_seq_event_t ev; + protected AlsaSeqLib.snd_seq_event_t ev; + string eventId; + int page; - public feedbackinfo(MidiEventProvider _prov, byte channel,uint param){ - ev = new AlsaSeqLib.snd_seq_event_t(); prov=_prov; - ev.data_ev_ctrl.channel = channel; - ev.data_ev_ctrl.param= param; - ev.type = AlsaSeqLib.snd_seq_event_type_t.SND_SEQ_EVENT_CONTROLLER; + + public feedbackinfo(MidiEventProvider _prov, string _eventId, int _page){ + prov = _prov; + eventId = _eventId; + page = _page; } + protected abstract bool UpdateEvent(byte data); + #region IFeedbackInfo implementation bool IFeedbackInfo.FeedBack (byte data) { - ev.data_ev_ctrl.value = (byte)((int)data * 127 / 255) ; - prov.SendEvent(ev); + if (!prov.eventlist.ContainsKey (eventId)) + return false; + + bool update = UpdateEvent (data); + + prov.eventlist[eventId].StoredEvent = ev; + + if(!update) return true; + + foreach (var src in prov.eventlist[eventId].Sources) { + if(prov.HasFeedback(src)) + { + prov.eventlist[eventId].LastKnownValues[src]=data; + } + } + + if(prov.CurrentPage == page || page == 0) + prov.SendEvent (ev); + return true; } #endregion } + class ctrlfeedbackinfo : feedbackinfo { + public ctrlfeedbackinfo(MidiEventProvider _prov, string _eventId, int _page, byte channel,uint param) + :base(_prov,_eventId,_page) + { + ev = new AlsaSeqLib.snd_seq_event_t(); + ev.data_ev_ctrl.channel = channel; + ev.data_ev_ctrl.param= param; + ev.type = AlsaSeqLib.snd_seq_event_type_t.SND_SEQ_EVENT_CONTROLLER; + } + + protected override bool UpdateEvent (byte data) + { + int newvalue= (int)data * 127 / 255; + if(newvalue==ev.data_ev_ctrl.value) return false; + ev.data_ev_ctrl.value = newvalue; + return true; + } + } + + class pitchbendfeedbackinfo : feedbackinfo { + public pitchbendfeedbackinfo(MidiEventProvider _prov, string _eventId,int _page, byte channel) + :base(_prov,_eventId,_page) + { + ev = new AlsaSeqLib.snd_seq_event_t(); + ev.data_ev_ctrl.channel = channel; + ev.type = AlsaSeqLib.snd_seq_event_type_t.SND_SEQ_EVENT_PITCHBEND; + } + + protected override bool UpdateEvent (byte data) + { + int newvalue = (int)data * 16000 / 255-8000; + if(newvalue==ev.data_ev_ctrl.value) return false; + ev.data_ev_ctrl.value = newvalue; + return true; + } + } + + public class MidiDev{ + string name; + public string Name {get{return name;} } + public bool HasFeedback { get; set; } + + readonly List connected = new List(); + public List ConnectedPorts { + get{return connected;} + } + + public MidiDev(string _name) + { + name=_name; + } + + } + + readonly Dictionary eventlist = new Dictionary(); + readonly Dictionary knowndevices = new Dictionary(); + readonly List feedbacksources = new List(); + readonly List unpaginatedchannels = new List(); + - Dictionary eventlist = new Dictionary(); - List midiPortAutoConnect = new List(); EventData last; internalEvent levent=null; bool connected=false; + int page=1; + + public int CurrentPage { + get { + return page; + } + set { + if(value<1 || value > 255) return; + page = value; + Refresh(); + Console.WriteLine(page); + } + } + + public List UnpaginatedChannels { + get { + return unpaginatedchannels; + } + } + + public Dictionary KnownDevices { + get { + return knowndevices; + } + } + + public MidiEventProvider (EventManager manager) { manager.RegisterProvider (this); AlsaSeqLib.Init (); - // Connection au port d'annonce pour detection auto - midiPortAutoConnect.Add("BCF2000:BCF2000 MIDI 1"); + AlsaSeqLib.ConnectFrom(AlsaSeqLib.SND_SEQ_CLIENT_SYSTEM, AlsaSeqLib.SND_SEQ_PORT_SYSTEM_ANNOUNCE); + + MidiDev dev = new MidiDev("VMPK Input:VMPK Input"); + dev.HasFeedback = true; + knowndevices.Add(dev.Name,dev); + dev = new MidiDev("VMPK Output:VMPK Output"); + dev.HasFeedback = true; + knowndevices.Add(dev.Name,dev); + foreach (var cli in AlsaSeqLib.EnumClients()) { foreach(var p in cli.Ports){ PortDetected(cli,p); } } + unpaginatedchannels.Add((byte)0); } void PortDetected (AlsaSeqLib.Client cli, AlsaSeqLib.Port p) @@ -89,25 +240,50 @@ namespace DMX2 string fullportname = cli.Name + ':' + p.Name; Console.WriteLine(fullportname); - if(midiPortAutoConnect.Contains(fullportname)) + if(knowndevices.ContainsKey(fullportname)){ AlsaSeqLib.Connect(p); + int srcid = p.ClientId <<8 + p.PortId; + knowndevices[fullportname].ConnectedPorts.Add(srcid); + if(knowndevices[fullportname].HasFeedback) + feedbacksources.Add(srcid); + } } + protected bool HasFeedback (int source) + { + return feedbacksources.Contains(source); + } public void SendEvent (AlsaSeqLib.snd_seq_event_t ev) { AlsaSeqLib.SendEventToSubscribers(ev); } + + public void Refresh () + { + string pageStr = string.Format("PAGE{0}",page); + foreach (var ievent in eventlist.Values) { + if (ievent.InternalName.Contains(pageStr)){ + SendEvent(ievent.StoredEvent); + } + } + } + #region IEventProvider implementation bool IEventProvider.Bind (string eventId) { // On indique a l'EventManager qu'on traite, si l'ID commence par 'MIDI-' - return eventId.StartsWith("MIDI-"); + if(! eventId.StartsWith("MIDI-")) return false; + if(! eventlist.ContainsKey(eventId)) eventlist.Add(eventId, new internalEvent(eventId)); + eventlist[eventId].Bound = true; + return true; } void IEventProvider.Unbind (string eventId) { + if(! eventlist.ContainsKey(eventId)) return; + eventlist[eventId].Bound = false; return; } @@ -121,8 +297,8 @@ namespace DMX2 retmenu.Add (lmenuitem); Gtk.Menu lmenu = new Gtk.Menu (); lmenuitem.Submenu = lmenu; - Gtk.MenuItem item = new Gtk.MenuItem(levent.description); - item.Data[EventManager.EventIdKey] = levent.internalName; + Gtk.MenuItem item = new Gtk.MenuItem(GetDescription(levent.InternalName)); + item.Data[EventManager.EventIdKey] = levent.InternalName; item.Data[EventManager.StateKey] = state; item.ButtonPressEvent += handler; lmenu.Add (item); @@ -138,8 +314,8 @@ namespace DMX2 foreach ( string key in sortedKeys ) { internalEvent evt= eventlist[key]; - Gtk.MenuItem item = new Gtk.MenuItem(evt.description); - item.Data[EventManager.EventIdKey] = evt.internalName; + Gtk.MenuItem item = new Gtk.MenuItem(GetDescription(evt.InternalName)); + item.Data[EventManager.EventIdKey] = evt.InternalName; item.Data[EventManager.StateKey] = state; item.ButtonPressEvent += handler; evmenu.Add (item); @@ -152,31 +328,48 @@ namespace DMX2 void IEventProvider.ProcessEvents (EventManagerCallback callback) { AlsaSeqLib.snd_seq_event_t evS; + int evpage; // Tant qu'il y des evenements midi en attente while (AlsaSeqLib.GetEvent(out evS)) { - string id=null, description=null; int value=0; + string id = null; + int value=0; + byte channel = 255; switch (evS.type) { case AlsaSeqLib.snd_seq_event_type_t.SND_SEQ_EVENT_PORT_SUBSCRIBED: // Connection d'un périph midi connected = true; continue; case AlsaSeqLib.snd_seq_event_type_t.SND_SEQ_EVENT_CONTROLLER: - id= string.Format("MIDI-CTRL-C{0}P{1}",evS.data_ev_ctrl.channel,evS.data_ev_ctrl.param); - description = string.Format("Controller Ch {0} Param {1}",evS.data_ev_ctrl.channel,evS.data_ev_ctrl.param); + if(evS.data_ev_ctrl.param==127 && value>0){ + CurrentPage++; continue; + } + + if(evS.data_ev_ctrl.param==126 && value>0){ + CurrentPage--; continue; + } + + id = string.Format("CTRL-C{0}P{1}",evS.data_ev_ctrl.channel,evS.data_ev_ctrl.param); + channel = evS.data_ev_ctrl.channel; value = 255 * evS.data_ev_ctrl.value / 127; // Conversion {0,127} => {0,255} break; case AlsaSeqLib.snd_seq_event_type_t.SND_SEQ_EVENT_NOTEON: - id= string.Format("MIDI-NOTE-C{0}N{1}",evS.data_ev_note.channel, evS.data_ev_note.note ); - description = string.Format("Note {1} Ch {0}",evS.data_ev_note.channel, evS.data_ev_note.note ); + id = string.Format("NOTE-C{0}N{1}",evS.data_ev_note.channel, evS.data_ev_note.note ); + channel = evS.data_ev_note.channel; value = 255 ; break; case AlsaSeqLib.snd_seq_event_type_t.SND_SEQ_EVENT_NOTEOFF: - id= string.Format("MIDI-NOTE-C{0}N{1}",evS.data_ev_note.channel, evS.data_ev_note.note ); - description = string.Format("Note {1} Ch {0}",evS.data_ev_note.channel, evS.data_ev_note.note ); + id = string.Format("NOTE-C{0}N{1}",evS.data_ev_note.channel, evS.data_ev_note.note ); + channel = evS.data_ev_note.channel; value = 0; break; + case AlsaSeqLib.snd_seq_event_type_t.SND_SEQ_EVENT_PITCHBEND: + id = string.Format("PB-C{0}",evS.data_ev_ctrl.channel); + channel = evS.data_ev_ctrl.channel; + value = ((evS.data_ev_ctrl.value + 8000) *255 / 16000); + if(value<0) value =0; if(value>255) value = 255; + break; case AlsaSeqLib.snd_seq_event_type_t.SND_SEQ_EVENT_CLOCK: case AlsaSeqLib.snd_seq_event_type_t.SND_SEQ_EVENT_SENSING: continue; @@ -199,19 +392,40 @@ namespace DMX2 connected=true; + + if(id!=null) { + + if(channel == 255 || unpaginatedchannels.Contains(channel)) + evpage= 0; + else + evpage= page; + + id = string.Format("MIDI-PAGE{0}-{1}",evpage,id); + + if(!eventlist.ContainsKey(id)) - eventlist.Add(id,new internalEvent(id,description)); + eventlist.Add(id,new internalEvent(id)); levent= eventlist[id]; //Dernier Evenement recu conserve pour menu + + int srcid = evS.source.client <<8 + evS.source.port; + if(!eventlist[id].LastKnownValues.ContainsKey(srcid)) + eventlist[id].LastKnownValues[srcid] = (byte)value; + EventData evData = new EventData(); evData.id = id; evData.value = (byte)value; + evData.prev_value = eventlist[id].LastKnownValues[srcid]; - if(evData.Equals(last)) continue; // On ignore les evenements répétés à l'identique - - callback(evData); + eventlist[id].LastKnownValues[srcid] = (byte)value; + + if(evData.Equals(last)) continue; last = evData; + + if(eventlist[id].Bound) { + callback(evData); + } } } } @@ -222,10 +436,21 @@ namespace DMX2 } } + //TODO gerer pages et feeddback + static System.Text.RegularExpressions.Regex regexCtrlEventID = new System.Text.RegularExpressions.Regex( - @"MIDI-CTRL-C(?\d+)P(?\d+)", + @"MIDI-PAGE(?\d+)-CTRL-C(?\d+)P(?\d+)", System.Text.RegularExpressions.RegexOptions.Compiled); + static System.Text.RegularExpressions.Regex regexPbEventID = new System.Text.RegularExpressions.Regex( + @"MIDI-PAGE(?\d+)-PB-C(?\d+)", + System.Text.RegularExpressions.RegexOptions.Compiled); + + string GetDescription (string eventId) + { + return eventId; + } + IFeedbackInfo IEventProvider.GetFeedbackInfo (string eventId) { var res = regexCtrlEventID.Match (eventId); @@ -233,7 +458,14 @@ namespace DMX2 Console.WriteLine("Succes"); byte chan = byte.Parse (res.Groups ["chan"].Value); uint param = uint.Parse (res.Groups ["param"].Value); - return new feedbackinfo (this, chan, param); + return new ctrlfeedbackinfo (this, eventId, page, chan, param); + } + res = regexPbEventID.Match (eventId); + if (res.Success) { + Console.WriteLine("Succes"); + byte chan = byte.Parse (res.Groups ["chan"].Value); + + return new pitchbendfeedbackinfo (this, eventId,page, chan); } return null; diff --git a/DMX-2.0/SequenceurLineaire.cs b/DMX-2.0/SequenceurLineaire.cs index d823983..d92d4bd 100644 --- a/DMX-2.0/SequenceurLineaire.cs +++ b/DMX-2.0/SequenceurLineaire.cs @@ -126,8 +126,7 @@ namespace DMX2 Circuit circuit; Dictionary valeursrecues= new Dictionary(); SequenceurLineaire seq; - int max=0, signe=-2; - bool nofeedbackflag = false; + int max=0;//, signe=-2; bool attache; @@ -136,7 +135,7 @@ namespace DMX2 return attache; } set { - signe=-2; + if(value==false)valeursrecues.Clear(); attache = value; } } @@ -148,18 +147,21 @@ namespace DMX2 bool IEventTarget.FireEvent (EventData data) { - valeursrecues[data.id]=data.value; - max = valeursrecues.Values.Max(); - if (!Attache) { - int val = seq.ValeurBruteCircuit (circuit); - int cs = Math.Sign (val - max); - if (signe == -2) signe=cs; - if (cs==0 || cs!=signe) Attache=true; - else return true ; + valeursrecues [data.id] = data.value; + max = valeursrecues.Values.Max (); + /*if (max != data.value) + return true;*/ + + int val = seq.ValeurBruteCircuit (circuit); + + if ((data.prev_value != val) + && ((data.prev_value < val && data.value < val) || + (data.prev_value > val && data.value > val))) { + return true; } - nofeedbackflag = true; + seq.ChangeValeur(circuit,max); - nofeedbackflag = false; + attache = true; return true; } @@ -184,7 +186,7 @@ namespace DMX2 } public void FeedBack(byte data){ - if(nofeedbackflag) return; + Attache = false; foreach (var fb in feedbacks) fb.FeedBack(data); } @@ -396,8 +398,6 @@ namespace DMX2 } } - - public void FinDeTransition () { lock(this) { @@ -439,7 +439,7 @@ namespace DMX2 timeStamp = TimeSpan.Zero; if (ui != null) ui.EffetChange (); - foreach(var t in targets.Values) t.Attache = false; + //foreach(var t in targets.Values) t.Attache = false; } }