Chris@0
|
1 /* -*- c-basic-offset: 4 -*- vi:set ts=8 sts=4 sw=4: */
|
Chris@0
|
2
|
Chris@0
|
3 /*
|
Chris@0
|
4 A waveform viewer and audio annotation editor.
|
Chris@2
|
5 Chris Cannam, Queen Mary University of London, 2005-2006
|
Chris@0
|
6
|
Chris@0
|
7 This is experimental software. Not for distribution.
|
Chris@0
|
8 */
|
Chris@0
|
9
|
Chris@0
|
10 #ifndef _FEATURE_EXTRACTION_PLUGIN_H_
|
Chris@0
|
11 #define _FEATURE_EXTRACTION_PLUGIN_H_
|
Chris@0
|
12
|
Chris@0
|
13 /**
|
Chris@0
|
14 * A base class for feature extraction plugins.
|
Chris@0
|
15 */
|
Chris@0
|
16
|
Chris@0
|
17 #include <string>
|
Chris@0
|
18 #include <vector>
|
Chris@0
|
19 #include <map>
|
Chris@0
|
20
|
Chris@0
|
21 #include "base/RealTime.h"
|
Chris@0
|
22
|
Chris@0
|
23 /**
|
Chris@0
|
24 * FeatureExtractionPlugin is a base class for plugin instance classes
|
Chris@0
|
25 * that provide feature extraction from audio or related data.
|
Chris@0
|
26 *
|
Chris@0
|
27 * In most cases, the input will be audio and the output will be a
|
Chris@0
|
28 * stream of derived data at a lower sampling resolution than the
|
Chris@0
|
29 * input.
|
Chris@0
|
30 */
|
Chris@0
|
31
|
Chris@0
|
32 class FeatureExtractionPlugin
|
Chris@0
|
33 {
|
Chris@0
|
34 public:
|
Chris@0
|
35 /**
|
Chris@0
|
36 * Initialise a plugin to prepare it for use with the given number
|
Chris@0
|
37 * of input channels, step size (window increment, in sample
|
Chris@0
|
38 * frames) and block size (window size, in sample frames).
|
Chris@0
|
39 *
|
Chris@0
|
40 * The input sample rate should have been already specified at
|
Chris@0
|
41 * construction time.
|
Chris@0
|
42 *
|
Chris@0
|
43 * Return true for successful initialisation, false if the number
|
Chris@0
|
44 * of input channels, step size and/or block size cannot be
|
Chris@0
|
45 * supported.
|
Chris@0
|
46 */
|
Chris@0
|
47 virtual bool initialise(size_t inputChannels,
|
Chris@0
|
48 size_t stepSize,
|
Chris@0
|
49 size_t blockSize) = 0;
|
Chris@0
|
50
|
Chris@0
|
51 /**
|
Chris@0
|
52 * Reset the plugin after use, to prepare it for another clean
|
Chris@0
|
53 * run. Not called for the first initialisation (i.e. initialise
|
Chris@0
|
54 * must also do a reset).
|
Chris@0
|
55 */
|
Chris@0
|
56 virtual void reset() = 0;
|
Chris@0
|
57
|
Chris@0
|
58 /**
|
Chris@0
|
59 * Get the computer-usable name of the plugin. This should be
|
Chris@0
|
60 * reasonably short and contain no whitespace or punctuation
|
Chris@0
|
61 * characters.
|
Chris@0
|
62 */
|
Chris@0
|
63 virtual std::string getName() const = 0;
|
Chris@0
|
64
|
Chris@0
|
65 /**
|
Chris@0
|
66 * Get a human-readable description of the plugin. This should be
|
Chris@0
|
67 * self-contained, as it may be shown to the user in isolation
|
Chris@0
|
68 * without also showing the plugin's "name".
|
Chris@0
|
69 */
|
Chris@0
|
70 virtual std::string getDescription() const = 0;
|
Chris@0
|
71
|
Chris@0
|
72 /**
|
Chris@0
|
73 * Get the name of the author or vendor of the plugin in
|
Chris@0
|
74 * human-readable form.
|
Chris@0
|
75 */
|
Chris@0
|
76 virtual std::string getMaker() const = 0;
|
Chris@0
|
77
|
Chris@0
|
78 /**
|
Chris@0
|
79 * Get the version number of the plugin.
|
Chris@0
|
80 */
|
Chris@0
|
81 virtual int getPluginVersion() const = 0;
|
Chris@0
|
82
|
Chris@0
|
83 /**
|
Chris@0
|
84 * Get the copyright statement or licensing summary of the plugin.
|
Chris@0
|
85 */
|
Chris@0
|
86 virtual std::string getCopyright() const = 0;
|
Chris@0
|
87
|
Chris@0
|
88 /**
|
Chris@0
|
89 * Get the preferred step size (window increment -- the distance
|
Chris@0
|
90 * in sample frames between the start frames of consecutive blocks
|
Chris@0
|
91 * passed to the process() function) for the plugin. This should
|
Chris@0
|
92 * be called before initialise().
|
Chris@0
|
93 */
|
Chris@0
|
94 virtual size_t getPreferredStepSize() const = 0;
|
Chris@0
|
95
|
Chris@0
|
96 /**
|
Chris@0
|
97 * Get the preferred block size (window size -- the number of
|
Chris@0
|
98 * sample frames passed in each block to the process() function).
|
Chris@0
|
99 * This should be called before initialise().
|
Chris@0
|
100 */
|
Chris@0
|
101 virtual size_t getPreferredBlockSize() const { return getPreferredStepSize(); }
|
Chris@0
|
102
|
Chris@0
|
103 /**
|
Chris@0
|
104 * Get the minimum supported number of input channels.
|
Chris@0
|
105 */
|
Chris@0
|
106 virtual size_t getMinChannelCount() const { return 1; }
|
Chris@0
|
107
|
Chris@0
|
108 /**
|
Chris@0
|
109 * Get the maximum supported number of input channels.
|
Chris@0
|
110 */
|
Chris@0
|
111 virtual size_t getMaxChannelCount() const { return 1; }
|
Chris@0
|
112
|
Chris@0
|
113
|
Chris@0
|
114 struct OutputDescriptor
|
Chris@0
|
115 {
|
Chris@0
|
116 /**
|
Chris@0
|
117 * The name of the output, in computer-usable form. Should be
|
Chris@0
|
118 * reasonably short and without whitespace or punctuation.
|
Chris@0
|
119 */
|
Chris@0
|
120 std::string name;
|
Chris@0
|
121
|
Chris@0
|
122 /**
|
Chris@0
|
123 * The human-readable name of the output.
|
Chris@0
|
124 */
|
Chris@0
|
125 std::string description;
|
Chris@0
|
126
|
Chris@0
|
127 /**
|
Chris@0
|
128 * The unit of the output, in human-readable form.
|
Chris@0
|
129 */
|
Chris@0
|
130 std::string unit;
|
Chris@0
|
131
|
Chris@0
|
132 /**
|
Chris@0
|
133 * True if the output has the same number of values per result
|
Chris@0
|
134 * for every output result. Outputs for which this is false
|
Chris@0
|
135 * are unlikely to be very useful in a general-purpose host.
|
Chris@0
|
136 */
|
Chris@0
|
137 bool hasFixedValueCount;
|
Chris@0
|
138
|
Chris@0
|
139 /**
|
Chris@0
|
140 * The number of values per result of the output. Undefined
|
Chris@0
|
141 * if hasFixedValueCount is false. If this is zero, the output
|
Chris@0
|
142 * is point data (i.e. only the time of each output is of
|
Chris@0
|
143 * interest, the value list will be empty).
|
Chris@0
|
144 *
|
Chris@0
|
145 * Note that this gives the number of values of a single
|
Chris@0
|
146 * output result, not of the output stream (which has one more
|
Chris@0
|
147 * dimension: time).
|
Chris@0
|
148 */
|
Chris@0
|
149 size_t valueCount;
|
Chris@0
|
150
|
Chris@0
|
151 /**
|
Chris@0
|
152 * True if the results in the output have a fixed numeric
|
Chris@0
|
153 * range (minimum and maximum values). Undefined if
|
Chris@0
|
154 * valueCount is zero.
|
Chris@0
|
155 */
|
Chris@0
|
156 bool hasKnownExtents;
|
Chris@0
|
157
|
Chris@0
|
158 /**
|
Chris@0
|
159 * Minimum value of the results in the output. Undefined if
|
Chris@0
|
160 * hasKnownExtents is false or valueCount is zero.
|
Chris@0
|
161 */
|
Chris@0
|
162 float minValue;
|
Chris@0
|
163
|
Chris@0
|
164 /**
|
Chris@0
|
165 * Maximum value of the results in the output. Undefined if
|
Chris@0
|
166 * hasKnownExtents is false or valueCount is zero.
|
Chris@0
|
167 */
|
Chris@0
|
168 float maxValue;
|
Chris@0
|
169
|
Chris@0
|
170 /**
|
Chris@0
|
171 * True if the output values are quantized to a particular
|
Chris@0
|
172 * resolution. Undefined if valueCount is zero.
|
Chris@0
|
173 */
|
Chris@0
|
174 bool isQuantized;
|
Chris@0
|
175
|
Chris@0
|
176 /**
|
Chris@0
|
177 * Quantization resolution of the output values (e.g. 1.0 if
|
Chris@0
|
178 * they are all integers). Undefined if isQuantized is false
|
Chris@0
|
179 * or valueCount is zero.
|
Chris@0
|
180 */
|
Chris@0
|
181 float quantizeStep;
|
Chris@0
|
182
|
Chris@0
|
183 enum SampleType {
|
Chris@0
|
184
|
Chris@0
|
185 /// Results from each process() align with that call's block start
|
Chris@0
|
186 OneSamplePerStep,
|
Chris@0
|
187
|
Chris@0
|
188 /// Results are evenly spaced in time (sampleRate specified below)
|
Chris@0
|
189 FixedSampleRate,
|
Chris@0
|
190
|
Chris@0
|
191 /// Results are unevenly spaced and have individual timestamps
|
Chris@0
|
192 VariableSampleRate
|
Chris@0
|
193 };
|
Chris@0
|
194
|
Chris@0
|
195 /**
|
Chris@0
|
196 * Positioning in time of the output results.
|
Chris@0
|
197 */
|
Chris@0
|
198 SampleType sampleType;
|
Chris@0
|
199
|
Chris@0
|
200 /**
|
Chris@0
|
201 * Sample rate of the output results. Undefined if sampleType
|
Chris@0
|
202 * is OneSamplePerStep.
|
Chris@0
|
203 *
|
Chris@0
|
204 * If sampleType is VariableSampleRate and this value is
|
Chris@0
|
205 * non-zero, then it may be used to calculate a resolution for
|
Chris@0
|
206 * the output (i.e. the "duration" of each value, in time).
|
Chris@0
|
207 * It's recommended to set this to zero if that behaviour is
|
Chris@0
|
208 * not desired.
|
Chris@0
|
209 */
|
Chris@0
|
210 float sampleRate;
|
Chris@0
|
211 };
|
Chris@0
|
212
|
Chris@0
|
213 typedef std::vector<OutputDescriptor> OutputList;
|
Chris@0
|
214
|
Chris@0
|
215 /**
|
Chris@0
|
216 * Get the outputs of this plugin. An output's index in this list
|
Chris@0
|
217 * is used as its numeric index when looking it up in the
|
Chris@0
|
218 * FeatureSet returned from the process() call.
|
Chris@0
|
219 */
|
Chris@0
|
220 virtual OutputList getOutputDescriptors() const = 0;
|
Chris@0
|
221
|
Chris@0
|
222
|
Chris@0
|
223 struct ParameterDescriptor
|
Chris@0
|
224 {
|
Chris@0
|
225 /**
|
Chris@0
|
226 * The name of the parameter, in computer-usable form. Should
|
Chris@0
|
227 * be reasonably short and without whitespace or punctuation.
|
Chris@0
|
228 */
|
Chris@0
|
229 std::string name;
|
Chris@0
|
230
|
Chris@0
|
231 /**
|
Chris@0
|
232 * The human-readable name of the parameter.
|
Chris@0
|
233 */
|
Chris@0
|
234 std::string description;
|
Chris@0
|
235
|
Chris@0
|
236 /**
|
Chris@0
|
237 * The unit of the parameter, in human-readable form.
|
Chris@0
|
238 */
|
Chris@0
|
239 std::string unit;
|
Chris@0
|
240
|
Chris@0
|
241 /**
|
Chris@0
|
242 * The minimum value of the parameter.
|
Chris@0
|
243 */
|
Chris@0
|
244 float minValue;
|
Chris@0
|
245
|
Chris@0
|
246 /**
|
Chris@0
|
247 * The maximum value of the parameter.
|
Chris@0
|
248 */
|
Chris@0
|
249 float maxValue;
|
Chris@0
|
250
|
Chris@0
|
251 /**
|
Chris@0
|
252 * The default value of the parameter.
|
Chris@0
|
253 */
|
Chris@0
|
254 float defaultValue;
|
Chris@0
|
255
|
Chris@0
|
256 /**
|
Chris@0
|
257 * True if the parameter values are quantized to a particular
|
Chris@0
|
258 * resolution.
|
Chris@0
|
259 */
|
Chris@0
|
260 bool isQuantized;
|
Chris@0
|
261
|
Chris@0
|
262 /**
|
Chris@0
|
263 * Quantization resolution of the parameter values (e.g. 1.0
|
Chris@0
|
264 * if they are all integers). Undefined if isQuantized is
|
Chris@0
|
265 * false.
|
Chris@0
|
266 */
|
Chris@0
|
267 float quantizeStep;
|
Chris@0
|
268 };
|
Chris@0
|
269
|
Chris@0
|
270 typedef std::vector<ParameterDescriptor> ParameterList;
|
Chris@0
|
271
|
Chris@0
|
272 /**
|
Chris@0
|
273 * Get the controllable parameters of this plugin.
|
Chris@0
|
274 */
|
Chris@0
|
275 virtual ParameterList getParameterDescriptors() const {
|
Chris@0
|
276 return ParameterList();
|
Chris@0
|
277 }
|
Chris@0
|
278
|
Chris@0
|
279 /**
|
Chris@0
|
280 * Get the value of a named parameter. The argument is the name
|
Chris@0
|
281 * field from that parameter's descriptor.
|
Chris@0
|
282 */
|
Chris@0
|
283 virtual float getParameter(std::string) const { return 0.0; }
|
Chris@0
|
284
|
Chris@0
|
285 /**
|
Chris@0
|
286 * Set a named parameter. The first argument is the name field
|
Chris@0
|
287 * from that parameter's descriptor.
|
Chris@0
|
288 */
|
Chris@0
|
289 virtual void setParameter(std::string, float) { }
|
Chris@0
|
290
|
Chris@0
|
291 struct Feature
|
Chris@0
|
292 {
|
Chris@0
|
293 /**
|
Chris@0
|
294 * True if an output feature has its own timestamp. This is
|
Chris@0
|
295 * mandatory if the output has VariableSampleRate, and is
|
Chris@0
|
296 * likely to be disregarded otherwise.
|
Chris@0
|
297 */
|
Chris@0
|
298 bool hasTimestamp;
|
Chris@0
|
299
|
Chris@0
|
300 /**
|
Chris@0
|
301 * Timestamp of the output feature. This is mandatory if the
|
Chris@0
|
302 * output has VariableSampleRate, and is likely to be
|
Chris@0
|
303 * disregarded otherwise. Undefined if hasTimestamp is false.
|
Chris@0
|
304 */
|
Chris@0
|
305 RealTime timestamp;
|
Chris@0
|
306
|
Chris@0
|
307 /**
|
Chris@0
|
308 * Results for a single sample of this feature. If the output
|
Chris@0
|
309 * hasFixedValueCount, there must be the same number of values
|
Chris@0
|
310 * as the output's valueCount count.
|
Chris@0
|
311 */
|
Chris@0
|
312 std::vector<float> values;
|
Chris@0
|
313
|
Chris@0
|
314 /**
|
Chris@0
|
315 * Label for the sample of this feature.
|
Chris@0
|
316 */
|
Chris@0
|
317 std::string label;
|
Chris@0
|
318 };
|
Chris@0
|
319
|
Chris@0
|
320 typedef std::vector<Feature> FeatureList;
|
Chris@0
|
321 typedef std::map<int, FeatureList> FeatureSet; // key is output no
|
Chris@0
|
322
|
Chris@0
|
323 /**
|
Chris@0
|
324 * Process a single block of input data. inputBuffers points to
|
Chris@0
|
325 * one array of floats per input channel, and each of those arrays
|
Chris@0
|
326 * contains the blockSize number of samples (the host will
|
Chris@0
|
327 * zero-pad as necessary). The timestamp is the real time in
|
Chris@0
|
328 * seconds of the start of the supplied block of samples.
|
Chris@0
|
329 *
|
Chris@0
|
330 * Return any features that have become available after this
|
Chris@0
|
331 * process call. (These do not necessarily have to fall within
|
Chris@0
|
332 * the process block, except for OneSamplePerStep outputs.)
|
Chris@0
|
333 */
|
Chris@0
|
334 virtual FeatureSet process(float **inputBuffers,
|
Chris@0
|
335 RealTime timestamp) = 0;
|
Chris@0
|
336
|
Chris@0
|
337 /**
|
Chris@0
|
338 * After all blocks have been processed, calculate and return any
|
Chris@0
|
339 * remaining features derived from the complete input.
|
Chris@0
|
340 */
|
Chris@0
|
341 virtual FeatureSet getRemainingFeatures() = 0;
|
Chris@0
|
342
|
Chris@0
|
343 protected:
|
Chris@0
|
344 FeatureExtractionPlugin(float inputSampleRate) :
|
Chris@0
|
345 m_inputSampleRate(inputSampleRate) { }
|
Chris@0
|
346
|
Chris@0
|
347 float m_inputSampleRate;
|
Chris@0
|
348 };
|
Chris@0
|
349
|
Chris@0
|
350 #endif
|
Chris@0
|
351
|
Chris@0
|
352
|
Chris@0
|
353
|