changeset 7:21147df9cb2d

* Error when deleting Spectrogram object in Tempogram::getRemainingFeatures(). * Moved Spectrogram computation into own class.
author Carl Bussey <c.bussey@se10.qmul.ac.uk>
date Thu, 07 Aug 2014 16:21:21 +0100 (2014-08-07)
parents 14a143a2c4c9
children 4e429b9f2b4d
files FIRFilter.cpp FIRFilter.h Makefile NoveltyCurve.cpp NoveltyCurve.h Spectrogram.cpp Spectrogram.h Tempogram.cpp Tempogram.h WindowFunction.cpp WindowFunction.h vamp-plugin.list vamp-plugin.map
diffstat 13 files changed, 280 insertions(+), 178 deletions(-) [+]
line wrap: on
line diff
--- a/FIRFilter.cpp	Tue Aug 05 16:00:30 2014 +0100
+++ b/FIRFilter.cpp	Thu Aug 07 16:21:21 2014 +0100
@@ -7,12 +7,8 @@
 //
 
 #include "FIRFilter.h"
-#include <cmath>
-#include <vamp-sdk/FFT.h>
-#include <assert.h>
-#include <iostream>
+
 using namespace std;
-
 using Vamp::FFT;
 
 FIRFilter::FIRFilter(const unsigned int lengthInput, const unsigned int numberOfCoefficients) :
