changeset 1832:7c92c644db20

Merge from branch audio-source-refactor. Various changes to memory management for plugins, ring buffers etc, for safer code further up the stack
author Chris Cannam
date Fri, 03 Apr 2020 12:12:02 +0100
parents 498ed1e86f92 (current diff) 5f8fbbde08ff (diff)
children 21c792334c2e 804dd0c06f0e
files
diffstat 24 files changed, 235 insertions(+), 361 deletions(-) [+]
line wrap: on
line diff
--- a/base/AudioPlaySource.h	Fri Mar 27 10:06:03 2020 +0000
+++ b/base/AudioPlaySource.h	Fri Apr 03 12:12:02 2020 +0100
@@ -18,6 +18,8 @@
 
 #include "BaseTypes.h"
 
+#include <memory>
+
 struct Auditionable {
     virtual ~Auditionable() { }
 };
@@ -101,9 +103,11 @@
 
     /**
      * Set a plugin or other subclass of Auditionable as an
-     * auditioning effect.
+     * auditioning effect. The Auditionable is shared with the caller:
+     * the expectation is that the caller may continue to modify its
+     * parameters etc during auditioning.
      */
-    virtual void setAuditioningEffect(Auditionable *) = 0;
+    virtual void setAuditioningEffect(std::shared_ptr<Auditionable>) = 0;
 
 };
 
--- a/base/RingBuffer.h	Fri Mar 27 10:06:03 2020 +0000
+++ b/base/RingBuffer.h	Fri Apr 03 12:12:02 2020 +0100
@@ -26,8 +26,9 @@
 #include "system/System.h"
 
 #include <bqvec/Barrier.h>
+#include <bqvec/VectorOps.h>
 
-#include <cstring> // memcpy, memset &c
+#include <vector>
 
 //#define DEBUG_RINGBUFFER 1
 
@@ -38,10 +39,6 @@
 /**
  * RingBuffer implements a lock-free ring buffer for one writer and N
  * readers, that is to be used to store a sample type T.
- *
- * For efficiency, RingBuffer frequently initialises samples by
- * writing zeroes into their memory space, so T should normally be a
- * simple type that can safely be set to zero using memset.
  */
 
 template <typename T, int N = 1>
@@ -68,21 +65,14 @@
     int getSize() const;
 
     /**
-     * Return a new ring buffer (allocated with "new" -- caller must
-     * delete when no longer needed) of the given size, containing the
-     * same data as this one as perceived by reader 0 of this buffer.
-     * If another thread reads from or writes to this buffer during
-     * the call, the contents of the new buffer may be incomplete or
+     * Return a new ring buffer of the given size, containing the same
+     * data as this one as perceived by reader 0 of this buffer.  If
+     * another thread reads from or writes to this buffer during the
+     * call, the contents of the new buffer may be incomplete or
      * inconsistent.  If this buffer's data will not fit in the new
-     * size, the contents are undefined.
+     * size, the contents are undetermined.
      */
-    RingBuffer<T, N> *resized(int newSize) const;
-
-    /**
-     * Lock the ring buffer into physical memory.  Returns true
-     * for success.
-     */
-    bool mlock();
+    RingBuffer<T, N> resized(int newSize) const;
 
     /**
      * Reset read and write pointers, thus emptying the buffer.
@@ -164,42 +154,26 @@
      */
     int zero(int n);
 
+    RingBuffer(const RingBuffer &) =default;
+    RingBuffer &operator=(const RingBuffer &) =default;
+    
 protected:
-    T   *m_buffer;
-    bool m_mlocked;
-    int  m_writer;
-    int *m_readers;
-    int  m_size;
-    int  m_spare;
-
-private:
-    RingBuffer(const RingBuffer &); // not provided
-    RingBuffer &operator=(const RingBuffer &); // not provided
+    std::vector<T, breakfastquay::StlAllocator<T>> m_buffer;
+    int m_writer;
+    std::vector<int> m_readers;
+    int m_size;
 };
 
 template <typename T, int N>
 RingBuffer<T, N>::RingBuffer(int n) :
-    m_buffer(new T[n + 1]),
-    m_mlocked(false),
+    m_buffer(n + 1, T()),
     m_writer(0),
-    m_readers(new int[N]),
+    m_readers(N, 0),
     m_size(n + 1)
 {
 #ifdef DEBUG_RINGBUFFER
     std::cerr << "RingBuffer<T," << N << ">[" << this << "]::RingBuffer(" << n << ")" << std::endl;
 #endif
-/*
-    std::cerr << "note: sizeof(RingBuffer<T,N> = " << sizeof(RingBuffer<T,N>) << ")" << std::endl;
-
-    std::cerr << "this = " << this << std::endl;
-    std::cerr << "&m_buffer = " << &m_buffer << std::endl;
-    std::cerr << "&m_mlocked = " << &m_mlocked << std::endl;
-    std::cerr << "&m_writer = " << &m_writer << std::endl;
-    std::cerr << "&m_readers = " << &m_readers << std::endl;
-    std::cerr << "&m_size = " << &m_size << std::endl;
-*/
-    
-    for (int i = 0; i < N; ++i) m_readers[i] = 0;
 }
 
 template <typename T, int N>
@@ -208,13 +182,6 @@
 #ifdef DEBUG_RINGBUFFER
     std::cerr << "RingBuffer<T," << N << ">[" << this << "]::~RingBuffer" << std::endl;
 #endif
-
-    delete[] m_readers;
-
-    if (m_mlocked) {
-        MUNLOCK((void *)m_buffer, m_size * sizeof(T));
-    }
-    delete[] m_buffer;
 }
 
 template <typename T, int N>
@@ -229,14 +196,14 @@
 }
 
 template <typename T, int N>
-RingBuffer<T, N> *
+RingBuffer<T, N>
 RingBuffer<T, N>::resized(int newSize) const
 {
 #ifdef DEBUG_RINGBUFFER
     std::cerr << "RingBuffer<T," << N << ">[" << this << "]::resized(" << newSize << ")" << std::endl;
 #endif
 
-    RingBuffer<T, N> *newBuffer = new RingBuffer<T, N>(newSize);
+    RingBuffer<T, N> newBuffer(newSize);
 
     int w = m_writer;
     int r = m_readers[0];
@@ -251,15 +218,6 @@
 }
 
 template <typename T, int N>
-bool
-RingBuffer<T, N>::mlock()
-{
-    if (MLOCK((void *)m_buffer, m_size * sizeof(T))) return false;
-    m_mlocked = true;
-    return true;
-}
-
-template <typename T, int N>
 void
 RingBuffer<T, N>::reset()
 {
@@ -268,7 +226,9 @@
 #endif
 
     m_writer = 0;
-    for (int i = 0; i < N; ++i) m_readers[i] = 0;
+    for (int i = 0; i < N; ++i) {
+        m_readers[i] = 0;
+    }
 }
 
 template <typename T, int N>
@@ -328,17 +288,17 @@
         std::cerr << "WARNING: Only " << available << " samples available"
                   << std::endl;
 #endif
