diff options
Diffstat (limited to 'libs/surfaces')
-rw-r--r-- | libs/surfaces/generic_midi/generic_midi_control_protocol.cc | 193 | ||||
-rw-r--r-- | libs/surfaces/generic_midi/generic_midi_control_protocol.h | 30 | ||||
-rw-r--r-- | libs/surfaces/generic_midi/midicontrollable.cc | 8 | ||||
-rw-r--r-- | libs/surfaces/generic_midi/midicontrollable.h | 7 | ||||
-rw-r--r-- | libs/surfaces/generic_midi/wscript | 1 |
5 files changed, 230 insertions, 9 deletions
diff --git a/libs/surfaces/generic_midi/generic_midi_control_protocol.cc b/libs/surfaces/generic_midi/generic_midi_control_protocol.cc index c3d7aabfaf..67e940d905 100644 --- a/libs/surfaces/generic_midi/generic_midi_control_protocol.cc +++ b/libs/surfaces/generic_midi/generic_midi_control_protocol.cc @@ -34,9 +34,11 @@ #include "generic_midi_control_protocol.h" #include "midicontrollable.h" +#include "midifunction.h" using namespace ARDOUR; using namespace PBD; +using namespace std; #include "i18n.h" @@ -44,7 +46,7 @@ using namespace PBD; #define ui_bind(x) boost::protect (boost::bind ((x))) GenericMidiControlProtocol::GenericMidiControlProtocol (Session& s) - : ControlProtocol (s, _("Generic MIDI"), MidiControlUI::instance()) + : ControlProtocol (s, _("Generic MIDI"), midi_ui_context()) { MIDI::Manager* mm = MIDI::Manager::instance(); @@ -71,10 +73,32 @@ GenericMidiControlProtocol::GenericMidiControlProtocol (Session& s) 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());; + + std::string xmlpath = "/tmp/midi.map"; + + load_bindings (xmlpath); + reset_controllables (); } GenericMidiControlProtocol::~GenericMidiControlProtocol () { + Glib::Mutex::Lock lm (pending_lock); + Glib::Mutex::Lock lm2 (controllables_lock); + + for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ++i) { + delete *i; + } + controllables.clear (); + + for (MIDIPendingControllables::iterator i = pending_controllables.begin(); i != pending_controllables.end(); ++i) { + delete *i; + } + pending_controllables.clear (); + + for (MIDIFunctions::iterator i = functions.begin(); i != functions.end(); ++i) { + delete *i; + } + functions.clear (); } int @@ -136,6 +160,9 @@ GenericMidiControlProtocol::start_learning (Controllable* c) return false; } + Glib::Mutex::Lock lm (pending_lock); + Glib::Mutex::Lock lm2 (controllables_lock); + MIDIControllables::iterator tmp; for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ) { tmp = i; @@ -392,3 +419,167 @@ GenericMidiControlProtocol::get_feedback () const return do_feedback; } +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")) { + + /* 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 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_("function")); + + MIDIFunction* mf = new MIDIFunction (*_port); + + if (mf->init (*this, prop->value())) { + delete mf; + return 0; + } + + mf->bind_midi (channel, ev, detail); + + cerr << "New MF with function = " << prop->value() << endl; + + return mf; +} diff --git a/libs/surfaces/generic_midi/generic_midi_control_protocol.h b/libs/surfaces/generic_midi/generic_midi_control_protocol.h index 39958bcf26..0c476f2418 100644 --- a/libs/surfaces/generic_midi/generic_midi_control_protocol.h +++ b/libs/surfaces/generic_midi/generic_midi_control_protocol.h @@ -1,7 +1,27 @@ +/* + Copyright (C) 2006 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 ardour_generic_midi_control_protocol_h #define ardour_generic_midi_control_protocol_h #include <set> +#include <list> #include <glibmm/thread.h> #include "ardour/types.h" @@ -20,6 +40,7 @@ namespace ARDOUR { } class MIDIControllable; +class MIDIFunction; class GenericMidiControlProtocol : public ARDOUR::ControlProtocol { public: @@ -50,6 +71,9 @@ class GenericMidiControlProtocol : public ARDOUR::ControlProtocol { typedef std::set<MIDIControllable*> MIDIControllables; MIDIControllables controllables; + typedef std::list<MIDIFunction*> MIDIFunctions; + MIDIFunctions functions; + typedef std::pair<MIDIControllable*,PBD::Connection> MIDIPendingControllable; typedef std::list<MIDIPendingControllable* > MIDIPendingControllables; MIDIPendingControllables pending_controllables; @@ -63,6 +87,12 @@ class GenericMidiControlProtocol : public ARDOUR::ControlProtocol { void create_binding (PBD::Controllable*, int, int); void delete_binding (PBD::Controllable*); + + int load_bindings (const std::string&); + MIDIControllable* create_binding (const XMLNode&); + MIDIFunction* create_function (const XMLNode&); + + void reset_controllables (); }; #endif /* ardour_generic_midi_control_protocol_h */ diff --git a/libs/surfaces/generic_midi/midicontrollable.cc b/libs/surfaces/generic_midi/midicontrollable.cc index d6b4007194..9c808af005 100644 --- a/libs/surfaces/generic_midi/midicontrollable.cc +++ b/libs/surfaces/generic_midi/midicontrollable.cc @@ -91,13 +91,9 @@ MIDIControllable::drop_external_control () } void -MIDIControllable::reacquire_controllable () +MIDIControllable::set_controllable (Controllable* c) { - if (!_current_uri.empty()) { - controllable = Controllable::by_uri (_current_uri); - } else { - controllable = 0; - } + controllable = c; } void diff --git a/libs/surfaces/generic_midi/midicontrollable.h b/libs/surfaces/generic_midi/midicontrollable.h index 4661b2f4c6..b6f7da5639 100644 --- a/libs/surfaces/generic_midi/midicontrollable.h +++ b/libs/surfaces/generic_midi/midicontrollable.h @@ -45,8 +45,10 @@ class MIDIControllable : public PBD::Stateful MIDIControllable (MIDI::Port&, const std::string& uri, bool bistate = false); virtual ~MIDIControllable (); - bool ok() const { return !_current_uri.empty(); } + void rediscover_controllable (); + bool ok() const { return !_current_uri.empty(); } + void send_feedback (); MIDI::byte* write_feedback (MIDI::byte* buf, int32_t& bufsize, bool force = false); @@ -64,6 +66,8 @@ class MIDIControllable : public PBD::Stateful MIDI::Port& get_port() const { return _port; } PBD::Controllable* get_controllable() const { return controllable; } + void set_controllable (PBD::Controllable*); + const std::string& current_uri() const { return _current_uri; } std::string control_description() const { return _control_description; } @@ -92,7 +96,6 @@ class MIDIControllable : public PBD::Stateful bool feedback; void init (); - void reacquire_controllable (); void midi_receiver (MIDI::Parser &p, MIDI::byte *, size_t); void midi_sense_note (MIDI::Parser &, MIDI::EventTwoBytes *, bool is_on); diff --git a/libs/surfaces/generic_midi/wscript b/libs/surfaces/generic_midi/wscript index 37975fb434..89e427323f 100644 --- a/libs/surfaces/generic_midi/wscript +++ b/libs/surfaces/generic_midi/wscript @@ -24,6 +24,7 @@ def build(bld): generic_midi_control_protocol.cc interface.cc midicontrollable.cc + midifunction.cc ''' obj.export_incdirs = ['.'] obj.cxxflags = '-DPACKAGE="ardour_genericmidi"' |