@@ -61,30 +57,22 @@
 void
 FIRFilter::process(const float* input, const float* coefficients, float* output)
 {
-    float max = 0;
-    for(int i = 0; i < _lengthInput; i++){
-        fftInput[i] = input[i];
-        max = max > fftInput[i] ? max : fftInput[i];
-        //cout << fftInput[i] << endl;
-    }
-    //cout << max << endl;
-    for(int i = 0; i < _numberOfCoefficients; i++){
-        fftCoefficients[i] = coefficients[i];
-        //cout << fftCoefficients[i] << endl;
+    for(int i = 0; i < _lengthFIRFFT; i++){
+        fftInput[i] = i < _lengthInput ? input[i] : 0.0;
+        fftCoefficients[i] = i < _numberOfCoefficients ? coefficients[i] : 0.0;
     }
     
     FFT::forward(_lengthFIRFFT, fftInput, NULL, fftReal1, fftImag1);
     FFT::forward(_lengthFIRFFT, fftCoefficients, NULL, fftReal2, fftImag2);
+    
     for (int i = 0; i < _lengthFIRFFT; i++){
         fftFilteredReal[i] = (fftReal1[i] * fftReal2[i]) - (fftImag1[i] * fftImag2[i]);
         fftFilteredImag[i] = (fftReal1[i] * fftImag2[i]) + (fftReal2[i] * fftImag1[i]);
     }
     FFT::inverse(_lengthFIRFFT, fftFilteredReal, fftFilteredImag, fftOutputReal, fftOutputImag);
     
-    max = 0;
-    for(int i = 0; i < _lengthInput; i++){
+    for (int i = 0; i < _lengthInput; i++){
         output[i] = fftOutputReal[i];
-        max = max > output[i] ? max : output[i];
     }
 }
 
@@ -92,23 +80,14 @@
 FIRFilter::cleanup()
 {
     delete []fftInput;
-    fftInput = NULL;
     delete []fftCoefficients;
-    fftCoefficients = NULL;
     delete []fftReal1;
-    fftReal1 = NULL;
     delete []fftImag1;
-    fftImag1 = NULL;
     delete []fftReal2;
-    fftReal2 = NULL;
     delete []fftImag2;
-    fftImag2 = NULL;
     delete []fftFilteredReal;
-    fftFilteredReal = NULL;
     delete []fftFilteredImag;
-    fftFilteredImag = NULL;
     delete []fftOutputReal;
-    fftOutputReal = NULL;
     delete []fftOutputImag;
-    fftOutputImag = NULL;
+    fftInput = fftCoefficients = fftReal1 = fftImag1 = fftReal2 = fftImag2 = fftFilteredReal = fftFilteredImag = fftOutputReal = fftOutputImag = NULL;
 }
\ No newline at end of file
--- a/FIRFilter.h	Tue Aug 05 16:00:30 2014 +0100
+++ b/FIRFilter.h	Thu Aug 07 16:21:21 2014 +0100
@@ -9,6 +9,11 @@
 #ifndef __Tempogram__FIRFilter__
 #define __Tempogram__FIRFilter__
 
+#include <cmath>
+#include <vamp-sdk/FFT.h>
+#include <assert.h>
+#include <iostream>
+
 class FIRFilter{
 public:
     FIRFilter(const unsigned int lengthInput, const unsigned int numberOfCoefficients);
--- a/Makefile	Tue Aug 05 16:00:30 2014 +0100
+++ b/Makefile	Thu Aug 07 16:21:21 2014 +0100
@@ -21,11 +21,11 @@
 
 # Edit this to list the .cpp or .c files in your plugin project
 #
-PLUGIN_SOURCES := Tempogram.cpp FIRFilter.cpp WindowFunction.cpp plugins.cpp NoveltyCurve.cpp
+PLUGIN_SOURCES := Tempogram.cpp FIRFilter.cpp WindowFunction.cpp plugins.cpp NoveltyCurve.cpp Spectrogram.cpp
 
 # Edit this to list the .h files in your plugin project
 #
-PLUGIN_HEADERS := Tempogram.h FIRFilter.h WindowFunction.h NoveltyCurve.h
+PLUGIN_HEADERS := Tempogram.h FIRFilter.h WindowFunction.h NoveltyCurve.h Spectrogram.h
 
 # Edit this to the location of the Vamp plugin SDK, relative to your
 # project directory
@@ -98,6 +98,9 @@
 $(PLUGIN_OBJECTS): $(PLUGIN_HEADERS)
 
 install: $(PLUGIN_LIBRARY_NAME)$(PLUGIN_EXT)
+	if [ -e ~/Library/Audio/Plug-Ins/Vamp/$(PLUGIN_LIBRARY_NAME)$(PLUGIN_EXT) ] ; then \
+		rm ~/Library/Audio/Plug-Ins/Vamp/$(PLUGIN_LIBRARY_NAME)$(PLUGIN_EXT) ;\
+	fi ;\
 	cp $(PLUGIN_LIBRARY_NAME)$(PLUGIN_EXT) ~/Library/Audio/Plug-Ins/Vamp
 
 clean:
--- a/NoveltyCurve.cpp	Tue Aug 05 16:00:30 2014 +0100
+++ b/NoveltyCurve.cpp	Thu Aug 07 16:21:21 2014 +0100
@@ -6,17 +6,13 @@
 //  Copyright (c) 2014 Carl Bussey. All rights reserved.
 //
 
-#include <cmath>
-#include <vector>
-#include <iostream>
-#include "FIRFilter.h"
-#include "WindowFunction.h"
+#include "NoveltyCurve.h"
 using namespace std;
-#include "NoveltyCurve.h"
 
-NoveltyCurve::NoveltyCurve(float samplingFrequency, int blockSize, int numberOfBlocks, int compressionConstant) :
+NoveltyCurve::NoveltyCurve(float samplingFrequency, int fftLength, int numberOfBlocks, int compressionConstant) :
     m_samplingFrequency(samplingFrequency),
-    m_blockSize(blockSize),
+    m_fftLength(fftLength),
+    m_blockSize(fftLength/2 + 1),
     m_numberOfBlocks(numberOfBlocks),
     m_compressionConstant(compressionConstant),
     m_numberOfBands(5),
@@ -44,14 +40,11 @@
     m_bandBoundaries[0] = 0;
     for (int band = 1; band < m_numberOfBands; band++){
         float lowFreq = 500*pow(2.5, band-1);
-        m_bandBoundaries[band] = m_blockSize*lowFreq/m_samplingFrequency;
+        m_bandBoundaries[band] = m_fftLength*lowFreq/m_samplingFrequency;
     }
-    m_bandBoundaries[m_numberOfBands] = m_blockSize/2 + 1;
+    m_bandBoundaries[m_numberOfBands] = m_blockSize;
     
-    m_bandSum = new float * [m_numberOfBands];
-    for (int i = 0; i < m_numberOfBands; i++){
-        m_bandSum[i] = new float[m_numberOfBlocks];
-    }
+    m_bandSum = new float [m_numberOfBands];
 }
 
 void
@@ -60,80 +53,104 @@
     m_hannWindow = NULL;
     delete []m_bandBoundaries;
     m_bandBoundaries = NULL;
-    
-    for(int i = 0; i < m_numberOfBands; i++){
-        delete []m_bandSum[i];
-        m_bandSum[i] = NULL;
-    }
     delete []m_bandSum;
     m_bandSum = NULL;
 }
 
-float NoveltyCurve::calculateMax(float ** spectrogram){
-    int specLength = (m_blockSize/2 + 1);
+float NoveltyCurve::calculateMax(vector< vector<float> > &spectrogram){
     float max = 0;
     
     for (int j = 0; j < m_numberOfBlocks; j++){
-        for (int i = 0; i < specLength; i++){
-            max = max > spectrogram[i][j] ? max : spectrogram[i][j];
+        for (int i = 0; i < m_blockSize; i++){
+            max = max > fabs(spectrogram[i][j]) ? max : fabs(spectrogram[i][j]);
         }
     }
     
     return max;
 }
 
-void NoveltyCurve::subtractLocalAverage(float * noveltyCurve){
+void NoveltyCurve::subtractLocalAverage(vector<float> &noveltyCurve){
     vector<float> localAverage(m_numberOfBlocks);
     
     FIRFilter *filter = new FIRFilter(m_numberOfBlocks, m_hannLength);
     filter->process(&noveltyCurve[0], m_hannWindow, &localAverage[0]);
     delete filter;
+    filter = NULL;
     
+    assert(noveltyCurve.size() == m_numberOfBlocks);
     for (int i = 0; i < m_numberOfBlocks; i++){
         noveltyCurve[i] -= localAverage[i];
         noveltyCurve[i] = noveltyCurve[i] >= 0 ? noveltyCurve[i] : 0;
     }
 }
 
+void NoveltyCurve::smoothedDifferentiator(vector< vector<float> > &spectrogram, int smoothLength){
+    
+    //need to make new hannWindow!!
+    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++){
+        diffHannWindow[i] = -diffHannWindow[i];
+    }
+    
+    FIRFilter *smoothFilter = new FIRFilter(m_numberOfBlocks, smoothLength);
+    
+    for (int i = 0; i < m_blockSize; i++){
+        smoothFilter->process(&spectrogram[i][0], diffHannWindow, &spectrogram[i][0]);
+    }
+    
+    delete smoothFilter;
+    smoothFilter = NULL;
+}
+
+void NoveltyCurve::halfWaveRectify(vector< vector<float> > &spectrogram){ //should this return spectrogram??
+    
+    for (int block = 0; block < m_numberOfBlocks; block++){
+        for (int k = 0; k < m_blockSize; k++){
+            if (spectrogram[k][block] < 0.0) spectrogram[k][block] = 0.0;
+        }
+    }
+}
+
 vector<float>
-NoveltyCurve::spectrogramToNoveltyCurve(float ** spectrogram){
+NoveltyCurve::spectrogramToNoveltyCurve(vector< vector<float> > &spectrogram){
+    
+    assert(spectrogram.size() == m_blockSize);
+    assert(spectrogram[0].size() == m_numberOfBlocks);
     
     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
+            spectrogram[k][block] = log(1+m_compressionConstant*spectrogram[k][block]);
+        }
+    }
+
+    smoothedDifferentiator(spectrogram, 5); //make smoothLength a parameter!
+    halfWaveRectify(spectrogram);
+    
+    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;
             
-            int specIndex = m_bandBoundaries[band];
-            int bandEnd = m_bandBoundaries[band+1];
-            
-            while(specIndex < bandEnd){
-                
-                spectrogram[specIndex][block] /= normaliseScale; //normalise
-                spectrogram[specIndex][block] = log(1+m_compressionConstant*spectrogram[specIndex][block]);
-                
-                int currentY = spectrogram[specIndex][block];
-                int prevBlock = block-1;
-                int previousY = prevBlock >= 0 ? spectrogram[specIndex][prevBlock] : 0;
-                
-                if(currentY > previousY){
-                    m_bandSum[band][block] += (currentY - previousY);
-                }
-                
-                //cout << specIndex << endl;
-                specIndex++;
+            while(k < bandEnd){
+                m_bandSum[band] += spectrogram[k][block];
+                k++;
             }
         }
-        
         float total = 0;
         for(int band = 0; band < m_numberOfBands; band++){
-            total += m_bandSum[band][block];
+            total += m_bandSum[band];
         }
-        float average = total/m_numberOfBands;
-        data[block] = average;
+        data[block] = total/m_numberOfBands;
     }
     
-    subtractLocalAverage(&data[0]);
+    subtractLocalAverage(data);
     
     return data;
-}
\ No newline at end of file
+}
--- a/NoveltyCurve.h	Tue Aug 05 16:00:30 2014 +0100
+++ b/NoveltyCurve.h	Thu Aug 07 16:21:21 2014 +0100
@@ -10,9 +10,16 @@
 #define __Tempogram__NoveltyCurve__
 
 #include <iostream>
