From 3d79e3c116a13e455c0ea1083a25c81af9107764 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Mon, 7 Dec 2015 12:04:23 -0500 Subject: [PATCH] adjust generic MIDI surface support to (1) properly use boost::shared_ptr (2) detect connection changes --- .../generic_midi_control_protocol.cc | 80 ++++++++++++++++++- .../generic_midi_control_protocol.h | 27 +++++-- libs/surfaces/generic_midi/gmcp_gui.cc | 5 +- 3 files changed, 101 insertions(+), 11 deletions(-) diff --git a/libs/surfaces/generic_midi/generic_midi_control_protocol.cc b/libs/surfaces/generic_midi/generic_midi_control_protocol.cc index 54bb65cb90..e319f65e1f 100644 --- a/libs/surfaces/generic_midi/generic_midi_control_protocol.cc +++ b/libs/surfaces/generic_midi/generic_midi_control_protocol.cc @@ -34,6 +34,8 @@ #include "midi++/port.h" +#include "ardour/async_midi_port.h" +#include "ardour/audioengine.h" #include "ardour/audioengine.h" #include "ardour/filesystem_paths.h" #include "ardour/session.h" @@ -58,12 +60,13 @@ using namespace std; GenericMidiControlProtocol::GenericMidiControlProtocol (Session& s) : ControlProtocol (s, _("Generic MIDI")) + , connection_state (ConnectionState (0)) , _motorised (false) , _threshold (10) , gui (0) { - _input_port = s.midi_input_port (); - _output_port = s.midi_output_port (); + _input_port = boost::dynamic_pointer_cast (s.midi_input_port ()); + _output_port = boost::dynamic_pointer_cast (s.midi_output_port ()); do_feedback = false; _feedback_interval = 10000; // microseconds @@ -94,6 +97,11 @@ GenericMidiControlProtocol::GenericMidiControlProtocol (Session& s) Route::RemoteControlIDChange.connect (*this, MISSING_INVALIDATOR, boost::bind (&GenericMidiControlProtocol::reset_controllables, this), midi_ui_context()); + /* Catch port connections and disconnections (cross-thread) */ + ARDOUR::AudioEngine::instance()->PortConnectedOrDisconnected.connect (port_connection, MISSING_INVALIDATOR, + boost::bind (&GenericMidiControlProtocol::connection_handler, this, _1, _2, _3, _4, _5), + midi_ui_context()); + reload_maps (); } @@ -229,7 +237,9 @@ GenericMidiControlProtocol::drop_bindings () int GenericMidiControlProtocol::set_active (bool /*yn*/) { - /* start/stop delivery/outbound thread */ + /* nothing to do here: the MIDI UI thread in libardour handles all our + I/O needs. + */ return 0; } @@ -1137,3 +1147,67 @@ GenericMidiControlProtocol::set_threshold (int t) { _threshold = t; } + +bool +GenericMidiControlProtocol::connection_handler (boost::weak_ptr, std::string name1, boost::weak_ptr, std::string name2, bool yn) +{ + if (!_input_port || !_output_port) { + return false; + } + + string ni = ARDOUR::AudioEngine::instance()->make_port_name_non_relative (boost::shared_ptr(_input_port)->name()); + string no = ARDOUR::AudioEngine::instance()->make_port_name_non_relative (boost::shared_ptr(_output_port)->name()); + + if (ni == name1 || ni == name2) { + if (yn) { + connection_state |= InputConnected; + } else { + connection_state &= ~InputConnected; + } + } else if (no == name1 || no == name2) { + if (yn) { + connection_state |= OutputConnected; + } else { + connection_state &= ~OutputConnected; + } + } else { + /* not our ports */ + return false; + } + + if ((connection_state & (InputConnected|OutputConnected)) == (InputConnected|OutputConnected)) { + + /* XXX this is a horrible hack. Without a short sleep here, + something prevents the device wakeup messages from being + sent and/or the responses from being received. + */ + + g_usleep (100000); + connected (); + + } else { + + } + + ConnectionChange (); /* emit signal for our GUI */ + + return true; /* connection status changed */ +} + +void +GenericMidiControlProtocol::connected () +{ + cerr << "Now connected\n"; +} + +boost::shared_ptr +GenericMidiControlProtocol::output_port() const +{ + return _output_port; +} + +boost::shared_ptr +GenericMidiControlProtocol::input_port() const +{ + return _input_port; +} diff --git a/libs/surfaces/generic_midi/generic_midi_control_protocol.h b/libs/surfaces/generic_midi/generic_midi_control_protocol.h index 9d51efc97d..a453716e95 100644 --- a/libs/surfaces/generic_midi/generic_midi_control_protocol.h +++ b/libs/surfaces/generic_midi/generic_midi_control_protocol.h @@ -34,8 +34,9 @@ namespace PBD { } namespace ARDOUR { - class Session; + class AsyncMIDIPort; class MidiPort; + class Session; } namespace MIDI { @@ -54,9 +55,9 @@ class GenericMidiControlProtocol : public ARDOUR::ControlProtocol { int set_active (bool yn); static bool probe() { return true; } - ARDOUR::Port* input_port () const { return ((ARDOUR::Port*) _input_port); } - ARDOUR::Port* output_port () const { return ((ARDOUR::Port*) _output_port); } - + boost::shared_ptr input_port () const; + boost::shared_ptr output_port () const; + void set_feedback_interval (ARDOUR::microseconds_t); int set_feedback (bool yn); @@ -103,9 +104,11 @@ class GenericMidiControlProtocol : public ARDOUR::ControlProtocol { } PBD::Signal0 ConnectionChange; + private: - MIDI::Port* _input_port; - MIDI::Port* _output_port; + boost::shared_ptr _input_port; + boost::shared_ptr _output_port; + ARDOUR::microseconds_t _feedback_interval; ARDOUR::microseconds_t last_feedback_time; @@ -143,6 +146,16 @@ class GenericMidiControlProtocol : public ARDOUR::ControlProtocol { void reset_controllables (); void drop_all (); + enum ConnectionState { + InputConnected = 0x1, + OutputConnected = 0x2 + }; + + int connection_state; + bool connection_handler (boost::weak_ptr, std::string name1, boost::weak_ptr, std::string name2, bool yn); + PBD::ScopedConnection port_connection; + void connected(); + std::string _current_binding; uint32_t _bank_size; uint32_t _current_bank; @@ -156,6 +169,8 @@ class GenericMidiControlProtocol : public ARDOUR::ControlProtocol { mutable void *gui; void build_gui (); + + }; #endif /* ardour_generic_midi_control_protocol_h */ diff --git a/libs/surfaces/generic_midi/gmcp_gui.cc b/libs/surfaces/generic_midi/gmcp_gui.cc index 427ed1d327..8e861b370d 100644 --- a/libs/surfaces/generic_midi/gmcp_gui.cc +++ b/libs/surfaces/generic_midi/gmcp_gui.cc @@ -65,7 +65,7 @@ private: void bank_changed (); void motorised_changed (); void threshold_changed (); - + void update_port_combos (); PBD::ScopedConnection connection_change_connection; void connection_handler (); @@ -131,6 +131,7 @@ GMCPGUI::GMCPGUI (GenericMidiControlProtocol& p) , motorised_button ("Motorised") , threshold_adjustment (p.threshold(), 1, 127, 1, 10) , threshold_spinner (threshold_adjustment) + , ignore_active_change (false) { vector popdowns; popdowns.push_back (_("Reset All")); @@ -179,7 +180,7 @@ GMCPGUI::GMCPGUI (GenericMidiControlProtocol& p) table->attach (*label, 0, 1, n, n+1, AttachOptions(FILL|EXPAND), AttachOptions(0)); table->attach (output_combo, 1, 2, n, n+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0); n++; - + //MIDI binding file selector... label = manage (new Label (_("MIDI Bindings:"))); label->set_alignment (0, 0.5); -- 2.30.2