annotate plugin/FeatureExtractionPlugin.h @ 61:749b5521e082

* adjust for latency if the plugin reports it
author Chris Cannam
date Mon, 27 Mar 2006 16:15:19 +0000
parents 0a34d529f8e0
children
rev   line source
Chris@49 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@0 2
Chris@0 3 /*
Chris@52 4 Sonic Visualiser
Chris@52 5 An audio file viewer and annotation editor.
Chris@52 6 Centre for Digital Music, Queen Mary, University of London.
Chris@52 7 This file copyright 2006 Chris Cannam.
Chris@0 8
Chris@52 9 This program is free software; you can redistribute it and/or
Chris@52 10 modify it under the terms of the GNU General Public License as
Chris@52 11 published by the Free Software Foundation; either version 2 of the
Chris@52 12 License, or (at your option) any later version. See the file
Chris@52 13 COPYING included with this distribution for more information.
Chris@0 14 */
Chris@0 15
Chris@0 16 #ifndef _FEATURE_EXTRACTION_PLUGIN_H_
Chris@0 17 #define _FEATURE_EXTRACTION_PLUGIN_H_
Chris@0 18
Chris@50 19 #include "PluginInstance.h"
Chris@0 20
Chris@0 21 #include <string>
Chris@0 22 #include <vector>
Chris@0 23 #include <map>
Chris@0 24
Chris@0 25 #include "base/RealTime.h"
Chris@0 26
Chris@0 27 /**
Chris@0 28 * FeatureExtractionPlugin is a base class for plugin instance classes
Chris@0 29 * that provide feature extraction from audio or related data.
Chris@0 30 *
Chris@0 31 * In most cases, the input will be audio and the output will be a
Chris@0 32 * stream of derived data at a lower sampling resolution than the
Chris@0 33 * input.
Chris@50 34 *
Chris@50 35 * Note that this class inherits several abstract methods from
Chris@50 36 * PluginInstance, that must be implemented by the subclass.
Chris@0 37 */
Chris@0 38
Chris@58 39 /**
Chris@58 40 * Plugin Lifecycle
Chris@58 41 * ================
Chris@58 42 *
Chris@58 43 * Feature extraction plugins are managed differently from real-time
Chris@58 44 * plugins. The main difference is that the parameters for a feature
Chris@58 45 * extraction plugin are configured before the plugin is used, and do
Chris@58 46 * not change during use.
Chris@58 47 *
Chris@58 48 * 1. Host constructs the plugin, passing it the input sample rate.
Chris@58 49 * The plugin may do basic initialisation, but should not do anything
Chris@58 50 * computationally expensive at this point.
Chris@58 51 *
Chris@58 52 * 2. Host may query the plugin's available outputs.
Chris@58 53 *
Chris@58 54 * 3. Host queries programs and parameter descriptors, and may set
Chris@58 55 * some or all of them. Parameters that are not explicitly set should
Chris@58 56 * take their default values as specified in the parameter descriptor.
Chris@58 57 * When a program is set, the parameter values may change and the host
Chris@58 58 * will re-query them to check.
Chris@58 59 *
Chris@58 60 * 4. Host queries the preferred step size, block size, number of
Chris@58 61 * channels, and the number of values per feature for the plugin's
Chris@58 62 * outputs. These may all vary depending on the parameter values.
Chris@58 63 *
Chris@58 64 * 5. Plugin is properly initialised with a call to initialise. This
Chris@58 65 * fixes the step size, block size, and number of channels, as well as
Chris@58 66 * all of the parameter and program settings. If the values passed in
Chris@58 67 * to initialise do not match the plugin's advertised preferred values
Chris@58 68 * from step 4, the plugin may refuse to initialise and return false
Chris@58 69 * (although if possible it should accept the new values).
Chris@58 70 *
Chris@58 71 * 6. Host will repeatedly call the process method to pass in blocks
Chris@58 72 * of input data. This method may return features extracted from that
Chris@58 73 * data (if the plugin is causal).
Chris@58 74 *
Chris@58 75 * 7. Host will call getRemainingFeatures exactly once, after all the
Chris@58 76 * input data has been processed. This may return any non-causal or
Chris@58 77 * leftover features.
Chris@58 78 *
Chris@58 79 * 8. At any point after initialise was called, the host may
Chris@58 80 * optionally call the reset method and restart processing. (This
Chris@58 81 * does not mean it can change the parameters, which are fixed from
Chris@58 82 * initialise until destruction.)
Chris@58 83 *
Chris@58 84 * A plugin does not need to handle the case where setParameter or
Chris@58 85 * selectProgram is called after initialise has been called. It's the
Chris@58 86 * host's responsibility not to do that.
Chris@58 87 */
Chris@58 88
Chris@50 89 class FeatureExtractionPlugin : public PluginInstance
Chris@0 90 {
Chris@0 91 public:
Chris@0 92 /**
Chris@0 93 * Initialise a plugin to prepare it for use with the given number
Chris@0 94 * of input channels, step size (window increment, in sample
Chris@0 95 * frames) and block size (window size, in sample frames).
Chris@0 96 *
Chris@0 97 * The input sample rate should have been already specified at
Chris@0 98 * construction time.
Chris@0 99 *
Chris@0 100 * Return true for successful initialisation, false if the number
Chris@0 101 * of input channels, step size and/or block size cannot be
Chris@0 102 * supported.
Chris@0 103 */
Chris@0 104 virtual bool initialise(size_t inputChannels,
Chris@0 105 size_t stepSize,
Chris@0 106 size_t blockSize) = 0;
Chris@0 107
Chris@0 108 /**
Chris@0 109 * Reset the plugin after use, to prepare it for another clean
Chris@0 110 * run. Not called for the first initialisation (i.e. initialise
Chris@0 111 * must also do a reset).
Chris@0 112 */
Chris@0 113 virtual void reset() = 0;
Chris@0 114
Chris@0 115 /**
Chris@0 116 * Get the preferred step size (window increment -- the distance
Chris@0 117 * in sample frames between the start frames of consecutive blocks
Chris@0 118 * passed to the process() function) for the plugin. This should
Chris@0 119 * be called before initialise().
Chris@0 120 */
Chris@0 121 virtual size_t getPreferredStepSize() const = 0;
Chris@0 122
Chris@0 123 /**
Chris@0 124 * Get the preferred block size (window size -- the number of
Chris@0 125 * sample frames passed in each block to the process() function).
Chris@0 126 * This should be called before initialise().
Chris@0 127 */
Chris@0 128 virtual size_t getPreferredBlockSize() const { return getPreferredStepSize(); }
Chris@0 129
Chris@0 130 /**
Chris@0 131 * Get the minimum supported number of input channels.
Chris@0 132 */
Chris@0 133 virtual size_t getMinChannelCount() const { return 1; }
Chris@0 134
Chris@0 135 /**
Chris@0 136 * Get the maximum supported number of input channels.
Chris@0 137 */
Chris@0 138 virtual size_t getMaxChannelCount() const { return 1; }
Chris@0 139
Chris@0 140 struct OutputDescriptor
Chris@0 141 {
Chris@0 142 /**
Chris@0 143 * The name of the output, in computer-usable form. Should be
Chris@0 144 * reasonably short and without whitespace or punctuation.
Chris@0 145 */
Chris@0 146 std::string name;
Chris@0 147
Chris@0 148 /**
Chris@0 149 * The human-readable name of the output.
Chris@0 150 */
Chris@0 151 std::string description;
Chris@0 152
Chris@0 153 /**
Chris@0 154 * The unit of the output, in human-readable form.
Chris@0 155 */
Chris@0 156 std::string unit;
Chris@0 157
Chris@0 158 /**
Chris@0 159 * True if the output has the same number of values per result
Chris@0 160 * for every output result. Outputs for which this is false
Chris@0 161 * are unlikely to be very useful in a general-purpose host.
Chris@0 162 */
Chris@0 163 bool hasFixedValueCount;
Chris@0 164
Chris@0 165 /**
Chris@0 166 * The number of values per result of the output. Undefined
Chris@0 167 * if hasFixedValueCount is false. If this is zero, the output
Chris@0 168 * is point data (i.e. only the time of each output is of
Chris@0 169 * interest, the value list will be empty).
Chris@0 170 *
Chris@0 171 * Note that this gives the number of values of a single
Chris@0 172 * output result, not of the output stream (which has one more
Chris@0 173 * dimension: time).
Chris@0 174 */
Chris@0 175 size_t valueCount;
Chris@0 176
Chris@0 177 /**
Chris@19 178 * The names of each of the values, if appropriate. This is
Chris@19 179 * always optional.
Chris@19 180 */
Chris@19 181 std::vector<std::string> valueNames;
Chris@19 182
Chris@19 183 /**
Chris@0 184 * True if the results in the output have a fixed numeric
Chris@0 185 * range (minimum and maximum values). Undefined if
Chris@0 186 * valueCount is zero.
Chris@0 187 */
Chris@0 188 bool hasKnownExtents;
Chris@0 189
Chris@0 190 /**
Chris@0 191 * Minimum value of the results in the output. Undefined if
Chris@0 192 * hasKnownExtents is false or valueCount is zero.
Chris@0 193 */
Chris@0 194 float minValue;
Chris@0 195
Chris@0 196 /**
Chris@0 197 * Maximum value of the results in the output. Undefined if
Chris@0 198 * hasKnownExtents is false or valueCount is zero.
Chris@0 199 */
Chris@0 200 float maxValue;
Chris@0 201
Chris@0 202 /**
Chris@0 203 * True if the output values are quantized to a particular
Chris@0 204 * resolution. Undefined if valueCount is zero.
Chris@0 205 */
Chris@0 206 bool isQuantized;
Chris@0 207
Chris@0 208 /**
Chris@0 209 * Quantization resolution of the output values (e.g. 1.0 if
Chris@0 210 * they are all integers). Undefined if isQuantized is false
Chris@0 211 * or valueCount is zero.
Chris@0 212 */
Chris@0 213 float quantizeStep;
Chris@0 214
Chris@0 215 enum SampleType {
Chris@0 216
Chris@0 217 /// Results from each process() align with that call's block start
Chris@0 218 OneSamplePerStep,
Chris@0 219
Chris@0 220 /// Results are evenly spaced in time (sampleRate specified below)
Chris@0 221 FixedSampleRate,
Chris@0 222
Chris@0 223 /// Results are unevenly spaced and have individual timestamps
Chris@0 224 VariableSampleRate
Chris@0 225 };
Chris@0 226
Chris@0 227 /**
Chris@0 228 * Positioning in time of the output results.
Chris@0 229 */
Chris@0 230 SampleType sampleType;
Chris@0 231
Chris@0 232 /**
Chris@0 233 * Sample rate of the output results. Undefined if sampleType
Chris@0 234 * is OneSamplePerStep.
Chris@0 235 *
Chris@0 236 * If sampleType is VariableSampleRate and this value is
Chris@0 237 * non-zero, then it may be used to calculate a resolution for
Chris@0 238 * the output (i.e. the "duration" of each value, in time).
Chris@0 239 * It's recommended to set this to zero if that behaviour is
Chris@0 240 * not desired.
Chris@0 241 */
Chris@0 242 float sampleRate;
Chris@0 243 };
Chris@0 244
Chris@0 245 typedef std::vector<OutputDescriptor> OutputList;
Chris@0 246
Chris@0 247 /**
Chris@0 248 * Get the outputs of this plugin. An output's index in this list
Chris@0 249 * is used as its numeric index when looking it up in the
Chris@0 250 * FeatureSet returned from the process() call.
Chris@0 251 */
Chris@0 252 virtual OutputList getOutputDescriptors() const = 0;
Chris@0 253
Chris@0 254 struct Feature
Chris@0 255 {
Chris@0 256 /**
Chris@0 257 * True if an output feature has its own timestamp. This is
Chris@0 258 * mandatory if the output has VariableSampleRate, and is
Chris@0 259 * likely to be disregarded otherwise.
Chris@0 260 */
Chris@0 261 bool hasTimestamp;
Chris@0 262
Chris@0 263 /**
Chris@0 264 * Timestamp of the output feature. This is mandatory if the
Chris@0 265 * output has VariableSampleRate, and is likely to be
Chris@0 266 * disregarded otherwise. Undefined if hasTimestamp is false.
Chris@0 267 */
Chris@0 268 RealTime timestamp;
Chris@0 269
Chris@0 270 /**
Chris@0 271 * Results for a single sample of this feature. If the output
Chris@0 272 * hasFixedValueCount, there must be the same number of values
Chris@0 273 * as the output's valueCount count.
Chris@0 274 */
Chris@0 275 std::vector<float> values;
Chris@0 276
Chris@0 277 /**
Chris@0 278 * Label for the sample of this feature.
Chris@0 279 */
Chris@0 280 std::string label;
Chris@0 281 };
Chris@0 282
Chris@0 283 typedef std::vector<Feature> FeatureList;
Chris@0 284 typedef std::map<int, FeatureList> FeatureSet; // key is output no
Chris@0 285
Chris@0 286 /**
Chris@0 287 * Process a single block of input data. inputBuffers points to
Chris@0 288 * one array of floats per input channel, and each of those arrays
Chris@0 289 * contains the blockSize number of samples (the host will
Chris@0 290 * zero-pad as necessary). The timestamp is the real time in
Chris@0 291 * seconds of the start of the supplied block of samples.
Chris@0 292 *
Chris@0 293 * Return any features that have become available after this
Chris@0 294 * process call. (These do not necessarily have to fall within
Chris@0 295 * the process block, except for OneSamplePerStep outputs.)
Chris@0 296 */
Chris@0 297 virtual FeatureSet process(float **inputBuffers,
Chris@0 298 RealTime timestamp) = 0;
Chris@0 299
Chris@0 300 /**
Chris@0 301 * After all blocks have been processed, calculate and return any
Chris@0 302 * remaining features derived from the complete input.
Chris@0 303 */
Chris@0 304 virtual FeatureSet getRemainingFeatures() = 0;
Chris@0 305
Chris@57 306 virtual std::string getType() const { return "Feature Extraction Plugin"; }
Chris@57 307
Chris@0 308 protected:
Chris@0 309 FeatureExtractionPlugin(float inputSampleRate) :
Chris@0 310 m_inputSampleRate(inputSampleRate) { }
Chris@0 311
Chris@0 312 float m_inputSampleRate;
Chris@0 313 };
Chris@0 314
Chris@0 315 #endif
Chris@0 316
Chris@0 317
Chris@0 318