13
0

MCP: start adding different view modes and support for Flip

git-svn-id: svn://localhost/ardour2/branches/3.0@11911 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
Paul Davis 2012-04-11 18:51:01 +00:00
parent 21f038c280
commit 5097af6a13
10 changed files with 280 additions and 169 deletions

View File

@ -20,6 +20,7 @@
#include "fader.h"
#include "surface.h"
#include "control_group.h"
#include "mackie_control_protocol.h"
using namespace Mackie;
@ -44,6 +45,11 @@ Fader::set_position (float normalized)
MidiByteArray
Fader::update_message ()
{
if (MackieControlProtocol::instance()->flip_mode() == MackieControlProtocol::Zero) {
/* do not send messages to move the faders when in this mode */
return MidiByteArray();
}
int posi = int (0x3fff * position);
return MidiByteArray (3, 0xe0 | id(), posi & 0x7f, posi >> 7);
}

View File

@ -99,7 +99,8 @@ MackieControlProtocol::MackieControlProtocol (Session& session)
, _gui (0)
, _zoom_mode (false)
, _scrub_mode (false)
, _flip_mode (false)
, _flip_mode (Normal)
, _view_mode (Global)
, _current_selected_track (-1)
{
DEBUG_TRACE (DEBUG::MackieControl, "MackieControlProtocol::MackieControlProtocol\n");
@ -1058,3 +1059,46 @@ MackieControlProtocol::f_press (uint32_t fn)
access_action (action);
}
}
void
MackieControlProtocol::set_view_mode (ViewMode m)
{
_view_mode = m;
if (surfaces.empty()) {
return;
}
boost::shared_ptr<Surface> surface = surfaces.front();
if (surface->type() != mcu) {
return;
}
switch (_view_mode) {
case Global:
surface->write (surface->two_char_display ("Gl"));
break;
case Dynamics:
surface->write (surface->two_char_display ("Dy"));
break;
case EQ:
surface->write (surface->two_char_display ("EQ"));
break;
case Loop:
surface->write (surface->two_char_display ("LP"));
break;
case AudioTracks:
surface->write (surface->two_char_display ("AT"));
break;
case MidiTracks:
surface->write (surface->two_char_display ("MT"));
break;
case Busses:
surface->write (surface->two_char_display ("Bs"));
break;
case Sends:
surface->write (surface->two_char_display ("Sn"));
break;
}
}

View File

