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/denoise-dehum

v0.3.0

Published

Mains hum removal: measured, then subtracted; no hum, no change

Readme

@audio/denoise-dehum npm MIT

Mains hum removal: measured, then subtracted; no hum, no change

npm install @audio/denoise-dehum
import dehum, { measure } from '@audio/denoise-dehum'

Measures the hum, then subtracts it: each harmonic of the mains frequency is estimated as a slowly varying sinusoid and taken out, so what goes with the hum is the program within a fraction of a hertz of each line, and less of it where the program is loud there. Without hum the audio comes back untouched. Notches (0.2.0) took whatever their band held, a band that grows with the harmonic (Q 30: 1.7 Hz at 50 Hz, 33 Hz at 1 kHz), an orchestra's G2 two hertz under the 100 Hz line among it; and as the mains frequency wanders (±0.02–0.05 Hz, h times that at harmonic h) narrow ones miss the upper harmonics.

dehum(data, { fs })                                            // 50 or 60 Hz, measured; nothing without hum
dehum(data, { fs, freq: 60 })                                  // the 60 Hz series, its exact frequency measured
dehum(data, { fs, freq: 60, harmonics: 4 })                    // remove 60–240 Hz as told
measure(data, fs)                                              // → { f0, harmonics } or null

| Param | Default | | |---|---|---| | freq | measured | Fundamental, Hz. Omitted: the 50 or 60 Hz series, whichever stands out. Given: its exact frequency within ±0.4 % (±drift Hz with adaptive) | | harmonics | to 1 kHz | Remove h = 1…harmonics. Omitted: every harmonic up to 1 kHz |

The measurement is one Fourier transform over the signal (its first 80–90 s, taken down to 3 kHz), where a hum line, steady for minutes, gathers into a peak 1/T wide while speech spreads. Hum is there when the fundamental stands out by 20 dB over the median of the ±8 Hz around it, or two of the first six harmonics by 15 dB (searched within ±0.4 %, the mains tolerance), each 6 dB over any other peak within 3 Hz, all of them harmonics of one fundamental (ph/h within 0.01 Hz). A bar of music repeated exactly is a comb of lines 1/bar apart (every 2 Hz at 120 bpm), lines at 50 and 60 Hz among them: none stands alone. On 164 music clips (MUSDB18 excerpts, BabySlakh) this finds hum in one, which has it (0.2.0: in 19); on 504 clean and 504 noisy VoiceBank training utterances, in one, a steady 49.86 Hz tone at the speech's level; with hum 20 dB under the speech, in 95 % (50 Hz) and 92 % (60 Hz) of them, as before.

Then the signal is cut into Hann frames four mains cycles long, two apart, and each harmonic's phasor taken per frame; the window's zeros fall on the other harmonics. Each harmonic's phasors are fitted over 2 s by weighted local-linear least squares (normalized convolution, Knutsson & Westin 1993), each frame weighted by the inverse of the program's power around the line there, so a passing voice or note is bridged from the frames around it rather than averaged in. The mains phase is tracked from the fitted phasors' turn, harmonics combined by h²·SNR (Hajj-Ahmad, Garg & Wu 2013) over 8 s, and the sinusoids are subtracted along it (harmonic subtraction, as power-line interference is taken out of ECG: Levkov et al. 2005). A cut in the recording jumps the hum's phase: within a second of it the fit blends the two phases and takes the hum ~10 dB down, not ~40. A note within ~0.5 Hz of a line for seconds is taken for hum. Whole clip (streaming: false), a second at least to measure; shorter, it removes the harmonics of a given freq as told and passes the audio through without one.

Measured by node scripts/dehum.js: the hum (12 harmonics at −6 dB per octave, levels drifting ±10 %, f0 0.05 Hz off nominal and wandering) and the program told apart by phase inversion (Hagerman & Olofsson 2004). 50 Hz hum 20 dB under the program, wandering ±0.02 Hz; program SDR per band where the band holds 1 % of the program:

| material | hum down, dB | program SDR, dB | <100 Hz | 100–300 | 300–1k | 1–4k | >4k | |---|---:|---:|---:|---:|---:|---:|---:| | speech | 45.5 | 38.5 | 28.9 | 39.2 | 39.2 | 83.0 | – | | narration | 43.5 | 42.7 | – | 38.8 | 42.9 | 64.5 | 73.9 | | vibeace | no hum found | | | | | | | | brahms | 42.2 | 25.7 | 30.2 | 17.9 | 27.0 | 57.8 | 50.2 | | nutcracker | 41.6 | 27.6 | 23.5 | 30.7 | 26.8 | 63.6 | – | | trumpet | 51.0 | 47.9 | – | – | 42.2 | 82.3 | – |

Hum down / program SDR, dB:

| material | 60 Hz | 50 Hz, ±0.05 Hz | 50 Hz, 30 dB under | |---|---|---|---| | speech | 46.3 / 42.1 | 36.6 / 38.6 | 38.7 / 38.6 | | narration | 43.6 / 44.0 | 33.8 / 42.8 | 42.3 / 42.9 | | vibeace | no hum found | no hum found | no hum found | | brahms | 41.7 / 29.0 | 27.8 / 25.7 | 33.9 / 25.7 | | nutcracker | 40.7 / 24.3 | 33.2 / 27.9 | no hum found | | trumpet | 51.9 / 47.8 | 46.0 / 47.7 | 48.4 / 48.0 |

The same mixtures through 0.2.0 (its Q 30 notches at the lines it found, run on hum and program apart): hum 5–15 dB down (26 in Vibe Ace at 60 Hz), program SDR 10–38 dB (speech 22.3, Brahms 13.6, its 100–300 Hz band 5.7). Hum alone, 30 s, ±0.02 Hz: 56 dB down (0.2.0: 26). Clean speech, narration and music: no sample changed. In Vibe Ace the hum's lines stand among the track's own steady ones, none alone, so none is taken for hum (0.2.0 found hum in the clean track); freq and harmonics remove them as told.

Use when: mains buzz, ground-loop hum, fixed tonal interference. Not for: broadband noise (use wiener/omlsa); shifting tones (use spectral methods).


Part of @audio/denoise — the denoise family umbrella. This README is generated from the umbrella docs.

MIT © audiojs