fix(streamer): db-scaled spectrum so bars match frontend visibility
This commit is contained in:
parent
9eaa16d818
commit
1c4c875c10
2 changed files with 11 additions and 5 deletions
|
|
@ -69,14 +69,19 @@ export class SpectrumAnalyzer {
|
|||
fftInPlace(re, im);
|
||||
|
||||
const alpha = this.opts.smoothing ?? 0.6;
|
||||
const peakRef = this.fftSize / 4;
|
||||
// db scaling — same idea as web audio's getByteFrequencyData.
|
||||
// hann-windowed full-scale sine has peak mag ~ fftSize/2; reference to that.
|
||||
const ref = this.fftSize / 2;
|
||||
const dbMin = -80;
|
||||
const dbMax = -20;
|
||||
for (let i = 0; i < this.opts.bars; i++) {
|
||||
let mag = 0;
|
||||
const s = this.bandStarts[i]!;
|
||||
const e = this.bandEnds[i]!;
|
||||
for (let k = s; k < e; k++) mag += Math.sqrt(re[k]! * re[k]! + im[k]! * im[k]!);
|
||||
mag /= e - s;
|
||||
const norm = Math.min(1, mag / peakRef);
|
||||
const db = 20 * Math.log10(Math.max(mag, 1e-9) / ref);
|
||||
const norm = Math.max(0, Math.min(1, (db - dbMin) / (dbMax - dbMin)));
|
||||
this.smooth[i] = alpha * this.smooth[i]! + (1 - alpha) * norm;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,13 +23,14 @@ describe("SpectrumAnalyzer", () => {
|
|||
});
|
||||
});
|
||||
|
||||
it("a 1khz sine puts most energy in low bars (logarithmic binning)", () => {
|
||||
it("a 200hz sine puts most energy in low bars (logarithmic binning)", () => {
|
||||
const a = new SpectrumAnalyzer({ bars: 48, sampleRate: 48000 });
|
||||
a.feed(sineFrame(1000));
|
||||
for (let n = 0; n < 4; n++) a.feed(sineFrame(200));
|
||||
const bars = a.bars();
|
||||
const lowSum = bars.slice(0, 16).reduce((s, v) => s + v, 0);
|
||||
const highSum = bars.slice(32).reduce((s, v) => s + v, 0);
|
||||
expect(lowSum).toBeGreaterThan(highSum * 5);
|
||||
expect(lowSum).toBeGreaterThan(0.1);
|
||||
expect(lowSum).toBeGreaterThan(highSum + 0.1);
|
||||
});
|
||||
|
||||
it("silence produces all-near-zero bars", () => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue