The #end should be #endif
[ardour.git] / libs / surfaces / faderport8 / faderport8.cc
index 5429ed29ead9e88deae052b591e27c259551b87d..7a2448e939f8088af071c5d91644a39d4da5df87 100644 (file)
@@ -94,7 +94,7 @@ FaderPort8::FaderPort8 (Session& s)
        , _parameter_off (0)
        , _blink_onoff (false)
        , _shift_lock (false)
-       , _shift_pressed (false)
+       , _shift_pressed (0)
        , gui (0)
 {
        boost::shared_ptr<ARDOUR::Port> inp;
@@ -124,11 +124,13 @@ FaderPort8::FaderPort8 (Session& s)
                session->engine().make_port_name_non_relative (outp->name())
                );
 
-       ARDOUR::AudioEngine::instance()->PortConnectedOrDisconnected.connect (port_connection, MISSING_INVALIDATOR, boost::bind (&FaderPort8::connection_handler, this, _1, _2, _3, _4, _5), this);
-
-       StripableSelectionChanged.connect (selection_connection, MISSING_INVALIDATOR, boost::bind (&FaderPort8::gui_track_selection_changed, this), this);
+       ARDOUR::AudioEngine::instance()->PortConnectedOrDisconnected.connect (port_connections, MISSING_INVALIDATOR, boost::bind (&FaderPort8::connection_handler, this, _2, _4), this);
+       ARDOUR::AudioEngine::instance()->Stopped.connect (port_connections, MISSING_INVALIDATOR, boost::bind (&FaderPort8::engine_reset, this), this);
+       ARDOUR::Port::PortDrop.connect (port_connections, MISSING_INVALIDATOR, boost::bind (&FaderPort8::engine_reset, this), this);
 
+       /* bind button events to call libardour actions */
        setup_actions ();
+
        _ctrls.FaderModeChanged.connect_same_thread (modechange_connections, boost::bind (&FaderPort8::notify_fader_mode_changed, this));
        _ctrls.MixModeChanged.connect_same_thread (modechange_connections, boost::bind (&FaderPort8::assign_strips, this, true));
 }
