annotate vamp-client/PiperVampPlugin.h @ 292:16842bf06026

Fix some compiler warnings
author Chris Cannam <cannam@all-day-breakfast.com>
date Wed, 13 Jan 2021 15:36:24 +0000
parents 26027c3a99a0
children
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@287 44 #include "vamp-support/PluginProgramParameters.h"
cannam@208 45
cannam@208 46 #include "PluginClient.h"
cannam@208 47
cannam@208 48 #include <cstdint>
cannam@208 49 #include <iostream>
cannam@208 50
cannam@208 51 namespace piper_vamp {
cannam@208 52 namespace client {
cannam@208 53
cannam@210 54 /**
cannam@210 55 * PiperVampPlugin presents a Piper feature extractor in the form of a
cannam@210 56 * Vamp plugin.
cannam@210 57 */
cannam@208 58 class PiperVampPlugin : public Vamp::Plugin
cannam@208 59 {
cannam@208 60 enum State {
cannam@208 61 /**
cannam@208 62 * The plugin's corresponding Piper feature extractor has been
cannam@208 63 * loaded but no subsequent state change has happened. This is
cannam@208 64 * the initial state of PiperVampPlugin on construction, since
cannam@208 65 * it is associated with a pre-loaded handle.
cannam@208 66 */
cannam@208 67 Loaded,
cannam@208 68
cannam@208 69 /**
cannam@208 70 * The plugin has been configured, and the step and block size
cannam@208 71 * received from the host in its last call to initialise()
cannam@208 72 * match those that were returned in the configuration
cannam@208 73 * response (i.e. the server's desired step and block
cannam@208 74 * size). Our m_config record reflects these correct
cannam@208 75 * values. The plugin is ready to process.
cannam@208 76 */
cannam@208 77 Configured,
cannam@208 78
cannam@208 79 /**
cannam@208 80 * The plugin has been configured, but the step and block size
cannam@208 81 * received from the host in its last call to initialise()
cannam@208 82 * differ from those returned by the server in the
cannam@208 83 * configuration response. Our initialise() call therefore
cannam@208 84 * returned false, and the plugin cannot be used until the
cannam@208 85 * host calls initialise() again with the "correct" step and
cannam@208 86 * block size. Our m_config record reflects these correct
cannam@208 87 * values, so the host can retrieve them through
cannam@208 88 * getPreferredStepSize and getPreferredBlockSize.
cannam@208 89 */
cannam@208 90 Misconfigured,
cannam@208 91
cannam@208 92 /**
cannam@208 93 * The finish() function has been called and the plugin
cannam@208 94 * unloaded. No further plugin activity is possible.
cannam@208 95 */
cannam@208 96 Finished,
cannam@208 97
cannam@208 98 /**
cannam@208 99 * A call has failed unrecoverably. No further plugin activity
cannam@208 100 * is possible.
cannam@208 101 */
cannam@208 102 Failed
cannam@208 103 };
cannam@208 104
cannam@208 105 public:
cannam@208 106 PiperVampPlugin(PluginClient *client,
cannam@208 107 std::string pluginKey,
cannam@208 108 float inputSampleRate,
cannam@208 109 int adapterFlags,
cannam@208 110 PluginStaticData psd,
cannam@287 111 PluginConfiguration defaultConfig,
cannam@287 112 PluginProgramParameters programParameters) :
cannam@208 113 Plugin(inputSampleRate),
cannam@208 114 m_client(client),
cannam@208 115 m_key(pluginKey),
cannam@208 116 m_adapterFlags(adapterFlags),
cannam@208 117 m_state(Loaded),
cannam@208 118 m_psd(psd),
cannam@208 119 m_defaultConfig(defaultConfig),
cannam@287 120 m_config(defaultConfig),
cannam@287 121 m_programParameters(programParameters)
cannam@208 122 { }
cannam@289 123
cannam@208 124 virtual ~PiperVampPlugin() {
cannam@208 125 if (m_state != Finished && m_state != Failed) {
cannam@208 126 try {
cannam@208 127 (void)m_client->finish(this);
cannam@208 128 } catch (const std::exception &e) {
cannam@208 129 // Finish can throw, but our destructor must not
cannam@208 130 std::cerr << "WARNING: PiperVampPlugin::~PiperVampPlugin: caught exception from finish(): " << e.what() << std::endl;
cannam@208 131 }
cannam@208 132 }
cannam@208 133 }
cannam@208 134
cannam@280 135 std::string getIdentifier() const override {
cannam@208 136 return m_psd.basic.identifier;
cannam@208 137 }
cannam@208 138
cannam@280 139 std::string getName() const override {
cannam@208 140 return m_psd.basic.name;
cannam@208 141 }
cannam@208 142
cannam@280 143 std::string getDescription() const override {
cannam@208 144 return m_psd.basic.description;
cannam@208 145 }
cannam@208 146
cannam@280 147 std::string getMaker() const override {
cannam@208 148 return m_psd.maker;
cannam@208 149 }
cannam@208 150
cannam@280 151 std::string getCopyright() const override {
cannam@208 152 return m_psd.copyright;
cannam@208 153 }
cannam@208 154
cannam@280 155 int getPluginVersion() const override {
cannam@208 156 return m_psd.pluginVersion;
cannam@208 157 }
cannam@208 158
cannam@280 159 ParameterList getParameterDescriptors() const override {
cannam@208 160 return m_psd.parameters;
cannam@208 161 }
cannam@208 162
cannam@280 163 float getParameter(std::string name) const override {
cannam@208 164 if (m_config.parameterValues.find(name) != m_config.parameterValues.end()) {
cannam@208 165 return m_config.parameterValues.at(name);
cannam@208 166 } else {
cannam@208 167 return 0.f;
cannam@208 168 }
cannam@208 169 }
cannam@208 170
cannam@280 171 void setParameter(std::string name, float value) override {
cannam@208 172 if (m_state == Failed) {
cannam@208 173 throw std::logic_error("Plugin is in failed state");
cannam@208 174 }
cannam@208 175 if (m_state != Loaded) {
cannam@208 176 m_state = Failed;
cannam@208 177 throw std::logic_error("Can't set parameter after plugin initialised");
cannam@208 178 }
cannam@208 179 m_config.parameterValues[name] = value;
cannam@208 180 }
cannam@208 181
cannam@280 182 ProgramList getPrograms() const override {
cannam@208 183 return m_psd.programs;
cannam@208 184 }
cannam@208 185
cannam@280 186 std::string getCurrentProgram() const override {
cannam@208 187 return m_config.currentProgram;
cannam@208 188 }
cannam@208 189
cannam@280 190 void selectProgram(std::string program) override {
cannam@208 191 if (m_state == Failed) {
cannam@208 192 throw std::logic_error("Plugin is in failed state");
cannam@208 193 }
cannam@208 194 if (m_state != Loaded) {
cannam@208 195 m_state = Failed;
cannam@208 196 throw std::logic_error("Can't select program after plugin initialised");
cannam@208 197 }
cannam@208 198 m_config.currentProgram = program;
cannam@287 199
cannam@287 200 const auto &pp = m_programParameters.programParameters;
cannam@287 201 if (pp.find(program) != pp.end()) {
cannam@287 202 for (auto param: pp.at(program)) {
cannam@287 203 m_config.parameterValues[param.first] = param.second;
cannam@287 204 }
cannam@287 205 }
cannam@208 206 }
cannam@208 207
cannam@280 208 bool initialise(size_t inputChannels,
cannam@287 209 size_t stepSize,
cannam@287 210 size_t blockSize) override {
cannam@208 211
cannam@208 212 if (m_state == Failed) {
cannam@208 213 throw std::logic_error("Plugin is in failed state");
cannam@208 214 }
cannam@208 215
cannam@208 216 if (m_state == Misconfigured) {
cannam@208 217 if (int(stepSize) == m_config.framing.stepSize &&
cannam@208 218 int(blockSize) == m_config.framing.blockSize) {
cannam@208 219 m_state = Configured;
cannam@208 220 return true;
cannam@208 221 } else {
cannam@208 222 return false;
cannam@208 223 }
cannam@208 224 }
cannam@208 225
cannam@208 226 if (m_state != Loaded) {
cannam@208 227 m_state = Failed;
cannam@208 228 throw std::logic_error("Plugin has already been initialised");
cannam@208 229 }
cannam@208 230
cannam@208 231 m_config.channelCount = int(inputChannels);
cannam@208 232 m_config.framing.stepSize = int(stepSize);
cannam@208 233 m_config.framing.blockSize = int(blockSize);
cannam@208 234
cannam@208 235 try {
cannam@208 236 auto response = m_client->configure(this, m_config);
cannam@208 237 m_outputs = response.outputs;
cannam@208 238
cannam@208 239 // Update with the new preferred step and block size now
cannam@208 240 // that the plugin has taken into account its parameter
cannam@208 241 // settings. If the values passed in to initialise()
cannam@208 242 // weren't suitable, then this ensures that a subsequent
cannam@208 243 // call to getPreferredStepSize/BlockSize on this plugin
cannam@208 244 // object will at least get acceptable values from now on
cannam@208 245 m_config.framing = response.framing;
cannam@208 246
cannam@208 247 // And if they didn't match up with the passed-in ones,
cannam@208 248 // lodge ourselves in Misconfigured state and report
cannam@208 249 // failure so as to provoke the host to call initialise()
cannam@208 250 // again before any processing.
cannam@208 251 if (m_config.framing.stepSize != int(stepSize) ||
cannam@208 252 m_config.framing.blockSize != int(blockSize)) {
cannam@208 253 m_state = Misconfigured;
cannam@208 254 return false;
cannam@208 255 }
cannam@208 256
cannam@264 257 } catch (const std::exception &) {
cannam@208 258 m_state = Failed;
cannam@208 259 throw;
cannam@208 260 }
cannam@208 261
cannam@208 262 if (!m_outputs.empty()) {
cannam@208 263 m_state = Configured;
cannam@208 264 return true;
cannam@208 265 } else {
cannam@208 266 return false;
cannam@208 267 }
cannam@208 268 }
cannam@208 269
cannam@280 270 void reset() override {
cannam@208 271
cannam@208 272 if (m_state == Failed) {
cannam@208 273 throw std::logic_error("Plugin is in failed state");
cannam@208 274 }
cannam@208 275 if (m_state == Loaded || m_state == Misconfigured) {
cannam@208 276 // reset is a no-op if the plugin hasn't been initialised yet
cannam@208 277 return;
cannam@208 278 }
cannam@208 279
cannam@208 280 try {
cannam@208 281 m_client->reset(this, m_config);
cannam@264 282 } catch (const std::exception &) {
cannam@208 283 m_state = Failed;
cannam@208 284 throw;
cannam@208 285 }
cannam@208 286
cannam@208 287 m_state = Configured;
cannam@208 288 }
cannam@208 289
cannam@280 290 InputDomain getInputDomain() const override {
cannam@208 291 return m_psd.inputDomain;
cannam@208 292 }
cannam@208 293
cannam@280 294 size_t getPreferredBlockSize() const override {
cannam@208 295 // Return this from m_config instead of m_defaultConfig, so
cannam@208 296 // that it gets updated in the event of an initialise() call
cannam@208 297 // that fails for the wrong value
cannam@208 298 return m_config.framing.blockSize;
cannam@208 299 }
cannam@208 300
cannam@280 301 size_t getPreferredStepSize() const override {
cannam@208 302 // Return this from m_config instead of m_defaultConfig, so
cannam@208 303 // that it gets updated in the event of an initialise() call
cannam@208 304 // that fails for the wrong value
cannam@208 305 return m_config.framing.stepSize;
cannam@208 306 }
cannam@208 307
cannam@280 308 size_t getMinChannelCount() const override {
cannam@208 309 return m_psd.minChannelCount;
cannam@208 310 }
cannam@208 311
cannam@280 312 size_t getMaxChannelCount() const override {
cannam@208 313 return m_psd.maxChannelCount;
cannam@208 314 }
cannam@208 315
cannam@280 316 OutputList getOutputDescriptors() const override {
cannam@208 317
cannam@208 318 if (m_state == Failed) {
cannam@208 319 throw std::logic_error("Plugin is in failed state");
cannam@208 320 }
cannam@208 321 if (m_state == Configured) {
cannam@208 322 return m_outputs;
cannam@208 323 }
cannam@208 324
cannam@208 325 //!!! todo: figure out for which hosts (and adapters?) it may
cannam@208 326 //!!! be a problem that the output descriptors are incomplete
cannam@208 327 //!!! here. Any such hosts/adapters are broken, but I bet they
cannam@208 328 //!!! exist
cannam@208 329
cannam@208 330 OutputList staticOutputs;
cannam@208 331 for (const auto &o: m_psd.basicOutputInfo) {
cannam@208 332 OutputDescriptor od;
cannam@208 333 od.identifier = o.identifier;
cannam@208 334 od.name = o.name;
cannam@208 335 od.description = o.description;
cannam@208 336 staticOutputs.push_back(od);
cannam@208 337 }
cannam@208 338 return staticOutputs;
cannam@208 339 }
cannam@208 340
cannam@280 341 FeatureSet process(const float *const *inputBuffers,
cannam@280 342 Vamp::RealTime timestamp) override {
cannam@208 343
cannam@208 344 if (m_state == Failed) {
cannam@208 345 throw std::logic_error("Plugin is in failed state");
cannam@208 346 }
cannam@208 347 if (m_state == Loaded || m_state == Misconfigured) {
cannam@208 348 m_state = Failed;
cannam@208 349 throw std::logic_error("Plugin has not been initialised");
cannam@208 350 }
cannam@208 351 if (m_state == Finished) {
cannam@208 352 m_state = Failed;
cannam@208 353 throw std::logic_error("Plugin has already been disposed of");
cannam@208 354 }
cannam@208 355
cannam@208 356 std::vector<std::vector<float> > vecbuf;
cannam@273 357
cannam@273 358 int bufferSize;
cannam@273 359 if (m_psd.inputDomain == FrequencyDomain) {
cannam@273 360 bufferSize = 2 * (m_config.framing.blockSize / 2) + 2;
cannam@273 361 } else {
cannam@273 362 bufferSize = m_config.framing.blockSize;
cannam@273 363 }
cannam@273 364
cannam@208 365 for (int c = 0; c < m_config.channelCount; ++c) {
cannam@208 366 vecbuf.push_back(std::vector<float>
cannam@273 367 (inputBuffers[c], inputBuffers[c] + bufferSize));
cannam@208 368 }
cannam@208 369
cannam@208 370 try {
cannam@208 371 return m_client->process(this, vecbuf, timestamp);
cannam@264 372 } catch (const std::exception &) {
cannam@208 373 m_state = Failed;
cannam@208 374 throw;
cannam@208 375 }
cannam@208 376 }
cannam@208 377
cannam@280 378 FeatureSet getRemainingFeatures() override {
cannam@208 379
cannam@208 380 if (m_state == Failed) {
cannam@208 381 throw std::logic_error("Plugin is in failed state");
cannam@208 382 }
cannam@208 383 if (m_state == Loaded || m_state == Misconfigured) {
cannam@208 384 m_state = Failed;
cannam@208 385 throw std::logic_error("Plugin has not been configured");
cannam@208 386 }
cannam@208 387 if (m_state == Finished) {
cannam@208 388 m_state = Failed;
cannam@208 389 throw std::logic_error("Plugin has already been disposed of");
cannam@208 390 }
cannam@208 391
cannam@208 392 m_state = Finished;
cannam@208 393
cannam@208 394 try {
cannam@208 395 return m_client->finish(this);
cannam@264 396 } catch (const std::exception &) {
cannam@208 397 m_state = Failed;
cannam@208 398 throw;
cannam@208 399 }
cannam@208 400 }
cannam@208 401
cannam@208 402 // Not Plugin methods, but needed by the PluginClient to support reloads:
cannam@208 403
cannam@208 404 virtual float getInputSampleRate() const {
cannam@208 405 return m_inputSampleRate;
cannam@208 406 }
cannam@208 407
cannam@208 408 virtual std::string getPluginKey() const {
cannam@208 409 return m_key;
cannam@208 410 }
cannam@208 411
cannam@208 412 virtual int getAdapterFlags() const {
cannam@208 413 return m_adapterFlags;
cannam@208 414 }
cannam@208 415
cannam@208 416 private:
cannam@208 417 PluginClient *m_client;
cannam@208 418 std::string m_key;
cannam@208 419 int m_adapterFlags;
cannam@208 420 State m_state;
cannam@208 421 PluginStaticData m_psd;
cannam@208 422 OutputList m_outputs;
cannam@208 423 PluginConfiguration m_defaultConfig;
cannam@208 424 PluginConfiguration m_config;
cannam@287 425 PluginProgramParameters m_programParameters;
cannam@208 426 };
cannam@208 427
cannam@208 428 }
cannam@208 429 }
cannam@208 430
cannam@208 431 #endif