2 Copyright (C) 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/unwind.h"
23 #include "ardour/control_group.h"
24 #include "ardour/gain_control.h"
26 using namespace ARDOUR;
29 ControlGroup::ControlGroup (Evoral::Parameter p)
38 ControlGroup::~ControlGroup ()
44 ControlGroup::set_active (bool yn)
50 ControlGroup::set_mode (Mode m)
56 ControlGroup::clear ()
58 /* we're giving up on all members, so we don't care about their
59 * DropReferences signals anymore
62 member_connections.drop_connections ();
64 /* make a copy so that when the control calls ::remove_control(), we
68 std::vector<boost::shared_ptr<AutomationControl> > controls;
70 Glib::Threads::RWLock::WriterLock lm (controls_lock);
71 for (ControlMap::const_iterator i = _controls.begin(); i != _controls.end(); ++i) {
72 controls.push_back (i->second);
78 for (std::vector<boost::shared_ptr<AutomationControl> >::iterator c = controls.begin(); c != controls.end(); ++c) {
79 (*c)->set_group (boost::shared_ptr<ControlGroup>());
84 ControlGroup::controls () const
89 Glib::Threads::RWLock::WriterLock lm (controls_lock);
90 for (ControlMap::const_iterator i = _controls.begin(); i != _controls.end(); ++i) {
91 c.push_back (i->second);
99 ControlGroup::control_going_away (boost::weak_ptr<AutomationControl> wac)
101 boost::shared_ptr<AutomationControl> ac (wac.lock());
110 ControlGroup::remove_control (boost::shared_ptr<AutomationControl> ac)
115 Glib::Threads::RWLock::WriterLock lm (controls_lock);
116 erased = _controls.erase (ac->id());
120 ac->set_group (boost::shared_ptr<ControlGroup>());
123 /* return zero if erased, non-zero otherwise */
128 ControlGroup::add_control (boost::shared_ptr<AutomationControl> ac)
130 if (ac->parameter() != _parameter) {
134 std::pair<ControlMap::iterator,bool> res;
137 Glib::Threads::RWLock::WriterLock lm (controls_lock);
138 res = _controls.insert (std::make_pair (ac->id(), ac));
142 /* already in ControlMap */
148 ac->set_group (shared_from_this());
150 ac->DropReferences.connect_same_thread (member_connections, boost::bind (&ControlGroup::control_going_away, this, boost::weak_ptr<AutomationControl>(ac)));
156 ControlGroup::pre_realtime_queue_stuff (double val)
158 Glib::Threads::RWLock::ReaderLock lm (controls_lock);
160 for (ControlMap::iterator c = _controls.begin(); c != _controls.end(); ++c) {
161 c->second->do_pre_realtime_queue_stuff (val);
166 ControlGroup::set_group_value (boost::shared_ptr<AutomationControl> control, double val)
168 double old = control->get_value ();
170 /* set the primary control */
172 control->set_value (val, Controllable::ForGroup);
178 /* now propagate across the group */
180 Glib::Threads::RWLock::ReaderLock lm (controls_lock);
182 if (_mode & Relative) {
184 const double factor = old / control->get_value ();
186 for (ControlMap::iterator c = _controls.begin(); c != _controls.end(); ++c) {
187 if (c->second != control) {
188 c->second->set_value (factor * c->second->get_value(), Controllable::ForGroup);
194 for (ControlMap::iterator c = _controls.begin(); c != _controls.end(); ++c) {
195 if (c->second != control) {
196 c->second->set_value (val, Controllable::ForGroup);
202 /*---- GAIN CONTROL GROUP -----------*/
204 GainControlGroup::GainControlGroup ()
205 : ControlGroup (GainAutomation)
210 GainControlGroup::get_min_factor (gain_t factor)
212 /* CALLER MUST HOLD READER LOCK */
214 for (ControlMap::iterator c = _controls.begin(); c != _controls.end(); ++c) {
215 gain_t const g = c->second->get_value();
217 if ((g + g * factor) >= 0.0f) {
221 if (g <= 0.0000003f) {
225 factor = 0.0000003f / g - 1.0f;
232 GainControlGroup::get_max_factor (gain_t factor)
234 /* CALLER MUST HOLD READER LOCK */
236 for (ControlMap::iterator c = _controls.begin(); c != _controls.end(); ++c) {
237 gain_t const g = c->second->get_value();
239 // if the current factor woulnd't raise this route above maximum
240 if ((g + g * factor) <= 1.99526231f) {
244 // if route gain is already at peak, return 0.0f factor
245 if (g >= 1.99526231f) {
249 // factor is calculated so that it would raise current route to max
250 factor = 1.99526231f / g - 1.0f;
257 GainControlGroup::set_group_value (boost::shared_ptr<AutomationControl> control, double val)
260 /* set the primary control */
261 control->set_value (val, Controllable::ForGroup);
265 Glib::Threads::RWLock::ReaderLock lm (controls_lock);
267 if (_mode & Relative) {
269 gain_t usable_gain = control->get_value();
271 if (usable_gain < 0.000001f) {
272 usable_gain = 0.000001f;
276 if (delta < 0.000001f) {
280 delta -= usable_gain;
286 gain_t factor = delta / usable_gain;
289 factor = get_max_factor (factor);
290 if (factor == 0.0f) {
291 control->Changed (true, Controllable::ForGroup); /* EMIT SIGNAL */
295 factor = get_min_factor (factor);
296 if (factor == 0.0f) {
297 control->Changed (true, Controllable::ForGroup); /* EMIT SIGNAL */
302 /* set the primary control */
304 control->set_value (val, Controllable::ForGroup);
306 /* now propagate across the group */
308 for (ControlMap::iterator c = _controls.begin(); c != _controls.end(); ++c) {
309 if (c->second == control) {
313 boost::shared_ptr<GainControl> gc = boost::dynamic_pointer_cast<GainControl> (c->second);
316 gc->inc_gain (factor);
322 /* just set entire group */
324 for (ControlMap::iterator c = _controls.begin(); c != _controls.end(); ++c) {
325 c->second->set_value (val, Controllable::ForGroup);