Add infrastructure for evaluating VCA automation curves
authorRobin Gareus <robin@gareus.org>
Sat, 3 Jun 2017 11:18:31 +0000 (13:18 +0200)
committerRobin Gareus <robin@gareus.org>
Sat, 3 Jun 2017 11:55:14 +0000 (13:55 +0200)
libs/ardour/ardour/slavable_automation_control.h
libs/ardour/slavable_automation_control.cc

index 6467dcd6decf0ed5575dd5d36c81169109413e79..f89d29c0d25bc50c891fe2404c53f5a3c683753f 100644 (file)
@@ -50,6 +50,14 @@ class LIBARDOUR_API SlavableAutomationControl : public AutomationControl
                return get_masters_value_locked ();
        }
 
+       bool get_masters_curve (framepos_t s, framepos_t e, float* v, framecnt_t l) const {
+               Glib::Threads::RWLock::ReaderLock lm (master_lock);
+               return get_masters_curve_locked (s, e, v, l);
+       }
+       virtual bool get_masters_curve_locked (framepos_t, framepos_t, float*, framecnt_t) const;
+
+       bool masters_curve_multiply (framepos_t, framepos_t, float*, framecnt_t) const;
+
        /* for toggled/boolean controls, returns a count of the number of
           masters currently enabled. For other controls, returns zero.
        */
index 6df2dd2720adb5a29716cef1438343bd31584783..40f4cb486f5ba3c92483cc95c03a9d29c4e47e84 100644 (file)
@@ -24,6 +24,8 @@
 #include "pbd/types_convert.h"
 #include "pbd/i18n.h"
 
+#include "evoral/Curve.hpp"
+
 #include "ardour/audioengine.h"
 #include "ardour/slavable_automation_control.h"
 #include "ardour/session.h"
@@ -110,6 +112,59 @@ SlavableAutomationControl::get_value() const
        }
 }
 
+bool
+SlavableAutomationControl::get_masters_curve_locked (framepos_t, framepos_t, float*, framecnt_t) const
+{
+       /* Every AutomationControl needs to implement this as-needed.
+        *
+        * This class also provides some convenient methods which
+        * could be used as defaults here (depending on  AutomationType)
+        * e.g. masters_curve_multiply()
+        */
+       return false;
+}
+
+bool
+SlavableAutomationControl::masters_curve_multiply (framepos_t start, framepos_t end, float* vec, framecnt_t veclen) const
+{
+       bool rv = list()->curve().rt_safe_get_vector (start, end, vec, veclen);
+       if (_masters.empty()) {
+               return rv;
+       }
+       gain_t* scratch = _session.scratch_automation_buffer ();
+       for (Masters::const_iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
+               boost::shared_ptr<AutomationControl> ac (mr->second.master());
+               bool got_curve;
+
+               boost::shared_ptr<SlavableAutomationControl> sc
+                       = boost::dynamic_pointer_cast<SlavableAutomationControl>(ac);
+               if (sc) {
+                       got_curve = sc->get_masters_curve_locked (start, end, scratch, veclen);
+               } else {
+                       got_curve = ac->list()->curve().rt_safe_get_vector (start, end, scratch, veclen);
+               }
+               if (got_curve) {
+                       // TODO use SSE/AVX methods, e.g. ARDOUR::apply_gain_to_buffer, mix_buffers_no_gain
+                       // which works as long as automation _types_ gain_t == ARDOUR::Sample type == float
+                       if (!rv) {
+                               // TODO optimize this, in case rv is false, direcly use "vec" above.
+                               rv = true;
+                               memcpy (vec, scratch, sizeof (float) * veclen);
+                       } else {
+                               for (framecnt_t i = 0; i < veclen; ++i) {
+                                       vec[i] *= scratch[i];
+                               }
+                       }
+               } else if (rv) {
+                       const float v = get_masters_value ();
+                       for (framecnt_t i = 0; i < veclen; ++i) {
+                               vec[i] *= v;
+                       }
+               }
+       }
+       return rv;
+}
+
 void
 SlavableAutomationControl::actually_set_value (double value, PBD::Controllable::GroupControlDisposition gcd)
 {