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.
19 #include "pbd/convert.h"
20 #include "pbd/strsplit.h"
22 #include "ardour/dB.h"
23 #include "ardour/gain_control.h"
24 #include "ardour/session.h"
25 #include "ardour/vca.h"
26 #include "ardour/vca_manager.h"
30 using namespace ARDOUR;
33 GainControl::GainControl (Session& session, const Evoral::Parameter ¶m, boost::shared_ptr<AutomationList> al)
34 : AutomationControl (session, param, ParameterDescriptor(param),
35 al ? al : boost::shared_ptr<AutomationList> (new AutomationList (param)),
36 param.type() == GainAutomation ? X_("gaincontrol") : X_("trimcontrol")) {
38 alist()->reset_default (1.0);
40 lower_db = accurate_coefficient_to_dB (_desc.lower);
41 range_db = accurate_coefficient_to_dB (_desc.upper) - lower_db;
45 GainControl::set_value (double val, PBD::Controllable::GroupControlDisposition group_override)
48 _set_value (val, group_override);
53 GainControl::set_value_unchecked (double val)
55 /* used only automation playback */
56 _set_value (val, Controllable::NoGroup);
60 GainControl::_set_value (double val, Controllable::GroupControlDisposition group_override)
62 AutomationControl::set_value (std::max (std::min (val, (double)_desc.upper), (double)_desc.lower), group_override);
63 _session.set_dirty ();
67 GainControl::internal_to_interface (double v) const
69 if (_desc.type == GainAutomation) {
70 return gain_to_slider_position (v);
72 return (accurate_coefficient_to_dB (v) - lower_db) / range_db;
77 GainControl::interface_to_internal (double v) const
79 if (_desc.type == GainAutomation) {
80 return slider_position_to_gain (v);
82 return dB_to_coefficient (lower_db + v * range_db);
87 GainControl::internal_to_user (double v) const
89 return accurate_coefficient_to_dB (v);
93 GainControl::user_to_internal (double u) const
95 return dB_to_coefficient (u);
99 GainControl::get_user_string () const
101 char theBuf[32]; sprintf( theBuf, _("%3.1f dB"), accurate_coefficient_to_dB (get_value()));
102 return std::string(theBuf);
106 GainControl::get_master_gain () const
108 Glib::Threads::Mutex::Lock sm (master_lock, Glib::Threads::TRY_LOCK);
111 return get_master_gain_locked ();
118 GainControl::get_master_gain_locked () const
120 /* Master lock MUST be held */
124 for (Masters::const_iterator m = _masters.begin(); m != _masters.end(); ++m) {
125 g *= (*m)->get_value ();
132 GainControl::add_master (boost::shared_ptr<VCA> vca)
134 gain_t old_master_val;
135 gain_t new_master_val;
136 std::pair<set<boost::shared_ptr<GainControl> >::iterator,bool> res;
139 Glib::Threads::Mutex::Lock lm (master_lock);
140 old_master_val = get_master_gain_locked ();
141 res = _masters.insert (vca->control());
142 _masters_numbers.insert (vca->number());
143 new_master_val = get_master_gain_locked ();
145 /* note that we bind @param m as a weak_ptr<GainControl>, thus
146 avoiding holding a reference to the control in the binding
150 vca->DropReferences.connect_same_thread (masters_connections, boost::bind (&GainControl::master_going_away, this, vca));
154 if (old_master_val != new_master_val) {
155 Changed(); /* EMIT SIGNAL */
159 VCAStatusChange (); /* EMIT SIGNAL */
164 GainControl::master_going_away (boost::weak_ptr<VCA> wv)
166 boost::shared_ptr<VCA> v = wv.lock();
173 GainControl::remove_master (boost::shared_ptr<VCA> vca)
175 gain_t old_master_val;
176 gain_t new_master_val;
177 set<boost::shared_ptr<GainControl> >::size_type erased = 0;
180 Glib::Threads::Mutex::Lock lm (master_lock);
181 old_master_val = get_master_gain_locked ();
182 erased = _masters.erase (vca->control());
183 _masters_numbers.erase (vca->number());
184 new_master_val = get_master_gain_locked ();
187 if (old_master_val != new_master_val) {
188 Changed(); /* EMIT SIGNAL */
192 VCAStatusChange (); /* EMIT SIGNAL */
197 GainControl::clear_masters ()
199 gain_t old_master_val;
200 gain_t new_master_val;
201 bool had_masters = false;
204 Glib::Threads::Mutex::Lock lm (master_lock);
205 old_master_val = get_master_gain_locked ();
206 if (!_masters.empty()) {
210 _masters_numbers.clear ();
211 new_master_val = get_master_gain_locked ();
214 if (old_master_val != new_master_val) {
215 Changed(); /* EMIT SIGNAL */
219 VCAStatusChange (); /* EMIT SIGNAL */
224 GainControl::slaved_to (boost::shared_ptr<VCA> vca) const
226 Glib::Threads::Mutex::Lock lm (master_lock);
227 return find (_masters.begin(), _masters.end(), vca->control()) != _masters.end();
231 GainControl::get_state ()
233 XMLNode& node (AutomationControl::get_state());
235 /* store VCA master IDs */
240 Glib::Threads::Mutex::Lock lm (master_lock);
241 for (set<uint32_t>::const_iterator m = _masters_numbers.begin(); m != _masters_numbers.end(); ++m) {
245 str += PBD::to_string (*m, std::dec);
250 node.add_property (X_("masters"), str);
257 GainControl::set_state (XMLNode const& node, int version)
259 AutomationControl::set_state (node, version);
261 XMLProperty const* prop = node.property (X_("masters"));
263 /* XXXProblem here if we allow VCA's to be slaved to other VCA's .. we
264 * have to load all VCAs first, then call ::set_state() so that
265 * vca_by_number() will succeed.
269 vector<string> masters;
270 split (prop->value(), masters, ',');
272 for (vector<string>::const_iterator m = masters.begin(); m != masters.end(); ++m) {
273 boost::shared_ptr<VCA> vca = _session.vca_manager().vca_by_number (PBD::atoi (*m));