Smooth RMS values per channel in Meter

Fixes #882
This commit is contained in:
Yifan Mai 2022-01-05 21:45:52 -08:00
parent aad2d8c890
commit 45d2009ccb
2 changed files with 32 additions and 5 deletions

View file

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

View file

@ -42,9 +42,9 @@ export class Meter extends MeterBase<MeterOptions> {
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<MeterOptions> {
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<MeterOptions> {
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];