├── .gitignore ├── package.json ├── LICENSE ├── index.js └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | npm-debug.log 2 | node_modules 3 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pcm-volume", 3 | "description": "Transform Stream that is able to change the volume of PCM data piped in and out of it.", 4 | "keywords": [ 5 | "pcm", 6 | "volume" 7 | ], 8 | "version": "1.0.0", 9 | "author": { 10 | "name": "René Raab", 11 | "email": "mail@reneraab.org", 12 | "url": "https://reneraab.org" 13 | }, 14 | "repository": { 15 | "type": "git", 16 | "url": "git://github.com/reneraab/pcm-volume.git" 17 | }, 18 | "main": "./index.js", 19 | "bugs": { 20 | "url": "https://github.com/reneraab/pcm-volume/issues" 21 | }, 22 | "dependencies": { 23 | "inherits": "^2.0.1" 24 | }, 25 | "homepage": "https://github.com/reneraab/pcm-volume", 26 | "license" : "MIT" 27 | } 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 René Raab 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var Transform = require('stream').Transform; 2 | var inherits = require('inherits'); 3 | 4 | function Volume (volume) { 5 | if (!(this instanceof Volume)) return new Volume(volume); 6 | 7 | if (volume === undefined) volume = 1; 8 | this.setVolume(volume); 9 | Transform.call(this); 10 | }; 11 | inherits(Volume, Transform); 12 | 13 | Volume.prototype.setVolume = function(volume) { 14 | this.volume = volume; 15 | // c.f. https://dsp.stackexchange.com/questions/2990/how-to-change-volume-of-a-pcm-16-bit-signed-audio/2996#2996 16 | //this.multiplier = Math.pow(10, (-48 + 54*this.volume)/20); 17 | 18 | // c.f. http://www.ypass.net/blog/2010/01/pcm-audio-part-3-basic-audio-effects-volume-control/ 19 | this.multiplier = Math.tan(this.volume); 20 | }; 21 | 22 | Volume.prototype._transform = function(buf, encoding, callback) { 23 | // create a new Buffer for the transformed data 24 | var out = new Buffer(buf.length); 25 | 26 | // Iterate the 16bit chunks 27 | for (i = 0; i < buf.length; i+=2) { 28 | // read Int16, multiply with volume multiplier and round down 29 | var uint = Math.floor(this.volume*buf.readInt16LE(i)); 30 | 31 | // higher/lower values exceed 16bit 32 | uint = Math.min(32767, uint); 33 | uint = Math.max(-32767, uint); 34 | 35 | // write those 2 bytes into the other buffer 36 | out.writeInt16LE(uint, i); 37 | } 38 | 39 | // return the buffer with the changed values 40 | this.push(out); 41 | callback(); 42 | }; 43 | 44 | module.exports = Volume; 45 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | pcm-volume 2 | =========== 3 | This module changes the volume of a given PCM data stream. At the moment only signed 16bit PCM data is supported, also I'm not quite sure about this as my knowledge about PCM is very limited. 4 | I don't know whether this is the right way to do things. Feel free to contact me/open a pull request if you want to add something. 5 | 6 | Install 7 | ------- 8 | 9 | Install with `npm install pcm-volume` or clone from GitHub and `npm install`. 10 | 11 | How to use 12 | ---------- 13 | Pipe an existing stream into an instance of pcm-volume. You can get a PCM-stream from node-lame for example. 14 | 15 | This example reads the file music.mp3 and changes the volume to 50% after 5seconds. 16 | ```js 17 | var Speaker = require("speaker"); 18 | var lame = require("lame"); 19 | var fs = require("fs"); 20 | var volume = require("pcm-volume"); 21 | 22 | var readable = fs.createReadStream("music.mp3"); 23 | 24 | // see node-lame documentation for more information 25 | var decoder = new lame.Decoder({ 26 | channels: 2, 27 | bitDepth: 16, 28 | sampleRate: 44100, 29 | bitRate: 128, 30 | outSampleRate: 22050, 31 | mode: lame.STEREO 32 | }); 33 | 34 | // Initialize speaker 35 | var speaker = new Speaker(); 36 | 37 | // Create a volume instance 38 | var v = new volume(); 39 | 40 | // Wait 5s, then change the volume to 50% 41 | setTimeout(function() { 42 | v.setVolume(0.5); 43 | }, 5000) 44 | 45 | v.pipe(speaker); // pipe volume to speaker 46 | decoder.pipe(v); // pipe PCM data to volume 47 | readable.pipe(decoder); // pipe file input to decoder 48 | ``` 49 | 50 | 51 | API 52 | --- 53 | pcm-volume is a Transform Stream (see https://nodejs.org/api/stream.html#stream_class_stream_transform for more information). Pipe in your PCM data and pipe out PCM data with a different volume. 54 | Use setVolume(v) to set the volume (v is a float between 0 and roughly 1.5 also you can go higher but it sounds like crap). 55 | --------------------------------------------------------------------------------