@@ -136,7 +138,7 @@ FaderPort8::FaderPort8 (Session& s)
 FaderPort8::~FaderPort8 ()
 {
        cerr << "~FP8\n";
-       stop_midi_handling  ();
+       disconnected ();
        close ();
 
        if (_input_port) {
@@ -265,13 +267,14 @@ FaderPort8::set_active (bool yn)
 void
 FaderPort8::close ()
 {
-       _assigned_strips.clear ();
+       DEBUG_TRACE (DEBUG::FaderPort8, "FaderPort8::close\n");
        stop_midi_handling ();
        session_connections.drop_connections ();
        automation_state_connections.drop_connections ();
        assigned_stripable_connections.drop_connections ();
+       _assigned_strips.clear ();
        drop_ctrl_connections ();
-       port_connection.disconnect ();
+       port_connections.drop_connections ();
        selection_connection.disconnect ();
 }
 
@@ -290,13 +293,19 @@ void
 FaderPort8::connected ()
 {
        DEBUG_TRACE (DEBUG::FaderPort8, "initializing\n");
+       assert (!_device_active);
+
+       if (_device_active) {
+               stop_midi_handling (); // re-init
+       }
+
        // ideally check firmware version >= 1.01 (USB bcdDevice 0x0101) (vendor 0x194f prod 0x0202)
        // but we don't have a handle to the underlying USB device here.
 
        _channel_off = _plugin_off = _parameter_off = 0;
        _blink_onoff = false;
        _shift_lock = false;
-       _shift_pressed = false;
+       _shift_pressed = 0;
 
        start_midi_handling ();
        _ctrls.initialize ();
@@ -328,13 +337,26 @@ void
 FaderPort8::disconnected ()
 {
        stop_midi_handling ();
-       for (uint8_t id = 0; id < 8; ++id) {
-               _ctrls.strip(id).unset_controllables ();
+       if (_device_active) {
+               for (uint8_t id = 0; id < 8; ++id) {
+                       _ctrls.strip(id).unset_controllables ();
+               }
+               _ctrls.all_lights_off ();
        }
 }
 
+void
+FaderPort8::engine_reset ()
+{
+       /* Port::PortDrop is called when the engine is halted or stopped */
+       DEBUG_TRACE (DEBUG::FaderPort8, "FaderPort8::engine_reset\n");
+       _connection_state = 0;
+       _device_active = false;
+       disconnected ();
+}
+
 bool
-FaderPort8::connection_handler (boost::weak_ptr<ARDOUR::Port>, std::string name1, boost::weak_ptr<ARDOUR::Port>, std::string name2, bool yn)
+FaderPort8::connection_handler (std::string name1, std::string name2)
 {
 #ifdef VERBOSE_DEBUG
        DEBUG_TRACE (DEBUG::FaderPort8, "FaderPort8::connection_handler: start\n");
@@ -347,13 +369,21 @@ FaderPort8::connection_handler (boost::weak_ptr<ARDOUR::Port>, std::string name1
        string no = ARDOUR::AudioEngine::instance()->make_port_name_non_relative (boost::shared_ptr<ARDOUR::Port>(_output_port)->name());
 
        if (ni == name1 || ni == name2) {
-               if (yn) {
+               DEBUG_TRACE (DEBUG::FaderPort8, string_compose ("Connection notify %1 and %2\n", name1, name2));
+               if (_input_port->connected ()) {
+                       if (_connection_state & InputConnected) {
+                               return false;
+                       }
                        _connection_state |= InputConnected;
                } else {
                        _connection_state &= ~InputConnected;
                }
        } else if (no == name1 || no == name2) {
-               if (yn) {
+               DEBUG_TRACE (DEBUG::FaderPort8, string_compose ("Connection notify %1 and %2\n", name1, name2));
+               if (_output_port->connected ()) {
+                       if (_connection_state & OutputConnected) {
+                               return false;
+                       }
                        _connection_state |= OutputConnected;
                } else {
                        _connection_state &= ~OutputConnected;
@@ -379,7 +409,9 @@ FaderPort8::connection_handler (boost::weak_ptr<ARDOUR::Port>, std::string name1
 
        } else {
                DEBUG_TRACE (DEBUG::FaderPort8, "Device disconnected (input or output or both) or not yet fully connected\n");
-               disconnected ();
+               if (_device_active) {
+                       disconnected ();
+               }
                _device_active = false;
        }
 
@@ -495,7 +527,7 @@ FaderPort8::pitchbend_handler (MIDI::Parser &, uint8_t chan, MIDI::pitchbend_t p
        /* fader 0..16368 (0x3ff0 -- 1024 steps) */
        bool handled = _ctrls.midi_fader (chan, pb);
        /* if Shift key is held while moving a fader (group override), don't lock shift. */
-       if (_shift_pressed && handled) {
+       if ((_shift_pressed > 0) && handled) {
                _shift_connection.disconnect ();
                _shift_lock = false;
        }
@@ -528,7 +560,10 @@ FaderPort8::note_on_handler (MIDI::Parser &, MIDI::EventTwoBytes* tb)
 
        /* special case shift */
        if (tb->note_number == 0x06 || tb->note_number == 0x46) {
-               _shift_pressed = true;
+               _shift_pressed |= (tb->note_number == 0x06) ? 1 : 2;
+               if (_shift_pressed == 3) {
+                       return;
+               }
                _shift_connection.disconnect ();
                if (_shift_lock) {
                        _shift_lock = false;
@@ -565,7 +600,10 @@ FaderPort8::note_off_handler (MIDI::Parser &, MIDI::EventTwoBytes* tb)
 
        /* special case shift */
        if (tb->note_number == 0x06 || tb->note_number == 0x46) {
-               _shift_pressed = false;
+               _shift_pressed &= (tb->note_number == 0x06) ? 2 : 1;
+               if (_shift_pressed > 0) {
+                       return;
+               }
                if (_shift_lock) {
                        return;
                }
@@ -580,7 +618,7 @@ FaderPort8::note_off_handler (MIDI::Parser &, MIDI::EventTwoBytes* tb)
 
        bool handled = _ctrls.midi_event (tb->note_number, tb->velocity);
        /* if Shift key is held while activating an action, don't lock shift. */
-       if (_shift_pressed && handled) {
+       if ((_shift_pressed > 0) && handled) {
                _shift_connection.disconnect ();
                _shift_lock = false;
        }
@@ -656,12 +694,12 @@ FaderPort8::get_state ()
                        continue;
                }
                XMLNode* btn = new XMLNode (X_("Button"));
-               btn->add_property (X_("id"), name);
+               btn->set_property (X_("id"), name);
                if (!i->second.action(true).empty ()) {
-                       btn->add_property ("press", i->second.action(true)._action_name);
+                       btn->set_property ("press", i->second.action(true)._action_name);
                }
                if (!i->second.action(false).empty ()) {
-                       btn->add_property ("release", i->second.action(false)._action_name);
+                       btn->set_property ("release", i->second.action(false)._action_name);
                }
                node.add_child_nocopy (*btn);
        }
@@ -705,23 +743,23 @@ FaderPort8::set_state (const XMLNode& node, int version)
                if ((*n)->name() != X_("Button")) {
                        continue;
                }
-               XMLProperty const* prop = (*n)->property (X_("id"));
-               if (!prop) {
+
+               std::string id_str;
+               if (!(*n)->get_property (X_("id"), id_str)) {
                        continue;
                }
 
                FP8Controls::ButtonId id;
-               if (!_ctrls.button_name_to_enum (prop->value(), id)) {
+               if (!_ctrls.button_name_to_enum (id_str, id)) {
                        continue;
                }
 
-               prop = (*n)->property (X_("press"));
-               if (prop) {
-                       set_button_action (id, true, prop->value());
+               std::string action_str;
+               if ((*n)->get_property (X_("press"), action_str)) {
+                       set_button_action (id, true, action_str);
                }
-               prop = (*n)->property (X_("release"));
-               if (prop) {
-                       set_button_action (id, false, prop->value());
+               if ((*n)->get_property (X_("release"), action_str)) {
+                       set_button_action (id, false, action_str);
                }
        }
 
@@ -798,7 +836,7 @@ static bool flt_instrument (boost::shared_ptr<Stripable> s) {
 
 struct FP8SortByNewDisplayOrder
 {
-       // return (a < b)
+       // return strict (a < b)
        bool operator () (const boost::shared_ptr<Stripable> & a, const boost::shared_ptr<Stripable> & b) const
        {
                if (a->presentation_info().flags () == b->presentation_info().flags ()) {
@@ -808,36 +846,34 @@ struct FP8SortByNewDisplayOrder
                int cmp_a = 0;
                int cmp_b = 0;
 
+               // see also gtk2_ardour/route_sorter.h
                if (a->presentation_info().flags () & ARDOUR::PresentationInfo::VCA) {
-                       cmp_a = 1;
+                       cmp_a = 2;
                }
 #ifdef MIXBUS
                else if (a->presentation_info().flags () & ARDOUR::PresentationInfo::MasterOut) {
                        cmp_a = 3;
                }
                else if (a->presentation_info().flags () & ARDOUR::PresentationInfo::Mixbus || a->mixbus()) {
-                       cmp_a = 2;
+                       cmp_a = 1;
                }
 #endif
 
                if (b->presentation_info().flags () & ARDOUR::PresentationInfo::VCA) {
-                       cmp_b = 1;
+                       cmp_b = 2;
                }
 #ifdef MIXBUS
                else if (b->presentation_info().flags () & ARDOUR::PresentationInfo::MasterOut) {
                        cmp_b = 3;
                }
                else if (b->presentation_info().flags () & ARDOUR::PresentationInfo::Mixbus || b->mixbus()) {
-                       cmp_b = 2;
+                       cmp_b = 1;
                }
 #endif
 
-#ifdef MIXBUS
-               // this can happen with older MB sessions (no PresentationInfo::Mixbus flag)
                if (cmp_a == cmp_b) {
                        return a->presentation_info().order() < b->presentation_info().order();
                }
-#endif
                return cmp_a < cmp_b;
        }
 };
@@ -959,34 +995,59 @@ FaderPort8::assign_stripables (bool select_only)
        }
 }
 
+/* ****************************************************************************
+ * Plugin selection and parameters
+ */
+
 void
 FaderPort8::assign_processor_ctrls ()
 {
-       int n_parameters = _proc_params.size();
-       if (n_parameters == 0) {
+       if (_proc_params.size() == 0) {
                _ctrls.set_fader_mode (ModeTrack);
                return;
        }
        set_periodic_display_mode (FP8Strip::PluginParam);
 
+       std::vector <ProcessorCtrl*> toggle_params;
+       std::vector <ProcessorCtrl*> slider_params;
+
+       for ( std::list <ProcessorCtrl>::iterator i = _proc_params.begin(); i != _proc_params.end(); ++i) {
+               if ((*i).ac->toggled()) {
+                       toggle_params.push_back (&(*i));
+               } else {
+                       slider_params.push_back (&(*i));
+               }
+       }
+
+       int n_parameters = std::max (toggle_params.size(), slider_params.size());
+
        _parameter_off = std::min (_parameter_off, n_parameters - 8);
        _parameter_off = std::max (0, _parameter_off);
 
-       int skip = _parameter_off;
        uint8_t id = 0;
-       for ( std::list <ProcessorCtrl>::iterator i = _proc_params.begin(); i != _proc_params.end(); ++i) {
-               if (skip > 0) {
-                       --skip;
-                       continue;
+       for (size_t i = _parameter_off; i < (size_t)n_parameters; ++i) {
+               if (i >= toggle_params.size ()) {
+                       _ctrls.strip(id).unset_controllables (FP8Strip::CTRL_ALL & ~FP8Strip::CTRL_FADER & ~FP8Strip::CTRL_TEXT0 & ~FP8Strip::CTRL_TEXT1);
+               }
+               else if (i >= slider_params.size ()) {
+                       _ctrls.strip(id).unset_controllables (FP8Strip::CTRL_ALL & ~FP8Strip::CTRL_SELECT & ~FP8Strip::CTRL_TEXT3);
+               } else {
+                       _ctrls.strip(id).unset_controllables (FP8Strip::CTRL_ALL & ~FP8Strip::CTRL_FADER & ~FP8Strip::CTRL_TEXT0 & ~FP8Strip::CTRL_TEXT1 & ~FP8Strip::CTRL_SELECT & ~FP8Strip::CTRL_TEXT3);
                }
-               _ctrls.strip(id).unset_controllables (FP8Strip::CTRL_ALL & ~FP8Strip::CTRL_FADER & ~FP8Strip::CTRL_TEXT0);
-               _ctrls.strip(id).set_fader_controllable ((*i).ac);
-               _ctrls.strip(id).set_text_line (0, (*i).name);
 
+               if (i < slider_params.size ()) {
+                       _ctrls.strip(id).set_fader_controllable (slider_params[i]->ac);
+                       _ctrls.strip(id).set_text_line (0, slider_params[i]->name);
+               }
+               if (i < toggle_params.size ()) {
+                       _ctrls.strip(id).set_select_controllable (toggle_params[i]->ac);
+                       _ctrls.strip(id).set_text_line (3, toggle_params[i]->name, true);
+               }
                 if (++id == 8) {
                         break;
                 }
        }
+
        // clear remaining
        for (; id < 8; ++id) {
                _ctrls.strip(id).unset_controllables ();
@@ -1001,8 +1062,17 @@ FaderPort8::build_well_known_processor_ctrls (boost::shared_ptr<Stripable> s, bo
        _proc_params.clear ();
        if (eq) {
                int cnt = s->eq_band_cnt();
-               PUSH_BACK_NON_NULL ("Enable", s->eq_enable_controllable ());
-               PUSH_BACK_NON_NULL ("HPF", s->eq_hpf_controllable ());
+
+#ifdef MIXBUS32C
+               PUSH_BACK_NON_NULL ("Flt In", s->filter_enable_controllable ());
+               PUSH_BACK_NON_NULL ("HP Freq", s->eq_hpf_controllable ());  
+               PUSH_BACK_NON_NULL ("LP Freq", s->eq_lpf_controllable ());
+               PUSH_BACK_NON_NULL ("EQ In", s->eq_enable_controllable ());
+#elif defined (MIXBUS)
+               PUSH_BACK_NON_NULL ("EQ In", s->eq_enable_controllable ());
+               PUSH_BACK_NON_NULL ("HP Freq", s->eq_hpf_controllable ());  
+#endif
+
                for (int band = 0; band < cnt; ++band) {
                        std::string bn = s->eq_band_name (band);
                        PUSH_BACK_NON_NULL (string_compose ("Gain %1", bn), s->eq_gain_controllable (band));
@@ -1011,7 +1081,7 @@ FaderPort8::build_well_known_processor_ctrls (boost::shared_ptr<Stripable> s, bo
                        PUSH_BACK_NON_NULL (string_compose ("Shape %1", bn), s->eq_shape_controllable (band));
                }
        } else {
-               PUSH_BACK_NON_NULL ("Enable", s->comp_enable_controllable ());
+               PUSH_BACK_NON_NULL ("Comp In", s->comp_enable_controllable ());
                PUSH_BACK_NON_NULL ("Threshold", s->comp_threshold_controllable ());
                PUSH_BACK_NON_NULL ("Speed", s->comp_speed_controllable ());
                PUSH_BACK_NON_NULL ("Mode", s->comp_mode_controllable ());
@@ -1110,12 +1180,16 @@ FaderPort8::spill_plugins ()
 
        for (uint32_t i = 0; 0 != (proc = r->nth_plugin (i)); ++i) {
                if (!proc->display_to_user ()) {
+#ifdef MIXBUS
+                       boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert> (proc);
+                       if (pi->is_channelstrip ()) // don't skip MB PRE
+#endif
                        continue;
                }
                int n_controls = 0;
                set<Evoral::Parameter> p = proc->what_can_be_automated ();
-               for (set<Evoral::Parameter>::iterator i = p.begin(); i != p.end(); ++i) {
-                       std::string n = proc->describe_parameter (*i);
+               for (set<Evoral::Parameter>::iterator j = p.begin(); j != p.end(); ++j) {
+                       std::string n = proc->describe_parameter (*j);
                        if (n == "hidden") {
                                continue;
                        }
@@ -1161,7 +1235,7 @@ FaderPort8::spill_plugins ()
                        break;
                }
                boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert> (proc);
-               boost::function<void ()> cb (boost::bind (&FaderPort8::select_plugin, this, i));
+               boost::function<void ()> cb (boost::bind (&FaderPort8::select_plugin, this, procs[i]));
 
                _ctrls.strip(id).unset_controllables (FP8Strip::CTRL_ALL & ~FP8Strip::CTRL_TEXT & ~FP8Strip::CTRL_SELECT);
                _ctrls.strip(id).set_select_cb (cb);
@@ -1213,6 +1287,10 @@ FaderPort8::spill_plugins ()
        assert (id == 8);
 }
 
+/* ****************************************************************************
+ * Aux Sends and Mixbus assigns
+ */
+
 void
 FaderPort8::assign_sends ()
 {
@@ -1255,7 +1333,6 @@ FaderPort8::assign_sends ()
                _ctrls.strip(id).set_fader_controllable (send);
                _ctrls.strip(id).set_text_line (0, s->send_name (i));
                _ctrls.strip(id).set_mute_controllable (s->send_enable_controllable (i));
-               _ctrls.strip(id).set_solo_controllable (s->master_send_enable_controllable ()); // XXX
 
                if (++id == 8) {
                        break;
@@ -1265,17 +1342,18 @@ FaderPort8::assign_sends ()
        for (; id < 8; ++id) {
                _ctrls.strip(id).unset_controllables (FP8Strip::CTRL_ALL & ~FP8Strip::CTRL_TEXT3 & ~FP8Strip::CTRL_SELECT);
        }
+#ifdef MIXBUS // master-assign on last solo
+       _ctrls.strip(7).set_solo_controllable (s->master_send_enable_controllable ());
+#endif
        /* set select buttons */
+       assigned_stripable_connections.drop_connections ();
+       _assigned_strips.clear ();
        assign_stripables (true);
 }
 
-void
-FaderPort8::set_periodic_display_mode (FP8Strip::DisplayMode m)
-{
-       for (uint8_t id = 0; id < 8; ++id) {
-               _ctrls.strip(id).set_periodic_display_mode (m);
-       }
-}
+/* ****************************************************************************
+ * Main stripable assignment (dispatch depending on mode)
+ */
 
 void
 FaderPort8::assign_strips (bool reset_bank)
@@ -1284,15 +1362,15 @@ FaderPort8::assign_strips (bool reset_bank)
                _channel_off = 0;
        }
 
-       _assigned_strips.clear ();
        assigned_stripable_connections.drop_connections ();
+       _assigned_strips.clear ();
 
        FaderMode fadermode = _ctrls.fader_mode ();
        switch (fadermode) {
                case ModeTrack:
                case ModePan:
                        assign_stripables ();
-                       gui_track_selection_changed (); // update selection, automation-state
+                       stripable_selection_changed (); // update selection, automation-state
                        break;
                case ModePlugins:
                        if (_proc_params.size() > 0) {
@@ -1307,6 +1385,17 @@ FaderPort8::assign_strips (bool reset_bank)
        }
 }
 
+/* ****************************************************************************
+ * some helper functions
+ */
+
+void
+FaderPort8::set_periodic_display_mode (FP8Strip::DisplayMode m)
+{
+       for (uint8_t id = 0; id < 8; ++id) {
+               _ctrls.strip(id).set_periodic_display_mode (m);
+       }
+}
 
 void
 FaderPort8::drop_ctrl_connections ()
@@ -1316,6 +1405,46 @@ FaderPort8::drop_ctrl_connections ()
        _showing_well_known = 0;
 }
 
+/* functor for FP8Strip's select button */
+void
+FaderPort8::select_strip (boost::weak_ptr<Stripable> ws)
+{
+       boost::shared_ptr<Stripable> s = ws.lock();
+       if (!s) {
+               return;
+       }
+#if 1 /* single exclusive selection by default, toggle via shift */
+       if (shift_mod ()) {
+               ToggleStripableSelection (s);
+       } else {
+               SetStripableSelection (s);
+       }
+#else
+       /* tri-state selection: This allows to set the "first selected"
+        * with a single click without clearing the selection.
+        * Single de/select via shift.
+        */
+       if (shift_mod ()) {
+               if (s->is_selected ()) {
+                       RemoveStripableFromSelection (s);
+               } else {
+                       SetStripableSelection (s);
+               }
+               return;
+       }
+       if (s->is_selected () && s != first_selected_stripable ()) {
+               set_first_selected_stripable (s);
+               stripable_selection_changed ();
+       } else {
+               ToggleStripableSelection (s);
+       }
+#endif
+}
+
+/* ****************************************************************************
+ * Assigned Stripable Callbacks
+ */
+
 void
 FaderPort8::notify_fader_mode_changed ()
 {
@@ -1346,10 +1475,6 @@ FaderPort8::notify_fader_mode_changed ()
        notify_automation_mode_changed ();
 }
 
-/* ****************************************************************************
- * Assigned Stripable Callbacks
- */
-
 void
 FaderPort8::notify_stripable_added_or_removed ()
 {
@@ -1363,30 +1488,6 @@ FaderPort8::notify_stripable_added_or_removed ()
        assign_strips (false);
 }
 
-/* functor for FP8Strip's select button */
-void
-FaderPort8::select_strip (boost::weak_ptr<Stripable> ws)
-{
-       boost::shared_ptr<Stripable> s = ws.lock();
-       if (!s) {
-               return;
-       }
-       if (shift_mod ()) {
-               if (s->is_selected ()) {
-                       RemoveStripableFromSelection (s);
-               } else {
-                       SetStripableSelection (s);
-               }
-               return;
-       }
-       if (s->is_selected () && s != first_selected_stripable ()) {
-               set_first_selected_stripable (s);
-               gui_track_selection_changed ();
-       } else {
-               ToggleStripableSelection (s);
-       }
-}
-
 /* called from static PresentationInfo::Change */
 void
 FaderPort8::notify_pi_property_changed (const PropertyChange& what_changed)
@@ -1408,7 +1509,19 @@ FaderPort8::notify_stripable_property_changed (boost::weak_ptr<Stripable> ws, co
                assert (0); // this should not happen
                return;
        }
-       assert (_assigned_strips.find (s) != _assigned_strips.end());
+       if (_assigned_strips.find (s) == _assigned_strips.end()) {
+               /* it can happen that signal emission is delayed.
+                * A signal may already be in the queue but the
+                * _assigned_strips has meanwhile changed.
+                *
+                * before _assigned_strips changes, the connections are dropped
+                * but that does not seem to invalidate pending requests :(
+                *
+                * Seen when creating a new MB session and Mixbusses are added
+                * incrementally.
+                */
+               return;
+       }
        uint8_t id = _assigned_strips[s];
 
        if (what_changed.contains (Properties::color)) {
@@ -1418,10 +1531,11 @@ FaderPort8::notify_stripable_property_changed (boost::weak_ptr<Stripable> ws, co
        if (what_changed.contains (Properties::name)) {
                switch (_ctrls.fader_mode ()) {
                        case ModeSend:
-                               _ctrls.strip(id).set_text_line (0, s->name());
+                               _ctrls.strip(id).set_text_line (3, s->name(), true);
+                               break;
                        case ModeTrack:
                        case ModePan:
-                               _ctrls.strip(id).set_text_line (3, s->name(), true);
+                               _ctrls.strip(id).set_text_line (0, s->name());
                                break;
                        case ModePlugins:
                                assert (0);
@@ -1431,8 +1545,14 @@ FaderPort8::notify_stripable_property_changed (boost::weak_ptr<Stripable> ws, co
 }
 
 void
-FaderPort8::gui_track_selection_changed (/*ARDOUR::StripableNotificationListPtr*/)
+FaderPort8::stripable_selection_changed ()
 {
+       if (!_device_active) {
+               /* this can be called anytime from the static
+                * ControlProtocol::StripableSelectionChanged
+                */
+               return;
+       }
        automation_state_connections.drop_connections();
 
        switch (_ctrls.fader_mode ()) {
@@ -1574,7 +1694,6 @@ FaderPort8::bank_param (bool down, bool page)
        if (down) {
                dt *= -1;
        }
-       _channel_off += dt;
        switch (_ctrls.fader_mode ()) {
                case ModePlugins:
                        if (_proc_params.size() > 0) {
@@ -1586,6 +1705,7 @@ FaderPort8::bank_param (bool down, bool page)
                        }
                        break;
                case ModeSend:
+                       _plugin_off += dt;
                        assign_sends ();
                        break;
                default: