From 4d47760d61a5d1f73d47c16663480c9353bfb318 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Fri, 2 Oct 2015 22:03:17 -0400 Subject: add new (fast) redisplay timer that pushes parameter display text to MCP device. Changes are queued in a FIFO, and pulled when a timeout in the MCP event loop fires. --- libs/surfaces/mackie/mackie_control_protocol.cc | 41 ++++++++++++++++-- libs/surfaces/mackie/mackie_control_protocol.h | 2 + libs/surfaces/mackie/strip.cc | 56 ++++++++++++++++++++----- libs/surfaces/mackie/surface.cc | 8 ++++ libs/surfaces/mackie/surface.h | 1 + 5 files changed, 94 insertions(+), 14 deletions(-) diff --git a/libs/surfaces/mackie/mackie_control_protocol.cc b/libs/surfaces/mackie/mackie_control_protocol.cc index d52deb115c..1b66528754 100644 --- a/libs/surfaces/mackie/mackie_control_protocol.cc +++ b/libs/surfaces/mackie/mackie_control_protocol.cc @@ -421,7 +421,13 @@ MackieControlProtocol::set_active (bool yn) Glib::RefPtr periodic_timeout = Glib::TimeoutSource::create (100); // milliseconds periodic_connection = periodic_timeout->connect (sigc::mem_fun (*this, &MackieControlProtocol::periodic)); periodic_timeout->attach (main_loop()->get_context()); + + /* a faster periodic task used to display parameter updates */ + Glib::RefPtr redisplay_timeout = Glib::TimeoutSource::create (10); // milliseconds + redisplay_connection = redisplay_timeout->connect (sigc::mem_fun (*this, &MackieControlProtocol::redisplay)); + redisplay_timeout->attach (main_loop()->get_context()); + } else { BaseUI::quit (); @@ -471,6 +477,33 @@ MackieControlProtocol::periodic () return true; } +bool +MackieControlProtocol::redisplay () +{ + if (!active()) { + return false; + } + + if (needs_ipmidi_restart) { + ipmidi_restart (); + return true; + } + + if (!_initialized) { + initialize(); + } + + { + Glib::Threads::Mutex::Lock lm (surfaces_lock); + + for (Surfaces::iterator s = surfaces.begin(); s != surfaces.end(); ++s) { + (*s)->redisplay (); + } + } + + return true; +} + void MackieControlProtocol::update_timecode_beats_led() { @@ -1244,7 +1277,7 @@ void MackieControlProtocol::handle_button_event (Surface& surface, Button& button, ButtonState bs) { Button::ID button_id = button.bid(); - + if (bs != press && bs != release) { update_led (surface, button, none); return; @@ -1258,9 +1291,9 @@ MackieControlProtocol::handle_button_event (Surface& surface, Button& button, Bu string action = _device_profile.get_button_action (button.bid(), _modifier_state); if (!action.empty()) { - + if (action.find ('/') != string::npos) { /* good chance that this is really an action */ - + DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Looked up action for button %1 with modifier %2, got [%3]\n", button.bid(), _modifier_state, action)); @@ -1273,7 +1306,9 @@ MackieControlProtocol::handle_button_event (Surface& surface, Button& button, Bu DEBUG_TRACE (DEBUG::MackieControl, string_compose ("executing action %1\n", action)); access_action (action); } + return; + } else { /* "action" is more likely to be a button name. We use this to diff --git a/libs/surfaces/mackie/mackie_control_protocol.h b/libs/surfaces/mackie/mackie_control_protocol.h index 140fdd8996..2008d9c887 100644 --- a/libs/surfaces/mackie/mackie_control_protocol.h +++ b/libs/surfaces/mackie/mackie_control_protocol.h @@ -281,6 +281,7 @@ class MackieControlProtocol Mackie::DeviceInfo _device_info; Mackie::DeviceProfile _device_profile; sigc::connection periodic_connection; + sigc::connection redisplay_connection; uint32_t _current_initial_bank; PBD::ScopedConnectionList audio_engine_connections; PBD::ScopedConnectionList session_connections; @@ -322,6 +323,7 @@ class MackieControlProtocol int create_surfaces (); bool periodic(); + bool redisplay(); void build_gui (); bool midi_input_handler (Glib::IOCondition ioc, MIDI::Port* port); void clear_ports (); diff --git a/libs/surfaces/mackie/strip.cc b/libs/surfaces/mackie/strip.cc index 9447b4121c..68978b3de9 100644 --- a/libs/surfaces/mackie/strip.cc +++ b/libs/surfaces/mackie/strip.cc @@ -96,6 +96,7 @@ Strip::Strip (Surface& s, const std::string& name, int index, const map (Fader::factory (*_surface, index, "fader", *this)); _vpot = dynamic_cast (Pot::factory (*_surface, Pot::ID + index, "vpot", *this)); @@ -318,18 +319,19 @@ Strip::notify_gain_changed (bool force_update) float gain_coefficient = ac->get_value(); float normalized_position = ac->internal_to_interface (gain_coefficient); + if (force_update || normalized_position != _last_gain_position_written) { if (_surface->mcp().flip_mode() != MackieControlProtocol::Normal) { if (!control->in_use()) { _surface->write (_vpot->set (normalized_position, true, Pot::wrap)); } - do_parameter_display (GainAutomation, gain_coefficient); + queue_parameter_display (GainAutomation, gain_coefficient); } else { if (!control->in_use()) { _surface->write (_fader->set_position (normalized_position)); } - do_parameter_display (GainAutomation, gain_coefficient); + queue_parameter_display (GainAutomation, gain_coefficient); } queue_display_reset (2000); @@ -391,7 +393,7 @@ Strip::notify_panner_azi_changed (bool force_update) _surface->write (_vpot->set (pos, true, Pot::dot)); } - do_parameter_display (PanAzimuthAutomation, pos); + queue_parameter_display (PanAzimuthAutomation, pos); queue_display_reset (2000); _last_pan_azi_position_written = pos; } @@ -435,7 +437,7 @@ Strip::notify_panner_width_changed (bool force_update) _surface->write (_vpot->set (pos, true, Pot::spread)); } - do_parameter_display (PanWidthAutomation, pos); + queue_parameter_display (PanWidthAutomation, pos); queue_display_reset (2000); _last_pan_azi_position_written = pos; } @@ -512,17 +514,17 @@ Strip::fader_touch_event (Button&, ButtonState bs) boost::shared_ptr ac = _fader->control (); - if (_surface->mcp().modifier_state() == MackieControlProtocol::MODIFIER_SHIFT) { + if (_surface->mcp().main_modifier_state() & MackieControlProtocol::MODIFIER_SHIFT) { if (ac) { ac->set_value (ac->normal()); } } else { - + _fader->set_in_use (true); _fader->start_touch (_surface->mcp().transport_frame()); if (ac) { - do_parameter_display ((AutomationType) ac->parameter().type(), ac->internal_to_interface (ac->get_value())); + queue_parameter_display ((AutomationType) ac->parameter().type(), ac->internal_to_interface (ac->get_value())); queue_display_reset (2000); } } @@ -604,6 +606,17 @@ Strip::handle_button (Button& button, ButtonState bs) } } +void +Strip::queue_parameter_display (AutomationType type, float val) +{ + RedisplayRequest req; + + req.type = type; + req.val = val; + + redisplay_requests.write (&req, 1); +} + void Strip::do_parameter_display (AutomationType type, float val) { @@ -658,11 +671,16 @@ Strip::handle_fader (Fader& fader, float position) DEBUG_TRACE (DEBUG::MackieControl, string_compose ("fader to %1\n", position)); fader.set_value (position); - queue_display_reset (2000); - // must echo bytes back to slider now, because - // the notifier only works if the fader is not being - // touched. Which it is if we're getting input. + /* From the Mackie Control MIDI implementation docs: + + In order to ensure absolute synchronization with the host software, + Mackie Control uses a closed-loop servo system for the faders, + meaning the faders will always move to their last received position. + When a host receives a Fader Position Message, it must then + re-transmit that message to the Mackie Control or else the faders + will return to their last position. + */ _surface->write (fader.set_position (position)); } @@ -697,6 +715,22 @@ Strip::periodic (uint64_t usecs) } } +void +Strip::redisplay () +{ + RedisplayRequest req; + bool have_request = false; + + while (redisplay_requests.read (&req, 1) == 1) { + /* read them all */ + have_request = true; + } + + if (have_request) { + do_parameter_display (req.type, req.val); + } +} + void Strip::update_automation () { diff --git a/libs/surfaces/mackie/surface.cc b/libs/surfaces/mackie/surface.cc index eb77e32c97..b448a7ca19 100644 --- a/libs/surfaces/mackie/surface.cc +++ b/libs/surfaces/mackie/surface.cc @@ -757,6 +757,14 @@ Surface::periodic (uint64_t now_usecs) } } +void +Surface::redisplay () +{ + for (Strips::iterator s = strips.begin(); s != strips.end(); ++s) { + (*s)->redisplay (); + } +} + void Surface::write (const MidiByteArray& data) { diff --git a/libs/surfaces/mackie/surface.h b/libs/surfaces/mackie/surface.h index 2473930528..cc9ba58e7f 100644 --- a/libs/surfaces/mackie/surface.h +++ b/libs/surfaces/mackie/surface.h @@ -87,6 +87,7 @@ public: const MidiByteArray& sysex_hdr() const; void periodic (uint64_t now_usecs); + void redisplay (); void handle_midi_pitchbend_message (MIDI::Parser&, MIDI::pitchbend_t, uint32_t channel_id); void handle_midi_controller_message (MIDI::Parser&, MIDI::EventTwoBytes*); -- cgit v1.2.3