annotate vamp-client/PluginStub.h @ 185:3eb00e5c76c4

Pull step & block size out into framing struct, return in config Update the C++ code to separate out the framing parameters (step and block size) from the configuration structure into their own structure, as in the latest schema, and to return the accepted framing params in the configuration response. This also implies that the plugin stub (which adapts Piper API back to Vamp) makes a note of the returned values, making them available via its own getPreferredStep/BlockSize so that the host can retry the initialise call in the case where it failed for having the wrong values first time.
author Chris Cannam <cannam@all-day-breakfast.com>
date Fri, 03 Feb 2017 16:23:21 +0000
parents 590b1a1fd955
children 52322dde68ea
rev   line source
c@118 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
c@118 2 /*
c@118 3 Piper C++
c@118 4
c@118 5 An API for audio analysis and feature extraction plugins.
c@118 6
c@118 7 Centre for Digital Music, Queen Mary, University of London.
c@118 8 Copyright 2006-2016 Chris Cannam and QMUL.
c@118 9
c@118 10 Permission is hereby granted, free of charge, to any person
c@118 11 obtaining a copy of this software and associated documentation
c@118 12 files (the "Software"), to deal in the Software without
c@118 13 restriction, including without limitation the rights to use, copy,
c@118 14 modify, merge, publish, distribute, sublicense, and/or sell copies
c@118 15 of the Software, and to permit persons to whom the Software is
c@118 16 furnished to do so, subject to the following conditions:
c@118 17
c@118 18 The above copyright notice and this permission notice shall be
c@118 19 included in all copies or substantial portions of the Software.
c@118 20
c@118 21 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
c@118 22 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
c@118 23 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
c@118 24 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
c@118 25 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
c@118 26 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
c@118 27 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
c@118 28
c@118 29 Except as contained in this notice, the names of the Centre for
c@118 30 Digital Music; Queen Mary, University of London; and Chris Cannam
c@118 31 shall not be used in advertising or otherwise to promote the sale,
c@118 32 use or other dealings in this Software without prior written
c@118 33 authorization.
c@118 34 */
c@94 35
c@94 36 #ifndef PIPER_PLUGIN_STUB_H
c@94 37 #define PIPER_PLUGIN_STUB_H
c@94 38
c@94 39 #include <vamp-hostsdk/Plugin.h>
c@94 40 #include <vamp-hostsdk/PluginLoader.h>
c@97 41
c@97 42 #include "vamp-support/PluginStaticData.h"
c@97 43 #include "vamp-support/PluginConfiguration.h"
c@94 44
cannam@167 45 #include "PluginClient.h"
cannam@167 46
c@94 47 #include <cstdint>
cannam@167 48 #include <iostream>
c@94 49
c@97 50 namespace piper_vamp {
c@97 51 namespace client {
c@94 52
c@94 53 class PluginStub : public Vamp::Plugin
c@94 54 {
c@94 55 enum State {
cannam@167 56 Loaded, Configured, Finished, Failed
c@94 57 };
c@94 58
c@94 59 public:
c@94 60 PluginStub(PluginClient *client,
c@94 61 std::string pluginKey,
c@94 62 float inputSampleRate,
c@94 63 int adapterFlags,
c@97 64 PluginStaticData psd,
c@97 65 PluginConfiguration defaultConfig) :
c@94 66 Plugin(inputSampleRate),
c@94 67 m_client(client),
c@94 68 m_key(pluginKey),
c@94 69 m_adapterFlags(adapterFlags),
c@94 70 m_state(Loaded),
c@94 71 m_psd(psd),
c@94 72 m_defaultConfig(defaultConfig),
c@94 73 m_config(defaultConfig)
c@94 74 { }
c@94 75
c@94 76 virtual ~PluginStub() {
cannam@167 77 if (m_state != Finished && m_state != Failed) {
cannam@167 78 try {
cannam@167 79 (void)m_client->finish(this);
cannam@167 80 } catch (const std::exception &e) {
cannam@167 81 // Finish can throw, but our destructor must not
cannam@167 82 std::cerr << "WARNING: PluginStub::~PluginStub: caught exception from finish(): " << e.what() << std::endl;
cannam@167 83 }
c@94 84 }
c@94 85 }
c@94 86
c@94 87 virtual std::string getIdentifier() const {
c@94 88 return m_psd.basic.identifier;
c@94 89 }
c@94 90
c@94 91 virtual std::string getName() const {
c@94 92 return m_psd.basic.name;
c@94 93 }
c@94 94
c@94 95 virtual std::string getDescription() const {
c@94 96 return m_psd.basic.description;
c@94 97 }
c@94 98
c@94 99 virtual std::string getMaker() const {
c@94 100 return m_psd.maker;
c@94 101 }
c@94 102
c@94 103 virtual std::string getCopyright() const {
c@94 104 return m_psd.copyright;
c@94 105 }
c@94 106
c@94 107 virtual int getPluginVersion() const {
c@94 108 return m_psd.pluginVersion;
c@94 109 }
c@94 110
c@94 111 virtual ParameterList getParameterDescriptors() const {
c@94 112 return m_psd.parameters;
c@94 113 }
c@94 114
c@94 115 virtual float getParameter(std::string name) const {
c@94 116 if (m_config.parameterValues.find(name) != m_config.parameterValues.end()) {
c@94 117 return m_config.parameterValues.at(name);
c@94 118 } else {
c@94 119 return 0.f;
c@94 120 }
c@94 121 }
c@94 122
c@94 123 virtual void setParameter(std::string name, float value) {
cannam@167 124 if (m_state == Failed) {
cannam@167 125 throw std::logic_error("Plugin is in failed state");
cannam@167 126 }
c@94 127 if (m_state != Loaded) {
cannam@167 128 m_state = Failed;
c@94 129 throw std::logic_error("Can't set parameter after plugin initialised");
c@94 130 }
c@94 131 m_config.parameterValues[name] = value;
c@94 132 }
c@94 133
c@94 134 virtual ProgramList getPrograms() const {
c@94 135 return m_psd.programs;
c@94 136 }
c@94 137
c@94 138 virtual std::string getCurrentProgram() const {
c@94 139 return m_config.currentProgram;
c@94 140 }
c@94 141
c@94 142 virtual void selectProgram(std::string program) {
cannam@167 143 if (m_state == Failed) {
cannam@167 144 throw std::logic_error("Plugin is in failed state");
cannam@167 145 }
c@94 146 if (m_state != Loaded) {
cannam@167 147 m_state = Failed;
c@94 148 throw std::logic_error("Can't select program after plugin initialised");
c@94 149 }
c@94 150 m_config.currentProgram = program;
c@94 151 }
c@94 152
c@94 153 virtual bool initialise(size_t inputChannels,
c@94 154 size_t stepSize,
c@94 155 size_t blockSize) {
c@94 156
cannam@167 157 if (m_state == Failed) {
cannam@167 158 throw std::logic_error("Plugin is in failed state");
cannam@167 159 }
c@94 160 if (m_state != Loaded) {
cannam@167 161 m_state = Failed;
c@94 162 throw std::logic_error("Plugin has already been initialised");
c@94 163 }
c@94 164
c@102 165 m_config.channelCount = int(inputChannels);
cannam@185 166 m_config.framing.stepSize = int(stepSize);
cannam@185 167 m_config.framing.blockSize = int(blockSize);
c@94 168
cannam@169 169 try {
cannam@185 170 auto response = m_client->configure(this, m_config);
cannam@185 171 m_outputs = response.outputs;
cannam@185 172
cannam@185 173 // Update with the new preferred step and block size now
cannam@185 174 // that the plugin has taken into account its parameter
cannam@185 175 // settings. If the values passed in to initialise()
cannam@185 176 // weren't suitable, then this ensures that a subsequent
cannam@185 177 // call to getPreferredStepSize/BlockSize on this plugin
cannam@185 178 // object will at least get acceptable values from now on
cannam@185 179 m_config.framing = response.framing;
cannam@185 180
cannam@169 181 } catch (const std::exception &e) {
cannam@169 182 m_state = Failed;
cannam@169 183 throw;
cannam@169 184 }
c@94 185
c@94 186 if (!m_outputs.empty()) {
c@94 187 m_state = Configured;
c@94 188 return true;
c@94 189 } else {
c@94 190 return false;
c@94 191 }
c@94 192 }
c@94 193
c@94 194 virtual void reset() {
c@94 195
cannam@167 196 if (m_state == Failed) {
cannam@167 197 throw std::logic_error("Plugin is in failed state");
cannam@167 198 }
c@94 199 if (m_state == Loaded) {
c@94 200 // reset is a no-op if the plugin hasn't been initialised yet
c@94 201 return;
c@94 202 }
cannam@169 203
cannam@169 204 try {
cannam@169 205 m_client->reset(this, m_config);
cannam@169 206 } catch (const std::exception &e) {
cannam@169 207 m_state = Failed;
cannam@169 208 throw;
cannam@169 209 }
c@94 210
c@94 211 m_state = Configured;
c@94 212 }
c@94 213
c@94 214 virtual InputDomain getInputDomain() const {
c@94 215 return m_psd.inputDomain;
c@94 216 }
c@94 217
c@94 218 virtual size_t getPreferredBlockSize() const {
cannam@185 219 // Return this from m_config instead of m_defaultConfig, so
cannam@185 220 // that it gets updated in the event of an initialise() call
cannam@185 221 // that fails for the wrong value
cannam@185 222 return m_config.framing.blockSize;
c@94 223 }
c@94 224
c@94 225 virtual size_t getPreferredStepSize() const {
cannam@185 226 // Return this from m_config instead of m_defaultConfig, so
cannam@185 227 // that it gets updated in the event of an initialise() call
cannam@185 228 // that fails for the wrong value
cannam@185 229 return m_config.framing.stepSize;
c@94 230 }
c@94 231
c@94 232 virtual size_t getMinChannelCount() const {
c@94 233 return m_psd.minChannelCount;
c@94 234 }
c@94 235
c@94 236 virtual size_t getMaxChannelCount() const {
c@94 237 return m_psd.maxChannelCount;
c@94 238 }
c@94 239
c@94 240 virtual OutputList getOutputDescriptors() const {
cannam@167 241
cannam@167 242 if (m_state == Failed) {
cannam@167 243 throw std::logic_error("Plugin is in failed state");
cannam@167 244 }
c@94 245 if (m_state == Configured) {
c@94 246 return m_outputs;
c@94 247 }
c@94 248
c@94 249 //!!! todo: figure out for which hosts (and adapters?) it may
c@94 250 //!!! be a problem that the output descriptors are incomplete
c@94 251 //!!! here. Any such hosts/adapters are broken, but I bet they
c@94 252 //!!! exist
c@94 253
c@94 254 OutputList staticOutputs;
c@94 255 for (const auto &o: m_psd.basicOutputInfo) {
c@94 256 OutputDescriptor od;
c@94 257 od.identifier = o.identifier;
c@94 258 od.name = o.name;
c@94 259 od.description = o.description;
c@94 260 staticOutputs.push_back(od);
c@94 261 }
c@94 262 return staticOutputs;
c@94 263 }
c@94 264
c@94 265 virtual FeatureSet process(const float *const *inputBuffers,
c@118 266 Vamp::RealTime timestamp) {
c@94 267
cannam@167 268 if (m_state == Failed) {
cannam@167 269 throw std::logic_error("Plugin is in failed state");
cannam@167 270 }
c@94 271 if (m_state == Loaded) {
cannam@167 272 m_state = Failed;
c@94 273 throw std::logic_error("Plugin has not been initialised");
c@94 274 }
c@94 275 if (m_state == Finished) {
cannam@167 276 m_state = Failed;
c@94 277 throw std::logic_error("Plugin has already been disposed of");
c@94 278 }
c@94 279
c@94 280 std::vector<std::vector<float> > vecbuf;
c@94 281 for (int c = 0; c < m_config.channelCount; ++c) {
c@94 282 vecbuf.push_back(std::vector<float>
c@94 283 (inputBuffers[c],
cannam@185 284 inputBuffers[c] + m_config.framing.blockSize));
c@94 285 }
cannam@169 286
cannam@169 287 try {
cannam@169 288 return m_client->process(this, vecbuf, timestamp);
cannam@169 289 } catch (const std::exception &e) {
cannam@169 290 m_state = Failed;
cannam@169 291 throw;
cannam@169 292 }
c@94 293 }
c@94 294
c@94 295 virtual FeatureSet getRemainingFeatures() {
c@94 296
cannam@167 297 if (m_state == Failed) {
cannam@167 298 throw std::logic_error("Plugin is in failed state");
cannam@167 299 }
c@94 300 if (m_state == Loaded) {
cannam@167 301 m_state = Failed;
c@94 302 throw std::logic_error("Plugin has not been configured");
c@94 303 }
c@94 304 if (m_state == Finished) {
cannam@167 305 m_state = Failed;
c@94 306 throw std::logic_error("Plugin has already been disposed of");
c@94 307 }
c@94 308
c@94 309 m_state = Finished;
c@94 310
cannam@169 311 try {
cannam@169 312 return m_client->finish(this);
cannam@169 313 } catch (const std::exception &e) {
cannam@169 314 m_state = Failed;
cannam@169 315 throw;
cannam@169 316 }
c@94 317 }
c@94 318
c@94 319 // Not Plugin methods, but needed by the PluginClient to support reloads:
c@94 320
c@94 321 virtual float getInputSampleRate() const {
c@94 322 return m_inputSampleRate;
c@94 323 }
c@94 324
c@94 325 virtual std::string getPluginKey() const {
c@94 326 return m_key;
c@94 327 }
c@94 328
c@94 329 virtual int getAdapterFlags() const {
c@94 330 return m_adapterFlags;
c@94 331 }
c@94 332
c@94 333 private:
c@94 334 PluginClient *m_client;
c@94 335 std::string m_key;
c@94 336 int m_adapterFlags;
c@94 337 State m_state;
c@97 338 PluginStaticData m_psd;
c@94 339 OutputList m_outputs;
c@97 340 PluginConfiguration m_defaultConfig;
c@97 341 PluginConfiguration m_config;
c@94 342 };
c@94 343
c@94 344 }
c@94 345 }
c@94 346
c@94 347 #endif