Prepare for FaderPort16 (ctrl-protocol)
[ardour.git] / libs / surfaces / faderport8 / fp8_strip.cc
index ba3ba318f423a47ab1bce4c1de8d400971350b5f..0aa64e1cb9069f55a09e4e5f9fdc32e42a7e4ea6 100644 (file)
 #include "ardour/automation_control.h"
 #include "ardour/gain_control.h"
 #include "ardour/meter.h"
-#include "ardour/mute_control.h"
 #include "ardour/plugin_insert.h"
 #include "ardour/session.h"
-#include "ardour/solo_control.h"
 #include "ardour/stripable.h"
 #include "ardour/track.h"
 #include "ardour/value_as_string.h"
@@ -35,18 +33,70 @@ using namespace ARDOUR;
 using namespace ArdourSurface;
 using namespace ArdourSurface::FP8Types;
 
+uint8_t /* static */
+FP8Strip::midi_ctrl_id (CtrlElement type, uint8_t id)
+{
+       assert (id < N_STRIPS);
+       if (id < 8) {
+               switch (type) {
+                       case BtnSolo:
+                               return 0x08 + id;
+                       case BtnMute:
+                               return 0x10 + id;
+                       case BtnSelect:
+                               return 0x18 + id;
+                       case Fader:
+                               return 0xe0 + id;
+                       case Meter:
+                               return 0xd0 + id;
+                       case Redux:
+                               return 0xd8 + id;
+                       case BarVal:
+                               return 0x30 + id;
+                       case BarMode:
+                               return 0x38 + id;
+               }
+       } else {
+               id -= 8;
+               switch (type) {
+                       case BtnSolo:
+                               return 0x50 + id;
+                       case BtnMute:
+                               return 0x78 + id;
+                       case BtnSelect:
+                               if (id == 0) { // strip 8
+                                       return 0x07;
+                               } else {
+                                       return 0x21 + id;
+                               }
+                       case Fader:
+                               return 0xe8 + id;
+                       case Meter:
+                               return 0xc0 + id;
+                       case Redux:
+                               return 0xc8 + id;
+                       case BarVal:
+                               return 0x40 + id;
+                       case BarMode:
+                               return 0x48 + id;
+               }
+       }
+       assert (0);
+       return 0;
+}
+
 FP8Strip::FP8Strip (FP8Base& b, uint8_t id)
        : _base (b)
        , _id (id)
-       , _solo   (b, 0x08 + id)
-       , _mute   (b, 0x10 + id)
-       , _selrec (b, 0x18 + id, true)
+       , _solo   (b, midi_ctrl_id (BtnSolo, id))
+       , _mute   (b, midi_ctrl_id (BtnMute, id))
+       , _selrec (b, midi_ctrl_id (BtnSelect, id), true)
        , _touching (false)
        , _strip_mode (0)
        , _bar_mode (0)
        , _displaymode (Stripables)
 {
-       assert (id < 8);
+       assert (id < N_STRIPS);
 
        _last_fader = 65535;
        _last_meter = _last_redux = _last_barpos = 0xff;
@@ -59,21 +109,31 @@ FP8Strip::FP8Strip (FP8Base& b, uint8_t id)
 }
 
 FP8Strip::~FP8Strip ()
+{
+       drop_automation_controls ();
+       _base_connection.disconnect ();
+       _button_connections.drop_connections ();
+}
+
+void
+FP8Strip::drop_automation_controls ()
 {
        _fader_connection.disconnect ();
        _mute_connection.disconnect ();
        _solo_connection.disconnect ();
        _rec_connection.disconnect ();
        _pan_connection.disconnect ();
+       _x_select_connection.disconnect ();
 
        _fader_ctrl.reset ();
        _mute_ctrl.reset ();
        _solo_ctrl.reset ();
        _rec_ctrl.reset ();
        _pan_ctrl.reset ();
-
-       _base_connection.disconnect ();
-       _button_connections.drop_connections ();
+       _x_select_ctrl.reset ();
+       _peak_meter.reset ();
+       _redux_ctrl.reset ();
+       _select_plugin_functor.clear ();
 }
 
 void
@@ -83,15 +143,14 @@ FP8Strip::initialize ()
         * ie from FaderPort8::connected()
         */
        _solo.set_active (false);
+       _solo.set_blinking (false);
        _mute.set_active (false);
 
        /* reset momentary button state */
        _mute.reset ();
        _solo.reset ();
 
