The Fast Fourrier Transform analysis.
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(); // 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); 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); // or use a sample // var wave = samplePlayer.isReady() ? samplePlayer.play() : 0.0; // 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(); } }