var Readable = require('stream').Readable, util = require('util'), int24 = require('int24'), Input = require('./input.js') ; 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 = this.buffer.readInt8; this.writeSample = this.buffer.writeInt8; this.sampleByteLength = 1; } else if (args.bitDepth == 32) { this.readSample = this.buffer.readInt32LE; this.writeSample = this.buffer.writeInt32LE; this.sampleByteLength = 4; } else if (args.bitDepth == 24) { this.readSample = function (offset) { return int24.readInt24LE(this.buffer, offset); }; this.writeSample = function (offset, value) { int24.writeInt24LE(this.buffer, offset, value); }; this.sampleByteLength = 3; } else { args.bitDepth = 16; this.readSample = this.buffer.readInt16LE; this.writeSample = this.buffer.writeInt16LE; this.sampleByteLength = 2; } this.channels = args.channels; this.sampleRate = args.sampleRate; this.inputs = []; } util.inherits(Mixer, Readable); Mixer.prototype._read = function() { var samples = 0; if (this.inputs.length){ samples = this.inputs.map(function (input) { return input.availSamples() || 0; }).reduce(function(a,b){ return Math.min(a,b); }); } if (samples) { 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); } 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 { if (this.inputs.length){ setImmediate(this._read.bind(this)); } } }; Mixer.prototype.input = function (args) { if (typeof args === 'undefined') args = {}; var input = new Input({ mixer: this, channels: args.channels || this.channels, bitDepth: args.bitDepth || this.bitDepth, sampleRate: args.sampleRate || this.sampleRate }); this.inputs.push(input); input.on('finish', () =>{ this.inputs.splice(this.inputs.indexOf(input), 1); }); if (this.inputs.length === 1){ setImmediate(this._read.bind(this)); } return input; }; module.exports = Mixer;