Add OSX configuration script.
[ardour.git] / libs / surfaces / faderport8 / actions.cc
index e6ad7fd0624919f4827a6fd1d528ab36170fd5fa..a710540b71dcbe3f96635dc7e7012acd39174222 100644 (file)
@@ -20,6 +20,7 @@
  */
 
 #include "ardour/dB.h"
+#include "ardour/plugin_insert.h"
 #include "ardour/session.h"
 #include "ardour/session_configuration.h"
 #include "ardour/types.h"
@@ -48,6 +49,11 @@ using namespace ArdourSurface::FP8Types;
        _ctrls.button (ID).pressed.connect_same_thread (button_connections, boost::bind (&FaderPort8::button_user, this, true, ID)); \
 _ctrls.button (ID).released.connect_same_thread (button_connections, boost::bind (&FaderPort8::button_user, this, false, ID));
 
+
+/* Bind button signals (press, release) to callback methods
+ * (called once after constructing buttons).
+ * Bound actions are handled the the ctrl-surface thread.
+ */
 void
 FaderPort8::setup_actions ()
 {
@@ -62,7 +68,11 @@ FaderPort8::setup_actions ()
        BindAction (BtnUndo, "Editor", "undo");
        BindAction (BtnRedo, "Editor", "redo");
 
+#ifdef FP8_MUTESOLO_UNDO
+       BindMethod (BtnSoloClear, button_solo_clear);
+#else
        BindAction (BtnSoloClear, "Main", "cancel-solo");
+#endif
        BindMethod (BtnMuteClear, button_mute_clear);
 
        BindMethod (FP8Controls::BtnArmAll, button_arm_all);
@@ -85,14 +95,14 @@ FaderPort8::setup_actions ()
        _ctrls.button (FP8Controls::BtnParam).pressed.connect_same_thread (button_connections, boost::bind (&FaderPort8::button_parameter, this));
 
 
-       BindAction (BtnBypass, "Mixer", "ab-plugins");
-       BindAction (BtnBypassAll, "Mixer", "ab-plugins"); // XXX
+       BindMethod (BtnBypass, button_bypass);
+       BindAction (BtnBypassAll, "Mixer", "ab-plugins");
 
-       BindAction (BtnMacro, "Mixer", "show-editor");
-       BindAction (BtnLink, "Window", "show-mixer");
+       BindAction (BtnMacro, "Common", "toggle-editor-and-mixer");
+       BindMethod (BtnOpen, button_open);
 
-       BindAction (BtnOpen, "Common", "addExistingAudioFiles");
-       BindAction (BtnLock, "Editor", "lock");
+       BindMethod (BtnLink, button_link);
+       BindMethod (BtnLock, button_lock);
 
        // user-specific
        for (FP8Controls::UserButtonMap::const_iterator i = _ctrls.user_buttons ().begin ();
@@ -101,6 +111,10 @@ FaderPort8::setup_actions ()
        }
 }
 
+/* ****************************************************************************
+ * Direct control callback Actions
+ */
+
 void
 FaderPort8::button_play ()
 {
@@ -143,6 +157,59 @@ FaderPort8::button_metronom ()
        Config->set_clicking (!Config->get_clicking ());
 }
 
+void
+FaderPort8::button_bypass ()
+{
+       boost::shared_ptr<PluginInsert> pi = _plugin_insert.lock();
+       if (pi) {
+               pi->enable (! pi->enabled ());
+       } else {
+               AccessAction ("Mixer", "ab-plugins");
+       }
+}
+
+void
+FaderPort8::button_open ()
+{
+       boost::shared_ptr<PluginInsert> pi = _plugin_insert.lock();
+       if (pi) {
+               pi->ToggleUI (); /* EMIT SIGNAL */
+       } else {
+               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)
 {
@@ -172,6 +239,8 @@ FaderPort8::button_automation (ARDOUR::AutoState as)
                        break;
        }
 
+       // TODO link/lock control automation?
+
        // apply to all selected tracks
        StripableList all;
        session->get_stripables (all);
@@ -233,35 +302,69 @@ FaderPort8::button_varispeed (bool ffw)
        session->request_transport_speed (speed, false);
 }
 
+#ifdef FP8_MUTESOLO_UNDO
 void
