annotate chromagramm/Chromagram.cpp @ 0:572c856e38ac

Starting up openFrameworks project for audio time warping. The ofxFileReader goes in addons of your OF folder, the libraries and source (chromogram, fftw and source code src+ timewarp) are probably best kept in the repository, then dragged into the project afresh. That way, as we update the repository, the code that the openFrameworks project looks for will be updated.
author Andrew N Robertson <andrew.robertson@eecs.qmul.ac.uk>
date Tue, 17 May 2011 08:48:58 +0100
parents
children 6842ff391568
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 }