annotate NoveltyCurveProcessor.cpp @ 23:7d36c742a183

* Tidying in TempogramPlugin.cpp
author Carl Bussey <c.bussey@se10.qmul.ac.uk>
date Tue, 19 Aug 2014 17:40:10 +0100
parents 99380ba63be6
children 957b83524c06
rev   line source
c@5 1 //
c@17 2 // NoveltyCurveProcessor.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@14 11 #include "NoveltyCurveProcessor.h"
c@5 12 using namespace std;
c@5 13
c@22 14 NoveltyCurveProcessor::NoveltyCurveProcessor(const float &samplingFrequency, const size_t &fftLength, const size_t &compressionConstant) :
c@5 15 m_samplingFrequency(samplingFrequency),
c@7 16 m_fftLength(fftLength),
c@7 17 m_blockSize(fftLength/2 + 1),
c@5 18 m_compressionConstant(compressionConstant),
c@5 19 m_numberOfBands(5),
c@13 20 m_pBandBoundaries(0),
c@13 21 m_pBandSum(0)
c@5 22 {
c@5 23 initialise();
c@5 24 }
c@5 25
c@14 26 NoveltyCurveProcessor::~NoveltyCurveProcessor(){
c@5 27 cleanup();
c@5 28 }
c@5 29
c@9 30 //allocate all space and set variable
c@5 31 void
c@14 32 NoveltyCurveProcessor::initialise(){
c@5 33
c@13 34 // for bandwise processing, the band is split into 5 bands. m_pBandBoundaries contains the upper and lower bin boundaries for each band.
c@13 35 m_pBandBoundaries = new int[m_numberOfBands+1];
c@13 36 m_pBandBoundaries[0] = 0;
c@13 37 for (unsigned int band = 1; band < m_numberOfBands; band++){
c@13 38 float lowFreq = 500*pow(2.5, (int)band-1);
c@13 39 m_pBandBoundaries[band] = m_fftLength*lowFreq/m_samplingFrequency;
c@5 40 }
c@13 41 m_pBandBoundaries[m_numberOfBands] = m_blockSize;
c@5 42
c@13 43 m_pBandSum = new float [m_numberOfBands];
c@5 44 }
c@5 45
c@9 46 //delete space allocated in initialise()
c@5 47 void
c@14 48 NoveltyCurveProcessor::cleanup(){
c@13 49 delete []m_pBandBoundaries;
c@13 50 m_pBandBoundaries = 0;
c@13 51 delete []m_pBandSum;
c@13 52 m_pBandSum = 0;
c@5 53 }
c@5 54
c@9 55 //calculate max of spectrogram
c@22 56 float NoveltyCurveProcessor::calculateMax(const Spectrogram &spectrogram) const
c@13 57 {
c@5 58 float max = 0;
c@5 59
c@22 60 int length = spectrogram.size();
c@22 61 int height = spectrogram[0].size();
c@22 62
c@22 63 for (int i = 0; i < length; i++){
c@22 64 for (int j = 0; j < height; j++){
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@14 74 void NoveltyCurveProcessor::subtractLocalAverage(vector<float> &noveltyCurve, const size_t &smoothLength) const
c@13 75 {
c@22 76 int numberOfBlocks = noveltyCurve.size();
c@22 77 vector<float> localAverage(numberOfBlocks);
c@5 78
c@13 79 float * m_hannWindow = new float[smoothLength];
c@13 80 WindowFunction::hanning(m_hannWindow, smoothLength, true);
c@9 81
c@22 82 FIRFilter filter(numberOfBlocks, smoothLength);
c@15 83 filter.process(&noveltyCurve[0], m_hannWindow, &localAverage[0], FIRFilter::middle);
c@5 84
c@22 85 for (int i = 0; i < numberOfBlocks; i++){
c@5 86 noveltyCurve[i] -= localAverage[i];
c@5 87 noveltyCurve[i] = noveltyCurve[i] >= 0 ? noveltyCurve[i] : 0;
c@5 88 }
c@9 89
c@11 90 delete []m_hannWindow;
c@13 91 m_hannWindow = 0;
c@5 92 }
c@5 93
c@9 94 //smoothed differentiator filter. Flips upper half of hanning window about y-axis to create coefficients.
c@22 95 void NoveltyCurveProcessor::smoothedDifferentiator(SpectrogramTransposed &spectrogramTransposed, const size_t &smoothLength) const
c@13 96 {
c@7 97
c@22 98 int numberOfBlocks = spectrogramTransposed[0].size();
c@22 99
c@7 100 float * diffHannWindow = new float [smoothLength];
c@7 101 WindowFunction::hanning(diffHannWindow, smoothLength, true);
c@7 102
c@7 103 if(smoothLength%2) diffHannWindow[(smoothLength+1)/2 - 1] = 0;
c@20 104 for(int i = (smoothLength+1)/2; i < (int)smoothLength; i++){
c@7 105 diffHannWindow[i] = -diffHannWindow[i];
c@7 106 }
c@7 107
c@22 108 FIRFilter smoothFilter(numberOfBlocks, smoothLength);
c@7 109
c@20 110 for (int i = 0; i < (int)m_blockSize; i++){
c@22 111 smoothFilter.process(&spectrogramTransposed[i][0], diffHannWindow, &spectrogramTransposed[i][0], FIRFilter::middle);
c@7 112 }
c@7 113 }
c@7 114
c@9 115 //half rectification (set negative to zero)
c@22 116 void NoveltyCurveProcessor::halfWaveRectify(SpectrogramTransposed &spectrogramTransposed) const
c@13 117 {
c@22 118 int numberOfBlocks = spectrogramTransposed[0].size();
c@22 119
c@23 120 for (int block = 0; block < numberOfBlocks; block++){
c@20 121 for (int k = 0; k < (int)m_blockSize; k++){
c@22 122 if (spectrogramTransposed[k][block] < 0.0) spectrogramTransposed[k][block] = 0.0;
c@7 123 }
c@7 124 }
c@7 125 }
c@7 126
c@9 127 //process method
c@5 128 vector<float>
c@22 129 NoveltyCurveProcessor::spectrogramToNoveltyCurve(const Spectrogram &spectrogram) const //make argument const &
c@13 130 {
c@22 131 int numberOfBlocks = spectrogram.size();
c@22 132 std::vector<float> noveltyCurve(numberOfBlocks);
c@22 133 SpectrogramTransposed spectrogramTransposed(spectrogram[0].size(), vector<float>(spectrogram.size()));
c@5 134
c@9 135 //normalise and log spectrogram
c@5 136 float normaliseScale = calculateMax(spectrogram);
c@22 137 for (int block = 0; block < (int)numberOfBlocks; block++){
c@20 138 for (int k = 0; k < (int)m_blockSize; k++){
c@22 139 spectrogramTransposed[k][block] = log(1+m_compressionConstant*spectrogram[block][k]);
c@22 140 if(normaliseScale != 0.0) spectrogramTransposed[k][block] /= normaliseScale; //normalise
c@7 141 }
c@7 142 }
c@7 143
c@9 144 //smooted differentiator
c@22 145 smoothedDifferentiator(spectrogramTransposed, 5); //make smoothLength a parameter!
c@9 146 //halfwave rectification
c@22 147 halfWaveRectify(spectrogramTransposed);
c@7 148
c@9 149 //bandwise processing
c@22 150 for (int block = 0; block < (int)numberOfBlocks; block++){
c@20 151 for (int band = 0; band < (int)m_numberOfBands; band++){
c@13 152 int k = m_pBandBoundaries[band];
c@13 153 int bandEnd = m_pBandBoundaries[band+1];
c@13 154 m_pBandSum[band] = 0;
c@5 155
c@7 156 while(k < bandEnd){
c@22 157 m_pBandSum[band] += spectrogramTransposed[k][block];
c@7 158 k++;
c@5 159 }
c@5 160 }
c@5 161 float total = 0;
c@20 162 for(int band = 0; band < (int)m_numberOfBands; band++){
c@13 163 total += m_pBandSum[band];
c@5 164 }
c@13 165 noveltyCurve[block] = total/m_numberOfBands;
c@5 166 }
c@5 167
c@9 168 //subtract local averages
c@13 169 subtractLocalAverage(noveltyCurve, 65);
c@5 170
c@13 171 return noveltyCurve;
c@7 172 }