diff --git a/example/example.js b/example/example.js new file mode 100644 index 0000000..e8baed9 --- /dev/null +++ b/example/example.js @@ -0,0 +1,46 @@ +var + fs = require('fs'), + Speaker = require('speaker'), + + Mixer = require('../index.js'), + + lame = require('lame') + ; + +/* + * Create the mixer and stream to speaker: + */ + +var mixer = new Mixer({ + channels: 1 +}); + +var speaker = new Speaker({ + channels: 1, + bitDepth: 16, + sampleRate: 44100 +}); + +mixer.pipe(speaker); + +/* + * Decode mp3 and add the stream as mixer input: + */ + +var file = fs.createReadStream('example0.mp3'); + +var decoder = new lame.Decoder(); +var mp3stream = file.pipe(decoder); + +decoder.on('format', function (format) { + console.log(format); + + mp3stream.pipe(mixer.input({ + sampleRate: format.sampleRate, + channels: format.channels, + bitDepth: format.bitDepth + })); + +}); + + diff --git a/example/example0.mp3 b/example/example0.mp3 new file mode 100644 index 0000000..be9b0bf Binary files /dev/null and b/example/example0.mp3 differ diff --git a/example/package.json b/example/package.json new file mode 100644 index 0000000..5a82833 --- /dev/null +++ b/example/package.json @@ -0,0 +1,6 @@ +{ + "dependencies": { + "lame": "*", + "speaker": "*" + } +} diff --git a/lib/input.js b/lib/input.js index 7f0c3d2..d32700c 100644 --- a/lib/input.js +++ b/lib/input.js @@ -1,10 +1,10 @@ var Writable = require('stream').Writable, - util = require('util'), + util = require('util') ; function Input(args) { - this.buffer = Buffer.concat([this.buffer, chunk]); + Writable.call(this, args); if (typeof args === 'undefined') args = {}; if (args.channels != 1 && args.channels != 2) args.channels = 2; @@ -16,19 +16,19 @@ function Input(args) { if (args.channels == 2) this.readStereo = this.read; if (args.bitDepth == 8) { - this.readSample = Buffer.readInt8; - this.writeSample = Buffer.writeInt8; + this.readSample = this.buffer.readInt8; + this.writeSample = this.buffer.writeInt8; this.sampleByteLength = 1; } else if (args.bitDepth == 32) { - this.readSample = Buffer.readInt32LE; - this.writeSample = Buffer.writeInt32LE; + this.readSample = this.buffer.readInt32LE; + this.writeSample = this.buffer.writeInt32LE; this.sampleByteLength = 4; } else { args.bitDepth = 16; - this.readSample = Buffer.readInt16LE; - this.writeSample = Buffer.writeInt16LE; + this.readSample = this.buffer.readInt16LE; + this.writeSample = this.buffer.writeInt16LE; this.sampleByteLength = 2; } @@ -42,10 +42,13 @@ function Input(args) { util.inherits(Input, Writable); Input.prototype.read = function (samples) { + console.log('read()'); var bytes = samples * (this.bitDepth / 8) * this.channels; if (this.buffer.length < bytes) bytes = this.buffer.length; + console.log(this.buffer.length); var r = this.buffer.slice(0, bytes); this.buffer = this.buffer.slice(bytes); + console.log(this.buffer.length); if (this.buffer.length <= 131072 && this.getMoreData !== null) { var getMoreData = this.getMoreData; @@ -57,6 +60,7 @@ Input.prototype.read = function (samples) { } Input.prototype.readMono = function (samples) { + console.log('readMono()'); // This function will be overridden by this.read, if input already is mono. var stereoBuffer = this.read(samples); var monoBuffer = new Buffer(stereoBuffer.length / 2); @@ -70,6 +74,7 @@ Input.prototype.readMono = function (samples) { } Input.prototype.readStereo = function (samples) { + console.log('readStereo()'); // This function will be overridden by this.read, if input already is stereo. var monoBuffer = this.read(samples); var stereoBuffer = new Buffer(monoBuffer.length * 2); @@ -82,12 +87,15 @@ Input.prototype.readStereo = function (samples) { return stereoBuffer; } -Input.availSamples = function (length) { +Input.prototype.availSamples = function (length) { if (typeof length === 'undefined') length = this.buffer.length; return Math.floor(length / ((this.bitDepth / 8) * this.channels)); } Input.prototype._write = function (chunk, encoding, next) { + + console.log('_write', arguments); + /* if (!Buffer.isBuffer(chunk)) { chunk = new Buffer(chunk, encoding); @@ -103,3 +111,4 @@ Input.prototype._write = function (chunk, encoding, next) { } +module.exports = Input; diff --git a/lib/mixer.js b/lib/mixer.js index 85dbc8e..7315fca 100644 --- a/lib/mixer.js +++ b/lib/mixer.js @@ -6,26 +6,29 @@ var ; function Mixer(args) { + Readable.call(this, args); if (typeof args === 'undefined') args = {}; if (args.channels != 1 && args.channels != 2) args.channels = 2; if (typeof args.sampleRate === 'number' || args.sampleRate < 1) args.sampleRate = 44100; + this.buffer = new Buffer(0); + this.bitDepth = args.bitDepth; if (args.bitDepth == 8) { - this.readSample = Buffer.readInt8; - this.writeSample = Buffer.writeInt8; + this.readSample = this.buffer.readInt8; + this.writeSample = this.buffer.writeInt8; this.sampleByteLength = 1; } else if (args.bitDepth == 32) { - this.readSample = Buffer.readInt32LE; - this.writeSample = Buffer.writeInt32LE; + this.readSample = this.buffer.readInt32LE; + this.writeSample = this.buffer.writeInt32LE; this.sampleByteLength = 4; } else { args.bitDepth = 16; - this.readSample = Buffer.readInt16LE; - this.writeSample = Buffer.writeInt16LE; + this.readSample = this.buffer.readInt16LE; + this.writeSample = this.buffer.writeInt16LE; this.sampleByteLength = 2; } @@ -39,23 +42,33 @@ util.inherits(Mixer, Readable); Mixer.prototype._read = function() { + console.log('_read', arguments); + var samples = 9007199254740992; this.inputs.forEach(function (input) { var as = input.availSamples(); if (as < samples) samples = as; }); - if (samples > 0) { + if (samples > 0 && samples != 9007199254740992) { + console.log('read samples', samples); - var mixedBuffer = new Buffer(samples * this.sampleByteLength); - for (var i = 0; i < samples; i++) { - var mixedSample = 0; - for (var j = 0; j < this.inputs.length; j++) { - mixedSample += this.inputs[j].readSample.call(this.inputs[j], i * this.inputs[j].sampleByteLength); + var mixedBuffer = new Buffer(samples * this.sampleByteLength * this.channels); + mixedBuffer.fill(0); + this.inputs.forEach(function (input) { + if (this.channels == 1) { + var inputBuffer = input.readMono(samples); + } else { + var inputBuffer = input.readStereo(samples); } - this.writeSample.call(mixedBuffer, Math.round(mixedSample / this.inputs.length), i * this.sampleByteLength); - } + for (var i = 0; i < samples * this.channels; i++) { + this.writeSample.call(mixedBuffer, this.readSample.call(mixedBuffer, i * this.sampleByteLength) + Math.round(this.readSample.call(inputBuffer, i * this.sampleByteLength) / this.inputs.length), i * this.sampleByteLength); + } + }.bind(this)); this.push(mixedBuffer); + } else { + console.log('Nothing to read.'); + setImmediate(this._read.bind(this)); } }