change exposed type of various objects' gain controls; remove Amp::gain() as a shortcut
[ardour.git] / libs / ardour / session.cc
index 856e89eced51d6a999d4101519c615658ee6bd0d..75547b534897c5d077544c727ac3775daedb5fee 100644 (file)
@@ -71,6 +71,7 @@
 #include "ardour/engine_state_controller.h"
 #endif
 #include "ardour/filename_extensions.h"
+#include "ardour/gain_control.h"
 #include "ardour/graph.h"
 #include "ardour/midiport_manager.h"
 #include "ardour/scene_changer.h"
@@ -183,6 +184,7 @@ Session::Session (AudioEngine &eng,
        , _worst_track_latency (0)
        , _have_captured (false)
        , _non_soloed_outs_muted (false)
+       , _listening (false)
        , _listen_cnt (0)
        , _solo_isolated_cnt (0)
        , _writable (false)
@@ -317,6 +319,11 @@ Session::Session (AudioEngine &eng,
                        throw SessionException (_("Cannot connect to audio/midi engine"));
                }
 
+               // set samplerate for plugins added early
+               // e.g from templates or MB channelstrip
+               set_block_size (_engine.samples_per_cycle());
+               set_frame_rate (_engine.sample_rate());
+
                if (create (mix_template, bus_profile)) {
                        destroy ();
                        throw SessionException (_("Session initialization failed"));
@@ -727,8 +734,12 @@ void
 Session::setup_click ()
 {
        _clicking = false;
+
+       boost::shared_ptr<AutomationList> gl (new AutomationList (Evoral::Parameter (GainAutomation)));
+       boost::shared_ptr<GainControl> gain_control = boost::shared_ptr<GainControl> (new GainControl (*this, Evoral::Parameter(GainAutomation), gl));
+
        _click_io.reset (new ClickIO (*this, X_("Click")));
-       _click_gain.reset (new Amp (*this));
+       _click_gain.reset (new Amp (*this, _("Fader"), gain_control, true));
        _click_gain->activate ();
        if (state_tree) {
                setup_click_state (state_tree->root());
@@ -1017,6 +1028,7 @@ Session::remove_monitor_section ()
        if (auditioner) {
                auditioner->connect ();
        }
+       Config->ParameterChanged ("use-monitor-bus");
 }
 
 void
@@ -1168,6 +1180,7 @@ Session::add_monitor_section ()
        if (auditioner) {
                auditioner->connect ();
        }
+       Config->ParameterChanged ("use-monitor-bus");
 }
 
 void
@@ -1819,6 +1832,19 @@ Session::enable_record ()
        }
 }
 
+void
+Session::set_all_tracks_record_enabled (bool enable )
+{
+       boost::shared_ptr<RouteList> rl = routes.reader();
+       for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
+               boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
+               if (tr) {
+                       tr->set_record_enabled (enable, Controllable::NoGroup);
+               }
+       }
+}
+
+
 void
 Session::disable_record (bool rt_context, bool force)
 {
@@ -2867,7 +2893,7 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod
                                //  0 for Stereo Out mode
                                //  0 Multi Out mode
                                if (Config->get_output_auto_connect() & AutoConnectMaster) {
-                                       track->set_gain (dB_to_coefficient (0), 0);
+                                       track->set_gain (dB_to_coefficient (0), Controllable::NoGroup);
                                }
                        }
 
@@ -3255,10 +3281,10 @@ Session::add_routes_inner (RouteList& new_routes, bool input_auto_connect, bool
                boost::weak_ptr<Route> wpr (*x);
                boost::shared_ptr<Route> r (*x);
 
-               r->listen_changed.connect_same_thread (*this, boost::bind (&Session::route_listen_changed, this, _2, wpr));
-               r->solo_changed.connect_same_thread (*this, boost::bind (&Session::route_solo_changed, this, _1, _3, wpr));
-               r->solo_isolated_changed.connect_same_thread (*this, boost::bind (&Session::route_solo_isolated_changed, this, _1, wpr));
-               r->mute_changed.connect_same_thread (*this, boost::bind (&Session::route_mute_changed, this, _1));
+               r->listen_changed.connect_same_thread (*this, boost::bind (&Session::route_listen_changed, this, _1, wpr));
+               r->solo_changed.connect_same_thread (*this, boost::bind (&Session::route_solo_changed, this, _1, _2, wpr));
+               r->solo_isolated_changed.connect_same_thread (*this, boost::bind (&Session::route_solo_isolated_changed, this, wpr));
+               r->mute_changed.connect_same_thread (*this, boost::bind (&Session::route_mute_changed, this));
                r->output()->changed.connect_same_thread (*this, boost::bind (&Session::set_worst_io_latencies_x, this, _1, _2));
                r->processors_changed.connect_same_thread (*this, boost::bind (&Session::route_processors_changed, this, _1));
 
@@ -3330,7 +3356,7 @@ Session::globally_set_send_gains_to_zero (boost::shared_ptr<Route> dest)
 
        for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
                if ((s = (*i)->internal_send_for (dest)) != 0) {
-                       s->amp()->gain_control()->set_value (GAIN_COEFF_ZERO);
+                       s->amp()->gain_control()->set_value (GAIN_COEFF_ZERO, Controllable::NoGroup);
                }
        }
 }
