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@7
|
9 #include "NoveltyCurve.h"
|
c@5
|
10 using namespace std;
|
c@5
|
11
|
c@7
|
12 NoveltyCurve::NoveltyCurve(float samplingFrequency, int fftLength, int numberOfBlocks, int compressionConstant) :
|
c@5
|
13 m_samplingFrequency(samplingFrequency),
|
c@7
|
14 m_fftLength(fftLength),
|
c@7
|
15 m_blockSize(fftLength/2 + 1),
|
c@5
|
16 m_numberOfBlocks(numberOfBlocks),
|
c@5
|
17 m_compressionConstant(compressionConstant),
|
c@5
|
18 m_numberOfBands(5),
|
c@5
|
19 m_bandBoundaries(NULL),
|
c@5
|
20 m_hannLength(65),
|
c@5
|
21 m_hannWindow(NULL),
|
c@5
|
22 m_bandSum(NULL)
|
c@5
|
23 {
|
c@5
|
24 initialise();
|
c@5
|
25 }
|
c@5
|
26
|
c@5
|
27 NoveltyCurve::~NoveltyCurve(){
|
c@5
|
28 cleanup();
|
c@5
|
29 }
|
c@5
|
30
|
c@5
|
31 void
|
c@5
|
32 NoveltyCurve::initialise(){
|
c@5
|
33 data = vector<float>(m_numberOfBlocks);
|
c@5
|
34
|
c@5
|
35 m_hannWindow = new float[m_hannLength];
|
c@5
|
36 WindowFunction::hanning(m_hannWindow, m_hannLength, true);
|
c@5
|
37
|
c@5
|
38 m_bandBoundaries = new int[m_numberOfBands+1]; //make index variable
|
c@5
|
39
|
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@5
|
50 void
|
c@5
|
51 NoveltyCurve::cleanup(){
|
c@5
|
52 delete []m_hannWindow;
|
c@5
|
53 m_hannWindow = NULL;
|
c@5
|
54 delete []m_bandBoundaries;
|
c@5
|
55 m_bandBoundaries = NULL;
|
c@5
|
56 delete []m_bandSum;
|
c@5
|
57 m_bandSum = NULL;
|
c@5
|
58 }
|
c@5
|
59
|
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@7
|
72 void NoveltyCurve::subtractLocalAverage(vector<float> &noveltyCurve){
|
c@5
|
73 vector<float> localAverage(m_numberOfBlocks);
|
c@5
|
74
|
c@5
|
75 FIRFilter *filter = new FIRFilter(m_numberOfBlocks, m_hannLength);
|
c@5
|
76 filter->process(&noveltyCurve[0], m_hannWindow, &localAverage[0]);
|
c@5
|
77 delete filter;
|
c@7
|
78 filter = NULL;
|
c@5
|
79
|
c@7
|
80 assert(noveltyCurve.size() == m_numberOfBlocks);
|
c@5
|
81 for (int i = 0; i < m_numberOfBlocks; i++){
|
c@5
|
82 noveltyCurve[i] -= localAverage[i];
|
c@5
|
83 noveltyCurve[i] = noveltyCurve[i] >= 0 ? noveltyCurve[i] : 0;
|
c@5
|
84 }
|
c@5
|
85 }
|
c@5
|
86
|
c@7
|
87 void NoveltyCurve::smoothedDifferentiator(vector< vector<float> > &spectrogram, int smoothLength){
|
c@7
|
88
|
c@7
|
89 //need to make new hannWindow!!
|
c@7
|
90 float * diffHannWindow = new float [smoothLength];
|
c@7
|
91 WindowFunction::hanning(diffHannWindow, smoothLength, true);
|
c@7
|
92
|
c@7
|
93 if(smoothLength%2) diffHannWindow[(smoothLength+1)/2 - 1] = 0;
|
c@7
|
94 for(int i = (smoothLength+1)/2; i < smoothLength; i++){
|
c@7
|
95 diffHannWindow[i] = -diffHannWindow[i];
|
c@7
|
96 }
|
c@7
|
97
|
c@7
|
98 FIRFilter *smoothFilter = new FIRFilter(m_numberOfBlocks, smoothLength);
|
c@7
|
99
|
c@7
|
100 for (int i = 0; i < m_blockSize; i++){
|
c@7
|
101 smoothFilter->process(&spectrogram[i][0], diffHannWindow, &spectrogram[i][0]);
|
c@7
|
102 }
|
c@7
|
103
|
c@7
|
104 delete smoothFilter;
|
c@7
|
105 smoothFilter = NULL;
|
c@7
|
106 }
|
c@7
|
107
|
c@7
|
108 void NoveltyCurve::halfWaveRectify(vector< vector<float> > &spectrogram){ //should this return spectrogram??
|
c@7
|
109
|
c@7
|
110 for (int block = 0; block < m_numberOfBlocks; block++){
|
c@7
|
111 for (int k = 0; k < m_blockSize; k++){
|
c@7
|
112 if (spectrogram[k][block] < 0.0) spectrogram[k][block] = 0.0;
|
c@7
|
113 }
|
c@7
|
114 }
|
c@7
|
115 }
|
c@7
|
116
|
c@5
|
117 vector<float>
|
c@7
|
118 NoveltyCurve::spectrogramToNoveltyCurve(vector< vector<float> > &spectrogram){
|
c@7
|
119
|
c@7
|
120 assert(spectrogram.size() == m_blockSize);
|
c@7
|
121 assert(spectrogram[0].size() == m_numberOfBlocks);
|
c@5
|
122
|
c@5
|
123 float normaliseScale = calculateMax(spectrogram);
|
c@5
|
124
|
c@5
|
125 for (int block = 0; block < m_numberOfBlocks; block++){
|
c@7
|
126 for (int k = 0; k < m_blockSize; k++){
|
c@7
|
127 if(normaliseScale != 0.0) spectrogram[k][block] /= normaliseScale; //normalise
|
c@7
|
128 spectrogram[k][block] = log(1+m_compressionConstant*spectrogram[k][block]);
|
c@7
|
129 }
|
c@7
|
130 }
|
c@7
|
131
|
c@7
|
132 smoothedDifferentiator(spectrogram, 5); //make smoothLength a parameter!
|
c@7
|
133 halfWaveRectify(spectrogram);
|
c@7
|
134
|
c@7
|
135 for (int block = 0; block < m_numberOfBlocks; block++){
|
c@5
|
136 for (int band = 0; band < m_numberOfBands; band++){
|
c@7
|
137 int k = m_bandBoundaries[band];
|
c@7
|
138 int bandEnd = m_bandBoundaries[band+1];
|
c@7
|
139 m_bandSum[band] = 0;
|
c@5
|
140
|
c@7
|
141 while(k < bandEnd){
|
c@7
|
142 m_bandSum[band] += spectrogram[k][block];
|
c@7
|
143 k++;
|
c@5
|
144 }
|
c@5
|
145 }
|
c@5
|
146 float total = 0;
|
c@5
|
147 for(int band = 0; band < m_numberOfBands; band++){
|
c@7
|
148 total += m_bandSum[band];
|
c@5
|
149 }
|
c@7
|
150 data[block] = total/m_numberOfBands;
|
c@5
|
151 }
|
c@5
|
152
|
c@7
|
153 subtractLocalAverage(data);
|
c@5
|
154
|
c@5
|
155 return data;
|
c@7
|
156 }
|