From 45d2009ccbfaeb053ebe146def9fee306c0fbed3 Mon Sep 17 00:00:00 2001 From: Yifan Mai Date: Wed, 5 Jan 2022 21:45:52 -0800 Subject: [PATCH] Smooth RMS values per channel in Meter Fixes #882 --- Tone/component/analysis/Meter.test.ts | 25 +++++++++++++++++++++++++ Tone/component/analysis/Meter.ts | 12 +++++++----- 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/Tone/component/analysis/Meter.test.ts b/Tone/component/analysis/Meter.test.ts index 2324ae4e..3b2398fb 100644 --- a/Tone/component/analysis/Meter.test.ts +++ b/Tone/component/analysis/Meter.test.ts @@ -5,6 +5,8 @@ import { ONLINE_TESTING } from "test/helper/Supports"; import { Signal } from "Tone/signal/Signal"; import { Oscillator } from "Tone/source/oscillator/Oscillator"; import { Meter } from "./Meter"; +import { Panner } from "Tone/component/channel/Panner"; +import { Merge } from "Tone/component/channel/Merge"; describe("Meter", () => { @@ -86,6 +88,29 @@ describe("Meter", () => { done(); }, 400); }); + + it("can get the rms levels for multiple channels", (done) => { + const meter = new Meter({ + channelCount: 2, + smoothing: 0.5, + }); + const merge = new Merge().connect(meter); + const osc0 = new Oscillator().connect(merge, 0, 0).start(); + const osc1 = new Oscillator().connect(merge, 0, 1).start(); + osc0.volume.value = -6; + osc1.volume.value = -18; + setTimeout(() => { + const values = meter.getValue(); + expect(values).to.have.lengthOf(2); + expect(values[0]).to.be.closeTo(-9, 1); + expect(values[1]).to.be.closeTo(-21, 1); + meter.dispose(); + merge.dispose(); + osc0.dispose(); + osc1.dispose(); + done(); + }, 400); + }); } }); }); diff --git a/Tone/component/analysis/Meter.ts b/Tone/component/analysis/Meter.ts index 88a6c1c1..cb710e3c 100644 --- a/Tone/component/analysis/Meter.ts +++ b/Tone/component/analysis/Meter.ts @@ -42,9 +42,9 @@ export class Meter extends MeterBase { smoothing: number; /** - * The previous frame's value + * The previous frame's value for each channel. */ - private _rms = 0; + private _rms: number[]; /** * @param smoothing The amount of smoothing applied between frames. @@ -64,6 +64,8 @@ export class Meter extends MeterBase { this.smoothing = options.smoothing, this.normalRange = options.normalRange; + this._rms = new Array(options.channelCount); + this._rms.fill(0); } static getDefaults(): MeterOptions { @@ -93,13 +95,13 @@ export class Meter extends MeterBase { getValue(): number | number[] { const aValues = this._analyser.getValue(); const channelValues = this.channels === 1 ? [aValues as Float32Array] : aValues as Float32Array[]; - const vals = channelValues.map(values => { + const vals = channelValues.map((values, index) => { const totalSquared = values.reduce((total, current) => total + current * current, 0); const rms = Math.sqrt(totalSquared / values.length); // the rms can only fall at the rate of the smoothing // but can jump up instantly - this._rms = Math.max(rms, this._rms * this.smoothing); - return this.normalRange ? this._rms : gainToDb(this._rms); + this._rms[index] = Math.max(rms, this._rms[index] * this.smoothing); + return this.normalRange ? this._rms[index] : gainToDb(this._rms[index]); }); if (this.channels === 1) { return vals[0];