#include "ardour/session.h"
#include "ardour/route.h"
#include "ardour/midi_ui.h"
+#include "ardour/rc_configuration.h"
#include "generic_midi_control_protocol.h"
#include "midicontrollable.h"
#include "midifunction.h"
+#include "midiaction.h"
using namespace ARDOUR;
using namespace PBD;
the name is defined in ardour.rc which is likely not internationalized.
*/
- _port = mm->port (X_("control"));
+ _port = mm->port (Config->get_midi_port_name());
if (_port == 0) {
- error << _("no MIDI port named \"control\" exists - generic MIDI control disabled") << endmsg;
+ error << string_compose (_("no MIDI port named \"%1\" exists - generic MIDI control disabled"),
+ Config->get_midi_port_name())
+ << endmsg;
throw failed_constructor();
}
Controllable::CreateBinding.connect_same_thread (*this, boost::bind (&GenericMidiControlProtocol::create_binding, this, _1, _2, _3));
Controllable::DeleteBinding.connect_same_thread (*this, boost::bind (&GenericMidiControlProtocol::delete_binding, this, _1));
- Session::SendFeedback.connect (*this, boost::bind (&GenericMidiControlProtocol::send_feedback, this), midi_ui_context());;
- Route::RemoteControlIDChange.connect (*this, boost::bind (&GenericMidiControlProtocol::reset_controllables, this), midi_ui_context());
+ Session::SendFeedback.connect (*this, MISSING_INVALIDATOR, boost::bind (&GenericMidiControlProtocol::send_feedback, this), midi_ui_context());;
+ Route::RemoteControlIDChange.connect (*this, MISSING_INVALIDATOR, boost::bind (&GenericMidiControlProtocol::reset_controllables, this), midi_ui_context());
reload_maps ();
}
delete *i;
}
functions.clear ();
+
+ for (MIDIActions::iterator i = actions.begin(); i != actions.end(); ++i) {
+ delete *i;
+ }
+ actions.clear ();
}
void
MIDIControllable* mc = 0;
for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
- if ((*i)->get_controllable()->id() == c->id()) {
+ if ((*i)->get_controllable() && ((*i)->get_controllable()->id() == c->id())) {
mc = *i;
break;
}
if (control != 0) {
Glib::Mutex::Lock lm2 (controllables_lock);
- for (MIDIControllables::iterator iter = controllables.begin(); iter != controllables.end(); ++iter) {
+ for (MIDIControllables::iterator iter = controllables.begin(); iter != controllables.end();) {
MIDIControllable* existingBinding = (*iter);
if (control == (existingBinding->get_controllable())) {
delete existingBinding;
- controllables.erase (iter);
+ iter = controllables.erase (iter);
+ } else {
+ ++iter;
}
}
// Remove any old binding for this midi channel/type/value pair
// Note: can't use delete_binding() here because we don't know the specific controllable we want to remove, only the midi information
- for (MIDIControllables::iterator iter = controllables.begin(); iter != controllables.end(); ++iter) {
+ for (MIDIControllables::iterator iter = controllables.begin(); iter != controllables.end();) {
MIDIControllable* existingBinding = (*iter);
if ((existingBinding->get_control_channel() & 0xf ) == channel &&
(existingBinding->get_control_type() & 0xf0 ) == MIDI::controller) {
delete existingBinding;
- controllables.erase (iter);
+ iter = controllables.erase (iter);
+ } else {
+ ++iter;
}
}
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);
+ }
+ }
}
}
mc->bind_midi (channel, ev, detail);
- cerr << "New MC with URI " << uri << " on channel " << (int) channel << " detail = " << (int) detail << endl;
-
return mc;
}
void
GenericMidiControlProtocol::reset_controllables ()
{
- cerr << "GM::RC\n";
Glib::Mutex::Lock lm2 (controllables_lock);
for (MIDIControllables::iterator iter = controllables.begin(); iter != controllables.end(); ++iter) {
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;
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;
return 0;
}
- sysex = new MIDI::byte[cnt];
- sysex_size = cnt;
+ data = new MIDI::byte[cnt];
+ data_size = cnt;
{
stringstream ss (prop->value());
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;
}
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;
}
- cerr << "New MF with function = " << prop->value() << " on channel " << (int) channel << " detail = " << (int) detail << endl;
mf->bind_midi (channel, ev, detail);
-
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)
{