/* 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 . */ using System; using System.Runtime.InteropServices; using System.Collections.Generic; using System.Linq; namespace DMX2 { public class MidiEventProvider : IEventProvider { class internalEvent { public string internalName; public string description; public internalEvent(string _id, string _desc) { internalName=_id; description=_desc; } } class feedbackinfo : IFeedbackInfo { MidiEventProvider prov; AlsaSeqLib.snd_seq_event_t ev; 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; } #region IFeedbackInfo implementation bool IFeedbackInfo.FeedBack (byte data) { ev.data_ev_ctrl.value = (byte)((int)data * 127 / 255) ; prov.SendEvent(ev); return true; } #endregion } Dictionary eventlist = new Dictionary(); EventData last; internalEvent levent=null; bool connected=false; public MidiEventProvider (EventManager manager) { manager.RegisterProvider(this); AlsaSeqLib.Init(); } public void SendEvent (AlsaSeqLib.snd_seq_event_t ev) { AlsaSeqLib.SendEventToSubscribers(ev); } #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-"); } void IEventProvider.Unbind (string eventId) { return; } Gtk.Menu IEventProvider.GetProviderSubMenu (EventManager.EventMenuData state, Gtk.ButtonPressEventHandler handler) { if(!connected) return null; // Si pas encore recu d'evenements => pas de menu Gtk.Menu retmenu = new Gtk.Menu (); if (levent != null) { // Creation du sous menu "Dernier" Gtk.MenuItem lmenuitem = new Gtk.MenuItem ("Dernier"); 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; item.Data[EventManager.StateKey] = state; item.ButtonPressEvent += handler; lmenu.Add (item); } Gtk.MenuItem evmenuitem = new Gtk.MenuItem ("Events"); // Creation du sous menu "Events" retmenu.Add (evmenuitem); Gtk.Menu evmenu = new Gtk.Menu (); evmenuitem.Submenu = evmenu; List sortedKeys = eventlist.Keys.ToList(); // On recupere des IDs sortedKeys.Sort(); // et on les trie 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 (EventManagerCallback callback) { AlsaSeqLib.snd_seq_event_t evS; // Tant qu'il y des evenements midi en attente while (AlsaSeqLib.GetEvent(out evS)) { string id=null, description=null; int value=0; 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); 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 ); 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 ); value = 0; break; case AlsaSeqLib.snd_seq_event_type_t.SND_SEQ_EVENT_CLOCK: case AlsaSeqLib.snd_seq_event_type_t.SND_SEQ_EVENT_SENSING: continue; //TODO : Regarder si d'autres controles interessants. default: id= null; #if DEBUG Info.Publish(string.Format ("event {0}", evS.type) ); // On affiche les evenements inconnus Console.WriteLine(string.Format ("event {0}", evS.type) ); #endif continue; } connected=true; if(id!=null) { if(!eventlist.ContainsKey(id)) eventlist.Add(id,new internalEvent(id,description)); levent= eventlist[id]; //Dernier Evenement recu conserve pour menu EventData evData = new EventData(); evData.id = id; evData.value = (byte)value; if(evData.Equals(last)) continue; // On ignore les evenements répétés à l'identique callback(evData); last = evData; } } } string IEventProvider.MenuName { get { return "Midi"; } } static System.Text.RegularExpressions.Regex regexCtrlEventID = new System.Text.RegularExpressions.Regex( @"MIDI-CTRL-C(?\d+)P(?\d+)", System.Text.RegularExpressions.RegexOptions.Compiled); IFeedbackInfo IEventProvider.GetFeedbackInfo (string eventId) { var res = regexCtrlEventID.Match (eventId); if (res.Success) { 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 null; } #endregion } }