-        memset(destination + available, 0, (n - available) * sizeof(T));
+        breakfastquay::v_zero(destination + available, n - available);
         n = available;
     }
     if (n == 0) return n;
 
     int here = m_size - m_readers[R];
     if (here >= n) {
-        memcpy(destination, m_buffer + m_readers[R], n * sizeof(T));
+        breakfastquay::v_copy(destination, m_buffer.data() + m_readers[R], n);
     } else {
-        memcpy(destination, m_buffer + m_readers[R], here * sizeof(T));
-        memcpy(destination + here, m_buffer, (n - here) * sizeof(T));
+        breakfastquay::v_copy(destination, m_buffer.data() + m_readers[R], here);
+        breakfastquay::v_copy(destination + here, m_buffer.data(), n - here);
     }
 
     BQ_MBARRIER();
@@ -373,11 +333,11 @@
 
     if (here >= n) {
         for (int i = 0; i < n; ++i) {
-            destination[i] += (m_buffer + m_readers[R])[i];
+            destination[i] += (m_buffer.data() + m_readers[R])[i];
         }
     } else {
         for (int i = 0; i < here; ++i) {
-            destination[i] += (m_buffer + m_readers[R])[i];
+            destination[i] += (m_buffer.data() + m_readers[R])[i];
         }
         for (int i = 0; i < (n - here); ++i) {
             destination[i + here] += m_buffer[i];
@@ -402,9 +362,7 @@
         std::cerr << "WARNING: No sample available"
                   << std::endl;
 #endif
-        T t;
-        memset(&t, 0, sizeof(T));
-        return t;
+        return T();
     }
     T value = m_buffer[m_readers[R]];
     BQ_MBARRIER();
@@ -426,17 +384,17 @@
         std::cerr << "WARNING: Only " << available << " samples available"
                   << std::endl;
 #endif
-        memset(destination + available, 0, (n - available) * sizeof(T));
+        breakfastquay::v_zero(destination + available, n - available);
         n = available;
     }
     if (n == 0) return n;
 
     int here = m_size - m_readers[R];
     if (here >= n) {
-        memcpy(destination, m_buffer + m_readers[R], n * sizeof(T));
+        breakfastquay::v_copy(destination, m_buffer.data() + m_readers[R], n);
     } else {
-        memcpy(destination, m_buffer + m_readers[R], here * sizeof(T));
-        memcpy(destination + here, m_buffer, (n - here) * sizeof(T));
+        breakfastquay::v_copy(destination, m_buffer.data() + m_readers[R], here);
+        breakfastquay::v_copy(destination + here, m_buffer.data(), n - here);
     }
 
 #ifdef DEBUG_RINGBUFFER
@@ -459,9 +417,7 @@
         std::cerr << "WARNING: No sample available"
                   << std::endl;
 #endif
-        T t;
-        memset(&t, 0, sizeof(T));
-        return t;
+        return T();
     }
     T value = m_buffer[m_readers[R]];
     return value;
@@ -508,10 +464,10 @@
 
     int here = m_size - m_writer;
     if (here >= n) {
-        memcpy(m_buffer + m_writer, source, n * sizeof(T));
+        breakfastquay::v_copy(m_buffer.data() + m_writer, source, n);
     } else {
-        memcpy(m_buffer + m_writer, source, here * sizeof(T));
-        memcpy(m_buffer, source + here, (n - here) * sizeof(T));
+        breakfastquay::v_copy(m_buffer.data() + m_writer, source, here);
+        breakfastquay::v_copy(m_buffer.data(), source + here, n - here);
     }
 
     BQ_MBARRIER();
@@ -544,10 +500,10 @@
 
     int here = m_size - m_writer;
     if (here >= n) {
-        memset(m_buffer + m_writer, 0, n * sizeof(T));
+        breakfastquay::v_zero(m_buffer.data() + m_writer, n);
     } else {
-        memset(m_buffer + m_writer, 0, here * sizeof(T));
-        memset(m_buffer, 0, (n - here) * sizeof(T));
+        breakfastquay::v_zero(m_buffer.data() + m_writer, here);
+        breakfastquay::v_zero(m_buffer.data(), n - here);
     }
     
     BQ_MBARRIER();
--- a/plugin/DSSIPluginFactory.cpp	Fri Mar 27 10:06:03 2020 +0000
+++ b/plugin/DSSIPluginFactory.cpp	Fri Apr 03 12:12:02 2020 +0100
@@ -110,7 +110,7 @@
     unloadUnusedLibraries();
 }
         
