andrew@0
|
1
|
andrew@0
|
2
|
andrew@0
|
3 #include "Chromagram.h"
|
andrew@0
|
4 #include <iostream>
|
andrew@0
|
5 #include <math.h>
|
andrew@0
|
6 using namespace std;
|
andrew@0
|
7
|
andrew@0
|
8 Chromagram :: Chromagram()
|
andrew@0
|
9 {
|
andrew@0
|
10 pi = 3.14159265;
|
andrew@0
|
11 bsize = 8192;
|
andrew@0
|
12
|
andrew@0
|
13 // array init
|
andrew@0
|
14 buffer = new float[8192]; // make audio buffer
|
andrew@0
|
15 wbuffer = new float[8192]; // to hold windowed audio buffer
|
andrew@0
|
16 win = new float[8192];
|
andrew@0
|
17 d_frame = new float[128];
|
andrew@0
|
18 hop = new float[1024];
|
andrew@0
|
19 mag = new float[(bsize/2)+1];
|
andrew@0
|
20
|
andrew@0
|
21 maximumChromaValue = 0;
|
andrew@0
|
22
|
andrew@0
|
23 float base = 130.81278265;
|
andrew@0
|
24
|
andrew@0
|
25 for (int i = 0;i < 12;i++)
|
andrew@0
|
26 {
|
andrew@0
|
27 note[i] = base*pow(2,(((float) i)/12));
|
andrew@0
|
28 }
|
andrew@0
|
29
|
andrew@0
|
30 harmonics = 2;
|
andrew@0
|
31 octaves = 2;
|
andrew@0
|
32 search = 2; // p is number of bins either side of target to search for other peaks
|
andrew@0
|
33
|
andrew@0
|
34 out = (fftwf_complex*) fftwf_malloc(sizeof(fftwf_complex) * bsize); // complex array to hold fft
|
andrew@0
|
35 p = fftwf_plan_dft_r2c_1d(bsize,wbuffer,out,FFTW_FORWARD*-1); // plan for executing fft of wbuffer
|
andrew@0
|
36
|
andrew@0
|
37 chromaready = 0;
|
andrew@0
|
38 }
|
andrew@0
|
39
|
andrew@0
|
40 //--------------------------------------------------------------------------------------
|
andrew@0
|
41 // destructor
|
andrew@0
|
42 Chromagram :: ~Chromagram()
|
andrew@0
|
43 {
|
andrew@0
|
44 // destroy fft plan
|
andrew@0
|
45 fftwf_destroy_plan(p);
|
andrew@0
|
46
|
andrew@0
|
47 // deallocate memory
|
andrew@0
|
48 win = NULL;
|
andrew@0
|
49 delete [] win;
|
andrew@0
|
50 buffer = NULL;
|
andrew@0
|
51 delete [] buffer;
|
andrew@0
|
52 wbuffer = NULL;
|
andrew@0
|
53 delete [] wbuffer;
|
andrew@0
|
54 }
|
andrew@0
|
55
|
andrew@0
|
56 //--------------------------------------------------------------------------------------
|
andrew@0
|
57 // Initialises all framesize dependent variables. Should be called to properly initialise variables and anytime the frame size changes.
|
andrew@0
|
58 void Chromagram :: initialise(int framesize,int hsize)
|
andrew@0
|
59 {
|
andrew@0
|
60 fsize = framesize;
|
andrew@0
|
61 hopsize = hsize;
|
andrew@0
|
62
|
andrew@0
|
63 d_frame = new float[fsize/4];
|
andrew@0
|
64 hop = new float[hopsize];
|
andrew@0
|
65
|
andrew@0
|
66
|
andrew@0
|
67 calcrate = (hopsize*4)/fsize;
|
andrew@0
|
68
|
andrew@0
|
69 count = 0;
|
andrew@0
|
70
|
andrew@0
|
71 //fsize = framesize; // set frame size
|
andrew@0
|
72
|
andrew@0
|
73 ratio = ((float) 11025) / ((float) 8192);
|
andrew@0
|
74 hamming(bsize); // define a hanning window offline
|
andrew@0
|
75 }
|
andrew@0
|
76
|
andrew@0
|
77 //--------------------------------------------------------------------------------------
|
andrew@0
|
78 // Processes a single frame
|
andrew@0
|
79 void Chromagram :: processframe(float frame[])
|
andrew@0
|
80 {
|
andrew@0
|
81 int i;
|
andrew@0
|
82 int j;
|
andrew@0
|
83 int c;
|
andrew@0
|
84
|
andrew@0
|
85 chromaready = 0; // default case that chroma isn't ready
|
andrew@0
|
86
|
andrew@0
|
87 // downsample frame
|
andrew@0
|
88 downsampleframe(frame);
|
andrew@0
|
89
|
andrew@0
|
90 if (count < calcrate)
|
andrew@0
|
91 {
|
andrew@0
|
92 c = count*(fsize/4);
|
andrew@0
|
93
|
andrew@0
|
94 j = 0;
|
andrew@0
|
95 for (i = c;i < c+(fsize/4);i++)
|
andrew@0
|
96 {
|
andrew@0
|
97 hop[i] = d_frame[j];
|
andrew@0
|
98 j++;
|
andrew@0
|
99 }
|
andrew@0
|
100 count = count + 1;
|
andrew@0
|
101 }
|
andrew@0
|
102
|
andrew@0
|
103 if (count == calcrate)
|
andrew@0
|
104 {
|
andrew@0
|
105 for (i=0;i < 8192-hopsize;i++)
|
andrew@0
|
106 {
|
andrew@0
|
107 buffer[i] = buffer[i+hopsize];
|
andrew@0
|
108 }
|
andrew@0
|
109
|
andrew@0
|
110 j = 0;
|
andrew@0
|
111 for (i=8192-hopsize;i < bsize;i++)
|
andrew@0
|
112 {
|
andrew@0
|
113 buffer[i] = hop[j];
|
andrew@0
|
114 j++;
|
andrew@0
|
115 }
|
andrew@0
|
116
|
andrew@0
|
117 chromacalc(buffer);
|
andrew@0
|
118
|
andrew@0
|
119 count = 0;
|
andrew@0
|
120 }
|
andrew@0
|
121
|
andrew@0
|
122
|
andrew@0
|
123 }
|
andrew@0
|
124
|
andrew@0
|
125 //--------------------------------------------------------------------------------------
|
andrew@0
|
126 // Processes a single frame
|
andrew@0
|
127 void Chromagram :: downsampleframe(float frame[])
|
andrew@0
|
128 {
|
andrew@0
|
129 float filt_frame[fsize];
|
andrew@0
|
130
|
andrew@0
|
131 float b0,b1,b2,a1,a2;
|
andrew@0
|
132 float x_1,x_2,y_1,y_2;
|
andrew@0
|
133
|
andrew@0
|
134 b0 = 0.2929;
|
andrew@0
|
135 b1 = 0.5858;
|
andrew@0
|
136 b2 = 0.2929;
|
andrew@0
|
137 a1 = -0.0000;
|
andrew@0
|
138 a2 = 0.1716;
|
andrew@0
|
139
|
andrew@0
|
140 x_1 = 0;
|
andrew@0
|
141 x_2 = 0;
|
andrew@0
|
142 y_1 = 0;
|
andrew@0
|
143 y_2 = 0;
|
andrew@0
|
144
|
andrew@0
|
145 for (int i=0;i < fsize;i++)
|
andrew@0
|
146 {
|
andrew@0
|
147 filt_frame[i] = frame[i]*b0 + x_1*b1 + x_2*b2 - y_1*a1 - y_2*a2;
|
andrew@0
|
148
|
andrew@0
|
149 x_2 = x_1;
|
andrew@0
|
150 x_1 = frame[i];
|
andrew@0
|
151 y_2 = y_1;
|
andrew@0
|
152 y_1 = filt_frame[i];
|
andrew@0
|
153 }
|
andrew@0
|
154
|
andrew@0
|
155 for (int i=0;i < (fsize/4);i++)
|
andrew@0
|
156 {
|
andrew@0
|
157 d_frame[i] = filt_frame[i*4];
|
andrew@0
|
158 }
|
andrew@0
|
159
|
andrew@0
|
160 }
|
andrew@0
|
161
|
andrew@0
|
162 //--------------------------------------------------------------------------------------
|
andrew@0
|
163 // main function to be called with 8192 sample frame at 11025 Hz
|
andrew@0
|
164 void Chromagram :: chromacalc(float frame[])
|
andrew@0
|
165 {
|
andrew@0
|
166 int i;
|
andrew@0
|
167
|
andrew@0
|
168 // apply hanning window to buffer
|
andrew@0
|
169 for (i = 0; i < bsize;i++)
|
andrew@0
|
170 {
|
andrew@0
|
171 wbuffer[i] = frame[i] * win[i];
|
andrew@0
|
172 }
|
andrew@0
|
173
|
andrew@0
|
174 getmagspectrum();
|
andrew@0
|
175
|
andrew@0
|
176 generatechromagram();
|
andrew@0
|
177
|
andrew@0
|
178 chromaready = 1;
|
andrew@0
|
179
|
andrew@0
|
180 // for (i = 0;i < 12;i++)
|
andrew@0
|
181 // {
|
andrew@0
|
182 // cout << chroma[i] << " ";
|
andrew@0
|
183 // }
|
andrew@0
|
184 //
|
andrew@0
|
185 // cout << endl;
|
andrew@0
|
186
|
andrew@0
|
187 //cout << "root: " << root << " type: " << type << " features: " << features << endl;
|
andrew@0
|
188
|
andrew@0
|
189 //cout << root << " " << quality << " " << intervals << endl;
|
andrew@0
|
190 }
|
andrew@0
|
191
|
andrew@0
|
192 //--------------------------------------------------------------------------------------
|
andrew@0
|
193 // creates a chromagram from the magnitude spectrum of the input signal
|
andrew@0
|
194 void Chromagram :: generatechromagram()
|
andrew@0
|
195 {
|
andrew@0
|
196 int i;
|
andrew@0
|
197 float sum;
|
andrew@0
|
198 float notesum = 0;
|
andrew@0
|
199 float noteval;
|
andrew@0
|
200 int index;
|
andrew@0
|
201 float maxval = 0;
|
andrew@0
|
202 int searchlength;
|
andrew@0
|
203
|
andrew@0
|
204 for (i = 0;i < 12;i++)
|
andrew@0
|
205 {
|
andrew@0
|
206 sum = 0;
|
andrew@0
|
207
|
andrew@0
|
208 for (int oct = 1;oct <= octaves;oct++)
|
andrew@0
|
209 {
|
andrew@0
|
210 noteval = (note[i]/ratio)*((float) oct);
|
andrew@0
|
211 notesum = 0;
|
andrew@0
|
212
|
andrew@0
|
213 for (int h = 1;h <= harmonics;h++)
|
andrew@0
|
214 {
|
andrew@0
|
215 index = round(noteval*((float) h));
|
andrew@0
|
216
|
andrew@0
|
217 searchlength = search*h;
|
andrew@0
|
218
|
andrew@0
|
219 maxval = 0;
|
andrew@0
|
220 for (int n = (index-searchlength);n <= index+searchlength;n++)
|
andrew@0
|
221 {
|
andrew@0
|
222 if (mag[n] > maxval)
|
andrew@0
|
223 {
|
andrew@0
|
224 maxval = mag[n];
|
andrew@0
|
225 }
|
andrew@0
|
226 }
|
andrew@0
|
227
|
andrew@0
|
228 notesum = notesum+(maxval*(1/((float) h)));
|
andrew@0
|
229 }
|
andrew@0
|
230 sum = sum + notesum;
|
andrew@0
|
231
|
andrew@0
|
232 if (oct == 1)
|
andrew@0
|
233 {
|
andrew@0
|
234 chroma_low[i] = notesum;
|
andrew@0
|
235 }
|
andrew@0
|
236 }
|
andrew@0
|
237
|
andrew@0
|
238 chroma[i] = sum;
|
andrew@0
|
239 rawChroma[i] = sum;
|
andrew@0
|
240
|
andrew@0
|
241 if (sum > maximumChromaValue)
|
andrew@0
|
242 maximumChromaValue = sum;
|
andrew@0
|
243
|
andrew@0
|
244 }
|
andrew@0
|
245
|
andrew@0
|
246
|
andrew@0
|
247 // normalise chromagram
|
andrew@0
|
248 maxval = max(chroma,12);
|
andrew@0
|
249
|
andrew@0
|
250 for (i = 0;i < 12;i++)
|
andrew@0
|
251 {
|
andrew@0
|
252 chroma[i] = chroma[i] / maxval;
|
andrew@0
|
253 }
|
andrew@0
|
254
|
andrew@0
|
255 }
|
andrew@0
|
256
|
andrew@0
|
257
|
andrew@0
|
258 //--------------------------------------------------------------------------------------
|
andrew@0
|
259 // main function to be called with 8192 sample frame at 11025 Hz
|
andrew@0
|
260 void Chromagram :: hamming(int N)
|
andrew@0
|
261 {
|
andrew@0
|
262 int n;
|
andrew@0
|
263
|
andrew@0
|
264 // apply hanning window to buffer
|
andrew@0
|
265 for (n = 0; n < N;n++)
|
andrew@0
|
266 {
|
andrew@0
|
267 win[n] = 0.54 - 0.46*cos(2*pi*(((float) n)/((float) N)));
|
andrew@0
|
268 }
|
andrew@0
|
269 }
|
andrew@0
|
270
|
andrew@0
|
271 //--------------------------------------------------------------------------------------
|
andrew@0
|
272 // finds mag spectrum of input
|
andrew@0
|
273 void Chromagram :: getmagspectrum()
|
andrew@0
|
274 {
|
andrew@0
|
275 int i = 0;
|
andrew@0
|
276
|
andrew@0
|
277 // execute fft plan, i.e. compute fft of buffer
|
andrew@0
|
278 fftwf_execute(p);
|
andrew@0
|
279
|
andrew@0
|
280 // compute first (N/2)+1 mag values
|
andrew@0
|
281 for (i = 0;i < (bsize/2)+1;i++)
|
andrew@0
|
282 {
|
andrew@0
|
283 mag[i] = sqrt(pow(out[i][0],2) + pow(out[i][1],2));
|
andrew@0
|
284 mag[i] = sqrt(mag[i]);
|
andrew@0
|
285 }
|
andrew@0
|
286 }
|
andrew@0
|
287
|
andrew@0
|
288 //--------------------------------------------------------------------------------------
|
andrew@0
|
289 // returns max value of an array
|
andrew@0
|
290 float Chromagram :: max(float array[],int length)
|
andrew@0
|
291 {
|
andrew@0
|
292 float max = 0;
|
andrew@0
|
293
|
andrew@0
|
294 for (int i=0;i < length;i++)
|
andrew@0
|
295 {
|
andrew@0
|
296 if (array[i] > max)
|
andrew@0
|
297 {
|
andrew@0
|
298 max = array[i];
|
andrew@0
|
299 }
|
andrew@0
|
300 }
|
andrew@0
|
301
|
andrew@0
|
302 return max;
|
andrew@0
|
303 }
|
andrew@0
|
304
|
andrew@0
|
305 //--------------------------------------------------------------------------------------
|
andrew@0
|
306 // returns index of minimum value of array
|
andrew@0
|
307 int Chromagram :: minindex(float array[],int length)
|
andrew@0
|
308 {
|
andrew@0
|
309 float min = 10000;
|
andrew@0
|
310 int minindex = 0;
|
andrew@0
|
311 int i;
|
andrew@0
|
312
|
andrew@0
|
313 for (i = 0;i < length;i++)
|
andrew@0
|
314 {
|
andrew@0
|
315 if (array[i] < min)
|
andrew@0
|
316 {
|
andrew@0
|
317 min = array[i];
|
andrew@0
|
318 minindex = i;
|
andrew@0
|
319 }
|
andrew@0
|
320 }
|
andrew@0
|
321
|
andrew@0
|
322 return minindex;
|
andrew@0
|
323 } |