-       /* clear cached values */
-       _last_fader = 65535;
-       _last_meter = _last_redux = _last_barpos = 0xff;
+       drop_automation_controls ();
 
        select_button ().set_color (0xffffffff);
        select_button ().set_active (false);
@@ -114,10 +173,14 @@ FP8Strip::initialize ()
 
        set_bar_mode (4); // off
 
-       _base.tx_midi2 (0xd0 + _id, 0); // reset meter
-       _base.tx_midi2 (0xd8 + _id, 0); // reset redux
+       _base.tx_midi2 (midi_ctrl_id (Meter, _id), 0); // reset meter
+       _base.tx_midi2 (midi_ctrl_id (Redux, _id), 0); // reset redux
+
+       _base.tx_midi3 (midi_ctrl_id (Fader, _id), 0, 0); // fader
 
-       _base.tx_midi3 (0xe0 + _id, 0, 0); // fader
+       /* clear cached values */
+       _last_fader = 65535;
+       _last_meter = _last_redux = _last_barpos = 0xff;
 }
 
 
@@ -168,6 +231,7 @@ FP8Strip::unset_controllables (int which)
 {
        _peak_meter = boost::shared_ptr<ARDOUR::PeakMeter>();
        _redux_ctrl = boost::shared_ptr<ARDOUR::ReadOnlyControl>();
+       _stripable_name.clear ();
 
        if (which & CTRL_FADER) {
                set_fader_controllable (boost::shared_ptr<AutomationControl>());
@@ -191,25 +255,44 @@ FP8Strip::unset_controllables (int which)
                select_button ().set_blinking (false);
        }
        if (which & CTRL_TEXT0) {
-               set_text_line (0x00, "");
+               set_text_line (0, "");
        }
        if (which & CTRL_TEXT1) {
-               set_text_line (0x01, "");
+               set_text_line (1, "");
        }
        if (which & CTRL_TEXT2) {
-               set_text_line (0x02, "");
+               set_text_line (2, "");
        }
        if (which & CTRL_TEXT3) {
-               set_text_line (0x03, "");
+               set_text_line (3, "");
        }
        set_bar_mode (4); // Off
 }
 
