VolumeInterface.js (2548B)
1 'use strict'; 2 3 const EventEmitter = require('events'); 4 5 /** 6 * An interface class for volume transformation. 7 * @extends {EventEmitter} 8 */ 9 class VolumeInterface extends EventEmitter { 10 constructor({ volume = 1 } = {}) { 11 super(); 12 this.setVolume(volume); 13 } 14 15 /** 16 * Whether or not the volume of this stream is editable 17 * @type {boolean} 18 * @readonly 19 */ 20 get volumeEditable() { 21 return true; 22 } 23 24 /** 25 * The current volume of the stream 26 * @type {number} 27 * @readonly 28 */ 29 get volume() { 30 return this._volume; 31 } 32 33 /** 34 * The current volume of the stream in decibels 35 * @type {number} 36 * @readonly 37 */ 38 get volumeDecibels() { 39 return Math.log10(this.volume) * 20; 40 } 41 42 /** 43 * The current volume of the stream from a logarithmic scale 44 * @type {number} 45 * @readonly 46 */ 47 get volumeLogarithmic() { 48 return Math.pow(this.volume, 1 / 1.660964); 49 } 50 51 applyVolume(buffer, volume) { 52 volume = volume || this._volume; 53 if (volume === 1) return buffer; 54 55 const out = Buffer.alloc(buffer.length); 56 for (let i = 0; i < buffer.length; i += 2) { 57 if (i >= buffer.length - 1) break; 58 const uint = Math.min(32767, Math.max(-32767, Math.floor(volume * buffer.readInt16LE(i)))); 59 out.writeInt16LE(uint, i); 60 } 61 62 return out; 63 } 64 65 /** 66 * Sets the volume relative to the input stream - i.e. 1 is normal, 0.5 is half, 2 is double. 67 * @param {number} volume The volume that you want to set 68 */ 69 setVolume(volume) { 70 /** 71 * Emitted when the volume of this interface changes. 72 * @event VolumeInterface#volumeChange 73 * @param {number} oldVolume The old volume of this interface 74 * @param {number} newVolume The new volume of this interface 75 */ 76 this.emit('volumeChange', this._volume, volume); 77 this._volume = volume; 78 } 79 80 /** 81 * Sets the volume in decibels. 82 * @param {number} db The decibels 83 */ 84 setVolumeDecibels(db) { 85 this.setVolume(Math.pow(10, db / 20)); 86 } 87 88 /** 89 * Sets the volume so that a perceived value of 0.5 is half the perceived volume etc. 90 * @param {number} value The value for the volume 91 */ 92 setVolumeLogarithmic(value) { 93 this.setVolume(Math.pow(value, 1.660964)); 94 } 95 } 96 97 const props = ['volumeDecibels', 'volumeLogarithmic', 'setVolumeDecibels', 'setVolumeLogarithmic']; 98 99 exports.applyToClass = function applyToClass(structure) { 100 for (const prop of props) { 101 Object.defineProperty(structure.prototype, prop, Object.getOwnPropertyDescriptor(VolumeInterface.prototype, prop)); 102 } 103 };