modification to make generic MIDI actually work again

git-svn-id: svn://localhost/ardour2/trunk@673 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
Paul Davis 2006-07-10 20:01:47 +00:00
parent 05f8fcd189
commit 26843b34fd
14 changed files with 142 additions and 24 deletions

View file

@ -23,6 +23,7 @@ struct ControlProtocolInfo {
std::string path; std::string path;
bool requested; bool requested;
bool mandatory; bool mandatory;
XMLNode* state;
}; };
class ControlProtocolManager : public sigc::trackable, public Stateful class ControlProtocolManager : public sigc::trackable, public Stateful

View file

@ -49,6 +49,10 @@ ControlProtocolManager::set_session (Session& s)
if ((*i)->requested || (*i)->mandatory) { if ((*i)->requested || (*i)->mandatory) {
instantiate (**i); instantiate (**i);
(*i)->requested = false; (*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->protocol = 0;
cpi->requested = false; cpi->requested = false;
cpi->mandatory = descriptor->mandatory; cpi->mandatory = descriptor->mandatory;
cpi->state = 0;
control_protocol_info.push_back (cpi); control_protocol_info.push_back (cpi);

View file

@ -62,7 +62,8 @@ BindingProxy::button_press_handler (GdkEventButton *ev)
if (Controllable::StartLearning (&controllable)) { if (Controllable::StartLearning (&controllable)) {
string prompt = _("operate controller now"); string prompt = _("operate controller now");
prompter.set_text (prompt); prompter.set_text (prompt);
prompter.show_all (); prompter.touch (); // shows popup
learning_connection = controllable.LearningFinished.connect (mem_fun (*this, &BindingProxy::learning_finished));
} }
return true; return true;
} }
@ -70,9 +71,18 @@ BindingProxy::button_press_handler (GdkEventButton *ev)
return false; return false;
} }
void
BindingProxy::learning_finished ()
{
learning_connection.disconnect ();
prompter.touch (); // hides popup
}
bool bool
BindingProxy::prompter_hiding (GdkEventAny *ev) BindingProxy::prompter_hiding (GdkEventAny *ev)
{ {
learning_connection.disconnect ();
Controllable::StopLearning (&controllable); Controllable::StopLearning (&controllable);
return false; return false;
} }

View file

@ -46,7 +46,8 @@ class BindingProxy : public sigc::trackable
PBD::Controllable& controllable; PBD::Controllable& controllable;
guint bind_button; guint bind_button;
guint bind_statemask; guint bind_statemask;
sigc::connection learning_connection;
void learning_finished ();
bool prompter_hiding (GdkEventAny *); bool prompter_hiding (GdkEventAny *);
}; };

View file

