annotate chromagramm/Chromagram.cpp @ 2:fa2af670b5c5 tip

SoundFileLoader might have moved
author Andrew N Robertson <andrew.robertson@eecs.qmul.ac.uk>
date Fri, 06 Jan 2012 00:23:26 +0000
parents bcb0d40158f4
children
rev   line source
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 }