From 0310f8997147cc50600a98f05ef1a6c486e688c7 Mon Sep 17 00:00:00 2001 From: Robin Gareus Date: Sun, 2 Jul 2017 18:16:54 +0200 Subject: FP8: Implement "Control-Link" --- libs/surfaces/faderport8/actions.cc | 139 ++++++++++++++++++++++++--------- libs/surfaces/faderport8/callbacks.cc | 16 ++++ libs/surfaces/faderport8/faderport8.cc | 75 ++++++++++++++++++ libs/surfaces/faderport8/faderport8.h | 19 +++++ 4 files changed, 213 insertions(+), 36 deletions(-) (limited to 'libs/surfaces') diff --git a/libs/surfaces/faderport8/actions.cc b/libs/surfaces/faderport8/actions.cc index f0a3289b10..212ecb14ba 100644 --- a/libs/surfaces/faderport8/actions.cc +++ b/libs/surfaces/faderport8/actions.cc @@ -99,10 +99,10 @@ FaderPort8::setup_actions () BindAction (BtnBypassAll, "Mixer", "ab-plugins"); BindAction (BtnMacro, "Mixer", "show-editor"); - BindAction (BtnLink, "Window", "show-mixer"); - BindMethod (BtnOpen, button_open); - BindAction (BtnLock, "Editor", "lock"); + + BindMethod (BtnLink, button_link); + BindMethod (BtnLock, button_lock); // user-specific for (FP8Controls::UserButtonMap::const_iterator i = _ctrls.user_buttons ().begin (); @@ -178,6 +178,37 @@ FaderPort8::button_open () AccessAction ("Common", "addExistingAudioFiles"); } } +void +FaderPort8::button_lock () +{ + if (!_link_enabled) { + AccessAction ("Editor", "lock"); + return; + } + if (_link_locked) { + unlock_link (); + } else if (!_link_control.expired ()) { + lock_link (); + } +} + +void +FaderPort8::button_link () +{ + switch (_ctrls.fader_mode()) { + case ModeTrack: + case ModePan: + if (_link_enabled) { + stop_link (); + } else { + start_link (); + } + break; + default: + //AccessAction ("Window", "show-mixer"); + break; + } +} void FaderPort8::button_automation (ARDOUR::AutoState as) @@ -348,6 +379,66 @@ FaderPort8::button_action (const std::string& group, const std::string& item) AccessAction (group, item); } +/* **************************************************************************** + * Control Interaction (encoder) + */ + +void +FaderPort8::handle_encoder_pan (int steps) +{ + boost::shared_ptr s = first_selected_stripable(); + if (s) { + boost::shared_ptr ac; + if (shift_mod () || _ctrls.fader_mode() == ModePan) { + ac = s->pan_width_control (); + } else { + ac = s->pan_azimuth_control (); + } + if (ac) { + if (ac->automation_state() == Touch && !ac->touching ()) { + ac->start_touch (ac->session().transport_frame()); + } + if (steps == 0) { + ac->set_value (ac->normal(), PBD::Controllable::UseGroup); + } else { + double v = ac->internal_to_interface (ac->get_value()); + v = std::max (0.0, std::min (1.0, v + steps * .01)); + ac->set_value (ac->interface_to_internal(v), PBD::Controllable::UseGroup); + } + } + } +} + +void +FaderPort8::handle_encoder_link (int steps) +{ + if (_link_control.expired ()) { + return; + } + boost::shared_ptr ac = boost::dynamic_pointer_cast (_link_control.lock ()); + if (!ac) { + return; + } + + double v = ac->internal_to_interface (ac->get_value()); + if (ac->automation_state() == Touch && !ac->touching ()) { + ac->start_touch (ac->session().transport_frame()); + } + + if (steps == 0) { + ac->set_value (ac->normal(), PBD::Controllable::UseGroup); + return; + } + + if (ac->desc().toggled) { + v = v > 0 ? 0. : 1.; + } else { + v = std::max (0.0, std::min (1.0, v + steps * .01)); + } + ac->set_value (ac->interface_to_internal(v), PBD::Controllable::UseGroup); +} + + /* **************************************************************************** * Mode specific and internal callbacks */ @@ -540,22 +631,10 @@ FaderPort8::button_parameter () switch (_ctrls.fader_mode()) { case ModeTrack: case ModePan: - { - boost::shared_ptr s = first_selected_stripable(); - if (s) { - boost::shared_ptr ac; - if (shift_mod () || _ctrls.fader_mode() == ModePan) { - ac = s->pan_width_control (); - } else { - ac = s->pan_azimuth_control (); - } - if (ac) { - if (ac->automation_state() == Touch && !ac->touching ()) { - ac->start_touch (ac->session().transport_frame()); - } - ac->set_value (ac->normal(), PBD::Controllable::UseGroup); - } - } + if (_link_enabled || _link_locked) { + handle_encoder_link (0); + } else { + handle_encoder_pan (0); } break; case ModePlugins: @@ -573,23 +652,11 @@ FaderPort8::encoder_parameter (bool neg, int steps) switch (_ctrls.fader_mode()) { case ModeTrack: case ModePan: - { - boost::shared_ptr s = first_selected_stripable(); - if (s) { - boost::shared_ptr ac; - if (shift_mod () || _ctrls.fader_mode() == ModePan) { - ac = s->pan_width_control (); - } else { - ac = s->pan_azimuth_control (); - } - if (ac) { - double v = ac->internal_to_interface (ac->get_value()); - v = std::max (0.0, std::min (1.0, v + steps * (neg ? -.01 : .01))); - if (ac->automation_state() == Touch && !ac->touching ()) { - ac->start_touch (ac->session().transport_frame()); - } - ac->set_value (ac->interface_to_internal(v), PBD::Controllable::UseGroup); - } + if (steps != 0) { + if (_link_enabled || _link_locked) { + handle_encoder_link (neg ? -steps : steps); + } else { + handle_encoder_pan (neg ? -steps : steps); } } break; diff --git a/libs/surfaces/faderport8/callbacks.cc b/libs/surfaces/faderport8/callbacks.cc index d8de1a714a..112b1d96bb 100644 --- a/libs/surfaces/faderport8/callbacks.cc +++ b/libs/surfaces/faderport8/callbacks.cc @@ -218,3 +218,19 @@ FaderPort8::notify_plugin_active_changed () _ctrls.button (FP8Controls::BtnBypass).set_color (0x888888ff); } } + +void +FaderPort8::nofity_focus_control (boost::weak_ptr c) +{ + assert (_link_enabled && !_link_locked); + // TODO consider subscribing to c's DropReferences + // (in case the control goes away while it has focus, update the BtnColor) + _link_control = c; + if (c.expired ()) { + _ctrls.button (FP8Controls::BtnLink).set_color (0xff8800ff); + _ctrls.button (FP8Controls::BtnLock).set_color (0xff0000ff); + } else { + _ctrls.button (FP8Controls::BtnLink).set_color (0x88ff00ff); + _ctrls.button (FP8Controls::BtnLock).set_color (0x00ff88ff); + } +} diff --git a/libs/surfaces/faderport8/faderport8.cc b/libs/surfaces/faderport8/faderport8.cc index bac6f13e03..3ae9994792 100644 --- a/libs/surfaces/faderport8/faderport8.cc +++ b/libs/surfaces/faderport8/faderport8.cc @@ -100,6 +100,8 @@ FaderPort8::FaderPort8 (Session& s) , _shift_lock (false) , _shift_pressed (0) , gui (0) + , _link_enabled (false) + , _link_locked (false) , _clock_mode (1) , _scribble_mode (2) , _two_line_text (false) @@ -982,6 +984,78 @@ FaderPort8::assign_stripables (bool select_only) } } +/* **************************************************************************** + * Control Link/Lock + */ + +void +FaderPort8::unlock_link (bool drop) +{ + link_locked_connection.disconnect (); + + if (drop) { + stop_link (); // calls back here with drop = false + return; + } + + _link_locked = false; + + if (_link_enabled) { + assert (_ctrls.button (FP8Controls::BtnLink).is_active ()); + _link_control.reset (); + start_link (); // re-connect & update LED colors + } else { + _ctrls.button (FP8Controls::BtnLink).set_active (false); + _ctrls.button (FP8Controls::BtnLink).set_color (0x888888ff); + _ctrls.button (FP8Controls::BtnLock).set_active (false); + _ctrls.button (FP8Controls::BtnLock).set_color (0x888888ff); + } +} + +void +FaderPort8::lock_link () +{ + boost::shared_ptr ac = boost::dynamic_pointer_cast (_link_control.lock ()); + if (!ac) { + return; + } + ac->DropReferences.connect (link_locked_connection, MISSING_INVALIDATOR, boost::bind (&FaderPort8::unlock_link, this, true), this); + + // stop watching for focus events + link_connection.disconnect (); + + _link_locked = true; + + _ctrls.button (FP8Controls::BtnLock).set_color (0x00ff00ff); + _ctrls.button (FP8Controls::BtnLink).set_color (0x00ff00ff); +} + +void +FaderPort8::stop_link () +{ + if (!_link_enabled) { + return; + } + link_connection.disconnect (); + _link_control.reset (); + _link_enabled = false; + unlock_link (); // also updates button colors +} + +void +FaderPort8::start_link () +{ + assert (!_link_locked); + + _link_enabled = true; + _ctrls.button (FP8Controls::BtnLink).set_active (true); + _ctrls.button (FP8Controls::BtnLock).set_active (true); + nofity_focus_control (_link_control); // update BtnLink, BtnLock colors + + PBD::Controllable::GUIFocusChanged.connect (link_connection, MISSING_INVALIDATOR, boost::bind (&FaderPort8::nofity_focus_control, this, _1), this); +} + + /* **************************************************************************** * Plugin selection and parameters */ @@ -1617,6 +1691,7 @@ FaderPort8::notify_fader_mode_changed () case ModeSend: _plugin_off = 0; _parameter_off = 0; + stop_link (); // force unset rec-arm button, see also FaderPort8::button_arm _ctrls.button (FP8Controls::BtnArm).set_active (false); ARMButtonChange (false); diff --git a/libs/surfaces/faderport8/faderport8.h b/libs/surfaces/faderport8/faderport8.h index 81f615835a..9b11fea6b4 100644 --- a/libs/surfaces/faderport8/faderport8.h +++ b/libs/surfaces/faderport8/faderport8.h @@ -31,6 +31,7 @@ #define ABSTRACT_UI_EXPORTS #include "pbd/abstract_ui.h" #include "pbd/properties.h" +#include "pbd/controllable.h" #include "ardour/types.h" #include "ardour/async_midi_port.h" @@ -271,6 +272,8 @@ private: void button_metronom (); void button_bypass (); void button_open (); + void button_link (); + void button_lock (); void button_varispeed (bool); #ifdef FP8_MUTESOLO_UNDO void button_solo_clear (); @@ -293,6 +296,22 @@ private: std::vector > _solo_state; #endif + /* Encoder handlers */ + void handle_encoder_pan (int steps); + void handle_encoder_link (int steps); + + /* Control Link */ + void stop_link (); + void start_link (); + void lock_link (); + void unlock_link (bool drop = false); + void nofity_focus_control (boost::weak_ptr); + PBD::ScopedConnection link_connection; + PBD::ScopedConnection link_locked_connection; + boost::weak_ptr _link_control; + bool _link_enabled; + bool _link_locked; // can only be true if _link_enabled + /* user prefs */ uint32_t _clock_mode; uint32_t _scribble_mode; -- cgit v1.2.3