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
|