-RealTimePluginInstance *
+std::shared_ptr<RealTimePluginInstance> 
 DSSIPluginFactory::instantiatePlugin(QString identifier,
                                      int instrument,
                                      int position,
@@ -124,10 +124,11 @@
 
     if (descriptor) {
 
-        DSSIPluginInstance *instance =
-            new DSSIPluginInstance
-            (this, instrument, identifier, position, sampleRate, blockSize, channels,
-             descriptor);
+        auto instance =
+            std::shared_ptr<RealTimePluginInstance>
+            (new DSSIPluginInstance
+             (this, instrument, identifier, position,
+              sampleRate, blockSize, channels, descriptor));
 
         m_instances.insert(instance);
 
@@ -320,18 +321,18 @@
             continue;
         }
 
-        RealTimePluginDescriptor *rtd = new RealTimePluginDescriptor;
-        rtd->name = ladspaDescriptor->Name;
-        rtd->label = ladspaDescriptor->Label;
-        rtd->maker = ladspaDescriptor->Maker;
-        rtd->copyright = ladspaDescriptor->Copyright;
-        rtd->category = "";
-        rtd->isSynth = (descriptor->run_synth ||
+        RealTimePluginDescriptor rtd;
+        rtd.name = ladspaDescriptor->Name;
+        rtd.label = ladspaDescriptor->Label;
+        rtd.maker = ladspaDescriptor->Maker;
+        rtd.copyright = ladspaDescriptor->Copyright;
+        rtd.category = "";
+        rtd.isSynth = (descriptor->run_synth ||
                         descriptor->run_multiple_synths);
-        rtd->parameterCount = 0;
-        rtd->audioInputPortCount = 0;
-        rtd->audioOutputPortCount = 0;
-        rtd->controlOutputPortCount = 0;
+        rtd.parameterCount = 0;
+        rtd.audioInputPortCount = 0;
+        rtd.audioOutputPortCount = 0;
+        rtd.controlOutputPortCount = 0;
 
         QString identifier = PluginIdentifier::createIdentifier
             ("dssi", soname, ladspaDescriptor->Label);
@@ -348,7 +349,7 @@
         }
 
         if (category == "") {
-            string name = rtd->name;
+            string name = rtd.name;
             if (name.length() > 4 &&
                 name.substr(name.length() - 4) == " VST") {
                 if (descriptor->run_synth || descriptor->run_multiple_synths) {
@@ -360,7 +361,7 @@
             }
         }
 
-        rtd->category = category.toStdString();
+        rtd.category = category.toStdString();
         
 //        cerr << "Plugin id is " << ladspaDescriptor->UniqueID
 //                  << ", identifier is \"" << identifier
@@ -399,20 +400,20 @@
         for (unsigned long i = 0; i < ladspaDescriptor->PortCount; i++) {
             if (LADSPA_IS_PORT_CONTROL(ladspaDescriptor->PortDescriptors[i])) {
                 if (LADSPA_IS_PORT_INPUT(ladspaDescriptor->PortDescriptors[i])) {
-                    ++rtd->parameterCount;
+                    ++rtd.parameterCount;
                 } else {
                     if (strcmp(ladspaDescriptor->PortNames[i], "latency") &&
                         strcmp(ladspaDescriptor->PortNames[i], "_latency")) {
-                        ++rtd->controlOutputPortCount;
-                        rtd->controlOutputPortNames.push_back
+                        ++rtd.controlOutputPortCount;
+                        rtd.controlOutputPortNames.push_back
                             (ladspaDescriptor->PortNames[i]);
                     }
                 }
             } else {
                 if (LADSPA_IS_PORT_INPUT(ladspaDescriptor->PortDescriptors[i])) {
-                    ++rtd->audioInputPortCount;
+                    ++rtd.audioInputPortCount;
                 } else if (LADSPA_IS_PORT_OUTPUT(ladspaDescriptor->PortDescriptors[i])) {
-                    ++rtd->audioOutputPortCount;
+                    ++rtd.audioOutputPortCount;
                 }
             }
         }
--- a/plugin/DSSIPluginFactory.h	Fri Mar 27 10:06:03 2020 +0000
+++ b/plugin/DSSIPluginFactory.h	Fri Apr 03 12:12:02 2020 +0100
@@ -37,12 +37,13 @@
 
     void enumeratePlugins(std::vector<QString> &list) override;
 
-    RealTimePluginInstance *instantiatePlugin(QString identifier,
-                                                      int clientId,
-                                                      int position,
-                                                      sv_samplerate_t sampleRate,
-                                                      int blockSize,
-                                                      int channels) override;
+    std::shared_ptr<RealTimePluginInstance>
+    instantiatePlugin(QString identifier,
+                      int clientId,
+                      int position,
+                      sv_samplerate_t sampleRate,
+                      int blockSize,
+                      int channels) override;
 
     static std::vector<QString> getPluginPath();
 
--- a/plugin/FeatureExtractionPluginFactory.h	Fri Mar 27 10:06:03 2020 +0000
+++ b/plugin/FeatureExtractionPluginFactory.h	Fri Apr 03 12:12:02 2020 +0100
@@ -24,6 +24,8 @@
 
 #include <QString>
 
+#include <memory>
+
 class FeatureExtractionPluginFactory
 {
 public:
@@ -47,8 +49,8 @@
      * blockSize or channels on this -- they're negotiated and handled
      * via initialize() on the plugin itself after loading.
      */
-    virtual Vamp::Plugin *instantiatePlugin(QString identifier,
-                                            sv_samplerate_t inputSampleRate) = 0;
+    virtual std::shared_ptr<Vamp::Plugin> instantiatePlugin(QString identifier,
+                                                            sv_samplerate_t inputSampleRate) = 0;
     
     /**
      * Get category metadata about a plugin (without instantiating it).
--- a/plugin/LADSPAPluginFactory.cpp	Fri Mar 27 10:06:03 2020 +0000
+++ b/plugin/LADSPAPluginFactory.cpp	Fri Apr 03 12:12:02 2020 +0100
@@ -51,12 +51,6 @@
  
 LADSPAPluginFactory::~LADSPAPluginFactory()
 {
-    for (std::set<RealTimePluginInstance *>::iterator i = m_instances.begin();
-         i != m_instances.end(); ++i) {
-        (*i)->setFactory(nullptr);
-        delete *i;
-    }
-    m_instances.clear();
     unloadUnusedLibraries();
 
 #ifdef HAVE_LRDF
@@ -138,17 +132,17 @@
     unloadUnusedLibraries();
 }
         
-const RealTimePluginDescriptor *
+RealTimePluginDescriptor
 LADSPAPluginFactory::getPluginDescriptor(QString identifier) const
 {
-    std::map<QString, RealTimePluginDescriptor *>::const_iterator i =
+    std::map<QString, RealTimePluginDescriptor>::const_iterator i =
         m_rtDescriptors.find(identifier);
 
     if (i != m_rtDescriptors.end()) {
         return i->second;
     } 
 
-    return nullptr;
+    return {};
 }
 
 float
@@ -334,7 +328,7 @@
 }
 
 
-RealTimePluginInstance *
+std::shared_ptr<RealTimePluginInstance>
 LADSPAPluginFactory::instantiatePlugin(QString identifier,
                                        int instrument,
                                        int position,
@@ -348,10 +342,11 @@
 
     if (descriptor) {
 
-        LADSPAPluginInstance *instance =
-            new LADSPAPluginInstance
-            (this, instrument, identifier, position, sampleRate, blockSize, channels,
-             descriptor);
+        auto instance =
+            std::shared_ptr<RealTimePluginInstance>
+            (new LADSPAPluginInstance
+             (this, instrument, identifier, position,
+              sampleRate, blockSize, channels, descriptor));
 
         m_instances.insert(instance);
 
@@ -366,53 +361,6 @@
     return nullptr;
 }
 
-void
-LADSPAPluginFactory::releasePlugin(RealTimePluginInstance *instance,
-                                   QString identifier)
-{
-    Profiler profiler("LADSPAPluginFactory::releasePlugin");
-
-    if (m_instances.find(instance) == m_instances.end()) {
-        cerr << "WARNING: LADSPAPluginFactory::releasePlugin: Not one of mine!"
-                  << endl;
-        return;
-    }
-
-    QString type, soname, label;
-    PluginIdentifier::parseIdentifier(identifier, type, soname, label);
-
-    m_instances.erase(instance);
-
-    bool stillInUse = false;
-
-    for (std::set<RealTimePluginInstance *>::iterator ii = m_instances.begin();
-         ii != m_instances.end(); ++ii) {
-        QString itype, isoname, ilabel;
-        PluginIdentifier::parseIdentifier((*ii)->getPluginIdentifier(), itype, isoname, ilabel);
-        if (isoname == soname) {
-#ifdef DEBUG_LADSPA_PLUGIN_FACTORY
-            SVDEBUG << "LADSPAPluginFactory::releasePlugin: dll " << soname << " is still in use for plugin " << ilabel << endl;
-#endif
-            stillInUse = true;
-            break;
-        }
-    }
-    
-    if (!stillInUse) {
-        if (soname != PluginIdentifier::BUILTIN_PLUGIN_SONAME) {
-#ifdef DEBUG_LADSPA_PLUGIN_FACTORY
-            SVDEBUG << "LADSPAPluginFactory::releasePlugin: dll " << soname << " no longer in use, unloading" << endl;
-#endif
-            unloadLibrary(soname);
-        }
-    }
-
-#ifdef DEBUG_LADSPA_PLUGIN_FACTORY
-    SVDEBUG << "LADSPAPluginFactory::releasePlugin("
-                  << identifier << ": now have " << m_instances.size() << " instances" << endl;
-#endif
-}
-
 const LADSPA_Descriptor *
 LADSPAPluginFactory::getLADSPADescriptor(QString identifier)
 {
@@ -525,31 +473,39 @@
 void
 LADSPAPluginFactory::unloadUnusedLibraries()
 {
+    std::set<std::weak_ptr<RealTimePluginInstance>,
+             std::owner_less<std::weak_ptr<RealTimePluginInstance>>> toRemove;
+
+    std::set<QString> soNamesInUse;
+    
+    for (auto wp: m_instances) {
+        if (auto p = wp.lock()) {
+            QString itype, isoname, ilabel;
+            PluginIdentifier::parseIdentifier(p->getPluginIdentifier(),
+                                              itype, isoname, ilabel);
+            soNamesInUse.insert(isoname);
+        } else {
+            toRemove.insert(wp);
+        }
+    }
+
+    for (auto wp: toRemove) {
+        m_instances.erase(wp);
+    }
+
     std::vector<QString> toUnload;
-
-    for (LibraryHandleMap::iterator i = m_libraryHandles.begin();
+    
+    for (auto i = m_libraryHandles.begin();
          i != m_libraryHandles.end(); ++i) {
 
-        bool stillInUse = false;
-
-        for (std::set<RealTimePluginInstance *>::iterator ii = m_instances.begin();
-             ii != m_instances.end(); ++ii) {
-
-            QString itype, isoname, ilabel;
-            PluginIdentifier::parseIdentifier((*ii)->getPluginIdentifier(), itype, isoname, ilabel);
-            if (isoname == i->first) {
-                stillInUse = true;
-                break;
-            }
+        if (soNamesInUse.find(i->first) == soNamesInUse.end()) {
+            toUnload.push_back(i->first);
         }
-
-        if (!stillInUse) toUnload.push_back(i->first);
     }
 
-    for (std::vector<QString>::iterator i = toUnload.begin();
-         i != toUnload.end(); ++i) {
-        if (*i != PluginIdentifier::BUILTIN_PLUGIN_SONAME) {
-            unloadLibrary(*i);
+    for (auto soname: toUnload) {
+        if (soname != PluginIdentifier::BUILTIN_PLUGIN_SONAME) {
+            unloadLibrary(soname);
         }
     }
 }
@@ -707,17 +663,17 @@
     int index = 0;
     while ((descriptor = fn(index))) {
 
-        RealTimePluginDescriptor *rtd = new RealTimePluginDescriptor;
-        rtd->name = descriptor->Name;
-        rtd->label = descriptor->Label;
-        rtd->maker = descriptor->Maker;
-        rtd->copyright = descriptor->Copyright;
-        rtd->category = "";
-        rtd->isSynth = false;
-        rtd->parameterCount = 0;
-        rtd->audioInputPortCount = 0;
-        rtd->audioOutputPortCount = 0;
-        rtd->controlOutputPortCount = 0;
+        RealTimePluginDescriptor rtd;
+        rtd.name = descriptor->Name;
+        rtd.label = descriptor->Label;
+        rtd.maker = descriptor->Maker;
+        rtd.copyright = descriptor->Copyright;
+        rtd.category = "";
+        rtd.isSynth = false;
+        rtd.parameterCount = 0;
+        rtd.audioInputPortCount = 0;
+        rtd.audioOutputPortCount = 0;
+        rtd.controlOutputPortCount = 0;
 
         QString identifier = PluginIdentifier::createIdentifier
             ("ladspa", soname, descriptor->Label);
@@ -735,7 +691,7 @@
         QString category = m_taxonomy[identifier];
         
         if (category == "") {
-            string name = rtd->name;
+            string name = rtd.name;
             if (name.length() > 4 &&
                 name.substr(name.length() - 4) == " VST") {
                 category = "VST effects";
@@ -743,7 +699,7 @@
             }
         }
         
-        rtd->category = category.toStdString();
+        rtd.category = category.toStdString();
 
 //        cerr << "Plugin id is " << descriptor->UniqueID
 //                  << ", category is \"" << (category ? category : QString("(none)"))
@@ -781,20 +737,20 @@
         for (int i = 0; i < (int)descriptor->PortCount; i++) {
             if (LADSPA_IS_PORT_CONTROL(descriptor->PortDescriptors[i])) {
                 if (LADSPA_IS_PORT_INPUT(descriptor->PortDescriptors[i])) {
-                    ++rtd->parameterCount;
+                    ++rtd.parameterCount;
                 } else {
                     if (strcmp(descriptor->PortNames[i], "latency") &&
                         strcmp(descriptor->PortNames[i], "_latency")) {
-                        ++rtd->controlOutputPortCount;
-                        rtd->controlOutputPortNames.push_back
+                        ++rtd.controlOutputPortCount;
+                        rtd.controlOutputPortNames.push_back
                             (descriptor->PortNames[i]);
                     }
                 }
             } else {
                 if (LADSPA_IS_PORT_INPUT(descriptor->PortDescriptors[i])) {
-                    ++rtd->audioInputPortCount;
+                    ++rtd.audioInputPortCount;
                 } else if (LADSPA_IS_PORT_OUTPUT(descriptor->PortDescriptors[i])) {
-                    ++rtd->audioOutputPortCount;
+                    ++rtd.audioOutputPortCount;
                 }
             }
         }
--- a/plugin/LADSPAPluginFactory.h	Fri Mar 27 10:06:03 2020 +0000
+++ b/plugin/LADSPAPluginFactory.h	Fri Apr 03 12:12:02 2020 +0100
@@ -44,14 +44,16 @@
 
     void enumeratePlugins(std::vector<QString> &list) override;
 
-    const RealTimePluginDescriptor *getPluginDescriptor(QString identifier) const override;
+    RealTimePluginDescriptor getPluginDescriptor(QString identifier)
+        const override;
 
-    RealTimePluginInstance *instantiatePlugin(QString identifier,
-                                                      int clientId,
-                                                      int position,
-                                                      sv_samplerate_t sampleRate,
-                                                      int blockSize,
-                                                      int channels) override;
+    std::shared_ptr<RealTimePluginInstance>
+    instantiatePlugin(QString identifier,
+                      int clientId,
+                      int position,
+                      sv_samplerate_t sampleRate,
+                      int blockSize,
+                      int channels) override;
 
     QString getPluginCategory(QString identifier) override;
 
@@ -79,8 +81,6 @@
     virtual void generateTaxonomy(QString uri, QString base);
     virtual void generateFallbackCategories();
 
-    void releasePlugin(RealTimePluginInstance *, QString) override;
-
     virtual const LADSPA_Descriptor *getLADSPADescriptor(QString identifier);
 
     void loadLibrary(QString soName);
@@ -89,13 +89,14 @@
 
     std::vector<QString> m_identifiers;
     std::map<QString, QString> m_libraries; // identifier -> full file path
-    std::map<QString, RealTimePluginDescriptor *> m_rtDescriptors;
+    std::map<QString, RealTimePluginDescriptor> m_rtDescriptors;
 
     std::map<QString, QString> m_taxonomy;
     std::map<unsigned long, QString> m_lrdfTaxonomy;
     std::map<unsigned long, std::map<int, float> > m_portDefaults;
 
-    std::set<RealTimePluginInstance *> m_instances;
+    std::set<std::weak_ptr<RealTimePluginInstance>,
+             std::owner_less<std::weak_ptr<RealTimePluginInstance>>> m_instances;
 
     typedef std::map<QString, void *> LibraryHandleMap;
     LibraryHandleMap m_libraryHandles;
--- a/plugin/NativeVampPluginFactory.cpp	Fri Mar 27 10:06:03 2020 +0000
+++ b/plugin/NativeVampPluginFactory.cpp	Fri Apr 03 12:12:02 2020 +0100
@@ -297,13 +297,13 @@
     }
 }
 
-Vamp::Plugin *
+std::shared_ptr<Vamp::Plugin>
 NativeVampPluginFactory::instantiatePlugin(QString identifier,
                                            sv_samplerate_t inputSampleRate)
 {
     Profiler profiler("NativeVampPluginFactory::instantiatePlugin");
 
-    Vamp::Plugin *rv = nullptr;
+    std::shared_ptr<Vamp::Plugin> rv = nullptr;
     Vamp::PluginHostAdapter *plugin = nullptr;
 
     const VampPluginDescriptor *descriptor = nullptr;
@@ -363,7 +363,8 @@
 
     if (plugin) {
         m_handleMap[plugin] = libraryHandle;
-        rv = new PluginDeletionNotifyAdapter(plugin, this);
+        rv = std::shared_ptr<Vamp::Plugin>
+            (new PluginDeletionNotifyAdapter(plugin, this));
     }
 
 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
@@ -384,7 +385,7 @@
 }
 
 void
-NativeVampPluginFactory::pluginDeleted(Vamp::Plugin *plugin)
+NativeVampPluginFactory::pluginDeleted(Vamp::Plugin* plugin)
 {
     void *handle = m_handleMap[plugin];
     if (!handle) return;
@@ -480,15 +481,13 @@
         catlist.push_back(s.toStdString());
     }
     
-    Vamp::Plugin *p = instantiatePlugin(identifier, 44100);
+    std::shared_ptr<Vamp::Plugin> p = instantiatePlugin(identifier, 44100);
     if (!p) return {};
 
     auto psd = piper_vamp::PluginStaticData::fromPlugin(pluginKey,
                                                         catlist,
-                                                        p);
+                                                        p.get());
 
-    delete p;
-    
     m_pluginData[identifier] = psd;
     return psd;
 }
--- a/plugin/NativeVampPluginFactory.h	Fri Mar 27 10:06:03 2020 +0000
+++ b/plugin/NativeVampPluginFactory.h	Fri Apr 03 12:12:02 2020 +0100
@@ -40,7 +40,7 @@
     virtual piper_vamp::PluginStaticData getPluginStaticData(QString identifier)
         override;
 
-    virtual Vamp::Plugin *instantiatePlugin(QString identifier,
+    virtual std::shared_ptr<Vamp::Plugin> instantiatePlugin(QString identifier,
                                             sv_samplerate_t inputSampleRate)
         override;
 
--- a/plugin/PiperVampPluginFactory.cpp	Fri Mar 27 10:06:03 2020 +0000
+++ b/plugin/PiperVampPluginFactory.cpp	Fri Apr 03 12:12:02 2020 +0100
@@ -166,7 +166,7 @@
     return rv;
 }
 
-Vamp::Plugin *
+std::shared_ptr<Vamp::Plugin> 
 PiperVampPluginFactory::instantiatePlugin(QString identifier,
                                           sv_samplerate_t inputSampleRate)
 {
@@ -197,7 +197,7 @@
         return nullptr;
     }
 
-    return ap;
+    return std::shared_ptr<Vamp::Plugin>(ap);
 }
 
 piper_vamp::PluginStaticData
--- a/plugin/PiperVampPluginFactory.h	Fri Mar 27 10:06:03 2020 +0000
+++ b/plugin/PiperVampPluginFactory.h	Fri Apr 03 12:12:02 2020 +0100
@@ -43,8 +43,8 @@
     virtual piper_vamp::PluginStaticData getPluginStaticData(QString identifier)
         override;
     
-    virtual Vamp::Plugin *instantiatePlugin(QString identifier,
-                                            sv_samplerate_t inputSampleRate)
+    virtual std::shared_ptr<Vamp::Plugin> instantiatePlugin(QString identifier,
+                                                            sv_samplerate_t inputSampleRate)
         override;
 
     virtual QString getPluginCategory(QString identifier) override;
--- a/plugin/PluginXml.cpp	Fri Mar 27 10:06:03 2020 +0000
+++ b/plugin/PluginXml.cpp	Fri Apr 03 12:12:02 2020 +0100
@@ -30,7 +30,10 @@
 
 #include <iostream>
 
-PluginXml::PluginXml(Vamp::PluginBase *plugin) :
+using std::shared_ptr;
+using std::dynamic_pointer_cast;
+
+PluginXml::PluginXml(shared_ptr<Vamp::PluginBase> plugin) :
     m_plugin(plugin)
 {
 }
@@ -90,8 +93,7 @@
             .arg(m_plugin->getParameter(i->identifier));
     }
 
-    RealTimePluginInstance *rtpi =
-        dynamic_cast<RealTimePluginInstance *>(m_plugin);
+    auto rtpi = dynamic_pointer_cast<RealTimePluginInstance>(m_plugin);
     if (rtpi) {
         std::map<std::string, std::string> configurePairs =
             rtpi->getConfigurePairs();
@@ -138,8 +140,7 @@
         cerr << "WARNING: PluginXml::setParameters: Plugin version does not match (attributes have " << version << ", my version is " << m_plugin->getPluginVersion() << ")" << endl;
     }
 
-    RealTimePluginInstance *rtpi =
-        dynamic_cast<RealTimePluginInstance *>(m_plugin);
+    auto rtpi = dynamic_pointer_cast<RealTimePluginInstance>(m_plugin);
     if (rtpi) {
         QString config = attrs.value("configuration");
         if (config != "") {
--- a/plugin/PluginXml.h	Fri Mar 27 10:06:03 2020 +0000
+++ b/plugin/PluginXml.h	Fri Apr 03 12:12:02 2020 +0100
@@ -19,20 +19,22 @@
 #include "base/XmlExportable.h"
 #include <vamp-hostsdk/PluginBase.h>
 
+#include <memory>
+
 class QXmlAttributes;
 
 class PluginXml : public XmlExportable
 {
 public:
-    PluginXml(Vamp::PluginBase *plugin);
+    PluginXml(std::shared_ptr<Vamp::PluginBase> plugin);
     virtual ~PluginXml();
 
     /**
      * Export plugin settings to XML.
      */
     void toXml(QTextStream &stream,
-                       QString indent = "",
-                       QString extraAttributes = "") const override;
+               QString indent = "",
+               QString extraAttributes = "") const override;
 
     /**
      * Set the parameters and program of a plugin from a set of XML
@@ -53,7 +55,7 @@
 protected:
     QString stripInvalidParameterNameCharacters(QString) const;
 
-    Vamp::PluginBase *m_plugin;
+    std::shared_ptr<Vamp::PluginBase> m_plugin;
 };
 
 #endif
--- a/plugin/RealTimePluginFactory.h	Fri Mar 27 10:06:03 2020 +0000
+++ b/plugin/RealTimePluginFactory.h	Fri Apr 03 12:12:02 2020 +0100
@@ -24,6 +24,7 @@
 
 #include <QString>
 #include <vector>
+#include <memory>
 
 #include "base/Debug.h"
 #include "base/BaseTypes.h"
@@ -80,12 +81,12 @@
     /**
      * Get some basic information about a plugin (rapidly).
      */
-    virtual const RealTimePluginDescriptor *getPluginDescriptor(QString identifier) const = 0;
+    virtual RealTimePluginDescriptor getPluginDescriptor(QString identifier) const = 0;
 
     /**
      * Instantiate a plugin.
      */
-    virtual RealTimePluginInstance *instantiatePlugin(QString identifier,
+    virtual std::shared_ptr<RealTimePluginInstance> instantiatePlugin(QString identifier,
                                                       int clientId,
                                                       int position,
                                                       sv_samplerate_t sampleRate,
@@ -108,10 +109,6 @@
 protected:
     RealTimePluginFactory() { }
 
-    // for call by RealTimePluginInstance dtor
-    virtual void releasePlugin(RealTimePluginInstance *, QString identifier) = 0;
-    friend class RealTimePluginInstance;
-
     static sv_samplerate_t m_sampleRate;
 };
 
--- a/plugin/RealTimePluginInstance.cpp	Fri Mar 27 10:06:03 2020 +0000
+++ b/plugin/RealTimePluginInstance.cpp	Fri Apr 03 12:12:02 2020 +0100
@@ -28,12 +28,5 @@
 
 RealTimePluginInstance::~RealTimePluginInstance()
 {
-//    SVDEBUG << "RealTimePluginInstance::~RealTimePluginInstance" << endl;
-
-    if (m_factory) {
-//        SVDEBUG << "Asking factory to release " << m_identifier << endl;
-
-        m_factory->releasePlugin(this, m_identifier);
-    }
 }
 
--- a/plugin/RealTimePluginInstance.h	Fri Mar 27 10:06:03 2020 +0000
+++ b/plugin/RealTimePluginInstance.h	Fri Apr 03 12:12:02 2020 +0100
@@ -134,8 +134,6 @@
     virtual void discardEvents() { }
     virtual void setIdealChannelCount(int channels) = 0; // must also silence(); may also re-instantiate
 
-    void setFactory(RealTimePluginFactory *f) { m_factory = f; } // ew
-
     std::string getType() const override { return "Real-Time Plugin"; }
 
     typedef std::map<std::string, std::string> ConfigurationPairMap;
@@ -151,8 +149,6 @@
     QString m_identifier;
 
     ConfigurationPairMap m_configurationData;
-
-    friend class PluginFactory;
 };
 
 
--- a/transform/FeatureExtractionModelTransformer.cpp	Fri Mar 27 10:06:03 2020 +0000
+++ b/transform/FeatureExtractionModelTransformer.cpp	Fri Apr 03 12:12:02 2020 +0100
@@ -266,7 +266,8 @@
             << QThread::currentThreadId() << endl;
 
     try {
-        delete m_plugin;
+        m_plugin = {}; // does not necessarily delete, as it's a
+                       // shared_ptr, but in the design case it will
     } catch (const std::exception &e) {
         // A destructor shouldn't throw an exception. But at one point
         // (now fixed) our plugin stub destructor could have
@@ -274,7 +275,6 @@
         SVCERR << "FeatureExtractionModelTransformer: caught exception while deleting plugin: " << e.what() << endl;
         m_message = e.what();
     }
-    m_plugin = nullptr;
 
     m_descriptors.clear();
 }
--- a/transform/FeatureExtractionModelTransformer.h	Fri Mar 27 10:06:03 2020 +0000
+++ b/transform/FeatureExtractionModelTransformer.h	Fri Apr 03 12:12:02 2020 +0100
@@ -58,7 +58,7 @@
 
     void run() override;
 
-    Vamp::Plugin *m_plugin;
+    std::shared_ptr<Vamp::Plugin> m_plugin;
 
     // descriptors per transform
     std::vector<Vamp::Plugin::OutputDescriptor> m_descriptors;
--- a/transform/ModelTransformerFactory.cpp	Fri Mar 27 10:06:03 2020 +0000
+++ b/transform/ModelTransformerFactory.cpp	Fri Apr 03 12:12:02 2020 +0100
@@ -40,6 +40,8 @@
 using std::vector;
 using std::set;
 using std::map;
+using std::shared_ptr;
+using std::make_shared;
 
 ModelTransformerFactory *
 ModelTransformerFactory::m_instance = new ModelTransformerFactory;
@@ -110,7 +112,7 @@
 
     SVDEBUG << "ModelTransformer: last configuration for identifier " << transform.getIdentifier() << ": " << configurationXml << endl;
 
-    Vamp::PluginBase *plugin = nullptr;
+    shared_ptr<Vamp::PluginBase> plugin;
 
     if (RealTimePluginFactory::instanceFor(id)) {
 
@@ -127,20 +129,16 @@
             channels = source->getTargetChannelCount();
         }
 
-        RealTimePluginInstance *rtp = factory->instantiatePlugin
+        plugin = factory->instantiatePlugin
             (id, 0, 0, sampleRate, blockSize, channels);
 
-        plugin = rtp;
-
     } else {
 
         SVDEBUG << "ModelTransformerFactory::getConfigurationForTransform: instantiating Vamp plugin" << endl;
 
-        Vamp::Plugin *vp =
+        plugin =
             FeatureExtractionPluginFactory::instance()->instantiatePlugin
             (id, float(defaultSampleRate));
-
-        plugin = vp;
     }
 
     if (plugin) {
@@ -172,10 +170,6 @@
             makeContextConsistentWithPlugin(transform, plugin);
 
         configurationXml = PluginXml(plugin).toXmlString();
-
-        SVDEBUG << "ModelTransformerFactory::getConfigurationForTransform: got configuration, deleting plugin" << endl;
-        
-        delete plugin;
     }
 
     if (ok) {
--- a/transform/ModelTransformerFactory.h	Fri Mar 27 10:06:03 2020 +0000
+++ b/transform/ModelTransformerFactory.h	Fri Apr 03 12:12:02 2020 +0100
@@ -29,6 +29,7 @@
 #include <map>
 #include <set>
 #include <vector>
+#include <memory>
 
 class AudioPlaySource;
 
@@ -45,7 +46,7 @@
     public:
         virtual bool configure(ModelTransformer::Input &input,
                                Transform &transform,
-                               Vamp::PluginBase *plugin,
+                               std::shared_ptr<Vamp::PluginBase> plugin,
                                ModelId &inputModel,
                                AudioPlaySource *source,
                                sv_frame_t startFrame,
--- a/transform/RealTimeEffectModelTransformer.cpp	Fri Mar 27 10:06:03 2020 +0000
+++ b/transform/RealTimeEffectModelTransformer.cpp	Fri Apr 03 12:12:02 2020 +0100
@@ -108,7 +108,6 @@
 
 RealTimeEffectModelTransformer::~RealTimeEffectModelTransformer()
 {
-    delete m_plugin;
 }
 
 void
--- a/transform/RealTimeEffectModelTransformer.h	Fri Mar 27 10:06:03 2020 +0000
+++ b/transform/RealTimeEffectModelTransformer.h	Fri Apr 03 12:12:02 2020 +0100
@@ -34,7 +34,7 @@
     void awaitOutputModels() override { } // they're created synchronously
     
     QString m_units;
-    RealTimePluginInstance *m_plugin;
+    std::shared_ptr<RealTimePluginInstance> m_plugin;
     int m_outputNo;
 };
 
--- a/transform/TransformFactory.cpp	Fri Mar 27 10:06:03 2020 +0000
+++ b/transform/TransformFactory.cpp	Fri Apr 03 12:12:02 2020 +0100
@@ -513,38 +513,38 @@
             continue;
         }
 
