13
0

Use a timeout to reset faders' in_use flags when in BCF mode (ie with faders that don't support touch).

git-svn-id: svn://localhost/ardour2/branches/3.0@9469 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
Carl Hetherington 2011-05-04 09:22:32 +00:00
parent f01dc1bfd5
commit 91d512174e
8 changed files with 87 additions and 59 deletions

View File

@ -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 )

View File

@ -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 );

View File

@ -397,7 +397,7 @@ MackieControlProtocol::set_active (bool yn)
}
bool
MackieControlProtocol::handle_strip_button (Control & control, ButtonState bs, boost::shared_ptr<Route> route)
MackieControlProtocol::handle_strip_button (SurfacePort & port, Control & control, ButtonState bs, boost::shared_ptr<Route> 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

View File

@ -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<ARDOUR::Route>);
bool handle_strip_button (Mackie::SurfacePort &, Mackie::Control &, Mackie::ButtonState, boost::shared_ptr<ARDOUR::Route>);
void add_port (MIDI::Port &, MIDI::Port &, int number);

View File

@ -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<bool> 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));
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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;