annotate src/rubberband-1.8.1/vamp/RubberBandVampPlugin.cpp @ 95:89f5e221ed7b

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