Gestion des evenements Midi

This commit is contained in:
tzim 2013-11-13 14:37:31 +00:00
parent 55b06fe771
commit 3fc814731f
7 changed files with 298 additions and 36 deletions

View file

@ -41,7 +41,7 @@ namespace DMX2
Pause = false;
midip = new MidiEventProvider();
midip = new MidiEventProvider(eventManager);
}
EventManager eventManager = new EventManager();
@ -175,8 +175,6 @@ namespace DMX2
TimeSpan deltaT = tickTime - dernierTick;
dernierTick = tickTime;
midip.Process();
if (!Pause) {
/* if (deltaT > TimeSpan.FromMilliseconds (15))
@ -212,6 +210,8 @@ namespace DMX2
// Cette fonction retourne quasi immédiatement, même si il y'a beaucoup a faire sur l'affichage
}
EventManager.ProcessEvents();
if(tickTime - derniereMaj > TimeSpan.FromMilliseconds(50)){
MainWindow.Win.ScheduleUpdate();
derniereMaj = DateTime.Now;

View file

@ -0,0 +1,90 @@
using System;
using Gdk;
using GLib;
using Gtk;
namespace DMX2
{
public class ContextMenuEventArgs : EventArgs
{
private Widget widget;
public Widget Widget { get { return widget; } }
private bool rightClick;
public bool RightClick { get { return rightClick; } }
public ContextMenuEventArgs (Widget widget, bool rightClick)
{
this.widget = widget;
this.rightClick = rightClick;
}
}
public class ContextMenuHelper
{
public event EventHandler<ContextMenuEventArgs> ContextMenu;
public ContextMenuHelper ()
{
}
public ContextMenuHelper (Widget widget)
{
AttachToWidget (widget);
}
public ContextMenuHelper (Widget widget, EventHandler<ContextMenuEventArgs> handler)
{
AttachToWidget (widget);
ContextMenu += handler;
}
public void AttachToWidget (Widget widget)
{
widget.PopupMenu += Widget_PopupMenu;
widget.ButtonPressEvent += Widget_ButtonPressEvent;
}
public void DetachFromWidget (Widget widget)
{
widget.PopupMenu -= Widget_PopupMenu;
widget.ButtonPressEvent -= Widget_ButtonPressEvent;
}
[GLib.ConnectBefore]
private void Widget_PopupMenu (object o, PopupMenuArgs args)
{
RaiseContextMenuEvent (args, (Widget)o, false);
}
[GLib.ConnectBefore]
private void Widget_ButtonPressEvent (object o, ButtonPressEventArgs args)
{
if (args.Event.Button == 3 && args.Event.Type == EventType.ButtonPress) {
RaiseContextMenuEvent (args, (Widget)o, true);
}
}
private bool propagating = false; //Prevent reentry
private void RaiseContextMenuEvent (SignalArgs signalArgs, Widget widget, bool rightClick)
{
if (!propagating) {
//Propagate the event
Event evnt = Gtk.Global.CurrentEvent;
propagating = true;
Gtk.Global.PropagateEvent (widget, evnt);
propagating = false;
signalArgs.RetVal = true; //The widget already processed the event in the propagation
//Raise the context menu event
ContextMenuEventArgs args = new ContextMenuEventArgs (widget, rightClick);
if (ContextMenu != null) {
ContextMenu.Invoke (this, args);
}
}
}
}
}

View file

@ -105,6 +105,7 @@
<Compile Include="EventManager.cs" />
<Compile Include="MidiEventProvider.cs" />
<Compile Include="MidiEventProvider.PInvoke.cs" />
<Compile Include="ContextMenuHelper.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ProjectExtensions>

View file

@ -13,10 +13,11 @@ namespace DMX2
public interface IEventProvider
{
string MenuName{ get; }
string[] GetEventList();
ICollection<string> GetEventList();
bool Bind (string eventId, IEventTarget target);
void Unbind (string eventId, IEventTarget target);
Gtk.Menu GetProviderSubMenu( Gtk.ButtonPressEventHandler handler );
Gtk.Menu GetProviderSubMenu( EventManager.EventMenuData state, Gtk.ButtonPressEventHandler handler );
void ProcessEvents();
}
public interface IEventTarget
@ -26,6 +27,9 @@ namespace DMX2
public class EventManager
{
static public object StateKey = new object();
static public object EventIdKey = new object();
class eventBinding
{
private eventBinding(){}
@ -51,28 +55,57 @@ namespace DMX2
{
providers.Add (prov);
List<string> evList = new List<string>(prov.GetEventList());
//List<string> evList = new List<string>(prov.GetEventList());
foreach (eventBinding b in bindings) {
if(b.provider == null && evList.Contains(b.id))
if(b.provider == null)
{
prov.Bind(b.id,b.target);
if(prov.Bind(b.id,b.target))
b.provider = prov;
}
}
}
public Gtk.Menu GetMenu ( Gtk.ButtonPressEventHandler handler )
{
Gtk.Menu menu = new Gtk.Menu();
public delegate void EventMenuCallBack(object state, string eventId);
public class EventMenuData {
public EventMenuCallBack CallBack;
public object state;
}
public Gtk.Menu GetMenu (object state, EventMenuCallBack callback)
{
Gtk.Menu menu = new Gtk.Menu ();
EventMenuData evd = new EventMenuData();
evd.CallBack = callback;
evd.state = state;
Gtk.ButtonPressEventHandler handler = new Gtk.ButtonPressEventHandler (HandleButtonPressEvent);
foreach (IEventProvider prov in providers) {
Gtk.MenuItem provitem = new Gtk.MenuItem(prov.MenuName);
provitem.Submenu = prov.GetProviderSubMenu(evd, handler);
menu.Add(provitem);
}
return menu;
}
void HandleButtonPressEvent (object o, Gtk.ButtonPressEventArgs args)
{
Gtk.MenuItem item = o as Gtk.MenuItem;
EventMenuData evd = item.Data[EventManager.StateKey] as EventMenuData;
string id = item.Data[EventManager.EventIdKey] as string;
evd.CallBack(evd.state,id);
}
public void ProcessEvents ()
{
foreach (IEventProvider prov in providers) {
prov.ProcessEvents();
}
}
public void UnregisterProvider (IEventProvider prov)
{

View file

@ -1,36 +1,53 @@
using System;
using System.Runtime.InteropServices;
using System.Collections.Generic;
namespace DMX2
{
public partial class MidiEventProvider : IEventProvider, IDisposable
{
IntPtr midi_seq_handle = IntPtr.Zero;
int midiport;
class internalEvent {
public string internalName;
public string description;
List<IEventTarget> boundTargets=null;
public MidiEventProvider ()
public internalEvent(string _id, string _desc)
{
internalName=_id;
description=_desc;
}
public bool HasTargets {
get {
return boundTargets==null?false:boundTargets.Count>0;
}
}
public List<IEventTarget> BoundTargets {
get {
if(boundTargets==null) boundTargets = new List<IEventTarget>();
return boundTargets;
}
}
}
Dictionary<string,internalEvent> eventlist = new Dictionary<string, internalEvent>();
IntPtr midi_seq_handle = IntPtr.Zero;
public MidiEventProvider (EventManager manager)
{
snd_seq_open(out midi_seq_handle, "default",SND_SEQ_OPEN_DUPLEX,0);
snd_seq_set_client_name(midi_seq_handle,"DMX2");
midiport = snd_seq_create_simple_port(midi_seq_handle,"dmx_ctrl",
snd_seq_create_simple_port(midi_seq_handle,"dmx_ctrl",
SND_SEQ_PORT_CAP_WRITE + SND_SEQ_PORT_CAP_SUBS_WRITE,
SND_SEQ_PORT_TYPE_APPLICATION);
Info.Publish(string.Format("Midi port {0}",midiport));
manager.RegisterProvider(this);
}
public void Process ()
{
int i; IntPtr ev;
while ((i = snd_seq_event_input_pending(midi_seq_handle,1))>0) {
//Console.WriteLine(i);
i=snd_seq_event_input(midi_seq_handle, out ev);
snd_seq_event_t evS =(snd_seq_event_t) Marshal.PtrToStructure(ev,typeof(snd_seq_event_t));
Info.Publish(string.Format ("event {0} {1}", evS.type, evS.data_ev_ctrl.value) );
snd_seq_free_event(ev);
}
}
#region IDisposable implementation
public void Dispose ()
@ -39,30 +56,110 @@ namespace DMX2
}
#endregion
#region IEventProvider implementation
string[] IEventProvider.GetEventList ()
ICollection<string> IEventProvider.GetEventList ()
{
throw new System.NotImplementedException ();
return eventlist.Keys;
}
bool IEventProvider.Bind (string eventId, IEventTarget target)
{
throw new System.NotImplementedException ();
if (!eventlist.ContainsKey (eventId)) {
// TODO : check if non received yet midi event...
return false;
}
eventlist[eventId].BoundTargets.Add(target);
return true;
}
void IEventProvider.Unbind (string eventId, IEventTarget target)
{
throw new System.NotImplementedException ();
if (!eventlist.ContainsKey (eventId)) return;
eventlist[eventId].BoundTargets.Remove(target);
return;
}
Gtk.Menu IEventProvider.GetProviderSubMenu (Gtk.ButtonPressEventHandler handler)
Gtk.Menu IEventProvider.GetProviderSubMenu (EventManager.EventMenuData state, Gtk.ButtonPressEventHandler handler)
{
throw new System.NotImplementedException ();
Gtk.Menu retmenu = new Gtk.Menu ();
//Gtk.MenuItem evmenuitem = new Gtk.MenuItem ("Events");
//retmenu.Add (evmenuitem);
Gtk.Menu evmenu = retmenu ;// new Gtk.Menu ();
//evmenuitem.Submenu = evmenu;
List<string> sortedKeys = new List<string>(eventlist.Keys);
sortedKeys.Sort();
foreach ( string key in sortedKeys ) {
internalEvent evt= eventlist[key];
Gtk.MenuItem item = new Gtk.MenuItem(evt.description);
item.Data[EventManager.EventIdKey] = evt.internalName;
item.Data[EventManager.StateKey] = state;
item.ButtonPressEvent += handler;
evmenu.Add (item);
}
return retmenu;
}
void IEventProvider.ProcessEvents ()
{
int ret; IntPtr evPtr;
while ((ret = snd_seq_event_input_pending(midi_seq_handle,1))>0) {
ret=snd_seq_event_input(midi_seq_handle, out evPtr);
snd_seq_event_t evS =(snd_seq_event_t) Marshal.PtrToStructure(evPtr,typeof(snd_seq_event_t));
snd_seq_free_event(evPtr);
string id=null, description=null; int value=0;
switch (evS.type) {
case 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);
value = 255 * evS.data_ev_ctrl.value / 127;
break;
case 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 );
value = 255 ;
break;
case 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 );
value = 0;
break;
//TODO : Regarder si d'autres controles interessants.
default:
id= null;
Info.Publish(string.Format ("event {0}", evS.type) );
break;
}
if(id!=null)
{
if(!eventlist.ContainsKey(id))
eventlist.Add(id,new internalEvent(id,description));
else{
if(eventlist[id].HasTargets)
{
EventData evData = new EventData();
evData.id = id;
evData.value = (byte)value;
foreach( IEventTarget t in eventlist[id].BoundTargets)
t.FireEvent(evData);
}
}
}
}
}
string IEventProvider.MenuName {
get {
throw new System.NotImplementedException ();
return "Midi";
}
}
#endregion

View file

@ -32,6 +32,8 @@ namespace DMX2
}
}
void OnRenameItemButtonPressed (object o, ButtonPressEventArgs args)
{
var dlg = new Dialog ("Nouveau Nom ?", GetAncestor(Gtk.Window.GType) as Gtk.Window , DialogFlags.Modal); var entry = new Entry (sequenceur.Name);
@ -241,6 +243,21 @@ namespace DMX2
return tirette;
}
void TirettePopup (object sender, ContextMenuEventArgs e)
{
Circuit c = e.Widget.Data[circuitKey] as Circuit;
Menu m = Conduite.Courante.EventManager.GetMenu(c,new EventManager.EventMenuCallBack(TirettePopupEnd));
m.ShowAll();
m.Popup();
}
void TirettePopupEnd (object state, string eventId)
{
Circuit c = state as Circuit;
sequenceur.BindEvent(c,eventId);
Console.WriteLine("{0} bound to {1}", c, eventId );
}
static Label NouveauLabel ()
{
Label l = new Label();
@ -286,6 +303,7 @@ namespace DMX2
tirette.Show();
tirette.ValueChanged += TiretteActionee;
tirette.Data.Add(circuitKey,c);
new ContextMenuHelper(tirette, new EventHandler<ContextMenuEventArgs>(TirettePopup));
tirette.TooltipText = c.Name;

View file

@ -362,6 +362,29 @@ namespace DMX2
}
}
private class circEvTarget : IEventTarget{
Circuit c; SequenceurLineaire seq;
public circEvTarget(SequenceurLineaire _seq, Circuit _c){
c=_c;
seq=_seq;
}
#region IEventTarget implementation
bool IEventTarget.FireEvent (EventData data)
{
seq.ChangeValeur(c,data.value);
return true;
}
#endregion
}
public void BindEvent (Circuit c, string eventId)
{
// TODO : plein de trucs
Conduite.Courante.EventManager.Bind(eventId,new circEvTarget(this,c));
}
public override void Save (System.Xml.XmlElement parent)
{
System.Xml.XmlElement el = parent.OwnerDocument.CreateElement ("SequenceurLineaire");