add support for "msg=" bindings and also action="SomeGroup/Action"
authorPaul Davis <paul@linuxaudiosystems.com>
Thu, 8 Apr 2010 21:05:55 +0000 (21:05 +0000)
committerPaul Davis <paul@linuxaudiosystems.com>
Thu, 8 Apr 2010 21:05:55 +0000 (21:05 +0000)
git-svn-id: svn://localhost/ardour2/branches/3.0@6876 d708f5d6-7413-0410-9779-e7cbd77b26cf

libs/surfaces/generic_midi/generic_midi_control_protocol.cc
libs/surfaces/generic_midi/generic_midi_control_protocol.h
libs/surfaces/generic_midi/midiaction.cc [new file with mode: 0644]
libs/surfaces/generic_midi/midiaction.h [new file with mode: 0644]
libs/surfaces/generic_midi/midifunction.cc
libs/surfaces/generic_midi/midifunction.h
libs/surfaces/generic_midi/midiinvokable.cc [new file with mode: 0644]
libs/surfaces/generic_midi/midiinvokable.h [new file with mode: 0644]
libs/surfaces/generic_midi/wscript

index b35a99dcf48400391e15b1b31d1754a79b5fe260..62cc93263befc29d956433458471c5e6c08917f5 100644 (file)
@@ -41,6 +41,7 @@
 #include "generic_midi_control_protocol.h"
 #include "midicontrollable.h"
 #include "midifunction.h"
+#include "midiaction.h"
 
 using namespace ARDOUR;
 using namespace PBD;
@@ -193,6 +194,11 @@ GenericMidiControlProtocol::drop_all ()
                delete *i;
        }
        functions.clear ();
+
+       for (MIDIActions::iterator i = actions.begin(); i != actions.end(); ++i) {
+               delete *i;
+       }
+       actions.clear ();
 }
 
 void
@@ -640,7 +646,14 @@ GenericMidiControlProtocol::load_bindings (const string& xmlpath)
                                if ((mf = create_function (*child)) != 0) {
                                        functions.push_back (mf);
                                }
-                       }
+
+                       } else if (child->property ("action")) {
+                                MIDIAction* ma;
+
+                               if ((ma = create_action (*child)) != 0) {
+                                       actions.push_back (ma);
+                               }
+                        }
                }
        }
        
@@ -744,8 +757,8 @@ GenericMidiControlProtocol::create_function (const XMLNode& node)
        MIDI::channel_t channel = 0;
        string uri;
        MIDI::eventType ev;
-       MIDI::byte* sysex = 0;
-       uint32_t sysex_size = 0;
+       MIDI::byte* data = 0;
+       uint32_t data_size = 0;
 
        if ((prop = node.property (X_("ctl"))) != 0) {
                ev = MIDI::controller;
@@ -753,9 +766,14 @@ GenericMidiControlProtocol::create_function (const XMLNode& node)
                ev = MIDI::on;
        } else if ((prop = node.property (X_("pgm"))) != 0) {
                ev = MIDI::program;
-       } else if ((prop = node.property (X_("sysex"))) != 0) {
+       } else if ((prop = node.property (X_("sysex"))) != 0 || (prop = node.property (X_("msg"))) != 0) {
+
+                if (prop->name() == X_("sysex")) {
+                        ev = MIDI::sysex;
+                } else {
+                        ev = MIDI::any;
+                }
 
-               ev = MIDI::sysex;
                int val;
                uint32_t cnt;
 
@@ -773,8 +791,8 @@ GenericMidiControlProtocol::create_function (const XMLNode& node)
                        return 0;
                }
 
-               sysex = new MIDI::byte[cnt];
-               sysex_size = cnt;
+               data = new MIDI::byte[cnt];
+               data_size = cnt;
                
                {
                        stringstream ss (prop->value());
@@ -782,16 +800,16 @@ GenericMidiControlProtocol::create_function (const XMLNode& node)
                        cnt = 0;
                        
                        while (ss >> val) {
-                               sysex[cnt++] = (MIDI::byte) val;
+                               data[cnt++] = (MIDI::byte) val;
                        }
                }