@ -88,6 +88,24 @@ class MackieControlProtocol
static const int MODIFIER_SHIFT;
static const int MODIFIER_CMDALT;
enum ViewMode {
Global,
Dynamics,
EQ,
Loop,
AudioTracks,
MidiTracks,
Busses,
Sends,
};
enum FlipMode {
Normal,
Mirror,
Swap,
Zero,
};
MackieControlProtocol(ARDOUR::Session &);
virtual ~MackieControlProtocol();
@ -95,6 +113,11 @@ class MackieControlProtocol
int set_active (bool yn);
FlipMode flip_mode () const { return _flip_mode; }
ViewMode view_mode () const { return _view_mode; }
void set_view_mode (ViewMode);
XMLNode& get_state ();
int set_state (const XMLNode&, int version);
@ -140,6 +163,126 @@ class MackieControlProtocol
void update_global_button(const std::string & name, Mackie::LedState);
void update_global_led(const std::string & name, Mackie::LedState);
ARDOUR::Session & get_session() { return *session; }
void add_in_use_timeout (Mackie::Surface& surface, Mackie::Control& in_use_control, Mackie::Control* touch_control);
int modifier_state() const { return _modifier_state; }
protected:
// shut down the surface
void close();
// This sets up the notifications and sets the
// controls to the correct values
void update_surfaces();
// connects global (not strip) signals from the Session to here
// so the surface can be notified of changes from the other UIs.
void connect_session_signals();
// set all controls to their zero position
void zero_all();
/**
Fetch the set of routes to be considered for control by the
surface. Excluding master, hidden and control routes, and inactive routes
*/
typedef std::vector<boost::shared_ptr<ARDOUR::Route> > Sorted;
Sorted get_sorted_routes();
// bank switching
void switch_banks (uint32_t first_remote_id, bool force = false);
void prev_track ();
void next_track ();
// also called from poll_automation to update timecode display
void update_timecode_display();
std::string format_bbt_timecode (ARDOUR::framepos_t now_frame);
std::string format_timecode_timecode (ARDOUR::framepos_t now_frame);
void do_request (MackieControlUIRequest*);
int stop ();
void thread_init ();
/* handling function key presses */
std::string f_action (uint32_t fn);
void f_press (uint32_t fn);
private:
static MackieControlProtocol* _instance;
void create_surfaces ();
void port_connected_or_disconnected (std::string, std::string, bool);
bool control_in_use_timeout (Mackie::Surface*, Mackie::Control *, Mackie::Control *);
bool periodic();
sigc::connection periodic_connection;
/// The initial remote_id of the currently switched in bank.
uint32_t _current_initial_bank;
/// protects the port list
Glib::Mutex update_mutex;
PBD::ScopedConnectionList audio_engine_connections;
PBD::ScopedConnectionList session_connections;
PBD::ScopedConnectionList port_connections;
PBD::ScopedConnectionList route_connections;
bool _transport_previously_rolling;
// timer for two quick marker left presses
Mackie::Timer _frm_left_last;
// last written timecode string
std::string _timecode_last;
// Which timecode are we displaying? BBT or Timecode
ARDOUR::AnyTime::Type _timecode_type;
// Bundle to represent our input ports
boost::shared_ptr<ARDOUR::Bundle> _input_bundle;
// Bundle to represent our output ports
boost::shared_ptr<ARDOUR::Bundle> _output_bundle;
void build_gui ();
void* _gui;
bool _zoom_mode;
bool _scrub_mode;
FlipMode _flip_mode;
ViewMode _view_mode;
int _current_selected_track;
int _modifier_state;
typedef std::list<GSource*> PortSources;
PortSources port_sources;
bool midi_input_handler (Glib::IOCondition ioc, MIDI::Port* port);
void clear_ports ();
struct ButtonHandlers {
Mackie::LedState (MackieControlProtocol::*press) (Mackie::Button&);
Mackie::LedState (MackieControlProtocol::*release) (Mackie::Button&);
ButtonHandlers (Mackie::LedState (MackieControlProtocol::*p) (Mackie::Button&),
Mackie::LedState (MackieControlProtocol::*r) (Mackie::Button&))
: press (p)
, release (r) {}
};
typedef std::map<int,ButtonHandlers> ButtonMap;
ButtonMap button_map;
void build_button_map ();
std::vector<std::string> _f_actions;
/* implemented button handlers */
Mackie::LedState frm_left_press(Mackie::Button &);
Mackie::LedState frm_left_release(Mackie::Button &);
@ -280,125 +423,6 @@ class MackieControlProtocol
Mackie::LedState user_b_release (Mackie::Button &);
Mackie::LedState fader_touch_press (Mackie::Button &);
Mackie::LedState fader_touch_release (Mackie::Button &);
ARDOUR::Session & get_session() { return *session; }
void add_in_use_timeout (Mackie::Surface& surface, Mackie::Control& in_use_control, Mackie::Control* touch_control);
int modifier_state() const { return _modifier_state; }
protected:
// shut down the surface
void close();
// This sets up the notifications and sets the
// controls to the correct values
void update_surfaces();
// connects global (not strip) signals from the Session to here
// so the surface can be notified of changes from the other UIs.
void connect_session_signals();
// set all controls to their zero position
void zero_all();
/**
Fetch the set of routes to be considered for control by the
surface. Excluding master, hidden and control routes, and inactive routes
*/
typedef std::vector<boost::shared_ptr<ARDOUR::Route> > Sorted;
Sorted get_sorted_routes();
// bank switching
void switch_banks (uint32_t first_remote_id, bool force = false);
void prev_track ();
void next_track ();
// also called from poll_automation to update timecode display
void update_timecode_display();
std::string format_bbt_timecode (ARDOUR::framepos_t now_frame);
std::string format_timecode_timecode (ARDOUR::framepos_t now_frame);
void do_request (MackieControlUIRequest*);
int stop ();
void thread_init ();
/* handling function key presses */
std::string f_action (uint32_t fn);
void f_press (uint32_t fn);
private:
static MackieControlProtocol* _instance;
void create_surfaces ();
void port_connected_or_disconnected (std::string, std::string, bool);
bool control_in_use_timeout (Mackie::Surface*, Mackie::Control *, Mackie::Control *);
bool periodic();
sigc::connection periodic_connection;
/// The initial remote_id of the currently switched in bank.
uint32_t _current_initial_bank;
/// protects the port list
Glib::Mutex update_mutex;
PBD::ScopedConnectionList audio_engine_connections;
PBD::ScopedConnectionList session_connections;
PBD::ScopedConnectionList port_connections;
PBD::ScopedConnectionList route_connections;
bool _transport_previously_rolling;
// timer for two quick marker left presses
Mackie::Timer _frm_left_last;
// last written timecode string
std::string _timecode_last;
// Which timecode are we displaying? BBT or Timecode
ARDOUR::AnyTime::Type _timecode_type;
// Bundle to represent our input ports
boost::shared_ptr<ARDOUR::Bundle> _input_bundle;
// Bundle to represent our output ports
boost::shared_ptr<ARDOUR::Bundle> _output_bundle;
void build_gui ();
void* _gui;
bool _zoom_mode;
bool _scrub_mode;
bool _flip_mode;
int _current_selected_track;
int _modifier_state;
typedef std::list<GSource*> PortSources;
PortSources port_sources;
bool midi_input_handler (Glib::IOCondition ioc, MIDI::Port* port);
void clear_ports ();
struct ButtonHandlers {
Mackie::LedState (MackieControlProtocol::*press) (Mackie::Button&);
Mackie::LedState (MackieControlProtocol::*release) (Mackie::Button&);
ButtonHandlers (Mackie::LedState (MackieControlProtocol::*p) (Mackie::Button&),
Mackie::LedState (MackieControlProtocol::*r) (Mackie::Button&))
: press (p)
, release (r) {}
};
typedef std::map<int,ButtonHandlers> ButtonMap;
ButtonMap button_map;
void build_button_map ();
std::vector<std::string> _f_actions;
};

