annotate vamp-client/PiperVampPlugin.h @ 218:ea8994465322

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