npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@audio/noise-estimate

v2.3.0

Published

Noise PSD estimation — minimum statistics (Martin 2001), IMCRA (Cohen 2003), and quiet-segment profiling for spectral denoisers

Readme

@audio/noise-estimate

Noise power-spectral-density estimation — the noise floor that spectral denoisers subtract, kept off a program's held notes.

Stateful estimators over STFT magnitude frames. Feed them per-frame; read .psd (a Float64Array of N/2+1 bins) whenever you need the current noise estimate.

import { minStats } from '@audio/noise-estimate'
import { stftAnalyse } from '@audio/stft'

let est = minStats(1024, { D: 96 })          // half = frameSize/2
stftAnalyse(signal, mag => est.update(mag), { frameSize: 2048 })
let noisePsd = est.psd                        // drive Wiener / MMSE / OM-LSA gain

minStats(half, opts?)

Minimum Statistics (Martin 2001): the minimum of the recursively smoothed periodogram over the last D frames, times the bias compensation Bmin that makes it estimate the noise power rather than its lower tail. opts: D (window frames, default 96: 1.1 s at hop 512, 44.1 kHz), alpha (smoothing, 0.7), bias (default Bmin(D, α), Martin 2001 eq. 17: 3.44 for the defaults; the window's mean caps it either way), partials (with fs and hop: see partials). Returns { psd, bias, partials, update(mag) }.

Once the window holds D frames, the estimate never exceeds their mean. Bmin is Gaussian noise's ratio of mean to minimum; a steady line (a whine, a pilot tone, a carrier) hardly swings, its minimum is its mean, and Bmin put it 5–7 dB over (6.5 dB in @audio/denoise-wiener's 1.5 s window at 44.1 kHz, where the line then came through 6 dB louder than on its learned profile). The noise holds no more power than its bin: the window's mean caps it, and where the bin swings as noise or speech does, the minimum governs. Before the window is full the minimum alone counts: over fewer frames Bmin(D) runs over the Gaussian bias of that window, and the mean would undercut it everywhere.

The smoother starts as the mean of the frames so far, and its values enter the minimum once its memory, ⌈1/(1−α)⌉ frames (4 at α 0.7), is full; until then that mean is the estimate. Frames of digital silence are skipped: neither a warm-up from zero nor an edited-out pause becomes the window's minimum. Before 2.2.0 the smoother started on the first frame's periodogram, which swings over 2 degrees of freedom rather than the smoothed 2(1+α)/(1−α) Bmin is for: 1 % of bins started 20 dB low and the minimum held them there for D frames (on white noise in a 1.5 s window at 48 kHz, 2.6 % of bins 10 dB under over the first window; now 0.09 %). On white Gaussian noise through 2048/512 Hann frames the estimate's mean is 0.4–0.7 dB under the noise power for D 48–96 and α 0.7–0.95 (the cap takes 0.03–0.35 dB of it, where Pmin·Bmin spreads over the mean).

imcra(half, opts?)

Improved Minima Controlled Recursive Averaging (Cohen 2003): recursive averaging of the noisy power, frozen by the speech presence probability, with that probability from two iterations of time–frequency smoothing and minimum tracking. As the paper (eqs. 7, 10–12, 14–29, Table I), with Cohen's own omlsa.m for what it leaves open; scripts/reference.py in @audio/denoise is written from the paper and reproduces omlsa.m to the last bit on VoiceBank frames (but for near-empty bins, where omlsa.m's absolute 1e-10 floors bind), and test.js holds this code to it.