+#include <cmath>
+#include <vector>
+#include <iostream>
+#include "FIRFilter.h"
+#include "WindowFunction.h"
+#include <cassert>
 
 class NoveltyCurve{
     float m_samplingFrequency;
+    int m_fftLength;
     int m_blockSize;
     int m_numberOfBlocks;
     int m_compressionConstant;
@@ -20,19 +27,21 @@
     int * m_bandBoundaries;
     int m_hannLength;
     float * m_hannWindow;
-    float ** m_bandSum;
+    float * m_bandSum;
     
     void initialise();
     void cleanup();
-    float calculateMax(float ** spectrogram);
-    void subtractLocalAverage(float * noveltyCurve);
+    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);
     
 public:
-    vector<float> data;
+    std::vector<float> data;
     
-    NoveltyCurve(float samplingFrequency, int blockSize, int numberOfBlocks, int compressionConstant);
+    NoveltyCurve(float samplingFrequency, int fftLength, int numberOfBlocks, int compressionConstant);
     ~NoveltyCurve();
-    vector<float> spectrogramToNoveltyCurve(float ** spectrogram);
+    std::vector<float> spectrogramToNoveltyCurve(std::vector< std::vector<float> > &spectrogram);
 };
 
 #endif /* defined(__Tempogram__NoveltyCurve__) */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Spectrogram.cpp	Thu Aug 07 16:21:21 2014 +0100
