Created
October 30, 2012 11:39
-
-
Save asanoboy/3979747 to your computer and use it in GitHub Desktop.
How to make a WAV file in Javascript.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var Wav = function(opt_params){ | |
/** | |
* @private | |
*/ | |
this._sampleRate = opt_params && opt_params.sampleRate ? opt_params.sampleRate : 44100; | |
/** | |
* @private | |
*/ | |
this._channels = opt_params && opt_params.channels ? opt_params.channels : 2; | |
/** | |
* @private | |
*/ | |
this._eof = true; | |
/** | |
* @private | |
*/ | |
this._bufferNeedle = 0; | |
/** | |
* @private | |
*/ | |
this._buffer; | |
}; | |
Wav.prototype.setBuffer = function(buffer){ | |
this._buffer = this.getWavInt16Array(buffer); | |
this._bufferNeedle = 0; | |
this._internalBuffer = ''; | |
this._hasOutputHeader = false; | |
this._eof = false; | |
}; | |
Wav.prototype.getBuffer = function(len){ | |
var rt; | |
if( this._bufferNeedle + len >= this._buffer.length ){ | |
rt = new Int16Array(this._buffer.length - this._bufferNeedle); | |
this._eof = true; | |
} | |
else { | |
rt = new Int16Array(len); | |
} | |
for(var i=0; i<rt.length; i++){ | |
rt[i] = this._buffer[i+this._bufferNeedle]; | |
} | |
this._bufferNeedle += rt.length; | |
return rt.buffer; | |
}; | |
Wav.prototype.eof = function(){ | |
return this._eof; | |
}; | |
Wav.prototype.getWavInt16Array = function(buffer){ | |
var intBuffer = new Int16Array(buffer.length + 23), tmp; | |
intBuffer[0] = 0x4952; // "RI" | |
intBuffer[1] = 0x4646; // "FF" | |
intBuffer[2] = (2*buffer.length + 15) & 0x0000ffff; // RIFF size | |
intBuffer[3] = ((2*buffer.length + 15) & 0xffff0000) >> 16; // RIFF size | |
intBuffer[4] = 0x4157; // "WA" | |
intBuffer[5] = 0x4556; // "VE" | |
intBuffer[6] = 0x6d66; // "fm" | |
intBuffer[7] = 0x2074; // "t " | |
intBuffer[8] = 0x0012; // fmt chunksize: 18 | |
intBuffer[9] = 0x0000; // | |
intBuffer[10] = 0x0001; // format tag : 1 | |
intBuffer[11] = this._channels; // channels: 2 | |
intBuffer[12] = this._sampleRate & 0x0000ffff; // sample per sec | |
intBuffer[13] = (this._sampleRate & 0xffff0000) >> 16; // sample per sec | |
intBuffer[14] = (2*this._channels*this._sampleRate) & 0x0000ffff; // byte per sec | |
intBuffer[15] = ((2*this._channels*this._sampleRate) & 0xffff0000) >> 16; // byte per sec | |
intBuffer[16] = 0x0004; // block align | |
intBuffer[17] = 0x0010; // bit per sample | |
intBuffer[18] = 0x0000; // cb size | |
intBuffer[19] = 0x6164; // "da" | |
intBuffer[20] = 0x6174; // "ta" | |
intBuffer[21] = (2*buffer.length) & 0x0000ffff; // data size[byte] | |
intBuffer[22] = ((2*buffer.length) & 0xffff0000) >> 16; // data size[byte] | |
for (var i = 0; i < buffer.length; i++) { | |
tmp = buffer[i]; | |
if (tmp >= 1) { | |
intBuffer[i+23] = (1 << 15) - 1; | |
} | |
else if (tmp <= -1) { | |
intBuffer[i+23] = -(1 << 15); | |
} | |
else { | |
intBuffer[i+23] = Math.round(tmp * (1 << 15)); | |
} | |
} | |
return intBuffer; | |
}; | |
var i=0, vol=0.1, | |
sampleRate = 48000, | |
wav = new Wav({sampleRate: sampleRate, channels: 1}), | |
buffer = new Float32Array(sampleRate); | |
while(i<sampleRate){ | |
if( parseInt(i/100) % 2 ){ | |
buffer[i] = -vol; | |
} | |
else { | |
buffer[i] = vol; | |
} | |
i++; | |
} | |
wav.setBuffer(buffer); | |
var srclist = []; | |
while( !wav.eof() ){ | |
srclist.push(wav.getBuffer(1000)); | |
} | |
var b = new Blob(srclist, {type:'audio/wav'}); | |
var URLObject = window.webkitURL || window.URL; | |
var url = URLObject.createObjectURL(b); | |
document.write("<a href='"+url+"'>play</a>"); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Anyone has an idea how we would go about writing an
INFO
chunk withLIST
sub-chunks containing song metadata? (e.g. artist name, track number, etc.)