+void
+FP8Strip::set_strip_name ()
+{
+       size_t lb = _base.show_meters () ? 6 : 9;
+       set_text_line (0, _stripable_name.substr (0, lb));
+       set_text_line (1, _stripable_name.length() > lb ? _stripable_name.substr (lb) : "");
+}
+
 void
 FP8Strip::set_stripable (boost::shared_ptr<Stripable> s, bool panmode)
 {
        assert (s);
 
+       if (_base.show_meters () && _base.show_panner ()) {
+               set_strip_mode (5, true);
+       } else if (_base.show_meters ()) {
+               set_strip_mode (4, true);
+       } else {
+               set_strip_mode (0, true);
+       }
+       if (!_base.show_panner ()) {
+               set_bar_mode (4, true); // Off
+       }
+
        if (panmode) {
                set_fader_controllable (s->pan_azimuth_control ());
        } else {
@@ -241,11 +324,16 @@ FP8Strip::set_stripable (boost::shared_ptr<Stripable> s, bool panmode)
        select_button ().set_color (s->presentation_info ().color());
        //select_button ().set_blinking (false);
 
-       set_strip_mode (0x05);
-       set_text_line (0x00, s->name ());
-       set_text_line (0x01, _pan_ctrl ? _pan_ctrl->get_user_string () : "");
-       set_text_line (0x02, "");
-       set_text_line (0x03, "");
+       _stripable_name = s->name ();
+
+       if (_base.twolinetext ()) {
+               set_strip_name ();
+       } else {
+               set_text_line (0, s->name ());
+               set_text_line (1, _pan_ctrl ? _pan_ctrl->get_user_string () : "");
+       }
+       set_text_line (2, "");
+       set_text_line (3, "");
 }
 
 /* *****************************************************************************
@@ -261,11 +349,9 @@ FP8Strip::midi_touch (bool t)
                return false;
        }
        if (t) {
-               if (!ac->touching ()) {
-                       ac->start_touch (ac->session().transport_frame());
-               }
+               ac->start_touch (ac->session().transport_sample());
        } else {
-               ac->stop_touch (true, ac->session().transport_frame());
+               ac->stop_touch (ac->session().transport_sample());
        }
        return true;
 }
@@ -281,9 +367,7 @@ FP8Strip::midi_fader (float val)
        if (!ac) {
                return false;
        }
-       if (!ac->touching ()) {
-               ac->start_touch (ac->session().transport_frame());
-       }
+       ac->start_touch (ac->session().transport_sample());
        ac->set_value (ac->interface_to_internal (val), group_mode ());
        return true;
 }
@@ -305,32 +389,31 @@ FP8Strip::group_mode () const
 void
 FP8Strip::set_mute (bool on)
 {
-       if (_mute_ctrl) {
-               if (!_mute_ctrl->touching ()) {
-                       _mute_ctrl->start_touch (_mute_ctrl->session().transport_frame());
-               }
-               _mute_ctrl->set_value (on ? 1.0 : 0.0, group_mode ());
+       if (!_mute_ctrl) {
+               return;
        }
+       _mute_ctrl->start_touch (_mute_ctrl->session().transport_sample());
+       _mute_ctrl->set_value (on ? 1.0 : 0.0, group_mode ());
 }
 
 void
 FP8Strip::set_solo (bool on)
 {
-       if (_solo_ctrl) {
-               if (!_solo_ctrl->touching ()) {
-                       _solo_ctrl->start_touch (_solo_ctrl->session().transport_frame());
-               }
-               _solo_ctrl->set_value (on ? 1.0 : 0.0, group_mode ());
+       if (!_solo_ctrl) {
+               return;
        }
+       _solo_ctrl->start_touch (_solo_ctrl->session().transport_sample());
+       _solo_ctrl->set_value (on ? 1.0 : 0.0, group_mode ());
 }
 
 void
 FP8Strip::set_recarm ()
 {
-       if (_rec_ctrl) {
-               const bool on = !recarm_button ().is_active();
-               _rec_ctrl->set_value (on ? 1.0 : 0.0, group_mode ());
+       if (!_rec_ctrl) {
+               return;
        }
+       const bool on = !recarm_button ().is_active();
+       _rec_ctrl->set_value (on ? 1.0 : 0.0, group_mode ());
 }
 
 void
@@ -340,9 +423,7 @@ FP8Strip::set_select ()
                assert (!_x_select_ctrl);
                _select_plugin_functor ();
        } else if (_x_select_ctrl) {
-               if (!_x_select_ctrl->touching ()) {
-                       _x_select_ctrl->start_touch (_x_select_ctrl->session().transport_frame());
-               }
+               _x_select_ctrl->start_touch (_x_select_ctrl->session().transport_sample());
                const bool on = !select_button ().is_active();
                _x_select_ctrl->set_value (on ? 1.0 : 0.0, group_mode ());
        }
@@ -361,22 +442,31 @@ FP8Strip::notify_fader_changed ()
        }
        float val = 0;
        if (ac) {
-               val = ac->internal_to_interface (ac->get_value()) * 16368.f; /* 16 * 1023 */
+               val = ac->internal_to_interface (ac->get_value());
+               val = std::max (0.f, std::min (1.f, val)) * 16368.f; /* 16 * 1023 */
        }
        unsigned short mv = lrintf (val);
        if (mv == _last_fader) {
                return;
        }
        _last_fader = mv;
-       _base.tx_midi3 (0xe0 + _id, (mv & 0x7f), (mv >> 7) & 0x7f);
+       _base.tx_midi3 (midi_ctrl_id (Fader, _id), (mv & 0x7f), (mv >> 7) & 0x7f);
 }
 
 void
 FP8Strip::notify_solo_changed ()
 {
        if (_solo_ctrl) {
-               _solo.set_active (_solo_ctrl->get_value () > 0);
+               boost::shared_ptr<SoloControl> sc = boost::dynamic_pointer_cast<SoloControl> (_solo_ctrl);
+               if (sc) {
+                       _solo.set_blinking (sc->soloed_by_others () && !sc->self_soloed ());
+                       _solo.set_active (sc->self_soloed ());
+               } else {
+                       _solo.set_blinking (false);
+                       _solo.set_active (_solo_ctrl->get_value () > 0);
+               }
        } else {
+               _solo.set_blinking (false);
                _solo.set_active (false);
        }
 }
@@ -420,8 +510,6 @@ FP8Strip::notify_x_select_changed ()
                select_button ().set_active (_x_select_ctrl->get_value() > 0.);
                select_button ().set_color (0xffff00ff);
                select_button ().set_blinking (false);
-       } else {
-               ; // leave alone.
        }
 }
 
@@ -437,10 +525,10 @@ FP8Strip::periodic_update_fader ()
                return;
        }
 
