summaryrefslogtreecommitdiff
path: root/libs/surfaces/faderport8
diff options
context:
space:
mode:
authorRobin Gareus <robin@gareus.org>2017-07-02 18:16:54 +0200
committerRobin Gareus <robin@gareus.org>2017-07-02 18:19:13 +0200
commit0310f8997147cc50600a98f05ef1a6c486e688c7 (patch)
tree0ae41ea7ce868913ddd1a10413a25d87cd087bb1 /libs/surfaces/faderport8
parent98a1a96f3244de660f5434a6816f2ddd36a38513 (diff)
FP8: Implement "Control-Link"
Diffstat (limited to 'libs/surfaces/faderport8')
-rw-r--r--libs/surfaces/faderport8/actions.cc139
-rw-r--r--libs/surfaces/faderport8/callbacks.cc16
-rw-r--r--libs/surfaces/faderport8/faderport8.cc75
-rw-r--r--libs/surfaces/faderport8/faderport8.h19
4 files changed, 213 insertions, 36 deletions
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)
@@ -349,6 +380,66 @@ FaderPort8::button_action (const std::string& group, const std::string& item)
}
/* ****************************************************************************
+ * Control Interaction (encoder)
+ */
+
+void
+FaderPort8::handle_encoder_pan (int steps)
+{
+ boost::shared_ptr<Stripable> s = first_selected_stripable();
+ if (s) {
+ boost::shared_ptr<AutomationControl> 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<AutomationControl> ac = boost::dynamic_pointer_cast<AutomationControl> (_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<Stripable> s = first_selected_stripable();
- if (s) {
- boost::shared_ptr<AutomationControl> 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<Stripable> s = first_selected_stripable();
- if (s) {
- boost::shared_ptr<AutomationControl> 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<PBD::Controllable> 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)
@@ -983,6 +985,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<AutomationControl> ac = boost::dynamic_pointer_cast<AutomationControl> (_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 <boost::weak_ptr<ARDOUR::AutomationControl> > _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::Controllable>);
+ PBD::ScopedConnection link_connection;
+ PBD::ScopedConnection link_locked_connection;
+ boost::weak_ptr<PBD::Controllable> _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;