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;
bool requested;
bool mandatory;
XMLNode* state;
};
class ControlProtocolManager : public sigc::trackable, public Stateful

View file

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

View file

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

View file

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

View file

@ -73,11 +73,12 @@ PopUp::remove ()
{
hide ();
if (delete_on_hide) {
std::cerr << "deleting prompter\n";
if (popdown_time != 0 && timeout != -1) {
gtk_timeout_remove (timeout);
}
if (delete_on_hide) {
std::cerr << "deleting prompter\n";
gtk_idle_add (idle_delete, this);
}
}
@ -125,11 +126,12 @@ PopUp::on_delete_event (GdkEventAny* ev)
{
hide();
if (delete_on_hide) {
std::cerr << "deleting prompter\n" << endl;
if (popdown_time != 0 && timeout != -1) {
gtk_timeout_remove (timeout);
}
if (delete_on_hide) {
std::cerr << "deleting prompter\n" << endl;
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; }
sigc::signal<void> LearningFinished;
static sigc::signal<void,Controllable*> Created;
static sigc::signal<void,Controllable*> GoingAway;

View file

@ -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();

View file

@ -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");
_port = mm->add_port (pr);
/* 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->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;
}

View file

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

View file

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

View file

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

View file

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

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 ();
XMLNode& get_state ();
int set_state (const XMLNode&);
private:
static const int VENDORID = 0x165b;
static const int PRODUCTID = 0x8101;