UNPKG

2.87 kBJavaScriptView Raw
1const log = require('./log');
2
3class Loudness {
4 /**
5 * Instrument and detect a loudness value from a local microphone.
6 * @param {AudioContext} audioContext - context to create nodes from for
7 * detecting loudness
8 * @constructor
9 */
10 constructor (audioContext) {
11 /**
12 * AudioContext the mic will connect to and provide analysis of
13 * @type {AudioContext}
14 */
15 this.audioContext = audioContext;
16
17 /**
18 * Are we connecting to the mic yet?
19 * @type {Boolean}
20 */
21 this.connectingToMic = false;
22
23 /**
24 * microphone, for measuring loudness, with a level meter analyzer
25 * @type {MediaStreamSourceNode}
26 */
27 this.mic = null;
28 }
29
30 /**
31 * Get the current loudness of sound received by the microphone.
32 * Sound is measured in RMS and smoothed.
33 * Some code adapted from Tone.js: https://github.com/Tonejs/Tone.js
34 * @return {number} loudness scaled 0 to 100
35 */
36 getLoudness () {
37 // The microphone has not been set up, so try to connect to it
38 if (!this.mic && !this.connectingToMic) {
39 this.connectingToMic = true; // prevent multiple connection attempts
40 navigator.mediaDevices.getUserMedia({audio: true}).then(stream => {
41 this.audioStream = stream;
42 this.mic = this.audioContext.createMediaStreamSource(stream);
43 this.analyser = this.audioContext.createAnalyser();
44 this.mic.connect(this.analyser);
45 this.micDataArray = new Float32Array(this.analyser.fftSize);
46 })
47 .catch(err => {
48 log.warn(err);
49 });
50 }
51
52 // If the microphone is set up and active, measure the loudness
53 if (this.mic && this.audioStream.active) {
54 this.analyser.getFloatTimeDomainData(this.micDataArray);
55 let sum = 0;
56 // compute the RMS of the sound
57 for (let i = 0; i < this.micDataArray.length; i++){
58 sum += Math.pow(this.micDataArray[i], 2);
59 }
60 let rms = Math.sqrt(sum / this.micDataArray.length);
61 // smooth the value, if it is descending
62 if (this._lastValue) {
63 rms = Math.max(rms, this._lastValue * 0.6);
64 }
65 this._lastValue = rms;
66
67 // Scale the measurement so it's more sensitive to quieter sounds
68 rms *= 1.63;
69 rms = Math.sqrt(rms);
70 // Scale it up to 0-100 and round
71 rms = Math.round(rms * 100);
72 // Prevent it from going above 100
73 rms = Math.min(rms, 100);
74 return rms;
75 }
76
77 // if there is no microphone input, return -1
78 return -1;
79 }
80}
81
82module.exports = Loudness;