# HG changeset patch # User Carl Bussey # Date 1407850837 -3600 # Node ID be59b4a73f49fde077183598ed28045c9a029331 # Parent 4e429b9f2b4de209b19d500ddda2996670dda709 * Added Spectrogram zero padding functionality * Made output bins correspond to BPM * User can now specify a range of output bins to view * Comments added diff -r 4e429b9f2b4d -r be59b4a73f49 FIRFilter.cpp --- a/FIRFilter.cpp Thu Aug 07 17:25:24 2014 +0100 +++ b/FIRFilter.cpp Tue Aug 12 14:40:37 2014 +0100 @@ -33,9 +33,11 @@ cleanup(); } +//allocate memory void FIRFilter::initialise() { + //next power of 2 m_lengthFIRFFT = pow(2,(ceil(log2(m_lengthInput+m_numberOfCoefficients-1)))); fftInput = new double[m_lengthFIRFFT]; @@ -57,6 +59,7 @@ void FIRFilter::process(const float* input, const float* coefficients, float* output) { + //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; @@ -65,17 +68,20 @@ FFT::forward(m_lengthFIRFFT, fftInput, NULL, fftReal1, fftImag1); FFT::forward(m_lengthFIRFFT, fftCoefficients, NULL, fftReal2, fftImag2); + //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]); } FFT::inverse(m_lengthFIRFFT, fftFilteredReal, fftFilteredImag, fftOutputReal, fftOutputImag); + //copy to output for (int i = 0; i < m_lengthInput; i++){ output[i] = fftOutputReal[i]; } } +//remove memory allocations void FIRFilter::cleanup() { diff -r 4e429b9f2b4d -r be59b4a73f49 FIRFilter.h --- a/FIRFilter.h Thu Aug 07 17:25:24 2014 +0100 +++ b/FIRFilter.h Tue Aug 12 14:40:37 2014 +0100 @@ -12,7 +12,6 @@ #include #include #include -#include class FIRFilter{ public: diff -r 4e429b9f2b4d -r be59b4a73f49 Makefile --- a/Makefile Thu Aug 07 17:25:24 2014 +0100 +++ b/Makefile Tue Aug 12 14:40:37 2014 +0100 @@ -39,7 +39,7 @@ CXX := g++ #-mmacosx-version-min=10.6 -CXXFLAGS := -mmacosx-version-min=10.6 -arch x86_64 -I$(VAMP_SDK_DIR) -Wall -fPIC +CXXFLAGS := -mmacosx-version-min=10.6 -arch x86_64 -I$(VAMP_SDK_DIR) -Wall -fPIC PLUGIN_EXT := .dylib LDFLAGS := $(CXXFLAGS) -dynamiclib -install_name $(PLUGIN_LIBRARY_NAME)$(PLUGIN_EXT) /usr/local/lib/libvamp-sdk.a -exported_symbols_list vamp-plugin.list diff -r 4e429b9f2b4d -r be59b4a73f49 NoveltyCurve.cpp --- a/NoveltyCurve.cpp Thu Aug 07 17:25:24 2014 +0100 +++ b/NoveltyCurve.cpp Tue Aug 12 14:40:37 2014 +0100 @@ -18,7 +18,6 @@ m_numberOfBands(5), m_bandBoundaries(NULL), m_hannLength(65), - m_hannWindow(NULL), m_bandSum(NULL) { initialise(); @@ -28,15 +27,13 @@ cleanup(); } +//allocate all space and set variable void NoveltyCurve::initialise(){ data = vector(m_numberOfBlocks); - m_hannWindow = new float[m_hannLength]; - WindowFunction::hanning(m_hannWindow, m_hannLength, true); - - m_bandBoundaries = new int[m_numberOfBands+1]; //make index variable - + // 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); @@ -47,16 +44,16 @@ m_bandSum = new float [m_numberOfBands]; } +//delete space allocated in initialise() void NoveltyCurve::cleanup(){ - delete []m_hannWindow; - m_hannWindow = NULL; delete []m_bandBoundaries; m_bandBoundaries = NULL; delete []m_bandSum; m_bandSum = NULL; } +//calculate max of spectrogram float NoveltyCurve::calculateMax(vector< vector > &spectrogram){ float max = 0; @@ -69,9 +66,14 @@ return max; } +//subtract local average of novelty curve +//uses m_hannWindow as filter void NoveltyCurve::subtractLocalAverage(vector &noveltyCurve){ vector localAverage(m_numberOfBlocks); + float * m_hannWindow = new float[m_hannLength]; + WindowFunction::hanning(m_hannWindow, m_hannLength, true); + FIRFilter *filter = new FIRFilter(m_numberOfBlocks, m_hannLength); filter->process(&noveltyCurve[0], m_hannWindow, &localAverage[0]); delete filter; @@ -82,11 +84,14 @@ noveltyCurve[i] -= localAverage[i]; noveltyCurve[i] = noveltyCurve[i] >= 0 ? noveltyCurve[i] : 0; } + + delete m_hannWindow; + m_hannWindow = NULL; } +//smoothed differentiator filter. Flips upper half of hanning window about y-axis to create coefficients. void NoveltyCurve::smoothedDifferentiator(vector< vector > &spectrogram, int smoothLength){ - //need to make new hannWindow!! float * diffHannWindow = new float [smoothLength]; WindowFunction::hanning(diffHannWindow, smoothLength, true); @@ -105,7 +110,8 @@ smoothFilter = NULL; } -void NoveltyCurve::halfWaveRectify(vector< vector > &spectrogram){ //should this return spectrogram?? +//half rectification (set negative to zero) +void NoveltyCurve::halfWaveRectify(vector< vector > &spectrogram){ for (int block = 0; block < m_numberOfBlocks; block++){ for (int k = 0; k < m_blockSize; k++){ @@ -114,14 +120,15 @@ } } +//process method vector NoveltyCurve::spectrogramToNoveltyCurve(vector< vector > &spectrogram){ 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++){ if(normaliseScale != 0.0) spectrogram[k][block] /= normaliseScale; //normalise @@ -129,9 +136,12 @@ } } + //smooted differentiator smoothedDifferentiator(spectrogram, 5); //make smoothLength a parameter! + //halfwave rectification 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]; @@ -150,6 +160,7 @@ data[block] = total/m_numberOfBands; } + //subtract local averages subtractLocalAverage(data); return data; diff -r 4e429b9f2b4d -r be59b4a73f49 NoveltyCurve.h --- a/NoveltyCurve.h Thu Aug 07 17:25:24 2014 +0100 +++ b/NoveltyCurve.h Tue Aug 12 14:40:37 2014 +0100 @@ -26,7 +26,6 @@ int m_numberOfBands; int * m_bandBoundaries; int m_hannLength; - float * m_hannWindow; float * m_bandSum; void initialise(); diff -r 4e429b9f2b4d -r be59b4a73f49 Spectrogram.cpp --- a/Spectrogram.cpp Thu Aug 07 17:25:24 2014 +0100 +++ b/Spectrogram.cpp Tue Aug 12 14:40:37 2014 +0100 @@ -7,12 +7,12 @@ // #include "Spectrogram.h" -#include using namespace std; using Vamp::FFT; -Spectrogram::Spectrogram(unsigned int inputLength, unsigned int fftLength, unsigned int hopSize) : +Spectrogram::Spectrogram(unsigned int inputLength, unsigned int windowLength, unsigned int fftLength, unsigned int hopSize) : m_inputLength(inputLength), + m_windowLength(windowLength), m_fftLength(fftLength), m_hopSize(hopSize), m_numberOfOutputBins(ceil(fftLength/2) + 1), @@ -32,7 +32,7 @@ fftOutputReal = new double [m_fftLength]; fftOutputImag = new double [m_fftLength]; - int numberOfBlocks = ceil(m_inputLength/m_hopSize) + 2*(ceil(m_fftLength/m_hopSize)-1); //The last term corresponds to overlaps at the beginning and end with padded zeros. I.e., if m_hopSize = m_fftLength/2, there'll be 1 overlap at each end. If m_hopSize = m_fftLength/4, there'll be 3 overlaps at each end, etc... + 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 >(m_numberOfOutputBins, vector(numberOfBlocks)); } @@ -44,15 +44,16 @@ fftInput = fftOutputReal = fftOutputImag = NULL; } +//process method vector< vector > Spectrogram::audioToMagnitudeSpectrogram(const float * const input, const float * window){ - int readPointerBeginIndex = m_hopSize-m_fftLength; + int readPointerBeginIndex = m_hopSize-m_windowLength; int writeBlockPointer = 0; while(readPointerBeginIndex < m_inputLength){ int readPointer = readPointerBeginIndex; - for (int n = 0; n < m_fftLength; n++){ + for (int n = 0; n < m_windowLength; n++){ if(readPointer < 0 || readPointer >= m_inputLength){ fftInput[n] = 0.0; //pad with zeros } @@ -61,13 +62,15 @@ } readPointer++; } + for (int n = m_windowLength; n < m_fftLength; n++){ + fftInput[n] = 0.0; + } FFT::forward(m_fftLength, fftInput, NULL, fftOutputReal, fftOutputImag); //@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? - cerr << writeBlockPointer << " : " << spectrogramOutput[k].size() << endl; } readPointerBeginIndex += m_hopSize; diff -r 4e429b9f2b4d -r be59b4a73f49 Spectrogram.h --- a/Spectrogram.h Thu Aug 07 17:25:24 2014 +0100 +++ b/Spectrogram.h Tue Aug 12 14:40:37 2014 +0100 @@ -14,6 +14,7 @@ class Spectrogram{ int m_inputLength; + int m_windowLength; int m_fftLength; int m_hopSize; int m_numberOfOutputBins; @@ -26,7 +27,7 @@ void cleanup(); public: std::vector< std::vector > audioToMagnitudeSpectrogram(const float * const input, const float * window); - Spectrogram(unsigned int inputLength, unsigned int fftLength, unsigned int hopSize); + Spectrogram(unsigned int inputLength, unsigned int windowLength, unsigned int fftLength, unsigned int hopSize); ~Spectrogram(); }; diff -r 4e429b9f2b4d -r be59b4a73f49 Tempogram.cpp --- a/Tempogram.cpp Thu Aug 07 17:25:24 2014 +0100 +++ b/Tempogram.cpp Tue Aug 12 14:40:37 2014 +0100 @@ -5,6 +5,8 @@ #include "Tempogram.h" +#include +#include using Vamp::FFT; using Vamp::RealTime; @@ -14,15 +16,16 @@ Plugin(inputSampleRate), m_blockSize(0), m_stepSize(0), - compressionConstant(1000), //make param - specMax(0), + compressionConstant(1000), //parameter minDB(0), - tN(128), //make param - thopSize(64), //make param - fftInput(NULL), - fftOutputReal(NULL), - fftOutputImag(NULL), - numberOfBlocks(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() // Also be sure to set your plugin parameters (presumably stored // in member variables) to their default values here -- the host @@ -89,13 +92,13 @@ size_t Tempogram::getPreferredBlockSize() const { - return 0; // 0 means "I can handle any block size" + return 2048; // 0 means "I can handle any block size" } size_t Tempogram::getPreferredStepSize() const { - return 0; // 0 means "anything sensible"; in practice this + return 1024; // 0 means "anything sensible"; in practice this // means the same as the block size for TimeDomain // plugins, or half of it for FrequencyDomain plugins } @@ -128,28 +131,49 @@ // not explicitly set your parameters to their defaults for you if // they have not changed in the mean time. - ParameterDescriptor C; - C.identifier = "C"; - C.name = "C"; - C.description = "Spectrogram compression constant, C"; - C.unit = ""; - C.minValue = 2; - C.maxValue = 10000; - C.defaultValue = 1000; - C.isQuantized = false; - list.push_back(C); + ParameterDescriptor d; + d.identifier = "C"; + d.name = "C"; + d.description = "Spectrogram compression constant, C, used when retrieving the novelty curve from the audio."; + d.unit = ""; + d.minValue = 2; + d.maxValue = 10000; + d.defaultValue = 1000; + d.isQuantized = false; + list.push_back(d); + + d.identifier = "TN"; + 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.isQuantized = true; + d.quantizeStep = 128; + list.push_back(d); - ParameterDescriptor tN; - tN.identifier = "tN"; - tN.name = "Tempogram FFT length"; - tN.description = "Tempogram FFT length."; - tN.unit = ""; - tN.minValue = 128; - tN.maxValue = 4096; - tN.defaultValue = 128; - tN.isQuantized = true; - tN.quantizeStep = 128; - list.push_back(tN); + d.identifier = "minBPM"; + d.name = "Minimum BPM"; + d.description = "The minimum BPM of the tempogram output bins."; + d.unit = ""; + d.minValue = 0; + d.maxValue = 2000; + d.defaultValue = 30; + d.isQuantized = true; + d.quantizeStep = 5; + list.push_back(d); + + d.identifier = "maxBPM"; + d.name = "Maximum BPM"; + d.description = "The minimum BPM of the tempogram output bins."; + d.unit = ""; + d.minValue = 30; + d.maxValue = 2000; + d.defaultValue = 480; + d.isQuantized = true; + d.quantizeStep = 5; + list.push_back(d); return list; } @@ -160,8 +184,14 @@ if (identifier == "C") { return compressionConstant; // return the ACTUAL current value of your parameter here! } - if (identifier == "tN"){ - return tN; + if (identifier == "TN"){ + return windowLength; + } + if (identifier == "minBPM") { + return minBPM; + } + if (identifier == "maxBPM"){ + return maxBPM; } return 0; @@ -170,12 +200,24 @@ void Tempogram::setParameter(string identifier, float value) { + if (identifier == "C") { compressionConstant = value; // set the actual value of your parameter } - if (identifier == "tN") { - tN = value; + if (identifier == "TN") { + windowLength = value; } + if (identifier == "minBPM") { + minBPM = value; + } + if (identifier == "maxBPM"){ + maxBPM = value; + } + +} + +void Tempogram::updateBPMParameters(){ + } Tempogram::ProgramList @@ -200,6 +242,14 @@ { } +string Tempogram::floatToString(float value) const +{ + ostringstream ss; + + if(!(ss << value)) throw runtime_error("Tempogram::floatToString(): invalid conversion from float to string"); + return ss.str(); +} + Tempogram::OutputList Tempogram::getOutputDescriptors() const { @@ -210,18 +260,23 @@ OutputDescriptor d; float d_sampleRate; + float tempogramInputSampleRate = (float)m_inputSampleRate/m_stepSize; d.identifier = "tempogram"; d.name = "Tempogram"; d.description = "Tempogram"; - d.unit = ""; + d.unit = "BPM"; d.hasFixedBinCount = true; - d.binCount = tN/2 + 1; + d.binCount = maxBin - minBin + 1; d.hasKnownExtents = false; d.isQuantized = false; d.sampleType = OutputDescriptor::FixedSampleRate; - d_sampleRate = m_inputSampleRate/(m_stepSize * thopSize); + d_sampleRate = tempogramInputSampleRate/thopSize; 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); + d.binNames.push_back(floatToString(w*60)); + } d.hasDuration = false; list.push_back(d); @@ -234,7 +289,7 @@ d.hasKnownExtents = false; d.isQuantized = false; d.sampleType = OutputDescriptor::FixedSampleRate; - d_sampleRate = m_inputSampleRate/m_stepSize; + d_sampleRate = tempogramInputSampleRate; d.sampleRate = d_sampleRate > 0 && !isnan(d_sampleRate) ? d_sampleRate : 0.0; d.hasDuration = false; list.push_back(d); @@ -247,12 +302,20 @@ { if (channels < getMinChannelCount() || channels > getMaxChannelCount()) return false; - + // Real initialisation work goes here! m_blockSize = blockSize; m_stepSize = stepSize; minDB = pow(10,(float)-74/20); + if (minBPM > maxBPM){ + minBPM = 30; + 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)); + specData = vector< vector >(m_blockSize/2 + 1); return true; @@ -282,6 +345,7 @@ const float *in = inputBuffers[0]; + //calculate magnitude of FrequencyDomain input for (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; @@ -289,23 +353,17 @@ } numberOfBlocks++; - ncTimestamps.push_back(timestamp); + ncTimestamps.push_back(timestamp); //save timestamp return featureSet; } void Tempogram::initialiseForGRF(){ - hannWindowtN = new float[tN]; - fftInput = new double[tN]; - fftOutputReal = new double[tN]; - fftOutputImag = new double[tN]; + hannWindowtN = new float[windowLength]; - for (int i = 0; i < tN; i ++){ + for (int i = 0; i < windowLength; i++){ hannWindowtN[i] = 0.0; - fftInput[i] = 0.0; - fftOutputReal[i] = 0.0; - fftOutputImag[i] = 0.0; } } @@ -313,9 +371,10 @@ Tempogram::cleanupForGRF(){ delete []hannWindowtN; hannWindowtN = NULL; - fftInput = fftOutputReal = fftOutputImag = NULL; } + + Tempogram::FeatureSet Tempogram::getRemainingFeatures() { @@ -323,9 +382,11 @@ initialiseForGRF(); FeatureSet featureSet; + //initialise noveltycurve processor NoveltyCurve nc(m_inputSampleRate, m_blockSize, numberOfBlocks, compressionConstant); - noveltyCurve = nc.spectrogramToNoveltyCurve(specData); + noveltyCurve = nc.spectrogramToNoveltyCurve(specData); //calculate novelty curve from magnitude data + //push novelty curve data to featureset 1 and set timestamps for (int i = 0; i < numberOfBlocks; i++){ Feature feature; feature.values.push_back(noveltyCurve[i]); @@ -334,21 +395,27 @@ featureSet[1].push_back(feature); } - WindowFunction::hanning(hannWindowtN, tN); - Spectrogram * spectrogramProcessor = new Spectrogram(numberOfBlocks, tN, thopSize); + //window function for spectrogram + WindowFunction::hanning(hannWindowtN,windowLength); + + //initialise spectrogram processor + Spectrogram * spectrogramProcessor = new Spectrogram(numberOfBlocks, windowLength, fftLength, thopSize); + //compute spectrogram from novelty curve data (i.e., tempogram) vector< vector > tempogram = spectrogramProcessor->audioToMagnitudeSpectrogram(&noveltyCurve[0], hannWindowtN); delete spectrogramProcessor; spectrogramProcessor = NULL; - int timePointer = thopSize-tN/2; + int timePointer = thopSize-windowLength/2; int tempogramLength = tempogram[0].size(); + //push tempogram data to featureset 0 and set timestamps. for (int block = 0; block < tempogramLength; block++){ Feature feature; int timeMS = floor(1000*(m_stepSize*timePointer)/m_inputSampleRate + 0.5); - for(int k = 0; k < tN/2 + 1; k++){ + assert(tempogram.size() == (fftLength/2 + 1)); + for(int k = minBin; k < maxBin; k++){ feature.values.push_back(tempogram[k][block]); } feature.hasTimestamp = true; diff -r 4e429b9f2b4d -r be59b4a73f49 Tempogram.h --- a/Tempogram.h Thu Aug 07 17:25:24 2014 +0100 +++ b/Tempogram.h Tue Aug 12 14:40:37 2014 +0100 @@ -3,6 +3,17 @@ // libraries. Replace MyPlugin and myPlugin throughout with the name // of your first plugin class, and fill in the gaps as appropriate. +//* Should I use initialiseForGRF()? I generally think it's nicer to initialise stuff before processing. It just means that for some reason if somebody needs to process quickly (and have preparation time before) it's a bit easier on the load. +//* I've taken this approach with NoveltyCurve, Spectrogram and FIRFilter too. Is this a good approach? +//* The names "cleanUpForGRF()" and "initialise...()" are horrible... +//* The "m_..." variable name thing (I've been quite inconsitent with that) +//* Using size_t and not unsigned int? +//* In Tempogram.h, should the protected methods be private? +//* NoveltyCurve::NoveltyCurve() calls initialise(). May be overdetermined with amount of info? i.e., constructor takes parameters fftLength, numberOfBlocks... these are dimensions of vector< vector >spectrogram. +//* When to use function() const? +//* spectrogram continues for too long? see tempogram output +//* should WindowFunction::hanning be static? Justification: no initialisation needed (i.e., no need for a constructor!). + // Remember to use a different guard symbol in each header! #ifndef _TEMPOGRAM_H_ @@ -12,11 +23,13 @@ #include "FIRFilter.h" #include "WindowFunction.h" #include "NoveltyCurve.h" +#include "Spectrogram.h" #include + #include #include -#include -#include "Spectrogram.h" +#include +#include using std::string; using std::vector; @@ -49,11 +62,8 @@ void selectProgram(string name); OutputList getOutputDescriptors() const; - + bool initialise(size_t channels, size_t stepSize, size_t blockSize); - void cleanup(); - void initialiseForGRF(); - void cleanupForGRF(); void reset(); FeatureSet process(const float *const *inputBuffers, @@ -66,18 +76,27 @@ size_t m_blockSize; size_t m_stepSize; float compressionConstant; - float specMax; float *previousY; float *currentY; - vector< vector > specData; - vector noveltyCurve; + vector< vector > specData; //spectrogram data + vector noveltyCurve; //novelty curve data float minDB; - unsigned int tN; + void cleanup(); //used to release anything allocated in initialise() + void initialiseForGRF(); //used to initialise anything for getRemainingFeatures() + void cleanupForGRF(); //used to clean up anything allocated in initialiseForGRF() + string floatToString(float value) const; + void updateBPMParameters(); + + //FFT params for noveltyCurve -> tempogra + unsigned int windowLength; + unsigned int fftLength; unsigned int thopSize; - double * fftInput; - double * fftOutputReal; - double * fftOutputImag; + + float minBPM; // tempogram output bin range min + float maxBPM; // tempogram output bin range max + unsigned int minBin; + unsigned int maxBin; int numberOfBlocks; float *hannWindowtN; diff -r 4e429b9f2b4d -r be59b4a73f49 WindowFunction.cpp --- a/WindowFunction.cpp Thu Aug 07 17:25:24 2014 +0100 +++ b/WindowFunction.cpp Tue Aug 12 14:40:37 2014 +0100 @@ -9,13 +9,13 @@ #include "WindowFunction.h" using std::vector; +//static function void WindowFunction::hanning(float *signal, const unsigned int N, const bool normalise){ float sum = 0; for(int i = 0; i < N; i++){ - signal[i] = 0.5*(1-cos((float)2*M_PI*i/N)); - sum += signal[i]; + sum += signal[i] = 0.5*(1-cos((float)2*M_PI*i/N)); } if (normalise){ for(int i = 0; i < N; i++){