+
+MIDIControllable*
+GenericMidiControlProtocol::create_binding (const XMLNode& node)
+{
+ const XMLProperty* prop;
+ MIDI::byte detail;
+ MIDI::channel_t channel;
+ string uri;
+ MIDI::eventType ev;
+ int intval;
+ bool momentary;
+
+ 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_("pb"))) != 0) {
+ ev = MIDI::pitchbend;
+ } else {
+ return 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;
+ }
+
+ if ((prop = node.property (X_("momentary"))) != 0) {
+ momentary = string_is_affirmative (prop->value());
+ } else {
+ momentary = false;
+ }
+
+ prop = node.property (X_("uri"));
+ uri = prop->value();
+
+ MIDIControllable* mc = new MIDIControllable (this, *_input_port->parser(), momentary);
+
+ if (mc->init (uri)) {
+ delete mc;
+ return 0;
+ }
+
+ mc->bind_midi (channel, ev, detail);
+
+ return mc;
+}
+
+void
+GenericMidiControlProtocol::reset_controllables ()
+{
+ Glib::Threads::Mutex::Lock lm2 (controllables_lock);
+
+ for (MIDIControllables::iterator iter = controllables.begin(); iter != controllables.end(); ) {
+ MIDIControllable* existingBinding = (*iter);
+ MIDIControllables::iterator next = iter;
+ ++next;
+
+ if (!existingBinding->learned()) {
+ ControllableDescriptor& desc (existingBinding->descriptor());
+
+ if (desc.banked()) {
+ desc.set_bank_offset (_current_bank * _bank_size);
+ }
+
+ /* its entirely possible that the session doesn't have
+ * the specified controllable (e.g. it has too few
+ * tracks). if we find this to be the case, we just leave
+ * the binding around, unbound, and it will do "late
+ * binding" (or "lazy binding") if/when any data arrives.
+ */
+
+ existingBinding->lookup_controllable ();
+ }
+
+ iter = next;
+ }
+}
+
+boost::shared_ptr<Controllable>
+GenericMidiControlProtocol::lookup_controllable (const ControllableDescriptor& desc) const
+{
+ return session->controllable_by_descriptor (desc);
+}
+
+MIDIFunction*
+GenericMidiControlProtocol::create_function (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;
+ string argument;
+
+ 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;
+ }
+ }
+
+ if ((prop = node.property (X_("arg"))) != 0 || (prop = node.property (X_("argument"))) != 0 || (prop = node.property (X_("arguments"))) != 0) {
+ argument = prop->value ();
+ }
+
+ prop = node.property (X_("function"));
+
+ MIDIFunction* mf = new MIDIFunction (*_input_port->parser());
+
+ if (mf->setup (*this, prop->value(), argument, data, data_size)) {
+ delete mf;
+ return 0;
+ }
+
+ 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 (*_input_port->parser());
+
+ 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)
+{
+ _current_bank = b;
+ reset_controllables ();
+}
+
+void
+GenericMidiControlProtocol::next_bank ()
+{
+ _current_bank++;
+ reset_controllables ();
+}
+
+void
+GenericMidiControlProtocol::prev_bank()
+{
+ if (_current_bank) {
+ _current_bank--;
+ reset_controllables ();
+ }
+}
+
+void
+GenericMidiControlProtocol::set_motorised (bool m)
+{
+ _motorised = m;
+}
+
+void
+GenericMidiControlProtocol::set_threshold (int t)
+{
+ _threshold = t;
+}