change VCA model to facilitate Harrison *and* SSL designs

This commit is contained in:
Paul Davis 2016-02-28 11:57:18 -05:00
parent 3daad04936
commit 405f9fc712
3 changed files with 78 additions and 26 deletions

View file

@ -20,7 +20,10 @@
#define __ardour_gain_control_h__ #define __ardour_gain_control_h__
#include <string> #include <string>
#include <list>
#include <boost/shared_ptr.hpp> #include <boost/shared_ptr.hpp>
#include <glibmm/threads.h>
#include "pbd/controllable.h" #include "pbd/controllable.h"
@ -51,12 +54,18 @@ class LIBARDOUR_API GainControl : public AutomationControl {
double lower_db; double lower_db;
double range_db; double range_db;
boost::shared_ptr<GainControl> master() const { return _master; } void add_master (boost::shared_ptr<GainControl>);
void set_master (boost::shared_ptr<GainControl>); void remove_master (boost::shared_ptr<GainControl>);
void clear_masters ();
private: private:
void _set_value (double val, PBD::Controllable::GroupControlDisposition group_override); void _set_value (double val, PBD::Controllable::GroupControlDisposition group_override);
boost::shared_ptr<GainControl> _master; gain_t get_master_gain () const;
mutable Glib::Threads::Mutex master_lock;
typedef std::list<boost::shared_ptr<GainControl> > Masters;
Masters _masters;
}; };
} /* namespace */ } /* namespace */

View file

@ -39,10 +39,17 @@ GainControl::GainControl (Session& session, const Evoral::Parameter &param, boos
double double
GainControl::get_value() const GainControl::get_value() const
{ {
if (!_master) { Glib::Threads::Mutex::Lock sm (master_lock, Glib::Threads::TRY_LOCK);
return AutomationControl::get_value();
if (sm.locked()) {
if (_masters.empty()) {
return AutomationControl::get_value();
}
return AutomationControl::get_value() * get_master_gain ();
} else {
/* could not take lock */
return AutomationControl::get_value ();
} }
return AutomationControl::get_value() * _master->get_value();
} }
void void
@ -106,25 +113,31 @@ GainControl::get_user_string () const
return std::string(theBuf); return std::string(theBuf);
} }
void gain_t
GainControl::set_master (boost::shared_ptr<GainControl> m) GainControl::get_master_gain () const
{ {
double old_master_val; /* Master lock MUST be held */
if (_master) { gain_t g = 1.0;
old_master_val = _master->get_value();
} else { for (Masters::const_iterator m = _masters.begin(); m != _masters.end(); ++m) {
old_master_val = 1.0; g *= (*m)->get_value ();
} }
_master = m; return g;
}
double new_master_val; void
GainControl::add_master (boost::shared_ptr<GainControl> m)
{
gain_t old_master_val;
gain_t new_master_val;
if (_master) { {
new_master_val = _master->get_value(); Glib::Threads::Mutex::Lock lm (master_lock);
} else { old_master_val = get_master_gain ();
new_master_val = 1.0; _masters.push_back (m);
new_master_val = get_master_gain ();
} }
if (old_master_val != new_master_val) { if (old_master_val != new_master_val) {
@ -132,3 +145,38 @@ GainControl::set_master (boost::shared_ptr<GainControl> m)
} }
} }
void
GainControl::remove_master (boost::shared_ptr<GainControl> m)
{
gain_t old_master_val;
gain_t new_master_val;
{
Glib::Threads::Mutex::Lock lm (master_lock);
old_master_val = get_master_gain ();
_masters.remove (m);
new_master_val = get_master_gain ();
}
if (old_master_val != new_master_val) {
Changed(); /* EMIT SIGNAL */
}
}
void
GainControl::clear_masters ()
{
gain_t old_master_val;
gain_t new_master_val;
{
Glib::Threads::Mutex::Lock lm (master_lock);
old_master_val = get_master_gain ();
_masters.clear ();
new_master_val = get_master_gain ();
}
if (old_master_val != new_master_val) {
Changed(); /* EMIT SIGNAL */
}
}

View file

@ -47,16 +47,11 @@ VCA::get_value() const
void void
VCA::add (boost::shared_ptr<Route> r) VCA::add (boost::shared_ptr<Route> r)
{ {
boost::dynamic_pointer_cast<GainControl>(r->gain_control())->set_master (_control); boost::dynamic_pointer_cast<GainControl>(r->gain_control())->add_master (_control);
} }
void void
VCA::remove (boost::shared_ptr<Route> r) VCA::remove (boost::shared_ptr<Route> r)
{ {
boost::shared_ptr<GainControl> route_gain = boost::dynamic_pointer_cast<GainControl>(r->gain_control()); r->gain_control()->remove_master (_control);
boost::shared_ptr<GainControl> current_master = route_gain->master();
if (current_master == _control) {
route_gain->set_master (boost::shared_ptr<GainControl>());
}
} }