@@ -0,0 +1,79 @@
+//
+//  Spectrogram.cpp
+//  Tempogram
+//
+//  Created by Carl Bussey on 07/08/2014.
+//  Copyright (c) 2014 Carl Bussey. All rights reserved.
+//
+
+#include "Spectrogram.h"
+#include <iostream>
+using namespace std;
+using Vamp::FFT;
+
+Spectrogram::Spectrogram(unsigned int inputLength, unsigned int fftLength, unsigned int hopSize) :
+    m_inputLength(inputLength),
+    m_fftLength(fftLength),
+    m_hopSize(hopSize),
+    m_numberOfOutputBins(floor(fftLength/2 + 0.5) + 1),
+    fftInput(NULL),
+    fftOutputReal(NULL),
+    fftOutputImag(NULL)
+{
+    initialise();
+}
+
+Spectrogram::~Spectrogram(){
+    cleanup();
+}
+
+void Spectrogram::initialise(){
+    fftInput = new double [m_fftLength];
+    fftOutputReal = new double [m_fftLength];
+    fftOutputImag = new double [m_fftLength];
+    
+    int numberOfBlocks = ceil(m_inputLength/m_hopSize) + m_fftLength/m_hopSize-1;
+    spectrogramOutput = vector< vector<float> >(m_numberOfOutputBins, vector<float>(numberOfBlocks));
+}
+
+void Spectrogram::cleanup(){
+    delete []fftInput;
+    delete []fftOutputReal;
+    delete []fftOutputImag;
+    
+    fftInput = fftOutputReal = fftOutputImag = NULL;
+    
+    cerr << "Spectrogram" << endl;
+}
+
+vector< vector<float> > Spectrogram::audioToMagnitudeSpectrogram(const float * const input, const float * window){
+    
+    int readPointerBeginIndex = m_hopSize-m_fftLength;
+    int writeBlockPointer = 0;
+    
+    while(readPointerBeginIndex < m_inputLength){
+        
+        int readPointer = readPointerBeginIndex;
+        for (int n = 0; n < m_fftLength; n++){
+            if(readPointer < 0 || readPointer >= m_inputLength){
+                fftInput[n] = 0.0; //pad with zeros
+            }
+            else{
+                fftInput[n] = input[readPointer] * window[n];
+            }
+            readPointer++;
+        }
+        
+        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?
+        }
+        
+        readPointerBeginIndex += m_hopSize;
+        writeBlockPointer++;
+    }
+    
+    return spectrogramOutput;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Spectrogram.h	Thu Aug 07 16:21:21 2014 +0100
@@ -0,0 +1,33 @@
+//
+//  Spectrogram.h
+//  Tempogram
+//
+//  Created by Carl Bussey on 07/08/2014.
+//  Copyright (c) 2014 Carl Bussey. All rights reserved.
+//
+
+#ifndef __Tempogram__Spectrogram__
+#define __Tempogram__Spectrogram__
+#include <vector>
+#include <vamp-sdk/FFT.h>
+#include <cmath>
+
+class Spectrogram{
+    int m_inputLength;
+    int m_fftLength;
+    int m_hopSize;
+    int m_numberOfOutputBins;
+    double * fftInput;
+    double * fftOutputReal;
+    double * fftOutputImag;
+    std::vector< std::vector <float> > spectrogramOutput;
+    
+    void initialise();
+    void cleanup();
+public:
+    std::vector< std::vector<float> > audioToMagnitudeSpectrogram(const float * const input, const float * window);
+    Spectrogram(unsigned int inputLength, unsigned int fftLength, unsigned int hopSize);
+    ~Spectrogram();
+};
+
+#endif /* defined(__Tempogram__Spectrogram__) */
--- a/Tempogram.cpp	Tue Aug 05 16:00:30 2014 +0100
+++ b/Tempogram.cpp	Thu Aug 07 16:21:21 2014 +0100
@@ -5,15 +5,9 @@
 
 
 #include "Tempogram.h"
