FFT

FFT example

Your browser does not support the canvas element.
var audio = new maximJs.maxiAudio();
audio.init();

var fft = new maximJs.maxiFFT();
var mfcc = new maximJs.maxiMFCC();
var oct = new maximJs.maxiFFTOctaveAnalyzer();

var nAverages = 12;

// for storing fft values
/* 
required as passing a vector from one class 
to another isn't currently working
*/
var magnitudes = new Module.VectorFloat();
var magnitudesDB = new Module.VectorFloat();
var phases = new Module.VectorFloat();

// will store mfcc output
var mfccs = new Module.VectorDouble(); 

var osc = new maximJs.maxiOsc();

// if you want to play a sample...
// var samplePlayer = new maximJs.maxiSample();
// audio.loadSample("audio/beat2.wav", samplePlayer);


var fftSize = 1024;
var sampleRate = 44100;

var magMult = 6;

var fftDraw = {
	barsBottom: 600,
	barsLeft: 50,
	barsSize:1,
	magMult: 6
};

var mfccDraw = {
	barsBottom: 350,
	barsLeft: 350,
	barsSize:10,
	magMult: 24
};

var octDraw = {
	barsBottom: 150,
	barsLeft: 350,
	barsSize:10,
	magMult: 0.5
};

var amtAvgs = 15;
var pitchHist = [];

window.onload = setup;
function setup(){
	fft.setup(fftSize, 512, 256);
	// ifft.setup(fftSize, 512, 256);
	mfcc.setup(512, 42, 13, 20, 20000, sampleRate);
	oct.setup(sampleRate, fftSize/2, nAverages);

	for(var i = 0; i < 13; ++i){
		mfccs.push_back(0);
	}

	for(var i = 0; i < fftSize/2; ++i){
		magnitudes.push_back(0);
	}

	// This gets the window in the browser
	var canvas=document.getElementById("myCanvas");

	// This creates a 2d drawing context in it.
	context=canvas.getContext("2d");

	//finally, we return setInterval, which wants a function to call,
	//and a period in milliseconds to wait between calling it.  
	return setInterval(draw, 40);
}

audio.play = function(){
	// create wave for fft
	var wave = osc.square(220);

	// if(samplePlayer.isReady()){ 
	// 	var wave = samplePlayer.play();
	// }

	// process wave
	if(fft.process(wave)){
		fft.magsToDB();

		// sorry, this is not nice
		Module.vectorTools.clearVectorFloat(magnitudes);
		Module.vectorTools.clearVectorFloat(magnitudesDB);

		for(var i = 0; i < fftSize/2; ++i){
			magnitudes.push_back(fft.getMagnitude(i));
			magnitudesDB.push_back(fft.getMagnitudeDB(i));
		}

		// pass magnitudes to mfcc and store in mfccs vector
		mfcc.mfcc(magnitudes, mfccs);
		oct.calculate(magnitudesDB);
	}
	
	this.output = wave; 
	
}


//The stuff inside the script tag is very similar to processing code.
function draw() {
//This is basically the same as any other 2D processing draw routine.
//clear the screen
context.clearRect(0,0,700,700);

// fft
context.fillStyle="#FF0000";
context.font = "30px Arial";
context.fillText("FFT",70,200);

for(var i=0; i < fftSize / 2; i++) {
	context.beginPath();
	context.rect(
		fftDraw.barsLeft + i,
		fftDraw.barsBottom,
		fftDraw.barsSize,
		-(fft.getMagnitude(i) * fftDraw.magMult)); 
	context.fill();
	context.closePath();
}

// mfcc
context.fillStyle="rgba(0, 220, 0, 0.5)"
context.font = "30px Arial";
context.fillText("MFCC",350,250);
for(var i=0; i < 13; i++) {
	context.beginPath();

	context.rect(
		mfccDraw.barsLeft + i*mfccDraw.barsSize,
		mfccDraw.barsBottom,
		mfccDraw.barsSize,
		(mfccs.get(i) * mfccDraw.magMult)); 
	context.fill();
	context.closePath();
}

// octave analyser
var j = 0;
for(var i=0; i < amtAvgs; ++i) {
	pitchHist[i] = 0;
}

for (var i = 0; i < oct.nAverages; ++i) {
	pitchHist[j] += oct.getAverage(i);
	j++;
	j = j % amtAvgs;
}

context.fillStyle="rgba(0, 0, 255, 0.5)"
context.font = "30px Arial";
context.fillText("OCT",350,50);
for(var i=0; i < amtAvgs; i++) {
	context.beginPath();
	context.rect(
		octDraw.barsLeft + i*(octDraw.barsSize*1.5),
		octDraw.barsBottom,
		octDraw.barsSize,
		-(pitchHist[i] * octDraw.magMult)); 
	context.fill();
	context.closePath();
}
}