changeset 193:bc35e19f3345

Merge branch 'master' of https://github.com/piper-audio/piper-cpp into test/plugin-stub-configured-framing
author Lucas Thompson <dev@lucas.im>
date Tue, 07 Feb 2017 16:35:32 +0000
parents 79c64ff2610b (current diff) 458766b73e71 (diff)
children 4848852c4fbd
files
diffstat 4 files changed, 125 insertions(+), 21 deletions(-) [+]
line wrap: on
line diff
--- a/vamp-client/PluginStub.h	Tue Feb 07 16:35:16 2017 +0000
+++ b/vamp-client/PluginStub.h	Tue Feb 07 16:35:32 2017 +0000
@@ -53,7 +53,48 @@
 class PluginStub : public Vamp::Plugin
 {
     enum State {
-        Loaded, Configured, Finished, Failed
+        /**
+         * The plugin's corresponding Piper feature extractor has been
+         * loaded but no subsequent state change has happened. This is
+         * the initial state of PluginStub on construction, since it
+         * is associated with a pre-loaded handle.
+         */
+        Loaded,
+        
+        /**
+         * The plugin has been configured, and the step and block size
+         * received from the host in its last call to initialise()
+         * match those that were returned in the configuration
+         * response (i.e. the server's desired step and block
+         * size). Our m_config record reflects these correct
+         * values. The plugin is ready to process.
+         */
+        Configured,
+
+        /**
+         * The plugin has been configured, but the step and block size
+         * received from the host in its last call to initialise()
+         * differ from those returned by the server in the
+         * configuration response. Our initialise() call therefore
+         * returned false, and the plugin cannot be used until the
+         * host calls initialise() again with the "correct" step and
+         * block size. Our m_config record reflects these correct
+         * values, so the host can retrieve them through
+         * getPreferredStepSize and getPreferredBlockSize.
+         */
+        Misconfigured,
+
+        /**
+         * The finish() function has been called and the plugin
+         * unloaded. No further plugin activity is possible.
+         */
+        Finished,
+
+        /** 
+         * A call has failed unrecoverably. No further plugin activity
+         * is possible.
+         */
+        Failed
     };
     
 public:
@@ -157,6 +198,17 @@
         if (m_state == Failed) {
             throw std::logic_error("Plugin is in failed state");
         }
+
+        if (m_state == Misconfigured) {
+            if (int(stepSize) == m_config.framing.stepSize &&
+                int(blockSize) == m_config.framing.blockSize) {
+                m_state = Configured;
+                return true;
+            } else {
+                return false;
+            }
+        }
+        
         if (m_state != Loaded) {
             m_state = Failed;
             throw std::logic_error("Plugin has already been initialised");
@@ -169,7 +221,7 @@
         try {
             auto response = m_client->configure(this, m_config);
             m_outputs = response.outputs;
-
+            
             // Update with the new preferred step and block size now
             // that the plugin has taken into account its parameter
             // settings. If the values passed in to initialise()
@@ -177,6 +229,16 @@
             // call to getPreferredStepSize/BlockSize on this plugin
             // object will at least get acceptable values from now on
             m_config.framing = response.framing;
+
+            // And if they didn't match up with the passed-in ones,
+            // lodge ourselves in Misconfigured state and report
+            // failure so as to provoke the host to call initialise()
+            // again before any processing.
+            if (m_config.framing.stepSize != int(stepSize) ||
+                m_config.framing.blockSize != int(blockSize)) {
+                m_state = Misconfigured;
+                return false;
+            }
             
         } catch (const std::exception &e) {
             m_state = Failed;
@@ -196,7 +258,7 @@
         if (m_state == Failed) {
             throw std::logic_error("Plugin is in failed state");
         }
-        if (m_state == Loaded) {
+        if (m_state == Loaded || m_state == Misconfigured) {
             // reset is a no-op if the plugin hasn't been initialised yet
             return;
         }
@@ -268,7 +330,7 @@
         if (m_state == Failed) {
             throw std::logic_error("Plugin is in failed state");
         }
-        if (m_state == Loaded) {
+        if (m_state == Loaded || m_state == Misconfigured) {
             m_state = Failed;
             throw std::logic_error("Plugin has not been initialised");
         }
@@ -297,7 +359,7 @@
         if (m_state == Failed) {
             throw std::logic_error("Plugin is in failed state");
         }
-        if (m_state == Loaded) {
+        if (m_state == Loaded || m_state == Misconfigured) {
             m_state = Failed;
             throw std::logic_error("Plugin has not been configured");
         }
--- a/vamp-client/qt/AutoPlugin.h	Tue Feb 07 16:35:16 2017 +0000
+++ b/vamp-client/qt/AutoPlugin.h	Tue Feb 07 16:35:32 2017 +0000
@@ -138,14 +138,7 @@
     virtual bool initialise(size_t inputChannels,
                             size_t stepSize,
                             size_t blockSize) {
-        try {
-            return getPlugin()->initialise(inputChannels, stepSize, blockSize);
-        } catch (const ServiceError &e) {
-            // Sadly, the Vamp API has taught hosts to try to divine
-            // initialisation problems from a bool return value alone
-            log(std::string("AutoPlugin: initialise failed: ") + e.what());
-            return false;
-        }
+        return getPlugin()->initialise(inputChannels, stepSize, blockSize);
     }
 
     virtual void reset() {
--- a/vamp-server/simple-server.cpp	Tue Feb 07 16:35:16 2017 +0000
+++ b/vamp-server/simple-server.cpp	Tue Feb 07 16:35:32 2017 +0000
@@ -495,7 +495,7 @@
             mapper.markConfigured
                 (h,
                  creq.configuration.channelCount,
-                 creq.configuration.framing.blockSize);
+                 response.configurationResponse.framing.blockSize);
             response.success = true;
         }
         break;
@@ -521,8 +521,12 @@
         const float **fbuffers = new const float *[channels];
         for (int i = 0; i < channels; ++i) {
             if (int(preq.inputBuffers[i].size()) != mapper.getBlockSize(h)) {
+                ostringstream os;
+                os << "wrong block size supplied to process ("
+                   << preq.inputBuffers[i].size()
+                   << ", expecting " << mapper.getBlockSize(h) << ")" << ends;
                 delete[] fbuffers;
-                throw runtime_error("wrong block size supplied to process");
+                throw runtime_error(os.str());
             }
             fbuffers[i] = preq.inputBuffers[i].data();
         }
--- a/vamp-support/LoaderRequests.h	Tue Feb 07 16:35:16 2017 +0000
+++ b/vamp-support/LoaderRequests.h	Tue Feb 07 16:35:32 2017 +0000
@@ -136,6 +136,10 @@
             return response;
         }
 
+        Framing pluginPreferredFraming;
+        pluginPreferredFraming.stepSize = req.plugin->getPreferredStepSize();
+        pluginPreferredFraming.blockSize = req.plugin->getPreferredBlockSize();
+        
 	if (req.plugin->initialise(req.configuration.channelCount,
 				   req.configuration.framing.stepSize,
 				   req.configuration.framing.blockSize)) {
@@ -148,13 +152,54 @@
             response.framing = req.configuration.framing;
 
 	} else {
+           
+            // If initialise() fails, one reason could be that it
+            // didn't like the passed-in framing (step and block
+            // size).
+            // 
+            // Vamp and Piper have quite different mechanisms for
+            // negotiating step and block size:
+            //
+            // - If a Vamp plugin doesn't like the step and block size
+            // passed to initialise(), it fails the initialise() call,
+            // returning false from it. The host is expected to have
+            // called getPreferredStepSize()/BlockSize() after it made
+            // any parameter changes that might have affected these
+            // preferences (but before calling initialise).
+            //
+            // - If a Piper server doesn't like the step and block
+            // size passed in a configure request, but if everything
+            // else about the configure request is OK, then it returns
+            // a successful configure response including its preferred
+            // step and block sizes in the response (which the host
+            // must then use). The important thing to note is that
+            // this is still a successful response, something we do
+            // not yet have here.
+            //
+            // We need to check whether the passed-in framing differs
+            // from the plugin's preferences; if so, then we form a
+            // working supposition that initialise() failed because of
+            // this. Vamp contains nothing to allow us to test this,
+            // except to try initialise() again with different
+            // values. So we try again with the values the plugin told
+            // us it would prefer and, if that succeeds, return them
+            // in a successful response in the Piper manner.
+            //
+            // Note that if the "other side" (i.e. the client) wants
+            // to interpret this as if it were dealing with a Vamp
+            // plugin, then it's going to need some equal-but-opposite
+            // acrobatics.
 
-            // If initialise() fails, one reason could be that it
-            // didn't like the passed-in step and block size. If we
-            // return its current preferred values here, the
-            // host/client can retry with these (if they differ)
-            response.framing.stepSize = req.plugin->getPreferredStepSize();
-            response.framing.blockSize = req.plugin->getPreferredBlockSize();
+            if (req.plugin->initialise(req.configuration.channelCount,
+                                       pluginPreferredFraming.stepSize,
+                                       pluginPreferredFraming.blockSize)) {
+
+                response.outputs = req.plugin->getOutputDescriptors();
+                response.framing = pluginPreferredFraming;
+
+            } // ... else we return no outputs, which is the error
+              // case (presumably to be converted to Piper error
+              // response).
         }
 
 	return response;