Add Control::in_use. Add a timeout-generated stop event to Pot.

git-svn-id: svn://localhost/ardour2/branches/2.0-ongoing@2197 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
John Anderson 2007-07-31 10:52:23 +00:00
parent 0259d68259
commit 2def7ef1ab
10 changed files with 110 additions and 32 deletions

View file

@ -1,8 +1,7 @@
* if mackie wheel moves too fast, it's ignored.
* active (pressed?) state for controls, including timeout
* update manual with jog wheel states
* alsa/sequencer ports unstable. possibly problems with use of ::poll
* use glib::timeout for check_scrubbing
* use glib::Timer instead of mine
* crash when mmc port set to mcu?
* remappable buttons
* how long can UI signal callbacks take to execute? What happens if they block?
@ -19,6 +18,7 @@ Later
-----
* remove commented couts
* Perhaps MackieControlProtocol shouldn't implement MackieButtonHandler
* Need a HostAdapter class to encapsulate ardour calls
* talk to route plugins
* check for excessiveness (ie too many events making other subsystems work too hard)
* Queueing of writes?

View file

@ -45,6 +45,15 @@ Strip::Strip( const std::string & name, int index )
{
}
Control::Control( int id, int ordinal, std::string name, Group & group )
: _id( id )
, _ordinal( ordinal )
, _name( name )
, _group( group )
, _in_use_timeout( 250 )
{
}
/**
generated with
@ -108,6 +117,17 @@ Button & Strip::fader_touch()
return *_fader_touch;
}
bool Control::in_use() const
{
return _in_use;
}
Control & Control::in_use( bool rhs )
{
_in_use = rhs;
return *this;
}
ostream & Mackie::operator << ( ostream & os, const Mackie::Control & control )
{
os << typeid( control ).name();

View file

@ -18,6 +18,8 @@
#ifndef mackie_controls_h
#define mackie_controls_h
#include <sigc++/sigc++.h>
#include <map>
#include <vector>
#include <string>
@ -157,11 +159,7 @@ class Control
public:
enum type_t { type_led, type_led_ring, type_fader = 0xe0, type_button = 0x90, type_pot = 0xb0 };
Control( int id, int ordinal, std::string name, Group & group )
: _id( id ), _ordinal( ordinal ), _name( name ), _group( group )
{
}
Control( int id, int ordinal, std::string name, Group & group );
virtual ~Control() {}
virtual const Led & led() const
@ -215,11 +213,29 @@ public:
/// Jog Wheel
virtual bool is_jog() const { return false; }
/**
Return true if the controlis 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 );
/// 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;
private:
int _id;
int _ordinal;
std::string _name;
Group & _group;
bool _in_use;
unsigned int _in_use_timeout;
};
std::ostream & operator << ( std::ostream & os, const Control & control );
@ -229,18 +245,10 @@ class Fader : public Control
public:
Fader( int id, int ordinal, std::string name, Group & group )
: Control( id, ordinal, name, group )
, _touch( false )
{
}
bool touch() const { return _touch; }
void touch( bool yn ) { _touch = yn; }
virtual type_t type() const { return type_fader; }
private:
bool _touch;
};
class Led : public Control
@ -272,12 +280,8 @@ public:
virtual type_t type() const { return type_button; };
bool pressed() const { return _pressed; }
Button & pressed( bool rhs ) { _pressed = rhs; return *this; }
private:
Led _led;
bool _pressed;
};
class LedRing : public Led

View file

@ -478,7 +478,7 @@ bool MackieControlProtocol::handle_strip_button( Control & control, ButtonState
if ( control.name() == "fader_touch" )
{
state = bs == press;
control.strip().gain().touch( state );
control.strip().gain().in_use( state );
}
return state;
@ -831,6 +831,7 @@ void MackieControlProtocol::handle_control_event( SurfacePort & port, Control &
switch ( control.type() )
{
case Control::type_fader:
// TODO this seems to be a duplicate of the above if
if ( control.group().is_strip() )
{
// find the route in the route table for the id
@ -984,7 +985,7 @@ void MackieControlProtocol::notify_gain_changed( RouteSignal * route_signal )
try
{
Fader & fader = route_signal->strip().gain();
if ( !fader.touch() )
if ( !fader.in_use() )
{
route_signal->port().write( builder.build_fader( fader, gain_to_slider_position( route_signal->route().effective_gain() ) ) );
}

View file

@ -64,9 +64,6 @@ void * MackieControlProtocol::monitor_work()
}
// poll for automation data from the routes
poll_automation();
// check if we need to stop scrubbing
_jog_wheel.check_scrubbing();
}
catch ( exception & e )
{

View file

@ -76,10 +76,18 @@ void JogWheel::jog_event( SurfacePort & port, Control & control, const ControlSt
case scrub:
{
add_scrub_interval( _scrub_timer.restart() );
// x clicks per second => speed == 1.0
float speed = _mcp.surface().scrub_scaling_factor() / average_scrub_interval() * state.ticks;
_mcp.get_session().request_transport_speed( speed * state.sign );
if ( state.delta != 0.0 )
{
add_scrub_interval( _scrub_timer.restart() );
// x clicks per second => speed == 1.0
float speed = _mcp.surface().scrub_scaling_factor() / average_scrub_interval() * state.ticks;
_mcp.get_session().request_transport_speed( speed * state.sign );
}
else
{
// we have a stop event
check_scrubbing();
}
break;
}

View file

@ -79,7 +79,7 @@ protected:
private:
MackieControlProtocol & _mcp;
// transport speed for ffwd and rew, controller by jog
/// transport speed for ffwd and rew, controller by jog
float _transport_speed;
int _transport_direction;

View file

@ -23,6 +23,8 @@
#include "controls.h"
#include "surface.h"
#include <glibmm/main.h>
#include <midi++/types.h>
#include <midi++/port.h>
#include <sigc++/sigc++.h>
@ -378,6 +380,17 @@ 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.
@ -402,6 +415,7 @@ void MackiePort::handle_midi_any (MIDI::Parser & parser, MIDI::byte * raw_bytes,
}
Control & control = lookup_control( raw_bytes, count );
control.in_use( true );
// This handles incoming bytes. Outgoing bytes
// are sent by the signal handlers.
@ -412,6 +426,9 @@ void MackiePort::handle_midi_any (MIDI::Parser & parser, MIDI::byte * raw_bytes,
{
// only the top-order 10 bits out of 14 are used
int midi_pos = ( ( raw_bytes[2] << 7 ) + raw_bytes[1] ) >> 4;
// in_use is set by the MackieControlProtocol::handle_strip_button
// relies on implicit ControlState constructor
control_event( *this, control, float(midi_pos) / float(0x3ff) );
}
@ -419,9 +436,13 @@ void MackiePort::handle_midi_any (MIDI::Parser & parser, MIDI::byte * raw_bytes,
// button
case Control::type_button:
// relies on implicit ControlState constructor
control_event( *this, control, raw_bytes[2] == 0x7f ? press : release );
{
ControlState control_state( raw_bytes[2] == 0x7f ? press : release );
control.in_use( control_state.button_state == press );
control_event( *this, control, control_state );
break;
}
// pot (jog wheel, external control)
case Control::type_pot:
@ -434,6 +455,29 @@ void MackiePort::handle_midi_any (MIDI::Parser & parser, MIDI::byte * raw_bytes,
state.ticks = ( raw_bytes[2] & 0x3f);
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.
*/
// 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
sigc::slot<bool> timeout_slot = sigc::bind(
mem_fun( *this, &MackiePort::handle_control_timeout_event )
, &control
);
control.in_use_connection = Glib::signal_timeout().connect(
timeout_slot
, control.in_use_timeout()
);
// emit the control event
control_event( *this, control, state );
break;
}

View file

@ -109,6 +109,10 @@ 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

@ -64,7 +64,7 @@ enum ButtonState { neither = -1, release = 0, press = 1 };
*/
struct ControlState
{
ControlState(): pos(0.0), delta(0.0), button_state(neither) {}
ControlState(): pos(0.0), sign(0), delta(0.0), ticks(0), led_state(off), button_state(neither) {}
ControlState( LedState ls ): pos(0.0), delta(0.0), led_state(ls), button_state(neither) {}