summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Davis <paul@linuxaudiosystems.com>2006-07-10 20:01:47 +0000
committerPaul Davis <paul@linuxaudiosystems.com>2006-07-10 20:01:47 +0000
commit26843b34fdd62e6f80630868c5eb3f8fee0c17f1 (patch)
treefe4001528aa6e4e360ec6392c7b1120ca75e0aa9
parent05f8fcd189ca714c2c18b9fb174d5813140849df (diff)
modification to make generic MIDI actually work again
git-svn-id: svn://localhost/ardour2/trunk@673 d708f5d6-7413-0410-9779-e7cbd77b26cf
-rw-r--r--libs/ardour/ardour/control_protocol_manager.h1
-rw-r--r--libs/ardour/control_protocol_manager.cc5
-rw-r--r--libs/gtkmm2ext/binding_proxy.cc12
-rw-r--r--libs/gtkmm2ext/gtkmm2ext/binding_proxy.h3
-rw-r--r--libs/gtkmm2ext/popup.cc14
-rw-r--r--libs/pbd/pbd/controllable.h2
-rw-r--r--libs/surfaces/control_protocol/control_protocol/control_protocol.h4
-rw-r--r--libs/surfaces/generic_midi/generic_midi_control_protocol.cc87
-rw-r--r--libs/surfaces/generic_midi/generic_midi_control_protocol.h7
-rw-r--r--libs/surfaces/generic_midi/interface.cc10
-rw-r--r--libs/surfaces/generic_midi/midicontrollable.cc3
-rw-r--r--libs/surfaces/generic_midi/midicontrollable.h3
-rw-r--r--libs/surfaces/tranzport/tranzport_control_protocol.cc12
-rw-r--r--libs/surfaces/tranzport/tranzport_control_protocol.h3
14 files changed, 142 insertions, 24 deletions
diff --git a/libs/ardour/ardour/control_protocol_manager.h b/libs/ardour/ardour/control_protocol_manager.h
index 9202696dff..8eda7a4555 100644
--- a/libs/ardour/ardour/control_protocol_manager.h
+++ b/libs/ardour/ardour/control_protocol_manager.h
@@ -23,6 +23,7 @@ struct ControlProtocolInfo {
std::string path;
bool requested;
bool mandatory;
+ XMLNode* state;
};
class ControlProtocolManager : public sigc::trackable, public Stateful
diff --git a/libs/ardour/control_protocol_manager.cc b/libs/ardour/control_protocol_manager.cc
index c2fb188953..0370886a35 100644
--- a/libs/ardour/control_protocol_manager.cc
+++ b/libs/ardour/control_protocol_manager.cc
@@ -49,6 +49,10 @@ ControlProtocolManager::set_session (Session& s)
if ((*i)->requested || (*i)->mandatory) {
instantiate (**i);
(*i)->requested = false;
+
+ if ((*i)->state) {
+ (*i)->protocol->set_state (*(*i)->state);
+ }
}
}
}
@@ -181,6 +185,7 @@ ControlProtocolManager::control_protocol_discover (string path)
cpi->protocol = 0;
cpi->requested = false;
cpi->mandatory = descriptor->mandatory;
+ cpi->state = 0;
control_protocol_info.push_back (cpi);
diff --git a/libs/gtkmm2ext/binding_proxy.cc b/libs/gtkmm2ext/binding_proxy.cc
index a29cb41632..3a2f5bbbc8 100644
--- a/libs/gtkmm2ext/binding_proxy.cc
+++ b/libs/gtkmm2ext/binding_proxy.cc
@@ -62,7 +62,8 @@ BindingProxy::button_press_handler (GdkEventButton *ev)
if (Controllable::StartLearning (&controllable)) {
string prompt = _("operate controller now");
prompter.set_text (prompt);
- prompter.show_all ();
+ prompter.touch (); // shows popup
+ learning_connection = controllable.LearningFinished.connect (mem_fun (*this, &BindingProxy::learning_finished));
}
return true;
}
@@ -70,9 +71,18 @@ BindingProxy::button_press_handler (GdkEventButton *ev)
return false;
}
+void
+BindingProxy::learning_finished ()
+{
+ learning_connection.disconnect ();
+ prompter.touch (); // hides popup
+}
+
+
bool
BindingProxy::prompter_hiding (GdkEventAny *ev)
{
+ learning_connection.disconnect ();
Controllable::StopLearning (&controllable);
return false;
}
diff --git a/libs/gtkmm2ext/gtkmm2ext/binding_proxy.h b/libs/gtkmm2ext/gtkmm2ext/binding_proxy.h
index 365668f72c..a26c8ace2a 100644
--- a/libs/gtkmm2ext/gtkmm2ext/binding_proxy.h
+++ b/libs/gtkmm2ext/gtkmm2ext/binding_proxy.h
@@ -46,7 +46,8 @@ class BindingProxy : public sigc::trackable
PBD::Controllable& controllable;
guint bind_button;
guint bind_statemask;
-
+ sigc::connection learning_connection;
+ void learning_finished ();
bool prompter_hiding (GdkEventAny *);
};
diff --git a/libs/gtkmm2ext/popup.cc b/libs/gtkmm2ext/popup.cc
index 0a48ebfc59..a8ffc4af66 100644
--- a/libs/gtkmm2ext/popup.cc
+++ b/libs/gtkmm2ext/popup.cc
@@ -73,11 +73,12 @@ PopUp::remove ()
{
hide ();
+ if (popdown_time != 0 && timeout != -1) {
+ gtk_timeout_remove (timeout);
+ }
+
if (delete_on_hide) {
std::cerr << "deleting prompter\n";
- if (popdown_time != 0 && timeout != -1) {
- gtk_timeout_remove (timeout);
- }
gtk_idle_add (idle_delete, this);
}
}
@@ -125,11 +126,12 @@ PopUp::on_delete_event (GdkEventAny* ev)
{
hide();
+ if (popdown_time != 0 && timeout != -1) {
+ gtk_timeout_remove (timeout);
+ }
+
if (delete_on_hide) {
std::cerr << "deleting prompter\n" << endl;
- if (popdown_time != 0 && timeout != -1) {
- gtk_timeout_remove (timeout);
- }
gtk_idle_add (idle_delete, this);
}
diff --git a/libs/pbd/pbd/controllable.h b/libs/pbd/pbd/controllable.h
index 4948e4e4a0..c46e477b6e 100644
--- a/libs/pbd/pbd/controllable.h
+++ b/libs/pbd/pbd/controllable.h
@@ -21,6 +21,8 @@ class Controllable : public virtual sigc::trackable, public Stateful {
virtual bool can_send_feedback() const { return true; }
+ sigc::signal<void> LearningFinished;
+
static sigc::signal<void,Controllable*> Created;
static sigc::signal<void,Controllable*> GoingAway;
diff --git a/libs/surfaces/control_protocol/control_protocol/control_protocol.h b/libs/surfaces/control_protocol/control_protocol/control_protocol.h
index 69135f2b4b..2bd23f5b48 100644
--- a/libs/surfaces/control_protocol/control_protocol/control_protocol.h
+++ b/libs/surfaces/control_protocol/control_protocol/control_protocol.h
@@ -26,7 +26,7 @@
#include <vector>
#include <list>
#include <sigc++/sigc++.h>
-
+#include <pbd/stateful.h>
#include <control_protocol/basic_ui.h>
namespace ARDOUR {
@@ -34,7 +34,7 @@ namespace ARDOUR {
class Route;
class Session;
-class ControlProtocol : public sigc::trackable, public BasicUI {
+class ControlProtocol : public sigc::trackable, public Stateful, public BasicUI {
public:
ControlProtocol (Session&, std::string name);
virtual ~ControlProtocol();
diff --git a/libs/surfaces/generic_midi/generic_midi_control_protocol.cc b/libs/surfaces/generic_midi/generic_midi_control_protocol.cc
index dec891703e..d905c0bc41 100644
--- a/libs/surfaces/generic_midi/generic_midi_control_protocol.cc
+++ b/libs/surfaces/generic_midi/generic_midi_control_protocol.cc
@@ -20,6 +20,9 @@
#include <algorithm>
+#include <pbd/error.h>
+#include <pbd/failed_constructor.h>
+
#include <midi++/port.h>
#include <midi++/manager.h>
#include <midi++/port_request.h>
@@ -39,9 +42,17 @@ GenericMidiControlProtocol::GenericMidiControlProtocol (Session& s)
: ControlProtocol (s, _("GenericMIDI"))
{
MIDI::Manager* mm = MIDI::Manager::instance();
- MIDI::PortRequest pr ("ardour:MIDI control", "ardour:MIDI control", "duplex", "alsa/seq");
+
+ /* XXX it might be nice to run "control" through i18n, but thats a bit tricky because
+ the name is defined in ardour.rc which is likely not internationalized.
+ */
- _port = mm->add_port (pr);
+ _port = mm->port (X_("control"));
+
+ if (_port == 0) {
+ error << _("no MIDI port named \"control\" exists - generic MIDI control disabled") << endmsg;
+ throw failed_constructor();
+ }
_feedback_interval = 10000; // microseconds
last_feedback_time = 0;
@@ -112,11 +123,13 @@ GenericMidiControlProtocol::start_learning (Controllable* c)
MIDIControllable* mc = new MIDIControllable (*_port, *c);
-
{
Glib::Mutex::Lock lm (pending_lock);
- pending_controllables.push_back (mc);
- mc->learning_stopped.connect (bind (mem_fun (*this, &GenericMidiControlProtocol::learning_stopped), mc));
+ std::pair<MIDIControllables::iterator,bool> result;
+ result = pending_controllables.insert (mc);
+ if (result.second) {
+ c->LearningFinished.connect (bind (mem_fun (*this, &GenericMidiControlProtocol::learning_stopped), mc));
+ }
}
mc->learn_about_external_control ();
@@ -135,7 +148,7 @@ GenericMidiControlProtocol::learning_stopped (MIDIControllable* mc)
pending_controllables.erase (i);
}
- controllables.push_back (mc);
+ controllables.insert (mc);
}
void
@@ -156,3 +169,65 @@ GenericMidiControlProtocol::stop_learning (Controllable* c)
}
}
}
+
+XMLNode&
+GenericMidiControlProtocol::get_state ()
+{
+ XMLNode* node = new XMLNode (_name); /* node name must match protocol name */
+ XMLNode* children = new XMLNode (X_("controls"));
+
+ node->add_child_nocopy (*children);
+
+ Glib::Mutex::Lock lm2 (controllables_lock);
+ for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
+ children->add_child_nocopy ((*i)->get_state());
+ }
+
+ return *node;
+}
+
+int
+GenericMidiControlProtocol::set_state (const XMLNode& node)
+{
+ XMLNodeList nlist;
+ XMLNodeConstIterator niter;
+ Controllable* c;
+
+ {
+ Glib::Mutex::Lock lm (pending_lock);
+ pending_controllables.clear ();
+ }
+
+ Glib::Mutex::Lock lm2 (controllables_lock);
+
+ controllables.clear ();
+
+ nlist = node.children();
+
+ if (nlist.empty()) {
+ return 0;
+ }
+
+ nlist = nlist.front()->children ();
+
+ for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
+
+ XMLProperty* prop;
+
+ if ((prop = (*niter)->property ("id")) != 0) {
+
+ ID id = prop->value ();
+
+ c = session->controllable_by_id (id);
+
+ if (c) {
+ MIDIControllable* mc = new MIDIControllable (*_port, *c);
+ if (mc->set_state (**niter) == 0) {
+ controllables.insert (mc);
+ }
+ }
+ }
+ }
+
+ return 0;
+}
diff --git a/libs/surfaces/generic_midi/generic_midi_control_protocol.h b/libs/surfaces/generic_midi/generic_midi_control_protocol.h
index f86f5f6434..5f5a470b13 100644
--- a/libs/surfaces/generic_midi/generic_midi_control_protocol.h
+++ b/libs/surfaces/generic_midi/generic_midi_control_protocol.h
@@ -1,7 +1,7 @@
#ifndef ardour_generic_midi_control_protocol_h
#define ardour_generic_midi_control_protocol_h
-#include <vector>
+#include <set>
#include <glibmm/thread.h>
#include <ardour/types.h>
@@ -32,6 +32,9 @@ class GenericMidiControlProtocol : public ARDOUR::ControlProtocol {
MIDI::Port* port () const { return _port; }
void set_feedback_interval (ARDOUR::microseconds_t);
+ XMLNode& get_state ();
+ int set_state (const XMLNode&);
+
private:
MIDI::Port* _port;
ARDOUR::microseconds_t _feedback_interval;
@@ -40,7 +43,7 @@ class GenericMidiControlProtocol : public ARDOUR::ControlProtocol {
void _send_feedback ();
void send_feedback ();
- typedef std::vector<MIDIControllable*> MIDIControllables;
+ typedef std::set<MIDIControllable*> MIDIControllables;
MIDIControllables controllables;
MIDIControllables pending_controllables;
Glib::Mutex controllables_lock;
diff --git a/libs/surfaces/generic_midi/interface.cc b/libs/surfaces/generic_midi/interface.cc
index c6c59c6589..230be694f2 100644
--- a/libs/surfaces/generic_midi/interface.cc
+++ b/libs/surfaces/generic_midi/interface.cc
@@ -1,3 +1,5 @@
+#include <pbd/failed_constructor.h>
+
#include <control_protocol/control_protocol.h>
#include "generic_midi_control_protocol.h"
@@ -6,7 +8,13 @@ using namespace ARDOUR;
ControlProtocol*
new_generic_midi_protocol (ControlProtocolDescriptor* descriptor, Session* s)
{
- GenericMidiControlProtocol* gmcp = new GenericMidiControlProtocol (*s);
+ GenericMidiControlProtocol* gmcp;
+
+ try {
+ gmcp = new GenericMidiControlProtocol (*s);
+ } catch (failed_constructor& err) {
+ return 0;
+ }
if (gmcp->set_active (true)) {
delete gmcp;
diff --git a/libs/surfaces/generic_midi/midicontrollable.cc b/libs/surfaces/generic_midi/midicontrollable.cc
index f4b7ef665b..d6135fd2a8 100644
--- a/libs/surfaces/generic_midi/midicontrollable.cc
+++ b/libs/surfaces/generic_midi/midicontrollable.cc
@@ -90,7 +90,6 @@ MIDIControllable::learn_about_external_control ()
{
drop_external_control ();
midi_learn_connection = _port.input()->any.connect (mem_fun (*this, &MIDIControllable::midi_receiver));
- learning_started ();
}
void
@@ -199,7 +198,7 @@ MIDIControllable::midi_receiver (Parser &p, byte *msg, size_t len)
bind_midi ((channel_t) (msg[0] & 0xf), eventType (msg[0] & 0xF0), msg[1]);
- learning_stopped ();
+ controllable.LearningFinished ();
}
void
diff --git a/libs/surfaces/generic_midi/midicontrollable.h b/libs/surfaces/generic_midi/midicontrollable.h
index 7dd0be1d87..ab15f9f4ab 100644
--- a/libs/surfaces/generic_midi/midicontrollable.h
+++ b/libs/surfaces/generic_midi/midicontrollable.h
@@ -53,9 +53,6 @@ class MIDIControllable : public Stateful
void stop_learning ();
void drop_external_control ();
- sigc::signal<void> learning_started;
- sigc::signal<void> learning_stopped;
-
bool get_midi_feedback () { return feedback; }
void set_midi_feedback (bool val) { feedback = val; }
diff --git a/libs/surfaces/tranzport/tranzport_control_protocol.cc b/libs/surfaces/tranzport/tranzport_control_protocol.cc
index 09ab88e4ed..1fe9b7231a 100644
--- a/libs/surfaces/tranzport/tranzport_control_protocol.cc
+++ b/libs/surfaces/tranzport/tranzport_control_protocol.cc
@@ -1574,3 +1574,15 @@ TranzportControlProtocol::print (int row, int col, const char *text)
}
}
+XMLNode&
+TranzportControlProtocol::get_state ()
+{
+ XMLNode* node = new XMLNode (_name); /* node name must match protocol name */
+ return *node;
+}
+
+int
+TranzportControlProtocol::set_state (const XMLNode& node)
+{
+ return 0;
+}
diff --git a/libs/surfaces/tranzport/tranzport_control_protocol.h b/libs/surfaces/tranzport/tranzport_control_protocol.h
index 546cc2f2af..e6e1a83e46 100644
--- a/libs/surfaces/tranzport/tranzport_control_protocol.h
+++ b/libs/surfaces/tranzport/tranzport_control_protocol.h
@@ -23,6 +23,9 @@ class TranzportControlProtocol : public ARDOUR::ControlProtocol
static bool probe ();
+ XMLNode& get_state ();
+ int set_state (const XMLNode&);
+
private:
static const int VENDORID = 0x165b;
static const int PRODUCTID = 0x8101;