mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-17 20:26:30 +01:00
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
This commit is contained in:
parent
5970212b87
commit
77c09fc824
9 changed files with 526 additions and 157 deletions
|
|
@ -41,6 +41,7 @@
|
||||||
#include "generic_midi_control_protocol.h"
|
#include "generic_midi_control_protocol.h"
|
||||||
#include "midicontrollable.h"
|
#include "midicontrollable.h"
|
||||||
#include "midifunction.h"
|
#include "midifunction.h"
|
||||||
|
#include "midiaction.h"
|
||||||
|
|
||||||
using namespace ARDOUR;
|
using namespace ARDOUR;
|
||||||
using namespace PBD;
|
using namespace PBD;
|
||||||
|
|
@ -193,6 +194,11 @@ GenericMidiControlProtocol::drop_all ()
|
||||||
delete *i;
|
delete *i;
|
||||||
}
|
}
|
||||||
functions.clear ();
|
functions.clear ();
|
||||||
|
|
||||||
|
for (MIDIActions::iterator i = actions.begin(); i != actions.end(); ++i) {
|
||||||
|
delete *i;
|
||||||
|
}
|
||||||
|
actions.clear ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -640,7 +646,14 @@ GenericMidiControlProtocol::load_bindings (const string& xmlpath)
|
||||||
if ((mf = create_function (*child)) != 0) {
|
if ((mf = create_function (*child)) != 0) {
|
||||||
functions.push_back (mf);
|
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;
|
MIDI::channel_t channel = 0;
|
||||||
string uri;
|
string uri;
|
||||||
MIDI::eventType ev;
|
MIDI::eventType ev;
|
||||||
MIDI::byte* sysex = 0;
|
MIDI::byte* data = 0;
|
||||||
uint32_t sysex_size = 0;
|
uint32_t data_size = 0;
|
||||||
|
|
||||||
if ((prop = node.property (X_("ctl"))) != 0) {
|
if ((prop = node.property (X_("ctl"))) != 0) {
|
||||||
ev = MIDI::controller;
|
ev = MIDI::controller;
|
||||||
|
|
@ -753,9 +766,14 @@ GenericMidiControlProtocol::create_function (const XMLNode& node)
|
||||||
ev = MIDI::on;
|
ev = MIDI::on;
|
||||||
} else if ((prop = node.property (X_("pgm"))) != 0) {
|
} else if ((prop = node.property (X_("pgm"))) != 0) {
|
||||||
ev = MIDI::program;
|
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;
|
int val;
|
||||||
uint32_t cnt;
|
uint32_t cnt;
|
||||||
|
|
||||||
|
|
@ -773,8 +791,8 @@ GenericMidiControlProtocol::create_function (const XMLNode& node)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
sysex = new MIDI::byte[cnt];
|
data = new MIDI::byte[cnt];
|
||||||
sysex_size = cnt;
|
data_size = cnt;
|
||||||
|
|
||||||
{
|
{
|
||||||
stringstream ss (prop->value());
|
stringstream ss (prop->value());
|
||||||
|
|
@ -782,7 +800,7 @@ GenericMidiControlProtocol::create_function (const XMLNode& node)
|
||||||
cnt = 0;
|
cnt = 0;
|
||||||
|
|
||||||
while (ss >> val) {
|
while (ss >> val) {
|
||||||
sysex[cnt++] = (MIDI::byte) val;
|
data[cnt++] = (MIDI::byte) val;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -791,7 +809,7 @@ GenericMidiControlProtocol::create_function (const XMLNode& node)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sysex_size == 0) {
|
if (data_size == 0) {
|
||||||
if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
|
if (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -816,7 +834,7 @@ GenericMidiControlProtocol::create_function (const XMLNode& node)
|
||||||
|
|
||||||
MIDIFunction* mf = new MIDIFunction (*_port);
|
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;
|
delete mf;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -826,6 +844,102 @@ GenericMidiControlProtocol::create_function (const XMLNode& node)
|
||||||
return mf;
|
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
|
void
|
||||||
GenericMidiControlProtocol::set_current_bank (uint32_t b)
|
GenericMidiControlProtocol::set_current_bank (uint32_t b)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,7 @@ namespace ARDOUR {
|
||||||
|
|
||||||
class MIDIControllable;
|
class MIDIControllable;
|
||||||
class MIDIFunction;
|
class MIDIFunction;
|
||||||
|
class MIDIAction;
|
||||||
|
|
||||||
class GenericMidiControlProtocol : public ARDOUR::ControlProtocol {
|
class GenericMidiControlProtocol : public ARDOUR::ControlProtocol {
|
||||||
public:
|
public:
|
||||||
|
|
@ -94,6 +95,9 @@ class GenericMidiControlProtocol : public ARDOUR::ControlProtocol {
|
||||||
typedef std::list<MIDIFunction*> MIDIFunctions;
|
typedef std::list<MIDIFunction*> MIDIFunctions;
|
||||||
MIDIFunctions functions;
|
MIDIFunctions functions;
|
||||||
|
|
||||||
|
typedef std::list<MIDIAction*> MIDIActions;
|
||||||
|
MIDIActions actions;
|
||||||
|
|
||||||
typedef std::pair<MIDIControllable*,PBD::ScopedConnection> MIDIPendingControllable;
|
typedef std::pair<MIDIControllable*,PBD::ScopedConnection> MIDIPendingControllable;
|
||||||
typedef std::list<MIDIPendingControllable* > MIDIPendingControllables;
|
typedef std::list<MIDIPendingControllable* > MIDIPendingControllables;
|
||||||
MIDIPendingControllables pending_controllables;
|
MIDIPendingControllables pending_controllables;
|
||||||
|
|
@ -110,6 +114,7 @@ class GenericMidiControlProtocol : public ARDOUR::ControlProtocol {
|
||||||
|
|
||||||
MIDIControllable* create_binding (const XMLNode&);
|
MIDIControllable* create_binding (const XMLNode&);
|
||||||
MIDIFunction* create_function (const XMLNode&);
|
MIDIFunction* create_function (const XMLNode&);
|
||||||
|
MIDIAction* create_action (const XMLNode&);
|
||||||
|
|
||||||
void reset_controllables ();
|
void reset_controllables ();
|
||||||
void drop_all ();
|
void drop_all ();
|
||||||
|
|
|
||||||
62
libs/surfaces/generic_midi/midiaction.cc
Normal file
62
libs/surfaces/generic_midi/midiaction.cc
Normal file
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
65
libs/surfaces/generic_midi/midiaction.h
Normal file
65
libs/surfaces/generic_midi/midiaction.h
Normal file
|
|
@ -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__
|
||||||
|
|
||||||
|
|
@ -26,52 +26,43 @@
|
||||||
using namespace MIDI;
|
using namespace MIDI;
|
||||||
|
|
||||||
MIDIFunction::MIDIFunction (MIDI::Port& p)
|
MIDIFunction::MIDIFunction (MIDI::Port& p)
|
||||||
: _port (p)
|
: MIDIInvokable (p)
|
||||||
{
|
{
|
||||||
sysex_size = 0;
|
|
||||||
sysex = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MIDIFunction::~MIDIFunction ()
|
MIDIFunction::~MIDIFunction ()
|
||||||
{
|
{
|
||||||
delete [] sysex;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
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;
|
_function = TransportStop;
|
||||||
} else if (strcasecmp (function_name.c_str(), "transport-roll") == 0) {
|
} else if (strcasecmp (_invokable_name.c_str(), "transport-roll") == 0) {
|
||||||
_function = TransportRoll;
|
_function = TransportRoll;
|
||||||
} else if (strcasecmp (function_name.c_str(), "transport-zero") == 0) {
|
} else if (strcasecmp (_invokable_name.c_str(), "transport-zero") == 0) {
|
||||||
_function = TransportZero;
|
_function = TransportZero;
|
||||||
} else if (strcasecmp (function_name.c_str(), "transport-start") == 0) {
|
} else if (strcasecmp (_invokable_name.c_str(), "transport-start") == 0) {
|
||||||
_function = TransportStart;
|
_function = TransportStart;
|
||||||
} else if (strcasecmp (function_name.c_str(), "transport-end") == 0) {
|
} else if (strcasecmp (_invokable_name.c_str(), "transport-end") == 0) {
|
||||||
_function = TransportEnd;
|
_function = TransportEnd;
|
||||||
} else if (strcasecmp (function_name.c_str(), "loop-toggle") == 0) {
|
} else if (strcasecmp (_invokable_name.c_str(), "loop-toggle") == 0) {
|
||||||
_function = TransportLoopToggle;
|
_function = TransportLoopToggle;
|
||||||
} else if (strcasecmp (function_name.c_str(), "rec-enable") == 0) {
|
} else if (strcasecmp (_invokable_name.c_str(), "rec-enable") == 0) {
|
||||||
_function = TransportRecordEnable;
|
_function = TransportRecordEnable;
|
||||||
} else if (strcasecmp (function_name.c_str(), "rec-disable") == 0) {
|
} else if (strcasecmp (_invokable_name.c_str(), "rec-disable") == 0) {
|
||||||
_function = TransportRecordDisable;
|
_function = TransportRecordDisable;
|
||||||
} else if (strcasecmp (function_name.c_str(), "next-bank") == 0) {
|
} else if (strcasecmp (_invokable_name.c_str(), "next-bank") == 0) {
|
||||||
_function = NextBank;
|
_function = NextBank;
|
||||||
} else if (strcasecmp (function_name.c_str(), "prev-bank") == 0) {
|
} else if (strcasecmp (_invokable_name.c_str(), "prev-bank") == 0) {
|
||||||
_function = PrevBank;
|
_function = PrevBank;
|
||||||
} else {
|
} else {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
_ui = &ui;
|
|
||||||
|
|
||||||
if (sysex_sz) {
|
|
||||||
/* we take ownership of the sysex data */
|
|
||||||
sysex = sysex_data;
|
|
||||||
sysex_size = sysex_sz;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
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&
|
XMLNode&
|
||||||
MIDIFunction::get_state ()
|
MIDIFunction::get_state ()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,8 @@
|
||||||
|
|
||||||
#include "ardour/types.h"
|
#include "ardour/types.h"
|
||||||
|
|
||||||
|
#include "midiinvokable.h"
|
||||||
|
|
||||||
namespace MIDI {
|
namespace MIDI {
|
||||||
class Channel;
|
class Channel;
|
||||||
class Port;
|
class Port;
|
||||||
|
|
@ -37,7 +39,7 @@ namespace MIDI {
|
||||||
|
|
||||||
class GenericMidiControlProtocol;
|
class GenericMidiControlProtocol;
|
||||||
|
|
||||||
class MIDIFunction : public PBD::Stateful
|
class MIDIFunction : public MIDIInvokable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
enum Function {
|
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);
|
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 _invokable_name; }
|
||||||
const std::string& function_name() const { return _function_name; }
|
|
||||||
|
|
||||||
XMLNode& get_state (void);
|
XMLNode& get_state (void);
|
||||||
int set_state (const XMLNode&, int version);
|
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:
|
private:
|
||||||
Function _function;
|
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 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__
|
#endif // __gm_midicontrollable_h__
|
||||||
|
|
|
||||||
171
libs/surfaces/generic_midi/midiinvokable.cc
Normal file
171
libs/surfaces/generic_midi/midiinvokable.cc
Normal file
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
78
libs/surfaces/generic_midi/midiinvokable.h
Normal file
78
libs/surfaces/generic_midi/midiinvokable.h
Normal file
|
|
@ -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__
|
||||||
|
|
||||||
|
|
@ -24,8 +24,10 @@ def build(bld):
|
||||||
generic_midi_control_protocol.cc
|
generic_midi_control_protocol.cc
|
||||||
gmcp_gui.cc
|
gmcp_gui.cc
|
||||||
interface.cc
|
interface.cc
|
||||||
|
midiinvokable.cc
|
||||||
midicontrollable.cc
|
midicontrollable.cc
|
||||||
midifunction.cc
|
midifunction.cc
|
||||||
|
midiaction.cc
|
||||||
'''
|
'''
|
||||||
obj.export_incdirs = ['.']
|
obj.export_incdirs = ['.']
|
||||||
obj.cxxflags = '-DPACKAGE="ardour_genericmidi"'
|
obj.cxxflags = '-DPACKAGE="ardour_genericmidi"'
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue