2 Copyright (C) 2006-2016 Paul Davis
4 This program is free software; you can redistribute it and/or modify it
5 under the terms of the GNU General Public License as published by the Free
6 Software Foundation; either version 2 of the License, or (at your option)
9 This program is distributed in the hope that it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 You should have received a copy of the GNU General Public License along
15 with this program; if not, write to the Free Software Foundation, Inc.,
16 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include "pbd/convert.h"
22 #include "pbd/strsplit.h"
24 #include "ardour/dB.h"
25 #include "ardour/gain_control.h"
26 #include "ardour/session.h"
27 #include "ardour/vca.h"
28 #include "ardour/vca_manager.h"
32 using namespace ARDOUR;
35 GainControl::GainControl (Session& session, const Evoral::Parameter ¶m, boost::shared_ptr<AutomationList> al)
36 : AutomationControl (session, param, ParameterDescriptor(param),
37 al ? al : boost::shared_ptr<AutomationList> (new AutomationList (param)),
38 param.type() == GainAutomation ? X_("gaincontrol") : X_("trimcontrol")) {
40 alist()->reset_default (1.0);
42 lower_db = accurate_coefficient_to_dB (_desc.lower);
43 range_db = accurate_coefficient_to_dB (_desc.upper) - lower_db;
47 GainControl::get_value () const
49 Glib::Threads::RWLock::ReaderLock lm (master_lock);
51 if (_masters.empty()) {
52 return AutomationControl::get_value();
57 for (Masters::const_iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
58 /* get current master value, scale by our current ratio with that master */
59 g *= mr->second.master()->get_value () * mr->second.ratio();
66 GainControl::set_value (double val, PBD::Controllable::GroupControlDisposition group_override)
69 _set_value (val, group_override);
74 GainControl::set_value_unchecked (double val)
76 /* used only automation playback */
77 _set_value (val, Controllable::NoGroup);
81 GainControl::_set_value (double val, Controllable::GroupControlDisposition group_override)
83 val = std::max (std::min (val, (double)_desc.upper), (double)_desc.lower);
86 Glib::Threads::RWLock::WriterLock lm (master_lock);
88 if (!_masters.empty()) {
89 recompute_masters_ratios (val);
93 AutomationControl::set_value (val, group_override);
95 _session.set_dirty ();
99 GainControl::internal_to_interface (double v) const
101 if (_desc.type == GainAutomation) {
102 return gain_to_slider_position (v);
104 return (accurate_coefficient_to_dB (v) - lower_db) / range_db;
109 GainControl::interface_to_internal (double v) const
111 if (_desc.type == GainAutomation) {
112 return slider_position_to_gain (v);
114 return dB_to_coefficient (lower_db + v * range_db);
119 GainControl::internal_to_user (double v) const
121 return accurate_coefficient_to_dB (v);
125 GainControl::user_to_internal (double u) const
127 return dB_to_coefficient (u);
131 GainControl::get_user_string () const
133 char theBuf[32]; sprintf( theBuf, _("%3.1f dB"), accurate_coefficient_to_dB (get_value()));
134 return std::string(theBuf);
138 GainControl::get_master_gain () const
140 Glib::Threads::RWLock::ReaderLock sm (master_lock, Glib::Threads::TRY_LOCK);
143 return get_master_gain_locked ();
150 GainControl::get_master_gain_locked () const
152 /* Master lock MUST be held (read or write lock is acceptable) */
156 for (Masters::const_iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
157 /* get current master value, scale by our current ratio with that master */
158 g *= mr->second.master()->get_value () * mr->second.ratio();
165 GainControl::add_master (boost::shared_ptr<VCA> vca)
167 gain_t old_master_val;
168 std::pair<Masters::iterator,bool> res;
171 Glib::Threads::RWLock::WriterLock lm (master_lock);
172 old_master_val = get_master_gain_locked ();
174 /* ratio will be recomputed below */
176 res = _masters.insert (make_pair<uint32_t,MasterRecord> (vca->number(), MasterRecord (vca->control(), 0.0)));
179 recompute_masters_ratios (old_master_val);
181 /* note that we bind @param m as a weak_ptr<GainControl>, thus
182 avoiding holding a reference to the control in the binding
186 vca->DropReferences.connect_same_thread (masters_connections, boost::bind (&GainControl::master_going_away, this, vca));
188 /* Store the connection inside the MasterRecord, so that when we destroy it, the connection is destroyed
189 and we no longer hear about changes to the VCA.
192 vca->control()->Changed.connect_same_thread (res.first->second.connection, boost::bind (&PBD::Signal0<void>::operator(), &Changed));
197 VCAStatusChange (); /* EMIT SIGNAL */
202 GainControl::master_going_away (boost::weak_ptr<VCA> wv)
204 boost::shared_ptr<VCA> v = wv.lock();
211 GainControl::remove_master (boost::shared_ptr<VCA> vca)
213 gain_t old_master_val;
214 Masters::size_type erased = 0;
217 Glib::Threads::RWLock::WriterLock lm (master_lock);
218 old_master_val = get_master_gain_locked ();
219 erased = _masters.erase (vca->number());
221 recompute_masters_ratios (old_master_val);
226 VCAStatusChange (); /* EMIT SIGNAL */
231 GainControl::clear_masters ()
233 bool had_masters = false;
236 Glib::Threads::RWLock::WriterLock lm (master_lock);
237 if (!_masters.empty()) {
244 VCAStatusChange (); /* EMIT SIGNAL */
249 GainControl::recompute_masters_ratios (double val)
251 /* Master WRITE lock must be held */
253 /* V' is the new gain value for this
255 Mv(n) is the return value of ::get_value() for the n-th master
256 Mr(n) is the return value of ::ratio() for the n-th master record
258 the slave should return V' on the next call to ::get_value().
260 but the value is determined by the masters, so we know:
262 V' = (Mv(1) * Mr(1)) * (Mv(2) * Mr(2)) * ... * (Mv(n) * Mr(n))
266 Mr(1) * Mr(2) * ... * (Mr(n) = V' / (Mv(1) * Mv(2) * ... * Mv(n))
268 if we make all ratios equal (i.e. each master contributes the same
269 fraction of its own gain level to make the final slave gain), then we
272 pow (Mr(n), n) = V' / (Mv(1) * Mv(2) * ... * Mv(n))
276 Mr(n) = pow ((V' / (Mv(1) * Mv(2) * ... * Mv(n))), 1/n)
278 Mr(n) is the new ratio number for the slaves
282 const double nmasters = _masters.size();
283 double masters_total_gain_coefficient = 1.0;
285 for (Masters::iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
286 masters_total_gain_coefficient *= mr->second.master()->get_value();
289 const double new_universal_ratio = pow ((val / masters_total_gain_coefficient), (1.0/nmasters));
291 for (Masters::iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
292 mr->second.reset_ratio (new_universal_ratio);
297 GainControl::slaved_to (boost::shared_ptr<VCA> vca) const
299 Glib::Threads::RWLock::ReaderLock lm (master_lock);
300 return _masters.find (vca->number()) != _masters.end();
304 GainControl::slaved () const
306 Glib::Threads::RWLock::ReaderLock lm (master_lock);
307 return !_masters.empty();
311 GainControl::get_state ()
313 XMLNode& node (AutomationControl::get_state());
315 /* store VCA master IDs */
320 Glib::Threads::RWLock::ReaderLock lm (master_lock);
321 for (Masters::const_iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
325 str += PBD::to_string (mr->first, std::dec);
330 node.add_property (X_("masters"), str);
337 GainControl::set_state (XMLNode const& node, int version)
339 AutomationControl::set_state (node, version);
341 XMLProperty const* prop = node.property (X_("masters"));
343 /* XXX Problem here if we allow VCA's to be slaved to other VCA's .. we
344 * have to load all VCAs first, then call ::set_state() so that
345 * vca_by_number() will succeed.
349 vector<string> masters;
350 split (prop->value(), masters, ',');
352 for (vector<string>::const_iterator m = masters.begin(); m != masters.end(); ++m) {
353 boost::shared_ptr<VCA> vca = _session.vca_manager().vca_by_number (PBD::atoi (*m));