@audio/denoise-detect 0.1.2 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/denoise.js +32 -24
  2. package/package.json +1 -1
package/denoise.js CHANGED
@@ -2,14 +2,15 @@
2
2
  // in `data` and dispatches to the most suitable single-pass method.
3
3
  //
4
4
  // Classification (single STFT sweep over the input):
5
- // - tonalScore — strong narrow peaks at mains harmonics → dehum
6
- // - clickScore — high kurtosis of AR residual → declick
7
- // - lfScore — LF/MF energy ratio above 4 → dewind
8
- // - sibilanceScore — 5–9 kHz peaks vs. mids → deesser
9
- // - reverbScore — slow late-tail decay (cepstral peak) → dereverb
10
- // - stationary → omlsa (best non-stationary general denoise)
11
- // - otherwise → wiener (transparent broadband)
5
+ // - hum — narrow peaks at mains harmonics (Goertzel) → dehum
6
+ // - click — high kurtosis of AR residual → declick
7
+ // - hi — 5–9 kHz / mid energy ratio → deesser
8
+ // - lf — LF/mid energy ratio → dewind
9
+ // - nonstationarity — frame-energy CV → omlsa
10
+ // - otherwise → wiener (transparent broadband)
12
11
  //
12
+ // dereverb has no reliable single-pass signature, so auto-mode never selects it —
13
+ // reach it explicitly via `denoise(data, { force: 'dereverb' })` or `dereverb()`.
13
14
  // Returns { out, plan } so callers can inspect which method ran.
14
15
 
15
16
  import { stftAnalyse } from '@audio/stft'
@@ -56,7 +57,7 @@ export function classify(data, fs = 44100) {
56
57
  let f = k * fs / N
57
58
  if (f < 200) lf += p
58
59
  else if (f < 2000) mf += p
59
- else if (f < 9000) hi += p
60
+ else if (f >= 5000 && f < 9000) hi += p // sibilance band, kept specific (not 2–9 kHz)
60
61
  }
61
62
  lfSum += lf; mfSum += mf; hiSum += hi
62
63
  frameVar.push(lf + mf + hi)
@@ -91,23 +92,30 @@ export function classify(data, fs = 44100) {
91
92
  // HI/MF ratio
92
93
  let hiRatio = hiSum / Math.max(mfSum, 1e-30)
93
94
 
94
- // Click score: AR residual kurtosis on a short window
95
+ // Click score: max AR-residual excess kurtosis over windows spanning the whole
96
+ // signal. Clicks are sparse and impulsive — a fixed prefix window can miss them
97
+ // entirely, so scan across and take the peak (the window holding a click spikes).
95
98
  let clickScore = 0
96
- if (data.length >= 4096) {
97
- let win = data.subarray(0, 4096)
98
- try {
99
- let { a } = arFit(win, 30)
100
- let resid = new Float64Array(4096), mean = 0, m2 = 0, m4 = 0
101
- for (let i = 30; i < 4096; i++) {
102
- let s = win[i]
103
- for (let k = 1; k <= 30; k++) s += a[k] * win[i - k]
104
- resid[i] = s; mean += s
105
- }
106
- mean /= (4096 - 30)
107
- for (let i = 30; i < 4096; i++) { let d = resid[i] - mean; m2 += d * d; m4 += d * d * d * d }
108
- m2 /= (4096 - 30); m4 /= (4096 - 30)
109
- clickScore = m2 > 0 ? m4 / (m2 * m2) - 3 : 0 // excess kurtosis
110
- } catch {}
99
+ let cw = 4096
100
+ if (data.length >= cw) {
101
+ let stride = Math.max(cw, Math.floor((data.length - cw) / 8) || cw)
102
+ for (let start = 0; start + cw <= data.length; start += stride) {
103
+ let seg = data.subarray(start, start + cw)
104
+ try {
105
+ let { a } = arFit(seg, 30)
106
+ let resid = new Float64Array(cw), mean = 0, m2 = 0, m4 = 0
107
+ for (let i = 30; i < cw; i++) {
108
+ let s = seg[i]
109
+ for (let k = 1; k <= 30; k++) s += a[k] * seg[i - k]
110
+ resid[i] = s; mean += s
111
+ }
112
+ mean /= (cw - 30)
113
+ for (let i = 30; i < cw; i++) { let d = resid[i] - mean; m2 += d * d; m4 += d * d * d * d }
114
+ m2 /= (cw - 30); m4 /= (cw - 30)
115
+ let ex = m2 > 0 ? m4 / (m2 * m2) - 3 : 0 // excess kurtosis
116
+ if (ex > clickScore) clickScore = ex
117
+ } catch {}
118
+ }
111
119
  }
112
120
 
113
121
  // Stationarity: variance-of-variances of frame energy
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@audio/denoise-detect",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "denoise — content-aware auto-selector that classifies the dominant noise type",
5
5
  "type": "module",
6
6
  "sideEffects": false,