opts: fs and hop (the frame step: Table I's constants are for 8 ms frames and are rescaled to it, the decision-directed α among them, so time constants and the ~1 s minimum window hold in seconds; without them the constants apply per frame), alpha (αs, 0.9), alphaD (αd, 0.85), beta (1.47), bMin (1.66), gamma0 (4.6), gamma1 (3), zeta0 (1.67), w (1), U (8), V (15 frames of 8 ms), alphaDD (0.92 per 8 ms) and xiMin (−25 dB) for the decision-directed a priori SNR, partials (partials). Until 2.2.0 alphaDD applied per frame, whatever the frame: its memory ran 1.8× longer at 48 kHz (10.7 ms steps) than at 44.1 kHz (5.8 ms).

Returns { psd, xi, xi0, gamma, v, gain, p, frames, update(mag, spp?) }: per frame, on the updated noise estimate, the a priori SNR ξ (xi0: on the previous estimate, what the speech presence probability used), the a posteriori SNR γ, v = γξ/(1+ξ), the LSA gain GH1 and the speech presence probability p. spp (a number or per-bin array) replaces p. Digital silence is skipped. On white Gaussian noise the estimate's mean is within 0.4 dB of the noise power at 16, 44.1 and 48 kHz.

partials(bins, opts?)

A program's partials kept out of a tracked noise. Minimum statistics and IMCRA take whatever holds a bin for about a second as noise: a held note, a sustained vowel, a chord's partials were learned, and the gain built on the estimate took them down. update(y2, psd), each frame after the tracker's own update, reads where a partial stands and there holds psd at what the bin held before the partial came:

  • P, |Y|² smoothed over 30 ms, and F, its morphological opening across frequency (the least over ±4 bins, then the largest of that over ±4): a peak narrower than 9 bins is taken off, the floor between partials stays (the inverse harmonic mask of Nelke, Naylor & Vary, ICASSP 2015).
  • A partial: P over 6 F (7.8 dB) within ±1 bin (vibrato, a glide) for 0.3 s running, and 10 dB over the bin's noise memory. It and its Hann main lobe (±2 bins) are held; a held bin stays held while the tracker reads it 6 dB over its memory, for the tracker still holds what the partial left after it ends.
  • The memory: the tracker's estimate averaged over the bin's free frames (neither peaked nor held), per eighth of T (60 s), the least of the last eight.

A line steady from the take's start (hum, a fan's whine, an engine) has no free frame and no memory: it stays noise. One that starts mid-take is held as a partial until its bin has had no free frame for T, then it is learned, as is a note held longer. A note sounding from the first frame is learned until its bin is once free of it: nothing tells it from a line there. On Gaussian noise alone nothing is held, and the estimate is the tracker's to the bit. Returns { flag, lines, mem, update }: flag, the bins held this frame; lines, the bins with no free frame in the window that have peaked for T/8 running or more (the lines of a noise bed, or a note sounding since the take began); mem, the memory. opts: dt (the frame step, s) and T.

minStats and imcra take it as partials: true (or its options) with fs and hop; their estimators then carry it as .partials. Off by default here; @audio/denoise-omlsa, -wiener and -spectral turn it on. The 0.3 s, the 10 dB and the 60 s were chosen on VoiceBank+DEMAND training speech, four music recordings and VocalSet long tones (scripts/broadband.mjs in @audio/denoise): held from 54 ms on, the guard also held down a noise rising under a voice's harmonics (PESQ −0.015); without the 10 dB rise over the memory, a noise's own peaks were held as partials; a 10 s window let a song's repeated chords be learned (Slakh mixes cut six times as much).

noiseProfile(data, opts?)

One-shot baseline: averages |X|² over a quiet segment (opts.from/opts.to samples). Returns a Float64Array PSD. Use when you can point at a known noise-only region.

known(profile, opts?)

A noise known rather than tracked: profile (a noiseProfile) is held, and each update(mag) gives what imcra gives on it: ξ, decision-directed on GH1 (alphaDD 0.92 per 8 ms, rescaled to the frame step given fs and hop as imcra's; xiMin −25 dB), γ, v and GH1, so a gain written for imcra (OM-LSA's) runs on a learned noise unchanged. xi0 is xi; p stays 0. Digital silence is skipped.

References

R. Martin, "Noise power spectral density estimation based on optimal smoothing and minimum statistics", IEEE Trans. Speech Audio Process. 9(5), 2001 · R. Martin, "Bias compensation methods for minimum statistics noise power spectral density estimation", Signal Processing 86, 2006 (M(D), Table 5) · I. Cohen, "Noise spectrum estimation in adverse environments: improved minima controlled recursive averaging", IEEE Trans. Speech Audio Process. 11(5), 2003 · I. Cohen, omlsa.m, israelcohen.com/software · C. M. Nelke, P. A. Naylor, P. Vary, "Wind noise short term power spectrum estimation using pitch adaptive inverse binary masks", ICASSP 2015.

Notes

STFT via @audio/stft; pairs with @audio/vad's spp(). Also re-exported from @audio/denoise. MIT.