-#include "FIRFilter.h"
-#include "WindowFunction.h"
-#include "NoveltyCurve.h"
-#include <vamp-sdk/FFT.h>
-#include <cmath>
-#include <fstream>
-#include <assert.h>
 
 using Vamp::FFT;
+using Vamp::RealTime;
 using namespace std;
 
 Tempogram::Tempogram(float inputSampleRate) :
@@ -22,12 +16,9 @@
     m_stepSize(0),
     compressionConstant(1000), //make param
     specMax(0),
-    previousY(NULL),
-    currentY(NULL),
-    spectrogram(NULL),
     minDB(0),
-    tN(256), //make param
-    thopSize(128), //make param
+    tN(128), //make param
+    thopSize(64), //make param
     fftInput(NULL),
     fftOutputReal(NULL),
     fftOutputImag(NULL),
@@ -42,6 +33,7 @@
 Tempogram::~Tempogram()
 {
     //delete stuff
+    cleanup();
 }
 
 string
@@ -154,7 +146,7 @@
     tN.unit = "";
     tN.minValue = 128;
     tN.maxValue = 4096;
-    tN.defaultValue = 1024;
+    tN.defaultValue = 128;
     tN.isQuantized = true;
     tN.quantizeStep = 128;
     list.push_back(tN);
@@ -217,20 +209,22 @@
     // Every plugin must have at least one output.
     
     OutputDescriptor d;
+    float d_sampleRate;
+    
     d.identifier = "tempogram";
-    d.name = "Cyclic Tempogram";
-    d.description = "Cyclic Tempogram";
+    d.name = "Tempogram";
+    d.description = "Tempogram";
     d.unit = "";
     d.hasFixedBinCount = true;
-    d.binCount = tN;
+    d.binCount = tN/2 + 1;
     d.hasKnownExtents = false;
     d.isQuantized = false;
     d.sampleType = OutputDescriptor::FixedSampleRate;
-    float d_sampleRate = m_inputSampleRate/(m_stepSize * thopSize);
+    d_sampleRate = m_inputSampleRate/(m_stepSize * thopSize);
     d.sampleRate = d_sampleRate > 0.0 && !isnan(d_sampleRate) ? d_sampleRate : 0.0;
     d.hasDuration = false;
     list.push_back(d);
-
+    
     d.identifier = "nc";
     d.name = "Novelty Curve";
     d.description = "Novelty Curve";
