Spaces:
Running
Running
/* | |
* 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.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 | |