-        const RealTimePluginDescriptor *descriptor =
+        RealTimePluginDescriptor descriptor =
             factory->getPluginDescriptor(pluginId);
 
-        if (!descriptor) {
+        if (descriptor.name == "") {
             cerr << "WARNING: TransformFactory::populateTransforms: Failed to query plugin " << pluginId << endl;
             continue;
         }
         
-//!!!        if (descriptor->controlOutputPortCount == 0 ||
-//            descriptor->audioInputPortCount == 0) continue;
+//!!!        if (descriptor.controlOutputPortCount == 0 ||
+//            descriptor.audioInputPortCount == 0) continue;
 
-//        cout << "TransformFactory::populateRealTimePlugins: plugin " << pluginId << " has " << descriptor->controlOutputPortCount << " control output ports, " << descriptor->audioOutputPortCount << " audio outputs, " << descriptor->audioInputPortCount << " audio inputs" << endl;
+//        cout << "TransformFactory::populateRealTimePlugins: plugin " << pluginId << " has " << descriptor.controlOutputPortCount << " control output ports, " << descriptor.audioOutputPortCount << " audio outputs, " << descriptor.audioInputPortCount << " audio inputs" << endl;
         
-        QString pluginName = descriptor->name.c_str();
+        QString pluginName = descriptor.name.c_str();
         QString category = factory->getPluginCategory(pluginId);
-        bool configurable = (descriptor->parameterCount > 0);
-        QString maker = descriptor->maker.c_str();
+        bool configurable = (descriptor.parameterCount > 0);
+        QString maker = descriptor.maker.c_str();
         if (maker == "") maker = tr("<unknown maker>");
 
-        if (descriptor->audioInputPortCount > 0) {
+        if (descriptor.audioInputPortCount > 0) {
 
-            for (int j = 0; j < (int)descriptor->controlOutputPortCount; ++j) {
+            for (int j = 0; j < (int)descriptor.controlOutputPortCount; ++j) {
 
                 QString transformId = QString("%1:%2").arg(pluginId).arg(j);
                 QString userName;
                 QString units;
                 QString portName;
 
-                if (j < (int)descriptor->controlOutputPortNames.size() &&
-                    descriptor->controlOutputPortNames[j] != "") {
+                if (j < (int)descriptor.controlOutputPortNames.size() &&
+                    descriptor.controlOutputPortNames[j] != "") {
 
-                    portName = descriptor->controlOutputPortNames[j].c_str();
+                    portName = descriptor.controlOutputPortNames[j].c_str();
 
                     userName = tr("%1: %2")
                         .arg(pluginName)
@@ -554,7 +554,7 @@
                         units = unitRE.cap(1);
                     }
 
-                } else if (descriptor->controlOutputPortCount > 1) {
+                } else if (descriptor.controlOutputPortCount > 1) {
 
                     userName = tr("%1: Output %2")
                         .arg(pluginName)
@@ -593,9 +593,9 @@
             }
         }
 
-        if (!descriptor->isSynth || descriptor->audioInputPortCount > 0) {
+        if (!descriptor.isSynth || descriptor.audioInputPortCount > 0) {
 
-            if (descriptor->audioOutputPortCount > 0) {
+            if (descriptor.audioOutputPortCount > 0) {
 
                 QString transformId = QString("%1:A").arg(pluginId);
                 TransformDescription::Type type = TransformDescription::Effects;
@@ -604,7 +604,7 @@
                     .arg(pluginName)
                     .arg(maker);
 
-                if (descriptor->audioInputPortCount == 0) {
+                if (descriptor.audioInputPortCount == 0) {
                     type = TransformDescription::Generator;
                     QString description = tr("Generate audio signal using \"%1\" plugin (from %2)")
                         .arg(pluginName)
@@ -753,25 +753,24 @@
     SVDEBUG << "TransformFactory::getDefaultTransformFor: identifier \""
             << id << "\"" << endl;
     
-    Vamp::PluginBase *plugin = instantiateDefaultPluginFor(id, rate);
+    std::shared_ptr<Vamp::PluginBase> plugin = instantiateDefaultPluginFor(id, rate);
 
     if (plugin) {
         t.setPluginVersion(QString("%1").arg(plugin->getPluginVersion()));
         setParametersFromPlugin(t, plugin);
         makeContextConsistentWithPlugin(t, plugin);
-        delete plugin;
     }
 
     return t;
 }
 
-Vamp::PluginBase *
+std::shared_ptr<Vamp::PluginBase> 
 TransformFactory::instantiatePluginFor(const Transform &transform)
 {
     SVDEBUG << "TransformFactory::instantiatePluginFor: identifier \""
             << transform.getIdentifier() << "\"" << endl;
     
-    Vamp::PluginBase *plugin = instantiateDefaultPluginFor
+    std::shared_ptr<Vamp::PluginBase> plugin = instantiateDefaultPluginFor
         (transform.getIdentifier(), transform.getSampleRate());
 
     if (plugin) {
@@ -781,7 +780,7 @@
     return plugin;
 }
 
-Vamp::PluginBase *
+std::shared_ptr<Vamp::PluginBase> 
 TransformFactory::instantiateDefaultPluginFor(TransformId identifier,
                                               sv_samplerate_t rate)
 {
@@ -790,7 +789,7 @@
     if (rate == 0) rate = 44100.0;
     QString pluginId = t.getPluginIdentifier();
 
-    Vamp::PluginBase *plugin = nullptr;
+    std::shared_ptr<Vamp::PluginBase> plugin = nullptr;
 
     if (t.getType() == Transform::FeatureExtraction) {
 
@@ -824,24 +823,6 @@
     return plugin;
 }
 
-Vamp::Plugin *
-TransformFactory::downcastVampPlugin(Vamp::PluginBase *plugin)
-{
-    Vamp::Plugin *vp = dynamic_cast<Vamp::Plugin *>(plugin);
-    if (!vp) {
-//        cerr << "makeConsistentWithPlugin: not a Vamp::Plugin" << endl;
-        vp = dynamic_cast<Vamp::PluginHostAdapter *>(plugin); //!!! why?
-}
-    if (!vp) {
-//        cerr << "makeConsistentWithPlugin: not a Vamp::PluginHostAdapter" << endl;
-        vp = dynamic_cast<Vamp::HostExt::PluginWrapper *>(plugin); //!!! no, I mean really why?
-    }
-    if (!vp) {
-//        cerr << "makeConsistentWithPlugin: not a Vamp::HostExt::PluginWrapper" << endl;
-    }
-    return vp;
-}
-
 bool
 TransformFactory::haveTransform(TransformId identifier)
 {
@@ -894,12 +875,12 @@
         return Vamp::Plugin::TimeDomain;
     }
 
-    Vamp::Plugin *plugin =
-        downcastVampPlugin(instantiateDefaultPluginFor(identifier, 0));
+    std::shared_ptr<Vamp::Plugin> plugin =
+        std::dynamic_pointer_cast<Vamp::Plugin>
+        (instantiateDefaultPluginFor(identifier, 0));
 
     if (plugin) {
         Vamp::Plugin::InputDomain d = plugin->getInputDomain();
-        delete plugin;
         return d;
     }
 
@@ -922,13 +903,15 @@
 
     if (RealTimePluginFactory::instanceFor(id)) {
 
-        const RealTimePluginDescriptor *descriptor = 
+        RealTimePluginDescriptor descriptor = 
             RealTimePluginFactory::instanceFor(id)->
             getPluginDescriptor(id);
-        if (!descriptor) return false;
+        if (descriptor.name == "") {
+            return false;
+        }
 
-        min = descriptor->audioInputPortCount;
-        max = descriptor->audioInputPortCount;
+        min = descriptor.audioInputPortCount;
+        max = descriptor.audioInputPortCount;
 
         return true;
 
@@ -949,7 +932,7 @@
 
 void
 TransformFactory::setParametersFromPlugin(Transform &transform,
-                                          Vamp::PluginBase *plugin)
+                                          std::shared_ptr<Vamp::PluginBase> plugin)
 {
     Transform::ParameterMap pmap;
 
@@ -976,8 +959,8 @@
         transform.setProgram(plugin->getCurrentProgram().c_str());
     }
 
-    RealTimePluginInstance *rtpi =
-        dynamic_cast<RealTimePluginInstance *>(plugin);
+    std::shared_ptr<RealTimePluginInstance> rtpi =
+        std::dynamic_pointer_cast<RealTimePluginInstance>(plugin);
 
     Transform::ConfigurationMap cmap;
 
@@ -997,14 +980,14 @@
 
 void
 TransformFactory::setPluginParameters(const Transform &transform,
-                                      Vamp::PluginBase *plugin)
+                                      std::shared_ptr<Vamp::PluginBase> plugin)
 {
     //!!! check plugin & API version (see e.g. PluginXml::setParameters)
 
     //!!! check that this is the right plugin!
 
-    RealTimePluginInstance *rtpi =
-        dynamic_cast<RealTimePluginInstance *>(plugin);
+    std::shared_ptr<RealTimePluginInstance> rtpi =
+        std::dynamic_pointer_cast<RealTimePluginInstance>(plugin);
 
     if (rtpi) {
         const Transform::ConfigurationMap &cmap = transform.getConfiguration();
@@ -1035,9 +1018,10 @@
 
 void
 TransformFactory::makeContextConsistentWithPlugin(Transform &transform,
-                                                  Vamp::PluginBase *plugin)
+                                                  std::shared_ptr<Vamp::PluginBase> plugin)
 {
-    const Vamp::Plugin *vp = downcastVampPlugin(plugin);
+    std::shared_ptr<Vamp::Plugin> vp =
+        std::dynamic_pointer_cast<Vamp::Plugin>(plugin);
 
     if (!vp) {
         // time domain input for real-time effects plugin
@@ -1078,8 +1062,7 @@
     SVDEBUG << "TransformFactory::getPluginConfigurationXml: identifier \""
             << t.getIdentifier() << "\"" << endl;
 
-    Vamp::PluginBase *plugin = instantiateDefaultPluginFor
-        (t.getIdentifier(), 0);
+    auto plugin = instantiateDefaultPluginFor(t.getIdentifier(), 0);
     if (!plugin) {
         SVDEBUG << "TransformFactory::getPluginConfigurationXml: "
                 << "Unable to instantiate plugin for transform \""
@@ -1091,7 +1074,6 @@
 
     QTextStream out(&xml);
     PluginXml(plugin).toXml(out);
-    delete plugin;
 
     return xml;
 }
@@ -1103,8 +1085,7 @@
     SVDEBUG << "TransformFactory::setParametersFromPluginConfigurationXml: identifier \""
             << t.getIdentifier() << "\"" << endl;
 
-    Vamp::PluginBase *plugin = instantiateDefaultPluginFor
-        (t.getIdentifier(), 0);
+    auto plugin = instantiateDefaultPluginFor(t.getIdentifier(), 0);
     if (!plugin) {
         SVDEBUG << "TransformFactory::setParametersFromPluginConfigurationXml: "
                 << "Unable to instantiate plugin for transform \""
@@ -1114,7 +1095,6 @@
 
     PluginXml(plugin).setParametersFromXml(xml);
     setParametersFromPlugin(t, plugin);
-    delete plugin;
 }
 
 TransformFactory::SearchResults
--- a/transform/TransformFactory.h	Fri Mar 27 10:06:03 2020 +0000
+++ b/transform/TransformFactory.h	Fri Apr 03 12:12:02 2020 +0100
@@ -88,7 +88,8 @@
      * with different parameters and execution context settings.
      * Return the default one for the given transform.
      */
-    Transform getDefaultTransformFor(TransformId identifier, sv_samplerate_t rate = 0);
+    Transform getDefaultTransformFor(TransformId identifier,
+                                     sv_samplerate_t rate = 0);
 
     /**
      * Full name of a transform, suitable for putting on a menu.
@@ -138,19 +139,9 @@
      * Vamp::PluginBase, but not necessarily a Vamp::Plugin (only if
      * the transform was a feature-extraction type -- call
      * downcastVampPlugin if you only want Vamp::Plugins).  Returns
-     * NULL if no suitable plugin was available.
-     *
-     * The returned plugin is owned by the caller, and should be
-     * deleted (using "delete") when no longer needed.
+     * nullptr if no suitable plugin was available.
      */
-    Vamp::PluginBase *instantiatePluginFor(const Transform &transform);
-
-    /**
-     * Convert a Vamp::PluginBase to a Vamp::Plugin, if it is one.
-     * Return NULL otherwise.  This ill-fitting convenience function
-     * is really just a dynamic_cast wrapper.
-     */
-    Vamp::Plugin *downcastVampPlugin(Vamp::PluginBase *);
+    std::shared_ptr<Vamp::PluginBase> instantiatePluginFor(const Transform &transform);
 
     /**
      * Set the plugin parameters, program and configuration strings on
@@ -158,20 +149,20 @@
      * Note that no check is made whether the plugin is actually the
      * "correct" one for the transform.
      */
-    void setParametersFromPlugin(Transform &transform, Vamp::PluginBase *plugin);
+    void setParametersFromPlugin(Transform &transform, std::shared_ptr<Vamp::PluginBase> plugin);
 
     /**
      * Set the parameters, program and configuration strings on the
      * given plugin from the given Transform object.
      */
-    void setPluginParameters(const Transform &transform, Vamp::PluginBase *plugin);
+    void setPluginParameters(const Transform &transform, std::shared_ptr<Vamp::PluginBase> plugin);
     
     /**
      * If the given Transform object has no processing step and block
      * sizes set, set them to appropriate defaults for the given
      * plugin.
      */
-    void makeContextConsistentWithPlugin(Transform &transform, Vamp::PluginBase *plugin); 
+    void makeContextConsistentWithPlugin(Transform &transform, std::shared_ptr<Vamp::PluginBase> plugin); 
 
     /**
      * Retrieve a <plugin ... /> XML fragment that describes the
@@ -216,7 +207,7 @@
     void populateFeatureExtractionPlugins(TransformDescriptionMap &);
     void populateRealTimePlugins(TransformDescriptionMap &);
 
-    Vamp::PluginBase *instantiateDefaultPluginFor(TransformId id, sv_samplerate_t rate);
+    std::shared_ptr<Vamp::PluginBase> instantiateDefaultPluginFor(TransformId id, sv_samplerate_t rate);
     QMutex m_transformsMutex;
     QMutex m_uninstalledTransformsMutex;