-
-
Save adrianjoconnor/b6afb618ba7ecc737bae to your computer and use it in GitHub Desktop.
riffwave.js
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
/* | |
* RIFFWAVE.js v0.03 - Audio encoder for HTML5 <audio> elements. | |
* Copyleft 2011 by Pedro Ladaria <pedro.ladaria at Gmail dot com> | |
* | |
* Public Domain | |
* | |
* Changelog: | |
* | |
* 0.01 - First release | |
* 0.02 - New faster base64 encoding | |
* 0.03 - Support for 16bit samples | |
* | |
* Notes: | |
* | |
* 8 bit data is unsigned: 0..255 | |
* 16 bit data is signed: −32,768..32,767 | |
* | |
*/ | |
var FastBase64 = { | |
chars: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=", | |
encLookup: [], | |
Init: function() { | |
for (var i=0; i<4096; i++) { | |
this.encLookup[i] = this.chars[i >> 6] + this.chars[i & 0x3F]; | |
} | |
}, | |
Encode: function(src) { | |
var len = src.length; | |
var dst = ''; | |
var i = 0; | |
while (len > 2) { | |
n = (src[i] << 16) | (src[i+1]<<8) | src[i+2]; | |
dst+= this.encLookup[n >> 12] + this.encLookup[n & 0xFFF]; | |
len-= 3; | |
i+= 3; | |
} | |
if (len > 0) { | |
var n1= (src[i] & 0xFC) >> 2; | |
var n2= (src[i] & 0x03) << 4; | |
if (len > 1) n2 |= (src[++i] & 0xF0) >> 4; | |
dst+= this.chars[n1]; | |
dst+= this.chars[n2]; | |
if (len == 2) { | |
var n3= (src[i++] & 0x0F) << 2; | |
n3 |= (src[i] & 0xC0) >> 6; | |
dst+= this.chars[n3]; | |
} | |
if (len == 1) dst+= '='; | |
dst+= '='; | |
} | |
return dst; | |
} // end Encode | |
} | |
FastBase64.Init(); | |
var RIFFWAVE = function(data) { | |
this.data = []; // Array containing audio samples | |
this.wav = []; // Array containing the generated wave file | |
this.dataURI = ''; // http://en.wikipedia.org/wiki/Data_URI_scheme | |
this.header = { // OFFS SIZE NOTES | |
chunkId : [0x52,0x49,0x46,0x46], // 0 4 "RIFF" = 0x52494646 | |
chunkSize : 0, // 4 4 36+SubChunk2Size = 4+(8+SubChunk1Size)+(8+SubChunk2Size) | |
format : [0x57,0x41,0x56,0x45], // 8 4 "WAVE" = 0x57415645 | |
subChunk1Id : [0x66,0x6d,0x74,0x20], // 12 4 "fmt " = 0x666d7420 | |
subChunk1Size: 16, // 16 4 16 for PCM | |
audioFormat : 1, // 20 2 PCM = 1 | |
numChannels : 1, // 22 2 Mono = 1, Stereo = 2... | |
sampleRate : 8000, // 24 4 8000, 44100... | |
byteRate : 0, // 28 4 SampleRate*NumChannels*BitsPerSample/8 | |
blockAlign : 0, // 32 2 NumChannels*BitsPerSample/8 | |
bitsPerSample: 8, // 34 2 8 bits = 8, 16 bits = 16 | |
subChunk2Id : [0x64,0x61,0x74,0x61], // 36 4 "data" = 0x64617461 | |
subChunk2Size: 0 // 40 4 data size = NumSamples*NumChannels*BitsPerSample/8 | |
}; | |
function u32ToArray(i) { | |
return [i&0xFF, (i>>8)&0xFF, (i>>16)&0xFF, (i>>24)&0xFF]; | |
} | |
function u16ToArray(i) { | |
return [i&0xFF, (i>>8)&0xFF]; | |
} | |
function split16bitArray(data) { | |
var r = []; | |
var j = 0; | |
var len = data.length; | |
for (var i=0; i<len; i++) { | |
r[j++] = data[i] & 0xFF; | |
r[j++] = (data[i]>>8) & 0xFF; | |
} | |
return r; | |
} | |
this.Make = function(data) { | |
if (data instanceof Array) this.data = data; | |
this.header.blockAlign = (this.header.numChannels * this.header.bitsPerSample) >> 3; | |
this.header.byteRate = this.header.blockAlign * this.header.sampleRate; | |
this.header.subChunk2Size = this.data.length * (this.header.bitsPerSample >> 3); | |
this.header.chunkSize = 36 + this.header.subChunk2Size; | |
this.wav = this.header.chunkId.concat( | |
u32ToArray(this.header.chunkSize), | |
this.header.format, | |
this.header.subChunk1Id, | |
u32ToArray(this.header.subChunk1Size), | |
u16ToArray(this.header.audioFormat), | |
u16ToArray(this.header.numChannels), | |
u32ToArray(this.header.sampleRate), | |
u32ToArray(this.header.byteRate), | |
u16ToArray(this.header.blockAlign), | |
u16ToArray(this.header.bitsPerSample), | |
this.header.subChunk2Id, | |
u32ToArray(this.header.subChunk2Size), | |
(this.header.bitsPerSample == 16) ? split16bitArray(this.data) : this.data | |
); | |
this.dataURI = 'data:audio/wav;base64,'+FastBase64.Encode(this.wav); | |
}; | |
if (data instanceof Array) this.Make(data); | |
}; // end RIFFWAVE |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Line 106 corrected to read this.header.sampleRate rather than this.sampleRate . This fixes an issue making the byte rate NaN, which is ignored by most players but incorrect. In Chrome at least, this writes the byterate as 0 in the header.