-FaderPort8::button_mute_clear ()
+FaderPort8::button_solo_clear ()
 {
-       StripableList all;
-       session->get_stripables (all);
-       boost::shared_ptr<ControlList> cl (new ControlList);
-       for (StripableList::const_iterator i = all.begin(); i != all.end(); ++i) {
-               if ((*i)->is_master() || (*i)->is_monitor()) {
-                       continue;
+       bool soloing = session->soloing() || session->listening();
+#ifdef MIXBUS
+       soloing |= session->mixbus_soloed();
+#endif
+       if (soloing) {
+               StripableList all;
+               session->get_stripables (all);
+               for (StripableList::const_iterator i = all.begin(); i != all.end(); ++i) {
+                       if ((*i)->is_master() || (*i)->is_auditioner() || (*i)->is_monitor()) {
+                               continue;
+                       }
+                       boost::shared_ptr<SoloControl> sc = (*i)->solo_control();
+                       if (sc && sc->self_soloed ()) {
+                               _solo_state.push_back (boost::weak_ptr<AutomationControl>(sc));
+                       }
                }
-               boost::shared_ptr<AutomationControl> ac = (*i)->mute_control();
-               if (ac && ac->get_value () > 0) {
-                       if (ac->automation_state() == Touch && !ac->touching ()) {
-                               ac->start_touch (ac->session().transport_frame());
+               AccessAction ("Main", "cancel-solo");
+       } else {
+               /* restore solo */
+               boost::shared_ptr<ControlList> cl (new ControlList);
+               for (std::vector <boost::weak_ptr<AutomationControl> >::const_iterator i = _solo_state.begin(); i != _solo_state.end(); ++i) {
+                       boost::shared_ptr<AutomationControl> ac = (*i).lock();
+                       if (!ac) {
+                               continue;
                        }
+                       ac->start_touch (ac->session().transport_frame());
                        cl->push_back (ac);
                }
+               if (!cl->empty()) {
+                       session->set_controls (cl, 1.0, PBD::Controllable::NoGroup);
+               }
        }
-       session->set_controls (cl, 0.0, PBD::Controllable::UseGroup);
 }
+#endif
 
 void
-FaderPort8::button_arm (bool press)
+FaderPort8::button_mute_clear ()
 {
-       FaderMode fadermode = _ctrls.fader_mode ();
-       if (fadermode == ModeTrack || fadermode == ModePan) {
-               _ctrls.button (FP8Controls::BtnArm).set_active (press);
-               ARMButtonChange (press);
+#ifdef FP8_MUTESOLO_UNDO
+       if (session->muted ()) {
+               _mute_state = session->cancel_all_mute ();
+       } else {
+               /* restore mute */
+               boost::shared_ptr<ControlList> cl (new ControlList);
+               for (std::vector <boost::weak_ptr<AutomationControl> >::const_iterator i = _mute_state.begin(); i != _mute_state.end(); ++i) {
+                       boost::shared_ptr<AutomationControl> ac = (*i).lock();
+                       if (!ac) {
+                               continue;
+                       }
+                       cl->push_back (ac);
+                       ac->start_touch (ac->session().transport_frame());
+               }
+               if (!cl->empty()) {
+                       session->set_controls (cl, 1.0, PBD::Controllable::NoGroup);
+               }
        }
+#else
+       session->cancel_all_mute ();
+#endif
 }
 
 void
@@ -270,12 +373,89 @@ FaderPort8::button_arm_all ()
        BasicUI::all_tracks_rec_in ();
 }
 
+/* access generic action */
 void
 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) {
+                       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());
+       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 if (ac->desc().integer_step) {
+               v += steps / (1.f + ac->desc().upper - ac->desc().lower);
+       } else if (ac->desc().enumeration) {
+               ac->set_value (ac->desc().step_enum (ac->get_value(), steps < 0), PBD::Controllable::UseGroup);
+               return;
+       } 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
+ */
+
+/* handle "ARM" press -- act like shift, change "Select" button mode */
+void
+FaderPort8::button_arm (bool press)
+{
+       FaderMode fadermode = _ctrls.fader_mode ();
+       if (fadermode == ModeTrack || fadermode == ModePan) {
+               _ctrls.button (FP8Controls::BtnArm).set_active (press);
+               ARMButtonChange (press); /* EMIT SIGNAL */
+       }
+}
+
 void
 FaderPort8::button_prev_next (bool next)
 {
@@ -318,6 +498,12 @@ FaderPort8::button_prev_next (bool next)
 void
 FaderPort8::button_encoder ()
 {
+       /* special-case metronome level */
+       if (_ctrls.button (FP8Controls::BtnClick).is_pressed ()) {
+               Config->set_click_gain (1.0);
+               _ctrls.button (FP8Controls::BtnClick).ignore_release();
+               return;
+       }
        switch (_ctrls.nav_mode()) {
                case NavZoom:
                        ZoomToSession (); // XXX undo zoom
@@ -326,6 +512,8 @@ FaderPort8::button_encoder ()
                        ZoomToSession ();
                        break;
                case NavChannel:
+                       AccessAction ("Editor", "select-topmost");
+                       break;
                case NavBank:
                        move_selected_into_view ();
                        break;
@@ -339,9 +527,7 @@ FaderPort8::button_encoder ()
                                        ac = session->master_out()->gain_control ();
                                }
                                if (ac) {
-                                       if (ac->automation_state() == Touch && !ac->touching ()) {
-                                               ac->start_touch (ac->session().transport_frame());
-                                       }
+                                       ac->start_touch (ac->session().transport_frame());
                                        ac->set_value (ac->normal(), PBD::Controllable::NoGroup);
                                }
                        }
@@ -388,9 +574,11 @@ FaderPort8::encoder_navigate (bool neg, int steps)
        switch (_ctrls.nav_mode()) {
                case NavChannel:
                        if (neg) {
-                               StepTracksUp ();
+                               AccessAction ("Mixer", "scroll-left");
+                               AccessAction ("Editor", "step-tracks-up");
                        } else {
-                               StepTracksDown ();
+                               AccessAction ("Mixer", "scroll-right");
+                               AccessAction ("Editor", "step-tracks-down");
                        }
                        break;
                case NavZoom:
@@ -419,9 +607,7 @@ FaderPort8::encoder_navigate (bool neg, int steps)
                                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->start_touch (ac->session().transport_frame());
                                        ac->set_value (ac->interface_to_internal(v), PBD::Controllable::NoGroup);
                                }
                        }
@@ -443,25 +629,14 @@ 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:
+                       toggle_preset_param_mode ();
                        break;
                case ModeSend:
                        break;
@@ -475,30 +650,18 @@ 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;
                case ModePlugins:
                case ModeSend:
                        while (steps > 0) {
-                               bank_param (neg, false);
+                               bank_param (neg, shift_mod());
                                --steps;
                        }
                        break;