changeset 740:846970dbef17 audio-source-refactor

Use shared_ptr for plugin instances throughout
author Chris Cannam
date Fri, 20 Mar 2020 16:31:58 +0000
parents ddfac001b543
children 6508d9d216c7
files audio/AudioCallbackPlaySource.cpp audio/EffectWrapper.cpp audio/TimeStretchWrapper.cpp audio/TimeStretchWrapper.h framework/TransformUserConfigurator.cpp framework/TransformUserConfigurator.h
diffstat 6 files changed, 88 insertions(+), 42 deletions(-) [+]
line wrap: on
line diff
--- a/audio/AudioCallbackPlaySource.cpp	Thu Mar 19 16:14:02 2020 +0000
+++ b/audio/AudioCallbackPlaySource.cpp	Fri Mar 20 16:31:58 2020 +0000
@@ -988,6 +988,9 @@
 void
 AudioCallbackPlaySource::setAuditioningEffect(std::shared_ptr<Auditionable> a)
 {
+    SVDEBUG << "AudioCallbackPlaySource::setAuditioningEffect(" << a << ")"
+            << endl;
+    
     auto plugin = std::dynamic_pointer_cast<RealTimePluginInstance>(a);
     if (a && !plugin) {
         SVCERR << "WARNING: AudioCallbackPlaySource::setAuditioningEffect: auditionable object " << a << " is not a real-time plugin instance" << endl;
--- a/audio/EffectWrapper.cpp	Thu Mar 19 16:14:02 2020 +0000
+++ b/audio/EffectWrapper.cpp	Fri Mar 20 16:31:58 2020 +0000
@@ -18,6 +18,8 @@
 
 #include "base/Debug.h"
 
+//#define DEBUG_EFFECT_WRAPPER 1
+
 using namespace std;
 
 static const int DEFAULT_RING_BUFFER_SIZE = 131071;
@@ -39,6 +41,11 @@
 {
     lock_guard<mutex> guard(m_mutex);
 
+#ifdef DEBUG_EFFECT_WRAPPER
+    SVCERR << "EffectWrapper[" << this
+           << "]::setEffect(" << effect.lock() << ")" << endl;
+#endif
+    
     m_effect = effect;
     m_failed = false;
 }
@@ -48,6 +55,11 @@
 {
     lock_guard<mutex> guard(m_mutex);
 
+#ifdef DEBUG_EFFECT_WRAPPER
+    SVCERR << "EffectWrapper[" << this
+           << "]::setBypassed(" << bypassed << ")" << endl;
+#endif
+
     m_bypassed = bypassed;
 }
 
@@ -64,9 +76,15 @@
 {
     lock_guard<mutex> guard(m_mutex);
 
+#ifdef DEBUG_EFFECT_WRAPPER
+    SVCERR << "EffectWrapper[" << this << "]::reset" << endl;
+#endif
+
     for (auto &rb: m_effectOutputBuffers) {
         rb.reset();
     }
+
+    m_failed = false;
 }
 
 int
@@ -75,16 +93,33 @@
 {
     lock_guard<mutex> guard(m_mutex);
 
+#ifdef DEBUG_EFFECT_WRAPPER
+    SVCERR << "EffectWrapper[" << this << "]::getSourceSamples: " << nframes
+           << " frames across " << nchannels << " channels" << endl;
+#endif
+    
     auto effect(m_effect.lock());
     
-    if (!effect || m_bypassed || m_failed) {
+    if (!effect) {
+#ifdef DEBUG_EFFECT_WRAPPER
+        SVCERR << "EffectWrapper::getSourceSamples: "
+               << "no effect is set" << endl;
+#endif
         return m_source->getSourceSamples(samples, nchannels, nframes);
     }
 
+    if (m_bypassed || m_failed) {
+#ifdef DEBUG_EFFECT_WRAPPER
+        SVCERR << "EffectWrapper::getSourceSamples: "
+               << "effect is bypassed or has failed" << endl;
+#endif
+        return m_source->getSourceSamples(samples, nchannels, nframes);
+    }
+    
     static int warnings = 0;
     if (nchannels != m_channelCount) {
         if (warnings >= 0) {
-            SVCERR << "WARNING: getSourceSamples called for a number of channels different from that set with setSystemPlaybackChannelCount ("
+            SVCERR << "WARNING: EffectWrapper::getSourceSamples called for a number of channels different from that set with setSystemPlaybackChannelCount ("
                    << nchannels << " vs " << m_channelCount << ")" << endl;
             if (++warnings == 6) {
                 SVCERR << "(further warnings will be suppressed)" << endl;
@@ -126,13 +161,13 @@
     int blockSize = effect->getBufferSize();
     
     int got = 0;
-    int offset = 0;
 
     while (got < nframes) {
 
         int read = 0;
         for (int c = 0; c < nchannels; ++c) {
-            read = m_effectOutputBuffers[c].read(samples[c], nframes - got);
+            read = m_effectOutputBuffers[c].read(samples[c] + got,
+                                                 nframes - got);
         }
 
         got += read;
@@ -142,6 +177,10 @@
             int toRun = m_source->getSourceSamples(ib, nchannels, blockSize);
             if (toRun <= 0) break;
 
+#ifdef DEBUG_EFFECT_WRAPPER
+            SVCERR << "EffectWrapper::getSourceSamples: Running effect "
+                   << "for " << toRun << " frames" << endl;
+#endif
             effect->run(Vamp::RealTime::zeroTime, toRun);
 
             for (int c = 0; c < nchannels; ++c) {
@@ -158,6 +197,10 @@
 {
     {
         lock_guard<mutex> guard(m_mutex);
+#ifdef DEBUG_EFFECT_WRAPPER
+        SVCERR << "EffectWrapper[" << this
+               << "]::setSystemPlaybackChannelCount(" << count << ")" << endl;
+#endif
         m_effectOutputBuffers.resize
             (count, RingBuffer<float>(DEFAULT_RING_BUFFER_SIZE));
         m_channelCount = count;
--- a/audio/TimeStretchWrapper.cpp	Thu Mar 19 16:14:02 2020 +0000
+++ b/audio/TimeStretchWrapper.cpp	Fri Mar 20 16:31:58 2020 +0000
@@ -85,9 +85,6 @@
         return m_source->getSourceSamples(samples, nchannels, nframes);
     }
 
-    sv_frame_t available;
-    sv_frame_t fedToStretcher = 0;
-
     vector<float *> inputPtrs(m_channelCount, nullptr);
     for (int i = 0; i < m_channelCount; ++i) {
         inputPtrs[i] = m_inputs[i].data();
@@ -96,11 +93,12 @@
     // The input block for a given output is approx output / ratio,
     // but we can't predict it exactly, for an adaptive timestretcher.
 
+    sv_frame_t available;
+
     while ((available = m_stretcher->available()) < nframes) {
         
-        sv_frame_t reqd = sv_frame_t
-            (ceil(double(nframes - available) / m_timeRatio));
-        reqd = std::max(reqd, sv_frame_t(m_stretcher->getSamplesRequired()));
+        int reqd = int(ceil(double(nframes - available) / m_timeRatio));
+        reqd = std::max(reqd, int(m_stretcher->getSamplesRequired()));
         reqd = std::min(reqd, m_stretcherInputSize);
         if (reqd == 0) reqd = 1;
         
@@ -126,12 +124,11 @@
     lock_guard<mutex> guard(m_mutex);
 
     if (m_timeRatio == 1.0 || !m_channelCount || !m_sampleRate) {
-        SVDEBUG << "TimeStretchWrapper::checkStretcher: m_timeRatio = "
-                << m_timeRatio << ", m_channelCount = " << m_channelCount
-                << ", m_sampleRate = " << m_sampleRate
-                << ", no need for stretcher" << endl;
         if (m_stretcher) {
-            SVDEBUG << "(Deleting existing one)" << endl;
+            SVDEBUG << "TimeStretchWrapper::checkStretcher: m_timeRatio = "
+                    << m_timeRatio << ", m_channelCount = " << m_channelCount
+                    << ", m_sampleRate = " << m_sampleRate
+                    << ", deleting existing stretcher" << endl;
             delete m_stretcher;
             m_stretcher = nullptr;
         }
@@ -147,7 +144,7 @@
     SVDEBUG << "TimeStretchWrapper::checkStretcher: creating stretcher with ratio " << m_timeRatio << endl;
     
     m_stretcher = new RubberBandStretcher
-        (m_sampleRate,
+        (size_t(round(m_sampleRate)),
          m_channelCount,
          RubberBandStretcher::OptionProcessRealTime,
          m_timeRatio);
--- a/audio/TimeStretchWrapper.h	Thu Mar 19 16:14:02 2020 +0000
+++ b/audio/TimeStretchWrapper.h	Fri Mar 20 16:31:58 2020 +0000
@@ -93,7 +93,7 @@
     double m_timeRatio;
     std::vector<std::vector<float>> m_inputs;
     std::mutex m_mutex;
-    sv_frame_t m_stretcherInputSize;
+    int m_stretcherInputSize;
     int m_channelCount;
     sv_samplerate_t m_sampleRate;
 
--- a/framework/TransformUserConfigurator.cpp	Thu Mar 19 16:14:02 2020 +0000
+++ b/framework/TransformUserConfigurator.cpp	Fri Mar 20 16:31:58 2020 +0000
@@ -40,15 +40,20 @@
 
 bool
 TransformUserConfigurator::getChannelRange(TransformId identifier,
-                                           Vamp::PluginBase *plugin,
+                                           std::shared_ptr<Vamp::PluginBase> plugin,
                                            int &minChannels, int &maxChannels)
 {
     if (plugin && plugin->getType() == "Feature Extraction Plugin") {
-        Vamp::Plugin *vp = static_cast<Vamp::Plugin *>(plugin);
-        SVDEBUG << "TransformUserConfigurator::getChannelRange: is a Vamp plugin" << endl;
-        minChannels = int(vp->getMinChannelCount());
-        maxChannels = int(vp->getMaxChannelCount());
-        return true;
+        auto vp = std::dynamic_pointer_cast<Vamp::Plugin>(plugin);
+        if (vp) {
+            SVDEBUG << "TransformUserConfigurator::getChannelRange: is a Vamp plugin" << endl;
+            minChannels = int(vp->getMinChannelCount());
+            maxChannels = int(vp->getMaxChannelCount());
+            return true;
+        } else {
+            SVCERR << "TransformUserConfigurator::getChannelRange: inconsistent plugin identity!" << endl;
+            return false;
+        }
     } else {
         SVDEBUG << "TransformUserConfigurator::getChannelRange: is not a Vamp plugin" << endl;
         return TransformFactory::getInstance()->
@@ -59,7 +64,7 @@
 bool
 TransformUserConfigurator::configure(ModelTransformer::Input &input,
                                      Transform &transform,
-                                     Vamp::PluginBase *plugin,
+                                     std::shared_ptr<Vamp::PluginBase> plugin,
                                      ModelId &inputModel,
                                      AudioPlaySource *source,
                                      sv_frame_t startFrame,
@@ -85,40 +90,35 @@
     if (RealTimePluginFactory::instanceFor(id)) {
 
         RealTimePluginFactory *factory = RealTimePluginFactory::instanceFor(id);
-        const RealTimePluginDescriptor *desc = factory->getPluginDescriptor(id);
+        RealTimePluginDescriptor desc = factory->getPluginDescriptor(id);
 
-        if (desc->audioInputPortCount > 0 && 
-            desc->audioOutputPortCount > 0 &&
-            !desc->isSynth) {
+        if (desc.audioInputPortCount > 0 && 
+            desc.audioOutputPortCount > 0 &&
+            !desc.isSynth) {
             effect = true;
         }
 
-        if (desc->audioInputPortCount == 0) {
+        if (desc.audioInputPortCount == 0) {
             generator = true;
         }
 
         if (output != "A") {
             int outputNo = output.toInt();
-            if (outputNo >= 0 && outputNo < int(desc->controlOutputPortCount)) {
-                outputLabel = desc->controlOutputPortNames[outputNo].c_str();
+            if (outputNo >= 0 && outputNo < int(desc.controlOutputPortCount)) {
+                outputLabel = desc.controlOutputPortNames[outputNo].c_str();
             }
         }
 
-        RealTimePluginInstance *rtp =
-            static_cast<RealTimePluginInstance *>(plugin);
-
-        if (effect && source) {
+        auto auditionable = std::dynamic_pointer_cast<Auditionable>(plugin);
+        
+        if (effect && source && auditionable) {
             SVDEBUG << "Setting auditioning effect" << endl;
-            //!!! This requires a shared_ptr, but we don't manage our
-            //!!! plugin using shared_ptrs yet. Do this as a stopgap.
-            std::shared_ptr<Auditionable> auditionable
-                (std::make_shared<bool>(true), rtp);
             source->setAuditioningEffect(auditionable);
         }
 
     } else {
 
-        Vamp::Plugin *vp = static_cast<Vamp::Plugin *>(plugin);
+        auto vp = std::dynamic_pointer_cast<Vamp::Plugin>(plugin);
 
         frequency = (vp->getInputDomain() == Vamp::Plugin::FrequencyDomain);
 
--- a/framework/TransformUserConfigurator.h	Thu Mar 19 16:14:02 2020 +0000
+++ b/framework/TransformUserConfigurator.h	Fri Mar 20 16:31:58 2020 +0000
@@ -17,6 +17,8 @@
 
 #include "transform/ModelTransformerFactory.h"
 
+#include <memory>
+
 class TransformUserConfigurator : public ModelTransformerFactory::UserConfigurator
 {
 public:
@@ -24,7 +26,7 @@
 
     bool configure(ModelTransformer::Input &input,
                    Transform &transform,
-                   Vamp::PluginBase *plugin,
+                   std::shared_ptr<Vamp::PluginBase> plugin,
                    ModelId &inputModel,
                    AudioPlaySource *source,
                    sv_frame_t startFrame,
@@ -37,7 +39,8 @@
 
 private:
     bool getChannelRange(TransformId identifier,
-                         Vamp::PluginBase *plugin, int &min, int &max);
+                         std::shared_ptr<Vamp::PluginBase> plugin,
+                         int &min, int &max);
 
 };