+
+int
+GenericMidiControlProtocol::load_bindings (const string& xmlpath)
+{
+ XMLTree state_tree;
+
+ if (!state_tree.read (xmlpath.c_str())) {
+ error << string_compose(_("Could not understand MIDI bindings file %1"), xmlpath) << endmsg;
+ return -1;
+ }
+
+ XMLNode* root = state_tree.root();
+
+ if (root->name() != X_("ArdourMIDIBindings")) {
+ error << string_compose (_("MIDI Bindings file %1 is not really a MIDI bindings file"), xmlpath) << endmsg;
+ return -1;
+ }
+
+ const XMLProperty* prop;
+
+ if ((prop = root->property ("version")) == 0) {
+ return -1;
+ } else {
+ int major;
+ int minor;
+ int micro;
+
+ sscanf (prop->value().c_str(), "%d.%d.%d", &major, &minor, µ);
+ Stateful::loading_state_version = (major * 1000) + minor;
+ }
+
+ const XMLNodeList& children (root->children());
+ XMLNodeConstIterator citer;
+ XMLNodeConstIterator gciter;
+
+ MIDIControllable* mc;
+
+ for (citer = children.begin(); citer != children.end(); ++citer) {
+ if ((*citer)->name() == "Binding") {
+ const XMLNode* child = *citer;
+
+ if (child->property ("uri")) {
+ /* controllable */
+
+ if ((mc = create_binding (*child)) != 0) {
+ Glib::Mutex::Lock lm2 (controllables_lock);
+ controllables.insert (mc);
+ }
+
+ } else if (child->property ("function")) {
+
+ cerr << "try to create a function from " << child->property ("function")->value() << endl;
+
+ /* function */
+ MIDIFunction* mf;
+
+ if ((mf = create_function (*child)) != 0) {
+ functions.push_back (mf);
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+MIDIControllable*
+GenericMidiControlProtocol::create_binding (const XMLNode& node)
+{
+ const XMLProperty* prop;
+ int detail;
+ int channel;
+ string uri;
+ MIDI::eventType ev;
+
+ if ((prop = node.property (X_("channel"))) == 0) {
+ return 0;
+ }
+
+ if (sscanf (prop->value().c_str(), "%d", &channel) != 1) {
+ return 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 {
+ return 0;
+ }
+
+ if (sscanf (prop->value().c_str(), "%d", &detail) != 1) {
+ return 0;
+ }
+
+ prop = node.property (X_("uri"));
+ uri = prop->value();
+
+ MIDIControllable* mc = new MIDIControllable (*_port, uri, false);
+ mc->bind_midi (channel, ev, detail);
+
+ cerr << "New MC with URI = " << uri << endl;
+
+ return mc;
+}
+
+void
+GenericMidiControlProtocol::reset_controllables ()
+{
+ Glib::Mutex::Lock lm2 (controllables_lock);
+
+ for (MIDIControllables::iterator iter = controllables.begin(); iter != controllables.end(); ++iter) {
+ MIDIControllable* existingBinding = (*iter);
+
+ boost::shared_ptr<Controllable> c = session->controllable_by_uri (existingBinding->current_uri());
+ existingBinding->set_controllable (c.get());
+ }
+}
+
+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* sysex = 0;
+ uint32_t sysex_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) {
+
+ ev = MIDI::sysex;
+ int val;
+ uint32_t cnt;
+
+ {
+ cnt = 0;
+ stringstream ss (prop->value());
+ ss << hex;
+
+ while (ss >> val) {
+ cnt++;
+ }
+ }
+
+ if (cnt == 0) {
+ return 0;
+ }
+
+ sysex = new MIDI::byte[cnt];
+ sysex_size = cnt;
+
+ {
+ stringstream ss (prop->value());
+ ss << hex;
+ cnt = 0;
+
+ while (ss >> val) {
+ sysex[cnt++] = (MIDI::byte) val;
+ cerr << hex << (int) sysex[cnt-1] << dec << ' ' << endl;
+ }
+ }
+
+ } else {
+ warning << "Binding ignored - unknown type" << endmsg;
+ return 0;
+ }
+
+ if (sysex_size == 0) {
+ 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 (sscanf (prop->value().c_str(), "%d", &intval) != 1) {
+ return 0;
+ }
+
+ detail = (MIDI::byte) intval;
+ }
+
+ prop = node.property (X_("function"));
+
+ MIDIFunction* mf = new MIDIFunction (*_port);
+
+ if (mf->init (*this, prop->value(), sysex, sysex_size)) {
+ delete mf;
+ return 0;
+ }
+
+ mf->bind_midi (channel, ev, detail);
+
+ cerr << "New MF with function = " << prop->value() << endl;
+
+ return mf;
+}