annotate TempogramPlugin.cpp @ 25:fe23998968b4

* Added tempogram via autocorrelation feature, using AutocorrelationProcessor * Moved calculateMax() from NoveltyCurveProcessor to SpectrogramProcessor
author Carl Bussey <c.bussey@se10.qmul.ac.uk>
date Wed, 20 Aug 2014 16:00:37 +0100
parents 957b83524c06
children ff6110f1144b
rev   line source
c@0 1
c@0 2 // This is a skeleton file for use in creating your own plugin
c@0 3 // libraries. Replace MyPlugin and myPlugin throughout with the name
c@0 4 // of your first plugin class, and fill in the gaps as appropriate.
c@0 5
c@0 6
c@14 7 #include "TempogramPlugin.h"
c@25 8
c@4 9
c@0 10 using Vamp::FFT;
c@7 11 using Vamp::RealTime;
c@0 12 using namespace std;
c@0 13
c@14 14 TempogramPlugin::TempogramPlugin(float inputSampleRate) :
c@0 15 Plugin(inputSampleRate),
c@18 16 m_inputBlockSize(0), //host parameter
c@18 17 m_inputStepSize(0), //host parameter
c@19 18 m_noveltyCurveMinDB(pow(10,(float)-74/20)), //set in initialise()
c@18 19 m_noveltyCurveCompressionConstant(1000), //parameter
c@18 20 m_tempogramLog2WindowLength(10), //parameter
c@18 21 m_tempogramWindowLength(pow((float)2,m_tempogramLog2WindowLength)),
c@18 22 m_tempogramLog2FftLength(m_tempogramLog2WindowLength), //parameter
c@18 23 m_tempogramFftLength(m_tempogramWindowLength),
c@18 24 m_tempogramLog2HopSize(6), //parameter
c@18 25 m_tempogramHopSize(pow((float)2,m_tempogramLog2HopSize)),
c@18 26 m_tempogramMinBPM(30), //parameter
c@18 27 m_tempogramMaxBPM(480), //parameter
c@18 28 m_tempogramMinBin(0), //set in initialise()
c@18 29 m_tempogramMaxBin(0), //set in initialise()
c@18 30 m_cyclicTempogramMinBPM(30), //reset in initialise()
c@18 31 m_cyclicTempogramNumberOfOctaves(0), //set in initialise()
c@18 32 m_cyclicTempogramOctaveDivider(30) //parameter
c@0 33
c@0 34 // Also be sure to set your plugin parameters (presumably stored
c@0 35 // in member variables) to their default values here -- the host
c@0 36 // will not do that for you
c@0 37 {
c@0 38 }
c@0 39
c@14 40 TempogramPlugin::~TempogramPlugin()
c@0 41 {
c@0 42 //delete stuff
c@19 43
c@0 44 }
c@0 45
c@0 46 string
c@14 47 TempogramPlugin::getIdentifier() const
c@0 48 {
c@0 49 return "tempogram";
c@0 50 }
c@0 51
c@0 52 string
c@14 53 TempogramPlugin::getName() const
c@0 54 {
c@0 55 return "Tempogram";
c@0 56 }
c@0 57
c@0 58 string
c@14 59 TempogramPlugin::getDescription() const
c@0 60 {
c@0 61 // Return something helpful here!
c@0 62 return "Cyclic Tempogram as described by Peter Grosche and Meinard Muller";
c@0 63 }
c@0 64
c@0 65 string
c@14 66 TempogramPlugin::getMaker() const
c@0 67 {
c@0 68 //Your name here
c@0 69 return "Carl Bussey";
c@0 70 }
c@0 71
c@0 72 int
c@14 73 TempogramPlugin::getPluginVersion() const
c@0 74 {
c@0 75 // Increment this each time you release a version that behaves
c@0 76 // differently from the previous one
c@0 77 return 1;
c@0 78 }
c@0 79
c@0 80 string
c@14 81 TempogramPlugin::getCopyright() const
c@0 82 {
c@0 83 // This function is not ideally named. It does not necessarily
c@0 84 // need to say who made the plugin -- getMaker does that -- but it
c@0 85 // should indicate the terms under which it is distributed. For
c@0 86 // example, "Copyright (year). All Rights Reserved", or "GPL"
c@0 87 return "";
c@0 88 }
c@0 89
c@14 90 TempogramPlugin::InputDomain
c@14 91 TempogramPlugin::getInputDomain() const
c@0 92 {
c@0 93 return FrequencyDomain;
c@0 94 }
c@0 95
c@0 96 size_t
c@14 97 TempogramPlugin::getPreferredBlockSize() const
c@0 98 {
c@9 99 return 2048; // 0 means "I can handle any block size"
c@0 100 }
c@0 101
c@0 102 size_t
c@14 103 TempogramPlugin::getPreferredStepSize() const
c@0 104 {
c@9 105 return 1024; // 0 means "anything sensible"; in practice this
c@0 106 // means the same as the block size for TimeDomain
c@0 107 // plugins, or half of it for FrequencyDomain plugins
c@0 108 }
c@0 109
c@0 110 size_t
c@14 111 TempogramPlugin::getMinChannelCount() const
c@0 112 {
c@0 113 return 1;
c@0 114 }
c@0 115
c@0 116 size_t
c@14 117 TempogramPlugin::getMaxChannelCount() const
c@0 118 {
c@0 119 return 1;
c@0 120 }
c@0 121
c@14 122 TempogramPlugin::ParameterList
c@14 123 TempogramPlugin::getParameterDescriptors() const
c@0 124 {
c@0 125 ParameterList list;
c@0 126
c@0 127 // If the plugin has no adjustable parameters, return an empty
c@0 128 // list here (and there's no need to provide implementations of
c@0 129 // getParameter and setParameter in that case either).
c@0 130
c@0 131 // Note that it is your responsibility to make sure the parameters
c@0 132 // start off having their default values (e.g. in the constructor
c@0 133 // above). The host needs to know the default value so it can do
c@0 134 // things like provide a "reset to default" function, but it will
c@0 135 // not explicitly set your parameters to their defaults for you if
c@0 136 // they have not changed in the mean time.
c@0 137
c@14 138 ParameterDescriptor d1;
c@14 139 d1.identifier = "C";
c@15 140 d1.name = "Novelty Curve Spectrogram Compression Constant";
c@14 141 d1.description = "Spectrogram compression constant, C, used when retrieving the novelty curve from the audio.";
c@14 142 d1.unit = "";
c@14 143 d1.minValue = 2;
c@14 144 d1.maxValue = 10000;
c@14 145 d1.defaultValue = 1000;
c@14 146 d1.isQuantized = false;
c@14 147 list.push_back(d1);
c@9 148
c@14 149 ParameterDescriptor d2;
c@14 150 d2.identifier = "log2TN";
c@14 151 d2.name = "Tempogram Window Length";
c@14 152 d2.description = "FFT window length when analysing the novelty curve and extracting the tempogram time-frequency function.";
c@14 153 d2.unit = "";
c@14 154 d2.minValue = 7;
c@14 155 d2.maxValue = 12;
c@14 156 d2.defaultValue = 10;
c@14 157 d2.isQuantized = true;
c@14 158 d2.quantizeStep = 1;
c@14 159 for (int i = d2.minValue; i <= d2.maxValue; i++){
c@14 160 d2.valueNames.push_back(floatToString(pow((float)2,(float)i)));
c@13 161 }
c@14 162 list.push_back(d2);
c@0 163
c@14 164 ParameterDescriptor d3;
c@14 165 d3.identifier = "log2HopSize";
c@14 166 d3.name = "Tempogram Hopsize";
c@14 167 d3.description = "FFT hopsize when analysing the novelty curve and extracting the tempogram time-frequency function.";
c@14 168 d3.unit = "";
c@14 169 d3.minValue = 6;
c@14 170 d3.maxValue = 12;
c@14 171 d3.defaultValue = 6;
c@14 172 d3.isQuantized = true;
c@14 173 d3.quantizeStep = 1;
c@14 174 for (int i = d3.minValue; i <= d3.maxValue; i++){
c@14 175 d3.valueNames.push_back(floatToString(pow((float)2,(float)i)));
c@14 176 }
c@14 177 list.push_back(d3);
c@9 178
c@14 179 ParameterDescriptor d4;
c@14 180 d4.identifier = "log2FftLength";
c@14 181 d4.name = "Tempogram FFT Length";
c@14 182 d4.description = "FFT length when analysing the novelty curve and extracting the tempogram time-frequency function. This parameter determines the amount of zero padding.";
c@14 183 d4.unit = "";
c@14 184 d4.minValue = 6;
c@14 185 d4.maxValue = 12;
c@14 186 d4.defaultValue = d2.defaultValue;
c@14 187 d4.isQuantized = true;
c@14 188 d4.quantizeStep = 1;
c@14 189 for (int i = d4.minValue; i <= d4.maxValue; i++){
c@14 190 d4.valueNames.push_back(floatToString(pow((float)2,(float)i)));
c@14 191 }
c@14 192 list.push_back(d4);
c@14 193
c@14 194 ParameterDescriptor d5;
c@14 195 d5.identifier = "minBPM";
c@18 196 d5.name = "(Cyclic) Tempogram Minimum BPM";
c@14 197 d5.description = "The minimum BPM of the tempogram output bins.";
c@14 198 d5.unit = "";
c@14 199 d5.minValue = 0;
c@14 200 d5.maxValue = 2000;
c@14 201 d5.defaultValue = 30;
c@14 202 d5.isQuantized = true;
c@14 203 d5.quantizeStep = 5;
c@14 204 list.push_back(d5);
c@14 205
c@14 206 ParameterDescriptor d6;
c@14 207 d6.identifier = "maxBPM";
c@18 208 d6.name = "(Cyclic) Tempogram Maximum BPM";
c@18 209 d6.description = "The maximum BPM of the tempogram output bins.";
c@14 210 d6.unit = "";
c@14 211 d6.minValue = 30;
c@14 212 d6.maxValue = 2000;
c@14 213 d6.defaultValue = 480;
c@14 214 d6.isQuantized = true;
c@14 215 d6.quantizeStep = 5;
c@14 216 list.push_back(d6);
c@18 217
c@18 218 ParameterDescriptor d7;
c@18 219 d7.identifier = "octDiv";
c@18 220 d7.name = "Cyclic Tempogram Octave Divider";
c@18 221 d7.description = "The number bins within each octave.";
c@18 222 d7.unit = "";
c@18 223 d7.minValue = 5;
c@18 224 d7.maxValue = 60;
c@18 225 d7.defaultValue = 30;
c@18 226 d7.isQuantized = true;
c@18 227 d7.quantizeStep = 1;
c@18 228 list.push_back(d7);
c@0 229
c@0 230 return list;
c@0 231 }
c@0 232
c@0 233 float
c@14 234 TempogramPlugin::getParameter(string identifier) const
c@0 235 {
c@0 236 if (identifier == "C") {
c@18 237 return m_noveltyCurveCompressionConstant; // return the ACTUAL current value of your parameter here!
c@0 238 }
c@14 239 else if (identifier == "log2TN"){
c@18 240 return m_tempogramLog2WindowLength;
c@9 241 }
c@14 242 else if (identifier == "log2HopSize"){
c@18 243 return m_tempogramLog2HopSize;
c@14 244 }
c@14 245 else if (identifier == "log2FftLength"){
c@18 246 return m_tempogramLog2FftLength;
c@14 247 }
c@14 248 else if (identifier == "minBPM") {
c@18 249 return m_tempogramMinBPM;
c@9 250 }
c@14 251 else if (identifier == "maxBPM"){
c@18 252 return m_tempogramMaxBPM;
c@18 253 }
c@18 254 else if (identifier == "octDiv"){
c@18 255 return m_cyclicTempogramOctaveDivider;
c@0 256 }
c@0 257
c@0 258 return 0;
c@0 259 }
c@0 260
c@0 261 void
c@14 262 TempogramPlugin::setParameter(string identifier, float value)
c@0 263 {
c@9 264
c@0 265 if (identifier == "C") {
c@18 266 m_noveltyCurveCompressionConstant = value; // set the actual value of your parameter
c@0 267 }
c@14 268 else if (identifier == "log2TN") {
c@18 269 m_tempogramWindowLength = pow(2,value);
c@18 270 m_tempogramLog2WindowLength = value;
c@0 271 }
c@14 272 else if (identifier == "log2HopSize"){
c@18 273 m_tempogramHopSize = pow(2,value);
c@18 274 m_tempogramLog2HopSize = value;
c@14 275 }
c@18 276 else if (identifier == "log2FftLength"){
c@18 277 m_tempogramFftLength = pow(2,value);
c@18 278 m_tempogramLog2FftLength = value;
c@14 279 }
c@14 280 else if (identifier == "minBPM") {
c@18 281 m_tempogramMinBPM = value;
c@9 282 }
c@14 283 else if (identifier == "maxBPM"){
c@18 284 m_tempogramMaxBPM = value;
c@18 285 }
c@18 286 else if (identifier == "octDiv"){
c@18 287 m_cyclicTempogramOctaveDivider = value;
c@9 288 }
c@9 289
c@9 290 }
c@9 291
c@14 292 TempogramPlugin::ProgramList
c@14 293 TempogramPlugin::getPrograms() const
c@0 294 {
c@0 295 ProgramList list;
c@0 296
c@0 297 // If you have no programs, return an empty list (or simply don't
c@0 298 // implement this function or getCurrentProgram/selectProgram)
c@0 299
c@0 300 return list;
c@0 301 }
c@0 302
c@0 303 string
c@14 304 TempogramPlugin::getCurrentProgram() const
c@0 305 {
c@0 306 return ""; // no programs
c@0 307 }
c@0 308
c@0 309 void
c@14 310 TempogramPlugin::selectProgram(string name)
c@0 311 {
c@0 312 }
c@0 313
c@14 314 TempogramPlugin::OutputList
c@14 315 TempogramPlugin::getOutputDescriptors() const
c@0 316 {
c@0 317 OutputList list;
c@0 318
c@0 319 // See OutputDescriptor documentation for the possibilities here.
c@0 320 // Every plugin must have at least one output.
c@1 321
c@7 322 float d_sampleRate;
c@18 323 float tempogramInputSampleRate = (float)m_inputSampleRate/m_inputStepSize;
c@7 324
c@25 325 OutputDescriptor d1;
c@25 326 d1.identifier = "cyclicTempogram";
c@25 327 d1.name = "Cyclic Tempogram";
c@25 328 d1.description = "Cyclic Tempogram";
c@25 329 d1.unit = "";
c@25 330 d1.hasFixedBinCount = true;
c@25 331 d1.binCount = m_cyclicTempogramOctaveDivider > 0 && !isnan(m_cyclicTempogramOctaveDivider) ? m_cyclicTempogramOctaveDivider : 0;
c@25 332 d1.hasKnownExtents = false;
c@25 333 d1.isQuantized = false;
c@25 334 d1.sampleType = OutputDescriptor::FixedSampleRate;
c@25 335 d_sampleRate = tempogramInputSampleRate/m_tempogramHopSize;
c@25 336 d1.sampleRate = d_sampleRate > 0.0 && !isnan(d_sampleRate) ? d_sampleRate : 0;
c@25 337 d1.hasDuration = false;
c@25 338 list.push_back(d1);
c@25 339
c@25 340 OutputDescriptor d2;
c@25 341 d2.identifier = "tempogramDFT";
c@25 342 d2.name = "Tempogram via DFT";
c@25 343 d2.description = "Tempogram via DFT";
c@25 344 d2.unit = "BPM";
c@25 345 d2.hasFixedBinCount = true;
c@25 346 d2.binCount = m_tempogramMaxBin - m_tempogramMinBin + 1;
c@25 347 d2.hasKnownExtents = false;
c@25 348 d2.isQuantized = false;
c@25 349 d2.sampleType = OutputDescriptor::FixedSampleRate;
c@25 350 d_sampleRate = tempogramInputSampleRate/m_tempogramHopSize;
c@25 351 d2.sampleRate = d_sampleRate > 0.0 && !isnan(d_sampleRate) ? d_sampleRate : 0.0;
c@25 352 for(int i = m_tempogramMinBin; i <= (int)m_tempogramMaxBin; i++){
c@25 353 float w = ((float)i/m_tempogramFftLength)*(tempogramInputSampleRate);
c@25 354 d2.binNames.push_back(floatToString(w*60));
c@25 355 }
c@25 356 d2.hasDuration = false;
c@25 357 list.push_back(d2);
c@25 358
c@21 359 OutputDescriptor d3;
c@25 360 d3.identifier = "tempogramACT";
c@25 361 d3.name = "Tempogram via ACT";
c@25 362 d3.description = "Tempogram via ACT";
c@25 363 d3.unit = "BPM";
c@21 364 d3.hasFixedBinCount = true;
c@25 365 d3.binCount = m_tempogramMaxBin - m_tempogramMinBin + 1;
c@21 366 d3.hasKnownExtents = false;
c@21 367 d3.isQuantized = false;
c@21 368 d3.sampleType = OutputDescriptor::FixedSampleRate;
c@21 369 d_sampleRate = tempogramInputSampleRate/m_tempogramHopSize;
c@25 370 d3.sampleRate = d_sampleRate > 0.0 && !isnan(d_sampleRate) ? d_sampleRate : 0.0;
c@25 371 for(int i = m_tempogramMinBin; i <= (int)m_tempogramMaxBin; i++){
c@25 372 float w = ((float)i/m_tempogramFftLength)*(tempogramInputSampleRate);
c@25 373 d3.binNames.push_back(floatToString(w*60));
c@25 374 }
c@21 375 d3.hasDuration = false;
c@21 376 list.push_back(d3);
c@21 377
c@25 378 OutputDescriptor d4;
c@25 379 d4.identifier = "nc";
c@25 380 d4.name = "Novelty Curve";
c@25 381 d4.description = "Novelty Curve";
c@25 382 d4.unit = "";
c@25 383 d4.hasFixedBinCount = true;
c@25 384 d4.binCount = 1;
c@25 385 d4.hasKnownExtents = false;
c@25 386 d4.isQuantized = false;
c@25 387 d4.sampleType = OutputDescriptor::FixedSampleRate;
c@9 388 d_sampleRate = tempogramInputSampleRate;
c@25 389 d4.sampleRate = d_sampleRate > 0 && !isnan(d_sampleRate) ? d_sampleRate : 0;
c@25 390 d4.hasDuration = false;
c@25 391 list.push_back(d4);
c@18 392
c@0 393 return list;
c@0 394 }
c@0 395
c@20 396 bool
c@20 397 TempogramPlugin::initialise(size_t channels, size_t stepSize, size_t blockSize)
c@20 398 {
c@20 399 if (channels < getMinChannelCount() ||
c@20 400 channels > getMaxChannelCount()) return false;
c@20 401
c@20 402 // Real initialisation work goes here!
c@20 403 m_inputBlockSize = blockSize;
c@20 404 m_inputStepSize = stepSize;
c@20 405
c@24 406 //m_spectrogram = Spectrogram(m_inputBlockSize/2 + 1);
c@21 407 if (!handleParameterValues()) return false;
c@19 408 //cout << m_cyclicTempogramOctaveDivider << endl;
c@4 409
c@0 410 return true;
c@0 411 }
c@0 412
c@0 413 void
c@14 414 TempogramPlugin::reset()
c@0 415 {
c@0 416 // Clear buffers, reset stored values, etc
c@19 417 m_spectrogram.clear();
c@21 418 handleParameterValues();
c@0 419 }
c@0 420
c@14 421 TempogramPlugin::FeatureSet
c@14 422 TempogramPlugin::process(const float *const *inputBuffers, Vamp::RealTime timestamp)
c@0 423 {
c@0 424
c@23 425 int n = m_inputBlockSize/2 + 1;
c@0 426 const float *in = inputBuffers[0];
c@3 427
c@9 428 //calculate magnitude of FrequencyDomain input
c@22 429 vector<float> fftCoefficients;
c@23 430 for (int i = 0; i < n; i++){
c@0 431 float magnitude = sqrt(in[2*i] * in[2*i] + in[2*i + 1] * in[2*i + 1]);
c@18 432 magnitude = magnitude > m_noveltyCurveMinDB ? magnitude : m_noveltyCurveMinDB;
c@22 433 fftCoefficients.push_back(magnitude);
c@0 434 }
c@22 435 m_spectrogram.push_back(fftCoefficients);
c@24 436 //m_spectrogram.push_back(fftCoefficients);
c@21 437
c@23 438 return FeatureSet();
c@0 439 }
c@0 440
c@14 441 TempogramPlugin::FeatureSet
c@14 442 TempogramPlugin::getRemainingFeatures()
c@11 443 {
c@0 444
c@18 445 float * hannWindow = new float[m_tempogramWindowLength];
c@20 446 for (int i = 0; i < (int)m_tempogramWindowLength; i++){
c@14 447 hannWindow[i] = 0.0;
c@4 448 }
c@11 449
c@1 450 FeatureSet featureSet;
c@0 451
c@19 452 //initialise novelty curve processor
c@23 453 int numberOfBlocks = m_spectrogram.size();
c@20 454 //cerr << numberOfBlocks << endl;
c@22 455 NoveltyCurveProcessor nc(m_inputSampleRate, m_inputBlockSize, m_noveltyCurveCompressionConstant);
c@21 456 vector<float> noveltyCurve = nc.spectrogramToNoveltyCurve(m_spectrogram); //calculate novelty curvefrom magnitude data
c@4 457
c@9 458 //push novelty curve data to featureset 1 and set timestamps
c@23 459 for (int i = 0; i < numberOfBlocks; i++){
c@19 460 Feature noveltyCurveFeature;
c@19 461 noveltyCurveFeature.values.push_back(noveltyCurve[i]);
c@19 462 noveltyCurveFeature.hasTimestamp = false;
c@25 463 featureSet[3].push_back(noveltyCurveFeature);
c@21 464 assert(!isnan(noveltyCurveFeature.values.back()));
c@4 465 }
c@4 466
c@9 467 //window function for spectrogram
c@18 468 WindowFunction::hanning(hannWindow, m_tempogramWindowLength);
c@9 469
c@9 470 //initialise spectrogram processor
c@18 471 SpectrogramProcessor spectrogramProcessor(m_tempogramWindowLength, m_tempogramFftLength, m_tempogramHopSize);
c@9 472 //compute spectrogram from novelty curve data (i.e., tempogram)
c@25 473 Tempogram tempogramDFT = spectrogramProcessor.process(&noveltyCurve[0], numberOfBlocks, hannWindow);
c@18 474 delete []hannWindow;
c@18 475 hannWindow = 0;
c@0 476
c@25 477 int tempogramLag = 1;
c@25 478 AutocorrelationProcessor autocorrelationProcessor(m_tempogramWindowLength, m_tempogramHopSize, tempogramLag);
c@25 479 Tempogram tempogramACT = autocorrelationProcessor.process(&noveltyCurve[0], numberOfBlocks);
c@25 480
c@25 481 int tempogramLength = tempogramDFT.size();
c@7 482
c@9 483 //push tempogram data to featureset 0 and set timestamps.
c@7 484 for (int block = 0; block < tempogramLength; block++){
c@25 485 Feature tempogramDFTFeature;
c@25 486 Feature tempogramACTFeature;
c@0 487
c@25 488 assert(tempogramDFT[block].size() == (m_tempogramFftLength/2 + 1));
c@18 489 for(int k = m_tempogramMinBin; k < (int)m_tempogramMaxBin; k++){
c@25 490 tempogramDFTFeature.values.push_back(tempogramDFT[block][k]);
c@25 491 tempogramACTFeature.values.push_back(tempogramACT[block][k]);
c@0 492 }
c@25 493 tempogramDFTFeature.hasTimestamp = false;
c@25 494 tempogramACTFeature.hasTimestamp = false;
c@25 495 featureSet[1].push_back(tempogramDFTFeature);
c@25 496 featureSet[2].push_back(tempogramACTFeature);
c@0 497 }
c@0 498
c@18 499 //Calculate cyclic tempogram
c@22 500 vector< vector<unsigned int> > logBins = calculateTempogramNearestNeighbourLogBins();
c@18 501
c@22 502 //assert((int)logBins.size() == m_cyclicTempogramOctaveDivider*m_cyclicTempogramNumberOfOctaves);
c@18 503 for (int block = 0; block < tempogramLength; block++){
c@19 504 Feature cyclicTempogramFeature;
c@18 505
c@23 506 for (int i = 0; i < m_cyclicTempogramOctaveDivider; i++){
c@18 507 float sum = 0;
c@21 508
c@23 509 for (int j = 0; j < m_cyclicTempogramNumberOfOctaves; j++){
c@25 510 sum += tempogramDFT[block][logBins[j][i]];
c@18 511 }
c@19 512 cyclicTempogramFeature.values.push_back(sum/m_cyclicTempogramNumberOfOctaves);
c@21 513 assert(!isnan(cyclicTempogramFeature.values.back()));
c@18 514 }
c@18 515
c@19 516 cyclicTempogramFeature.hasTimestamp = false;
c@21 517 featureSet[0].push_back(cyclicTempogramFeature);
c@18 518 }
c@0 519
c@0 520 return featureSet;
c@0 521 }
c@22 522
c@22 523 vector< vector<unsigned int> > TempogramPlugin::calculateTempogramNearestNeighbourLogBins() const
c@22 524 {
c@22 525 vector< vector<unsigned int> > logBins;
c@22 526
c@22 527 for (int octave = 0; octave < (int)m_cyclicTempogramNumberOfOctaves; octave++){
c@22 528 vector<unsigned int> octaveBins;
c@22 529
c@22 530 for (int bin = 0; bin < (int)m_cyclicTempogramOctaveDivider; bin++){
c@22 531 float bpm = m_cyclicTempogramMinBPM*pow(2.0f, octave+(float)bin/m_cyclicTempogramOctaveDivider);
c@22 532 octaveBins.push_back(bpmToBin(bpm));
c@23 533 //cout << octaveBins.back() << endl;
c@22 534 }
c@22 535 logBins.push_back(octaveBins);
c@22 536 }
c@22 537
c@22 538 //cerr << logBins.size() << endl;
c@22 539
c@22 540 return logBins;
c@22 541 }
c@22 542
c@22 543 unsigned int TempogramPlugin::bpmToBin(const float &bpm) const
c@22 544 {
c@22 545 float w = (float)bpm/60;
c@22 546 float sampleRate = m_inputSampleRate/m_inputStepSize;
c@22 547 int bin = floor((float)m_tempogramFftLength*w/sampleRate + 0.5);
c@22 548
c@22 549 if(bin < 0) bin = 0;
c@22 550 else if(bin > m_tempogramFftLength/2.0f) bin = m_tempogramFftLength;
c@22 551
c@22 552 return bin;
c@22 553 }
c@22 554
c@22 555 float TempogramPlugin::binToBPM(const int &bin) const
c@22 556 {
c@22 557 float sampleRate = m_inputSampleRate/m_inputStepSize;
c@22 558
c@22 559 return (bin*sampleRate/m_tempogramFftLength)*60;
c@22 560 }
c@22 561
c@22 562 bool TempogramPlugin::handleParameterValues(){
c@22 563
c@22 564 if (m_tempogramHopSize <= 0) return false;
c@22 565 if (m_tempogramLog2FftLength <= 0) return false;
c@22 566
c@22 567 if (m_tempogramFftLength < m_tempogramWindowLength){
c@22 568 m_tempogramFftLength = m_tempogramWindowLength;
c@22 569 }
c@22 570 if (m_tempogramMinBPM >= m_tempogramMaxBPM){
c@22 571 m_tempogramMinBPM = 30;
c@22 572 m_tempogramMaxBPM = 480;
c@22 573 }
c@22 574
c@22 575 float tempogramInputSampleRate = (float)m_inputSampleRate/m_inputStepSize;
c@22 576 m_tempogramMinBin = (max(floor(((m_tempogramMinBPM/60)/tempogramInputSampleRate)*m_tempogramFftLength), (float)0.0));
c@22 577 m_tempogramMaxBin = (min(ceil(((m_tempogramMaxBPM/60)/tempogramInputSampleRate)*m_tempogramFftLength), (float)m_tempogramFftLength/2));
c@22 578
c@25 579 if (m_tempogramMinBPM > m_cyclicTempogramMinBPM) m_cyclicTempogramMinBPM = m_tempogramMinBPM; //m_cyclicTempogram can't be less than default = 30
c@22 580 float cyclicTempogramMaxBPM = 480;
c@22 581 if (m_tempogramMaxBPM < cyclicTempogramMaxBPM) cyclicTempogramMaxBPM = m_tempogramMaxBPM;
c@22 582
c@22 583 m_cyclicTempogramNumberOfOctaves = floor(log2(cyclicTempogramMaxBPM/m_cyclicTempogramMinBPM));
c@22 584
c@22 585 return true;
c@22 586 }
c@22 587
c@22 588 string TempogramPlugin::floatToString(float value) const
c@22 589 {
c@22 590 ostringstream ss;
c@22 591
c@22 592 if(!(ss << value)) throw runtime_error("TempogramPlugin::floatToString(): invalid conversion from float to string");
c@22 593 return ss.str();
c@22 594 }