mirror of
https://github.com/Ardour/ardour.git
synced 2026-01-03 04:09:29 +01:00
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:
parent
0259d68259
commit
2def7ef1ab
10 changed files with 110 additions and 32 deletions
|
|
@ -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?
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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() ) ) );
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 )
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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) {}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue