13
0
livetrax/libs/surfaces/mackie/mackie_jog_wheel.cc

197 lines
4.3 KiB
C++

#include <cmath>
#include "ardour/session.h"
#include "mackie_jog_wheel.h"
#include "mackie_control_protocol.h"
#include "surface_port.h"
#include "controls.h"
#include "surface.h"
#include <algorithm>
using namespace Mackie;
using std::isnan;
JogWheel::JogWheel( MackieControlProtocol & mcp )
: _mcp( mcp )
, _transport_speed( 4.0 )
, _transport_direction( 0 )
, _shuttle_speed( 0.0 )
{
}
JogWheel::State JogWheel::jog_wheel_state() const
{
if ( !_jog_wheel_states.empty() )
return _jog_wheel_states.top();
else
return scroll;
}
void JogWheel::zoom_event (SurfacePort &, Control &, const ControlState &)
{
}
void JogWheel::scrub_event (SurfacePort &, Control &, const ControlState &)
{
}
void JogWheel::speed_event (SurfacePort &, Control &, const ControlState &)
{
}
void JogWheel::scroll_event (SurfacePort &, Control &, const ControlState &)
{
}
void JogWheel::jog_event (SurfacePort &, Control &, const ControlState & state)
{
// TODO use current snap-to setting?
switch ( jog_wheel_state() )
{
case scroll:
_mcp.ScrollTimeline( state.delta * state.sign );
break;
case zoom:
// Chunky Zoom.
// TODO implement something similar to ScrollTimeline which
// ends up in Editor::control_scroll for smoother zooming.
if ( state.sign > 0 )
for ( unsigned int i = 0; i < state.ticks; ++i ) _mcp.ZoomIn();
else
for ( unsigned int i = 0; i < state.ticks; ++i ) _mcp.ZoomOut();
break;
case speed:
// locally, _transport_speed is an positive value
_transport_speed += _mcp.surface().scaled_delta( state, _mcp.get_session().transport_speed() );
// make sure no weirdness gets to the session
if ( _transport_speed < 0 || isnan( _transport_speed ) )
{
_transport_speed = 0.0;
}
// translate _transport_speed speed to a signed transport velocity
_mcp.get_session().request_transport_speed_nonzero (transport_speed() * transport_direction());
break;
case scrub:
{
if ( state.sign != 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_nonzero (speed * state.sign);
}
else
{
// we have a stop event
check_scrubbing();
}
break;
}
case shuttle:
_shuttle_speed = _mcp.get_session().transport_speed();
_shuttle_speed += _mcp.surface().scaled_delta( state, _mcp.get_session().transport_speed() );
_mcp.get_session().request_transport_speed_nonzero (_shuttle_speed);
break;
case select:
std::cout << "JogWheel select not implemented" << std::endl;
break;
}
}
void JogWheel::check_scrubbing()
{
// if the last elapsed is greater than the average + std deviation, then stop
if ( !_scrub_intervals.empty() && _scrub_timer.elapsed() > average_scrub_interval() + std_dev_scrub_interval() )
{
_mcp.get_session().request_transport_speed( 0.0 );
_scrub_intervals.clear();
}
}
void JogWheel::push( State state )
{
_jog_wheel_states.push( state );
}
void JogWheel::pop()
{
if ( _jog_wheel_states.size() > 0 )
{
_jog_wheel_states.pop();
}
}
void JogWheel::zoom_state_toggle()
{
if ( jog_wheel_state() == zoom )
pop();
else
push( zoom );
}
JogWheel::State JogWheel::scrub_state_cycle()
{
State top = jog_wheel_state();
if ( top == scrub )
{
// stop scrubbing and go to shuttle
pop();
push( shuttle );
_shuttle_speed = 0.0;
}
else if ( top == shuttle )
{
// default to scroll, or the last selected
pop();
}
else
{
// start with scrub
push( scrub );
}
return jog_wheel_state();
}
void JogWheel::add_scrub_interval( unsigned long elapsed )
{
if ( _scrub_intervals.size() > 5 )
{
_scrub_intervals.pop_front();
}
_scrub_intervals.push_back( elapsed );
}
float JogWheel::average_scrub_interval()
{
float sum = 0.0;
for ( std::deque<unsigned long>::iterator it = _scrub_intervals.begin(); it != _scrub_intervals.end(); ++it )
{
sum += *it;
}
return sum / _scrub_intervals.size();
}
float JogWheel::std_dev_scrub_interval()
{
float average = average_scrub_interval();
// calculate standard deviation
float sum = 0.0;
for ( std::deque<unsigned long>::iterator it = _scrub_intervals.begin(); it != _scrub_intervals.end(); ++it )
{
sum += pow( *it - average, 2 );
}
return sqrt( sum / _scrub_intervals.size() -1 );
}