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>"); |
nice work ^_^
can i use some part of you code on my diploma in university?
In wav.getBuffer(1000)
what is the use of 1000
? I have tried changing its value, I see no difference.
Anyone has an idea how we would go about writing an INFO
chunk with LIST
sub-chunks containing song metadata? (e.g. artist name, track number, etc.)
@JohnWeisz have you found a way to do that yet? I'm trying to do the same thing.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
There will be problem with URLObject if it runs on the client. I'm finding a workaround.