comparison NoveltyCurveProcessor.cpp @ 14:c11367df624d

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