Mercurial > hg > vamp-tempogram
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 } |