buddy

node MVC discord bot
Log | Files | Refs | README

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 };