summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libs/ardour/ardour/session.h1
-rw-r--r--libs/ardour/midi_ui.cc12
-rw-r--r--libs/ardour/session_state.cc35
-rw-r--r--libs/pbd/base_ui.cc1
-rw-r--r--libs/surfaces/generic_midi/generic_midi_control_protocol.cc193
-rw-r--r--libs/surfaces/generic_midi/generic_midi_control_protocol.h30
-rw-r--r--libs/surfaces/generic_midi/midicontrollable.cc8
-rw-r--r--libs/surfaces/generic_midi/midicontrollable.h7
-rw-r--r--libs/surfaces/generic_midi/wscript1
9 files changed, 279 insertions, 9 deletions
diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h
index b72822bd1c..a21bc04690 100644
--- a/libs/ardour/ardour/session.h
+++ b/libs/ardour/ardour/session.h
@@ -769,6 +769,7 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
/* Controllables */
boost::shared_ptr<PBD::Controllable> controllable_by_id (const PBD::ID&);
+ boost::shared_ptr<PBD::Controllable> controllable_by_uri (const std::string&);
void add_controllable (boost::shared_ptr<PBD::Controllable>);
void remove_controllable (PBD::Controllable*);
diff --git a/libs/ardour/midi_ui.cc b/libs/ardour/midi_ui.cc
index aa81ff2068..fb85309ee1 100644
--- a/libs/ardour/midi_ui.cc
+++ b/libs/ardour/midi_ui.cc
@@ -68,6 +68,12 @@ MidiControlUI::do_request (MidiUIRequest* req)
} else if (req->type == CallSlot) {
+#ifndef NDEBUG
+ if (getenv ("DEBUG_THREADED_SIGNALS")) {
+ cerr << "MIDI UI calls a slot\n";
+ }
+#endif
+
req->the_slot ();
} else if (req->type == Quit) {
@@ -149,6 +155,12 @@ MidiControlUI::thread_init ()
{
struct sched_param rtparam;
+ char* c = new char[7];
+ strcpy (c, X_("midiUI"));
+ pthread_set_name (c);
+
+ cerr << "MIDI UI running\n";
+
PBD::notify_gui_about_thread_creation (X_("gui"), pthread_self(), X_("MIDI"), 2048);
SessionEvent::create_per_thread_pool (X_("MIDI I/O"), 128);
diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc
index 9394cd7bec..8ff076f759 100644
--- a/libs/ardour/session_state.cc
+++ b/libs/ardour/session_state.cc
@@ -2678,6 +2678,41 @@ Session::controllable_by_id (const PBD::ID& id)
return boost::shared_ptr<Controllable>();
}
+boost::shared_ptr<Controllable>
+Session::controllable_by_uri (const std::string& uri)
+{
+ boost::shared_ptr<Controllable> c;
+ string::size_type last_slash;
+ string useful_part;
+
+ if ((last_slash = uri.find_last_of ('/')) == string::npos) {
+ return c;
+ }
+
+ useful_part = uri.substr (last_slash+1);
+
+ uint32_t rid;
+ char what[64];
+
+ if (sscanf (useful_part.c_str(), "rid=%" PRIu32 "?%63s", &rid, what) != 2) {
+ return c;
+ }
+
+ boost::shared_ptr<Route> r = route_by_remote_id (rid);
+
+ if (!r) {
+ return c;
+ }
+
+ if (strncmp (what, "gain", 4) == 0) {
+ c = r->gain_control ();
+ } else if (strncmp (what, "pan", 3) == 0) {
+ } else if (strncmp (what, "plugin", 6) == 0) {
+ }
+
+ return c;
+}
+
void
Session::add_instant_xml (XMLNode& node, bool write_to_config)
{
diff --git a/libs/pbd/base_ui.cc b/libs/pbd/base_ui.cc
index 5e856d1ca0..ce7018a005 100644
--- a/libs/pbd/base_ui.cc
+++ b/libs/pbd/base_ui.cc
@@ -25,6 +25,7 @@
#include <cstring>
#include "pbd/base_ui.h"
+#include "pbd/pthread_utils.h"
#include "pbd/error.h"
#include "pbd/compose.h"
#include "pbd/failed_constructor.h"
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, &micro);
+ 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"'