diff --git a/libs/surfaces/mackie/controls.cc b/libs/surfaces/mackie/controls.cc index d73530f95b..ca7e086042 100644 --- a/libs/surfaces/mackie/controls.cc +++ b/libs/surfaces/mackie/controls.cc @@ -111,7 +111,6 @@ Control::Control( int id, int ordinal, std::string name, Group & group ) , _name( name ) , _group( group ) , _in_use( false ) -, _in_use_timeout( 250 ) { } @@ -178,15 +177,22 @@ Button & Strip::fader_touch() return *_fader_touch; } -bool Control::in_use() const +/** @return true if the control is in use, or false otherwise. + Buttons are `in use' when they are held down. + Faders with touch support are `in use' when they are being touched. + Pots, or faders without touch support, are `in use' from the first move + event until a timeout after the last move event. +*/ +bool +Control::in_use () const { return _in_use; } -Control & Control::in_use( bool rhs ) +void +Control::set_in_use (bool in_use) { - _in_use = rhs; - return *this; + _in_use = in_use; } ostream & Mackie::operator << ( ostream & os, const Mackie::Control & control ) diff --git a/libs/surfaces/mackie/controls.h b/libs/surfaces/mackie/controls.h index bc39570efb..8ccf7dbf03 100644 --- a/libs/surfaces/mackie/controls.h +++ b/libs/surfaces/mackie/controls.h @@ -214,21 +214,16 @@ public: /// Return true if this control is the one and only Jog Wheel virtual bool is_jog() const { return false; } - /** - Return true if the control is in use, or false otherwise. For buttons - this returns true if the button is currently being held down. For - faders, the touch button has not been released. For pots, this returns - true from the first move event until a timeout after the last move event. - */ - virtual bool in_use() const; - virtual Control & in_use( bool ); + bool in_use () const; + void set_in_use (bool); - /// The timeout value for this control. Normally defaulted to 250ms, but - /// certain controls (ie jog wheel) may want to override it. - virtual unsigned int in_use_timeout() { return _in_use_timeout; } - /// Keep track of the timeout so it can be updated with more incoming events sigc::connection in_use_connection; + + /** If we are doing an in_use timeout for a fader without touch, this + * is its touch button control; otherwise 0. + */ + Control* in_use_touch_control; private: int _id; @@ -236,7 +231,6 @@ private: std::string _name; Group & _group; bool _in_use; - unsigned int _in_use_timeout; }; std::ostream & operator << ( std::ostream & os, const Control & control ); diff --git a/libs/surfaces/mackie/mackie_control_protocol.cc b/libs/surfaces/mackie/mackie_control_protocol.cc index 63a8dde543..0165b74337 100644 --- a/libs/surfaces/mackie/mackie_control_protocol.cc +++ b/libs/surfaces/mackie/mackie_control_protocol.cc @@ -397,7 +397,7 @@ MackieControlProtocol::set_active (bool yn) } bool -MackieControlProtocol::handle_strip_button (Control & control, ButtonState bs, boost::shared_ptr route) +MackieControlProtocol::handle_strip_button (SurfacePort & port, Control & control, ButtonState bs, boost::shared_ptr route) { bool state = false; @@ -433,7 +433,14 @@ MackieControlProtocol::handle_strip_button (Control & control, ButtonState bs, b if (control.name() == "fader_touch") { state = bs == press; - control.strip().gain().in_use (state); + control.strip().gain().set_in_use (state); + + if (ARDOUR::Config->get_mackie_emulation() == "bcf" && state) { + /* BCF faders don't support touch, so add a timeout to reset + their `in_use' state. + */ + port.add_in_use_timeout (control.strip().gain(), &control.strip().fader_touch()); + } } return state; @@ -803,6 +810,11 @@ MackieControlProtocol::handle_control_event (SurfacePort & port, Control & contr { route->gain_control()->set_value (state.pos); + if (ARDOUR::Config->get_mackie_emulation() == "bcf") { + /* reset the timeout while we're still moving the fader */ + port.add_in_use_timeout (control, control.in_use_touch_control); + } + // 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. @@ -814,7 +826,7 @@ MackieControlProtocol::handle_control_event (SurfacePort & port, Control & contr if (control.group().is_strip()) { // strips if (route != 0) { - handle_strip_button (control, state.button_state, route); + handle_strip_button (port, control, state.button_state, route); } else { // no route so always switch the light off // because no signals will be emitted by a non-route @@ -823,7 +835,7 @@ MackieControlProtocol::handle_control_event (SurfacePort & port, Control & contr } else if (control.group().is_master()) { // master fader touch if (route != 0) { - handle_strip_button (control, state.button_state, route); + handle_strip_button (port, control, state.button_state, route); } } else { // handle all non-strip buttons diff --git a/libs/surfaces/mackie/mackie_control_protocol.h b/libs/surfaces/mackie/mackie_control_protocol.h index 5147586787..05308dbd63 100644 --- a/libs/surfaces/mackie/mackie_control_protocol.h +++ b/libs/surfaces/mackie/mackie_control_protocol.h @@ -270,7 +270,7 @@ class MackieControlProtocol Handle a button press for the control and return whether the corresponding light should be on or off. */ - bool handle_strip_button(Mackie::Control &, Mackie::ButtonState, boost::shared_ptr); + bool handle_strip_button (Mackie::SurfacePort &, Mackie::Control &, Mackie::ButtonState, boost::shared_ptr); void add_port (MIDI::Port &, MIDI::Port &, int number); diff --git a/libs/surfaces/mackie/mackie_port.cc b/libs/surfaces/mackie/mackie_port.cc index 77cce35f43..bda1c2765d 100644 --- a/libs/surfaces/mackie/mackie_port.cc +++ b/libs/surfaces/mackie/mackie_port.cc @@ -374,17 +374,6 @@ Control & MackiePort::lookup_control( MIDI::byte * bytes, size_t count ) return *control; } -bool MackiePort::handle_control_timeout_event ( Control * control ) -{ - // empty control_state - ControlState control_state; - control->in_use( false ); - control_event( *this, *control, control_state ); - - // only call this method once from the timer - return false; -} - // converts midi messages into control_event signals // it might be worth combining this with lookup_control // because they have similar logic flows. @@ -407,7 +396,7 @@ void MackiePort::handle_midi_any (MIDI::Parser &, MIDI::byte * raw_bytes, size_t } Control & control = lookup_control( raw_bytes, count ); - control.in_use( true ); + control.set_in_use (true); // This handles incoming bytes. Outgoing bytes // are sent by the signal handlers. @@ -429,7 +418,7 @@ void MackiePort::handle_midi_any (MIDI::Parser &, MIDI::byte * raw_bytes, size_t case Control::type_button: { ControlState control_state( raw_bytes[2] == 0x7f ? press : release ); - control.in_use( control_state.button_state == press ); + control.set_in_use (control_state.button_state == press); control_event( *this, control, control_state ); break; @@ -452,26 +441,12 @@ void MackiePort::handle_midi_any (MIDI::Parser &, MIDI::byte * raw_bytes, size_t } state.delta = float( state.ticks ) / float( 0x3f ); - /* - Pots only emit events when they move, not when they - stop moving. So to get a stop event, we need to use a timeout. + /* Pots only emit events when they move, not when they + stop moving. So to get a stop event, we need to use a timeout. */ - // this is set to false ... - control.in_use( true ); - - // ... by this timeout - - // first disconnect any previous timeouts - control.in_use_connection.disconnect(); - - // now connect a new timeout to call handle_control_timeout_event - // XXX should this use the GUI event loop (default) or the - // MIDI UI event loop ? - sigc::slot timeout_slot = sigc::bind - (sigc::mem_fun( *this, &MackiePort::handle_control_timeout_event), &control); - - control.in_use_connection = Glib::signal_timeout().connect (timeout_slot , control.in_use_timeout()); + control.set_in_use (true); + add_in_use_timeout (control, &control); // emit the control event control_event( *this, control, state ); @@ -489,3 +464,4 @@ void MackiePort::handle_midi_any (MIDI::Parser &, MIDI::byte * raw_bytes, size_t DEBUG_TRACE (DEBUG::MackieControl, string_compose ("finished MackiePort::handle_midi_any %1\n", bytes)); } + diff --git a/libs/surfaces/mackie/mackie_port.h b/libs/surfaces/mackie/mackie_port.h index 65dcf850b1..d12de3a099 100644 --- a/libs/surfaces/mackie/mackie_port.h +++ b/libs/surfaces/mackie/mackie_port.h @@ -72,7 +72,7 @@ public: /// Connect the any signal from the parser to handle_midi_any /// unless it's already connected void connect_any(); - + protected: /** The initialisation sequence is fairly complex. First a lock is acquired @@ -107,10 +107,6 @@ protected: */ void probe_emulation( const MidiByteArray & bytes ); - /// Handle timeout events set for controls that don't emit - /// an off event - bool handle_control_timeout_event ( Control * ); - private: MackieControlProtocol & _mcp; port_type_t _port_type; diff --git a/libs/surfaces/mackie/surface_port.cc b/libs/surfaces/mackie/surface_port.cc index e5abb6aa68..3e10fa7b36 100644 --- a/libs/surfaces/mackie/surface_port.cc +++ b/libs/surfaces/mackie/surface_port.cc @@ -178,3 +178,43 @@ ostream & Mackie::operator << ( ostream & os, const SurfacePort & port ) os << " }"; return os; } + +/** Handle timeouts to reset in_use for controls that can't + * do this by themselves (e.g. pots, and faders without touch support). + * @param in_use_control the control whose in_use flag to reset. + * @param touch_control a touch control to emit an event for, or 0. + */ +bool +SurfacePort::control_in_use_timeout (Control* in_use_control, Control* touch_control) +{ + in_use_control->set_in_use (false); + + if (touch_control) { + // empty control_state + ControlState control_state; + control_event (*this, *touch_control, control_state); + } + + // only call this method once from the timer + return false; +} + +/** Add a timeout so that a control's in_use flag will be reset some time in the future. + * @param in_use_control the control whose in_use flag to reset. + * @param touch_control a touch control to emit an event for, or 0. + */ +void +SurfacePort::add_in_use_timeout (Control& in_use_control, Control* touch_control) +{ + in_use_control.in_use_connection.disconnect (); + + /* XXX should this use the GUI event loop (default) or the MIDI UI event loop? */ + + /* timeout after 250ms */ + in_use_control.in_use_connection = Glib::signal_timeout().connect ( + sigc::bind (sigc::mem_fun (*this, &SurfacePort::control_in_use_timeout), &in_use_control, touch_control), + 250 + ); + + in_use_control.in_use_touch_control = touch_control; +} diff --git a/libs/surfaces/mackie/surface_port.h b/libs/surfaces/mackie/surface_port.h index 214c8e6291..fb2d8d0019 100644 --- a/libs/surfaces/mackie/surface_port.h +++ b/libs/surfaces/mackie/surface_port.h @@ -86,12 +86,16 @@ public: virtual bool active() const { return _active; } virtual void active( bool yn ) { _active = yn; } + + void add_in_use_timeout (Control &, Control *); protected: /// Only for use by DummyPort SurfacePort(); private: + bool control_in_use_timeout (Control *, Control *); + MIDI::Port * _input_port; MIDI::Port * _output_port; int _number;