View File

@ -45,28 +45,33 @@ void JogWheel::scroll_event (SurfacePort &, Control &, const ControlState &)
{
}
void JogWheel::jog_event (SurfacePort &, Control &, const ControlState & state)
void JogWheel::jog_event (SurfacePort &, Control &, float delta)
{
// TODO use current snap-to setting?
switch (jog_wheel_state())
{
case scroll:
_mcp.ScrollTimeline (state.delta * state.sign);
_mcp.ScrollTimeline (delta);
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();
if (delta > 0) {
for (unsigned int i = 0; i < fabs (delta); ++i) {
_mcp.ZoomIn();
}
} else {
for (unsigned int i = 0; i < fabs (delta); ++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());
_transport_speed += _mcp.surfaces.front()->scaled_delta (delta, _mcp.get_session().transport_speed());
// make sure no weirdness gets to the session
if (_transport_speed < 0 || isnan (_transport_speed))
@ -80,12 +85,11 @@ void JogWheel::jog_event (SurfacePort &, Control &, const ControlState & state)
case scrub:
{
if (state.sign != 0)
{
if (delta != 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);
float speed = _mcp.surfaces.front()->scrub_scaling_factor() / average_scrub_interval() * delta;
_mcp.get_session().request_transport_speed_nonzero (speed);
}
else
{
@ -97,7 +101,7 @@ void JogWheel::jog_event (SurfacePort &, Control &, const ControlState & state)
case shuttle:
_shuttle_speed = _mcp.get_session().transport_speed();
_shuttle_speed += _mcp.surfaces.front()->scaled_delta (state, _mcp.get_session().transport_speed());
_shuttle_speed += _mcp.surfaces.front()->scaled_delta (delta, _mcp.get_session().transport_speed());
_mcp.get_session().request_transport_speed_nonzero (_shuttle_speed);
break;

View File

@ -31,17 +31,17 @@ class JogWheel
public:
enum State { scroll, zoom, speed, scrub, shuttle, select };
JogWheel( MackieControlProtocol & mcp );
JogWheel (MackieControlProtocol & mcp);
/// As the wheel turns...
void jog_event( SurfacePort & port, Control & control, const ControlState & state );
void jog_event (SurfacePort & port, Control & control, float delta);
// These are for incoming button presses that change the internal state
// but they're not actually used at the moment.
void zoom_event( SurfacePort & port, Control & control, const ControlState & state );
void scrub_event( SurfacePort & port, Control & control, const ControlState & state );
void speed_event( SurfacePort & port, Control & control, const ControlState & state );
void scroll_event( SurfacePort & port, Control & control, const ControlState & state );
void zoom_event (SurfacePort & port, Control & control, const ControlState & state);
void scrub_event (SurfacePort & port, Control & control, const ControlState & state);
void speed_event (SurfacePort & port, Control & control, const ControlState & state);
void scroll_event (SurfacePort & port, Control & control, const ControlState & state);
/// Return the current jog wheel mode, which defaults to Scroll
State jog_wheel_state() const;
@ -52,9 +52,9 @@ public:
/// one of -1,0,1
int transport_direction() const { return _transport_direction; }
void transport_direction( int rhs ) { _transport_direction = rhs; }
void transport_direction (int rhs) { _transport_direction = rhs; }
void push( State state );
void push (State state);
void pop();
/// Turn zoom mode on and off
@ -72,7 +72,7 @@ public:
void check_scrubbing();
protected:
void add_scrub_interval( unsigned long elapsed );
void add_scrub_interval (unsigned long elapsed);
float average_scrub_interval();
float std_dev_scrub_interval();

View File

@ -530,8 +530,13 @@ MackieControlProtocol::ffwd_release (Button &)
LedState
MackieControlProtocol::loop_press (Button &)
{
session->request_play_loop (!session->get_play_loop());
return none;
if (_modifier_state & MODIFIER_CONTROL) {
set_view_mode (Loop);
return on;
} else {
session->request_play_loop (!session->get_play_loop());
return none;
}
}
LedState
@ -736,12 +741,13 @@ MackieControlProtocol::io_release (Button &)
LedState
MackieControlProtocol::sends_press (Button &)
{
return off;
set_view_mode (Sends);
return on;
}
LedState
MackieControlProtocol::sends_release (Button &)
{
return off;
return none;
}
LedState
MackieControlProtocol::pan_press (Button &)
@ -766,33 +772,44 @@ MackieControlProtocol::plugin_release (Button &)
LedState
MackieControlProtocol::eq_press (Button &)
{
return off;
set_view_mode (EQ);
return on;
}
LedState
MackieControlProtocol::eq_release (Button &)
{
return off;
return none;
}
LedState
MackieControlProtocol::dyn_press (Button &)
{
return off;
set_view_mode (Dynamics);
return on;
}
LedState
MackieControlProtocol::dyn_release (Button &)
{
return off;
return none;
}
LedState
MackieControlProtocol::flip_press (Button &)
{
_flip_mode = !_flip_mode;
return (_flip_mode ? on : off);
if (_modifier_state == 0) {
if (_flip_mode != Normal) {
_flip_mode = Normal;
} else {
_flip_mode = Swap;
}
} else if (_modifier_state & MODIFIER_CONTROL) {
_flip_mode = Zero;
}
return (_flip_mode != Normal ? on : off);
}
LedState
MackieControlProtocol::flip_release (Button &)
{
return (_flip_mode ? on : off);
return none;
}
LedState
MackieControlProtocol::edit_press (Button &)

View File

@ -498,6 +498,20 @@ Strip::handle_fader (Fader& fader, float position)
{
DEBUG_TRACE (DEBUG::MackieControl, string_compose ("fader to %1\n", position));
switch (_surface->mcp().flip_mode()) {
case MackieControlProtocol::Normal:
break;
case MackieControlProtocol::Zero:
break;
case MackieControlProtocol::Mirror:
break;
case MackieControlProtocol::Swap:
if (_vpot) {
handle_pot (*_vpot, 1.0);
}
return;
}
if (_route) {
_route->gain_control()->set_value (slider_position_to_gain (position));
}
@ -515,7 +529,7 @@ Strip::handle_fader (Fader& fader, float position)
}
void
Strip::handle_pot (Pot& pot, ControlState& state)
Strip::handle_pot (Pot& pot, float delta)
{
if (!_route) {
_surface->write (pot.set_onoff (false));
@ -536,7 +550,7 @@ Strip::handle_pot (Pot& pot, ControlState& state)
double p = ac->get_value();
// calculate new value, and adjust
p += state.delta * state.sign;
p += delta;
p = min (1.0, p);
p = max (0.0, p);

View File

@ -79,7 +79,7 @@ public:
void handle_button (Button&, ButtonState bs);
void handle_fader (Fader&, float position);
void handle_pot (Pot&, ControlState&);
void handle_pot (Pot&, float delta);
void periodic ();

View File

@ -259,9 +259,10 @@ Surface::init_strips ()
}
float
Surface::scaled_delta (const ControlState & state, float current_speed)
Surface::scaled_delta (float delta, float current_speed)
{
return state.sign * (std::pow (float(state.ticks + 1), 2) + current_speed) / 100.0;
/* XXX needs work before use */
return (std::pow (float(delta + 1), 2) + current_speed) / 100.0;
}
void
@ -396,35 +397,36 @@ Surface::handle_midi_controller_message (MIDI::Parser &, MIDI::EventTwoBytes* ev
if (pot) {
ControlState state;
// bytes[2] & 0b01000000 (0x40) give sign
state.sign = (ev->value & 0x40) == 0 ? 1 : -1;
// bytes[2] & 0b00111111 (0x3f) gives delta
state.ticks = (ev->value & 0x3f);
if (state.ticks == 0) {
// bit 6 gives the sign
float sign = (ev->value & 0x40) == 0 ? 1.0 : -1.0;
// bits 0..3 give the velocity. we interpret this as "ticks
// moved before this message was sent"
float ticks = (ev->value & 0xf);
if (ticks == 0) {
/* euphonix and perhaps other devices send zero
when they mean 1, we think.
*/
state.ticks = 1;
ticks = 1;
}
state.delta = float (state.ticks) / float (0x3f);
float delta = sign * (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.
*/
_mcp.add_in_use_timeout (*this, *pot, pot);
Strip* strip = dynamic_cast<Strip*> (&pot->group());
if (strip) {
strip->handle_pot (*pot, state);
strip->handle_pot (*pot, delta);
} else {
JogWheel* wheel = dynamic_cast<JogWheel*> (pot);
if (wheel) {
DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Jog wheel moved %1\n", state.ticks));
wheel->jog_event (*_port, *pot, state);
wheel->jog_event (*_port, *pot, delta);
} else {
DEBUG_TRACE (DEBUG::MackieControl, string_compose ("External controller moved %1\n", state.ticks));
cout << "external controller" << state.ticks * state.sign << endl;
cout << "external controller" << delta << endl;
}
}
} else {

View File

@ -126,7 +126,7 @@ public:
high definition control at low speeds and quick speed changes to/from
higher speeds.
*/
float scaled_delta (const ControlState & state, float current_speed);
float scaled_delta (float delta, float current_speed);
// display the first 2 chars of the msg in the 2 char display
// . is appended to the previous character, so A.B. would