Mercurial > hg > sv-dependency-builds
comparison src/rubberband-1.8.1/vamp/RubberBandVampPlugin.cpp @ 10:37bf6b4a2645
Add FFTW3
author | Chris Cannam |
---|---|
date | Wed, 20 Mar 2013 15:35:50 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
9:c0fb53affa76 | 10:37bf6b4a2645 |
---|---|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ | |
2 | |
3 /* | |
4 Rubber Band Library | |
5 An audio time-stretching and pitch-shifting library. | |
6 Copyright 2007-2012 Particular Programs Ltd. | |
7 | |
8 This program is free software; you can redistribute it and/or | |
9 modify it under the terms of the GNU General Public License as | |
10 published by the Free Software Foundation; either version 2 of the | |
11 License, or (at your option) any later version. See the file | |
12 COPYING included with this distribution for more information. | |
13 | |
14 Alternatively, if you have a valid commercial licence for the | |
15 Rubber Band Library obtained by agreement with the copyright | |
16 holders, you may redistribute and/or modify it under the terms | |
17 described in that licence. | |
18 | |
19 If you wish to distribute code using the Rubber Band Library | |
20 under terms other than those of the GNU General Public License, | |
21 you must obtain a valid commercial licence before doing so. | |
22 */ | |
23 | |
24 #include "RubberBandVampPlugin.h" | |
25 | |
26 #include "StretchCalculator.h" | |
27 #include "system/sysutils.h" | |
28 | |
29 #include <cmath> | |
30 #include <cstdio> | |
31 | |
32 using std::string; | |
33 using std::vector; | |
34 using std::cerr; | |
35 using std::endl; | |
36 | |
37 class RubberBandVampPlugin::Impl | |
38 { | |
39 public: | |
40 size_t m_stepSize; | |
41 size_t m_blockSize; | |
42 size_t m_sampleRate; | |
43 | |
44 float m_timeRatio; | |
45 float m_pitchRatio; | |
46 | |
47 bool m_realtime; | |
48 bool m_elasticTiming; | |
49 int m_transientMode; | |
50 bool m_phaseIndependent; | |
51 int m_windowLength; | |
52 | |
53 RubberBand::RubberBandStretcher *m_stretcher; | |
54 | |
55 int m_incrementsOutput; | |
56 int m_aggregateIncrementsOutput; | |
57 int m_divergenceOutput; | |
58 int m_phaseResetDfOutput; | |
59 int m_smoothedPhaseResetDfOutput; | |
60 int m_phaseResetPointsOutput; | |
61 int m_timeSyncPointsOutput; | |
62 | |
63 size_t m_counter; | |
64 size_t m_accumulatedIncrement; | |
65 | |
66 float **m_outputDump; | |
67 | |
68 FeatureSet processOffline(const float *const *inputBuffers, | |
69 Vamp::RealTime timestamp); | |
70 | |
71 FeatureSet getRemainingFeaturesOffline(); | |
72 | |
73 FeatureSet processRealTime(const float *const *inputBuffers, | |
74 Vamp::RealTime timestamp); | |
75 | |
76 FeatureSet getRemainingFeaturesRealTime(); | |
77 | |
78 FeatureSet createFeatures(size_t inputIncrement, | |
79 std::vector<int> &outputIncrements, | |
80 std::vector<float> &phaseResetDf, | |
81 std::vector<int> &exactPoints, | |
82 std::vector<float> &smoothedDf, | |
83 size_t baseCount, | |
84 bool includeFinal); | |
85 }; | |
86 | |
87 | |
88 RubberBandVampPlugin::RubberBandVampPlugin(float inputSampleRate) : | |
89 Plugin(inputSampleRate) | |
90 { | |
91 m_d = new Impl(); | |
92 m_d->m_stepSize = 0; | |
93 m_d->m_timeRatio = 1.f; | |
94 m_d->m_pitchRatio = 1.f; | |
95 m_d->m_realtime = false; | |
96 m_d->m_elasticTiming = true; | |
97 m_d->m_transientMode = 0; | |
98 m_d->m_phaseIndependent = false; | |
99 m_d->m_windowLength = 0; | |
100 m_d->m_stretcher = 0; | |
101 m_d->m_sampleRate = lrintf(m_inputSampleRate); | |
102 } | |
103 | |
104 RubberBandVampPlugin::~RubberBandVampPlugin() | |
105 { | |
106 if (m_d->m_outputDump) { | |
107 for (size_t i = 0; i < m_d->m_stretcher->getChannelCount(); ++i) { | |
108 delete[] m_d->m_outputDump[i]; | |
109 } | |
110 delete[] m_d->m_outputDump; | |
111 } | |
112 delete m_d->m_stretcher; | |
113 delete m_d; | |
114 } | |
115 | |
116 string | |
117 RubberBandVampPlugin::getIdentifier() const | |
118 { | |
119 return "rubberband"; | |
120 } | |
121 | |
122 string | |
123 RubberBandVampPlugin::getName() const | |
124 { | |
125 return "Rubber Band Timestretch Analysis"; | |
126 } | |
127 | |
128 string | |
129 RubberBandVampPlugin::getDescription() const | |
130 { | |
131 return "Carry out analysis phases of time stretcher process"; | |
132 } | |
133 | |
134 string | |
135 RubberBandVampPlugin::getMaker() const | |
136 { | |
137 return "Breakfast Quay"; | |
138 } | |
139 | |
140 int | |
141 RubberBandVampPlugin::getPluginVersion() const | |
142 { | |
143 return 1; | |
144 } | |
145 | |
146 string | |
147 RubberBandVampPlugin::getCopyright() const | |
148 { | |
149 return "";//!!! | |
150 } | |
151 | |
152 RubberBandVampPlugin::OutputList | |
153 RubberBandVampPlugin::getOutputDescriptors() const | |
154 { | |
155 OutputList list; | |
156 | |
157 size_t rate = 0; | |
158 if (m_d->m_stretcher) { | |
159 rate = lrintf(m_inputSampleRate / m_d->m_stretcher->getInputIncrement()); | |
160 } | |
161 | |
162 OutputDescriptor d; | |
163 d.identifier = "increments"; | |
164 d.name = "Output Increments"; | |
165 d.description = "Output time increment for each input step"; | |
166 d.unit = "samples"; | |
167 d.hasFixedBinCount = true; | |
168 d.binCount = 1; | |
169 d.hasKnownExtents = false; | |
170 d.isQuantized = true; | |
171 d.quantizeStep = 1.0; | |
172 d.sampleType = OutputDescriptor::VariableSampleRate; | |
173 d.sampleRate = float(rate); | |
174 m_d->m_incrementsOutput = list.size(); | |
175 list.push_back(d); | |
176 | |
177 d.identifier = "aggregate_increments"; | |
178 d.name = "Accumulated Output Increments"; | |
179 d.description = "Accumulated output time increments"; | |
180 d.sampleRate = 0; | |
181 m_d->m_aggregateIncrementsOutput = list.size(); | |
182 list.push_back(d); | |
183 | |
184 d.identifier = "divergence"; | |
185 d.name = "Divergence from Linear"; | |
186 d.description = "Difference between actual output time and the output time for a theoretical linear stretch"; | |
187 d.isQuantized = false; | |
188 d.sampleRate = 0; | |
189 m_d->m_divergenceOutput = list.size(); | |
190 list.push_back(d); | |
191 | |
192 d.identifier = "phaseresetdf"; | |
193 d.name = "Phase Reset Detection Function"; | |
194 d.description = "Curve whose peaks are used to identify transients for phase reset points"; | |
195 d.unit = ""; | |
196 d.sampleRate = float(rate); | |
197 m_d->m_phaseResetDfOutput = list.size(); | |
198 list.push_back(d); | |
199 | |
200 d.identifier = "smoothedphaseresetdf"; | |
201 d.name = "Smoothed Phase Reset Detection Function"; | |
202 d.description = "Phase reset curve smoothed for peak picking"; | |
203 d.unit = ""; | |
204 m_d->m_smoothedPhaseResetDfOutput = list.size(); | |
205 list.push_back(d); | |
206 | |
207 d.identifier = "phaseresetpoints"; | |
208 d.name = "Phase Reset Points"; | |
209 d.description = "Points estimated as transients at which phase reset occurs"; | |
210 d.unit = ""; | |
211 d.hasFixedBinCount = true; | |
212 d.binCount = 0; | |
213 d.hasKnownExtents = false; | |
214 d.isQuantized = false; | |
215 d.sampleRate = 0; | |
216 m_d->m_phaseResetPointsOutput = list.size(); | |
217 list.push_back(d); | |
218 | |
219 d.identifier = "timesyncpoints"; | |
220 d.name = "Time Sync Points"; | |
221 d.description = "Salient points which stretcher aims to place with strictly correct timing"; | |
222 d.unit = ""; | |
223 d.hasFixedBinCount = true; | |
224 d.binCount = 0; | |
225 d.hasKnownExtents = false; | |
226 d.isQuantized = false; | |
227 d.sampleRate = 0; | |
228 m_d->m_timeSyncPointsOutput = list.size(); | |
229 list.push_back(d); | |
230 | |
231 return list; | |
232 } | |
233 | |
234 RubberBandVampPlugin::ParameterList | |
235 RubberBandVampPlugin::getParameterDescriptors() const | |
236 { | |
237 ParameterList list; | |
238 | |
239 ParameterDescriptor d; | |
240 d.identifier = "timeratio"; | |
241 d.name = "Time Ratio"; | |
242 d.description = "Ratio to modify overall duration by"; | |
243 d.unit = "%"; | |
244 d.minValue = 1; | |
245 d.maxValue = 500; | |
246 d.defaultValue = 100; | |
247 d.isQuantized = false; | |
248 list.push_back(d); | |
249 | |
250 d.identifier = "pitchratio"; | |
251 d.name = "Pitch Scale Ratio"; | |
252 d.description = "Frequency ratio to modify pitch by"; | |
253 d.unit = "%"; | |
254 d.minValue = 1; | |
255 d.maxValue = 500; | |
256 d.defaultValue = 100; | |
257 d.isQuantized = false; | |
258 list.push_back(d); | |
259 | |
260 d.identifier = "mode"; | |
261 d.name = "Processing Mode"; | |
262 d.description = ""; //!!! | |
263 d.unit = ""; | |
264 d.minValue = 0; | |
265 d.maxValue = 1; | |
266 d.defaultValue = 0; | |
267 d.isQuantized = true; | |
268 d.quantizeStep = 1; | |
269 d.valueNames.clear(); | |
270 d.valueNames.push_back("Offline"); | |
271 d.valueNames.push_back("Real Time"); | |
272 list.push_back(d); | |
273 | |
274 d.identifier = "stretchtype"; | |
275 d.name = "Stretch Flexibility"; | |
276 d.description = ""; //!!! | |
277 d.unit = ""; | |
278 d.minValue = 0; | |
279 d.maxValue = 1; | |
280 d.defaultValue = 0; | |
281 d.isQuantized = true; | |
282 d.quantizeStep = 1; | |
283 d.valueNames.clear(); | |
284 d.valueNames.push_back("Elastic"); | |
285 d.valueNames.push_back("Precise"); | |
286 list.push_back(d); | |
287 | |
288 d.identifier = "transientmode"; | |
289 d.name = "Transient Handling"; | |
290 d.description = ""; //!!! | |
291 d.unit = ""; | |
292 d.minValue = 0; | |
293 d.maxValue = 2; | |
294 d.defaultValue = 0; | |
295 d.isQuantized = true; | |
296 d.quantizeStep = 1; | |
297 d.valueNames.clear(); | |
298 d.valueNames.push_back("Mixed"); | |
299 d.valueNames.push_back("Smooth"); | |
300 d.valueNames.push_back("Crisp"); | |
301 list.push_back(d); | |
302 | |
303 d.identifier = "phasemode"; | |
304 d.name = "Phase Handling"; | |
305 d.description = ""; //!!! | |
306 d.unit = ""; | |
307 d.minValue = 0; | |
308 d.maxValue = 1; | |
309 d.defaultValue = 0; | |
310 d.isQuantized = true; | |
311 d.quantizeStep = 1; | |
312 d.valueNames.clear(); | |
313 d.valueNames.push_back("Laminar"); | |
314 d.valueNames.push_back("Independent"); | |
315 list.push_back(d); | |
316 | |
317 d.identifier = "windowmode"; | |
318 d.name = "Window Length"; | |
319 d.description = ""; //!!! | |
320 d.unit = ""; | |
321 d.minValue = 0; | |
322 d.maxValue = 2; | |
323 d.defaultValue = 0; | |
324 d.isQuantized = true; | |
325 d.quantizeStep = 1; | |
326 d.valueNames.clear(); | |
327 d.valueNames.push_back("Standard"); | |
328 d.valueNames.push_back("Short"); | |
329 d.valueNames.push_back("Long"); | |
330 list.push_back(d); | |
331 | |
332 return list; | |
333 } | |
334 | |
335 float | |
336 RubberBandVampPlugin::getParameter(std::string id) const | |
337 { | |
338 if (id == "timeratio") return m_d->m_timeRatio * 100.f; | |
339 if (id == "pitchratio") return m_d->m_pitchRatio * 100.f; | |
340 if (id == "mode") return m_d->m_realtime ? 1.f : 0.f; | |
341 if (id == "stretchtype") return m_d->m_elasticTiming ? 0.f : 1.f; | |
342 if (id == "transientmode") return float(m_d->m_transientMode); | |
343 if (id == "phasemode") return m_d->m_phaseIndependent ? 1.f : 0.f; | |
344 if (id == "windowmode") return float(m_d->m_windowLength); | |
345 return 0.f; | |
346 } | |
347 | |
348 void | |
349 RubberBandVampPlugin::setParameter(std::string id, float value) | |
350 { | |
351 if (id == "timeratio") { | |
352 m_d->m_timeRatio = value / 100; | |
353 } else if (id == "pitchratio") { | |
354 m_d->m_pitchRatio = value / 100; | |
355 } else { | |
356 bool set = (value > 0.5); | |
357 if (id == "mode") m_d->m_realtime = set; | |
358 else if (id == "stretchtype") m_d->m_elasticTiming = !set; | |
359 else if (id == "transientmode") m_d->m_transientMode = int(value + 0.5); | |
360 else if (id == "phasemode") m_d->m_phaseIndependent = set; | |
361 else if (id == "windowmode") m_d->m_windowLength = int(value + 0.5); | |
362 } | |
363 } | |
364 | |
365 bool | |
366 RubberBandVampPlugin::initialise(size_t channels, size_t stepSize, size_t blockSize) | |
367 { | |
368 if (channels < getMinChannelCount() || | |
369 channels > getMaxChannelCount()) return false; | |
370 | |
371 m_d->m_stepSize = std::min(stepSize, blockSize); | |
372 m_d->m_blockSize = stepSize; | |
373 | |
374 RubberBand::RubberBandStretcher::Options options = 0; | |
375 | |
376 if (m_d->m_realtime) | |
377 options |= RubberBand::RubberBandStretcher::OptionProcessRealTime; | |
378 else options |= RubberBand::RubberBandStretcher::OptionProcessOffline; | |
379 | |
380 if (m_d->m_elasticTiming) | |
381 options |= RubberBand::RubberBandStretcher::OptionStretchElastic; | |
382 else options |= RubberBand::RubberBandStretcher::OptionStretchPrecise; | |
383 | |
384 if (m_d->m_transientMode == 0) | |
385 options |= RubberBand::RubberBandStretcher::OptionTransientsMixed; | |
386 else if (m_d->m_transientMode == 1) | |
387 options |= RubberBand::RubberBandStretcher::OptionTransientsSmooth; | |
388 else options |= RubberBand::RubberBandStretcher::OptionTransientsCrisp; | |
389 | |
390 if (m_d->m_phaseIndependent) | |
391 options |= RubberBand::RubberBandStretcher::OptionPhaseIndependent; | |
392 else options |= RubberBand::RubberBandStretcher::OptionPhaseLaminar; | |
393 | |
394 if (m_d->m_windowLength == 0) | |
395 options |= RubberBand::RubberBandStretcher::OptionWindowStandard; | |
396 else if (m_d->m_windowLength == 1) | |
397 options |= RubberBand::RubberBandStretcher::OptionWindowShort; | |
398 else options |= RubberBand::RubberBandStretcher::OptionWindowLong; | |
399 | |
400 delete m_d->m_stretcher; | |
401 m_d->m_stretcher = new RubberBand::RubberBandStretcher | |
402 (m_d->m_sampleRate, channels, options); | |
403 m_d->m_stretcher->setDebugLevel(1); | |
404 m_d->m_stretcher->setTimeRatio(m_d->m_timeRatio); | |
405 m_d->m_stretcher->setPitchScale(m_d->m_pitchRatio); | |
406 | |
407 m_d->m_counter = 0; | |
408 m_d->m_accumulatedIncrement = 0; | |
409 | |
410 m_d->m_outputDump = 0; | |
411 | |
412 return true; | |
413 } | |
414 | |
415 void | |
416 RubberBandVampPlugin::reset() | |
417 { | |
418 if (m_d->m_stretcher) m_d->m_stretcher->reset(); | |
419 } | |
420 | |
421 RubberBandVampPlugin::FeatureSet | |
422 RubberBandVampPlugin::process(const float *const *inputBuffers, | |
423 Vamp::RealTime timestamp) | |
424 { | |
425 if (m_d->m_realtime) { | |
426 return m_d->processRealTime(inputBuffers, timestamp); | |
427 } else { | |
428 return m_d->processOffline(inputBuffers, timestamp); | |
429 } | |
430 } | |
431 | |
432 RubberBandVampPlugin::FeatureSet | |
433 RubberBandVampPlugin::getRemainingFeatures() | |
434 { | |
435 if (m_d->m_realtime) { | |
436 return m_d->getRemainingFeaturesRealTime(); | |
437 } else { | |
438 return m_d->getRemainingFeaturesOffline(); | |
439 } | |
440 } | |
441 | |
442 RubberBandVampPlugin::FeatureSet | |
443 RubberBandVampPlugin::Impl::processOffline(const float *const *inputBuffers, | |
444 Vamp::RealTime timestamp) | |
445 { | |
446 if (!m_stretcher) { | |
447 cerr << "ERROR: RubberBandVampPlugin::processOffline: " | |
448 << "RubberBandVampPlugin has not been initialised" | |
449 << endl; | |
450 return FeatureSet(); | |
451 } | |
452 | |
453 m_stretcher->study(inputBuffers, m_blockSize, false); | |
454 return FeatureSet(); | |
455 } | |
456 | |
457 RubberBandVampPlugin::FeatureSet | |
458 RubberBandVampPlugin::Impl::getRemainingFeaturesOffline() | |
459 { | |
460 m_stretcher->study(0, 0, true); | |
461 | |
462 m_stretcher->calculateStretch(); | |
463 | |
464 int rate = m_sampleRate; | |
465 | |
466 RubberBand::StretchCalculator sc(rate, m_stretcher->getInputIncrement(), true); | |
467 | |
468 size_t inputIncrement = m_stretcher->getInputIncrement(); | |
469 std::vector<int> outputIncrements = m_stretcher->getOutputIncrements(); | |
470 std::vector<float> phaseResetDf = m_stretcher->getPhaseResetCurve(); | |
471 std::vector<int> peaks = m_stretcher->getExactTimePoints(); | |
472 std::vector<float> smoothedDf = sc.smoothDF(phaseResetDf); | |
473 | |
474 FeatureSet features = createFeatures | |
475 (inputIncrement, outputIncrements, phaseResetDf, peaks, smoothedDf, | |
476 0, true); | |
477 | |
478 return features; | |
479 } | |
480 | |
481 RubberBandVampPlugin::FeatureSet | |
482 RubberBandVampPlugin::Impl::processRealTime(const float *const *inputBuffers, | |
483 Vamp::RealTime timestamp) | |
484 { | |
485 // This function is not in any way a real-time function (i.e. it | |
486 // has no requirement to be RT safe); it simply operates the | |
487 // stretcher in RT mode. | |
488 | |
489 if (!m_stretcher) { | |
490 cerr << "ERROR: RubberBandVampPlugin::processRealTime: " | |
491 << "RubberBandVampPlugin has not been initialised" | |
492 << endl; | |
493 return FeatureSet(); | |
494 } | |
495 | |
496 m_stretcher->process(inputBuffers, m_blockSize, false); | |
497 | |
498 size_t inputIncrement = m_stretcher->getInputIncrement(); | |
499 std::vector<int> outputIncrements = m_stretcher->getOutputIncrements(); | |
500 std::vector<float> phaseResetDf = m_stretcher->getPhaseResetCurve(); | |
501 std::vector<float> smoothedDf; // not meaningful in RT mode | |
502 std::vector<int> dummyPoints; | |
503 FeatureSet features = createFeatures | |
504 (inputIncrement, outputIncrements, phaseResetDf, dummyPoints, smoothedDf, | |
505 m_counter, false); | |
506 m_counter += outputIncrements.size(); | |
507 | |
508 int available = 0; | |
509 while ((available = m_stretcher->available()) > 0) { | |
510 if (!m_outputDump) { | |
511 m_outputDump = new float *[m_stretcher->getChannelCount()]; | |
512 for (size_t i = 0; i < m_stretcher->getChannelCount(); ++i) { | |
513 m_outputDump[i] = new float[m_blockSize]; | |
514 } | |
515 } | |
516 m_stretcher->retrieve(m_outputDump, | |
517 std::min(int(m_blockSize), available)); | |
518 } | |
519 | |
520 return features; | |
521 } | |
522 | |
523 RubberBandVampPlugin::FeatureSet | |
524 RubberBandVampPlugin::Impl::getRemainingFeaturesRealTime() | |
525 { | |
526 return FeatureSet(); | |
527 } | |
528 | |
529 RubberBandVampPlugin::FeatureSet | |
530 RubberBandVampPlugin::Impl::createFeatures(size_t inputIncrement, | |
531 std::vector<int> &outputIncrements, | |
532 std::vector<float> &phaseResetDf, | |
533 std::vector<int> &exactPoints, | |
534 std::vector<float> &smoothedDf, | |
535 size_t baseCount, | |
536 bool includeFinal) | |
537 { | |
538 size_t actual = m_accumulatedIncrement; | |
539 | |
540 double overallRatio = m_timeRatio * m_pitchRatio; | |
541 | |
542 char label[200]; | |
543 | |
544 FeatureSet features; | |
545 | |
546 int rate = m_sampleRate; | |
547 | |
548 size_t epi = 0; | |
549 | |
550 for (size_t i = 0; i < outputIncrements.size(); ++i) { | |
551 | |
552 size_t frame = (baseCount + i) * inputIncrement; | |
553 | |
554 int oi = outputIncrements[i]; | |
555 bool hard = false; | |
556 bool soft = false; | |
557 | |
558 if (oi < 0) { | |
559 oi = -oi; | |
560 hard = true; | |
561 } | |
562 | |
563 if (epi < exactPoints.size() && int(i) == exactPoints[epi]) { | |
564 soft = true; | |
565 ++epi; | |
566 } | |
567 | |
568 double linear = (frame * overallRatio); | |
569 | |
570 Vamp::RealTime t = Vamp::RealTime::frame2RealTime(frame, rate); | |
571 | |
572 Feature feature; | |
573 feature.hasTimestamp = true; | |
574 feature.timestamp = t; | |
575 feature.values.push_back(float(oi)); | |
576 feature.label = Vamp::RealTime::frame2RealTime(oi, rate).toText(); | |
577 features[m_incrementsOutput].push_back(feature); | |
578 | |
579 feature.values.clear(); | |
580 feature.values.push_back(float(actual)); | |
581 feature.label = Vamp::RealTime::frame2RealTime(actual, rate).toText(); | |
582 features[m_aggregateIncrementsOutput].push_back(feature); | |
583 | |
584 feature.values.clear(); | |
585 feature.values.push_back(actual - linear); | |
586 | |
587 sprintf(label, "expected %ld, actual %ld, difference %ld (%s ms)", | |
588 long(linear), long(actual), long(actual - linear), | |
589 // frame2RealTime expects an integer frame number, | |
590 // hence our multiplication factor | |
591 (Vamp::RealTime::frame2RealTime | |
592 (lrintf((actual - linear) * 1000), rate) / 1000) | |
593 .toText().c_str()); | |
594 feature.label = label; | |
595 | |
596 features[m_divergenceOutput].push_back(feature); | |
597 actual += oi; | |
598 | |
599 char buf[30]; | |
600 | |
601 if (i < phaseResetDf.size()) { | |
602 feature.values.clear(); | |
603 feature.values.push_back(phaseResetDf[i]); | |
604 sprintf(buf, "%d", int(baseCount + i)); | |
605 feature.label = buf; | |
606 features[m_phaseResetDfOutput].push_back(feature); | |
607 } | |
608 | |
609 if (i < smoothedDf.size()) { | |
610 feature.values.clear(); | |
611 feature.values.push_back(smoothedDf[i]); | |
612 features[m_smoothedPhaseResetDfOutput].push_back(feature); | |
613 } | |
614 | |
615 if (hard) { | |
616 feature.values.clear(); | |
617 feature.label = "Phase Reset"; | |
618 features[m_phaseResetPointsOutput].push_back(feature); | |
619 } | |
620 | |
621 if (hard || soft) { | |
622 feature.values.clear(); | |
623 feature.label = "Time Sync"; | |
624 features[m_timeSyncPointsOutput].push_back(feature); | |
625 } | |
626 } | |
627 | |
628 if (includeFinal) { | |
629 Vamp::RealTime t = Vamp::RealTime::frame2RealTime | |
630 (inputIncrement * (baseCount + outputIncrements.size()), rate); | |
631 Feature feature; | |
632 feature.hasTimestamp = true; | |
633 feature.timestamp = t; | |
634 feature.label = Vamp::RealTime::frame2RealTime(actual, rate).toText(); | |
635 feature.values.clear(); | |
636 feature.values.push_back(float(actual)); | |
637 features[m_aggregateIncrementsOutput].push_back(feature); | |
638 | |
639 float linear = ((baseCount + outputIncrements.size()) | |
640 * inputIncrement * overallRatio); | |
641 feature.values.clear(); | |
642 feature.values.push_back(actual - linear); | |
643 feature.label = // see earlier comment | |
644 (Vamp::RealTime::frame2RealTime //!!! update this as earlier label | |
645 (lrintf((actual - linear) * 1000), rate) / 1000) | |
646 .toText(); | |
647 features[m_divergenceOutput].push_back(feature); | |
648 } | |
649 | |
650 m_accumulatedIncrement = actual; | |
651 | |
652 return features; | |
653 } | |
654 |