62 lines
2.4 KiB
JavaScript
62 lines
2.4 KiB
JavaScript
// wav.js by Frank Force - https://github.com/KilledByAPixel/ZzFX
|
|
|
|
export function buildWavBlob(sampleChannels, sampleRate = 44100)
|
|
{
|
|
// adapted from https://gist.github.com/asanoboy/3979747
|
|
const channelCount = sampleChannels.length;
|
|
const sampleCount = sampleChannels[0].length;
|
|
const length = channelCount * sampleCount;
|
|
const buffer = new Int16Array(length + 23);
|
|
|
|
console.assert(channelCount && sampleCount, 'No channels or samples found!');
|
|
|
|
// wave header
|
|
buffer[ 0] = 0x4952; // RI
|
|
buffer[ 1] = 0x4646; // FF
|
|
buffer[ 2] = (2*length + 15) & 0x0000ffff; // RIFF size
|
|
buffer[ 3] = ((2*length + 15) & 0xffff0000) >> 16; // RIFF size
|
|
buffer[ 4] = 0x4157; // WA
|
|
buffer[ 5] = 0x4556; // VE
|
|
buffer[ 6] = 0x6d66; // fm
|
|
buffer[ 7] = 0x2074; // t
|
|
buffer[ 8] = 0x0012; // fmt chunksize: 18
|
|
buffer[ 9] = 0x0000; //
|
|
buffer[10] = 0x0001; // format tag : 1
|
|
buffer[11] = channelCount; // channelCount
|
|
buffer[12] = sampleRate & 0x0000ffff; // sample per sec
|
|
buffer[13] = (sampleRate & 0xffff0000) >> 16; // sample per sec
|
|
buffer[14] = (2*channelCount*sampleRate) & 0x0000ffff; // byte per sec
|
|
buffer[15] = ((2*channelCount*sampleRate) & 0xffff0000) >> 16; // byte per sec
|
|
buffer[16] = 0x0004; // block align
|
|
buffer[17] = 0x0010; // bit per sample
|
|
buffer[18] = 0x0000; // cb size
|
|
buffer[19] = 0x6164; // da
|
|
buffer[20] = 0x6174; // ta
|
|
buffer[21] = (2*length) & 0x0000ffff; // data size[byte]
|
|
buffer[22] = ((2*length) & 0xffff0000) >> 16; // data size[byte]
|
|
|
|
// copy samples to buffer
|
|
for (let i = 0; i < sampleCount; i++)
|
|
for (let j = 0; j < channelCount; j++)
|
|
{
|
|
const s = sampleChannels[j][i];
|
|
buffer[i*channelCount + j + 23] = s>=1 ? (1<<15) - 1 : (s * (1<<15) | 0);
|
|
}
|
|
|
|
// build the blob
|
|
let end = 0;
|
|
let bufferNeedle = 0;
|
|
const blobData = [];
|
|
const GetBuffer = (length) =>
|
|
{
|
|
end = bufferNeedle + length >= buffer.length;
|
|
const rt = new Int16Array(end? buffer.length - bufferNeedle : length);
|
|
for(let i = 0; i < rt.length; i++)
|
|
rt[i] = buffer[i + bufferNeedle];
|
|
bufferNeedle += rt.length;
|
|
return rt.buffer;
|
|
}
|
|
while ( !end ) blobData.push(GetBuffer(1e3));
|
|
|
|
return new Blob(blobData, {type:'audio/wav'});
|
|
} |