Skip to content

Instantly share code, notes, and snippets.

@bklimt
Last active December 14, 2015 03:38
Show Gist options
  • Save bklimt/5022117 to your computer and use it in GitHub Desktop.
Save bklimt/5022117 to your computer and use it in GitHub Desktop.
WaveWriter for JavaScript
/**
* Creates a helper to write a WAVE file to a Buffer.
* @param {Number} seconds - The length of the WAVE file to write.
* @param {Number} sampleRate - The sample rate in Hz, such as 44100 for a CD.
* @param {Number} bitsPerSample - Either 8 or 16.
*/
var WaveWriter = function(seconds, sampleRate, bitsPerSample) {
this._sampleRate = sampleRate;
this._bitsPerSample = bitsPerSample;
this._writer = new BufferWriter();
this._samples = Math.round(this._sampleRate * seconds);
var numChannels = 1;
var subChunk2Size = this._samples * numChannels * bitsPerSample / 8;
var chunkSize = 36 + subChunk2Size;
try {
this._writer.writeUTF8("RIFF");
this._writer.writeUInt32LE(chunkSize);
this._writer.writeUTF8("WAVE");
} catch (e1) {
console.error("Got an exception while writing WAVE header.");
throw e1;
}
try {
// Sub-chunk 1
var byteRate = 36 + sampleRate * numChannels * bitsPerSample / 8;
var blockAlign = numChannels * bitsPerSample / 8;
this._writer.writeUTF8("fmt ");
this._writer.writeUInt32LE(16);
this._writer.writeUInt16LE(1);
this._writer.writeUInt16LE(numChannels);
this._writer.writeUInt32LE(sampleRate);
this._writer.writeUInt32LE(byteRate);
this._writer.writeUInt16LE(blockAlign);
this._writer.writeUInt16LE(bitsPerSample);
} catch (e2) {
console.error("Got an exception while writing subchunk 1.");
throw e2;
}
try {
// Sub-chunk 2
this._writer.writeUTF8("data");
this._writer.writeUInt32LE(subChunk2Size);
} catch (e3) {
console.error("Got an exception while writing subchunk 2.");
throw e3;
}
};
_.extend(WaveWriter.prototype, {
/**
* Write a single sample to the WAVE file.
* @param {Number} sample The amplitude of the sample, from -1 to 1.
* @return {Boolean} false if the file is already full, true otherwise.
*/
writeSample: function(sample) {
if (this._samples === 0) {
return false;
}
// Clamp values out of range.
if (sample < -1.0) {
sample = -1;
}
if (sample > 1.0) {
sample = 1;
}
if (this._bitsPerSample === 16) {
this._writer.writeInt16(Math.floor(32767 * sample));
} else if (this._bitsPerSample === 8) {
try {
this._writer.writeUInt8(Math.floor(-127.5 * sample + 127.5));
} catch (e) {
console.error("Got an exception while writing a sample.");
console.error("Sample is " + Math.floor(-127.5 * sample + 127.5));
throw e;
}
}
this._samples = this._samples - 1;
return true;
},
/**
* Fills the rest of the file with zero-amplitude samples.
*/
close: function() {
while (this._samples > 0) {
this.writeSample(0.0);
}
},
/**
* Returns the underlying buffer with the contents of the WAVE file.
*/
buffer: function() {
return this._writer.buffer();
},
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment