The #end should be #endif
[ardour.git] / libs / surfaces / faderport8 / faderport8.cc
index 2eb24a15543ba31445927ed1569ef1288cd59ea5..7a2448e939f8088af071c5d91644a39d4da5df87 100644 (file)
@@ -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));
 }
@@ -265,13 +267,14 @@ FaderPort8::set_active (bool yn)
 void
 FaderPort8::close ()
 {
+       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,6 +293,12 @@ 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.
 
@@ -336,8 +345,18 @@ FaderPort8::disconnected ()
        }
 }
 
+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");
@@ -350,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;
@@ -382,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;
        }
 
@@ -665,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);
        }
@@ -714,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);
                }
        }
 
@@ -807,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 ()) {
@@ -817,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;
        }
 };
@@ -968,6 +995,10 @@ FaderPort8::assign_stripables (bool select_only)
        }
 }
 
+/* ****************************************************************************
+ * Plugin selection and parameters
+ */
+
 void
 FaderPort8::assign_processor_ctrls ()
 {
@@ -1031,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));
@@ -1041,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 ());
@@ -1148,8 +1188,8 @@ FaderPort8::spill_plugins ()
                }
                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;
                        }
@@ -1247,6 +1287,10 @@ FaderPort8::spill_plugins ()
        assert (id == 8);
 }
 
+/* ****************************************************************************
+ * Aux Sends and Mixbus assigns
+ */
+
 void
 FaderPort8::assign_sends ()
 {
@@ -1307,13 +1351,9 @@ FaderPort8::assign_sends ()
        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)
@@ -1330,7 +1370,7 @@ FaderPort8::assign_strips (bool reset_bank)
                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) {
@@ -1345,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 ()
@@ -1354,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 ()
 {
@@ -1384,10 +1475,6 @@ FaderPort8::notify_fader_mode_changed ()
        notify_automation_mode_changed ();
 }
 
-/* ****************************************************************************
- * Assigned Stripable Callbacks
- */
-
 void
 FaderPort8::notify_stripable_added_or_removed ()
 {
@@ -1401,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)
@@ -1482,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 ()) {