-       ARDOUR::AutoState state = ac->automation_state();
-       if (state == Touch || state == Play) {
-               notify_fader_changed ();
+       if (!ac->automation_playback ()) {
+               return;
        }
+       notify_fader_changed ();
 }
 
 void
@@ -455,38 +543,39 @@ FP8Strip::set_periodic_display_mode (DisplayMode m) {
 void
 FP8Strip::periodic_update_meter ()
 {
+       bool show_meters = _base.show_meters ();
        bool have_meter = false;
        bool have_panner = false;
 
-       if (_peak_meter) {
+       if (_peak_meter && show_meters) {
                have_meter = true;
                float dB = _peak_meter->meter_level (0, MeterMCP);
                // TODO: deflect meter
                int val = std::min (127.f, std::max (0.f, 2.f * dB + 127.f));
                if (val != _last_meter || val > 0) {
-                       _base.tx_midi2 (0xd0 + _id, val & 0x7f); // falls off automatically
+                       _base.tx_midi2 (midi_ctrl_id (Meter, _id), val & 0x7f); // falls off automatically
                        _last_meter = val;
                }
 
-       } else {
+       } else if (show_meters) {
                if (0 != _last_meter) {
-                       _base.tx_midi2 (0xd0 + _id, 0);
+                       _base.tx_midi2 (midi_ctrl_id (Meter, _id), 0);
                        _last_meter = 0;
                }
        }
 
        // show redux only if there's a meter, too  (strip display mode 5)
-       if (_peak_meter && _redux_ctrl) {
+       if (_peak_meter && _redux_ctrl && show_meters) {
                float rx = (1.f - _redux_ctrl->get_parameter ()) * 127.f;
                // TODO: deflect redux
                int val = std::min (127.f, std::max (0.f, rx));
                if (val != _last_redux) {
-                       _base.tx_midi2 (0xd8 + _id, val & 0x7f);
+                       _base.tx_midi2 (midi_ctrl_id (Redux, _id), val & 0x7f);
                        _last_redux = val;
                }
-       } else {
+       } else if (show_meters) {
                if (0 != _last_redux) {
-                       _base.tx_midi2 (0xd8 + _id, 0);
+                       _base.tx_midi2 (midi_ctrl_id (Redux, _id), 0);
                        _last_redux = 0;
                }
        }
@@ -494,37 +583,49 @@ FP8Strip::periodic_update_meter ()
        if (_displaymode == PluginParam) {
                if (_fader_ctrl) {
                        set_bar_mode (2); // Fill
-                       set_text_line (0x01, value_as_string(_fader_ctrl->desc(), _fader_ctrl->get_value()));
+                       set_text_line (2, value_as_string(_fader_ctrl->desc(), _fader_ctrl->get_value()));
                        float barpos = _fader_ctrl->internal_to_interface (_fader_ctrl->get_value());
                        int val = std::min (127.f, std::max (0.f, barpos * 128.f));
                        if (val != _last_barpos) {
-                               _base.tx_midi3 (0xb0, 0x30 + _id, val & 0x7f);
+                               _base.tx_midi3 (0xb0, midi_ctrl_id (BarVal, _id), val & 0x7f);
                                _last_barpos = val;
                        }
                } else {
                        set_bar_mode (4); // Off
-                       set_text_line (0x01, "");
+                       set_text_line (2, "");
                }
        }
+       else if (_displaymode == PluginSelect) {
+               set_bar_mode (4); // Off
+       }
        else if (_displaymode == SendDisplay) {
                set_bar_mode (4); // Off
                if (_fader_ctrl) {
-                       set_text_line (0x01, value_as_string(_fader_ctrl->desc(), _fader_ctrl->get_value()));
+                       set_text_line (1, value_as_string(_fader_ctrl->desc(), _fader_ctrl->get_value()));
                } else {
-                       set_text_line (0x01, "");
+                       set_text_line (1, "");
                }
        } else if (_pan_ctrl) {
-               have_panner = true;
+               have_panner = _base.show_panner ();
                float panpos = _pan_ctrl->internal_to_interface (_pan_ctrl->get_value());
                int val = std::min (127.f, std::max (0.f, panpos * 128.f));
-               set_bar_mode (1); // Bipolar
-               if (val != _last_barpos) {
-                       _base.tx_midi3 (0xb0, 0x30 + _id, val & 0x7f);
+               set_bar_mode (have_panner ? 1 : 4); // Bipolar or Off
+               if (val != _last_barpos && have_panner) {
+                       _base.tx_midi3 (0xb0, midi_ctrl_id (BarVal, _id), val & 0x7f);
                        _last_barpos = val;
                }
-               set_text_line (0x01, _pan_ctrl->get_user_string ());
+               if (_base.twolinetext ()) {
+                       set_strip_name ();
+               } else {
+                       set_text_line (1, _pan_ctrl->get_user_string ());
+               }
        } else {
                set_bar_mode (4); // Off
+               if (_base.twolinetext ()) {
+                       set_strip_name ();
+               } else {
+                       set_text_line (1, "");
+               }
        }
 
        if (_displaymode == SendDisplay || _displaymode == PluginParam) {
@@ -537,9 +638,9 @@ FP8Strip::periodic_update_meter ()
                set_strip_mode (4); // big meters + 3 lines of text (3rd line is large)
        }
        else if (have_panner) {
-               set_strip_mode (0); // 3 lines of text (3rd line is large) + value-bar
+               set_strip_mode (0); // 3 lines of text (3rd line is large + long) + value-bar
        } else {
-               set_strip_mode (0); // 3 lines of text (3rd line is large) + value-bar
+               set_strip_mode (0); // 3 lines of text (3rd line is large + long) + value-bar
        }
 }
 
@@ -549,19 +650,34 @@ FP8Strip::set_strip_mode (uint8_t strip_mode, bool clear)
        if (strip_mode == _strip_mode && !clear) {
                return;
        }
+
        _strip_mode = strip_mode;
        _base.tx_sysex (3, 0x13, _id, (_strip_mode & 0x07) | (clear ? 0x10 : 0));
-       //_base.tx_midi3 (0xb0, 0x38 + _id, _bar_mode);
+
+       if (clear) {
+               /* work-around, when swiching modes, the FP8 may not
+                * properly redraw long lines. Only update lines 0, 1
+                * (line 2 is timecode, line 3 may be inverted)
+                */
+               _base.tx_text (_id, 0, 0x00, _last_line[0]);
+               _base.tx_text (_id, 1, 0x00, _last_line[1]);
+       }
 }
 
 void
-FP8Strip::set_bar_mode (uint8_t bar_mode)
+FP8Strip::set_bar_mode (uint8_t bar_mode, bool force)
 {
-       if (bar_mode == _bar_mode) {
+       if (bar_mode == _bar_mode && !force) {
                return;
        }
+
+       if (bar_mode == 4) {
+               _base.tx_midi3 (0xb0, midi_ctrl_id (BarVal, _id), 0);
+               _last_barpos = 0xff;
+       }
+
        _bar_mode = bar_mode;
-       _base.tx_midi3 (0xb0, 0x38 + _id, bar_mode);
+       _base.tx_midi3 (0xb0, midi_ctrl_id (BarMode, _id), bar_mode);
 }
 
 void
@@ -576,16 +692,29 @@ FP8Strip::set_text_line (uint8_t line, std::string const& txt, bool inv)
 }
 
 void
-FP8Strip::periodic_update_timecode ()
+FP8Strip::periodic_update_timecode (uint32_t m)
 {
-       if (_id >= 2 && _id < 6) {
-               std::string const& tc = _base.timecode();
-               //" HH:MM:SS:FF"
+       if (m == 0) {
+               return;
+       }
+       if (m == 3) {
+               bool mc = _id >= 4;
+               std::string const& tc = mc ? _base.musical_time () : _base.timecode();
+               std::string t;
+               if (tc.size () == 12) {
+                       t = tc.substr (1 + (_id - (mc ? 4 : 0)) * 3, 2);
+               }
+               set_text_line (2, t);
+       } else if (_id >= 2 && _id < 6) {
+               std::string const& tc = (m == 2) ? _base.musical_time () : _base.timecode();
+               //" HH:MM:SS:FF" or " BR|BT|TI|CK"
                std::string t;
                if (tc.size () == 12) {
                        t = tc.substr (1 + (_id - 2) * 3, 2);
                }
-               set_text_line (0x02, t);
+               set_text_line (2, t);
+       } else {
+               set_text_line (2, "");
        }
 }
 
@@ -594,7 +723,7 @@ FP8Strip::periodic ()
 {
        periodic_update_fader ();
        periodic_update_meter ();
-       if (_displaymode != PluginSelect) {
-               periodic_update_timecode ();
+       if (_displaymode != PluginSelect && _displaymode != PluginParam) {
+               periodic_update_timecode (_base.clock_mode ());
        }
 }