@@ -245,18 +239,6 @@
     d.hasDuration = false;
     list.push_back(d);
     
-    d.identifier = "spect";
-    d.name = "spect";
-    d.description = "spect";
-    d.unit = "";
-    d.hasFixedBinCount = true;
-    d.binCount = m_blockSize/2;
-    d.hasKnownExtents = false;
-    d.isQuantized = false;
-    d.sampleType = OutputDescriptor::OneSamplePerStep;
-    d.hasDuration = false;
-    list.push_back(d);
-    
     return list;
 }
 
@@ -269,20 +251,24 @@
     // Real initialisation work goes here!
     m_blockSize = blockSize;
     m_stepSize = stepSize;
-    currentY = new float[m_blockSize];
-    previousY = new float[m_blockSize];
-    minDB = pow((float)10,(float)-74/20);
+    minDB = pow(10,(float)-74/20);
     
     specData = vector< vector<float> >(m_blockSize/2 + 1);
-    spectrogram = new float * [m_blockSize/2 + 1];
     
     return true;
 }
 
+void Tempogram::cleanup(){
+
+}
+
 void
 Tempogram::reset()
 {
     // Clear buffers, reset stored values, etc
+    cleanupForGRF();
+    ncTimestamps.clear();
+    specData.clear();
 }
 
 Tempogram::FeatureSet
@@ -300,13 +286,11 @@
         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);
-        feature.values.push_back(magnitude);
     }
     
     numberOfBlocks++;
     ncTimestamps.push_back(timestamp);
-    featureSet[2].push_back(feature);
-    
+
     return featureSet;
 }
 
@@ -317,8 +301,11 @@
     fftOutputReal = new double[tN];
     fftOutputImag = new double[tN];
     
-    for (int i = 0; i < (m_blockSize/2 + 1); i ++){
-        spectrogram[i] = &specData[i][0];
+    for (int i = 0; i < tN; i ++){
+        hannWindowtN[i] = 0.0;
+        fftInput[i] = 0.0;
+        fftOutputReal[i] = 0.0;
+        fftOutputImag[i] = 0.0;
     }
 }
 
@@ -326,12 +313,7 @@
 Tempogram::cleanupForGRF(){
     delete []hannWindowtN;
     hannWindowtN = NULL;
-    delete []fftInput;
-    fftInput = NULL;
-    delete []fftOutputReal;
-    fftOutputReal = NULL;
-    delete []fftOutputImag;
-    fftOutputImag = NULL;
+    fftInput = fftOutputReal = fftOutputImag = NULL;
 }
 
 Tempogram::FeatureSet
@@ -342,60 +324,43 @@
     FeatureSet featureSet;
     
     NoveltyCurve nc(m_inputSampleRate, m_blockSize, numberOfBlocks, compressionConstant);
-    noveltyCurve = nc.spectrogramToNoveltyCurve(spectrogram);
+    noveltyCurve = nc.spectrogramToNoveltyCurve(specData);
     
     for (int i = 0; i < numberOfBlocks; i++){
-        Feature featureNC;
-        cout << "nc:" << noveltyCurve[i] << endl;
-        featureNC.values.push_back(noveltyCurve[i]);
-        featureNC.hasTimestamp = true;
-        featureNC.timestamp = ncTimestamps[i];
-        featureSet[1].push_back(featureNC);
+        Feature feature;
+        feature.values.push_back(noveltyCurve[i]);
+        feature.hasTimestamp = true;
+        feature.timestamp = ncTimestamps[i];
+        featureSet[1].push_back(feature);
     }
     
     WindowFunction::hanning(hannWindowtN, tN);
+    Spectrogram * spectrogramProcessor = new Spectrogram(numberOfBlocks, tN, thopSize);
+    vector< vector<float> > tempogram = spectrogramProcessor->audioToMagnitudeSpectrogram(&noveltyCurve[0], hannWindowtN);
     
-    int timestampInc = floor((((float)ncTimestamps[1].nsec - ncTimestamps[0].nsec)/1e9)*(thopSize) + 0.5);
-    int i = 0;
-    int index;
-    int frameBeginOffset = thopSize;
+    cout << "About to delete..." << endl;
+    delete spectrogramProcessor;
+    cout << "Deleted!" << endl;
+    spectrogramProcessor = NULL;
     
