Changes

Jump to: navigation, search

User:David.humphrey/Audio Data API 2

3,646 bytes added, 18:41, 21 May 2010
Complete Example: Visualizing Audio Spectrum
===== Complete Example: Visualizing Audio Spectrum =====
'''NOTE: This example is not updated to the new API.''' This example uses the native calculates and displays FFT spectrum data from <code>mozSpectrum</code> to display for the frequency spectrum in a canvasplaying audio:
[[File:fft.png]]
<!DOCTYPE html>
<html>
<head>
<title>JavaScript Spectrum Example</title>
</head>
<body>
<audio src="song.ogg"
controls="true"
onloadedmetadata="loadedMetadata(event);"
onaudiowritten="audioWritten(event);"
style="width: 512px;">
</audio>
<div><canvas id="fft" width="512" height="200"></canvas></div>
<script>
var spectrum; var canvas = document.getElementById('fft');, var ctx = canvas.getContext('2d'), channels, rate;  function loadedMetadata(event) { channels = event.mozChannels; rate = event.mozRate; }
function audioWritten(event) {
spectrum var fb = event.mozSpectrummozFrameBuffer, fft = new FFT(fb.length / channels, rate), signal = new Float32Array(fb.length / channels), magnitude; for (var specSize i = 0, fbl = spectrumfb.length/ 2; i < fbl; i++ ) { // Assuming interlaced stereo channels, magnitudeneed to split and merge into a stero-mix mono signal signal[i] = (fb[2*i] + fb[2*i+1]) / 2; }  fft.forward(signal); 
// Clear the canvas before drawing spectrum
ctx.clearRect(0,0, canvas.width, canvas.height);
for ( var i = 0; i < specSizefft.spectrum.length; i++ ) { magnitude = fft.spectrum.item([i) ] * 4000; // multiply spectrum by a zoom value
// Draw rectangle bars for each frequency bin
ctx.fillRect(i * 4, canvas.height, 3, -magnitude);
}
}
 
// FFT from dsp.js, see below
var FFT = function(bufferSize, sampleRate) {
this.bufferSize = bufferSize;
this.sampleRate = sampleRate;
this.spectrum = new Float32Array(bufferSize/2);
this.real = new Float32Array(bufferSize);
this.imag = new Float32Array(bufferSize);
this.reverseTable = new Uint32Array(bufferSize);
this.sinTable = new Float32Array(bufferSize);
this.cosTable = new Float32Array(bufferSize);
 
var limit = 1,
bit = bufferSize >> 1;
 
while ( limit < bufferSize ) {
for ( var i = 0; i < limit; i++ ) {
this.reverseTable[i + limit] = this.reverseTable[i] + bit;
}
 
limit = limit << 1;
bit = bit >> 1;
}
 
for ( var i = 0; i < bufferSize; i++ ) {
this.sinTable[i] = Math.sin(-Math.PI/i);
this.cosTable[i] = Math.cos(-Math.PI/i);
}
};
 
FFT.prototype.forward = function(buffer) {
var bufferSize = this.bufferSize,
cosTable = this.cosTable,
sinTable = this.sinTable,
reverseTable = this.reverseTable,
real = this.real,
imag = this.imag,
spectrum = this.spectrum;
 
if ( bufferSize % 2 !== 0 ) {
throw "Invalid buffer size, must be a power of 2.";
}
if ( bufferSize !== buffer.length ) {
throw "Supplied buffer is not the same size as defined FFT. FFT Size: " +
bufferSize + " Buffer Size: " + buffer.length;
}
 
for ( var i = 0; i < bufferSize; i++ ) {
real[i] = buffer[reverseTable[i]];
imag[i] = 0;
}
 
var halfSize = 1,
phaseShiftStepReal,
phaseShiftStepImag,
currentPhaseShiftReal,
currentPhaseShiftImag,
off,
tr,
ti,
tmpReal,
i;
 
while ( halfSize < bufferSize ) {
phaseShiftStepReal = cosTable[halfSize];
phaseShiftStepImag = sinTable[halfSize];
currentPhaseShiftReal = 1.0;
currentPhaseShiftImag = 0.0;
 
for ( var fftStep = 0; fftStep < halfSize; fftStep++ ) {
i = fftStep;
 
while ( i < bufferSize ) {
off = i + halfSize;
tr = (currentPhaseShiftReal * real[off]) - (currentPhaseShiftImag * imag[off]);
ti = (currentPhaseShiftReal * imag[off]) + (currentPhaseShiftImag * real[off]);
 
real[off] = real[i] - tr;
imag[off] = imag[i] - ti;
real[i] += tr;
imag[i] += ti;
 
i += halfSize << 1;
}
 
tmpReal = currentPhaseShiftReal;
currentPhaseShiftReal = (tmpReal * phaseShiftStepReal) - (currentPhaseShiftImag * phaseShiftStepImag);
currentPhaseShiftImag = (tmpReal * phaseShiftStepImag) + (currentPhaseShiftImag * phaseShiftStepReal);
}
 
halfSize = halfSize << 1;
}
 
i = bufferSize/2;
while(i--) {
spectrum[i] = 2 * Math.sqrt(real[i] * real[i] + imag[i] * imag[i]) / bufferSize;
}
};
</script>
</body>
Confirm
656
edits

Navigation menu