From 965b13584213319b0edd7e0a95992c1ea69f16c9 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Sat, 10 Oct 2015 17:13:04 -0400 Subject: numerous changes to Mackie support, generally offering better robustness --- libs/surfaces/mackie/gui.cc | 68 ++++++---------- libs/surfaces/mackie/gui.h | 7 +- libs/surfaces/mackie/mackie_control_protocol.cc | 102 +++++++++++++++++------- libs/surfaces/mackie/mackie_control_protocol.h | 1 + libs/surfaces/mackie/strip.cc | 64 +++++++++------ libs/surfaces/mackie/strip.h | 3 +- libs/surfaces/mackie/surface.cc | 15 +++- libs/surfaces/mackie/surface.h | 4 +- 8 files changed, 157 insertions(+), 107 deletions(-) diff --git a/libs/surfaces/mackie/gui.cc b/libs/surfaces/mackie/gui.cc index e627d797e5..4b33126c8d 100644 --- a/libs/surfaces/mackie/gui.cc +++ b/libs/surfaces/mackie/gui.cc @@ -118,6 +118,7 @@ MackieControlProtocolGUI::MackieControlProtocolGUI (MackieControlProtocol& p) _surface_combo.signal_changed().connect (sigc::mem_fun (*this, &MackieControlProtocolGUI::surface_combo_changed)); _cp.DeviceChanged.connect (device_change_connection, invalidator (*this), boost::bind (&MackieControlProtocolGUI::device_changed, this), gui_context()); + _cp.ConnectionChange.connect (connection_change_connection, invalidator (*this), boost::bind (&MackieControlProtocolGUI::connection_handler, this), gui_context()); ipmidi_base_port_adjustment.signal_value_changed().connect (sigc::mem_fun (*this, &MackieControlProtocolGUI::ipmidi_spinner_changed)); @@ -239,6 +240,29 @@ MackieControlProtocolGUI::MackieControlProtocolGUI (MackieControlProtocol& p) fkey_packer->show_all(); } +void +MackieControlProtocolGUI::connection_handler () +{ + vector::iterator ic; + vector::iterator oc; + + vector midi_inputs; + vector midi_outputs; + + ARDOUR::AudioEngine::instance()->get_ports ("", ARDOUR::DataType::MIDI, ARDOUR::PortFlags (ARDOUR::IsOutput|ARDOUR::IsPhysical), midi_inputs); + ARDOUR::AudioEngine::instance()->get_ports ("", ARDOUR::DataType::MIDI, ARDOUR::PortFlags (ARDOUR::IsInput|ARDOUR::IsPhysical), midi_outputs); + + + for (ic = input_combos.begin(), oc = output_combos.begin(); ic != input_combos.end() && oc != output_combos.end(); ++ic, ++oc) { + + boost::shared_ptr surface = _cp.get_surface_by_raw_pointer ((*ic)->get_data ("surface")); + + if (surface) { + update_port_combos (midi_inputs, midi_outputs, *ic, *oc, surface); + } + } +} + void MackieControlProtocolGUI::update_port_combos (vector const& midi_inputs, vector const& midi_outputs, Gtk::ComboBoxText* input_combo, @@ -827,47 +851,3 @@ MackieControlProtocolGUI::touch_sensitive_change () int sensitivity = (int) touch_sensitivity_adjustment.get_value (); _cp.set_touch_sensitivity (sensitivity); } - -void -MackieControlProtocolGUI::surface_connectivity_change (Surface* raw_surface) -{ - boost::shared_ptr surface; - - for (MackieControlProtocol::Surfaces::iterator s = _cp.surfaces.begin(); s != _cp.surfaces.end(); ++s) { - if ((*s).get() == raw_surface) { - surface = *s; - break; - } - } - - if (!surface) { - return; - } - - Gtk::ComboBoxText* input_combo = 0; - Gtk::ComboBoxText* output_combo = 0; - - for (vector::iterator c = input_combos.begin(); c != input_combos.end(); ++c) { - if ((*c)->get_data ("surface") == raw_surface) { - input_combo = *c; - } - } - - for (vector::iterator c = output_combos.begin(); c != output_combos.end(); ++c) { - if ((*c)->get_data ("surface") == raw_surface) { - output_combo = *c; - } - } - - if (!input_combo || !output_combo) { - return; - } - - vector midi_inputs; - vector midi_outputs; - - ARDOUR::AudioEngine::instance()->get_ports ("", ARDOUR::DataType::MIDI, ARDOUR::PortFlags (ARDOUR::IsOutput|ARDOUR::IsPhysical), midi_inputs); - ARDOUR::AudioEngine::instance()->get_ports ("", ARDOUR::DataType::MIDI, ARDOUR::PortFlags (ARDOUR::IsInput|ARDOUR::IsPhysical), midi_outputs); - - update_port_combos (midi_inputs, midi_outputs, input_combo, output_combo, surface); -} diff --git a/libs/surfaces/mackie/gui.h b/libs/surfaces/mackie/gui.h index 8421068fd8..b2df91ed7a 100644 --- a/libs/surfaces/mackie/gui.h +++ b/libs/surfaces/mackie/gui.h @@ -135,11 +135,8 @@ class MackieControlProtocolGUI : public Gtk::Notebook Gtk::ComboBoxText* output_combo, boost::shared_ptr surface); - /* this takes a raw pointer to Surface, because it connects to a signal - emitted by a Surface and we don't want to use - boost::shared_from_this. - */ - void surface_connectivity_change (Mackie::Surface* raw_surface); + PBD::ScopedConnection connection_change_connection; + void connection_handler (); }; } diff --git a/libs/surfaces/mackie/mackie_control_protocol.cc b/libs/surfaces/mackie/mackie_control_protocol.cc index 6f942445f8..0334431d81 100644 --- a/libs/surfaces/mackie/mackie_control_protocol.cc +++ b/libs/surfaces/mackie/mackie_control_protocol.cc @@ -400,11 +400,11 @@ MackieControlProtocol::set_active (bool yn) BaseUI::run (); - if (create_surfaces ()) { - return -1; - } connect_session_signals (); - update_surfaces (); + + if (!_device_info.name().empty()) { + set_device (_device_info.name(), true); + } /* set up periodic task for metering and automation */ @@ -534,6 +534,10 @@ MackieControlProtocol::update_global_button (int id, LedState ls) { Glib::Threads::Mutex::Lock lm (surfaces_lock); + if (surfaces.empty()) { + return; + } + if (!_device_info.has_global_controls()) { return; } @@ -554,6 +558,10 @@ MackieControlProtocol::update_global_led (int id, LedState ls) { Glib::Threads::Mutex::Lock lm (surfaces_lock); + if (surfaces.empty()) { + return; + } + if (!_device_info.has_global_controls()) { return; } @@ -688,6 +696,8 @@ MackieControlProtocol::set_device_info (const string& device_name) int MackieControlProtocol::set_device (const string& device_name, bool force) { + cerr << "Set Device\n\n\n\n\n\n"; + if (device_name == device_info().name() && !force) { /* already using that device, nothing to do */ return 0; @@ -708,15 +718,17 @@ MackieControlProtocol::set_device (const string& device_name, bool force) hui_timeout->attach (main_loop()->get_context()); } - if (create_surfaces ()) { - return -1; - } - if (!_device_info.uses_ipmidi()) { + /* notice that the handler for this will execute in our event + loop, not in the thread where the + PortConnectedOrDisconnected signal is emitted. + */ ARDOUR::AudioEngine::instance()->PortConnectedOrDisconnected.connect (port_connection, MISSING_INVALIDATOR, boost::bind (&MackieControlProtocol::connection_handler, this, _1, _2, _3, _4, _5), this); } - switch_banks (0, true); + if (create_surfaces ()) { + return -1; + } DeviceChanged (); @@ -735,18 +747,17 @@ MackieControlProtocol::create_surfaces () { string device_name; surface_type_t stype = mcu; // type not yet determined - char buf[128]; - - if (_device_info.extenders() == 0) { - device_name = X_("mackie control"); - } else { - device_name = X_("mackie control #1"); - } - DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Create %1 surfaces\n", 1 + _device_info.extenders())); + DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Create %1 surfaces for %2\n", 1 + _device_info.extenders(), _device_info.name())); for (uint32_t n = 0; n < 1 + _device_info.extenders(); ++n) { + if (n == 0) { + device_name = _device_info.name(); + } else { + device_name = string_compose ("%1 #%2", _device_info.name(), n+1); + } + boost::shared_ptr surface; if (n == _device_info.master_position()) { @@ -765,6 +776,7 @@ MackieControlProtocol::create_surfaces () } if (_surfaces_state) { + cerr << "Resetting surface state\n"; surface->set_state (*_surfaces_state, _surfaces_version); } @@ -773,13 +785,6 @@ MackieControlProtocol::create_surfaces () surfaces.push_back (surface); } - if (_device_info.extenders() < 2) { - device_name = X_("mackie control #2"); - } else { - snprintf (buf, sizeof (buf), X_("mackie control #%d"), n+2); - device_name = buf; - } - if (!_device_info.uses_ipmidi()) { _input_bundle.reset (new ARDOUR::Bundle (_("Mackie Control In"), true)); @@ -857,6 +862,7 @@ MackieControlProtocol::create_surfaces () void MackieControlProtocol::close() { + port_connection.disconnect (); session_connections.drop_connections (); route_connections.drop_connections (); periodic_connection.disconnect (); @@ -1050,6 +1056,14 @@ void MackieControlProtocol::notify_parameter_changed (std::string const & p) void MackieControlProtocol::notify_route_added (ARDOUR::RouteList & rl) { + { + Glib::Threads::Mutex::Lock lm (surfaces_lock); + + if (surfaces.empty()) { + return; + } + } + // currently assigned banks are less than the full set of // strips, so activate the new strip now. @@ -1072,6 +1086,11 @@ MackieControlProtocol::notify_solo_active_changed (bool active) { Glib::Threads::Mutex::Lock lm (surfaces_lock); + + if (surfaces.empty()) { + return; + } + surface = _master_surface; } @@ -1087,6 +1106,14 @@ MackieControlProtocol::notify_solo_active_changed (bool active) void MackieControlProtocol::notify_remote_id_changed() { + { + Glib::Threads::Mutex::Lock lm (surfaces_lock); + + if (surfaces.empty()) { + return; + } + } + Sorted sorted = get_sorted_routes(); uint32_t sz = n_strips(); @@ -1150,6 +1177,9 @@ MackieControlProtocol::notify_record_state_changed () { Glib::Threads::Mutex::Lock lm (surfaces_lock); + if (surfaces.empty()) { + return; + } surface = _master_surface; } @@ -1771,7 +1801,6 @@ MackieControlProtocol::ipmidi_restart () void MackieControlProtocol::clear_surfaces () { - port_connection.disconnect (); clear_ports (); { @@ -1814,6 +1843,20 @@ MackieControlProtocol::toggle_backlight () } } +boost::shared_ptr +MackieControlProtocol::get_surface_by_raw_pointer (void* ptr) const +{ + Glib::Threads::Mutex::Lock lm (surfaces_lock); + + for (Surfaces::const_iterator s = surfaces.begin(); s != surfaces.end(); ++s) { + if ((*s).get() == (Surface*) ptr) { + return *s; + } + } + + return boost::shared_ptr (); +} + boost::shared_ptr MackieControlProtocol::nth_surface (uint32_t n) const { @@ -1831,11 +1874,14 @@ MackieControlProtocol::nth_surface (uint32_t n) const void MackieControlProtocol::connection_handler (boost::weak_ptr wp1, std::string name1, boost::weak_ptr wp2, std::string name2, bool yn) { - Glib::Threads::Mutex::Lock lm (surfaces_lock); + Surfaces scopy; + { + Glib::Threads::Mutex::Lock lm (surfaces_lock); + scopy = surfaces; + } - for (Surfaces::const_iterator s = surfaces.begin(); s != surfaces.end(); ++s) { + for (Surfaces::const_iterator s = scopy.begin(); s != scopy.end(); ++s) { if ((*s)->connection_handler (wp1, name1, wp2, name2, yn)) { - cerr << (*s)->name() << " Connected, or disconnected\n"; ConnectionChange (*s); break; } diff --git a/libs/surfaces/mackie/mackie_control_protocol.h b/libs/surfaces/mackie/mackie_control_protocol.h index 14beb707f4..091fa3898f 100644 --- a/libs/surfaces/mackie/mackie_control_protocol.h +++ b/libs/surfaces/mackie/mackie_control_protocol.h @@ -166,6 +166,7 @@ class MackieControlProtocol typedef std::list > Surfaces; Surfaces surfaces; + boost::shared_ptr get_surface_by_raw_pointer (void*) const; boost::shared_ptr nth_surface (uint32_t) const; std::list > bundles (); diff --git a/libs/surfaces/mackie/strip.cc b/libs/surfaces/mackie/strip.cc index dad5eb098a..a2eb2843fd 100644 --- a/libs/surfaces/mackie/strip.cc +++ b/libs/surfaces/mackie/strip.cc @@ -200,7 +200,6 @@ Strip::set_route (boost::shared_ptr r, bool /*with_messages*/) _pan_mode = PanAzimuthAutomation; potmode_changed (true); - _route->solo_changed.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_solo_changed, this), ui_context()); _route->listen_changed.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_solo_changed, this), ui_context()); @@ -368,7 +367,14 @@ Strip::notify_trim_changed (bool force_update) _surface->write (_vpot->zero()); return; } - Control* control = control_by_parameter[TrimAutomation]; + Control* control = 0; + ControlParameterMap::iterator i = control_by_parameter.find (TrimAutomation); + + if (i == control_by_parameter.end()) { + return; + } + + control = i->second; boost::shared_ptr ac = _route->trim_control(); @@ -432,12 +438,15 @@ Strip::notify_panner_azi_changed (bool force_update) return; } - Control* control = control_by_parameter[PanAzimuthAutomation]; + Control* control = 0; + ControlParameterMap::iterator i = control_by_parameter.find (PanAzimuthAutomation); - if (!control) { + if (i == control_by_parameter.end()) { return; } + control = i->second; + double pos = pannable->pan_azimuth_control->internal_to_interface (pannable->pan_azimuth_control->get_value()); if (force_update || pos != _last_pan_azi_position_written) { @@ -472,13 +481,15 @@ Strip::notify_panner_width_changed (bool force_update) return; } + Control* control = 0; + ControlParameterMap::iterator i = control_by_parameter.find (PanWidthAutomation); - Control* control = control_by_parameter[PanWidthAutomation]; - - if (!control) { + if (i == control_by_parameter.end()) { return; } + control = i->second; + double pos = pannable->pan_width_control->internal_to_interface (pannable->pan_width_control->get_value()); if (force_update || pos != _last_pan_azi_position_written) { @@ -1007,22 +1018,23 @@ Strip::potmode_changed (bool notify) // WIP int pm = _surface->mcp().pot_mode(); switch (pm) { - case MackieControlProtocol::Pan: - // This needs to set current pan mode (azimuth or width... or whatever) - set_vpot_parameter (_pan_mode); - DEBUG_TRACE (DEBUG::MackieControl, "Assign pot to Pan mode.\n"); - break; - case MackieControlProtocol::Tracks: // should change the Tracks to Trim - DEBUG_TRACE (DEBUG::MackieControl, "Assign pot to Trim mode.\n"); + case MackieControlProtocol::Pan: + // This needs to set current pan mode (azimuth or width... or whatever) + set_vpot_parameter (_pan_mode); + DEBUG_TRACE (DEBUG::MackieControl, "Assign pot to Pan mode.\n"); + break; + case MackieControlProtocol::Tracks: // should change the Tracks to Trim + DEBUG_TRACE (DEBUG::MackieControl, "Assign pot to Trim mode.\n"); set_vpot_parameter (TrimAutomation); break; - case MackieControlProtocol::Send: - DEBUG_TRACE (DEBUG::MackieControl, "Assign pot to Send mode.\n"); - // set to current send - break; - default: - break; - } + case MackieControlProtocol::Send: + DEBUG_TRACE (DEBUG::MackieControl, "Assign pot to Send mode.\n"); + // set to current send + break; + default: + cerr << "Pot mode " << pm << " not yet handled\n"; + break; + } if (notify) { notify_all (); @@ -1133,9 +1145,13 @@ Strip::set_vpot_parameter (Evoral::Parameter p) DEBUG_TRACE (DEBUG::MackieControl, string_compose ("switch to vpot mode %1\n", p)); reset_saved_values (); - for (int i = 0; i <= TrimAutomation; ++i) { - if (control_by_parameter[i] == _vpot) { - control_by_parameter[i] = 0; + + /* unset any mapping between the vpot and any existing parameters */ + + for (ControlParameterMap::iterator i = control_by_parameter.begin(); i != control_by_parameter.end(); ++i) { + + if (i != control_by_parameter.end() && i->second == _vpot) { + i->second = 0; } } diff --git a/libs/surfaces/mackie/strip.h b/libs/surfaces/mackie/strip.h index e06eccf25f..f0c972aa73 100644 --- a/libs/surfaces/mackie/strip.h +++ b/libs/surfaces/mackie/strip.h @@ -155,7 +155,8 @@ private: void reset_saved_values (); - std::map control_by_parameter; + typedef std::map ControlParameterMap; + ControlParameterMap control_by_parameter; }; } diff --git a/libs/surfaces/mackie/surface.cc b/libs/surfaces/mackie/surface.cc index 7709ebb264..3b42aa1e8f 100644 --- a/libs/surfaces/mackie/surface.cc +++ b/libs/surfaces/mackie/surface.cc @@ -37,6 +37,8 @@ #include "ardour/session.h" #include "ardour/utils.h" +#include + #include "control_group.h" #include "surface_port.h" #include "surface.h" @@ -221,6 +223,13 @@ Surface::connection_handler (boost::weak_ptr, std::string name1, b to queue it with the MCP event loop. */ + /* 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 { @@ -662,9 +671,7 @@ Surface::handle_midi_sysex (MIDI::Parser &, MIDI::byte * raw_bytes, size_t count write_sysex (host_connection_query (bytes)); } else { DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Mackie Control Device ready, current status = %1\n", _active)); - if (!_active) { - turn_it_on (); - } + turn_it_on (); } break; @@ -672,7 +679,7 @@ Surface::handle_midi_sysex (MIDI::Parser &, MIDI::byte * raw_bytes, size_t count DEBUG_TRACE (DEBUG::MackieControl, "Logic Control Device confirms connection, ardour replies\n"); if (bytes[4] == 0x10 || bytes[4] == 0x11) { write_sysex (host_connection_confirmation (bytes)); - _active = true; + turn_it_on (); } break; diff --git a/libs/surfaces/mackie/surface.h b/libs/surfaces/mackie/surface.h index c0a2cff871..166b8ed4bf 100644 --- a/libs/surfaces/mackie/surface.h +++ b/libs/surfaces/mackie/surface.h @@ -3,6 +3,8 @@ #include +#include + #include "pbd/signals.h" #include "pbd/xml++.h" #include "midi++/types.h" @@ -43,7 +45,7 @@ class Jog; class Pot; class Led; -class Surface : public PBD::ScopedConnectionList +class Surface : public PBD::ScopedConnectionList, public sigc::trackable { public: Surface (MackieControlProtocol&, const std::string& name, uint32_t number, surface_type_t stype); -- cgit v1.2.3