@ -73,11 +73,12 @@ PopUp::remove ()
{ {
hide (); hide ();
if (popdown_time != 0 && timeout != -1) {
gtk_timeout_remove (timeout);
}
if (delete_on_hide) { if (delete_on_hide) {
std::cerr << "deleting prompter\n"; std::cerr << "deleting prompter\n";
if (popdown_time != 0 && timeout != -1) {
gtk_timeout_remove (timeout);
}
gtk_idle_add (idle_delete, this); gtk_idle_add (idle_delete, this);
} }
} }
@ -125,11 +126,12 @@ PopUp::on_delete_event (GdkEventAny* ev)
{ {
hide(); hide();
if (popdown_time != 0 && timeout != -1) {
gtk_timeout_remove (timeout);
}
if (delete_on_hide) { if (delete_on_hide) {
std::cerr << "deleting prompter\n" << endl; std::cerr << "deleting prompter\n" << endl;
if (popdown_time != 0 && timeout != -1) {
gtk_timeout_remove (timeout);
}
gtk_idle_add (idle_delete, this); gtk_idle_add (idle_delete, this);
} }

View file

@ -21,6 +21,8 @@ class Controllable : public virtual sigc::trackable, public Stateful {
virtual bool can_send_feedback() const { return true; } virtual bool can_send_feedback() const { return true; }
sigc::signal<void> LearningFinished;
static sigc::signal<void,Controllable*> Created; static sigc::signal<void,Controllable*> Created;
static sigc::signal<void,Controllable*> GoingAway; static sigc::signal<void,Controllable*> GoingAway;

View file

@ -26,7 +26,7 @@
#include <vector> #include <vector>
#include <list> #include <list>
#include <sigc++/sigc++.h> #include <sigc++/sigc++.h>
#include <pbd/stateful.h>
#include <control_protocol/basic_ui.h> #include <control_protocol/basic_ui.h>
namespace ARDOUR { namespace ARDOUR {
@ -34,7 +34,7 @@ namespace ARDOUR {
class Route; class Route;
class Session; class Session;
class ControlProtocol : public sigc::trackable, public BasicUI { class ControlProtocol : public sigc::trackable, public Stateful, public BasicUI {
public: public:
ControlProtocol (Session&, std::string name); ControlProtocol (Session&, std::string name);
virtual ~ControlProtocol(); virtual ~ControlProtocol();

View file

@ -20,6 +20,9 @@
#include <algorithm> #include <algorithm>
#include <pbd/error.h>
#include <pbd/failed_constructor.h>
#include <midi++/port.h> #include <midi++/port.h>
#include <midi++/manager.h> #include <midi++/manager.h>
#include <midi++/port_request.h> #include <midi++/port_request.h>
@ -39,9 +42,17 @@ GenericMidiControlProtocol::GenericMidiControlProtocol (Session& s)
: ControlProtocol (s, _("GenericMIDI")) : ControlProtocol (s, _("GenericMIDI"))
{ {
MIDI::Manager* mm = MIDI::Manager::instance(); 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 _feedback_interval = 10000; // microseconds
last_feedback_time = 0; last_feedback_time = 0;
@ -112,11 +123,13 @@ GenericMidiControlProtocol::start_learning (Controllable* c)
MIDIControllable* mc = new MIDIControllable (*_port, *c); MIDIControllable* mc = new MIDIControllable (*_port, *c);
{ {
Glib::Mutex::Lock lm (pending_lock); Glib::Mutex::Lock lm (pending_lock);
pending_controllables.push_back (mc); std::pair<MIDIControllables::iterator,bool> result;
mc->learning_stopped.connect (bind (mem_fun (*this, &GenericMidiControlProtocol::learning_stopped), mc)); result = pending_controllables.insert (mc);
if (result.second) {
c->LearningFinished.connect (bind (mem_fun (*this, &GenericMidiControlProtocol::learning_stopped), mc));
}
} }
mc->learn_about_external_control (); mc->learn_about_external_control ();
@ -135,7 +148,7 @@ GenericMidiControlProtocol::learning_stopped (MIDIControllable* mc)
pending_controllables.erase (i); pending_controllables.erase (i);
} }
controllables.push_back (mc); controllables.insert (mc);
} }
void 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;
}

View file

@ -1,7 +1,7 @@
#ifndef ardour_generic_midi_control_protocol_h #ifndef ardour_generic_midi_control_protocol_h
#define ardour_generic_midi_control_protocol_h #define ardour_generic_midi_control_protocol_h
#include <vector> #include <set>
#include <glibmm/thread.h> #include <glibmm/thread.h>
#include <ardour/types.h> #include <ardour/types.h>
@ -32,6 +32,9 @@ class GenericMidiControlProtocol : public ARDOUR::ControlProtocol {
MIDI::Port* port () const { return _port; } MIDI::Port* port () const { return _port; }
void set_feedback_interval (ARDOUR::microseconds_t); void set_feedback_interval (ARDOUR::microseconds_t);
XMLNode& get_state ();
int set_state (const XMLNode&);
private: private:
MIDI::Port* _port; MIDI::Port* _port;
ARDOUR::microseconds_t _feedback_interval; ARDOUR::microseconds_t _feedback_interval;
@ -40,7 +43,7 @@ class GenericMidiControlProtocol : public ARDOUR::ControlProtocol {
void _send_feedback (); void _send_feedback ();
void send_feedback (); void send_feedback ();
typedef std::vector<MIDIControllable*> MIDIControllables; typedef std::set<MIDIControllable*> MIDIControllables;
MIDIControllables controllables; MIDIControllables controllables;
MIDIControllables pending_controllables; MIDIControllables pending_controllables;
Glib::Mutex controllables_lock; Glib::Mutex controllables_lock;

View file

@ -1,3 +1,5 @@
#include <pbd/failed_constructor.h>
#include <control_protocol/control_protocol.h> #include <control_protocol/control_protocol.h>
#include "generic_midi_control_protocol.h" #include "generic_midi_control_protocol.h"
@ -6,7 +8,13 @@ using namespace ARDOUR;
ControlProtocol* ControlProtocol*
new_generic_midi_protocol (ControlProtocolDescriptor* descriptor, Session* s) 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)) { if (gmcp->set_active (true)) {
delete gmcp; delete gmcp;

View file

@ -90,7 +90,6 @@ MIDIControllable::learn_about_external_control ()
{ {
drop_external_control (); drop_external_control ();
midi_learn_connection = _port.input()->any.connect (mem_fun (*this, &MIDIControllable::midi_receiver)); midi_learn_connection = _port.input()->any.connect (mem_fun (*this, &MIDIControllable::midi_receiver));
learning_started ();
} }
void 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]); bind_midi ((channel_t) (msg[0] & 0xf), eventType (msg[0] & 0xF0), msg[1]);
learning_stopped (); controllable.LearningFinished ();
} }
void void

View file

@ -53,9 +53,6 @@ class MIDIControllable : public Stateful
void stop_learning (); void stop_learning ();
void drop_external_control (); void drop_external_control ();
sigc::signal<void> learning_started;
sigc::signal<void> learning_stopped;
bool get_midi_feedback () { return feedback; } bool get_midi_feedback () { return feedback; }
void set_midi_feedback (bool val) { feedback = val; } void set_midi_feedback (bool val) { feedback = val; }

View file

@ -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;
}

View file

@ -23,6 +23,9 @@ class TranzportControlProtocol : public ARDOUR::ControlProtocol
static bool probe (); static bool probe ();
XMLNode& get_state ();
int set_state (const XMLNode&);
private: private:
static const int VENDORID = 0x165b; static const int VENDORID = 0x165b;
static const int PRODUCTID = 0x8101; static const int PRODUCTID = 0x8101;