- gain_t current_value;
- std::pair<Masters::iterator,bool> res;
-
- {
- Glib::Threads::RWLock::WriterLock lm (master_lock);
- current_value = get_value_locked ();
-
- /* ratio will be recomputed below */
-
- res = _masters.insert (make_pair<uint32_t,MasterRecord> (vca->number(), MasterRecord (vca->control(), 0.0)));
-
- if (res.second) {
-
- recompute_masters_ratios (current_value);
-
- /* note that we bind @param m as a weak_ptr<GainControl>, thus
- avoiding holding a reference to the control in the binding
- itself.
- */
-
- vca->DropReferences.connect_same_thread (masters_connections, boost::bind (&GainControl::master_going_away, this, vca));
-
- /* Store the connection inside the MasterRecord, so that when we destroy it, the connection is destroyed
- and we no longer hear about changes to the VCA.
- */
-
- vca->control()->Changed.connect_same_thread (res.first->second.connection, boost::bind (&PBD::Signal0<void>::operator(), &Changed));
- }
- }
-
- if (res.second) {
- VCAStatusChange (); /* EMIT SIGNAL */
- }
-}
-
-void
-GainControl::master_going_away (boost::weak_ptr<VCA> wv)
-{
- boost::shared_ptr<VCA> v = wv.lock();
- if (v) {
- remove_master (v);
- }
-}
-
-void
-GainControl::remove_master (boost::shared_ptr<VCA> vca)
-{
- gain_t current_value;
- Masters::size_type erased = 0;
-
- {
- Glib::Threads::RWLock::WriterLock lm (master_lock);
- current_value = get_value_locked ();
- erased = _masters.erase (vca->number());
- if (erased) {
- recompute_masters_ratios (current_value);
- }
- }
-
- if (erased) {
- VCAStatusChange (); /* EMIT SIGNAL */
- }
-}
-
-void
-GainControl::clear_masters ()
-{
- bool had_masters = false;
-
- {
- Glib::Threads::RWLock::WriterLock lm (master_lock);
- if (!_masters.empty()) {
- had_masters = true;
- }
- _masters.clear ();
- }
-
- if (had_masters) {
- VCAStatusChange (); /* EMIT SIGNAL */
- }
-}
-
-void
-GainControl::recompute_masters_ratios (double val)
-{
- /* Master WRITE lock must be held */
-
- /* V' is the new gain value for this
-
- Mv(n) is the return value of ::get_value() for the n-th master
- Mr(n) is the return value of ::ratio() for the n-th master record
-
- the slave should return V' on the next call to ::get_value().
-
- but the value is determined by the masters, so we know:
-
- V' = (Mv(1) * Mr(1)) * (Mv(2) * Mr(2)) * ... * (Mv(n) * Mr(n))
-
- hence:
-
- Mr(1) * Mr(2) * ... * (Mr(n) = V' / (Mv(1) * Mv(2) * ... * Mv(n))
-
- if we make all ratios equal (i.e. each master contributes the same
- fraction of its own gain level to make the final slave gain), then we
- have:
-
- pow (Mr(n), n) = V' / (Mv(1) * Mv(2) * ... * Mv(n))
-
- which gives
-
- Mr(n) = pow ((V' / (Mv(1) * Mv(2) * ... * Mv(n))), 1/n)
-
- Mr(n) is the new ratio number for the slaves
- */
-
-
- const double nmasters = _masters.size();
- double masters_total_gain_coefficient = 1.0;
-
- for (Masters::iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
- masters_total_gain_coefficient *= mr->second.master()->get_value();
- }
-
- const double new_universal_ratio = pow ((val / masters_total_gain_coefficient), (1.0/nmasters));
-
- for (Masters::iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
- mr->second.reset_ratio (new_universal_ratio);