FP8: Implement "Control-Link"

This commit is contained in:
Robin Gareus 2017-07-02 18:16:54 +02:00
parent 98a1a96f32
commit 0310f89971
4 changed files with 213 additions and 36 deletions

View file

@ -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<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;

View file

@ -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);
}
}

View file

@ -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<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);

View file

@ -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;