comparison src/BTrack.cpp @ 88:995ddf0eadd4

Implemented frequency domain calculation of the auto-correlation function, rather than old the time domain method. Makes for a very small (max 5%) speed up overall for the algorithm
author Adam Stark <adamstark.uk@gmail.com>
date Sat, 30 Jan 2016 23:55:13 +0000
parents 866024f9f95a
children 5ef334c782f3
comparison
equal deleted inserted replaced
86:5eeabb24d677 88:995ddf0eadd4
41 { 41 {
42 initialise(hopSize_, frameSize_); 42 initialise(hopSize_, frameSize_);
43 } 43 }
44 44
45 //======================================================================= 45 //=======================================================================
46 BTrack::~BTrack()
47 {
48 // destroy fft plan
49 fftw_destroy_plan(acfForwardFFT);
50 fftw_destroy_plan(acfBackwardFFT);
51 fftw_free(complexIn);
52 fftw_free(complexOut);
53 }
54
55 //=======================================================================
46 double BTrack::getBeatTimeInSeconds(long frameNumber,int hopSize,int fs) 56 double BTrack::getBeatTimeInSeconds(long frameNumber,int hopSize,int fs)
47 { 57 {
48 double hop = (double) hopSize; 58 double hop = (double) hopSize;
49 double samplingFrequency = (double) fs; 59 double samplingFrequency = (double) fs;
50 double frameNum = (double) frameNumber; 60 double frameNum = (double) frameNumber;
116 // in case it is requested before any processing takes place 126 // in case it is requested before any processing takes place
117 latestCumulativeScoreValue = 0; 127 latestCumulativeScoreValue = 0;
118 128
119 // initialise algorithm given the hopsize 129 // initialise algorithm given the hopsize
120 setHopSize(hopSize_); 130 setHopSize(hopSize_);
131
132
133 // Set up FFT for calculating the auto-correlation function
134 FFTLengthForACFCalculation = 1024;
135
136 complexIn = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * FFTLengthForACFCalculation); // complex array to hold fft data
137 complexOut = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * FFTLengthForACFCalculation); // complex array to hold fft data
138
139 acfForwardFFT = fftw_plan_dft_1d(FFTLengthForACFCalculation, complexIn, complexOut, FFTW_FORWARD, FFTW_ESTIMATE); // FFT plan initialisation
140 acfBackwardFFT = fftw_plan_dft_1d(FFTLengthForACFCalculation, complexOut, complexIn, FFTW_BACKWARD, FFTW_ESTIMATE); // FFT plan initialisation
121 } 141 }
122 142
123 //======================================================================= 143 //=======================================================================
124 void BTrack::setHopSize(int hopSize_) 144 void BTrack::setHopSize(int hopSize_)
125 { 145 {
527 } 547 }
528 548
529 //======================================================================= 549 //=======================================================================
530 void BTrack::calculateBalancedACF(double *onsetDetectionFunction) 550 void BTrack::calculateBalancedACF(double *onsetDetectionFunction)
531 { 551 {
532 int l, n = 0; 552 int onsetDetectionFunctionLength = 512;
533 double sum, tmp; 553
534 554 // copy into complex array and zero pad
535 // for l lags from 0-511 555 for (int i = 0;i < FFTLengthForACFCalculation;i++)
536 for (l = 0;l < 512;l++) 556 {
537 { 557 if (i < onsetDetectionFunctionLength)
538 sum = 0; 558 {
539 559 complexIn[i][0] = onsetDetectionFunction[i];
540 // for n samples from 0 - (512-lag) 560 complexIn[i][1] = 0.0;
541 for (n = 0;n < (512-l);n++) 561 }
542 { 562 else
543 tmp = onsetDetectionFunction[n] * onsetDetectionFunction[n+l]; // multiply current sample n by sample (n+l) 563 {
544 sum = sum + tmp; // add to sum 564 complexIn[i][0] = 0.0;
545 } 565 complexIn[i][1] = 0.0;
546 566 }
547 acf[l] = sum / (512-l); // weight by number of mults and add to acf buffer 567 }
548 } 568
569 // perform the fft
570 fftw_execute(acfForwardFFT);
571
572 // multiply by complex conjugate
573 for (int i = 0;i < FFTLengthForACFCalculation;i++)
574 {
575 complexOut[i][0] = complexOut[i][0]*complexOut[i][0] + complexOut[i][1]*complexOut[i][1];
576 complexOut[i][1] = 0.0;
577 }
578
579 // perform the ifft
580 fftw_execute(acfBackwardFFT);
581
582
583 double lag = 512;
584
585 for (int i = 0;i < 512;i++)
586 {
587 // calculate absolute value of result
588 double absValue = sqrt(complexIn[i][0]*complexIn[i][0] + complexIn[i][1]*complexIn[i][1]);
589
590 // divide by inverse lad to deal with scale bias towards small lags
591 acf[i] = absValue / lag;
592
593 // this division by 1024 is technically unnecessary but it ensures the algorithm produces
594 // exactly the same ACF output as the old time domain implementation. The time difference is
595 // minimal so I decided to keep it
596 acf[i] = acf[i] / 1024.;
597
598 lag = lag - 1.;
599 }
549 } 600 }
550 601
551 //======================================================================= 602 //=======================================================================
552 double BTrack::calculateMeanOfArray(double *array,int startIndex,int endIndex) 603 double BTrack::calculateMeanOfArray(double *array,int startIndex,int endIndex)
553 { 604 {