annotate vamp-sdk/Plugin.h @ 190:1982246a3902

* Provide PluginWrapper method for getting hold of a nested wrapper directly (a bit gross, but useful) * Use the above to enable the simple host to adjust timestamps appropriately when printing out results from input domain adapter wrapped plugins
author cannam
date Wed, 17 Sep 2008 13:16:09 +0000
parents 31eda4b11f2b
children d4fbd4e6fdbf
rev   line source
cannam@3 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
cannam@3 2
cannam@3 3 /*
cannam@3 4 Vamp
cannam@3 5
cannam@3 6 An API for audio analysis and feature extraction plugins.
cannam@3 7
cannam@3 8 Centre for Digital Music, Queen Mary, University of London.
cannam@3 9 Copyright 2006 Chris Cannam.
cannam@3 10
cannam@3 11 Permission is hereby granted, free of charge, to any person
cannam@3 12 obtaining a copy of this software and associated documentation
cannam@3 13 files (the "Software"), to deal in the Software without
cannam@3 14 restriction, including without limitation the rights to use, copy,
cannam@3 15 modify, merge, publish, distribute, sublicense, and/or sell copies
cannam@3 16 of the Software, and to permit persons to whom the Software is
cannam@3 17 furnished to do so, subject to the following conditions:
cannam@3 18
cannam@3 19 The above copyright notice and this permission notice shall be
cannam@3 20 included in all copies or substantial portions of the Software.
cannam@3 21
cannam@3 22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
cannam@3 23 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
cannam@3 24 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
cannam@6 25 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
cannam@3 26 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
cannam@3 27 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
cannam@3 28 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
cannam@3 29
cannam@3 30 Except as contained in this notice, the names of the Centre for
cannam@3 31 Digital Music; Queen Mary, University of London; and Chris Cannam
cannam@3 32 shall not be used in advertising or otherwise to promote the sale,
cannam@3 33 use or other dealings in this Software without prior written
cannam@3 34 authorization.
cannam@3 35 */
cannam@3 36
cannam@3 37 #ifndef _VAMP_PLUGIN_H_
cannam@3 38 #define _VAMP_PLUGIN_H_
cannam@3 39
cannam@3 40 #include "PluginBase.h"
cannam@3 41 #include "RealTime.h"
cannam@3 42
cannam@3 43 #include <string>
cannam@3 44 #include <vector>
cannam@3 45 #include <map>
cannam@3 46
cannam@3 47 namespace Vamp {
cannam@3 48
cannam@3 49 /**
cannam@76 50 * \class Plugin Plugin.h <vamp-sdk/Plugin.h>
cannam@76 51 *
cannam@3 52 * Vamp::Plugin is a base class for plugin instance classes
cannam@3 53 * that provide feature extraction from audio or related data.
cannam@3 54 *
cannam@3 55 * In most cases, the input will be audio and the output will be a
cannam@3 56 * stream of derived data at a lower sampling resolution than the
cannam@3 57 * input.
cannam@3 58 *
cannam@3 59 * Note that this class inherits several abstract methods from
cannam@53 60 * PluginBase. These must be implemented by the subclass.
cannam@53 61 *
cannam@53 62 *
cannam@53 63 * PLUGIN LIFECYCLE
cannam@3 64 *
cannam@3 65 * Feature extraction plugins are managed differently from real-time
cannam@3 66 * plugins (such as VST effects). The main difference is that the
cannam@3 67 * parameters for a feature extraction plugin are configured before
cannam@3 68 * the plugin is used, and do not change during use.
cannam@3 69 *
cannam@3 70 * 1. Host constructs the plugin, passing it the input sample rate.
cannam@3 71 * The plugin may do basic initialisation, but should not do anything
cannam@74 72 * computationally expensive at this point. You must make sure your
cannam@74 73 * plugin is cheap to construct, otherwise you'll seriously affect the
cannam@74 74 * startup performance of almost all hosts. If you have serious
cannam@74 75 * initialisation to do, the proper place is in initialise() (step 5).
cannam@3 76 *
cannam@3 77 * 2. Host may query the plugin's available outputs.
cannam@3 78 *
cannam@3 79 * 3. Host queries programs and parameter descriptors, and may set
cannam@3 80 * some or all of them. Parameters that are not explicitly set should
cannam@3 81 * take their default values as specified in the parameter descriptor.
cannam@3 82 * When a program is set, the parameter values may change and the host
cannam@3 83 * will re-query them to check.
cannam@3 84 *
cannam@27 85 * 4. Host queries the preferred step size, block size and number of
cannam@27 86 * channels. These may all vary depending on the parameter values.
cannam@3 87 * (Note however that you cannot make the number of distinct outputs
cannam@27 88 * dependent on parameter values.)
cannam@3 89 *
cannam@3 90 * 5. Plugin is properly initialised with a call to initialise. This
cannam@3 91 * fixes the step size, block size, and number of channels, as well as
cannam@3 92 * all of the parameter and program settings. If the values passed in
cannam@3 93 * to initialise do not match the plugin's advertised preferred values
cannam@3 94 * from step 4, the plugin may refuse to initialise and return false
cannam@35 95 * (although if possible it should accept the new values). Any
cannam@35 96 * computationally expensive setup code should take place here.
cannam@3 97 *
cannam@80 98 * 6. Host finally checks the number of values, resolution, extents
cannam@80 99 * etc per output (which may vary depending on the number of channels,
cannam@80 100 * step size and block size as well as the parameter values).
cannam@27 101 *
cannam@27 102 * 7. Host will repeatedly call the process method to pass in blocks
cannam@3 103 * of input data. This method may return features extracted from that
cannam@3 104 * data (if the plugin is causal).
cannam@3 105 *
cannam@27 106 * 8. Host will call getRemainingFeatures exactly once, after all the
cannam@3 107 * input data has been processed. This may return any non-causal or
cannam@3 108 * leftover features.
cannam@3 109 *
cannam@27 110 * 9. At any point after initialise was called, the host may
cannam@3 111 * optionally call the reset method and restart processing. (This
cannam@3 112 * does not mean it can change the parameters, which are fixed from
cannam@3 113 * initialise until destruction.)
cannam@3 114 *
cannam@3 115 * A plugin does not need to handle the case where setParameter or
cannam@3 116 * selectProgram is called after initialise has been called. It's the
cannam@35 117 * host's responsibility not to do that. Similarly, the plugin may
cannam@35 118 * safely assume that initialise is called no more than once.
cannam@3 119 */
cannam@3 120
cannam@3 121 class Plugin : public PluginBase
cannam@3 122 {
cannam@3 123 public:
cannam@20 124 virtual ~Plugin() { }
cannam@20 125
cannam@3 126 /**
cannam@3 127 * Initialise a plugin to prepare it for use with the given number
cannam@3 128 * of input channels, step size (window increment, in sample
cannam@3 129 * frames) and block size (window size, in sample frames).
cannam@3 130 *
cannam@3 131 * The input sample rate should have been already specified at
cannam@3 132 * construction time.
cannam@3 133 *
cannam@3 134 * Return true for successful initialisation, false if the number
cannam@3 135 * of input channels, step size and/or block size cannot be
cannam@3 136 * supported.
cannam@3 137 */
cannam@3 138 virtual bool initialise(size_t inputChannels,
cannam@3 139 size_t stepSize,
cannam@3 140 size_t blockSize) = 0;
cannam@3 141
cannam@3 142 /**
cannam@3 143 * Reset the plugin after use, to prepare it for another clean
cannam@3 144 * run. Not called for the first initialisation (i.e. initialise
cannam@3 145 * must also do a reset).
cannam@3 146 */
cannam@3 147 virtual void reset() = 0;
cannam@3 148
cannam@3 149 enum InputDomain { TimeDomain, FrequencyDomain };
cannam@3 150
cannam@3 151 /**
cannam@3 152 * Get the plugin's required input domain. If this is TimeDomain,
cannam@3 153 * the samples provided to the process() function (below) will be
cannam@3 154 * in the time domain, as for a traditional audio processing
cannam@3 155 * plugin. If this is FrequencyDomain, the host will carry out a
cannam@3 156 * windowed FFT of size equal to the negotiated block size on the
cannam@3 157 * data before passing the frequency bin data in to process().
cannam@3 158 * The plugin does not get to choose the window type -- the host
cannam@3 159 * will either let the user do so, or will use a Hanning window.
cannam@3 160 */
cannam@3 161 virtual InputDomain getInputDomain() const = 0;
cannam@3 162
cannam@3 163 /**
cannam@8 164 * Get the preferred block size (window size -- the number of
cannam@8 165 * sample frames passed in each block to the process() function).
cannam@8 166 * This should be called before initialise().
cannam@8 167 *
cannam@8 168 * A plugin that can handle any block size may return 0. The
cannam@8 169 * final block size will be set in the initialise() call.
cannam@8 170 */
cannam@8 171 virtual size_t getPreferredBlockSize() const { return 0; }
cannam@8 172
cannam@8 173 /**
cannam@3 174 * Get the preferred step size (window increment -- the distance
cannam@3 175 * in sample frames between the start frames of consecutive blocks
cannam@3 176 * passed to the process() function) for the plugin. This should
cannam@3 177 * be called before initialise().
cannam@8 178 *
cannam@8 179 * A plugin may return 0 if it has no particular interest in the
cannam@8 180 * step size. In this case, the host should make the step size
cannam@8 181 * equal to the block size if the plugin is accepting input in the
cannam@8 182 * time domain. If the plugin is accepting input in the frequency
cannam@8 183 * domain, the host may use any step size. The final step size
cannam@8 184 * will be set in the initialise() call.
cannam@3 185 */
cannam@8 186 virtual size_t getPreferredStepSize() const { return 0; }
cannam@3 187
cannam@3 188 /**
cannam@3 189 * Get the minimum supported number of input channels.
cannam@3 190 */
cannam@3 191 virtual size_t getMinChannelCount() const { return 1; }
cannam@3 192
cannam@3 193 /**
cannam@3 194 * Get the maximum supported number of input channels.
cannam@3 195 */
cannam@3 196 virtual size_t getMaxChannelCount() const { return 1; }
cannam@3 197
cannam@3 198 struct OutputDescriptor
cannam@3 199 {
cannam@3 200 /**
cannam@3 201 * The name of the output, in computer-usable form. Should be
cannam@49 202 * reasonably short and without whitespace or punctuation, using
cannam@134 203 * the characters [a-zA-Z0-9_-] only.
cannam@49 204 * Example: "zero_crossing_count"
cannam@49 205 */
cannam@49 206 std::string identifier;
cannam@49 207
cannam@49 208 /**
cannam@49 209 * The human-readable name of the output.
cannam@49 210 * Example: "Zero Crossing Counts"
cannam@3 211 */
cannam@3 212 std::string name;
cannam@3 213
cannam@3 214 /**
cannam@49 215 * A human-readable short text describing the output. May be
cannam@49 216 * empty if the name has said it all already.
cannam@49 217 * Example: "The number of zero crossing points per processing block"
cannam@3 218 */
cannam@3 219 std::string description;
cannam@3 220
cannam@3 221 /**
cannam@3 222 * The unit of the output, in human-readable form.
cannam@3 223 */
cannam@3 224 std::string unit;
cannam@3 225
cannam@3 226 /**
cannam@9 227 * True if the output has the same number of values per sample
cannam@9 228 * for every output sample. Outputs for which this is false
cannam@3 229 * are unlikely to be very useful in a general-purpose host.
cannam@3 230 */
cannam@9 231 bool hasFixedBinCount;
cannam@3 232
cannam@3 233 /**
cannam@3 234 * The number of values per result of the output. Undefined
cannam@9 235 * if hasFixedBinCount is false. If this is zero, the output
cannam@3 236 * is point data (i.e. only the time of each output is of
cannam@3 237 * interest, the value list will be empty).
cannam@3 238 */
cannam@9 239 size_t binCount;
cannam@3 240
cannam@3 241 /**
cannam@49 242 * The (human-readable) names of each of the bins, if
cannam@49 243 * appropriate. This is always optional.
cannam@3 244 */
cannam@9 245 std::vector<std::string> binNames;
cannam@3 246
cannam@3 247 /**
cannam@9 248 * True if the results in each output bin fall within a fixed
cannam@9 249 * numeric range (minimum and maximum values). Undefined if
cannam@9 250 * binCount is zero.
cannam@3 251 */
cannam@3 252 bool hasKnownExtents;
cannam@3 253
cannam@3 254 /**
cannam@3 255 * Minimum value of the results in the output. Undefined if
cannam@9 256 * hasKnownExtents is false or binCount is zero.
cannam@3 257 */
cannam@3 258 float minValue;
cannam@3 259
cannam@3 260 /**
cannam@3 261 * Maximum value of the results in the output. Undefined if
cannam@9 262 * hasKnownExtents is false or binCount is zero.
cannam@3 263 */
cannam@3 264 float maxValue;
cannam@3 265
cannam@3 266 /**
cannam@3 267 * True if the output values are quantized to a particular
cannam@9 268 * resolution. Undefined if binCount is zero.
cannam@3 269 */
cannam@3 270 bool isQuantized;
cannam@3 271
cannam@3 272 /**
cannam@3 273 * Quantization resolution of the output values (e.g. 1.0 if
cannam@3 274 * they are all integers). Undefined if isQuantized is false
cannam@9 275 * or binCount is zero.
cannam@3 276 */
cannam@3 277 float quantizeStep;
cannam@3 278
cannam@3 279 enum SampleType {
cannam@3 280
cannam@3 281 /// Results from each process() align with that call's block start
cannam@3 282 OneSamplePerStep,
cannam@3 283
cannam@3 284 /// Results are evenly spaced in time (sampleRate specified below)
cannam@3 285 FixedSampleRate,
cannam@3 286
cannam@3 287 /// Results are unevenly spaced and have individual timestamps
cannam@3 288 VariableSampleRate
cannam@3 289 };
cannam@3 290
cannam@3 291 /**
cannam@3 292 * Positioning in time of the output results.
cannam@3 293 */
cannam@3 294 SampleType sampleType;
cannam@3 295
cannam@3 296 /**
cannam@17 297 * Sample rate of the output results, as samples per second.
cannam@17 298 * Undefined if sampleType is OneSamplePerStep.
cannam@3 299 *
cannam@3 300 * If sampleType is VariableSampleRate and this value is
cannam@3 301 * non-zero, then it may be used to calculate a resolution for
cannam@17 302 * the output (i.e. the "duration" of each sample, in time,
cannam@17 303 * will be 1/sampleRate seconds). It's recommended to set
cannam@17 304 * this to zero if that behaviour is not desired.
cannam@3 305 */
cannam@3 306 float sampleRate;
cannam@167 307
cannam@167 308 OutputDescriptor() : // defaults for mandatory non-class-type members
cannam@167 309 hasFixedBinCount(false), hasKnownExtents(false), isQuantized(false),
cannam@167 310 sampleType(OneSamplePerStep) { }
cannam@3 311 };
cannam@3 312
cannam@3 313 typedef std::vector<OutputDescriptor> OutputList;
cannam@3 314
cannam@3 315 /**
cannam@3 316 * Get the outputs of this plugin. An output's index in this list
cannam@3 317 * is used as its numeric index when looking it up in the
cannam@3 318 * FeatureSet returned from the process() call.
cannam@3 319 */
cannam@3 320 virtual OutputList getOutputDescriptors() const = 0;
cannam@3 321
cannam@3 322 struct Feature
cannam@3 323 {
cannam@3 324 /**
cannam@3 325 * True if an output feature has its own timestamp. This is
cannam@167 326 * mandatory if the output has VariableSampleRate, optional if
cannam@167 327 * the output has FixedSampleRate, and unused if the output
cannam@167 328 * has OneSamplePerStep.
cannam@3 329 */
cannam@3 330 bool hasTimestamp;
cannam@3 331
cannam@3 332 /**
cannam@3 333 * Timestamp of the output feature. This is mandatory if the
cannam@167 334 * output has VariableSampleRate or if the output has
cannam@167 335 * FixedSampleRate and hasTimestamp is true, and unused
cannam@167 336 * otherwise.
cannam@3 337 */
cannam@3 338 RealTime timestamp;
cannam@167 339
cannam@167 340 /**
cannam@167 341 * True if an output feature has a specified duration. This
cannam@167 342 * is optional if the output has VariableSampleRate or
cannam@167 343 * FixedSampleRate, and and unused if the output has
cannam@167 344 * OneSamplePerStep.
cannam@167 345 */
cannam@167 346 bool hasDuration;
cannam@167 347
cannam@167 348 /**
cannam@167 349 * Duration of the output feature. This is mandatory if the
cannam@167 350 * output has VariableSampleRate or FixedSampleRate and
cannam@167 351 * hasDuration is true, and unused otherwise.
cannam@167 352 */
cannam@167 353 RealTime duration;
cannam@3 354
cannam@3 355 /**
cannam@3 356 * Results for a single sample of this feature. If the output
cannam@9 357 * hasFixedBinCount, there must be the same number of values
cannam@9 358 * as the output's binCount count.
cannam@3 359 */
cannam@3 360 std::vector<float> values;
cannam@3 361
cannam@3 362 /**
cannam@3 363 * Label for the sample of this feature.
cannam@3 364 */
cannam@3 365 std::string label;
cannam@167 366
cannam@167 367 Feature() : // defaults for mandatory non-class-type members
cannam@167 368 hasTimestamp(false), hasDuration(false) { }
cannam@3 369 };
cannam@3 370
cannam@3 371 typedef std::vector<Feature> FeatureList;
cannam@167 372
cannam@3 373 typedef std::map<int, FeatureList> FeatureSet; // key is output no
cannam@3 374
cannam@3 375 /**
cannam@3 376 * Process a single block of input data.
cannam@3 377 *
cannam@3 378 * If the plugin's inputDomain is TimeDomain, inputBuffers will
cannam@3 379 * point to one array of floats per input channel, and each of
cannam@3 380 * these arrays will contain blockSize consecutive audio samples
cannam@190 381 * (the host will zero-pad as necessary). The timestamp in this
cannam@190 382 * case will be the real time in seconds of the start of the
cannam@190 383 * supplied block of samples.
cannam@3 384 *
cannam@3 385 * If the plugin's inputDomain is FrequencyDomain, inputBuffers
cannam@3 386 * will point to one array of floats per input channel, and each
cannam@47 387 * of these arrays will contain blockSize/2+1 consecutive pairs of
cannam@3 388 * real and imaginary component floats corresponding to bins
cannam@78 389 * 0..(blockSize/2) of the FFT output. That is, bin 0 (the first
cannam@78 390 * pair of floats) contains the DC output, up to bin blockSize/2
cannam@78 391 * which contains the Nyquist-frequency output. There will
cannam@78 392 * therefore be blockSize+2 floats per channel in total. The
cannam@78 393 * timestamp will be the real time in seconds of the centre of the
cannam@78 394 * FFT input window (i.e. the very first block passed to process
cannam@78 395 * might contain the FFT of half a block of zero samples and the
cannam@78 396 * first half-block of the actual data, with a timestamp of zero).
cannam@3 397 *
cannam@3 398 * Return any features that have become available after this
cannam@3 399 * process call. (These do not necessarily have to fall within
cannam@3 400 * the process block, except for OneSamplePerStep outputs.)
cannam@3 401 */
cannam@47 402 virtual FeatureSet process(const float *const *inputBuffers,
cannam@3 403 RealTime timestamp) = 0;
cannam@3 404
cannam@3 405 /**
cannam@3 406 * After all blocks have been processed, calculate and return any
cannam@3 407 * remaining features derived from the complete input.
cannam@3 408 */
cannam@3 409 virtual FeatureSet getRemainingFeatures() = 0;
cannam@3 410
cannam@53 411 /**
cannam@53 412 * Used to distinguish between Vamp::Plugin and other potential
cannam@64 413 * sibling subclasses of PluginBase. Do not reimplement this
cannam@53 414 * function in your subclass.
cannam@53 415 */
cannam@3 416 virtual std::string getType() const { return "Feature Extraction Plugin"; }
cannam@3 417
cannam@3 418 protected:
cannam@3 419 Plugin(float inputSampleRate) :
cannam@3 420 m_inputSampleRate(inputSampleRate) { }
cannam@3 421
cannam@3 422 float m_inputSampleRate;
cannam@3 423 };
cannam@3 424
cannam@3 425 }
cannam@3 426
cannam@3 427 #endif
cannam@3 428
cannam@3 429
cannam@3 430