Mercurial > hg > audio-file-loader
view 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 |
line wrap: on
line source
#include "Chromagram.h" #include <iostream> #include <math.h> using namespace std; Chromagram :: Chromagram() { pi = 3.14159265; bsize = 8192; // array init buffer = new float[8192]; // make audio buffer wbuffer = new float[8192]; // to hold windowed audio buffer win = new float[8192]; d_frame = new float[128]; hop = new float[1024]; mag = new float[(bsize/2)+1]; maximumChromaValue = 0; float base = 130.81278265; for (int i = 0;i < 12;i++) { note[i] = base*pow(2,(((float) i)/12)); } harmonics = 2; octaves = 2; search = 2; // p is number of bins either side of target to search for other peaks out = (fftwf_complex*) fftwf_malloc(sizeof(fftwf_complex) * bsize); // complex array to hold fft p = fftwf_plan_dft_r2c_1d(bsize,wbuffer,out,FFTW_FORWARD*-1); // plan for executing fft of wbuffer chromaready = 0; } //-------------------------------------------------------------------------------------- // destructor Chromagram :: ~Chromagram() { // destroy fft plan fftwf_destroy_plan(p); // deallocate memory win = NULL; delete [] win; buffer = NULL; delete [] buffer; wbuffer = NULL; delete [] wbuffer; } //-------------------------------------------------------------------------------------- // Initialises all framesize dependent variables. Should be called to properly initialise variables and anytime the frame size changes. void Chromagram :: initialise(int framesize,int hsize) { fsize = framesize; hopsize = hsize; d_frame = new float[fsize/4]; hop = new float[hopsize]; calcrate = (hopsize*4)/fsize; count = 0; //fsize = framesize; // set frame size ratio = ((float) 11025) / ((float) 8192); hamming(bsize); // define a hanning window offline } //-------------------------------------------------------------------------------------- // Processes a single frame void Chromagram :: processframe(float frame[]) { int i; int j; int c; chromaready = 0; // default case that chroma isn't ready // downsample frame downsampleframe(frame); if (count < calcrate) { c = count*(fsize/4); j = 0; for (i = c;i < c+(fsize/4);i++) { hop[i] = d_frame[j]; j++; } count = count + 1; } if (count == calcrate) { for (i=0;i < 8192-hopsize;i++) { buffer[i] = buffer[i+hopsize]; } j = 0; for (i=8192-hopsize;i < bsize;i++) { buffer[i] = hop[j]; j++; } chromacalc(buffer); count = 0; } } //-------------------------------------------------------------------------------------- // Processes a single frame void Chromagram :: downsampleframe(float frame[]) { float filt_frame[fsize]; float b0,b1,b2,a1,a2; float x_1,x_2,y_1,y_2; b0 = 0.2929; b1 = 0.5858; b2 = 0.2929; a1 = -0.0000; a2 = 0.1716; x_1 = 0; x_2 = 0; y_1 = 0; y_2 = 0; for (int i=0;i < fsize;i++) { filt_frame[i] = frame[i]*b0 + x_1*b1 + x_2*b2 - y_1*a1 - y_2*a2; x_2 = x_1; x_1 = frame[i]; y_2 = y_1; y_1 = filt_frame[i]; } for (int i=0;i < (fsize/4);i++) { d_frame[i] = filt_frame[i*4]; } } //-------------------------------------------------------------------------------------- // main function to be called with 8192 sample frame at 11025 Hz void Chromagram :: chromacalc(float frame[]) { int i; // apply hanning window to buffer for (i = 0; i < bsize;i++) { wbuffer[i] = frame[i] * win[i]; } getmagspectrum(); generatechromagram(); chromaready = 1; // for (i = 0;i < 12;i++) // { // cout << chroma[i] << " "; // } // // cout << endl; //cout << "root: " << root << " type: " << type << " features: " << features << endl; //cout << root << " " << quality << " " << intervals << endl; } //-------------------------------------------------------------------------------------- // creates a chromagram from the magnitude spectrum of the input signal void Chromagram :: generatechromagram() { int i; float sum; float notesum = 0; float noteval; int index; float maxval = 0; int searchlength; for (i = 0;i < 12;i++) { sum = 0; for (int oct = 1;oct <= octaves;oct++) { noteval = (note[i]/ratio)*((float) oct); notesum = 0; for (int h = 1;h <= harmonics;h++) { index = round(noteval*((float) h)); searchlength = search*h; maxval = 0; for (int n = (index-searchlength);n <= index+searchlength;n++) { if (mag[n] > maxval) { maxval = mag[n]; } } notesum = notesum+(maxval*(1/((float) h))); } sum = sum + notesum; if (oct == 1) { chroma_low[i] = notesum; } } chroma[i] = sum; rawChroma[i] = sum; if (sum > maximumChromaValue) maximumChromaValue = sum; } // normalise chromagram maxval = max(chroma,12); for (i = 0;i < 12;i++) { chroma[i] = chroma[i] / maxval; } } //-------------------------------------------------------------------------------------- // main function to be called with 8192 sample frame at 11025 Hz void Chromagram :: hamming(int N) { int n; // apply hanning window to buffer for (n = 0; n < N;n++) { win[n] = 0.54 - 0.46*cos(2*pi*(((float) n)/((float) N))); } } //-------------------------------------------------------------------------------------- // finds mag spectrum of input void Chromagram :: getmagspectrum() { int i = 0; // execute fft plan, i.e. compute fft of buffer fftwf_execute(p); // compute first (N/2)+1 mag values for (i = 0;i < (bsize/2)+1;i++) { mag[i] = sqrt(pow(out[i][0],2) + pow(out[i][1],2)); mag[i] = sqrt(mag[i]); } } //-------------------------------------------------------------------------------------- // returns max value of an array float Chromagram :: max(float array[],int length) { float max = 0; for (int i=0;i < length;i++) { if (array[i] > max) { max = array[i]; } } return max; } //-------------------------------------------------------------------------------------- // returns index of minimum value of array int Chromagram :: minindex(float array[],int length) { float min = 10000; int minindex = 0; int i; for (i = 0;i < length;i++) { if (array[i] < min) { min = array[i]; minindex = i; } } return minindex; }