Permalink
Browse files

added optional safe clipping

  • Loading branch information...
1 parent 638033e commit cf2573254b52cfef9b9154297b8497becdcd6173 @fritzo committed Feb 15, 2012
Showing with 40 additions and 22 deletions.
  1. +40 −22 wavencoder.js
View
@@ -47,6 +47,7 @@ var WavEncoder = (function(){
var bytesPerSample = options.bytesPerSample || defaults.bytesPerSample;
var numChannels = options.numChannels || defaults.numChannels;
var sampleRateHz = options.sampleRateHz || defaults.sampleRateHz;
+ this.clip = 'clip' in options ? !!options.clip : defaults.clip;
var PCM_FORMAT = 1;
var bitsPerSample = bytesPerSample * 8;
@@ -63,14 +64,15 @@ var WavEncoder = (function(){
switch (bytesPerSample) {
case 1:
- this.encode = this.encode8;
+ this.encode = this._encode8;
break;
case 2:
- this.encode = this.encode16;
+ this.encode = this._encode16;
break;
- default: throw 'unsupported bytesPerSample: ' + bytesPerSample;
+ default: throw new WavEncoderException(
+ 'unsupported bytesPerSample: ' + bytesPerSample);
}
// we encode using 16-bit words
@@ -98,14 +100,14 @@ var WavEncoder = (function(){
var bytesPerWord = 2;
var dataWords = dataBytes / bytesPerWord;
- words.length = this.headerWords + dataWords;
+ words.length = this._headerWords + dataWords;
while (words.length % 3) words.push(0);
};
WavEncoder.prototype = {
- headerBytes: 44,
- headerWords: 22,
+ _headerBytes: 44,
+ _headerWords: 22, // for 16-bit words
/**
* @param {string}
@@ -144,24 +146,33 @@ var WavEncoder = (function(){
* @param {number[]}
* @returns {string}
*/
- encode8: function (samples) {
+ _encode8: function (samples) {
// this is hard-coded for 8-bit mono
assertEqual(samples.length, this.numSamples, 'Wrong number of samples');
+ var floor = Math.floor;
+ var sqrt = Math.sqrt;
+ var clip = this.clip;
+
var words = this.words;
- var h = this.headerWords;
+ var h = this._headerWords;
for (var t = 0, T = this.numSamples - 1; t < T; t += 2) {
var x1 = samples[t + 0];
var x2 = samples[t + 1];
+ if (clip) {
+ x1 /= sqrt(1 + x1 * x1);
+ x2 /= sqrt(1 + x2 * x2);
+ }
// 8-bit samples are unsigned
- var sample1 = Math.floor(128 * (x1 + 1));
- var sample2 = Math.floor(128 * (x2 + 1));
+ var sample1 = floor(128 * (x1 + 1));
+ var sample2 = floor(128 * (x2 + 1));
words[h++] = (sample1 << 8) | sample2;
}
if (this.numSamples % 2) {
var x1 = samples[t + 0];
- var sample1 = Math.floor(128 * (x1 + 1));
+ if (clip) x1 /= sqrt(1 + x1 * x1);
+ var sample1 = floor(128 * (x1 + 1));
words[h++] = sample1 << 8;
}
@@ -172,17 +183,22 @@ var WavEncoder = (function(){
* @param {number[]}
* @returns {string}
*/
- encode16: function (samples) {
+ _encode16: function (samples) {
// this is hard-coded for 16-bit mono
assertEqual(samples.length, this.numSamples, 'Wrong number of samples');
+ var floor = Math.floor;
+ var sqrt = Math.sqrt;
+ var clip = this.clip;
+
var words = this.words;
- var h = this.headerWords;
+ var h = this._headerWords;
for (var t = 0, T = this.numSamples; t < T; ++t) {
var x = samples[t];
+ if (clip) x /= sqrt(1 + x * x);
// 16-bit samples are signed
- var sample = Math.floor(32768 * x);
+ var sample = floor(32768 * x);
if (sample < 0) sample += 65536; // 2's compliment
words[h++] = ((sample >> 8) | (sample << 8)) & 65535;
}
@@ -195,7 +211,7 @@ var WavEncoder = (function(){
*/
_encodeWords: function () {
var words = this.words;
- var pairTable = WavEncoder.pairTable;
+ var pairTable = WavEncoder._pairTable;
var result = new Array(1 + words.length * 4/3);
var r = 0;
@@ -226,7 +242,8 @@ var WavEncoder = (function(){
WavEncoder.defaults = {
numChannels: 1, // mono
sampleRateHz: 22050, // 22050 Hz
- bytesPerSample: 2 // 16 bit
+ bytesPerSample: 2, // 16 bit
+ clip: true
};
(function(){
@@ -239,23 +256,24 @@ var WavEncoder = (function(){
pairTable[ij] = charTable[ij >> 6] + charTable[ij & 63];
}
- WavEncoder.pairTable = pairTable;
+ WavEncoder._pairTable = pairTable;
})();
+ WavEncoder.Exception = WavEncoderException;
+
/**
* WavEncoder is optimized to encode many data sequences of the same length,
- * but we provide a one-off function for convenience.
+ * but we provide this one-off function for convenience.
*
* @param {number[]}
+ * @param {object?}
* @returns {string}
*/
- WavEncoder.encode = function (data) {
- var encoder = new WavEncoder(data.length);
+ WavEncoder.encode = function (data, options) {
+ var encoder = new WavEncoder(data.length, options);
return encoder.encode(data);
};
- WavEncoder.Exception = WavEncoderException;
-
return WavEncoder;
}());

0 comments on commit cf25732

Please sign in to comment.