Mercurial > hg > btrack
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 { |