diff options
author | Paul Davis <paul@linuxaudiosystems.com> | 2016-04-08 16:51:34 -0400 |
---|---|---|
committer | Paul Davis <paul@linuxaudiosystems.com> | 2016-05-31 15:30:40 -0400 |
commit | 4aa1c242ab1e1bf4fc3575c5d88a22824976a04f (patch) | |
tree | f71d4c56255a9c72bfd582668d03caed1d2c731c /libs/ardour/control_group.cc | |
parent | 653ae4acd639fef149314fe6f8c7a0d862afae40 (diff) |
add new files to source tree
Diffstat (limited to 'libs/ardour/control_group.cc')
-rw-r--r-- | libs/ardour/control_group.cc | 287 |
1 files changed, 287 insertions, 0 deletions
diff --git a/libs/ardour/control_group.cc b/libs/ardour/control_group.cc new file mode 100644 index 0000000000..6752940d27 --- /dev/null +++ b/libs/ardour/control_group.cc @@ -0,0 +1,287 @@ +/* + Copyright (C) 2016 Paul Davis + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include <vector> + +#include "pbd/unwind.h" + +#include "ardour/control_group.h" +#include "ardour/gain_control.h" + +using namespace ARDOUR; +using namespace PBD; + +ControlGroup::ControlGroup (Evoral::Parameter p) + : _parameter (p) + , _active (true) + , _mode (Mode (0)) + , propagating (false) +{ +} + + +ControlGroup::~ControlGroup () +{ + clear (); +} + +void +ControlGroup::set_active (bool yn) +{ + _active = yn; + std::cerr << " CG for " << enum_2_string ((AutomationType) _parameter.type()) << " now active ? " << _active << std::endl; +} + +void +ControlGroup::clear () +{ + /* we're giving up on all members, so we don't care about their + * DropReferences signals anymore + */ + + member_connections.drop_connections (); + + /* make a copy so that when the control calls ::remove_control(), we + * don't deadlock. + */ + + std::vector<boost::shared_ptr<AutomationControl> > controls; + { + Glib::Threads::RWLock::WriterLock lm (controls_lock); + for (ControlMap::const_iterator i = _controls.begin(); i != _controls.end(); ++i) { + controls.push_back (i->second); + } + } + + _controls.clear (); + + for (std::vector<boost::shared_ptr<AutomationControl> >::iterator c = controls.begin(); c != controls.end(); ++c) { + (*c)->set_group (boost::shared_ptr<ControlGroup>()); + } +} + +ControlList +ControlGroup::controls () const +{ + ControlList c; + + if (_active) { + Glib::Threads::RWLock::WriterLock lm (controls_lock); + for (ControlMap::const_iterator i = _controls.begin(); i != _controls.end(); ++i) { + c.push_back (i->second); + } + } + + return c; +} + +void +ControlGroup::control_going_away (boost::weak_ptr<AutomationControl> wac) +{ + boost::shared_ptr<AutomationControl> ac (wac.lock()); + if (!ac) { + return; + } + + remove_control (ac); +} + +int +ControlGroup::remove_control (boost::shared_ptr<AutomationControl> ac) +{ + Glib::Threads::RWLock::WriterLock lm (controls_lock); + /* return zero if erased, non-zero otherwise */ + return !(_controls.erase (ac->id()) > 0); +} + +int +ControlGroup::add_control (boost::shared_ptr<AutomationControl> ac) +{ + if (ac->parameter() != _parameter) { + return -1; + } + + std::pair<ControlMap::iterator,bool> res; + + { + Glib::Threads::RWLock::WriterLock lm (controls_lock); + res = _controls.insert (std::make_pair (ac->id(), ac)); + } + + if (!res.second) { + /* already in ControlMap */ + return -1; + } + + /* Inserted */ + + ac->set_group (shared_from_this()); + + ac->DropReferences.connect_same_thread (member_connections, boost::bind (&ControlGroup::control_going_away, this, boost::weak_ptr<AutomationControl>(ac))); + + return 0; +} + +void +ControlGroup::set_group_value (boost::shared_ptr<AutomationControl> control, double val) +{ + double old = control->get_value (); + + /* set the primary control */ + + control->set_value (val, Controllable::ForGroup); + + /* now propagate across the group */ + + Glib::Threads::RWLock::ReaderLock lm (controls_lock); + + if (_mode & Relative) { + + const double factor = old / control->get_value (); + + for (ControlMap::iterator c = _controls.begin(); c != _controls.end(); ++c) { + if (c->second != control) { + c->second->set_value (factor * c->second->get_value(), Controllable::ForGroup); + } + } + + } else { + + for (ControlMap::iterator c = _controls.begin(); c != _controls.end(); ++c) { + if (c->second != control) { + c->second->set_value (val, Controllable::ForGroup); + } + } + } +} + +/*---- GAIN CONTROL GROUP -----------*/ + +gain_t +GainControlGroup::get_min_factor (gain_t factor) +{ + /* CALLER MUST HOLD READER LOCK */ + + for (ControlMap::iterator c = _controls.begin(); c != _controls.end(); ++c) { + gain_t const g = c->second->get_value(); + + if ((g + g * factor) >= 0.0f) { + continue; + } + + if (g <= 0.0000003f) { + return 0.0f; + } + + factor = 0.0000003f / g - 1.0f; + } + + return factor; +} + +gain_t +GainControlGroup::get_max_factor (gain_t factor) +{ + /* CALLER MUST HOLD READER LOCK */ + + for (ControlMap::iterator c = _controls.begin(); c != _controls.end(); ++c) { + gain_t const g = c->second->get_value(); + + // if the current factor woulnd't raise this route above maximum + if ((g + g * factor) <= 1.99526231f) { + continue; + } + + // if route gain is already at peak, return 0.0f factor + if (g >= 1.99526231f) { + return 0.0f; + } + + // factor is calculated so that it would raise current route to max + factor = 1.99526231f / g - 1.0f; + } + + return factor; +} + +void +GainControlGroup::set_group_value (boost::shared_ptr<AutomationControl> control, double val) +{ + /* set the primary control */ + + control->set_value (val, Controllable::ForGroup); + + /* now propagate across the group */ + + Glib::Threads::RWLock::ReaderLock lm (controls_lock); + + if (_mode & Relative) { + + gain_t usable_gain = control->get_value(); + + if (usable_gain < 0.000001f) { + usable_gain = 0.000001f; + } + + gain_t delta = val; + if (delta < 0.000001f) { + delta = 0.000001f; + } + + delta -= usable_gain; + + if (delta == 0.0f) + return; + + gain_t factor = delta / usable_gain; + + if (factor > 0.0f) { + factor = get_max_factor (factor); + if (factor == 0.0f) { + control->Changed (true, Controllable::ForGroup); /* EMIT SIGNAL */ + return; + } + } else { + factor = get_min_factor (factor); + if (factor == 0.0f) { + control->Changed (true, Controllable::ForGroup); /* EMIT SIGNAL */ + return; + } + } + + for (ControlMap::iterator c = _controls.begin(); c != _controls.end(); ++c) { + if (c->second == control) { + continue; + } + + boost::shared_ptr<GainControl> gc = boost::dynamic_pointer_cast<GainControl> (c->second); + + if (gc) { + gc->inc_gain (factor); + } + } + + } else { + + for (ControlMap::iterator c = _controls.begin(); c != _controls.end(); ++c) { + if (c->second != control) { + c->second->set_value (val, Controllable::ForGroup); + } + } + } +} |