From: Paul Davis Date: Mon, 10 Jul 2006 20:01:47 +0000 (+0000) Subject: modification to make generic MIDI actually work again X-Git-Tag: 2.0beta4~130 X-Git-Url: https://main.carlh.net/gitweb/?a=commitdiff_plain;h=26843b34fdd62e6f80630868c5eb3f8fee0c17f1;p=ardour.git modification to make generic MIDI actually work again git-svn-id: svn://localhost/ardour2/trunk@673 d708f5d6-7413-0410-9779-e7cbd77b26cf --- 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 LearningFinished; + static sigc::signal Created; static sigc::signal 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 #include #include - +#include #include 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 +#include +#include + #include #include #include @@ -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 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 +#include #include #include @@ -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 MIDIControllables; + typedef std::set 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 + #include #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 learning_started; - sigc::signal 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;