Mercurial > hg > vamp-tempogram
comparison TempogramPlugin.cpp @ 18:89bc9e5199d7
* Added Cyclic Tempogram output - very buggy right now!
| author | Carl Bussey <c.bussey@se10.qmul.ac.uk> |
|---|---|
| date | Thu, 14 Aug 2014 16:43:26 +0100 |
| parents | 203551cbad47 |
| children | e90a4797e579 |
comparison
equal
deleted
inserted
replaced
| 17:1e4c02ca8b81 | 18:89bc9e5199d7 |
|---|---|
| 12 using Vamp::RealTime; | 12 using Vamp::RealTime; |
| 13 using namespace std; | 13 using namespace std; |
| 14 | 14 |
| 15 TempogramPlugin::TempogramPlugin(float inputSampleRate) : | 15 TempogramPlugin::TempogramPlugin(float inputSampleRate) : |
| 16 Plugin(inputSampleRate), | 16 Plugin(inputSampleRate), |
| 17 m_blockSize(0), | 17 m_inputBlockSize(0), //host parameter |
| 18 m_stepSize(0), | 18 m_inputStepSize(0), //host parameter |
| 19 m_compressionConstant(1000), //parameter | 19 m_noveltyCurveMinDB(0), //set in initialise() |
| 20 m_minDB(0), | 20 m_noveltyCurveCompressionConstant(1000), //parameter |
| 21 m_log2WindowLength(10), //parameter | 21 m_tempogramLog2WindowLength(10), //parameter |
| 22 m_windowLength(pow((float)2,m_log2WindowLength)), | 22 m_tempogramWindowLength(pow((float)2,m_tempogramLog2WindowLength)), |
| 23 m_log2FftLength(m_log2WindowLength), | 23 m_tempogramLog2FftLength(m_tempogramLog2WindowLength), //parameter |
| 24 m_fftLength(m_windowLength), | 24 m_tempogramFftLength(m_tempogramWindowLength), |
| 25 m_log2HopSize(6), //parameter | 25 m_tempogramLog2HopSize(6), //parameter |
| 26 m_hopSize(pow((float)2,m_log2HopSize)), | 26 m_tempogramHopSize(pow((float)2,m_tempogramLog2HopSize)), |
| 27 m_minBPM(30), | 27 m_tempogramMinBPM(30), //parameter |
| 28 m_maxBPM(480), | 28 m_tempogramMaxBPM(480), //parameter |
| 29 m_minBin(0), //set in initialise() | 29 m_tempogramMinBin(0), //set in initialise() |
| 30 m_maxBin(0) //set in initialise() | 30 m_tempogramMaxBin(0), //set in initialise() |
| 31 m_cyclicTempogramMinBPM(30), //reset in initialise() | |
| 32 m_cyclicTempogramNumberOfOctaves(0), //set in initialise() | |
| 33 m_cyclicTempogramOctaveDivider(30) //parameter | |
| 31 | 34 |
| 32 // Also be sure to set your plugin parameters (presumably stored | 35 // Also be sure to set your plugin parameters (presumably stored |
| 33 // in member variables) to their default values here -- the host | 36 // in member variables) to their default values here -- the host |
| 34 // will not do that for you | 37 // will not do that for you |
| 35 { | 38 { |
| 189 } | 192 } |
| 190 list.push_back(d4); | 193 list.push_back(d4); |
| 191 | 194 |
| 192 ParameterDescriptor d5; | 195 ParameterDescriptor d5; |
| 193 d5.identifier = "minBPM"; | 196 d5.identifier = "minBPM"; |
| 194 d5.name = "Tempogram Minimum BPM"; | 197 d5.name = "(Cyclic) Tempogram Minimum BPM"; |
| 195 d5.description = "The minimum BPM of the tempogram output bins."; | 198 d5.description = "The minimum BPM of the tempogram output bins."; |
| 196 d5.unit = ""; | 199 d5.unit = ""; |
| 197 d5.minValue = 0; | 200 d5.minValue = 0; |
| 198 d5.maxValue = 2000; | 201 d5.maxValue = 2000; |
| 199 d5.defaultValue = 30; | 202 d5.defaultValue = 30; |
| 201 d5.quantizeStep = 5; | 204 d5.quantizeStep = 5; |
| 202 list.push_back(d5); | 205 list.push_back(d5); |
| 203 | 206 |
| 204 ParameterDescriptor d6; | 207 ParameterDescriptor d6; |
| 205 d6.identifier = "maxBPM"; | 208 d6.identifier = "maxBPM"; |
| 206 d6.name = "Tempogram Maximum BPM"; | 209 d6.name = "(Cyclic) Tempogram Maximum BPM"; |
| 207 d6.description = "The minimum BPM of the tempogram output bins."; | 210 d6.description = "The maximum BPM of the tempogram output bins."; |
| 208 d6.unit = ""; | 211 d6.unit = ""; |
| 209 d6.minValue = 30; | 212 d6.minValue = 30; |
| 210 d6.maxValue = 2000; | 213 d6.maxValue = 2000; |
| 211 d6.defaultValue = 480; | 214 d6.defaultValue = 480; |
| 212 d6.isQuantized = true; | 215 d6.isQuantized = true; |
| 213 d6.quantizeStep = 5; | 216 d6.quantizeStep = 5; |
| 214 list.push_back(d6); | 217 list.push_back(d6); |
| 218 | |
| 219 ParameterDescriptor d7; | |
| 220 d7.identifier = "octDiv"; | |
| 221 d7.name = "Cyclic Tempogram Octave Divider"; | |
| 222 d7.description = "The number bins within each octave."; | |
| 223 d7.unit = ""; | |
| 224 d7.minValue = 5; | |
| 225 d7.maxValue = 60; | |
| 226 d7.defaultValue = 30; | |
| 227 d7.isQuantized = true; | |
| 228 d7.quantizeStep = 1; | |
| 229 list.push_back(d7); | |
| 215 | 230 |
| 216 return list; | 231 return list; |
| 217 } | 232 } |
| 218 | 233 |
| 219 float | 234 float |
| 220 TempogramPlugin::getParameter(string identifier) const | 235 TempogramPlugin::getParameter(string identifier) const |
| 221 { | 236 { |
| 222 if (identifier == "C") { | 237 if (identifier == "C") { |
| 223 return m_compressionConstant; // return the ACTUAL current value of your parameter here! | 238 return m_noveltyCurveCompressionConstant; // return the ACTUAL current value of your parameter here! |
| 224 } | 239 } |
| 225 else if (identifier == "log2TN"){ | 240 else if (identifier == "log2TN"){ |
| 226 return m_log2WindowLength; | 241 return m_tempogramLog2WindowLength; |
| 227 } | 242 } |
| 228 else if (identifier == "log2HopSize"){ | 243 else if (identifier == "log2HopSize"){ |
| 229 return m_log2HopSize; | 244 return m_tempogramLog2HopSize; |
| 230 } | 245 } |
| 231 else if (identifier == "log2FftLength"){ | 246 else if (identifier == "log2FftLength"){ |
| 232 return m_log2FftLength; | 247 return m_tempogramLog2FftLength; |
| 233 } | 248 } |
| 234 else if (identifier == "minBPM") { | 249 else if (identifier == "minBPM") { |
| 235 return m_minBPM; | 250 return m_tempogramMinBPM; |
| 236 } | 251 } |
| 237 else if (identifier == "maxBPM"){ | 252 else if (identifier == "maxBPM"){ |
| 238 return m_maxBPM; | 253 return m_tempogramMaxBPM; |
| 254 } | |
| 255 else if (identifier == "octDiv"){ | |
| 256 return m_cyclicTempogramOctaveDivider; | |
| 239 } | 257 } |
| 240 | 258 |
| 241 return 0; | 259 return 0; |
| 242 } | 260 } |
| 243 | 261 |
| 244 void | 262 void |
| 245 TempogramPlugin::setParameter(string identifier, float value) | 263 TempogramPlugin::setParameter(string identifier, float value) |
| 246 { | 264 { |
| 247 | 265 |
| 248 if (identifier == "C") { | 266 if (identifier == "C") { |
| 249 m_compressionConstant = value; // set the actual value of your parameter | 267 m_noveltyCurveCompressionConstant = value; // set the actual value of your parameter |
| 250 } | 268 } |
| 251 else if (identifier == "log2TN") { | 269 else if (identifier == "log2TN") { |
| 252 m_windowLength = pow(2,value); | 270 m_tempogramWindowLength = pow(2,value); |
| 253 m_log2WindowLength = value; | 271 m_tempogramLog2WindowLength = value; |
| 254 } | 272 } |
| 255 else if (identifier == "log2HopSize"){ | 273 else if (identifier == "log2HopSize"){ |
| 256 m_hopSize = pow(2,value); | 274 m_tempogramHopSize = pow(2,value); |
| 257 m_log2HopSize = value; | 275 m_tempogramLog2HopSize = value; |
| 258 } | 276 } |
| 259 else if (identifier == "log2HopFftLength"){ | 277 else if (identifier == "log2FftLength"){ |
| 260 m_fftLength = pow(2,value); | 278 m_tempogramFftLength = pow(2,value); |
| 261 m_log2FftLength = value; | 279 m_tempogramLog2FftLength = value; |
| 262 } | 280 } |
| 263 else if (identifier == "minBPM") { | 281 else if (identifier == "minBPM") { |
| 264 m_minBPM = value; | 282 m_tempogramMinBPM = value; |
| 265 } | 283 } |
| 266 else if (identifier == "maxBPM"){ | 284 else if (identifier == "maxBPM"){ |
| 267 m_maxBPM = value; | 285 m_tempogramMaxBPM = value; |
| 286 } | |
| 287 else if (identifier == "octDiv"){ | |
| 288 m_cyclicTempogramOctaveDivider = value; | |
| 268 } | 289 } |
| 269 | 290 |
| 270 } | 291 } |
| 271 | 292 |
| 272 void TempogramPlugin::updateBPMParameters(){ | 293 void TempogramPlugin::updateBPMParameters(){ |
| 309 OutputList list; | 330 OutputList list; |
| 310 | 331 |
| 311 // See OutputDescriptor documentation for the possibilities here. | 332 // See OutputDescriptor documentation for the possibilities here. |
| 312 // Every plugin must have at least one output. | 333 // Every plugin must have at least one output. |
| 313 | 334 |
| 314 OutputDescriptor d; | 335 OutputDescriptor d1; |
| 315 float d_sampleRate; | 336 float d_sampleRate; |
| 316 float tempogramInputSampleRate = (float)m_inputSampleRate/m_stepSize; | 337 float tempogramInputSampleRate = (float)m_inputSampleRate/m_inputStepSize; |
| 317 | 338 |
| 318 d.identifier = "tempogram"; | 339 d1.identifier = "tempogram"; |
| 319 d.name = "Tempogram"; | 340 d1.name = "Tempogram"; |
| 320 d.description = "Tempogram"; | 341 d1.description = "Tempogram"; |
| 321 d.unit = "BPM"; | 342 d1.unit = "BPM"; |
| 322 d.hasFixedBinCount = true; | 343 d1.hasFixedBinCount = true; |
| 323 d.binCount = m_maxBin - m_minBin + 1; | 344 d1.binCount = m_tempogramMaxBin - m_tempogramMinBin + 1; |
| 324 d.hasKnownExtents = false; | 345 d1.hasKnownExtents = false; |
| 325 d.isQuantized = false; | 346 d1.isQuantized = false; |
| 326 d.sampleType = OutputDescriptor::FixedSampleRate; | 347 d1.sampleType = OutputDescriptor::FixedSampleRate; |
| 327 d_sampleRate = tempogramInputSampleRate/m_hopSize; | 348 d_sampleRate = tempogramInputSampleRate/m_tempogramHopSize; |
| 328 d.sampleRate = d_sampleRate > 0.0 && !isnan(d_sampleRate) ? d_sampleRate : 0.0; | 349 d1.sampleRate = d_sampleRate > 0.0 && !isnan(d_sampleRate) ? d_sampleRate : 0.0; |
| 329 for(int i = m_minBin; i <= (int)m_maxBin; i++){ | 350 for(int i = m_tempogramMinBin; i <= (int)m_tempogramMaxBin; i++){ |
| 330 float w = ((float)i/m_fftLength)*(tempogramInputSampleRate); | 351 float w = ((float)i/m_tempogramFftLength)*(tempogramInputSampleRate); |
| 331 d.binNames.push_back(floatToString(w*60)); | 352 d1.binNames.push_back(floatToString(w*60)); |
| 332 } | 353 } |
| 333 d.hasDuration = false; | 354 d1.hasDuration = false; |
| 334 list.push_back(d); | 355 list.push_back(d1); |
| 335 | 356 |
| 336 d.identifier = "nc"; | 357 OutputDescriptor d2; |
| 337 d.name = "Novelty Curve"; | 358 d2.identifier = "nc"; |
| 338 d.description = "Novelty Curve"; | 359 d2.name = "Novelty Curve"; |
| 339 d.unit = ""; | 360 d2.description = "Novelty Curve"; |
| 340 d.hasFixedBinCount = true; | 361 d2.unit = ""; |
| 341 d.binCount = 1; | 362 d2.hasFixedBinCount = true; |
| 342 d.hasKnownExtents = false; | 363 d2.binCount = 1; |
| 343 d.isQuantized = false; | 364 d2.hasKnownExtents = false; |
| 344 d.sampleType = OutputDescriptor::FixedSampleRate; | 365 d2.isQuantized = false; |
| 366 d2.sampleType = OutputDescriptor::FixedSampleRate; | |
| 345 d_sampleRate = tempogramInputSampleRate; | 367 d_sampleRate = tempogramInputSampleRate; |
| 346 d.sampleRate = d_sampleRate > 0 && !isnan(d_sampleRate) ? d_sampleRate : 0.0; | 368 d2.sampleRate = d_sampleRate > 0 && !isnan(d_sampleRate) ? d_sampleRate : 0; |
| 347 d.hasDuration = false; | 369 d2.hasDuration = false; |
| 348 list.push_back(d); | 370 list.push_back(d2); |
| 371 | |
| 372 OutputDescriptor d3; | |
| 373 d3.identifier = "cyclicTempogram"; | |
| 374 d3.name = "Cyclic Tempogram"; | |
| 375 d3.description = "Cyclic Tempogram"; | |
| 376 d3.unit = ""; | |
| 377 d3.hasFixedBinCount = true; | |
| 378 d3.binCount = m_cyclicTempogramOctaveDivider > 0 && !isnan(m_cyclicTempogramOctaveDivider) ? m_cyclicTempogramOctaveDivider : 0; | |
| 379 d3.hasKnownExtents = false; | |
| 380 d3.isQuantized = false; | |
| 381 d3.sampleType = OutputDescriptor::FixedSampleRate; | |
| 382 d_sampleRate = tempogramInputSampleRate/m_tempogramHopSize; | |
| 383 d3.sampleRate = d_sampleRate > 0.0 && !isnan(d_sampleRate) ? d_sampleRate : 0; | |
| 384 d3.hasDuration = false; | |
| 385 list.push_back(d3); | |
| 349 | 386 |
| 350 return list; | 387 return list; |
| 351 } | 388 } |
| 352 | 389 |
| 353 bool | 390 bool |
| 355 { | 392 { |
| 356 if (channels < getMinChannelCount() || | 393 if (channels < getMinChannelCount() || |
| 357 channels > getMaxChannelCount()) return false; | 394 channels > getMaxChannelCount()) return false; |
| 358 | 395 |
| 359 // Real initialisation work goes here! | 396 // Real initialisation work goes here! |
| 360 m_blockSize = blockSize; | 397 m_inputBlockSize = blockSize; |
| 361 m_stepSize = stepSize; | 398 m_inputStepSize = stepSize; |
| 362 m_minDB = pow(10,(float)-74/20); | 399 m_noveltyCurveMinDB = pow(10,(float)-74/20); |
| 363 | 400 |
| 364 if (m_fftLength < m_windowLength){ | 401 if (m_tempogramFftLength < m_tempogramWindowLength){ |
| 365 m_fftLength = m_windowLength; | 402 m_tempogramFftLength = m_tempogramWindowLength; |
| 366 } | 403 } |
| 367 if (m_minBPM > m_maxBPM){ | 404 if (m_tempogramMinBPM > m_tempogramMaxBPM){ |
| 368 m_minBPM = 30; | 405 m_tempogramMinBPM = 30; |
| 369 m_maxBPM = 480; | 406 m_tempogramMaxBPM = 480; |
| 370 } | 407 } |
| 371 float tempogramInputSampleRate = (float)m_inputSampleRate/m_stepSize; | 408 |
| 372 m_minBin = (unsigned int)(max(floor(((m_minBPM/60)/tempogramInputSampleRate)*m_fftLength), (float)0.0)); | 409 float tempogramInputSampleRate = (float)m_inputSampleRate/m_inputStepSize; |
| 373 m_maxBin = (unsigned int)(min(ceil(((m_maxBPM/60)/tempogramInputSampleRate)*m_fftLength), (float)m_fftLength/2)); | 410 m_tempogramMinBin = (unsigned int)(max(floor(((m_tempogramMinBPM/60)/tempogramInputSampleRate)*m_tempogramFftLength), (float)0.0)); |
| 374 | 411 m_tempogramMaxBin = (unsigned int)(min(ceil(((m_tempogramMaxBPM/60)/tempogramInputSampleRate)*m_tempogramFftLength), (float)m_tempogramFftLength/2)); |
| 375 m_spectrogram = SpectrogramTransposed(m_blockSize/2 + 1); | 412 |
| 413 if (m_tempogramMinBPM > m_cyclicTempogramMinBPM) m_cyclicTempogramMinBPM = m_tempogramMinBPM; | |
| 414 float cyclicTempogramMaxBPM = 480; | |
| 415 if (m_tempogramMaxBPM < cyclicTempogramMaxBPM) cyclicTempogramMaxBPM = m_tempogramMaxBPM; | |
| 416 | |
| 417 m_spectrogram = SpectrogramTransposed(m_inputBlockSize/2 + 1); | |
| 418 | |
| 419 m_cyclicTempogramNumberOfOctaves = floor(log2(cyclicTempogramMaxBPM/m_cyclicTempogramMinBPM)); | |
| 420 int numberOfBinsInFirstOctave = bpmToBin(m_cyclicTempogramMinBPM); | |
| 421 if (m_cyclicTempogramOctaveDivider < numberOfBinsInFirstOctave) m_cyclicTempogramOctaveDivider = numberOfBinsInFirstOctave; | |
| 376 | 422 |
| 377 return true; | 423 return true; |
| 378 } | 424 } |
| 379 | 425 |
| 380 void TempogramPlugin::cleanup(){ | 426 void TempogramPlugin::cleanup(){ |
| 383 | 429 |
| 384 void | 430 void |
| 385 TempogramPlugin::reset() | 431 TempogramPlugin::reset() |
| 386 { | 432 { |
| 387 // Clear buffers, reset stored values, etc | 433 // Clear buffers, reset stored values, etc |
| 388 ncTimestamps.clear(); | 434 m_spectrogram = SpectrogramTransposed(m_inputBlockSize/2 + 1); |
| 389 m_spectrogram = SpectrogramTransposed(m_blockSize/2 + 1); | |
| 390 } | 435 } |
| 391 | 436 |
| 392 TempogramPlugin::FeatureSet | 437 TempogramPlugin::FeatureSet |
| 393 TempogramPlugin::process(const float *const *inputBuffers, Vamp::RealTime timestamp) | 438 TempogramPlugin::process(const float *const *inputBuffers, Vamp::RealTime timestamp) |
| 394 { | 439 { |
| 395 size_t n = m_blockSize/2 + 1; | 440 size_t n = m_inputBlockSize/2 + 1; |
| 396 | 441 |
| 397 FeatureSet featureSet; | 442 FeatureSet featureSet; |
| 398 Feature feature; | 443 Feature feature; |
| 399 | 444 |
| 400 const float *in = inputBuffers[0]; | 445 const float *in = inputBuffers[0]; |
| 401 | 446 |
| 402 //calculate magnitude of FrequencyDomain input | 447 //calculate magnitude of FrequencyDomain input |
| 403 for (unsigned int i = 0; i < n; i++){ | 448 for (unsigned int i = 0; i < n; i++){ |
| 404 float magnitude = sqrt(in[2*i] * in[2*i] + in[2*i + 1] * in[2*i + 1]); | 449 float magnitude = sqrt(in[2*i] * in[2*i] + in[2*i + 1] * in[2*i + 1]); |
| 405 magnitude = magnitude > m_minDB ? magnitude : m_minDB; | 450 magnitude = magnitude > m_noveltyCurveMinDB ? magnitude : m_noveltyCurveMinDB; |
| 406 m_spectrogram[i].push_back(magnitude); | 451 m_spectrogram[i].push_back(magnitude); |
| 407 } | 452 } |
| 408 | |
| 409 ncTimestamps.push_back(timestamp); //save timestamp | |
| 410 | 453 |
| 411 return featureSet; | 454 return featureSet; |
| 455 } | |
| 456 | |
| 457 vector<unsigned int> TempogramPlugin::calculateTempogramNearestNeighbourLogBins() const | |
| 458 { | |
| 459 vector<unsigned int> logBins; | |
| 460 | |
| 461 for (int i = 0; i < (int)ceil(m_cyclicTempogramNumberOfOctaves*m_cyclicTempogramOctaveDivider); i++){ | |
| 462 float bpm = m_cyclicTempogramMinBPM*pow(2.0f, (float)i/m_cyclicTempogramOctaveDivider); | |
| 463 int bin = bpmToBin(bpm); | |
| 464 | |
| 465 logBins.push_back(bin); | |
| 466 } | |
| 467 | |
| 468 return logBins; | |
| 469 } | |
| 470 | |
| 471 int TempogramPlugin::bpmToBin(const float &bpm) const | |
| 472 { | |
| 473 float w = (float)bpm/60; | |
| 474 float sampleRate = m_inputSampleRate/m_inputStepSize; | |
| 475 int bin = floor((float)m_tempogramFftLength*w/sampleRate + 0.5); | |
| 476 | |
| 477 if(bin < 0) bin = 0; | |
| 478 else if(bin > m_tempogramFftLength/2) bin = m_tempogramFftLength; | |
| 479 | |
| 480 return bin; | |
| 412 } | 481 } |
| 413 | 482 |
| 414 TempogramPlugin::FeatureSet | 483 TempogramPlugin::FeatureSet |
| 415 TempogramPlugin::getRemainingFeatures() | 484 TempogramPlugin::getRemainingFeatures() |
| 416 { | 485 { |
| 417 | 486 |
| 418 float * hannWindow = new float[m_windowLength]; | 487 float * hannWindow = new float[m_tempogramWindowLength]; |
| 419 for (unsigned int i = 0; i < m_windowLength; i++){ | 488 for (unsigned int i = 0; i < m_tempogramWindowLength; i++){ |
| 420 hannWindow[i] = 0.0; | 489 hannWindow[i] = 0.0; |
| 421 } | 490 } |
| 422 | 491 |
| 423 FeatureSet featureSet; | 492 FeatureSet featureSet; |
| 424 | 493 |
| 425 //initialise m_noveltyCurve processor | 494 //initialise m_noveltyCurve processor |
| 426 size_t numberOfBlocks = m_spectrogram[0].size(); | 495 size_t numberOfBlocks = m_spectrogram[0].size(); |
| 427 NoveltyCurveProcessor nc(m_inputSampleRate, m_blockSize, numberOfBlocks, m_compressionConstant); | 496 NoveltyCurveProcessor nc(m_inputSampleRate, m_inputBlockSize, numberOfBlocks, m_noveltyCurveCompressionConstant); |
| 428 m_noveltyCurve = nc.spectrogramToNoveltyCurve(m_spectrogram); //calculate novelty curve from magnitude data | 497 m_noveltyCurve = nc.spectrogramToNoveltyCurve(m_spectrogram); //calculate novelty curve from magnitude data |
| 429 | 498 |
| 430 //push novelty curve data to featureset 1 and set timestamps | 499 //push novelty curve data to featureset 1 and set timestamps |
| 431 for (unsigned int i = 0; i < numberOfBlocks; i++){ | 500 for (unsigned int i = 0; i < numberOfBlocks; i++){ |
| 432 Feature feature; | 501 Feature feature; |
| 435 //feature.timestamp = ncTimestamps[i]; | 504 //feature.timestamp = ncTimestamps[i]; |
| 436 featureSet[1].push_back(feature); | 505 featureSet[1].push_back(feature); |
| 437 } | 506 } |
| 438 | 507 |
| 439 //window function for spectrogram | 508 //window function for spectrogram |
| 440 WindowFunction::hanning(hannWindow, m_windowLength); | 509 WindowFunction::hanning(hannWindow, m_tempogramWindowLength); |
| 441 | 510 |
| 442 //initialise spectrogram processor | 511 //initialise spectrogram processor |
| 443 SpectrogramProcessor spectrogramProcessor(m_windowLength, m_fftLength, m_hopSize); | 512 SpectrogramProcessor spectrogramProcessor(m_tempogramWindowLength, m_tempogramFftLength, m_tempogramHopSize); |
| 444 //compute spectrogram from novelty curve data (i.e., tempogram) | 513 //compute spectrogram from novelty curve data (i.e., tempogram) |
| 445 Spectrogram tempogram = spectrogramProcessor.process(&m_noveltyCurve[0], numberOfBlocks, hannWindow); | 514 Tempogram tempogram = spectrogramProcessor.process(&m_noveltyCurve[0], numberOfBlocks, hannWindow); |
| 446 | 515 delete []hannWindow; |
| 447 int timePointer = m_hopSize-m_windowLength/2; | 516 hannWindow = 0; |
| 517 | |
| 448 int tempogramLength = tempogram.size(); | 518 int tempogramLength = tempogram.size(); |
| 449 | 519 |
| 450 //push tempogram data to featureset 0 and set timestamps. | 520 //push tempogram data to featureset 0 and set timestamps. |
| 451 for (int block = 0; block < tempogramLength; block++){ | 521 for (int block = 0; block < tempogramLength; block++){ |
| 452 Feature feature; | 522 Feature feature; |
| 453 | 523 |
| 454 //int timeMS = floor(1000*(m_stepSize*timePointer)/m_inputSampleRate + 0.5); | 524 assert(tempogram[block].size() == (m_tempogramFftLength/2 + 1)); |
| 455 | 525 for(int k = m_tempogramMinBin; k < (int)m_tempogramMaxBin; k++){ |
| 456 assert(tempogram[block].size() == (m_fftLength/2 + 1)); | |
| 457 for(int k = m_minBin; k < (int)m_maxBin; k++){ | |
| 458 feature.values.push_back(tempogram[block][k]); | 526 feature.values.push_back(tempogram[block][k]); |
| 459 //cout << tempogram[k][block] << endl; | |
| 460 } | 527 } |
| 461 feature.hasTimestamp = false; | 528 feature.hasTimestamp = false; |
| 462 //feature.timestamp = RealTime::fromMilliseconds(timeMS); | |
| 463 featureSet[0].push_back(feature); | 529 featureSet[0].push_back(feature); |
| 530 } | |
| 531 | |
| 532 //Calculate cyclic tempogram | |
| 533 vector<unsigned int> logBins = calculateTempogramNearestNeighbourLogBins(); | |
| 534 Tempogram cyclicTempogram; | |
| 535 | |
| 536 for (int block = 0; block < tempogramLength; block++){ | |
| 537 Feature feature; | |
| 464 | 538 |
| 465 timePointer += m_hopSize; | 539 for (int i = 0; i < m_cyclicTempogramOctaveDivider; i++){ |
| 466 } | 540 float sum = 0; |
| 467 | 541 for (int j = 0; j < m_cyclicTempogramNumberOfOctaves; j++){ |
| 468 delete []hannWindow; | 542 sum += tempogram[block][logBins[i+j*m_cyclicTempogramOctaveDivider]]; |
| 469 hannWindow = 0; | 543 } |
| 544 feature.values.push_back(sum/m_cyclicTempogramNumberOfOctaves); | |
| 545 } | |
| 546 | |
| 547 feature.hasTimestamp = false; | |
| 548 | |
| 549 featureSet[2].push_back(feature); | |
| 550 } | |
| 470 | 551 |
| 471 return featureSet; | 552 return featureSet; |
| 472 } | 553 } |
