Chris@0
|
1
|
Chris@0
|
2
|
Chris@0
|
3 #include "VampTestPlugin.h"
|
Chris@0
|
4
|
Chris@22
|
5 #include <vamp-sdk/FFT.h>
|
Chris@22
|
6
|
Chris@19
|
7 #include <iostream>
|
Chris@3
|
8 #include <sstream>
|
Chris@18
|
9 #include <cmath>
|
Chris@3
|
10
|
Chris@19
|
11 using namespace std;
|
Chris@3
|
12
|
Chris@3
|
13 using Vamp::RealTime;
|
Chris@0
|
14
|
Chris@20
|
15 VampTestPlugin::VampTestPlugin(float inputSampleRate, bool freq) :
|
Chris@3
|
16 Plugin(inputSampleRate),
|
Chris@20
|
17 m_frequencyDomain(freq),
|
Chris@17
|
18 m_produceOutput(true),
|
Chris@3
|
19 m_n(0),
|
Chris@18
|
20 m_channels(1),
|
Chris@3
|
21 m_stepSize(0),
|
Chris@3
|
22 m_blockSize(0)
|
Chris@0
|
23 {
|
Chris@3
|
24 for (int i = 0; i < 10; ++i) {
|
Chris@3
|
25 m_instants.push_back(RealTime::fromSeconds(1.5 * i));
|
Chris@3
|
26 }
|
Chris@0
|
27 }
|
Chris@0
|
28
|
Chris@0
|
29 VampTestPlugin::~VampTestPlugin()
|
Chris@0
|
30 {
|
Chris@0
|
31 }
|
Chris@0
|
32
|
Chris@0
|
33 string
|
Chris@0
|
34 VampTestPlugin::getIdentifier() const
|
Chris@0
|
35 {
|
Chris@20
|
36 if (m_frequencyDomain) {
|
Chris@20
|
37 return "vamp-test-plugin-freq";
|
Chris@20
|
38 } else {
|
Chris@20
|
39 return "vamp-test-plugin";
|
Chris@20
|
40 }
|
Chris@0
|
41 }
|
Chris@0
|
42
|
Chris@0
|
43 string
|
Chris@0
|
44 VampTestPlugin::getName() const
|
Chris@0
|
45 {
|
Chris@20
|
46 if (m_frequencyDomain) {
|
Chris@20
|
47 return "Vamp Test Plugin (Frequency-Domain Input)";
|
Chris@20
|
48 } else {
|
Chris@20
|
49 return "Vamp Test Plugin";
|
Chris@20
|
50 }
|
Chris@0
|
51 }
|
Chris@0
|
52
|
Chris@0
|
53 string
|
Chris@0
|
54 VampTestPlugin::getDescription() const
|
Chris@0
|
55 {
|
Chris@0
|
56 return "Test plugin for hosts handling various output types";
|
Chris@0
|
57 }
|
Chris@0
|
58
|
Chris@0
|
59 string
|
Chris@0
|
60 VampTestPlugin::getMaker() const
|
Chris@0
|
61 {
|
Chris@0
|
62 return "Chris Cannam";
|
Chris@0
|
63 }
|
Chris@0
|
64
|
Chris@0
|
65 int
|
Chris@0
|
66 VampTestPlugin::getPluginVersion() const
|
Chris@0
|
67 {
|
Chris@20
|
68 return 3;
|
Chris@0
|
69 }
|
Chris@0
|
70
|
Chris@0
|
71 string
|
Chris@0
|
72 VampTestPlugin::getCopyright() const
|
Chris@0
|
73 {
|
Chris@0
|
74 return "BSD";
|
Chris@0
|
75 }
|
Chris@0
|
76
|
Chris@0
|
77 VampTestPlugin::InputDomain
|
Chris@0
|
78 VampTestPlugin::getInputDomain() const
|
Chris@0
|
79 {
|
Chris@20
|
80 return m_frequencyDomain ? FrequencyDomain : TimeDomain;
|
Chris@0
|
81 }
|
Chris@0
|
82
|
Chris@0
|
83 size_t
|
Chris@0
|
84 VampTestPlugin::getPreferredBlockSize() const
|
Chris@0
|
85 {
|
Chris@0
|
86 return 0;
|
Chris@0
|
87 }
|
Chris@0
|
88
|
Chris@0
|
89 size_t
|
Chris@0
|
90 VampTestPlugin::getPreferredStepSize() const
|
Chris@0
|
91 {
|
Chris@0
|
92 return 0;
|
Chris@0
|
93 }
|
Chris@0
|
94
|
Chris@0
|
95 size_t
|
Chris@0
|
96 VampTestPlugin::getMinChannelCount() const
|
Chris@0
|
97 {
|
Chris@0
|
98 return 1;
|
Chris@0
|
99 }
|
Chris@0
|
100
|
Chris@0
|
101 size_t
|
Chris@0
|
102 VampTestPlugin::getMaxChannelCount() const
|
Chris@0
|
103 {
|
Chris@18
|
104 return 10;
|
Chris@0
|
105 }
|
Chris@0
|
106
|
Chris@0
|
107 VampTestPlugin::ParameterList
|
Chris@0
|
108 VampTestPlugin::getParameterDescriptors() const
|
Chris@0
|
109 {
|
Chris@0
|
110 ParameterList list;
|
Chris@17
|
111
|
Chris@17
|
112 // Provide one parameter, and make it so that we can easily tell
|
Chris@17
|
113 // whether it has been changed
|
Chris@17
|
114 ParameterDescriptor d;
|
Chris@17
|
115 d.identifier = "produce_output";
|
Chris@17
|
116 d.name = "Produce some output";
|
Chris@17
|
117 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
|
118 d.unit = "";
|
Chris@17
|
119 d.minValue = 0;
|
Chris@17
|
120 d.maxValue = 1;
|
Chris@17
|
121 d.defaultValue = 1;
|
Chris@17
|
122 d.isQuantized = true;
|
Chris@17
|
123 d.quantizeStep = 1;
|
Chris@17
|
124 list.push_back(d);
|
Chris@17
|
125
|
Chris@0
|
126 return list;
|
Chris@0
|
127 }
|
Chris@0
|
128
|
Chris@0
|
129 float
|
Chris@0
|
130 VampTestPlugin::getParameter(string identifier) const
|
Chris@0
|
131 {
|
Chris@17
|
132 if (identifier == "produce_output") {
|
Chris@17
|
133 return m_produceOutput ? 1.f : 0.f;
|
Chris@17
|
134 }
|
Chris@0
|
135 return 0;
|
Chris@0
|
136 }
|
Chris@0
|
137
|
Chris@0
|
138 void
|
Chris@0
|
139 VampTestPlugin::setParameter(string identifier, float value)
|
Chris@0
|
140 {
|
Chris@17
|
141 if (identifier == "produce_output") {
|
Chris@17
|
142 m_produceOutput = (value > 0.5);
|
Chris@17
|
143 }
|
Chris@0
|
144 }
|
Chris@0
|
145
|
Chris@0
|
146 VampTestPlugin::ProgramList
|
Chris@0
|
147 VampTestPlugin::getPrograms() const
|
Chris@0
|
148 {
|
Chris@0
|
149 ProgramList list;
|
Chris@0
|
150 return list;
|
Chris@0
|
151 }
|
Chris@0
|
152
|
Chris@0
|
153 string
|
Chris@0
|
154 VampTestPlugin::getCurrentProgram() const
|
Chris@0
|
155 {
|
Chris@0
|
156 return ""; // no programs
|
Chris@0
|
157 }
|
Chris@0
|
158
|
Chris@0
|
159 void
|
Chris@23
|
160 VampTestPlugin::selectProgram(string)
|
Chris@0
|
161 {
|
Chris@0
|
162 }
|
Chris@0
|
163
|
Chris@0
|
164 VampTestPlugin::OutputList
|
Chris@0
|
165 VampTestPlugin::getOutputDescriptors() const
|
Chris@0
|
166 {
|
Chris@0
|
167 OutputList list;
|
Chris@0
|
168
|
Chris@7
|
169 int n = 0;
|
Chris@7
|
170
|
Chris@0
|
171 OutputDescriptor d;
|
Chris@1
|
172
|
Chris@1
|
173 d.identifier = "instants";
|
Chris@1
|
174 d.name = "Instants";
|
Chris@2
|
175 d.description = "Single time points without values";
|
Chris@1
|
176 d.unit = "";
|
Chris@1
|
177 d.hasFixedBinCount = true;
|
Chris@1
|
178 d.binCount = 0;
|
Chris@1
|
179 d.hasKnownExtents = false;
|
Chris@1
|
180 d.isQuantized = false;
|
Chris@1
|
181 d.sampleType = OutputDescriptor::VariableSampleRate;
|
Chris@1
|
182 d.hasDuration = false;
|
Chris@7
|
183 m_outputNumbers[d.identifier] = n++;
|
Chris@1
|
184 list.push_back(d);
|
Chris@1
|
185
|
Chris@1
|
186 d.identifier = "curve-oss";
|
Chris@1
|
187 d.name = "Curve: OneSamplePerStep";
|
Chris@2
|
188 d.description = "A time series with one value per process block";
|
Chris@0
|
189 d.unit = "";
|
Chris@0
|
190 d.hasFixedBinCount = true;
|
Chris@0
|
191 d.binCount = 1;
|
Chris@0
|
192 d.hasKnownExtents = false;
|
Chris@0
|
193 d.isQuantized = false;
|
Chris@0
|
194 d.sampleType = OutputDescriptor::OneSamplePerStep;
|
Chris@0
|
195 d.hasDuration = false;
|
Chris@7
|
196 m_outputNumbers[d.identifier] = n++;
|
Chris@0
|
197 list.push_back(d);
|
Chris@0
|
198
|
Chris@1
|
199 d.identifier = "curve-fsr";
|
Chris@1
|
200 d.name = "Curve: FixedSampleRate";
|
Chris@2
|
201 d.description = "A time series with equally-spaced values (independent of process step size)";
|
Chris@1
|
202 d.unit = "";
|
Chris@1
|
203 d.hasFixedBinCount = true;
|
Chris@1
|
204 d.binCount = 1;
|
Chris@1
|
205 d.hasKnownExtents = false;
|
Chris@1
|
206 d.isQuantized = false;
|
Chris@1
|
207 d.sampleType = OutputDescriptor::FixedSampleRate;
|
Chris@8
|
208 d.sampleRate = 2.5;
|
Chris@1
|
209 d.hasDuration = false;
|
Chris@7
|
210 m_outputNumbers[d.identifier] = n++;
|
Chris@1
|
211 list.push_back(d);
|
Chris@1
|
212
|
Chris@7
|
213 d.identifier = "curve-fsr-timed";
|
Chris@7
|
214 d.name = "Curve: FixedSampleRate/Timed";
|
Chris@7
|
215 d.description = "A time series with a fixed sample rate (independent of process step size) but with timestamps on features";
|
Chris@7
|
216 d.unit = "";
|
Chris@7
|
217 d.hasFixedBinCount = true;
|
Chris@7
|
218 d.binCount = 1;
|
Chris@7
|
219 d.hasKnownExtents = false;
|
Chris@7
|
220 d.isQuantized = false;
|
Chris@7
|
221 d.sampleType = OutputDescriptor::FixedSampleRate;
|
Chris@8
|
222 d.sampleRate = 2.5;
|
Chris@7
|
223 d.hasDuration = false;
|
Chris@7
|
224 m_outputNumbers[d.identifier] = n++;
|
Chris@7
|
225 list.push_back(d);
|
Chris@7
|
226
|
Chris@1
|
227 d.identifier = "curve-vsr";
|
Chris@1
|
228 d.name = "Curve: VariableSampleRate";
|
Chris@2
|
229 d.description = "A variably-spaced series of values";
|
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::VariableSampleRate;
|
Chris@2
|
236 d.sampleRate = 0;
|
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@2
|
241 d.identifier = "grid-oss";
|
Chris@2
|
242 d.name = "Grid: OneSamplePerStep";
|
Chris@2
|
243 d.description = "A fixed-height grid of values with one column per process block";
|
Chris@2
|
244 d.unit = "";
|
Chris@2
|
245 d.hasFixedBinCount = true;
|
Chris@4
|
246 d.binCount = 10;
|
Chris@2
|
247 d.hasKnownExtents = false;
|
Chris@2
|
248 d.isQuantized = false;
|
Chris@4
|
249 d.sampleType = OutputDescriptor::OneSamplePerStep;
|
Chris@2
|
250 d.sampleRate = 0;
|
Chris@2
|
251 d.hasDuration = false;
|
Chris@7
|
252 m_outputNumbers[d.identifier] = n++;
|
Chris@2
|
253 list.push_back(d);
|
Chris@2
|
254
|
Chris@2
|
255 d.identifier = "grid-fsr";
|
Chris@2
|
256 d.name = "Grid: FixedSampleRate";
|
Chris@2
|
257 d.description = "A fixed-height grid of values with equally-spaced columns (independent of process step size)";
|
Chris@2
|
258 d.unit = "";
|
Chris@2
|
259 d.hasFixedBinCount = true;
|
Chris@4
|
260 d.binCount = 10;
|
Chris@2
|
261 d.hasKnownExtents = false;
|
Chris@2
|
262 d.isQuantized = false;
|
Chris@4
|
263 d.sampleType = OutputDescriptor::FixedSampleRate;
|
Chris@8
|
264 d.sampleRate = 2.5;
|
Chris@2
|
265 d.hasDuration = false;
|
Chris@7
|
266 m_outputNumbers[d.identifier] = n++;
|
Chris@2
|
267 list.push_back(d);
|
Chris@2
|
268
|
Chris@5
|
269 d.identifier = "notes-regions";
|
Chris@5
|
270 d.name = "Notes or Regions";
|
Chris@5
|
271 d.description = "Variably-spaced features with one value and duration";
|
Chris@5
|
272 d.unit = "";
|
Chris@5
|
273 d.hasFixedBinCount = true;
|
Chris@5
|
274 d.binCount = 1;
|
Chris@5
|
275 d.hasKnownExtents = false;
|
Chris@5
|
276 d.isQuantized = false;
|
Chris@5
|
277 d.sampleType = OutputDescriptor::VariableSampleRate;
|
Chris@5
|
278 d.sampleRate = 0;
|
Chris@5
|
279 d.hasDuration = true;
|
Chris@7
|
280 m_outputNumbers[d.identifier] = n++;
|
Chris@5
|
281 list.push_back(d);
|
Chris@2
|
282
|
Chris@19
|
283 d.identifier = "input-summary";
|
Chris@19
|
284 d.name = "Data derived from inputs";
|
Chris@22
|
285 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
|
286 d.unit = "";
|
Chris@18
|
287 d.hasFixedBinCount = true;
|
Chris@18
|
288 d.binCount = m_channels;
|
Chris@18
|
289 d.hasKnownExtents = false;
|
Chris@18
|
290 d.isQuantized = false;
|
Chris@18
|
291 d.sampleType = OutputDescriptor::OneSamplePerStep;
|
Chris@18
|
292 d.hasDuration = false;
|
Chris@18
|
293 m_outputNumbers[d.identifier] = n++;
|
Chris@18
|
294 list.push_back(d);
|
Chris@18
|
295
|
Chris@20
|
296 d.identifier = "input-timestamp";
|
Chris@20
|
297 d.name = "Input timestamp";
|
Chris@21
|
298 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
|
299 d.unit = "samples";
|
Chris@20
|
300 d.hasFixedBinCount = true;
|
Chris@20
|
301 d.binCount = 1;
|
Chris@20
|
302 d.hasKnownExtents = false;
|
Chris@20
|
303 d.isQuantized = false;
|
Chris@20
|
304 d.sampleType = OutputDescriptor::OneSamplePerStep;
|
Chris@20
|
305 d.hasDuration = false;
|
Chris@20
|
306 m_outputNumbers[d.identifier] = n++;
|
Chris@20
|
307 list.push_back(d);
|
Chris@20
|
308
|
Chris@0
|
309 return list;
|
Chris@0
|
310 }
|
Chris@0
|
311
|
Chris@0
|
312 bool
|
Chris@0
|
313 VampTestPlugin::initialise(size_t channels, size_t stepSize, size_t blockSize)
|
Chris@0
|
314 {
|
Chris@0
|
315 if (channels < getMinChannelCount() ||
|
Chris@0
|
316 channels > getMaxChannelCount()) return false;
|
Chris@0
|
317
|
Chris@18
|
318 m_channels = channels;
|
Chris@3
|
319 m_stepSize = stepSize;
|
Chris@3
|
320 m_blockSize = blockSize;
|
Chris@0
|
321
|
Chris@0
|
322 return true;
|
Chris@0
|
323 }
|
Chris@0
|
324
|
Chris@0
|
325 void
|
Chris@0
|
326 VampTestPlugin::reset()
|
Chris@0
|
327 {
|
Chris@3
|
328 m_n = 0;
|
Chris@3
|
329 }
|
Chris@3
|
330
|
Chris@3
|
331 static Vamp::Plugin::Feature
|
Chris@3
|
332 instant(RealTime r, int i, int n)
|
Chris@3
|
333 {
|
Chris@19
|
334 stringstream s;
|
Chris@3
|
335 Vamp::Plugin::Feature f;
|
Chris@3
|
336 f.hasTimestamp = true;
|
Chris@3
|
337 f.timestamp = r;
|
Chris@3
|
338 f.hasDuration = false;
|
Chris@3
|
339 s << i+1 << " of " << n << " at " << r.toText();
|
Chris@3
|
340 f.label = s.str();
|
Chris@3
|
341 return f;
|
Chris@3
|
342 }
|
Chris@3
|
343
|
Chris@3
|
344 static Vamp::Plugin::Feature
|
Chris@3
|
345 untimedCurveValue(RealTime r, int i, int n)
|
Chris@3
|
346 {
|
Chris@19
|
347 stringstream s;
|
Chris@3
|
348 Vamp::Plugin::Feature f;
|
Chris@3
|
349 f.hasTimestamp = false;
|
Chris@3
|
350 f.hasDuration = false;
|
Chris@3
|
351 float v = float(i) / float(n);
|
Chris@3
|
352 f.values.push_back(v);
|
Chris@3
|
353 s << i+1 << " of " << n << ": " << v << " at " << r.toText();
|
Chris@3
|
354 f.label = s.str();
|
Chris@3
|
355 return f;
|
Chris@0
|
356 }
|
Chris@0
|
357
|
Chris@4
|
358 static Vamp::Plugin::Feature
|
Chris@4
|
359 timedCurveValue(RealTime r, int i, int n)
|
Chris@4
|
360 {
|
Chris@19
|
361 stringstream s;
|
Chris@4
|
362 Vamp::Plugin::Feature f;
|
Chris@4
|
363 f.hasTimestamp = true;
|
Chris@4
|
364 f.timestamp = r;
|
Chris@4
|
365 f.hasDuration = false;
|
Chris@4
|
366 float v = float(i) / float(n);
|
Chris@4
|
367 f.values.push_back(v);
|
Chris@4
|
368 s << i+1 << " of " << n << ": " << v << " at " << r.toText();
|
Chris@4
|
369 f.label = s.str();
|
Chris@4
|
370 return f;
|
Chris@4
|
371 }
|
Chris@4
|
372
|
Chris@4
|
373 static Vamp::Plugin::Feature
|
Chris@7
|
374 snappedCurveValue(RealTime r, RealTime sn, int i, int n)
|
Chris@7
|
375 {
|
Chris@19
|
376 stringstream s;
|
Chris@7
|
377 Vamp::Plugin::Feature f;
|
Chris@7
|
378 f.hasTimestamp = true;
|
Chris@7
|
379 f.timestamp = r;
|
Chris@7
|
380 f.hasDuration = false;
|
Chris@7
|
381 float v = float(i) / float(n);
|
Chris@7
|
382 f.values.push_back(v);
|
Chris@7
|
383 s << i+1 << " of " << n << ": " << v << " at " << r.toText() << " snap to " << sn.toText();
|
Chris@7
|
384 f.label = s.str();
|
Chris@7
|
385 return f;
|
Chris@7
|
386 }
|
Chris@7
|
387
|
Chris@7
|
388 static Vamp::Plugin::Feature
|
Chris@4
|
389 gridColumn(RealTime r, int i, int n)
|
Chris@4
|
390 {
|
Chris@19
|
391 stringstream s;
|
Chris@4
|
392 Vamp::Plugin::Feature f;
|
Chris@4
|
393 f.hasTimestamp = false;
|
Chris@4
|
394 f.hasDuration = false;
|
Chris@4
|
395 for (int j = 0; j < 10; ++j) {
|
Chris@4
|
396 float v = float(j + i + 2) / float(n + 10);
|
Chris@4
|
397 f.values.push_back(v);
|
Chris@4
|
398 }
|
Chris@4
|
399 s << i+1 << " of " << n << " at " << r.toText();
|
Chris@4
|
400 f.label = s.str();
|
Chris@4
|
401 return f;
|
Chris@4
|
402 }
|
Chris@4
|
403
|
Chris@5
|
404 static Vamp::Plugin::Feature
|
Chris@5
|
405 noteOrRegion(RealTime r, RealTime d, int i, int n)
|
Chris@5
|
406 {
|
Chris@19
|
407 stringstream s;
|
Chris@5
|
408 Vamp::Plugin::Feature f;
|
Chris@5
|
409 f.hasTimestamp = true;
|
Chris@5
|
410 f.timestamp = r;
|
Chris@5
|
411 f.hasDuration = true;
|
Chris@5
|
412 f.duration = d;
|
Chris@5
|
413 float v = float(i) / float(n);
|
Chris@5
|
414 f.values.push_back(v);
|
Chris@5
|
415 s << i+1 << " of " << n << ": " << v << " at " << r.toText() << " dur. " << d.toText();
|
Chris@5
|
416 f.label = s.str();
|
Chris@5
|
417 return f;
|
Chris@5
|
418 }
|
Chris@5
|
419
|
Chris@7
|
420 static
|
Chris@7
|
421 float snap(float x, float r)
|
Chris@7
|
422 {
|
Chris@7
|
423 int n = int(x / r + 0.5);
|
Chris@7
|
424 return n * r;
|
Chris@7
|
425 }
|
Chris@7
|
426
|
Chris@5
|
427 Vamp::Plugin::FeatureSet
|
Chris@5
|
428 VampTestPlugin::featuresFrom(RealTime timestamp, bool final)
|
Chris@0
|
429 {
|
Chris@3
|
430 FeatureSet fs;
|
Chris@3
|
431
|
Chris@3
|
432 RealTime endTime = timestamp + RealTime::frame2RealTime
|
Chris@3
|
433 (m_stepSize, m_inputSampleRate);
|
Chris@3
|
434
|
Chris@3
|
435 for (int i = 0; i < (int)m_instants.size(); ++i) {
|
Chris@5
|
436
|
Chris@5
|
437 if (m_instants[i] >= timestamp && (final || m_instants[i] < endTime)) {
|
Chris@7
|
438 fs[m_outputNumbers["instants"]]
|
Chris@7
|
439 .push_back(instant(m_instants[i], i, m_instants.size()));
|
Chris@3
|
440 }
|
Chris@4
|
441
|
Chris@4
|
442 RealTime variCurveTime = m_instants[i] / 2;
|
Chris@5
|
443 if (variCurveTime >= timestamp && (final || variCurveTime < endTime)) {
|
Chris@7
|
444 fs[m_outputNumbers["curve-vsr"]]
|
Chris@7
|
445 .push_back(timedCurveValue(variCurveTime, i, m_instants.size()));
|
Chris@4
|
446 }
|
Chris@5
|
447
|
Chris@5
|
448 RealTime noteTime = (m_instants[i] + m_instants[i]) / 3;
|
Chris@5
|
449 RealTime noteDuration = RealTime::fromSeconds((i % 2 == 0) ? 1.75 : 0.5);
|
Chris@5
|
450
|
Chris@5
|
451 if (noteTime >= timestamp && (final || noteTime < endTime)) {
|
Chris@7
|
452 fs[m_outputNumbers["notes-regions"]]
|
Chris@7
|
453 .push_back(noteOrRegion(noteTime, noteDuration, i, m_instants.size()));
|
Chris@5
|
454 }
|
Chris@3
|
455 }
|
Chris@3
|
456
|
Chris@5
|
457 if (!final) {
|
Chris@3
|
458
|
Chris@5
|
459 if (m_n < 20) {
|
Chris@7
|
460 fs[m_outputNumbers["curve-oss"]]
|
Chris@7
|
461 .push_back(untimedCurveValue(timestamp, m_n, 20));
|
Chris@5
|
462 }
|
Chris@3
|
463
|
Chris@5
|
464 if (m_n < 5) {
|
Chris@7
|
465 fs[m_outputNumbers["curve-fsr"]]
|
Chris@8
|
466 .push_back(untimedCurveValue(RealTime::fromSeconds(m_n / 2.5), m_n, 10));
|
Chris@6
|
467
|
Chris@7
|
468 float s = (m_n / 4) * 2;
|
Chris@7
|
469 if ((m_n % 4) > 0) {
|
Chris@7
|
470 s += float((m_n % 4) - 1) / 6.0;
|
Chris@7
|
471 }
|
Chris@7
|
472 fs[m_outputNumbers["curve-fsr-timed"]]
|
Chris@7
|
473 .push_back(snappedCurveValue(RealTime::fromSeconds(s),
|
Chris@8
|
474 RealTime::fromSeconds(snap(s, 0.4)),
|
Chris@7
|
475 m_n, 10));
|
Chris@5
|
476 }
|
Chris@5
|
477
|
Chris@5
|
478 if (m_n < 20) {
|
Chris@7
|
479 fs[m_outputNumbers["grid-oss"]]
|
Chris@7
|
480 .push_back(gridColumn(timestamp, m_n, 20));
|
Chris@5
|
481 }
|
Chris@5
|
482
|
Chris@5
|
483 } else {
|
Chris@5
|
484
|
Chris@5
|
485 for (int i = (m_n > 5 ? 5 : m_n); i < 10; ++i) {
|
Chris@7
|
486 fs[m_outputNumbers["curve-fsr"]]
|
Chris@8
|
487 .push_back(untimedCurveValue(RealTime::fromSeconds(i / 2.5), i, 10));
|
Chris@7
|
488
|
Chris@7
|
489 float s = (i / 4) * 2;
|
Chris@7
|
490 if ((i % 4) > 0) {
|
Chris@7
|
491 s += float((i % 4) - 1) / 6.0;
|
Chris@7
|
492 }
|
Chris@7
|
493 fs[m_outputNumbers["curve-fsr-timed"]]
|
Chris@7
|
494 .push_back(snappedCurveValue(RealTime::fromSeconds(s),
|
Chris@8
|
495 RealTime::fromSeconds(snap(s, 0.4)),
|
Chris@7
|
496 i, 10));
|
Chris@5
|
497 }
|
Chris@5
|
498
|
Chris@8
|
499 for (int i = 0; i < 10; ++i) {
|
Chris@7
|
500 fs[m_outputNumbers["grid-fsr"]]
|
Chris@9
|
501 .push_back(gridColumn(RealTime::fromSeconds(i / 2.5), i, 10));
|
Chris@5
|
502 }
|
Chris@4
|
503 }
|
Chris@4
|
504
|
Chris@3
|
505 m_lastTime = endTime;
|
Chris@3
|
506 m_n = m_n + 1;
|
Chris@3
|
507 return fs;
|
Chris@5
|
508 }
|
Chris@5
|
509
|
Chris@5
|
510 VampTestPlugin::FeatureSet
|
Chris@5
|
511 VampTestPlugin::process(const float *const *inputBuffers, RealTime timestamp)
|
Chris@5
|
512 {
|
Chris@17
|
513 if (!m_produceOutput) return FeatureSet();
|
Chris@5
|
514 FeatureSet fs = featuresFrom(timestamp, false);
|
Chris@22
|
515
|
Chris@22
|
516 Feature f;
|
Chris@22
|
517 float eps = 1e-6f;
|
Chris@18
|
518
|
Chris@18
|
519 for (int c = 0; c < m_channels; ++c) {
|
Chris@22
|
520 if (!m_frequencyDomain) {
|
Chris@22
|
521 // first value plus number of non-zero values
|
Chris@22
|
522 float sum = inputBuffers[c][0];
|
Chris@22
|
523 for (int i = 0; i < m_blockSize; ++i) {
|
Chris@22
|
524 if (fabsf(inputBuffers[c][i]) >= eps) sum += 1;
|
Chris@22
|
525 }
|
Chris@22
|
526 f.values.push_back(sum);
|
Chris@22
|
527 } else {
|
Chris@22
|
528 // If we're in frequency-domain mode, we convert back to
|
Chris@22
|
529 // time-domain to calculate the input-summary feature
|
Chris@22
|
530 // output. That should help the caller check that
|
Chris@22
|
531 // time-frequency conversion has gone more or less OK,
|
Chris@22
|
532 // though they'll still have to bear in mind windowing and
|
Chris@22
|
533 // FFT shift (i.e. phase shift which puts the first
|
Chris@22
|
534 // element in the middle of the frame)
|
Chris@22
|
535 vector<double> ri(m_blockSize, 0.0);
|
Chris@22
|
536 vector<double> ii(m_blockSize, 0.0);
|
Chris@22
|
537 vector<double> ro(m_blockSize, 0.0);
|
Chris@22
|
538 vector<double> io(m_blockSize, 0.0);
|
Chris@22
|
539 for (int i = 0; i <= m_blockSize/2; ++i) {
|
Chris@22
|
540 ri[i] = inputBuffers[c][i*2];
|
Chris@22
|
541 ii[i] = inputBuffers[c][i*2 + 1];
|
Chris@22
|
542 if (i > 0) ri[m_blockSize-i] = ri[i];
|
Chris@22
|
543 if (i > 0) ii[m_blockSize-i] = -ii[i];
|
Chris@22
|
544 }
|
Chris@22
|
545 Vamp::FFT::inverse(m_blockSize, &ri[0], &ii[0], &ro[0], &io[0]);
|
Chris@22
|
546 float sum = 0;
|
Chris@22
|
547 for (int i = 0; i < m_blockSize; ++i) {
|
Chris@22
|
548 if (fabsf(ro[i]) >= eps) sum += 1;
|
Chris@22
|
549 }
|
Chris@22
|
550 sum += ro[0];
|
Chris@22
|
551 f.values.push_back(sum);
|
Chris@22
|
552 }
|
Chris@18
|
553 }
|
Chris@22
|
554
|
Chris@19
|
555 fs[m_outputNumbers["input-summary"]].push_back(f);
|
Chris@20
|
556
|
Chris@20
|
557 f.values.clear();
|
Chris@22
|
558 float frame = RealTime::realTime2Frame(timestamp, m_inputSampleRate);
|
Chris@22
|
559 f.values.push_back(frame);
|
Chris@20
|
560 fs[m_outputNumbers["input-timestamp"]].push_back(f);
|
Chris@18
|
561
|
Chris@5
|
562 return fs;
|
Chris@0
|
563 }
|
Chris@0
|
564
|
Chris@0
|
565 VampTestPlugin::FeatureSet
|
Chris@0
|
566 VampTestPlugin::getRemainingFeatures()
|
Chris@0
|
567 {
|
Chris@17
|
568 if (!m_produceOutput) return FeatureSet();
|
Chris@5
|
569 FeatureSet fs = featuresFrom(m_lastTime, true);
|
Chris@3
|
570 return fs;
|
Chris@0
|
571 }
|
Chris@0
|
572
|