@@ -3343,7 +3369,7 @@ Session::globally_set_send_gains_to_unity (boost::shared_ptr<Route> dest)
 
        for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
                if ((s = (*i)->internal_send_for (dest)) != 0) {
-                       s->amp()->gain_control()->set_value (GAIN_COEFF_UNITY);
+                       s->amp()->gain_control()->set_value (GAIN_COEFF_UNITY, Controllable::NoGroup);
                }
        }
 }
@@ -3356,7 +3382,7 @@ Session::globally_set_send_gains_from_track(boost::shared_ptr<Route> dest)
 
        for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
                if ((s = (*i)->internal_send_for (dest)) != 0) {
-                       s->amp()->gain_control()->set_value ((*i)->gain_control()->get_value());
+                       s->amp()->gain_control()->set_value ((*i)->gain_control()->get_value(), Controllable::NoGroup);
                }
        }
 }
@@ -3424,7 +3450,7 @@ Session::remove_routes (boost::shared_ptr<RouteList> routes_to_remove)
                                continue;
                        }
 
-                       (*iter)->set_solo (false, this);
+                       (*iter)->set_solo (false, Controllable::NoGroup);
 
                        rs->remove (*iter);
 
@@ -3532,13 +3558,13 @@ Session::remove_route (boost::shared_ptr<Route> route)
 }
 
 void
-Session::route_mute_changed (void* /*src*/)
+Session::route_mute_changed ()
 {
        set_dirty ();
 }
 
 void
