Skip to content

Instantly share code, notes, and snippets.

@withattribution
Created October 16, 2014 01:38
Show Gist options
  • Select an option

  • Save withattribution/508b80095976ab9d2f88 to your computer and use it in GitHub Desktop.

Select an option

Save withattribution/508b80095976ab9d2f88 to your computer and use it in GitHub Desktop.
var inherits = require('inherits');
var Readable = require('readable-stream').Readable;
var spawn = require('child_process').spawn;
module.exports = function (opts, fn) {
if (typeof opts === 'function') {
fn = opts;
opts = {};
}
if (!opts) opts = {};
var b = new B (opts, fn);
return b;
};
function B (opts, fn) {
Readable.call(this);
this.readable = true;
this.rate = opts.rate || 44100;
this._fn = fn;
this.t = 0;
this.i = 0;
}
inherits(B, Readable);
B.prototype._read = function (bytes) {
if (!bytes) bytes = 8192;
var self = this;
var buf = new Buffer(Math.floor(bytes));
function clamp (x) {
return Math.max(Math.min(x, Math.pow(2,31)-1), -Math.pow(2,31));
}
for (var i = 0; i < buf.length; i += 4) {
var t = self.t + Math.floor(i / 4) / self.rate;
var counter = self.i + Math.floor(i / 4);
var n = this._fn.call(self, t, counter);
if (isNaN(n)) n = 0;
buf.writeInt32LE(clamp(signed(n)), i);
}
self.i += buf.length / 4;
self.t += buf.length / 4 / self.rate;
if (!self._ended) this.push(buf);
};
B.prototype.end = function () {
this._ended = true;
Readable.prototype.push.call(this, null);
};
function mergeArgs (opts, args) {
Object.keys(opts || {}).forEach(function (key) {
args[key] = opts[key];
});
return Object.keys(args).reduce(function (acc, key) {
var dash = key.length === 1 ? '-' : '--';
return acc.concat(dash + key, args[key]);
}, []);
}
B.prototype.play = function (opts) {
var ps = this._spawn('play', mergeArgs(opts, {
'c': 1,
'r': this.rate,
't': 's32'
}).concat('-', '-V6'));
ps.stderr.on('data',function(err){
console.log('REC ERR: ---------------------------------- \n'
+err
+'REC ERR: ********************************** \n');
});
this.pipe(ps.stdin);
return ps;
};
B.prototype.record = function (file, opts) {
var ps = this._spawn('sox', mergeArgs(opts, {
'c' : 2,
'r' : 48000,
't' : 's32',
}).concat('-', '-q', '-o', file));
this.pipe(ps.stdin);
return ps;
};
B.prototype._spawn = function (cmd, args) {
var self = this;
var ps = spawn(cmd, args);
ps.on('error', function (err) {
if (err.code === 'ENOENT') {
self.emit('error', new Error(
'Failed to launch the `' + cmd + '` command.\n'
+ 'Make sure you have sox installed:\n\n'
+ ' http://sox.sourceforge.net\n'
));
}
else self.emit('error', err);
});
ps.stdin.on('error', function () {});
return ps;
};
function signed (n) {
if (isNaN(n)) return 0;
var b = Math.pow(2, 31);
return n > 0
? Math.min(b - 1, Math.floor((b * n) - 1))
: Math.max(-b, Math.ceil((b * n) - 1))
;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment