13
0
livetrax/libs/surfaces/mackie/mackie_jog_wheel.cc
Paul Davis 02c8ccf348 move all code to construct MIDI messages into relevant Control/Strip/Surface object; remove MackieMidiBuilder
git-svn-id: svn://localhost/ardour2/branches/3.0@11895 d708f5d6-7413-0410-9779-e7cbd77b26cf
2012-04-11 13:03:41 +00:00

196 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.surfaces.front()->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.surfaces.front()->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.surfaces.front()->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);
}