-Session::route_listen_changed (bool group_override, boost::weak_ptr<Route> wpr)
+Session::route_listen_changed (Controllable::GroupControlDisposition group_override, boost::weak_ptr<Route> wpr)
 {
        boost::shared_ptr<Route> route = wpr.lock();
        if (!route) {
@@ -3549,18 +3575,32 @@ Session::route_listen_changed (bool group_override, boost::weak_ptr<Route> wpr)
        if (route->listening_via_monitor ()) {
 
                if (Config->get_exclusive_solo()) {
-                       /* new listen: disable all other listen, except solo-grouped channels */
+
                        RouteGroup* rg = route->route_group ();
-                       bool leave_group_alone = (rg && rg->is_active() && rg->is_solo());
-                       if (group_override && rg) {
-                               leave_group_alone = !leave_group_alone;
-                       }
+                       const bool group_already_accounted_for = route->use_group (group_override, &RouteGroup::is_solo);
+
                        boost::shared_ptr<RouteList> r = routes.reader ();
+
                        for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
-                               if ((*i) == route || (*i)->solo_isolated() || (*i)->is_master() || (*i)->is_monitor() || (*i)->is_auditioner() || (leave_group_alone && ((*i)->route_group() == rg))) {
+                               if ((*i) == route) {
+                                       /* already changed */
+                                       continue;
+                               }
+
+                               if ((*i)->solo_isolated() || (*i)->is_master() || (*i)->is_monitor() || (*i)->is_auditioner()) {
+                                       /* route does not get solo propagated to it */
+                                       continue;
+                               }
+
+                               if ((group_already_accounted_for && (*i)->route_group() && (*i)->route_group() == rg)) {
+                                       /* this route is a part of the same solo group as the route
+                                        * that was changed. Changing that route did change or will
+                                        * change all group members appropriately, so we can ignore it
+                                        * here
+                                        */
                                        continue;
                                }
-                               (*i)->set_listen (false, this, group_override);
+                               (*i)->set_listen (false, Controllable::NoGroup);
                        }
                }
 
@@ -3574,7 +3614,7 @@ Session::route_listen_changed (bool group_override, boost::weak_ptr<Route> wpr)
        update_route_solo_state ();
 }
 void
-Session::route_solo_isolated_changed (void* /*src*/, boost::weak_ptr<Route> wpr)
+Session::route_solo_isolated_changed (boost::weak_ptr<Route> wpr)
 {
        boost::shared_ptr<Route> route = wpr.lock ();
 
@@ -3604,7 +3644,7 @@ Session::route_solo_isolated_changed (void* /*src*/, boost::weak_ptr<Route> wpr)
 }
 
 void
-Session::route_solo_changed (bool self_solo_change, bool group_override,  boost::weak_ptr<Route> wpr)
+Session::route_solo_changed (bool self_solo_change, Controllable::GroupControlDisposition group_override,  boost::weak_ptr<Route> wpr)
 {
        DEBUG_TRACE (DEBUG::Solo, string_compose ("route solo change, self = %1\n", self_solo_change));
 
@@ -3625,21 +3665,51 @@ Session::route_solo_changed (bool self_solo_change, bool group_override,  boost:
                delta = -1;
        }
 
+       /* the route may be a member of a group that has shared-solo
+        * semantics. If so, then all members of that group should follow the
+        * solo of the changed route. But ... this is optional, controlled by a
+        * Controllable::GroupControlDisposition.
+        *
+        * The first argument to the signal that this method is connected to is the
+        * GroupControlDisposition value that was used to change solo.
+        *
+        * If the solo change was done with group semantics (either InverseGroup
+        * (force the entire group to change even if the group shared solo is
+        * disabled) or UseGroup (use the group, which may or may not have the
+        * shared solo property enabled)) then as we propagate the change to
+        * the entire session we should IGNORE THE GROUP that the changed route
+        * belongs to.
+        */
+
        RouteGroup* rg = route->route_group ();
-       bool leave_group_alone = (rg && rg->is_active() && rg->is_solo());
-       if (group_override && rg) {
-               leave_group_alone = !leave_group_alone;
-       }
+       const bool group_already_accounted_for = route->use_group (group_override, &RouteGroup::is_solo);
+
        if (delta == 1 && Config->get_exclusive_solo()) {
 
                /* new solo: disable all other solos, but not the group if its solo-enabled */
 
                for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
-                       if ((*i) == route || (*i)->is_master() || (*i)->is_monitor() || (*i)->is_auditioner() ||
-                           (leave_group_alone && ((*i)->route_group() == rg))) {
+
+                       if ((*i) == route) {
+                               /* already changed */
+                               continue;
+                       }
+
+                       if ((*i)->solo_isolated() || (*i)->is_master() || (*i)->is_monitor() || (*i)->is_auditioner()) {
+                               /* route does not get solo propagated to it */
+                               continue;
+                       }
+
+                       if ((group_already_accounted_for && (*i)->route_group() && (*i)->route_group() == rg)) {
+                               /* this route is a part of the same solo group as the route
+                                * that was changed. Changing that route did change or will
+                                * change all group members appropriately, so we can ignore it
+                                * here
+                                */
                                continue;
                        }
-                       (*i)->set_solo (false, this, group_override);
+
+                       (*i)->set_solo (false, group_override);
                }
        }
 
@@ -3653,8 +3723,22 @@ Session::route_solo_changed (bool self_solo_change, bool group_override,  boost:
                bool via_sends_only;
                bool in_signal_flow;
 
-               if ((*i) == route || (*i)->is_master() || (*i)->is_monitor() || (*i)->is_auditioner() ||
-                   (leave_group_alone && ((*i)->route_group() == rg))) {
+               if ((*i) == route) {
+                       /* already changed */
+                       continue;
+               }
+
+               if ((*i)->solo_isolated() || (*i)->is_master() || (*i)->is_monitor() || (*i)->is_auditioner()) {
+                       /* route does not get solo propagated to it */
+                       continue;
+               }
+
+               if ((group_already_accounted_for && (*i)->route_group() && (*i)->route_group() == rg)) {
+                       /* this route is a part of the same solo group as the route
+                        * that was changed. Changing that route did change or will
+                        * change all group members appropriately, so we can ignore it
+                        * here
+                        */
                        continue;
                }
 
@@ -3720,7 +3804,7 @@ Session::route_solo_changed (bool self_solo_change, bool group_override,  boost:
        for (RouteList::iterator i = uninvolved.begin(); i != uninvolved.end(); ++i) {
                DEBUG_TRACE (DEBUG::Solo, string_compose ("mute change for %1, which neither feeds or is fed by %2\n", (*i)->name(), route->name()));
                (*i)->act_on_mute ();
-               (*i)->mute_changed (this);
+               (*i)->mute_changed ();
        }
 
        SoloChanged (); /* EMIT SIGNAL */
@@ -3733,6 +3817,7 @@ Session::update_route_solo_state (boost::shared_ptr<RouteList> r)
        /* now figure out if anything that matters is soloed (or is "listening")*/
 
        bool something_soloed = false;
+       bool something_listening = false;
        uint32_t listeners = 0;
        uint32_t isolated = 0;
 
@@ -3748,8 +3833,9 @@ Session::update_route_solo_state (boost::shared_ptr<RouteList> r)
                if (!(*i)->is_auditioner() && (*i)->listening_via_monitor()) {
                        if (Config->get_solo_control_is_listen_control()) {
                                listeners++;
+                               something_listening = true;
                        } else {
-                               (*i)->set_listen (false, this);
+                               (*i)->set_listen (false, Controllable::NoGroup);
                        }
                }
 
@@ -3763,6 +3849,11 @@ Session::update_route_solo_state (boost::shared_ptr<RouteList> r)
                SoloActive (_non_soloed_outs_muted); /* EMIT SIGNAL */
        }
 
+       if (something_listening != _listening) {
+               _listening = something_listening;
+               SoloActive (_listening);
+       }
+
        _listen_cnt = listeners;
 
        if (isolated != _solo_isolated_cnt) {