summaryrefslogtreecommitdiff
path: root/libs
diff options
context:
space:
mode:
authorPaul Davis <paul@linuxaudiosystems.com>2010-04-08 21:05:55 +0000
committerPaul Davis <paul@linuxaudiosystems.com>2010-04-08 21:05:55 +0000
commit77c09fc8248160ab60e2e229710d07934fe08894 (patch)
treeffda53a98c2ecf61a47417e0675c91791d35ecfb /libs
parent5970212b876efa658857c4f1e7014bf89e358e53 (diff)
add support for "msg=" bindings and also action="SomeGroup/Action"
git-svn-id: svn://localhost/ardour2/branches/3.0@6876 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'libs')
-rw-r--r--libs/surfaces/generic_midi/generic_midi_control_protocol.cc136
-rw-r--r--libs/surfaces/generic_midi/generic_midi_control_protocol.h5
-rw-r--r--libs/surfaces/generic_midi/midiaction.cc62
-rw-r--r--libs/surfaces/generic_midi/midiaction.h65
-rw-r--r--libs/surfaces/generic_midi/midifunction.cc135
-rw-r--r--libs/surfaces/generic_midi/midifunction.h29
-rw-r--r--libs/surfaces/generic_midi/midiinvokable.cc171
-rw-r--r--libs/surfaces/generic_midi/midiinvokable.h78
-rw-r--r--libs/surfaces/generic_midi/wscript2
9 files changed, 526 insertions, 157 deletions
diff --git a/libs/surfaces/generic_midi/generic_midi_control_protocol.cc b/libs/surfaces/generic_midi/generic_midi_control_protocol.cc
index b35a99dcf4..62cc93263b 100644
--- a/libs/surfaces/generic_midi/generic_midi_control_protocol.cc
+++ b/libs/surfaces/generic_midi/generic_midi_control_protocol.cc
@@ -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)
{
diff --git a/libs/surfaces/generic_midi/generic_midi_control_protocol.h b/libs/surfaces/generic_midi/generic_midi_control_protocol.h
index e0867fad78..1ad2c681d4 100644
--- a/libs/surfaces/generic_midi/generic_midi_control_protocol.h
+++ b/libs/surfaces/generic_midi/generic_midi_control_protocol.h
@@ -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
index 0000000000..f432b7dffb
--- /dev/null
+++ b/libs/surfaces/generic_midi/midiaction.cc
@@ -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
index 0000000000..521f59f26d
--- /dev/null
+++ b/libs/surfaces/generic_midi/midiaction.h
@@ -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__
+
diff --git a/libs/surfaces/generic_midi/midifunction.cc b/libs/surfaces/generic_midi/midifunction.cc
index 3ce447b799..3d407b4c76 100644
--- a/libs/surfaces/generic_midi/midifunction.cc
+++ b/libs/surfaces/generic_midi/midifunction.cc
@@ -26,52 +26,43 @@
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 ()
{
diff --git a/libs/surfaces/generic_midi/midifunction.h b/libs/surfaces/generic_midi/midifunction.h
index bc019cfb3c..73ba21434e 100644
--- a/libs/surfaces/generic_midi/midifunction.h
+++ b/libs/surfaces/generic_midi/midifunction.h
@@ -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
index 0000000000..a77335fa7a
--- /dev/null
+++ b/libs/surfaces/generic_midi/midiinvokable.cc
@@ -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
index 0000000000..b86bdb858b
--- /dev/null
+++ b/libs/surfaces/generic_midi/midiinvokable.h
@@ -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__
+
diff --git a/libs/surfaces/generic_midi/wscript b/libs/surfaces/generic_midi/wscript
index 5926e0e9da..8471830766 100644
--- a/libs/surfaces/generic_midi/wscript
+++ b/libs/surfaces/generic_midi/wscript
@@ -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"'