From 5097af6a13828adf9f1bb87bd8bd8557963c0d7e Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Wed, 11 Apr 2012 18:51:01 +0000 Subject: [PATCH] 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 --- libs/surfaces/mackie/fader.cc | 6 + .../mackie/mackie_control_protocol.cc | 46 ++- .../surfaces/mackie/mackie_control_protocol.h | 262 ++++++++++-------- libs/surfaces/mackie/mackie_jog_wheel.cc | 28 +- libs/surfaces/mackie/mackie_jog_wheel.h | 18 +- libs/surfaces/mackie/mcp_buttons.cc | 39 ++- libs/surfaces/mackie/strip.cc | 18 +- libs/surfaces/mackie/strip.h | 2 +- libs/surfaces/mackie/surface.cc | 28 +- libs/surfaces/mackie/surface.h | 2 +- 10 files changed, 280 insertions(+), 169 deletions(-) diff --git a/libs/surfaces/mackie/fader.cc b/libs/surfaces/mackie/fader.cc index bcb8f73ca6..a55c23c129 100644 --- a/libs/surfaces/mackie/fader.cc +++ b/libs/surfaces/mackie/fader.cc @@ -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); } diff --git a/libs/surfaces/mackie/mackie_control_protocol.cc b/libs/surfaces/mackie/mackie_control_protocol.cc index f85d153e5a..6ad63df9a7 100644 --- a/libs/surfaces/mackie/mackie_control_protocol.cc +++ b/libs/surfaces/mackie/mackie_control_protocol.cc @@ -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 = 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; + } +} diff --git a/libs/surfaces/mackie/mackie_control_protocol.h b/libs/surfaces/mackie/mackie_control_protocol.h index 82096d0997..2da47821d6 100644 --- a/libs/surfaces/mackie/mackie_control_protocol.h +++ b/libs/surfaces/mackie/mackie_control_protocol.h @@ -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 > 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 _input_bundle; + // Bundle to represent our output ports + boost::shared_ptr _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 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 ButtonMap; + ButtonMap button_map; + + void build_button_map (); + + std::vector _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 > 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 _input_bundle; - // Bundle to represent our output ports - boost::shared_ptr _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 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 ButtonMap; - ButtonMap button_map; - - void build_button_map (); - - std::vector _f_actions; }; diff --git a/libs/surfaces/mackie/mackie_jog_wheel.cc b/libs/surfaces/mackie/mackie_jog_wheel.cc index 917dd426e0..3ff3298627 100644 --- a/libs/surfaces/mackie/mackie_jog_wheel.cc +++ b/libs/surfaces/mackie/mackie_jog_wheel.cc @@ -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; diff --git a/libs/surfaces/mackie/mackie_jog_wheel.h b/libs/surfaces/mackie/mackie_jog_wheel.h index 83a4364393..7a3e016cff 100644 --- a/libs/surfaces/mackie/mackie_jog_wheel.h +++ b/libs/surfaces/mackie/mackie_jog_wheel.h @@ -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(); diff --git a/libs/surfaces/mackie/mcp_buttons.cc b/libs/surfaces/mackie/mcp_buttons.cc index 37035353bc..6b6ce6528e 100644 --- a/libs/surfaces/mackie/mcp_buttons.cc +++ b/libs/surfaces/mackie/mcp_buttons.cc @@ -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 &) diff --git a/libs/surfaces/mackie/strip.cc b/libs/surfaces/mackie/strip.cc index d7a7a9946d..d924825bc7 100644 --- a/libs/surfaces/mackie/strip.cc +++ b/libs/surfaces/mackie/strip.cc @@ -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); diff --git a/libs/surfaces/mackie/strip.h b/libs/surfaces/mackie/strip.h index 4a96fdcf39..cb2fe67d51 100644 --- a/libs/surfaces/mackie/strip.h +++ b/libs/surfaces/mackie/strip.h @@ -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 (); diff --git a/libs/surfaces/mackie/surface.cc b/libs/surfaces/mackie/surface.cc index 0dab9d87ad..97afee5c51 100644 --- a/libs/surfaces/mackie/surface.cc +++ b/libs/surfaces/mackie/surface.cc @@ -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 (&pot->group()); if (strip) { - strip->handle_pot (*pot, state); + strip->handle_pot (*pot, delta); } else { JogWheel* wheel = dynamic_cast (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 { diff --git a/libs/surfaces/mackie/surface.h b/libs/surfaces/mackie/surface.h index 186f600d9f..d88f37e5c6 100644 --- a/libs/surfaces/mackie/surface.h +++ b/libs/surfaces/mackie/surface.h @@ -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