annotate NoveltyCurve.cpp @ 11:09fb76606b2b

* Removed many unnecessary heap allocations with objects
author Carl Bussey <c.bussey@se10.qmul.ac.uk>
date Wed, 13 Aug 2014 10:45:46 +0100
parents be59b4a73f49
children 7680cc4c0073
rev   line source
c@5 1 //
c@5 2 // NoveltyCurve.cpp
c@5 3 // Tempogram
c@5 4 //
c@5 5 // Created by Carl Bussey on 10/07/2014.
c@5 6 // Copyright (c) 2014 Carl Bussey. All rights reserved.
c@5 7 //
c@5 8
c@11 9 //Spectrogram dimensions should be flipped?
c@11 10
c@7 11 #include "NoveltyCurve.h"
c@11 12 #include <memory>
c@5 13 using namespace std;
c@5 14
c@7 15 NoveltyCurve::NoveltyCurve(float samplingFrequency, int fftLength, int numberOfBlocks, int compressionConstant) :
c@5 16 m_samplingFrequency(samplingFrequency),
c@7 17 m_fftLength(fftLength),
c@7 18 m_blockSize(fftLength/2 + 1),
c@5 19 m_numberOfBlocks(numberOfBlocks),
c@5 20 m_compressionConstant(compressionConstant),
c@5 21 m_numberOfBands(5),
c@5 22 m_bandBoundaries(NULL),
c@5 23 m_hannLength(65),
c@5 24 m_bandSum(NULL)
c@5 25 {
c@5 26 initialise();
c@5 27 }
c@5 28
c@5 29 NoveltyCurve::~NoveltyCurve(){
c@5 30 cleanup();
c@5 31 }
c@5 32
c@9 33 //allocate all space and set variable
c@5 34 void
c@5 35 NoveltyCurve::initialise(){
c@5 36 data = vector<float>(m_numberOfBlocks);
c@5 37
c@9 38 // for bandwise processing, the band is split into 5 bands. m_bandBoundaries contains the upper and lower bin boundaries for each band.
c@9 39 m_bandBoundaries = new int[m_numberOfBands+1];
c@5 40 m_bandBoundaries[0] = 0;
c@5 41 for (int band = 1; band < m_numberOfBands; band++){
c@5 42 float lowFreq = 500*pow(2.5, band-1);
c@7 43 m_bandBoundaries[band] = m_fftLength*lowFreq/m_samplingFrequency;
c@5 44 }
c@7 45 m_bandBoundaries[m_numberOfBands] = m_blockSize;
c@5 46
c@7 47 m_bandSum = new float [m_numberOfBands];
c@5 48 }
c@5 49
c@9 50 //delete space allocated in initialise()
c@5 51 void
c@5 52 NoveltyCurve::cleanup(){
c@5 53 delete []m_bandBoundaries;
c@5 54 m_bandBoundaries = NULL;
c@5 55 delete []m_bandSum;
c@5 56 m_bandSum = NULL;
c@5 57 }
c@5 58
c@9 59 //calculate max of spectrogram
c@7 60 float NoveltyCurve::calculateMax(vector< vector<float> > &spectrogram){
c@5 61 float max = 0;
c@5 62
c@5 63 for (int j = 0; j < m_numberOfBlocks; j++){
c@7 64 for (int i = 0; i < m_blockSize; i++){
c@7 65 max = max > fabs(spectrogram[i][j]) ? max : fabs(spectrogram[i][j]);
c@5 66 }
c@5 67 }
c@5 68
c@5 69 return max;
c@5 70 }
c@5 71
c@9 72 //subtract local average of novelty curve
c@9 73 //uses m_hannWindow as filter
c@7 74 void NoveltyCurve::subtractLocalAverage(vector<float> &noveltyCurve){
c@5 75 vector<float> localAverage(m_numberOfBlocks);
c@5 76
c@9 77 float * m_hannWindow = new float[m_hannLength];
c@9 78 WindowFunction::hanning(m_hannWindow, m_hannLength, true);
c@9 79
c@11 80 FIRFilter filter(m_numberOfBlocks, m_hannLength);
c@11 81 filter.process(&noveltyCurve[0], m_hannWindow, &localAverage[0]);
c@5 82
c@7 83 assert(noveltyCurve.size() == m_numberOfBlocks);
c@5 84 for (int i = 0; i < m_numberOfBlocks; i++){
c@5 85 noveltyCurve[i] -= localAverage[i];
c@5 86 noveltyCurve[i] = noveltyCurve[i] >= 0 ? noveltyCurve[i] : 0;
c@5 87 }
c@9 88
c@11 89 delete []m_hannWindow;
c@9 90 m_hannWindow = NULL;
c@5 91 }
c@5 92
c@9 93 //smoothed differentiator filter. Flips upper half of hanning window about y-axis to create coefficients.
c@7 94 void NoveltyCurve::smoothedDifferentiator(vector< vector<float> > &spectrogram, int smoothLength){
c@7 95
c@7 96 float * diffHannWindow = new float [smoothLength];
c@7 97 WindowFunction::hanning(diffHannWindow, smoothLength, true);
c@7 98
c@7 99 if(smoothLength%2) diffHannWindow[(smoothLength+1)/2 - 1] = 0;
c@7 100 for(int i = (smoothLength+1)/2; i < smoothLength; i++){
c@7 101 diffHannWindow[i] = -diffHannWindow[i];
c@7 102 }
c@7 103
c@11 104 FIRFilter smoothFilter(m_numberOfBlocks, smoothLength);
c@7 105
c@7 106 for (int i = 0; i < m_blockSize; i++){
c@11 107 smoothFilter.process(&spectrogram[i][0], diffHannWindow, &spectrogram[i][0]);
c@7 108 }
c@7 109 }
c@7 110
c@9 111 //half rectification (set negative to zero)
c@9 112 void NoveltyCurve::halfWaveRectify(vector< vector<float> > &spectrogram){
c@7 113
c@7 114 for (int block = 0; block < m_numberOfBlocks; block++){
c@7 115 for (int k = 0; k < m_blockSize; k++){
c@7 116 if (spectrogram[k][block] < 0.0) spectrogram[k][block] = 0.0;
c@7 117 }
c@7 118 }
c@7 119 }
c@7 120
c@9 121 //process method
c@5 122 vector<float>
c@11 123 NoveltyCurve::spectrogramToNoveltyCurve(vector< vector<float> > spectrogram){
c@7 124
c@7 125 assert(spectrogram.size() == m_blockSize);
c@7 126 assert(spectrogram[0].size() == m_numberOfBlocks);
c@5 127
c@9 128 //normalise and log spectrogram
c@5 129 float normaliseScale = calculateMax(spectrogram);
c@5 130 for (int block = 0; block < m_numberOfBlocks; block++){
c@7 131 for (int k = 0; k < m_blockSize; k++){
c@7 132 if(normaliseScale != 0.0) spectrogram[k][block] /= normaliseScale; //normalise
c@7 133 spectrogram[k][block] = log(1+m_compressionConstant*spectrogram[k][block]);
c@7 134 }
c@7 135 }
c@7 136
c@9 137 //smooted differentiator
c@7 138 smoothedDifferentiator(spectrogram, 5); //make smoothLength a parameter!
c@9 139 //halfwave rectification
c@7 140 halfWaveRectify(spectrogram);
c@7 141
c@9 142 //bandwise processing
c@7 143 for (int block = 0; block < m_numberOfBlocks; block++){
c@5 144 for (int band = 0; band < m_numberOfBands; band++){
c@7 145 int k = m_bandBoundaries[band];
c@7 146 int bandEnd = m_bandBoundaries[band+1];
c@7 147 m_bandSum[band] = 0;
c@5 148
c@7 149 while(k < bandEnd){
c@7 150 m_bandSum[band] += spectrogram[k][block];
c@7 151 k++;
c@5 152 }
c@5 153 }
c@5 154 float total = 0;
c@5 155 for(int band = 0; band < m_numberOfBands; band++){
c@7 156 total += m_bandSum[band];
c@5 157 }
c@7 158 data[block] = total/m_numberOfBands;
c@5 159 }
c@5 160
c@9 161 //subtract local averages
c@7 162 subtractLocalAverage(data);
c@5 163
c@5 164 return data;
c@7 165 }