Mercurial > hg > vamp-tempogram
changeset 13:7680cc4c0073
* Tidying - made length of array variables type size_t and for loops unsigned int, where index > 0.
* Window length parameter is now a dropdown box.
author | Carl Bussey <c.bussey@se10.qmul.ac.uk> |
---|---|
date | Wed, 13 Aug 2014 14:18:00 +0100 |
parents | d58409ecd720 |
children | c11367df624d |
files | FIRFilter.cpp FIRFilter.h NoveltyCurve.cpp NoveltyCurve.h Spectrogram.cpp Spectrogram.h Tempogram.cpp Tempogram.h WindowFunction.cpp WindowFunction.h |
diffstat | 10 files changed, 243 insertions(+), 230 deletions(-) [+] |
line wrap: on
line diff
--- a/FIRFilter.cpp Wed Aug 13 10:47:39 2014 +0100 +++ b/FIRFilter.cpp Wed Aug 13 14:18:00 2014 +0100 @@ -11,19 +11,19 @@ using namespace std; using Vamp::FFT; -FIRFilter::FIRFilter(const unsigned int lengthInput, const unsigned int numberOfCoefficients) : +FIRFilter::FIRFilter(const size_t &lengthInput, const size_t &numberOfCoefficients) : m_lengthInput(lengthInput), m_numberOfCoefficients(numberOfCoefficients), - fftInput(0), - fftCoefficients(0), - fftReal1(0), - fftImag1(0), - fftReal2(0), - fftImag2(0), - fftFilteredReal(0), - fftFilteredImag(0), - fftOutputReal(0), - fftOutputImag(0) + m_pFftInput(0), + m_pFftCoefficients(0), + m_pFftReal1(0), + m_pFftImag1(0), + m_pFftReal2(0), + m_pFftImag2(0), + m_pFftFilteredReal(0), + m_pFftFilteredImag(0), + m_pFftOutputReal(0), + m_pFftOutputImag(0) { initialise(); } @@ -40,44 +40,45 @@ //next power of 2 m_lengthFIRFFT = pow(2,(ceil(log2(m_lengthInput+m_numberOfCoefficients-1)))); - fftInput = new double[m_lengthFIRFFT]; - fftCoefficients = new double[m_lengthFIRFFT]; - fftReal1 = new double[m_lengthFIRFFT]; - fftImag1 = new double[m_lengthFIRFFT]; - fftReal2 = new double[m_lengthFIRFFT]; - fftImag2 = new double[m_lengthFIRFFT]; - fftFilteredReal = new double[m_lengthFIRFFT]; - fftFilteredImag = new double[m_lengthFIRFFT]; - fftOutputReal = new double[m_lengthFIRFFT]; - fftOutputImag = new double[m_lengthFIRFFT]; + m_pFftInput = new double[m_lengthFIRFFT]; + m_pFftCoefficients = new double[m_lengthFIRFFT]; + m_pFftReal1 = new double[m_lengthFIRFFT]; + m_pFftImag1 = new double[m_lengthFIRFFT]; + m_pFftReal2 = new double[m_lengthFIRFFT]; + m_pFftImag2 = new double[m_lengthFIRFFT]; + m_pFftFilteredReal = new double[m_lengthFIRFFT]; + m_pFftFilteredImag = new double[m_lengthFIRFFT]; + m_pFftOutputReal = new double[m_lengthFIRFFT]; + m_pFftOutputImag = new double[m_lengthFIRFFT]; - for(int i = 0; i < m_lengthFIRFFT; i++){ - fftInput[i] = fftCoefficients[i] = fftReal1[i] = fftImag1[i] = fftReal2[i] = fftImag2[i] = fftFilteredReal[i] = fftFilteredImag[i] = fftOutputReal[i] = fftOutputImag[i] = 0.0; + for(unsigned int i = 0; i < m_lengthFIRFFT; i++){ + m_pFftInput[i] = m_pFftCoefficients[i] = m_pFftReal1[i] = m_pFftImag1[i] = m_pFftReal2[i] = m_pFftImag2[i] = m_pFftFilteredReal[i] = m_pFftFilteredImag[i] = m_pFftOutputReal[i] = m_pFftOutputImag[i] = 0.0; } } void -FIRFilter::process(const float* input, const float* coefficients, float* output) +FIRFilter::process(const float* pInput, const float* pCoefficients, float* pOutput) { //Copy to same length FFT buffers - for(int i = 0; i < m_lengthFIRFFT; i++){ - fftInput[i] = i < m_lengthInput ? input[i] : 0.0; - fftCoefficients[i] = i < m_numberOfCoefficients ? coefficients[i] : 0.0; + for(unsigned int i = 0; i < m_lengthFIRFFT; i++){ + m_pFftInput[i] = i < m_lengthInput ? pInput[i] : 0.0; + m_pFftCoefficients[i] = i < m_numberOfCoefficients ? pCoefficients[i] : 0.0; } - FFT::forward(m_lengthFIRFFT, fftInput, 0, fftReal1, fftImag1); - FFT::forward(m_lengthFIRFFT, fftCoefficients, 0, fftReal2, fftImag2); + FFT::forward(m_lengthFIRFFT, m_pFftInput, 0, m_pFftReal1, m_pFftImag1); + FFT::forward(m_lengthFIRFFT, m_pFftCoefficients, 0, m_pFftReal2, m_pFftImag2); //Multiply FFT coefficients. Multiplication in freq domain is convolution in time domain. - for (int i = 0; i < m_lengthFIRFFT; i++){ - fftFilteredReal[i] = (fftReal1[i] * fftReal2[i]) - (fftImag1[i] * fftImag2[i]); - fftFilteredImag[i] = (fftReal1[i] * fftImag2[i]) + (fftReal2[i] * fftImag1[i]); + for (unsigned int i = 0; i < m_lengthFIRFFT; i++){ + m_pFftFilteredReal[i] = (m_pFftReal1[i] * m_pFftReal2[i]) - (m_pFftImag1[i] * m_pFftImag2[i]); + m_pFftFilteredImag[i] = (m_pFftReal1[i] * m_pFftImag2[i]) + (m_pFftReal2[i] * m_pFftImag1[i]); } - FFT::inverse(m_lengthFIRFFT, fftFilteredReal, fftFilteredImag, fftOutputReal, fftOutputImag); + + FFT::inverse(m_lengthFIRFFT, m_pFftFilteredReal, m_pFftFilteredImag, m_pFftOutputReal, m_pFftOutputImag); //copy to output - for (int i = 0; i < m_lengthInput; i++){ - output[i] = fftOutputReal[i]; + for (unsigned int i = 0; i < m_lengthInput; i++){ + pOutput[i] = m_pFftOutputReal[i]; } } @@ -85,15 +86,15 @@ void FIRFilter::cleanup() { - delete []fftInput; - delete []fftCoefficients; - delete []fftReal1; - delete []fftImag1; - delete []fftReal2; - delete []fftImag2; - delete []fftFilteredReal; - delete []fftFilteredImag; - delete []fftOutputReal; - delete []fftOutputImag; - fftInput = fftCoefficients = fftReal1 = fftImag1 = fftReal2 = fftImag2 = fftFilteredReal = fftFilteredImag = fftOutputReal = fftOutputImag = 0; + delete []m_pFftInput; + delete []m_pFftCoefficients; + delete []m_pFftReal1; + delete []m_pFftImag1; + delete []m_pFftReal2; + delete []m_pFftImag2; + delete []m_pFftFilteredReal; + delete []m_pFftFilteredImag; + delete []m_pFftOutputReal; + delete []m_pFftOutputImag; + m_pFftInput = m_pFftCoefficients = m_pFftReal1 = m_pFftImag1 = m_pFftReal2 = m_pFftImag2 = m_pFftFilteredReal = m_pFftFilteredImag = m_pFftOutputReal = m_pFftOutputImag = 0; }
--- a/FIRFilter.h Wed Aug 13 10:47:39 2014 +0100 +++ b/FIRFilter.h Wed Aug 13 14:18:00 2014 +0100 @@ -15,24 +15,24 @@ class FIRFilter{ public: - FIRFilter(const unsigned int lengthInput, const unsigned int numberOfCoefficients); + FIRFilter(const size_t &lengthInput, const size_t &numberOfCoefficients); ~FIRFilter(); - void process(const float *input, const float *coefficients, float *output); + void process(const float *pInput, const float *pCoefficients, float * pOutput); private: - unsigned int m_lengthInput; - unsigned int m_numberOfCoefficients; - unsigned int m_lengthFIRFFT; + size_t m_lengthInput; + size_t m_numberOfCoefficients; + int m_lengthFIRFFT; - double *fftInput; - double *fftCoefficients; - double *fftReal1; - double *fftImag1; - double *fftReal2; - double *fftImag2; - double *fftFilteredReal; - double *fftFilteredImag; - double *fftOutputReal; - double *fftOutputImag; + double *m_pFftInput; + double *m_pFftCoefficients; + double *m_pFftReal1; + double *m_pFftImag1; + double *m_pFftReal2; + double *m_pFftImag2; + double *m_pFftFilteredReal; + double *m_pFftFilteredImag; + double *m_pFftOutputReal; + double *m_pFftOutputImag; void initialise(); void cleanup();
--- a/NoveltyCurve.cpp Wed Aug 13 10:47:39 2014 +0100 +++ b/NoveltyCurve.cpp Wed Aug 13 14:18:00 2014 +0100 @@ -12,16 +12,15 @@ #include <memory> using namespace std; -NoveltyCurve::NoveltyCurve(float samplingFrequency, int fftLength, int numberOfBlocks, int compressionConstant) : +NoveltyCurve::NoveltyCurve(const float &samplingFrequency, const size_t &fftLength, const size_t &numberOfBlocks, const size_t &compressionConstant) : m_samplingFrequency(samplingFrequency), m_fftLength(fftLength), m_blockSize(fftLength/2 + 1), m_numberOfBlocks(numberOfBlocks), m_compressionConstant(compressionConstant), m_numberOfBands(5), - m_bandBoundaries(NULL), - m_hannLength(65), - m_bandSum(NULL) + m_pBandBoundaries(0), + m_pBandSum(0) { initialise(); } @@ -33,35 +32,35 @@ //allocate all space and set variable void NoveltyCurve::initialise(){ - data = vector<float>(m_numberOfBlocks); - // for bandwise processing, the band is split into 5 bands. m_bandBoundaries contains the upper and lower bin boundaries for each band. - m_bandBoundaries = new int[m_numberOfBands+1]; - m_bandBoundaries[0] = 0; - for (int band = 1; band < m_numberOfBands; band++){ - float lowFreq = 500*pow(2.5, band-1); - m_bandBoundaries[band] = m_fftLength*lowFreq/m_samplingFrequency; + // for bandwise processing, the band is split into 5 bands. m_pBandBoundaries contains the upper and lower bin boundaries for each band. + m_pBandBoundaries = new int[m_numberOfBands+1]; + m_pBandBoundaries[0] = 0; + for (unsigned int band = 1; band < m_numberOfBands; band++){ + float lowFreq = 500*pow(2.5, (int)band-1); + m_pBandBoundaries[band] = m_fftLength*lowFreq/m_samplingFrequency; } - m_bandBoundaries[m_numberOfBands] = m_blockSize; + m_pBandBoundaries[m_numberOfBands] = m_blockSize; - m_bandSum = new float [m_numberOfBands]; + m_pBandSum = new float [m_numberOfBands]; } //delete space allocated in initialise() void NoveltyCurve::cleanup(){ - delete []m_bandBoundaries; - m_bandBoundaries = NULL; - delete []m_bandSum; - m_bandSum = NULL; + delete []m_pBandBoundaries; + m_pBandBoundaries = 0; + delete []m_pBandSum; + m_pBandSum = 0; } //calculate max of spectrogram -float NoveltyCurve::calculateMax(vector< vector<float> > &spectrogram){ +float NoveltyCurve::calculateMax(const vector< vector<float> > &spectrogram) const +{ float max = 0; - for (int j = 0; j < m_numberOfBlocks; j++){ - for (int i = 0; i < m_blockSize; i++){ + for (unsigned int j = 0; j < m_numberOfBlocks; j++){ + for (unsigned int i = 0; i < m_blockSize; i++){ max = max > fabs(spectrogram[i][j]) ? max : fabs(spectrogram[i][j]); } } @@ -71,48 +70,50 @@ //subtract local average of novelty curve //uses m_hannWindow as filter -void NoveltyCurve::subtractLocalAverage(vector<float> &noveltyCurve){ +void NoveltyCurve::subtractLocalAverage(vector<float> &noveltyCurve, const size_t &smoothLength) const +{ vector<float> localAverage(m_numberOfBlocks); - float * m_hannWindow = new float[m_hannLength]; - WindowFunction::hanning(m_hannWindow, m_hannLength, true); + float * m_hannWindow = new float[smoothLength]; + WindowFunction::hanning(m_hannWindow, smoothLength, true); - FIRFilter filter(m_numberOfBlocks, m_hannLength); + FIRFilter filter(m_numberOfBlocks, smoothLength); filter.process(&noveltyCurve[0], m_hannWindow, &localAverage[0]); assert(noveltyCurve.size() == m_numberOfBlocks); - for (int i = 0; i < m_numberOfBlocks; i++){ + for (unsigned int i = 0; i < m_numberOfBlocks; i++){ noveltyCurve[i] -= localAverage[i]; noveltyCurve[i] = noveltyCurve[i] >= 0 ? noveltyCurve[i] : 0; } delete []m_hannWindow; - m_hannWindow = NULL; + m_hannWindow = 0; } //smoothed differentiator filter. Flips upper half of hanning window about y-axis to create coefficients. -void NoveltyCurve::smoothedDifferentiator(vector< vector<float> > &spectrogram, int smoothLength){ +void NoveltyCurve::smoothedDifferentiator(vector< vector<float> > &spectrogram, const size_t &smoothLength) const +{ float * diffHannWindow = new float [smoothLength]; WindowFunction::hanning(diffHannWindow, smoothLength, true); if(smoothLength%2) diffHannWindow[(smoothLength+1)/2 - 1] = 0; - for(int i = (smoothLength+1)/2; i < smoothLength; i++){ + for(unsigned int i = (smoothLength+1)/2; i < smoothLength; i++){ diffHannWindow[i] = -diffHannWindow[i]; } FIRFilter smoothFilter(m_numberOfBlocks, smoothLength); - for (int i = 0; i < m_blockSize; i++){ + for (unsigned int i = 0; i < m_blockSize; i++){ smoothFilter.process(&spectrogram[i][0], diffHannWindow, &spectrogram[i][0]); } } //half rectification (set negative to zero) -void NoveltyCurve::halfWaveRectify(vector< vector<float> > &spectrogram){ - - for (int block = 0; block < m_numberOfBlocks; block++){ - for (int k = 0; k < m_blockSize; k++){ +void NoveltyCurve::halfWaveRectify(vector< vector<float> > &spectrogram) const +{ + for (unsigned int block = 0; block < m_numberOfBlocks; block++){ + for (unsigned int k = 0; k < m_blockSize; k++){ if (spectrogram[k][block] < 0.0) spectrogram[k][block] = 0.0; } } @@ -120,15 +121,17 @@ //process method vector<float> -NoveltyCurve::spectrogramToNoveltyCurve(vector< vector<float> > spectrogram){ +NoveltyCurve::spectrogramToNoveltyCurve(Spectrogram spectrogram) const +{ + std::vector<float> noveltyCurve(m_numberOfBlocks); assert(spectrogram.size() == m_blockSize); assert(spectrogram[0].size() == m_numberOfBlocks); //normalise and log spectrogram float normaliseScale = calculateMax(spectrogram); - for (int block = 0; block < m_numberOfBlocks; block++){ - for (int k = 0; k < m_blockSize; k++){ + for (unsigned int block = 0; block < m_numberOfBlocks; block++){ + for (unsigned int k = 0; k < m_blockSize; k++){ if(normaliseScale != 0.0) spectrogram[k][block] /= normaliseScale; //normalise spectrogram[k][block] = log(1+m_compressionConstant*spectrogram[k][block]); } @@ -140,26 +143,26 @@ halfWaveRectify(spectrogram); //bandwise processing - for (int block = 0; block < m_numberOfBlocks; block++){ - for (int band = 0; band < m_numberOfBands; band++){ - int k = m_bandBoundaries[band]; - int bandEnd = m_bandBoundaries[band+1]; - m_bandSum[band] = 0; + for (unsigned int block = 0; block < m_numberOfBlocks; block++){ + for (unsigned int band = 0; band < m_numberOfBands; band++){ + int k = m_pBandBoundaries[band]; + int bandEnd = m_pBandBoundaries[band+1]; + m_pBandSum[band] = 0; while(k < bandEnd){ - m_bandSum[band] += spectrogram[k][block]; + m_pBandSum[band] += spectrogram[k][block]; k++; } } float total = 0; - for(int band = 0; band < m_numberOfBands; band++){ - total += m_bandSum[band]; + for(unsigned int band = 0; band < m_numberOfBands; band++){ + total += m_pBandSum[band]; } - data[block] = total/m_numberOfBands; + noveltyCurve[block] = total/m_numberOfBands; } //subtract local averages - subtractLocalAverage(data); + subtractLocalAverage(noveltyCurve, 65); - return data; + return noveltyCurve; }
--- a/NoveltyCurve.h Wed Aug 13 10:47:39 2014 +0100 +++ b/NoveltyCurve.h Wed Aug 13 14:18:00 2014 +0100 @@ -18,6 +18,7 @@ #include "FIRFilter.h" #include "WindowFunction.h" #include <cassert> +#include "Spectrogram.h" class NoveltyCurve{ float m_samplingFrequency; @@ -26,23 +27,21 @@ int m_numberOfBlocks; int m_compressionConstant; int m_numberOfBands; - int * m_bandBoundaries; - int m_hannLength; - float * m_bandSum; - std::vector<float> data; + int * m_pBandBoundaries; + float * m_pBandSum; void initialise(); void cleanup(); - float calculateMax(std::vector< std::vector<float> > &spectrogram); - void subtractLocalAverage(std::vector<float> &noveltyCurve); - void smoothedDifferentiator(std::vector< std::vector<float> > &spectrogram, int smoothLength); - void halfWaveRectify(std::vector< std::vector<float> > &spectrogram); + float calculateMax(const std::vector< std::vector<float> > &spectrogram) const; + void subtractLocalAverage(std::vector<float> &noveltyCurve, const size_t &smoothLength) const; + void smoothedDifferentiator(std::vector< std::vector<float> > &spectrogram, const size_t &smoothLength) const; + void halfWaveRectify(std::vector< std::vector<float> > &spectrogram) const; public: - NoveltyCurve(float samplingFrequency, int fftLength, int numberOfBlocks, int compressionConstant); + NoveltyCurve(const float &samplingFrequency, const size_t &fftLength, const size_t &numberOfBlocks, const size_t &compressionConstant); ~NoveltyCurve(); - std::vector<float> spectrogramToNoveltyCurve(std::vector< std::vector<float> > spectrogram); + std::vector<float> spectrogramToNoveltyCurve(Spectrogram spectrogram) const; }; #endif /* defined(__Tempogram__NoveltyCurve__) */
--- a/Spectrogram.cpp Wed Aug 13 10:47:39 2014 +0100 +++ b/Spectrogram.cpp Wed Aug 13 14:18:00 2014 +0100 @@ -9,16 +9,17 @@ #include "Spectrogram.h" using namespace std; using Vamp::FFT; +#include <iostream> -SpectrogramProcessor::SpectrogramProcessor(unsigned int inputLength, unsigned int windowLength, unsigned int fftLength, unsigned int hopSize) : +SpectrogramProcessor::SpectrogramProcessor(const size_t &inputLength, const size_t &windowLength, const size_t &fftLength, const size_t &hopSize) : m_inputLength(inputLength), m_windowLength(windowLength), m_fftLength(fftLength), m_hopSize(hopSize), m_numberOfOutputBins(ceil(fftLength/2) + 1), - fftInput(0), - fftOutputReal(0), - fftOutputImag(0) + m_pFftInput(0), + m_pFftOutputReal(0), + m_pFftOutputImag(0) { initialise(); } @@ -28,54 +29,55 @@ } void SpectrogramProcessor::initialise(){ - fftInput = new double [m_fftLength]; - fftOutputReal = new double [m_fftLength]; - fftOutputImag = new double [m_fftLength]; - - int numberOfBlocks = ceil(m_inputLength/m_hopSize) + 2*(ceil(m_windowLength/m_hopSize)-1); //The last term corresponds to overlaps at the beginning and end with padded zeros. I.e., if m_hopSize = m_windowLength/2, there'll be 1 overlap at each end. If m_hopSize = m_windowLength/4, there'll be 3 overlaps at each end, etc... - spectrogramOutput = vector< vector<float> >(m_numberOfOutputBins, vector<float>(numberOfBlocks)); + m_pFftInput = new double [m_fftLength]; + m_pFftOutputReal = new double [m_fftLength]; + m_pFftOutputImag = new double [m_fftLength]; } void SpectrogramProcessor::cleanup(){ - delete []fftInput; - delete []fftOutputReal; - delete []fftOutputImag; + delete []m_pFftInput; + delete []m_pFftOutputReal; + delete []m_pFftOutputImag; - fftInput = fftOutputReal = fftOutputImag = 0; + m_pFftInput = m_pFftOutputReal = m_pFftOutputImag = 0; } //process method -vector< vector<float> > SpectrogramProcessor::process(const float * const input, const float * window){ +Spectrogram SpectrogramProcessor::process(const float * const pInput, const float * pWindow) const +{ + int numberOfBlocks = ceil(m_inputLength/m_hopSize) + 2*(ceil(m_windowLength/m_hopSize)-1); //The last term corresponds to overlaps at the beginning and end with padded zeros. I.e., if m_hopSize = m_windowLength/2, there'll be 1 overlap at each end. If m_hopSize = m_windowLength/4, there'll be 3 overlaps at each end, etc... + Spectrogram spectrogram(m_numberOfOutputBins, vector<float>(numberOfBlocks)); int readPointerBeginIndex = m_hopSize-m_windowLength; - int writeBlockPointer = 0; + unsigned int writeBlockPointer = 0; - while(readPointerBeginIndex < m_inputLength){ + while(readPointerBeginIndex < (int)m_inputLength){ int readPointer = readPointerBeginIndex; - for (int n = 0; n < m_windowLength; n++){ - if(readPointer < 0 || readPointer >= m_inputLength){ - fftInput[n] = 0.0; //pad with zeros + for (unsigned int n = 0; n < m_windowLength; n++){ + if(readPointer < 0 || readPointer >= (int)m_inputLength){ + m_pFftInput[n] = 0.0; //pad with zeros } else{ - fftInput[n] = input[readPointer] * window[n]; + m_pFftInput[n] = pInput[readPointer] * pWindow[n]; } readPointer++; } - for (int n = m_windowLength; n < m_fftLength; n++){ - fftInput[n] = 0.0; + for (unsigned int n = m_windowLength; n < m_fftLength; n++){ + m_pFftInput[n] = 0.0; } - FFT::forward(m_fftLength, fftInput, 0, fftOutputReal, fftOutputImag); + FFT::forward(m_fftLength, m_pFftInput, 0, m_pFftOutputReal, m_pFftOutputImag); //@todo: sample at logarithmic spacing? Leave for host? - for(int k = 0; k < m_numberOfOutputBins; k++){ - spectrogramOutput[k][writeBlockPointer] = (fftOutputReal[k]*fftOutputReal[k] + fftOutputImag[k]*fftOutputImag[k]); //Magnitude or power? + for(unsigned int k = 0; k < m_numberOfOutputBins; k++){ + spectrogram[k][writeBlockPointer] = (m_pFftOutputReal[k]*m_pFftOutputReal[k] + m_pFftOutputImag[k]*m_pFftOutputImag[k]); //Magnitude or power? + //std::cout << spectrogram[k][writeBlockPointer] << std::endl; } readPointerBeginIndex += m_hopSize; writeBlockPointer++; } - return spectrogramOutput; + return spectrogram; }
--- a/Spectrogram.h Wed Aug 13 10:47:39 2014 +0100 +++ b/Spectrogram.h Wed Aug 13 14:18:00 2014 +0100 @@ -12,23 +12,26 @@ #include <vamp-sdk/FFT.h> #include <cmath> +typedef std::vector <std::vector<float> > Spectrogram; +typedef std::vector <std::vector<float> > SpectrogramTransposed; + class SpectrogramProcessor{ - int m_inputLength; - int m_windowLength; - int m_fftLength; - int m_hopSize; - int m_numberOfOutputBins; - double * fftInput; - double * fftOutputReal; - double * fftOutputImag; - std::vector< std::vector <float> > spectrogramOutput; + size_t m_inputLength; + size_t m_windowLength; + size_t m_fftLength; + size_t m_hopSize; + size_t m_numberOfOutputBins; + double * m_pFftInput; + double * m_pFftOutputReal; + double * m_pFftOutputImag; void initialise(); void cleanup(); public: - std::vector< std::vector<float> > process(const float * const input, const float * window); - SpectrogramProcessor(unsigned int inputLength, unsigned int windowLength, unsigned int fftLength, unsigned int hopSize); + SpectrogramProcessor(const size_t &inputLength, const size_t &windowLength, const size_t &fftLength, const size_t &hopSize); ~SpectrogramProcessor(); + + std::vector< std::vector<float> > process(const float * const pInput, const float * pWindow) const; }; #endif /* defined(__Tempogram__Spectrogram__) */
--- a/Tempogram.cpp Wed Aug 13 10:47:39 2014 +0100 +++ b/Tempogram.cpp Wed Aug 13 14:18:00 2014 +0100 @@ -16,16 +16,17 @@ Plugin(inputSampleRate), m_blockSize(0), m_stepSize(0), - compressionConstant(1000), //parameter - minDB(0), - windowLength(128), //parameter - fftLength(4096), //parameter - thopSize(64), //parameter - minBPM(30), - maxBPM(480), - minBin(0), //set in initialise() - maxBin(0), //set in initialise() - numberOfBlocks(0) //incremented in process() + m_compressionConstant(1000), //parameter + m_minDB(0), + m_log2WindowLength(10), + m_windowLength(pow((float)2,(float)m_log2WindowLength)), //parameter + m_fftLength(4096), //parameter + m_hopSize(64), //parameter + m_minBPM(30), + m_maxBPM(480), + m_minBin(0), //set in initialise() + m_maxBin(0), //set in initialise() + m_numberOfBlocks(0) //incremented in process() // Also be sure to set your plugin parameters (presumably stored // in member variables) to their default values here -- the host @@ -142,15 +143,18 @@ d.isQuantized = false; list.push_back(d); - d.identifier = "TN"; + d.identifier = "log2TN"; d.name = "Tempogram Window Length"; d.description = "FFT window length when analysing the novelty curve and extracting the tempogram time-frequency function."; d.unit = ""; - d.minValue = 1024; - d.maxValue = 4096; - d.defaultValue = 128; + d.minValue = 7; + d.maxValue = 12; + d.defaultValue = 10; d.isQuantized = true; - d.quantizeStep = 128; + d.quantizeStep = 1; + for (int i = d.minValue; i <= d.maxValue; i++){ + d.valueNames.push_back(floatToString(pow((float)2,(float)i))); + } list.push_back(d); d.identifier = "minBPM"; @@ -182,16 +186,16 @@ Tempogram::getParameter(string identifier) const { if (identifier == "C") { - return compressionConstant; // return the ACTUAL current value of your parameter here! + return m_compressionConstant; // return the ACTUAL current value of your parameter here! } - if (identifier == "TN"){ - return windowLength; + if (identifier == "log2TN"){ + return m_log2WindowLength; } if (identifier == "minBPM") { - return minBPM; + return m_minBPM; } if (identifier == "maxBPM"){ - return maxBPM; + return m_maxBPM; } return 0; @@ -202,16 +206,17 @@ { if (identifier == "C") { - compressionConstant = value; // set the actual value of your parameter + m_compressionConstant = value; // set the actual value of your parameter } - if (identifier == "TN") { - windowLength = value; + if (identifier == "log2TN") { + m_windowLength = pow(2,value); + m_log2WindowLength = value; } if (identifier == "minBPM") { - minBPM = value; + m_minBPM = value; } if (identifier == "maxBPM"){ - maxBPM = value; + m_maxBPM = value; } } @@ -267,14 +272,14 @@ d.description = "Tempogram"; d.unit = "BPM"; d.hasFixedBinCount = true; - d.binCount = maxBin - minBin + 1; + d.binCount = m_maxBin - m_minBin + 1; d.hasKnownExtents = false; d.isQuantized = false; d.sampleType = OutputDescriptor::FixedSampleRate; - d_sampleRate = tempogramInputSampleRate/thopSize; + d_sampleRate = tempogramInputSampleRate/m_hopSize; d.sampleRate = d_sampleRate > 0.0 && !isnan(d_sampleRate) ? d_sampleRate : 0.0; - for(int i = minBin; i <= maxBin; i++){ - float w = ((float)i/fftLength)*(tempogramInputSampleRate); + for(int i = m_minBin; i <= (int)m_maxBin; i++){ + float w = ((float)i/m_fftLength)*(tempogramInputSampleRate); d.binNames.push_back(floatToString(w*60)); } d.hasDuration = false; @@ -306,17 +311,17 @@ // Real initialisation work goes here! m_blockSize = blockSize; m_stepSize = stepSize; - minDB = pow(10,(float)-74/20); + m_minDB = pow(10,(float)-74/20); - if (minBPM > maxBPM){ - minBPM = 30; - maxBPM = 480; + if (m_minBPM > m_maxBPM){ + m_minBPM = 30; + m_maxBPM = 480; } float tempogramInputSampleRate = (float)m_inputSampleRate/m_stepSize; - minBin = (unsigned int)(max(floor(((minBPM/60)/tempogramInputSampleRate)*fftLength), (float)0.0)); - maxBin = (unsigned int)(min(ceil(((maxBPM/60)/tempogramInputSampleRate)*fftLength), (float)fftLength/2)); + m_minBin = (unsigned int)(max(floor(((m_minBPM/60)/tempogramInputSampleRate)*m_fftLength), (float)0.0)); + m_maxBin = (unsigned int)(min(ceil(((m_maxBPM/60)/tempogramInputSampleRate)*m_fftLength), (float)m_fftLength/2)); - specData = vector< vector<float> >(m_blockSize/2 + 1); + m_spectrogram = vector< vector<float> >(m_blockSize/2 + 1); return true; } @@ -330,8 +335,8 @@ { // Clear buffers, reset stored values, etc ncTimestamps.clear(); - specData.clear(); - specData = vector< vector<float> >(m_blockSize/2 + 1); + m_spectrogram.clear(); + m_spectrogram = vector< vector<float> >(m_blockSize/2 + 1); } Tempogram::FeatureSet @@ -345,13 +350,13 @@ const float *in = inputBuffers[0]; //calculate magnitude of FrequencyDomain input - for (int i = 0; i < n; i++){ + for (unsigned int i = 0; i < n; i++){ float magnitude = sqrt(in[2*i] * in[2*i] + in[2*i + 1] * in[2*i + 1]); - magnitude = magnitude > minDB ? magnitude : minDB; - specData[i].push_back(magnitude); + magnitude = magnitude > m_minDB ? magnitude : m_minDB; + m_spectrogram[i].push_back(magnitude); } - numberOfBlocks++; + m_numberOfBlocks++; ncTimestamps.push_back(timestamp); //save timestamp return featureSet; @@ -361,35 +366,35 @@ Tempogram::getRemainingFeatures() { - float * hannWindowtN = new float[windowLength]; - for (int i = 0; i < windowLength; i++){ + float * hannWindowtN = new float[m_windowLength]; + for (unsigned int i = 0; i < m_windowLength; i++){ hannWindowtN[i] = 0.0; } FeatureSet featureSet; - //initialise noveltycurve processor - NoveltyCurve nc(m_inputSampleRate, m_blockSize, numberOfBlocks, compressionConstant); - noveltyCurve = nc.spectrogramToNoveltyCurve(specData); //calculate novelty curve from magnitude data + //initialise m_noveltyCurve processor + NoveltyCurve nc(m_inputSampleRate, m_blockSize, m_numberOfBlocks, m_compressionConstant); + m_noveltyCurve = nc.spectrogramToNoveltyCurve(m_spectrogram); //calculate novelty curve from magnitude data //push novelty curve data to featureset 1 and set timestamps - for (int i = 0; i < numberOfBlocks; i++){ + for (unsigned int i = 0; i < m_numberOfBlocks; i++){ Feature feature; - feature.values.push_back(noveltyCurve[i]); + feature.values.push_back(m_noveltyCurve[i]); feature.hasTimestamp = true; feature.timestamp = ncTimestamps[i]; featureSet[1].push_back(feature); } //window function for spectrogram - WindowFunction::hanning(hannWindowtN,windowLength); + WindowFunction::hanning(hannWindowtN,m_windowLength); //initialise spectrogram processor - SpectrogramProcessor spectrogramProcessor(numberOfBlocks, windowLength, fftLength, thopSize); + SpectrogramProcessor spectrogramProcessor(m_numberOfBlocks, m_windowLength, m_fftLength, m_hopSize); //compute spectrogram from novelty curve data (i.e., tempogram) - vector< vector<float> > tempogram = spectrogramProcessor.process(&noveltyCurve[0], hannWindowtN); + Spectrogram tempogram = spectrogramProcessor.process(&m_noveltyCurve[0], hannWindowtN); - int timePointer = thopSize-windowLength/2; + int timePointer = m_hopSize-m_windowLength/2; int tempogramLength = tempogram[0].size(); //push tempogram data to featureset 0 and set timestamps. @@ -398,21 +403,22 @@ int timeMS = floor(1000*(m_stepSize*timePointer)/m_inputSampleRate + 0.5); - assert(tempogram.size() == (fftLength/2 + 1)); - for(int k = minBin; k < maxBin; k++){ + assert(tempogram.size() == (m_fftLength/2 + 1)); + for(int k = m_minBin; k < (int)m_maxBin; k++){ feature.values.push_back(tempogram[k][block]); + //cout << tempogram[k][block] << endl; } feature.hasTimestamp = true; feature.timestamp = RealTime::fromMilliseconds(timeMS); featureSet[0].push_back(feature); - timePointer += thopSize; + timePointer += m_hopSize; } //float func = [](){ cout << "Hello"; }; delete []hannWindowtN; - hannWindowtN = NULL; + hannWindowtN = 0; return featureSet; }
--- a/Tempogram.h Wed Aug 13 10:47:39 2014 +0100 +++ b/Tempogram.h Wed Aug 13 14:18:00 2014 +0100 @@ -75,28 +75,27 @@ // plugin-specific data and methods go here size_t m_blockSize; size_t m_stepSize; - float compressionConstant; - float *previousY; - float *currentY; - vector< vector<float> > specData; //spectrogram data - vector<float> noveltyCurve; //novelty curve data - float minDB; + float m_compressionConstant; + vector< vector<float> > m_spectrogram; //spectrogram data + vector<float> m_noveltyCurve; //novelty curve data + float m_minDB; void cleanup(); //used to release anything allocated in initialise() string floatToString(float value) const; void updateBPMParameters(); //FFT params for noveltyCurve -> tempogra - unsigned int windowLength; - unsigned int fftLength; - unsigned int thopSize; + int m_log2WindowLength; + size_t m_windowLength; + size_t m_fftLength; + size_t m_hopSize; - float minBPM; // tempogram output bin range min - float maxBPM; // tempogram output bin range max - unsigned int minBin; - unsigned int maxBin; + float m_minBPM; // tempogram output bin range min + float m_maxBPM; // tempogram output bin range max + unsigned int m_minBin; + unsigned int m_maxBin; - int numberOfBlocks; + unsigned int m_numberOfBlocks; vector<Vamp::RealTime> ncTimestamps; };
--- a/WindowFunction.cpp Wed Aug 13 10:47:39 2014 +0100 +++ b/WindowFunction.cpp Wed Aug 13 14:18:00 2014 +0100 @@ -11,10 +11,10 @@ //static function void -WindowFunction::hanning(float *window, const unsigned int N, const bool normalise){ +WindowFunction::hanning(float * window, const unsigned int &N, const bool &normalise){ float sum = 0; - for(int i = 0; i < N; i++){ + for(unsigned int i = 0; i < N; i++){ window[i] = 0.5*(1-cos((float)2*M_PI*i/N)); sum += window[i]; }
--- a/WindowFunction.h Wed Aug 13 10:47:39 2014 +0100 +++ b/WindowFunction.h Wed Aug 13 14:18:00 2014 +0100 @@ -15,7 +15,7 @@ class WindowFunction{ public: - static void hanning(float *signal, const unsigned int N, const bool normalise = false); + static void hanning(float *signal, const unsigned int &N, const bool &normalise = false); }; #endif /* defined(__Tempogram__WindowFunction__) */