-    while(i < numberOfBlocks){
+    int timePointer = thopSize-tN/2;
+    int tempogramLength = tempogram[0].size();
+    
+    for (int block = 0; block < tempogramLength; block++){
         Feature feature;
         
-        for (int n = frameBeginOffset; n < tN; n++){
-            index = i + n - thopSize;
-            assert (index >= 0);
-            
-            if(index < numberOfBlocks){
-                fftInput[n] = noveltyCurve[i + n] * hannWindowtN[n];
-            }
-            else if(index >= numberOfBlocks){
-                fftInput[n] = 0.0; //pad the end with zeros
-            }
+        int timeMS = floor(1000*(m_stepSize*timePointer)/m_inputSampleRate + 0.5);
+        
+        cout << timeMS << endl;
+        
+        for(int k = 0; k < tN/2 + 1; k++){
+            feature.values.push_back(tempogram[k][block]);
         }
+        feature.hasTimestamp = true;
+        feature.timestamp = RealTime::fromMilliseconds(timeMS);
+        featureSet[0].push_back(feature);
         
-        if (i+thopSize > numberOfBlocks){
-            feature.timestamp = Vamp::RealTime::fromSeconds(ncTimestamps[i].sec + timestampInc);
-        }
-        else{
-            feature.timestamp = ncTimestamps[i + thopSize];
-        }
-        
-        FFT::forward(tN, fftInput, NULL, fftOutputReal, fftOutputImag);
-        
-        //@todo: sample at logarithmic spacing? Leave for host?
-        for(int k = 0; k < tN; k++){
-            float fftOutputPower = (fftOutputReal[k]*fftOutputReal[k] + fftOutputImag[k]*fftOutputImag[k]); //Magnitude or power?
-            
-            feature.values.push_back(fftOutputPower);
-        }
-
-        i += thopSize;
-        frameBeginOffset = 0;
-        
-        feature.hasTimestamp = true;
-        featureSet[0].push_back(feature);
+        timePointer += thopSize;
     }
     
     //Make sure this is called at the end of the function
--- a/Tempogram.h	Tue Aug 05 16:00:30 2014 +0100
+++ b/Tempogram.h	Thu Aug 07 16:21:21 2014 +0100
@@ -9,6 +9,14 @@
 #define _TEMPOGRAM_H_
 
 #include <vamp-sdk/Plugin.h>
+#include "FIRFilter.h"
+#include "WindowFunction.h"
+#include "NoveltyCurve.h"
+#include <vamp-sdk/FFT.h>
+#include <cmath>
+#include <fstream>
+#include <assert.h>
+#include "Spectrogram.h"
 
 using std::string;
 using std::vector;
@@ -43,6 +51,7 @@
     OutputList getOutputDescriptors() const;
 
     bool initialise(size_t channels, size_t stepSize, size_t blockSize);
+    void cleanup();
     void initialiseForGRF();
     void cleanupForGRF();
     void reset();
@@ -61,7 +70,6 @@
     float *previousY;
     float *currentY;
     vector< vector<float> > specData;
-    float ** spectrogram;
     vector<float> noveltyCurve;
     float minDB;
     
--- a/WindowFunction.cpp	Tue Aug 05 16:00:30 2014 +0100
+++ b/WindowFunction.cpp	Thu Aug 07 16:21:21 2014 +0100
@@ -7,9 +7,6 @@
 //
 
 #include "WindowFunction.h"
-#include <cmath>
-#include <vector>
-#include <iostream>
 using std::vector;
 
 void
--- a/WindowFunction.h	Tue Aug 05 16:00:30 2014 +0100
+++ b/WindowFunction.h	Thu Aug 07 16:21:21 2014 +0100
@@ -10,6 +10,8 @@
 #define __Tempogram__WindowFunction__
 
 #include <iostream>
+#include <cmath>
+#include <vector>
 
 class WindowFunction{
 public:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vamp-plugin.list	Thu Aug 07 16:21:21 2014 +0100
@@ -0,0 +1,1 @@
+_vampGetPluginDescriptor
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vamp-plugin.map	Thu Aug 07 16:21:21 2014 +0100
@@ -0,0 +1,4 @@
+{
+	global: vampGetPluginDescriptor;
+	local: *;
+};