comparison Tempogram.cpp @ 4:597f033fa7a2

* Some cleaning and rearranging to prepare for band processing implementation
author Carl Bussey <c.bussey@se10.qmul.ac.uk>
date Tue, 05 Aug 2014 15:56:59 +0100
parents 5125d34fda67
children 21147df9cb2d
comparison
equal deleted inserted replaced
3:5125d34fda67 4:597f033fa7a2
5 5
6 6
7 #include "Tempogram.h" 7 #include "Tempogram.h"
8 #include "FIRFilter.h" 8 #include "FIRFilter.h"
9 #include "WindowFunction.h" 9 #include "WindowFunction.h"
10 #include "NoveltyCurve.h"
10 #include <vamp-sdk/FFT.h> 11 #include <vamp-sdk/FFT.h>
11 #include <cmath> 12 #include <cmath>
12 #include <fstream> 13 #include <fstream>
13 #include <assert.h> 14 #include <assert.h>
15
14 using Vamp::FFT; 16 using Vamp::FFT;
15 using namespace std; 17 using namespace std;
16 18
17 Tempogram::Tempogram(float inputSampleRate) : 19 Tempogram::Tempogram(float inputSampleRate) :
18 Plugin(inputSampleRate), 20 Plugin(inputSampleRate),
20 m_stepSize(0), 22 m_stepSize(0),
21 compressionConstant(1000), //make param 23 compressionConstant(1000), //make param
22 specMax(0), 24 specMax(0),
23 previousY(NULL), 25 previousY(NULL),
24 currentY(NULL), 26 currentY(NULL),
27 spectrogram(NULL),
25 minDB(0), 28 minDB(0),
26 tN(1024), //make param 29 tN(256), //make param
27 thopSize(512), //make param 30 thopSize(128), //make param
28 fftInput(NULL), 31 fftInput(NULL),
29 fftOutputReal(NULL), 32 fftOutputReal(NULL),
30 fftOutputImag(NULL), 33 fftOutputImag(NULL),
31 numberOfBlocks(0), 34 numberOfBlocks(0)
32 hannN(0)
33 35
34 // Also be sure to set your plugin parameters (presumably stored 36 // Also be sure to set your plugin parameters (presumably stored
35 // in member variables) to their default values here -- the host 37 // in member variables) to their default values here -- the host
36 // will not do that for you 38 // will not do that for you
37 { 39 {
269 m_stepSize = stepSize; 271 m_stepSize = stepSize;
270 currentY = new float[m_blockSize]; 272 currentY = new float[m_blockSize];
271 previousY = new float[m_blockSize]; 273 previousY = new float[m_blockSize];
272 minDB = pow((float)10,(float)-74/20); 274 minDB = pow((float)10,(float)-74/20);
273 275
276 specData = vector< vector<float> >(m_blockSize/2 + 1);
277 spectrogram = new float * [m_blockSize/2 + 1];
278
274 return true; 279 return true;
275 } 280 }
276 281
277 void 282 void
278 Tempogram::reset() 283 Tempogram::reset()
281 } 286 }
282 287
283 Tempogram::FeatureSet 288 Tempogram::FeatureSet
284 Tempogram::process(const float *const *inputBuffers, Vamp::RealTime timestamp) 289 Tempogram::process(const float *const *inputBuffers, Vamp::RealTime timestamp)
285 { 290 {
291
286 size_t n = m_blockSize/2 + 1; 292 size_t n = m_blockSize/2 + 1;
287 293
288 FeatureSet featureSet; 294 FeatureSet featureSet;
289 Feature feature; 295 Feature feature;
290 296
291 const float *in = inputBuffers[0]; 297 const float *in = inputBuffers[0];
292 298
293 for (int i = 0; i < n; i++){ 299 for (int i = 0; i < n; i++){
294 float magnitude = sqrt(in[2*i] * in[2*i] + in[2*i + 1] * in[2*i + 1]); 300 float magnitude = sqrt(in[2*i] * in[2*i] + in[2*i + 1] * in[2*i + 1]);
295 magnitude = magnitude > minDB ? magnitude : minDB; 301 magnitude = magnitude > minDB ? magnitude : minDB;
296 specData.push_back(magnitude); 302 specData[i].push_back(magnitude);
297 feature.values.push_back(magnitude); 303 feature.values.push_back(magnitude);
298
299 specMax = specMax > magnitude ? specMax : magnitude;
300 } 304 }
301 305
302 numberOfBlocks++; 306 numberOfBlocks++;
303 ncTimestamps.push_back(timestamp); 307 ncTimestamps.push_back(timestamp);
304 featureSet[2].push_back(feature); 308 featureSet[2].push_back(feature);
306 return featureSet; 310 return featureSet;
307 } 311 }
308 312
309 void 313 void
310 Tempogram::initialiseForGRF(){ 314 Tempogram::initialiseForGRF(){
311 hannN = 129;
312 hannWindow = new float[hannN];
313 hannWindowtN = new float[tN]; 315 hannWindowtN = new float[tN];
314 fftInput = new double[tN]; 316 fftInput = new double[tN];
315 fftOutputReal = new double[tN]; 317 fftOutputReal = new double[tN];
316 fftOutputImag = new double[tN]; 318 fftOutputImag = new double[tN];
317 319
318 WindowFunction::hanning(hannWindow, hannN, true); 320 for (int i = 0; i < (m_blockSize/2 + 1); i ++){
321 spectrogram[i] = &specData[i][0];
322 }
319 } 323 }
320 324
321 void 325 void
322 Tempogram::cleanupForGRF(){ 326 Tempogram::cleanupForGRF(){
323 delete []hannWindow;
324 hannWindow = NULL;
325 delete []hannWindowtN; 327 delete []hannWindowtN;
326 hannWindowtN = NULL; 328 hannWindowtN = NULL;
327 delete []fftInput; 329 delete []fftInput;
328 fftInput = NULL; 330 fftInput = NULL;
329 delete []fftOutputReal; 331 delete []fftOutputReal;
330 fftOutputReal = NULL; 332 fftOutputReal = NULL;
331 delete []fftOutputImag; 333 delete []fftOutputImag;
332 fftOutputImag = NULL; 334 fftOutputImag = NULL;
333 } 335 }
334 336
335 vector<float>
336 Tempogram::spectrogramToNoveltyCurve(vector<float> spectrogram, int numberOfBlocks, int blockSize, float samplingFrequency, FeatureSet * featureSet){
337 int numberOfBands = 5;
338
339 for (int block = 0; block < numberOfBlocks; block++){
340 vector<float> sum = vector<float>(numberOfBands);
341
342 int band = 0;
343 for (int k = 0; k < blockSize; k++){
344 int index = block*blockSize + k;
345
346 if(index > 500*pow(2.5, band))
347 if(band < numberOfBands)
348 band++;
349
350 specData[index] = log(1+compressionConstant*(specData[index]/specMax));
351
352 float currentY = specData[index];
353 float prevI = index - m_blockSize;
354 float previousY = prevI >= 0 ? specData[prevI] : 0;
355
356 if(currentY >= previousY){
357 sum[band] += (currentY - previousY);
358 }
359 }
360
361 float total = 0;
362 for(int band = 0; band < numberOfBands; band++){
363 total += sum[band];
364 }
365 float average = total/numberOfBands;
366
367 noveltyCurve.push_back(average);
368 }
369
370 vector<float> noveltyCurveLocalAverage(numberOfBlocks);
371
372 FIRFilter *filter = new FIRFilter(numberOfBlocks, hannN);
373 filter->process(&noveltyCurve[0], hannWindow, &noveltyCurveLocalAverage[0]);
374 delete filter;
375
376 for (int i = 0; i < numberOfBlocks; i++){
377
378 noveltyCurve[i] -= noveltyCurveLocalAverage[i];
379 noveltyCurve[i] = noveltyCurve[i] >= 0 ? noveltyCurve[i] : 0;
380
381 if(featureSet != NULL){
382 Feature ncFeature;
383 ncFeature.hasTimestamp = true;
384 ncFeature.timestamp = ncTimestamps[i];
385 ncFeature.values.push_back(noveltyCurve[i]);
386 (*featureSet)[1].push_back(ncFeature);
387 }
388 }
389
390 return noveltyCurve;
391 }
392
393 Tempogram::FeatureSet 337 Tempogram::FeatureSet
394 Tempogram::getRemainingFeatures() 338 Tempogram::getRemainingFeatures()
395 { 339 {
396 //Make sure this is called at the beginning of the function 340 //Make sure this is called at the beginning of the function
397 initialiseForGRF(); 341 initialiseForGRF();
398 FeatureSet featureSet; 342 FeatureSet featureSet;
399 343
400 noveltyCurve = spectrogramToNoveltyCurve(specData, numberOfBlocks, m_blockSize, m_inputSampleRate, &featureSet); 344 NoveltyCurve nc(m_inputSampleRate, m_blockSize, numberOfBlocks, compressionConstant);
345 noveltyCurve = nc.spectrogramToNoveltyCurve(spectrogram);
346
347 for (int i = 0; i < numberOfBlocks; i++){
348 Feature featureNC;
349 cout << "nc:" << noveltyCurve[i] << endl;
350 featureNC.values.push_back(noveltyCurve[i]);
351 featureNC.hasTimestamp = true;
352 featureNC.timestamp = ncTimestamps[i];
353 featureSet[1].push_back(featureNC);
354 }
355
401 WindowFunction::hanning(hannWindowtN, tN); 356 WindowFunction::hanning(hannWindowtN, tN);
402 357
403 int timestampInc = floor((((float)ncTimestamps[1].nsec - ncTimestamps[0].nsec)/1e9)*(thopSize) + 0.5); 358 int timestampInc = floor((((float)ncTimestamps[1].nsec - ncTimestamps[0].nsec)/1e9)*(thopSize) + 0.5);
404 int i = 0; 359 int i = 0;
405 int index; 360 int index;
406 int frameBeginOffset = floor(tN/2 + 0.5); 361 int frameBeginOffset = thopSize;
407 362
408 while(i < numberOfBlocks){ 363 while(i < numberOfBlocks){
409 Feature feature; 364 Feature feature;
410 365
411 for (int n = frameBeginOffset; n < tN; n++){ 366 for (int n = frameBeginOffset; n < tN; n++){
412 index = i + n - tN/2; 367 index = i + n - thopSize;
413 assert (index >= 0); 368 assert (index >= 0);
414 369
415 if(index < numberOfBlocks){ 370 if(index < numberOfBlocks){
416 fftInput[n] = noveltyCurve[i + n] * hannWindowtN[n]; 371 fftInput[n] = noveltyCurve[i + n] * hannWindowtN[n];
417 } 372 }
418 else if(index >= numberOfBlocks){ 373 else if(index >= numberOfBlocks){
419 fftInput[n] = 0.0; //pad the end with zeros 374 fftInput[n] = 0.0; //pad the end with zeros
420 } 375 }
421 //cout << fftInput[n] << endl;
422 } 376 }
423 if (i+tN/2 > numberOfBlocks){ 377
378 if (i+thopSize > numberOfBlocks){
424 feature.timestamp = Vamp::RealTime::fromSeconds(ncTimestamps[i].sec + timestampInc); 379 feature.timestamp = Vamp::RealTime::fromSeconds(ncTimestamps[i].sec + timestampInc);
425 } 380 }
426 else{ 381 else{
427 feature.timestamp = ncTimestamps[i + tN/2]; 382 feature.timestamp = ncTimestamps[i + thopSize];
428 } 383 }
429 384
430 FFT::forward(tN, fftInput, NULL, fftOutputReal, fftOutputImag); 385 FFT::forward(tN, fftInput, NULL, fftOutputReal, fftOutputImag);
431 386
432 //TODO: sample at logarithmic spacing 387 //@todo: sample at logarithmic spacing? Leave for host?
433 for(int k = 0; k < tN; k++){ 388 for(int k = 0; k < tN; k++){
434 float fftOutputPower = (fftOutputReal[k]*fftOutputReal[k] + fftOutputImag[k]*fftOutputImag[k]); //Magnitude or power? 389 float fftOutputPower = (fftOutputReal[k]*fftOutputReal[k] + fftOutputImag[k]*fftOutputImag[k]); //Magnitude or power?
435 390
436 feature.values.push_back(fftOutputPower); 391 feature.values.push_back(fftOutputPower);
437 } 392 }