-               
+
        } else {
                warning << "Binding ignored - unknown type" << endmsg;
                return 0;
        }
 
-       if (sysex_size == 0) {
+       if (data_size == 0) {
                if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
                        return 0;
                }
@@ -816,7 +834,7 @@ GenericMidiControlProtocol::create_function (const XMLNode& node)
        
        MIDIFunction* mf = new MIDIFunction (*_port);
        
-       if (mf->init (*this, prop->value(), sysex, sysex_size)) {
+       if (mf->init (*this, prop->value(), data, data_size)) {
                delete mf;
                return 0;
        }
@@ -826,6 +844,102 @@ GenericMidiControlProtocol::create_function (const XMLNode& node)
        return mf;
 }
 
+MIDIAction*
+GenericMidiControlProtocol::create_action (const XMLNode& node)
+{
+       const XMLProperty* prop;
+       int intval;
+       MIDI::byte detail = 0;
+       MIDI::channel_t channel = 0;
+       string uri;
+       MIDI::eventType ev;
+       MIDI::byte* data = 0;
+       uint32_t data_size = 0;
+
+       if ((prop = node.property (X_("ctl"))) != 0) {
+               ev = MIDI::controller;
+       } else if ((prop = node.property (X_("note"))) != 0) {
+               ev = MIDI::on;
+       } else if ((prop = node.property (X_("pgm"))) != 0) {
+               ev = MIDI::program;
+       } else if ((prop = node.property (X_("sysex"))) != 0 || (prop = node.property (X_("msg"))) != 0) {
+
+                if (prop->name() == X_("sysex")) {
+                        ev = MIDI::sysex;
+                } else {
+                        ev = MIDI::any;
+                }
+
+               int val;
+               uint32_t cnt;
+
+               {
+                       cnt = 0;
+                       stringstream ss (prop->value());
+                       ss << hex;
+                       
+                       while (ss >> val) {
+                               cnt++;
+                       }
+               }
+
+               if (cnt == 0) {
+                       return 0;
+               }
+
+               data = new MIDI::byte[cnt];
+               data_size = cnt;
+               
+               {
+                       stringstream ss (prop->value());
+                       ss << hex;
+                       cnt = 0;
+                       
+                       while (ss >> val) {
+                               data[cnt++] = (MIDI::byte) val;
+                       }
+               }
+
+       } else {
+               warning << "Binding ignored - unknown type" << endmsg;
+               return 0;
+       }
+
+       if (data_size == 0) {
+               if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
+                       return 0;
+               }
+               
+               detail = (MIDI::byte) intval;
+
+               if ((prop = node.property (X_("channel"))) == 0) {
+                       return 0;
+               }
+       
+               if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
+                       return 0;
+               }
+               channel = (MIDI::channel_t) intval;
+               /* adjust channel to zero-based counting */
+               if (channel > 0) {
+                       channel -= 1;
+               }
+       }
+
+       prop = node.property (X_("action"));
+       
+       MIDIAction* ma = new MIDIAction (*_port);
+        
+       if (ma->init (*this, prop->value(), data, data_size)) {
+               delete ma;
+               return 0;
+       }
+
+       ma->bind_midi (channel, ev, detail);
+
+       return ma;
+}
+
 void
 GenericMidiControlProtocol::set_current_bank (uint32_t b)
 {
index e0867fad7808916a5389988234c17c0d9b905c3d..1ad2c681d4ce8e993711b2b4e01c1830add33d28 100644 (file)
@@ -40,6 +40,7 @@ namespace ARDOUR {
 
 class MIDIControllable;
 class MIDIFunction;
+class MIDIAction;
 
 class GenericMidiControlProtocol : public ARDOUR::ControlProtocol {
   public:
@@ -94,6 +95,9 @@ class GenericMidiControlProtocol : public ARDOUR::ControlProtocol {
        typedef std::list<MIDIFunction*> MIDIFunctions;
        MIDIFunctions functions;
 
+       typedef std::list<MIDIAction*> MIDIActions;
+       MIDIActions actions;
+
        typedef std::pair<MIDIControllable*,PBD::ScopedConnection> MIDIPendingControllable;
        typedef std::list<MIDIPendingControllable* > MIDIPendingControllables;
        MIDIPendingControllables pending_controllables;
@@ -110,6 +114,7 @@ class GenericMidiControlProtocol : public ARDOUR::ControlProtocol {
 
        MIDIControllable* create_binding (const XMLNode&);
        MIDIFunction* create_function (const XMLNode&);
+       MIDIAction* create_action (const XMLNode&);
 
        void reset_controllables ();
        void drop_all ();
diff --git a/libs/surfaces/generic_midi/midiaction.cc b/libs/surfaces/generic_midi/midiaction.cc
new file mode 100644 (file)
index 0000000..f432b7d
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+    Copyright (C) 2009-2010 Paul Davis
+    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, or
+    (at your option) any later version.
+
+    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, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <cstring>
+
+#include "midi++/port.h"
+
+#include "midiaction.h"
+#include "generic_midi_control_protocol.h"
+
+using namespace MIDI;
+
+MIDIAction::MIDIAction (MIDI::Port& p)
+       : MIDIInvokable (p)
+{
+}
+
+MIDIAction::~MIDIAction ()
+{
+}
+
+int
+MIDIAction::init (GenericMidiControlProtocol& ui, const std::string& invokable_name, MIDI::byte* msg_data, size_t data_sz)
+{
+        MIDIInvokable::init (ui, invokable_name, msg_data, data_sz);
+       return 0;
+}
+
+void
+MIDIAction::execute ()
+{
+        _ui->access_action (_invokable_name);
+}
+
+XMLNode&
+MIDIAction::get_state ()
+{
+       XMLNode* node = new XMLNode ("MIDIAction");
+       return *node;
+}
+
+int
+MIDIAction::set_state (const XMLNode& node, int version)
+{
+       return 0;
+}
+
diff --git a/libs/surfaces/generic_midi/midiaction.h b/libs/surfaces/generic_midi/midiaction.h
new file mode 100644 (file)
index 0000000..521f59f
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+    Copyright (C) 2009 Paul Davis
+    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, or
+    (at your option) any later version.
+
+    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, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __gm_midiaction_h__
+#define __gm_midiaction_h__
+
+#include <string>
+
+#include "midi++/types.h"
+
+#include "pbd/signals.h"
+#include "pbd/stateful.h"
+
+#include "ardour/types.h"
+
+#include "midiinvokable.h"
+
+namespace Gtk { 
+        class Action;
+}
+
+namespace MIDI {
+       class Channel;
+       class Port;
+       class Parser;
+}
+
+class GenericMidiControlProtocol;
+
+class MIDIAction : public MIDIInvokable
+{
+  public:
+       MIDIAction (MIDI::Port&);
+       virtual ~MIDIAction ();
+
+       int init (GenericMidiControlProtocol&, const std::string& action_name, MIDI::byte* sysex = 0, size_t ssize = 0);
+
+       const std::string& action_name() const { return _invokable_name; }
+
+       XMLNode& get_state (void);
+       int set_state (const XMLNode&, int version);
+
+  private:
+        Gtk::Action* _action;
+       void execute ();
+};
+
+#endif // __gm_midicontrollable_h__
+
index 3ce447b799c980df7195ba038a9169992ea20761..3d407b4c76c4345bf8680c172cea428b64ebd95f 100644 (file)
 using namespace MIDI;
 
 MIDIFunction::MIDIFunction (MIDI::Port& p)
-       : _port (p)
+       : MIDIInvokable (p)
 {
-       sysex_size = 0;
-       sysex = 0;
 }
 
 MIDIFunction::~MIDIFunction ()
 {
-       delete [] sysex;
 }
 
 int
-MIDIFunction::init (GenericMidiControlProtocol& ui, const std::string& function_name, MIDI::byte* sysex_data, size_t sysex_sz)
+MIDIFunction::init (GenericMidiControlProtocol& ui, const std::string& invokable_name, MIDI::byte* msg_data, size_t data_sz)
 {
-       if (strcasecmp (function_name.c_str(), "transport-stop") == 0) {
+        MIDIInvokable::init (ui, invokable_name, msg_data, data_sz);
+
+       if (strcasecmp (_invokable_name.c_str(), "transport-stop") == 0) {
                _function = TransportStop;
-       } else if (strcasecmp (function_name.c_str(), "transport-roll") == 0) {
+       } else if (strcasecmp (_invokable_name.c_str(), "transport-roll") == 0) {
                _function = TransportRoll;
-       } else if (strcasecmp (function_name.c_str(), "transport-zero") == 0) {
+       } else if (strcasecmp (_invokable_name.c_str(), "transport-zero") == 0) {
                _function = TransportZero;
-       } else if (strcasecmp (function_name.c_str(), "transport-start") == 0) {
+       } else if (strcasecmp (_invokable_name.c_str(), "transport-start") == 0) {
                _function = TransportStart;
-       } else if (strcasecmp (function_name.c_str(), "transport-end") == 0) {
+       } else if (strcasecmp (_invokable_name.c_str(), "transport-end") == 0) {
                _function = TransportEnd;
-       } else if (strcasecmp (function_name.c_str(), "loop-toggle") == 0) {
+       } else if (strcasecmp (_invokable_name.c_str(), "loop-toggle") == 0) {
                _function = TransportLoopToggle;
-       } else if (strcasecmp (function_name.c_str(), "rec-enable") == 0) {
+       } else if (strcasecmp (_invokable_name.c_str(), "rec-enable") == 0) {
                _function = TransportRecordEnable;
-       } else if (strcasecmp (function_name.c_str(), "rec-disable") == 0) {
+       } else if (strcasecmp (_invokable_name.c_str(), "rec-disable") == 0) {
                _function = TransportRecordDisable;
-       } else if (strcasecmp (function_name.c_str(), "next-bank") == 0) {
+       } else if (strcasecmp (_invokable_name.c_str(), "next-bank") == 0) {
                _function = NextBank;
-       } else if (strcasecmp (function_name.c_str(), "prev-bank") == 0) {
+       } else if (strcasecmp (_invokable_name.c_str(), "prev-bank") == 0) {
                _function = PrevBank;
        } else {
                return -1;
        }
 
-       _ui = &ui;
-
-       if (sysex_sz) {
-               /* we take ownership of the sysex data */
-               sysex = sysex_data;
-               sysex_size = sysex_sz;
-       }
-
        return 0;
 }
 
@@ -121,104 +112,6 @@ MIDIFunction::execute ()
        }
 }
 
-void
-MIDIFunction::midi_sense_note_on (Parser &p, EventTwoBytes *tb)
-{
-       midi_sense_note (p, tb, true);
-}
-
-void
-MIDIFunction::midi_sense_note_off (Parser &p, EventTwoBytes *tb)
-{
-       midi_sense_note (p, tb, false);
-}
-
-void
-MIDIFunction::midi_sense_note (Parser &, EventTwoBytes *msg, bool /* is_on */)
-{
-       if (msg->note_number == control_additional) {
-               execute ();
-       }
-}
-
-void
-MIDIFunction::midi_sense_controller (Parser &, EventTwoBytes *msg)
-{
-       if (control_additional == msg->controller_number) {
-               execute ();
-       }
-}
-
-void
-MIDIFunction::midi_sense_program_change (Parser &, byte msg)
-{
-       if (msg == control_additional) {
-               execute ();
-       }
-}
-
-void
-MIDIFunction::midi_sense_sysex (Parser &, byte* msg, size_t sz)
-{
-       if (sz != sysex_size) {
-               return;
-       }
-
-       if (memcmp (msg, sysex, sysex_size) != 0) {
-               return;
-       }
-
-       execute ();
-}
-
-void
-MIDIFunction::bind_midi (channel_t chn, eventType ev, MIDI::byte additional)
-{
-       midi_sense_connection[0].disconnect ();
-       midi_sense_connection[1].disconnect ();
-
-       control_type = ev;
-       control_channel = chn;
-       control_additional = additional;
-
-       if (_port.input() == 0) {
-               return;
-       }
-
-       Parser& p = *_port.input();
-
-       int chn_i = chn;
-
-       /* incoming MIDI is parsed by Ardour' MidiUI event loop/thread, and we want our handlers to execute in that context, so we use
-          Signal::connect_same_thread() here.
-       */
-
-       switch (ev) {
-       case MIDI::off:
-               p.channel_note_off[chn_i].connect_same_thread (midi_sense_connection[0], boost::bind (&MIDIFunction::midi_sense_note_off, this, _1, _2));
-               break;
-
-       case MIDI::on:
-               p.channel_note_on[chn_i].connect_same_thread (midi_sense_connection[0], boost::bind (&MIDIFunction::midi_sense_note_on, this, _1, _2));
-               break;
-               
-       case MIDI::controller:
-               p.channel_controller[chn_i].connect_same_thread (midi_sense_connection[0], boost::bind (&MIDIFunction::midi_sense_controller, this, _1, _2));
-               break;
-
-       case MIDI::program:
-               p.channel_program_change[chn_i].connect_same_thread (midi_sense_connection[0], boost::bind (&MIDIFunction::midi_sense_program_change, this, _1, _2));
-               break;
-
-       case MIDI::sysex:
-               p.sysex.connect_same_thread (midi_sense_connection[0], boost::bind (&MIDIFunction::midi_sense_sysex, this, _1, _2, _3));
-               break;
-
-       default:
-               break;
-       }
-}
-
 XMLNode&
 MIDIFunction::get_state ()
 {
index bc019cfb3c24721b1b4799c03f1158f55ddb704b..73ba21434e95980e59f8ccf98bf45d17f611f48a 100644 (file)
@@ -29,6 +29,8 @@
 
 #include "ardour/types.h"
 
+#include "midiinvokable.h"
+
 namespace MIDI {
        class Channel;
        class Port;
@@ -37,7 +39,7 @@ namespace MIDI {
 
 class GenericMidiControlProtocol;
 
-class MIDIFunction : public PBD::Stateful
+class MIDIFunction : public MIDIInvokable
 {
   public:
        enum Function { 
@@ -58,37 +60,14 @@ class MIDIFunction : public PBD::Stateful
 
        int init (GenericMidiControlProtocol&, const std::string& function_name, MIDI::byte* sysex = 0, size_t ssize = 0);
 
-       MIDI::Port& get_port() const { return _port; }
-       const std::string& function_name() const { return _function_name; }
+       const std::string& function_name() const { return _invokable_name; }
 
        XMLNode& get_state (void);
        int set_state (const XMLNode&, int version);
 
-       void bind_midi (MIDI::channel_t, MIDI::eventType, MIDI::byte);
-       MIDI::channel_t get_control_channel () { return control_channel; }
-       MIDI::eventType get_control_type () { return control_type; }
-       MIDI::byte get_control_additional () { return control_additional; }
-       
   private:
        Function        _function;
-       GenericMidiControlProtocol* _ui;
-       std::string     _function_name;
-       MIDI::Port&     _port;
-       PBD::ScopedConnection midi_sense_connection[2];
-       MIDI::eventType  control_type;
-       MIDI::byte       control_additional;
-       MIDI::channel_t  control_channel;
-       MIDI::byte*      sysex;
-       size_t         sysex_size;
-
        void execute ();
-
-       void midi_sense_note (MIDI::Parser &, MIDI::EventTwoBytes *, bool is_on);
-       void midi_sense_note_on (MIDI::Parser &p, MIDI::EventTwoBytes *tb);
-       void midi_sense_note_off (MIDI::Parser &p, MIDI::EventTwoBytes *tb);
-       void midi_sense_controller (MIDI::Parser &, MIDI::EventTwoBytes *);
-       void midi_sense_program_change (MIDI::Parser &, MIDI::byte);
-       void midi_sense_sysex (MIDI::Parser &, MIDI::byte*, size_t);
 };
 
 #endif // __gm_midicontrollable_h__
diff --git a/libs/surfaces/generic_midi/midiinvokable.cc b/libs/surfaces/generic_midi/midiinvokable.cc
new file mode 100644 (file)
index 0000000..a77335f
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+    Copyright (C) 2009 Paul Davis
+    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, or
+    (at your option) any later version.
+
+    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, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <cstring>
+
+#include "midi++/port.h"
+
+#include "midifunction.h"
+#include "generic_midi_control_protocol.h"
+
+using namespace MIDI;
+
+MIDIInvokable::MIDIInvokable (MIDI::Port& p)
+       : _port (p)
+{
+       data_size = 0;
+       data = 0;
+}
+
+MIDIInvokable::~MIDIInvokable ()
+{
+       delete [] data;
+}
+
+int
+MIDIInvokable::init (GenericMidiControlProtocol& ui, const std::string& name, MIDI::byte* msg_data, size_t data_sz)
+{
+        _ui = &ui;
+        _invokable_name = name;
+
+       if (data_sz) {
+               /* we take ownership of the sysex data */
+               data = msg_data;
+               data_size = data_sz;
+       }
+
+       return 0;
+}
+
+void
+MIDIInvokable::midi_sense_note_on (Parser &p, EventTwoBytes *tb)
+{
+       midi_sense_note (p, tb, true);
+}
+
+void
+MIDIInvokable::midi_sense_note_off (Parser &p, EventTwoBytes *tb)
+{
+       midi_sense_note (p, tb, false);
+}
+
+void
+MIDIInvokable::midi_sense_note (Parser &, EventTwoBytes *msg, bool /* is_on */)
+{
+       if (msg->note_number == control_additional) {
+               execute ();
+       }
+}
+
+void
+MIDIInvokable::midi_sense_controller (Parser &, EventTwoBytes *msg)
+{
+       if (control_additional == msg->controller_number) {
+               execute ();
+       }
+}
+
+void
+MIDIInvokable::midi_sense_program_change (Parser &, byte msg)
+{
+       if (msg == control_additional) {
+               execute ();
+       }
+}
+
+void
+MIDIInvokable::midi_sense_sysex (Parser &, byte* msg, size_t sz)
+{
+       if (sz != data_size) {
+               return;
+       }
+
+       if (memcmp (msg, data, data_size) != 0) {
+               return;
+       }
+
+       execute ();
+}
+
+void
+MIDIInvokable::midi_sense_any (Parser &, byte* msg, size_t sz)
+{
+       if (sz != data_size) {
+               return;
+       }
+
+       if (memcmp (msg, data, data_size) != 0) {
+               return;
+       }
+
+       execute ();
+}
+
+
+void
+MIDIInvokable::bind_midi (channel_t chn, eventType ev, MIDI::byte additional)
+{
+       midi_sense_connection[0].disconnect ();
+       midi_sense_connection[1].disconnect ();
+
+       control_type = ev;
+       control_channel = chn;
+       control_additional = additional;
+
+       if (_port.input() == 0) {
+               return;
+       }
+
+       Parser& p = *_port.input();
+
+       int chn_i = chn;
+
+       /* incoming MIDI is parsed by Ardour' MidiUI event loop/thread, and we want our handlers to execute in that context, so we use
+          Signal::connect_same_thread() here.
+       */
+
+       switch (ev) {
+       case MIDI::off:
+               p.channel_note_off[chn_i].connect_same_thread (midi_sense_connection[0], boost::bind (&MIDIInvokable::midi_sense_note_off, this, _1, _2));
+               break;
+
+       case MIDI::on:
+               p.channel_note_on[chn_i].connect_same_thread (midi_sense_connection[0], boost::bind (&MIDIInvokable::midi_sense_note_on, this, _1, _2));
+               break;
+               
+       case MIDI::controller:
+               p.channel_controller[chn_i].connect_same_thread (midi_sense_connection[0], boost::bind (&MIDIInvokable::midi_sense_controller, this, _1, _2));
+               break;
+
+       case MIDI::program:
+               p.channel_program_change[chn_i].connect_same_thread (midi_sense_connection[0], boost::bind (&MIDIInvokable::midi_sense_program_change, this, _1, _2));
+               break;
+
+       case MIDI::sysex:
+               p.sysex.connect_same_thread (midi_sense_connection[0], boost::bind (&MIDIInvokable::midi_sense_sysex, this, _1, _2, _3));
+               break;
+
+       case MIDI::any:
+               p.any.connect_same_thread (midi_sense_connection[0], boost::bind (&MIDIInvokable::midi_sense_any, this, _1, _2, _3));
+               break;
+
+       default:
+               break;
+       }
+}
+
diff --git a/libs/surfaces/generic_midi/midiinvokable.h b/libs/surfaces/generic_midi/midiinvokable.h
new file mode 100644 (file)
index 0000000..b86bdb8
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+    Copyright (C) 2009 Paul Davis
+    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, or
+    (at your option) any later version.
+
+    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, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __gm_midiinvokable_h__
+#define __gm_midiinvokable_h__
+
+#include <string>
+
+#include "midi++/types.h"
+
+#include "pbd/signals.h"
+#include "pbd/stateful.h"
+
+#include "ardour/types.h"
+
+namespace MIDI {
+       class Channel;
+       class Port;
+       class Parser;
+}
+
+class GenericMidiControlProtocol;
+
+class MIDIInvokable : public PBD::Stateful
+{
+  public:
+       MIDIInvokable (MIDI::Port&);
+       virtual ~MIDIInvokable ();
+
+       virtual int init (GenericMidiControlProtocol&, const std::string&, MIDI::byte* data = 0, size_t dsize = 0);
+
+       MIDI::Port& get_port() const { return _port; }
+
+       void bind_midi (MIDI::channel_t, MIDI::eventType, MIDI::byte);
+       MIDI::channel_t get_control_channel () { return control_channel; }
+       MIDI::eventType get_control_type () { return control_type; }
+       MIDI::byte get_control_additional () { return control_additional; }
+       
+  protected:
+       GenericMidiControlProtocol* _ui;
+       std::string     _invokable_name;
+       MIDI::Port&     _port;
+       PBD::ScopedConnection midi_sense_connection[2];
+       MIDI::eventType  control_type;
+       MIDI::byte       control_additional;
+       MIDI::channel_t  control_channel;
+       MIDI::byte*      data;
+       size_t           data_size;
+
+       void midi_sense_note (MIDI::Parser &, MIDI::EventTwoBytes *, bool is_on);
+       void midi_sense_note_on (MIDI::Parser &p, MIDI::EventTwoBytes *tb);
+       void midi_sense_note_off (MIDI::Parser &p, MIDI::EventTwoBytes *tb);
+       void midi_sense_controller (MIDI::Parser &, MIDI::EventTwoBytes *);
+       void midi_sense_program_change (MIDI::Parser &, MIDI::byte);
+       void midi_sense_sysex (MIDI::Parser &, MIDI::byte*, size_t);
+       void midi_sense_any (MIDI::Parser &, MIDI::byte*, size_t);
+
+       virtual void execute () = 0;
+};
+
+#endif // __gm_midicontrollable_h__
+
index 5926e0e9da06399ecdb77c9b44088747675317d5..8471830766d48b051e31b3471a95091795cd7a44 100644 (file)
@@ -24,8 +24,10 @@ def build(bld):
                generic_midi_control_protocol.cc
                 gmcp_gui.cc
                interface.cc
+               midiinvokable.cc
                midicontrollable.cc
                midifunction.cc
+               midiaction.cc
        '''
        obj.export_incdirs = ['.']
        obj.cxxflags     = '-DPACKAGE="ardour_genericmidi"'