Chris@31
|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
Chris@31
|
2 /*
|
Chris@31
|
3 Vamp Test Plugin
|
Chris@31
|
4 Copyright (c) 2013-2016 Queen Mary, University of London
|
Chris@0
|
5
|
Chris@31
|
6 Permission is hereby granted, free of charge, to any person
|
Chris@31
|
7 obtaining a copy of this software and associated documentation
|
Chris@31
|
8 files (the "Software"), to deal in the Software without
|
Chris@31
|
9 restriction, including without limitation the rights to use, copy,
|
Chris@31
|
10 modify, merge, publish, distribute, sublicense, and/or sell copies
|
Chris@31
|
11 of the Software, and to permit persons to whom the Software is
|
Chris@31
|
12 furnished to do so, subject to the following conditions:
|
Chris@31
|
13
|
Chris@31
|
14 The above copyright notice and this permission notice shall be
|
Chris@31
|
15 included in all copies or substantial portions of the Software.
|
Chris@31
|
16
|
Chris@31
|
17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
Chris@31
|
18 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
Chris@31
|
19 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
Chris@31
|
20 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
Chris@31
|
21 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
Chris@31
|
22 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
Chris@31
|
23 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
Chris@31
|
24
|
Chris@31
|
25 Except as contained in this notice, the names of the Centre for
|
Chris@31
|
26 Digital Music and Queen Mary, University of London shall not be
|
Chris@31
|
27 used in advertising or otherwise to promote the sale, use or other
|
Chris@31
|
28 dealings in this Software without prior written authorization.
|
Chris@31
|
29 */
|
Chris@0
|
30
|
Chris@0
|
31 #include "VampTestPlugin.h"
|
Chris@0
|
32
|
Chris@22
|
33 #include <vamp-sdk/FFT.h>
|
Chris@22
|
34
|
Chris@19
|
35 #include <iostream>
|
Chris@3
|
36 #include <sstream>
|
Chris@18
|
37 #include <cmath>
|
Chris@3
|
38
|
Chris@19
|
39 using namespace std;
|
Chris@3
|
40
|
Chris@3
|
41 using Vamp::RealTime;
|
Chris@0
|
42
|
Chris@20
|
43 VampTestPlugin::VampTestPlugin(float inputSampleRate, bool freq) :
|
Chris@3
|
44 Plugin(inputSampleRate),
|
Chris@20
|
45 m_frequencyDomain(freq),
|
Chris@17
|
46 m_produceOutput(true),
|
Chris@3
|
47 m_n(0),
|
Chris@18
|
48 m_channels(1),
|
Chris@3
|
49 m_stepSize(0),
|
Chris@3
|
50 m_blockSize(0)
|
Chris@0
|
51 {
|
Chris@3
|
52 for (int i = 0; i < 10; ++i) {
|
Chris@31
|
53 m_instants.push_back(RealTime::fromSeconds(1.5 * i));
|
Chris@3
|
54 }
|
Chris@0
|
55 }
|
Chris@0
|
56
|
Chris@0
|
57 VampTestPlugin::~VampTestPlugin()
|
Chris@0
|
58 {
|
Chris@0
|
59 }
|
Chris@0
|
60
|
Chris@0
|
61 string
|
Chris@0
|
62 VampTestPlugin::getIdentifier() const
|
Chris@0
|
63 {
|
Chris@20
|
64 if (m_frequencyDomain) {
|
Chris@31
|
65 return "vamp-test-plugin-freq";
|
Chris@20
|
66 } else {
|
Chris@31
|
67 return "vamp-test-plugin";
|
Chris@20
|
68 }
|
Chris@0
|
69 }
|
Chris@0
|
70
|
Chris@0
|
71 string
|
Chris@0
|
72 VampTestPlugin::getName() const
|
Chris@0
|
73 {
|
Chris@20
|
74 if (m_frequencyDomain) {
|
Chris@31
|
75 return "Vamp Test Plugin (Frequency-Domain Input)";
|
Chris@20
|
76 } else {
|
Chris@31
|
77 return "Vamp Test Plugin";
|
Chris@20
|
78 }
|
Chris@0
|
79 }
|
Chris@0
|
80
|
Chris@0
|
81 string
|
Chris@0
|
82 VampTestPlugin::getDescription() const
|
Chris@0
|
83 {
|
Chris@0
|
84 return "Test plugin for hosts handling various output types";
|
Chris@0
|
85 }
|
Chris@0
|
86
|
Chris@0
|
87 string
|
Chris@0
|
88 VampTestPlugin::getMaker() const
|
Chris@0
|
89 {
|
Chris@0
|
90 return "Chris Cannam";
|
Chris@0
|
91 }
|
Chris@0
|
92
|
Chris@0
|
93 int
|
Chris@0
|
94 VampTestPlugin::getPluginVersion() const
|
Chris@0
|
95 {
|
Chris@35
|
96 return 4;
|
Chris@0
|
97 }
|
Chris@0
|
98
|
Chris@0
|
99 string
|
Chris@0
|
100 VampTestPlugin::getCopyright() const
|
Chris@0
|
101 {
|
Chris@0
|
102 return "BSD";
|
Chris@0
|
103 }
|
Chris@0
|
104
|
Chris@0
|
105 VampTestPlugin::InputDomain
|
Chris@0
|
106 VampTestPlugin::getInputDomain() const
|
Chris@0
|
107 {
|
Chris@20
|
108 return m_frequencyDomain ? FrequencyDomain : TimeDomain;
|
Chris@0
|
109 }
|
Chris@0
|
110
|
Chris@0
|
111 size_t
|
Chris@0
|
112 VampTestPlugin::getPreferredBlockSize() const
|
Chris@0
|
113 {
|
Chris@0
|
114 return 0;
|
Chris@0
|
115 }
|
Chris@0
|
116
|
Chris@0
|
117 size_t
|
Chris@0
|
118 VampTestPlugin::getPreferredStepSize() const
|
Chris@0
|
119 {
|
Chris@0
|
120 return 0;
|
Chris@0
|
121 }
|
Chris@0
|
122
|
Chris@0
|
123 size_t
|
Chris@0
|
124 VampTestPlugin::getMinChannelCount() const
|
Chris@0
|
125 {
|
Chris@0
|
126 return 1;
|
Chris@0
|
127 }
|
Chris@0
|
128
|
Chris@0
|
129 size_t
|
Chris@0
|
130 VampTestPlugin::getMaxChannelCount() const
|
Chris@0
|
131 {
|
Chris@18
|
132 return 10;
|
Chris@0
|
133 }
|
Chris@0
|
134
|
Chris@0
|
135 VampTestPlugin::ParameterList
|
Chris@0
|
136 VampTestPlugin::getParameterDescriptors() const
|
Chris@0
|
137 {
|
Chris@0
|
138 ParameterList list;
|
Chris@17
|
139
|
Chris@17
|
140 // Provide one parameter, and make it so that we can easily tell
|
Chris@17
|
141 // whether it has been changed
|
Chris@17
|
142 ParameterDescriptor d;
|
Chris@17
|
143 d.identifier = "produce_output";
|
Chris@17
|
144 d.name = "Produce some output";
|
Chris@17
|
145 d.description = "Whether to produce any output. If this parameter is switched off, the plugin will produce no output. This is intended for basic testing of whether a host's parameter setting logic is functioning.";
|
Chris@17
|
146 d.unit = "";
|
Chris@17
|
147 d.minValue = 0;
|
Chris@17
|
148 d.maxValue = 1;
|
Chris@17
|
149 d.defaultValue = 1;
|
Chris@17
|
150 d.isQuantized = true;
|
Chris@17
|
151 d.quantizeStep = 1;
|
Chris@17
|
152 list.push_back(d);
|
Chris@17
|
153
|
Chris@0
|
154 return list;
|
Chris@0
|
155 }
|
Chris@0
|
156
|
Chris@0
|
157 float
|
Chris@0
|
158 VampTestPlugin::getParameter(string identifier) const
|
Chris@0
|
159 {
|
Chris@17
|
160 if (identifier == "produce_output") {
|
Chris@31
|
161 return m_produceOutput ? 1.f : 0.f;
|
Chris@17
|
162 }
|
Chris@0
|
163 return 0;
|
Chris@0
|
164 }
|
Chris@0
|
165
|
Chris@0
|
166 void
|
Chris@0
|
167 VampTestPlugin::setParameter(string identifier, float value)
|
Chris@0
|
168 {
|
Chris@17
|
169 if (identifier == "produce_output") {
|
Chris@31
|
170 m_produceOutput = (value > 0.5);
|
Chris@17
|
171 }
|
Chris@0
|
172 }
|
Chris@0
|
173
|
Chris@0
|
174 VampTestPlugin::ProgramList
|
Chris@0
|
175 VampTestPlugin::getPrograms() const
|
Chris@0
|
176 {
|
Chris@0
|
177 ProgramList list;
|
Chris@0
|
178 return list;
|
Chris@0
|
179 }
|
Chris@0
|
180
|
Chris@0
|
181 string
|
Chris@0
|
182 VampTestPlugin::getCurrentProgram() const
|
Chris@0
|
183 {
|
Chris@0
|
184 return ""; // no programs
|
Chris@0
|
185 }
|
Chris@0
|
186
|
Chris@0
|
187 void
|
Chris@23
|
188 VampTestPlugin::selectProgram(string)
|
Chris@0
|
189 {
|
Chris@0
|
190 }
|
Chris@0
|
191
|
Chris@0
|
192 VampTestPlugin::OutputList
|
Chris@0
|
193 VampTestPlugin::getOutputDescriptors() const
|
Chris@0
|
194 {
|
Chris@0
|
195 OutputList list;
|
Chris@0
|
196
|
Chris@7
|
197 int n = 0;
|
Chris@7
|
198
|
Chris@0
|
199 OutputDescriptor d;
|
Chris@1
|
200
|
Chris@1
|
201 d.identifier = "instants";
|
Chris@1
|
202 d.name = "Instants";
|
Chris@2
|
203 d.description = "Single time points without values";
|
Chris@1
|
204 d.unit = "";
|
Chris@1
|
205 d.hasFixedBinCount = true;
|
Chris@1
|
206 d.binCount = 0;
|
Chris@1
|
207 d.hasKnownExtents = false;
|
Chris@1
|
208 d.isQuantized = false;
|
Chris@1
|
209 d.sampleType = OutputDescriptor::VariableSampleRate;
|
Chris@1
|
210 d.hasDuration = false;
|
Chris@7
|
211 m_outputNumbers[d.identifier] = n++;
|
Chris@1
|
212 list.push_back(d);
|
Chris@1
|
213
|
Chris@1
|
214 d.identifier = "curve-oss";
|
Chris@1
|
215 d.name = "Curve: OneSamplePerStep";
|
Chris@2
|
216 d.description = "A time series with one value per process block";
|
Chris@0
|
217 d.unit = "";
|
Chris@0
|
218 d.hasFixedBinCount = true;
|
Chris@0
|
219 d.binCount = 1;
|
Chris@0
|
220 d.hasKnownExtents = false;
|
Chris@0
|
221 d.isQuantized = false;
|
Chris@0
|
222 d.sampleType = OutputDescriptor::OneSamplePerStep;
|
Chris@0
|
223 d.hasDuration = false;
|
Chris@7
|
224 m_outputNumbers[d.identifier] = n++;
|
Chris@0
|
225 list.push_back(d);
|
Chris@0
|
226
|
Chris@1
|
227 d.identifier = "curve-fsr";
|
Chris@1
|
228 d.name = "Curve: FixedSampleRate";
|
Chris@2
|
229 d.description = "A time series with equally-spaced values (independent of process step size)";
|
Chris@1
|
230 d.unit = "";
|
Chris@1
|
231 d.hasFixedBinCount = true;
|
Chris@1
|
232 d.binCount = 1;
|
Chris@1
|
233 d.hasKnownExtents = false;
|
Chris@1
|
234 d.isQuantized = false;
|
Chris@1
|
235 d.sampleType = OutputDescriptor::FixedSampleRate;
|
Chris@8
|
236 d.sampleRate = 2.5;
|
Chris@1
|
237 d.hasDuration = false;
|
Chris@7
|
238 m_outputNumbers[d.identifier] = n++;
|
Chris@1
|
239 list.push_back(d);
|
Chris@1
|
240
|
Chris@7
|
241 d.identifier = "curve-fsr-timed";
|
Chris@7
|
242 d.name = "Curve: FixedSampleRate/Timed";
|
Chris@7
|
243 d.description = "A time series with a fixed sample rate (independent of process step size) but with timestamps on features";
|
Chris@7
|
244 d.unit = "";
|
Chris@7
|
245 d.hasFixedBinCount = true;
|
Chris@7
|
246 d.binCount = 1;
|
Chris@7
|
247 d.hasKnownExtents = false;
|
Chris@7
|
248 d.isQuantized = false;
|
Chris@7
|
249 d.sampleType = OutputDescriptor::FixedSampleRate;
|
Chris@8
|
250 d.sampleRate = 2.5;
|
Chris@7
|
251 d.hasDuration = false;
|
Chris@7
|
252 m_outputNumbers[d.identifier] = n++;
|
Chris@7
|
253 list.push_back(d);
|
Chris@7
|
254
|
Chris@32
|
255 d.identifier = "curve-fsr-mixed";
|
Chris@32
|
256 d.name = "Curve: FixedSampleRate/Mixed";
|
Chris@32
|
257 d.description = "A time series with a fixed sample rate (independent of process step size) and with timestamps on some features";
|
Chris@32
|
258 d.unit = "";
|
Chris@32
|
259 d.hasFixedBinCount = true;
|
Chris@32
|
260 d.binCount = 1;
|
Chris@32
|
261 d.hasKnownExtents = false;
|
Chris@32
|
262 d.isQuantized = false;
|
Chris@32
|
263 d.sampleType = OutputDescriptor::FixedSampleRate;
|
Chris@32
|
264 d.sampleRate = 2.5;
|
Chris@32
|
265 d.hasDuration = false;
|
Chris@32
|
266 m_outputNumbers[d.identifier] = n++;
|
Chris@32
|
267 list.push_back(d);
|
Chris@32
|
268
|
Chris@1
|
269 d.identifier = "curve-vsr";
|
Chris@1
|
270 d.name = "Curve: VariableSampleRate";
|
Chris@2
|
271 d.description = "A variably-spaced series of values";
|
Chris@1
|
272 d.unit = "";
|
Chris@1
|
273 d.hasFixedBinCount = true;
|
Chris@1
|
274 d.binCount = 1;
|
Chris@1
|
275 d.hasKnownExtents = false;
|
Chris@1
|
276 d.isQuantized = false;
|
Chris@1
|
277 d.sampleType = OutputDescriptor::VariableSampleRate;
|
Chris@2
|
278 d.sampleRate = 0;
|
Chris@1
|
279 d.hasDuration = false;
|
Chris@7
|
280 m_outputNumbers[d.identifier] = n++;
|
Chris@1
|
281 list.push_back(d);
|
Chris@1
|
282
|
Chris@2
|
283 d.identifier = "grid-oss";
|
Chris@2
|
284 d.name = "Grid: OneSamplePerStep";
|
Chris@2
|
285 d.description = "A fixed-height grid of values with one column per process block";
|
Chris@2
|
286 d.unit = "";
|
Chris@2
|
287 d.hasFixedBinCount = true;
|
Chris@4
|
288 d.binCount = 10;
|
Chris@2
|
289 d.hasKnownExtents = false;
|
Chris@2
|
290 d.isQuantized = false;
|
Chris@4
|
291 d.sampleType = OutputDescriptor::OneSamplePerStep;
|
Chris@2
|
292 d.sampleRate = 0;
|
Chris@2
|
293 d.hasDuration = false;
|
Chris@7
|
294 m_outputNumbers[d.identifier] = n++;
|
Chris@2
|
295 list.push_back(d);
|
Chris@2
|
296
|
Chris@2
|
297 d.identifier = "grid-fsr";
|
Chris@2
|
298 d.name = "Grid: FixedSampleRate";
|
Chris@2
|
299 d.description = "A fixed-height grid of values with equally-spaced columns (independent of process step size)";
|
Chris@2
|
300 d.unit = "";
|
Chris@2
|
301 d.hasFixedBinCount = true;
|
Chris@4
|
302 d.binCount = 10;
|
Chris@2
|
303 d.hasKnownExtents = false;
|
Chris@2
|
304 d.isQuantized = false;
|
Chris@4
|
305 d.sampleType = OutputDescriptor::FixedSampleRate;
|
Chris@8
|
306 d.sampleRate = 2.5;
|
Chris@2
|
307 d.hasDuration = false;
|
Chris@7
|
308 m_outputNumbers[d.identifier] = n++;
|
Chris@2
|
309 list.push_back(d);
|
Chris@2
|
310
|
Chris@5
|
311 d.identifier = "notes-regions";
|
Chris@5
|
312 d.name = "Notes or Regions";
|
Chris@5
|
313 d.description = "Variably-spaced features with one value and duration";
|
Chris@5
|
314 d.unit = "";
|
Chris@5
|
315 d.hasFixedBinCount = true;
|
Chris@5
|
316 d.binCount = 1;
|
Chris@5
|
317 d.hasKnownExtents = false;
|
Chris@5
|
318 d.isQuantized = false;
|
Chris@5
|
319 d.sampleType = OutputDescriptor::VariableSampleRate;
|
Chris@5
|
320 d.sampleRate = 0;
|
Chris@5
|
321 d.hasDuration = true;
|
Chris@7
|
322 m_outputNumbers[d.identifier] = n++;
|
Chris@5
|
323 list.push_back(d);
|
Chris@2
|
324
|
Chris@19
|
325 d.identifier = "input-summary";
|
Chris@19
|
326 d.name = "Data derived from inputs";
|
Chris@22
|
327 d.description = "One-sample-per-step features with n values, where n is the number of input channels. Each feature contains, for each input channel, the first sample value on that channel plus the total number of non-zero samples on that channel. (\"Non-zero\" is determined by comparison against a magnitude threshold which is actually 1e-6 rather than exactly zero.)";
|
Chris@18
|
328 d.unit = "";
|
Chris@18
|
329 d.hasFixedBinCount = true;
|
Chris@18
|
330 d.binCount = m_channels;
|
Chris@18
|
331 d.hasKnownExtents = false;
|
Chris@18
|
332 d.isQuantized = false;
|
Chris@18
|
333 d.sampleType = OutputDescriptor::OneSamplePerStep;
|
Chris@18
|
334 d.hasDuration = false;
|
Chris@18
|
335 m_outputNumbers[d.identifier] = n++;
|
Chris@18
|
336 list.push_back(d);
|
Chris@18
|
337
|
Chris@20
|
338 d.identifier = "input-timestamp";
|
Chris@20
|
339 d.name = "Input timestamp";
|
Chris@21
|
340 d.description = "One-sample-per-step features with one value, containing the time in sample frames converted from the timestamp of the corresponding process input block.";
|
Chris@21
|
341 d.unit = "samples";
|
Chris@20
|
342 d.hasFixedBinCount = true;
|
Chris@20
|
343 d.binCount = 1;
|
Chris@20
|
344 d.hasKnownExtents = false;
|
Chris@20
|
345 d.isQuantized = false;
|
Chris@20
|
346 d.sampleType = OutputDescriptor::OneSamplePerStep;
|
Chris@20
|
347 d.hasDuration = false;
|
Chris@20
|
348 m_outputNumbers[d.identifier] = n++;
|
Chris@20
|
349 list.push_back(d);
|
Chris@20
|
350
|
Chris@0
|
351 return list;
|
Chris@0
|
352 }
|
Chris@0
|
353
|
Chris@0
|
354 bool
|
Chris@0
|
355 VampTestPlugin::initialise(size_t channels, size_t stepSize, size_t blockSize)
|
Chris@0
|
356 {
|
Chris@0
|
357 if (channels < getMinChannelCount() ||
|
Chris@31
|
358 channels > getMaxChannelCount()) return false;
|
Chris@0
|
359
|
Chris@18
|
360 m_channels = channels;
|
Chris@3
|
361 m_stepSize = stepSize;
|
Chris@3
|
362 m_blockSize = blockSize;
|
Chris@0
|
363
|
Chris@0
|
364 return true;
|
Chris@0
|
365 }
|
Chris@0
|
366
|
Chris@0
|
367 void
|
Chris@0
|
368 VampTestPlugin::reset()
|
Chris@0
|
369 {
|
Chris@3
|
370 m_n = 0;
|
Chris@3
|
371 }
|
Chris@3
|
372
|
Chris@3
|
373 static Vamp::Plugin::Feature
|
Chris@3
|
374 instant(RealTime r, int i, int n)
|
Chris@3
|
375 {
|
Chris@19
|
376 stringstream s;
|
Chris@3
|
377 Vamp::Plugin::Feature f;
|
Chris@3
|
378 f.hasTimestamp = true;
|
Chris@3
|
379 f.timestamp = r;
|
Chris@3
|
380 f.hasDuration = false;
|
Chris@3
|
381 s << i+1 << " of " << n << " at " << r.toText();
|
Chris@3
|
382 f.label = s.str();
|
Chris@3
|
383 return f;
|
Chris@3
|
384 }
|
Chris@3
|
385
|
Chris@3
|
386 static Vamp::Plugin::Feature
|
Chris@3
|
387 untimedCurveValue(RealTime r, int i, int n)
|
Chris@3
|
388 {
|
Chris@19
|
389 stringstream s;
|
Chris@3
|
390 Vamp::Plugin::Feature f;
|
Chris@3
|
391 f.hasTimestamp = false;
|
Chris@3
|
392 f.hasDuration = false;
|
Chris@3
|
393 float v = float(i) / float(n);
|
Chris@3
|
394 f.values.push_back(v);
|
Chris@3
|
395 s << i+1 << " of " << n << ": " << v << " at " << r.toText();
|
Chris@3
|
396 f.label = s.str();
|
Chris@3
|
397 return f;
|
Chris@0
|
398 }
|
Chris@0
|
399
|
Chris@4
|
400 static Vamp::Plugin::Feature
|
Chris@4
|
401 timedCurveValue(RealTime r, int i, int n)
|
Chris@4
|
402 {
|
Chris@19
|
403 stringstream s;
|
Chris@4
|
404 Vamp::Plugin::Feature f;
|
Chris@4
|
405 f.hasTimestamp = true;
|
Chris@4
|
406 f.timestamp = r;
|
Chris@4
|
407 f.hasDuration = false;
|
Chris@4
|
408 float v = float(i) / float(n);
|
Chris@4
|
409 f.values.push_back(v);
|
Chris@4
|
410 s << i+1 << " of " << n << ": " << v << " at " << r.toText();
|
Chris@4
|
411 f.label = s.str();
|
Chris@4
|
412 return f;
|
Chris@4
|
413 }
|
Chris@4
|
414
|
Chris@4
|
415 static Vamp::Plugin::Feature
|
Chris@7
|
416 snappedCurveValue(RealTime r, RealTime sn, int i, int n)
|
Chris@7
|
417 {
|
Chris@19
|
418 stringstream s;
|
Chris@7
|
419 Vamp::Plugin::Feature f;
|
Chris@7
|
420 f.hasTimestamp = true;
|
Chris@7
|
421 f.timestamp = r;
|
Chris@7
|
422 f.hasDuration = false;
|
Chris@7
|
423 float v = float(i) / float(n);
|
Chris@7
|
424 f.values.push_back(v);
|
Chris@7
|
425 s << i+1 << " of " << n << ": " << v << " at " << r.toText() << " snap to " << sn.toText();
|
Chris@7
|
426 f.label = s.str();
|
Chris@7
|
427 return f;
|
Chris@7
|
428 }
|
Chris@7
|
429
|
Chris@7
|
430 static Vamp::Plugin::Feature
|
Chris@4
|
431 gridColumn(RealTime r, int i, int n)
|
Chris@4
|
432 {
|
Chris@19
|
433 stringstream s;
|
Chris@4
|
434 Vamp::Plugin::Feature f;
|
Chris@4
|
435 f.hasTimestamp = false;
|
Chris@4
|
436 f.hasDuration = false;
|
Chris@4
|
437 for (int j = 0; j < 10; ++j) {
|
Chris@31
|
438 float v = float(j + i + 2) / float(n + 10);
|
Chris@31
|
439 f.values.push_back(v);
|
Chris@4
|
440 }
|
Chris@4
|
441 s << i+1 << " of " << n << " at " << r.toText();
|
Chris@4
|
442 f.label = s.str();
|
Chris@4
|
443 return f;
|
Chris@4
|
444 }
|
Chris@4
|
445
|
Chris@5
|
446 static Vamp::Plugin::Feature
|
Chris@5
|
447 noteOrRegion(RealTime r, RealTime d, int i, int n)
|
Chris@5
|
448 {
|
Chris@19
|
449 stringstream s;
|
Chris@5
|
450 Vamp::Plugin::Feature f;
|
Chris@5
|
451 f.hasTimestamp = true;
|
Chris@5
|
452 f.timestamp = r;
|
Chris@5
|
453 f.hasDuration = true;
|
Chris@5
|
454 f.duration = d;
|
Chris@5
|
455 float v = float(i) / float(n);
|
Chris@5
|
456 f.values.push_back(v);
|
Chris@5
|
457 s << i+1 << " of " << n << ": " << v << " at " << r.toText() << " dur. " << d.toText();
|
Chris@5
|
458 f.label = s.str();
|
Chris@5
|
459 return f;
|
Chris@5
|
460 }
|
Chris@5
|
461
|
Chris@7
|
462 static
|
Chris@7
|
463 float snap(float x, float r)
|
Chris@7
|
464 {
|
Chris@7
|
465 int n = int(x / r + 0.5);
|
Chris@7
|
466 return n * r;
|
Chris@7
|
467 }
|
Chris@7
|
468
|
Chris@5
|
469 Vamp::Plugin::FeatureSet
|
Chris@5
|
470 VampTestPlugin::featuresFrom(RealTime timestamp, bool final)
|
Chris@0
|
471 {
|
Chris@3
|
472 FeatureSet fs;
|
Chris@3
|
473
|
Chris@3
|
474 RealTime endTime = timestamp + RealTime::frame2RealTime
|
Chris@31
|
475 (m_stepSize, m_inputSampleRate);
|
Chris@3
|
476
|
Chris@3
|
477 for (int i = 0; i < (int)m_instants.size(); ++i) {
|
Chris@5
|
478
|
Chris@31
|
479 if (m_instants[i] >= timestamp && (final || m_instants[i] < endTime)) {
|
Chris@31
|
480 fs[m_outputNumbers["instants"]]
|
Chris@31
|
481 .push_back(instant(m_instants[i], i, m_instants.size()));
|
Chris@31
|
482 }
|
Chris@4
|
483
|
Chris@31
|
484 RealTime variCurveTime = m_instants[i] / 2;
|
Chris@31
|
485 if (variCurveTime >= timestamp && (final || variCurveTime < endTime)) {
|
Chris@31
|
486 fs[m_outputNumbers["curve-vsr"]]
|
Chris@31
|
487 .push_back(timedCurveValue(variCurveTime, i, m_instants.size()));
|
Chris@31
|
488 }
|
Chris@5
|
489
|
Chris@31
|
490 RealTime noteTime = (m_instants[i] + m_instants[i]) / 3;
|
Chris@31
|
491 RealTime noteDuration = RealTime::fromSeconds((i % 2 == 0) ? 1.75 : 0.5);
|
Chris@5
|
492
|
Chris@31
|
493 if (noteTime >= timestamp && (final || noteTime < endTime)) {
|
Chris@31
|
494 fs[m_outputNumbers["notes-regions"]]
|
Chris@31
|
495 .push_back(noteOrRegion(noteTime, noteDuration, i, m_instants.size()));
|
Chris@31
|
496 }
|
Chris@3
|
497 }
|
Chris@3
|
498
|
Chris@5
|
499 if (!final) {
|
Chris@3
|
500
|
Chris@31
|
501 if (m_n < 20) {
|
Chris@31
|
502 fs[m_outputNumbers["curve-oss"]]
|
Chris@31
|
503 .push_back(untimedCurveValue(timestamp, m_n, 20));
|
Chris@31
|
504 }
|
Chris@3
|
505
|
Chris@31
|
506 if (m_n < 5) {
|
Chris@31
|
507 fs[m_outputNumbers["curve-fsr"]]
|
Chris@31
|
508 .push_back(untimedCurveValue(RealTime::fromSeconds(m_n / 2.5), m_n, 10));
|
Chris@6
|
509
|
Chris@31
|
510 float s = (m_n / 4) * 2;
|
Chris@31
|
511 if ((m_n % 4) > 0) {
|
Chris@31
|
512 s += float((m_n % 4) - 1) / 6.0;
|
Chris@31
|
513 }
|
Chris@31
|
514 fs[m_outputNumbers["curve-fsr-timed"]]
|
Chris@31
|
515 .push_back(snappedCurveValue(RealTime::fromSeconds(s),
|
Chris@31
|
516 RealTime::fromSeconds(snap(s, 0.4)),
|
Chris@31
|
517 m_n, 10));
|
Chris@31
|
518 }
|
Chris@5
|
519
|
Chris@31
|
520 if (m_n < 20) {
|
Chris@31
|
521 fs[m_outputNumbers["grid-oss"]]
|
Chris@31
|
522 .push_back(gridColumn(timestamp, m_n, 20));
|
Chris@31
|
523 }
|
Chris@5
|
524
|
Chris@5
|
525 } else {
|
Chris@5
|
526
|
Chris@31
|
527 for (int i = (m_n > 5 ? 5 : m_n); i < 10; ++i) {
|
Chris@31
|
528 fs[m_outputNumbers["curve-fsr"]]
|
Chris@31
|
529 .push_back(untimedCurveValue(RealTime::fromSeconds(i / 2.5), i, 10));
|
Chris@7
|
530
|
Chris@31
|
531 float s = (i / 4) * 2;
|
Chris@31
|
532 if ((i % 4) > 0) {
|
Chris@31
|
533 s += float((i % 4) - 1) / 6.0;
|
Chris@31
|
534 }
|
Chris@31
|
535 fs[m_outputNumbers["curve-fsr-timed"]]
|
Chris@31
|
536 .push_back(snappedCurveValue(RealTime::fromSeconds(s),
|
Chris@31
|
537 RealTime::fromSeconds(snap(s, 0.4)),
|
Chris@31
|
538 i, 10));
|
Chris@31
|
539 }
|
Chris@32
|
540
|
Chris@32
|
541 for (int i = 0; i < 10; ++i) {
|
Chris@32
|
542 static std::vector<float> times {
|
Chris@33
|
543 2.4, 2.9, 3.14, 3.5, 4.0, 4.4, 3.9, 4.4, 4.8, 5
|
Chris@32
|
544 };
|
Chris@32
|
545 float s = times[i];
|
Chris@32
|
546 float sn = snap(s, 0.4) + 1e-5; // to avoid printing e.g. 2.799
|
Chris@33
|
547 if (i == 4 || i == 5 || i == 8) {
|
Chris@32
|
548 fs[m_outputNumbers["curve-fsr-mixed"]]
|
Chris@32
|
549 .push_back(untimedCurveValue(RealTime::fromSeconds(s),
|
Chris@32
|
550 i, 10));
|
Chris@32
|
551 } else {
|
Chris@32
|
552 fs[m_outputNumbers["curve-fsr-mixed"]]
|
Chris@32
|
553 .push_back(snappedCurveValue(RealTime::fromSeconds(s),
|
Chris@32
|
554 RealTime::fromSeconds(sn),
|
Chris@32
|
555 i, 10));
|
Chris@32
|
556 }
|
Chris@32
|
557 }
|
Chris@31
|
558
|
Chris@31
|
559 for (int i = 0; i < 10; ++i) {
|
Chris@31
|
560 fs[m_outputNumbers["grid-fsr"]]
|
Chris@31
|
561 .push_back(gridColumn(RealTime::fromSeconds(i / 2.5), i, 10));
|
Chris@31
|
562 }
|
Chris@4
|
563 }
|
Chris@4
|
564
|
Chris@3
|
565 m_lastTime = endTime;
|
Chris@3
|
566 m_n = m_n + 1;
|
Chris@3
|
567 return fs;
|
Chris@5
|
568 }
|
Chris@5
|
569
|
Chris@5
|
570 VampTestPlugin::FeatureSet
|
Chris@5
|
571 VampTestPlugin::process(const float *const *inputBuffers, RealTime timestamp)
|
Chris@5
|
572 {
|
Chris@17
|
573 if (!m_produceOutput) return FeatureSet();
|
Chris@5
|
574 FeatureSet fs = featuresFrom(timestamp, false);
|
Chris@22
|
575
|
Chris@22
|
576 Feature f;
|
Chris@22
|
577 float eps = 1e-6f;
|
Chris@18
|
578
|
Chris@18
|
579 for (int c = 0; c < m_channels; ++c) {
|
Chris@31
|
580 if (!m_frequencyDomain) {
|
Chris@31
|
581 // first value plus number of non-zero values
|
Chris@31
|
582 float sum = inputBuffers[c][0];
|
Chris@31
|
583 for (int i = 0; i < m_blockSize; ++i) {
|
Chris@31
|
584 if (fabsf(inputBuffers[c][i]) >= eps) sum += 1;
|
Chris@31
|
585 }
|
Chris@31
|
586 f.values.push_back(sum);
|
Chris@31
|
587 } else {
|
Chris@31
|
588 // If we're in frequency-domain mode, we convert back to
|
Chris@31
|
589 // time-domain to calculate the input-summary feature
|
Chris@31
|
590 // output. That should help the caller check that
|
Chris@31
|
591 // time-frequency conversion has gone more or less OK,
|
Chris@31
|
592 // though they'll still have to bear in mind windowing and
|
Chris@31
|
593 // FFT shift (i.e. phase shift which puts the first
|
Chris@31
|
594 // element in the middle of the frame)
|
Chris@31
|
595 vector<double> ri(m_blockSize, 0.0);
|
Chris@31
|
596 vector<double> ii(m_blockSize, 0.0);
|
Chris@31
|
597 vector<double> ro(m_blockSize, 0.0);
|
Chris@31
|
598 vector<double> io(m_blockSize, 0.0);
|
Chris@31
|
599 for (int i = 0; i <= m_blockSize/2; ++i) {
|
Chris@31
|
600 ri[i] = inputBuffers[c][i*2];
|
Chris@31
|
601 ii[i] = inputBuffers[c][i*2 + 1];
|
Chris@31
|
602 if (i > 0) ri[m_blockSize-i] = ri[i];
|
Chris@31
|
603 if (i > 0) ii[m_blockSize-i] = -ii[i];
|
Chris@31
|
604 }
|
Chris@31
|
605 Vamp::FFT::inverse(m_blockSize, &ri[0], &ii[0], &ro[0], &io[0]);
|
Chris@31
|
606 float sum = 0;
|
Chris@31
|
607 for (int i = 0; i < m_blockSize; ++i) {
|
Chris@31
|
608 if (fabs(ro[i]) >= eps) sum += 1;
|
Chris@31
|
609 }
|
Chris@31
|
610 sum += ro[0];
|
Chris@31
|
611 f.values.push_back(sum);
|
Chris@31
|
612 }
|
Chris@18
|
613 }
|
Chris@22
|
614
|
Chris@19
|
615 fs[m_outputNumbers["input-summary"]].push_back(f);
|
Chris@20
|
616
|
Chris@20
|
617 f.values.clear();
|
Chris@22
|
618 float frame = RealTime::realTime2Frame(timestamp, m_inputSampleRate);
|
Chris@22
|
619 f.values.push_back(frame);
|
Chris@20
|
620 fs[m_outputNumbers["input-timestamp"]].push_back(f);
|
Chris@18
|
621
|
Chris@5
|
622 return fs;
|
Chris@0
|
623 }
|
Chris@0
|
624
|
Chris@0
|
625 VampTestPlugin::FeatureSet
|
Chris@0
|
626 VampTestPlugin::getRemainingFeatures()
|
Chris@0
|
627 {
|
Chris@17
|
628 if (!m_produceOutput) return FeatureSet();
|
Chris@5
|
629 FeatureSet fs = featuresFrom(m_lastTime, true);
|
Chris@3
|
630 return fs;
|
Chris@0
|
631 }
|
Chris@0
|
632
|