{"_id":"@audio/measure-correct","name":"@audio/measure-correct","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@audio/measure-correct","version":"0.1.0","description":"Response correction design — measured response + target curve → FIR and/or parametric correction EQ (REW/Dirac/Acourate class)","type":"module","sideEffects":false,"main":"correct.js","exports":{".":"./correct.js","./package.json":"./package.json"},"dependencies":{"@audio/encode-wav":"^1.0.0","@audio/eq-fir":"^1.0.0","@audio/eq-parametric":"^1.0.0","@audio/measure-response":"^1.0.0","@audio/spectral-target":"^1.0.0","fourier-transform":"^2.2.0"},"optionalDependencies":{"@audio/eq-fit":"^0.1.0"},"devDependencies":{"@audio/biquad":"^1.0.0","@audio/decode-wav":"^1.0.0","tst":"^9.4.0"},"scripts":{"test":"node test.js"},"keywords":["audio","dsp","measurement","eq","correction","room-eq","headphone-eq","linearization","fir","parametric"],"license":"MIT","author":{"name":"Dmitry Iv.","email":"dfcreative@gmail.com"},"engines":{"node":">=18"},"publishConfig":{"access":"public"},"repository":{"type":"git","url":"git+https://github.com/audiojs/measure.git","directory":"packages/measure-correct"},"types":"index.d.ts","funding":"https://github.com/sponsors/audiojs","gitHead":"f2a50859fe5dabcd2f9b0199ff5cbfecca2f31ec","_id":"@audio/measure-correct@0.1.0","bugs":{"url":"https://github.com/audiojs/measure/issues"},"homepage":"https://github.com/audiojs/measure#readme","_nodeVersion":"25.9.0","_npmVersion":"11.12.1","dist":{"integrity":"sha512-a1y05X2jH/HMLbVaIQqNSfTxfdUv2vfju5W/0SlkKGQiSLCH/bhV5EcuB2FDuZUBnLWYQh/FpcNu/CDZUJOAKw==","shasum":"f133d87494393742b78955b66d4dda6cec0d149d","tarball":"https://registry.npmjs.org/@audio/measure-correct/-/measure-correct-0.1.0.tgz","fileCount":5,"unpackedSize":30165,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIDTFzPsG2WeM2F20r/OXjjQy8w43QzuUZHqbmh3fs+PrAiAqWIfJModKvPG3+0unbo6tDQgHe00PVe4mCQAQFddu4A=="}]},"_npmUser":{"name":"dy","email":"df.creative@gmail.com"},"directories":{},"maintainers":[{"name":"jamen","email":"jamenmarz@gmail.com"},{"name":"dfcreative","email":"df.creative@gmail.com"},{"name":"dy","email":"df.creative@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/measure-correct_0.1.0_1787959420478_0.43976046977024663"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-28T23:23:40.331Z","0.1.0":"2026-08-28T23:23:40.595Z","modified":"2026-08-28T23:23:40.973Z"},"maintainers":[{"name":"jamen","email":"jamenmarz@gmail.com"},{"name":"dfcreative","email":"df.creative@gmail.com"},{"name":"dy","email":"df.creative@gmail.com"}],"description":"Response correction design — measured response + target curve → FIR and/or parametric correction EQ (REW/Dirac/Acourate class)","homepage":"https://github.com/audiojs/measure#readme","keywords":["audio","dsp","measurement","eq","correction","room-eq","headphone-eq","linearization","fir","parametric"],"repository":{"type":"git","url":"git+https://github.com/audiojs/measure.git","directory":"packages/measure-correct"},"author":{"name":"Dmitry Iv.","email":"dfcreative@gmail.com"},"bugs":{"url":"https://github.com/audiojs/measure/issues"},"license":"MIT","readme":"# @audio/measure-correct [![npm](https://img.shields.io/npm/v/@audio/measure-correct)](https://www.npmjs.com/package/@audio/measure-correct) [![MIT](https://img.shields.io/badge/MIT-%E0%A5%90-white)](https://github.com/krishnized/license)\n\nResponse correction design — measured response + target curve → FIR and/or parametric correction EQ\n\n```\nnpm install @audio/measure-correct\n```\n\n```js\nimport correct from '@audio/measure-correct'\n```\n\nRoom/headphone/speaker linearization, REW/Dirac/Acourate class: given a measured response (an impulse response, a `{freqs, db}` curve, or `{f, gain}` points) and a target curve, designs a correction EQ that flattens the difference. The measured curve is fractional-octave smoothed, level-aligned to the target, then inverted with Kirkeby-regularized deviation (`correction = dev·|H|²/(|H|²+λ)` in linear magnitude — a deep null in the measured response gets rolled off toward 0 rather than boosted to cancel it, since a literal 1/H inverse blows up exactly where H is small) and clamped to boost/cut limits, tapering to 0 dB outside `[fMin, fMax]`. The correction renders as a linear-phase (or minimum-phase) FIR via [`@audio/eq-fir`](https://github.com/audiojs/eq/tree/main/packages/eq-fir)'s frequency-sampling design and/or as parametric bands via [`@audio/eq-fit`](https://github.com/audiojs/eq/tree/main/packages/eq-fit)'s Levenberg-Marquardt fit.\n\n> Kirkeby, O. & Nelson, P.A. — *Digital Filter Design for Inversion Problems in Sound Reproduction*, J. Audio Eng. Soc. 47(7/8):583–595, 1999.\n> Oppenheim, A.V. & Schafer, R.W. — *Discrete-Time Signal Processing*, 3rd ed., §12 (Homomorphic Filtering) — minimum-phase reconstruction from a magnitude spectrum via real-cepstrum folding.\n> Precedents: REW ([Room EQ Wizard](https://www.roomeqwizard.com/)), [Dirac Live](https://www.dirac.com/), [Acourate](https://www.acourate.com/) — commercial/reference room-correction tools this module's shape follows (target curve, smoothing, boost/cut limits, band edges, min-phase option).\n> Olive, S., Welti, T. & McMullin, E. — *A Statistical Model that Predicts Listeners' Preference Ratings of In-Room Loudspeaker Response*, AES 135th Convention, 2013 — the Harman target curve, one shape for `opts.target`'s `{freqs, db}` form.\n\n```js\nlet ir = /* Float32Array impulse response from @audio/measure-ir */\nlet result = await correct(ir, { fs: 48000, target: 'flat', mode: 'fir' })\n// result.coefs — Float64Array, linear-phase FIR, ready for @audio/eq-fir's firEq\n\nimport { apply } from '@audio/measure-correct'\nawait apply(myBuffer, result, { fs: 48000 })   // firEq(coefs) or eq-parametric(bands+preamp)\n```\n\n```js\n// parametric — a real EQ's band list, plus an Equalizer APO export\nlet result = await correct(ir, { fs: 48000, target: 'flat', mode: 'parametric', bands: 8 })\nlet apo = await toEqualizerApo(result)   // 'Preamp: -5.0 dB\\nFilter 1: ON PK Fc 80 Hz Gain -6.0 dB Q 3.82\\n...'\n```\n\n| Param | Default | |\n|---|---|---|\n| `fs` | `44100` | Sample rate, Hz |\n| `target` | `'flat'` | `'flat'` \\| `'speech'`\\|`'music'`\\|`'pink'`\\|`'voice-music'` ([`@audio/spectral-target`](https://github.com/audiojs/spectral/tree/main/packages/spectral-target) presets) \\| `{f, gain}[]` \\| `f => dB` \\| `{freqs, db}` |\n| `fMin` / `fMax` | `20` / `20000` | Correction band, Hz — outside it, correction tapers to 0 dB over 1/3 octave |\n| `smoothOct` | `1/6` | Fractional-octave smoothing of the measured curve. REW's own default for room EQ; use `1/12` for headphones |\n| `maxBoost` / `maxCut` | `6` / `20` | Correction limits, dB |\n| `regularization` | `0.1` | Kirkeby λ — 0 disables regularization (naive `target − measured` inversion) |\n| `level` | `'auto'` | `'auto'` mean-matches the measured curve to the target's in-band level; a number is a fixed dB offset added to the measured curve instead |\n| `mode` | `'fir'` | `'fir'` \\| `'parametric'` \\| `'both'` |\n| `taps` | `4095` | FIR length (forced odd) |\n| `bands` | `10` | Max parametric band count |\n| `minPhase` | `false` | Convert the FIR to minimum phase (real-cepstrum folding) — same magnitude, near-zero group delay instead of `(taps−1)/2` samples |\n\nReturns `{ freqs, measured, target, correction, coefs?, bands?, preamp?, residual, rms, maxBoost }` — see `index.d.ts` for the full shape. `measured` is the smoothed-and-level-aligned curve the correction was computed against; `residual` is `target − (measured + realized correction)`, predicted from the actual FIR (its own FFT magnitude) or parametric cascade ([`@audio/eq-fit`](https://github.com/audiojs/eq/tree/main/packages/eq-fit)'s `response()`, preamp excluded — preamp is a broadband headroom offset, not part of the corrected shape, matching `eq-fit`'s own `error` convention).\n\n`correct()`, `apply()`, `toEqualizerApo()` and `toWavIr()` are all **async**: `mode: 'parametric'` dynamically imports `@audio/eq-fit` (an optional peer — install it to unlock parametric/both modes; `mode: 'fir'` never needs it and works standalone), and `apply()`/`toWavIr()` dynamically import `@audio/eq-fir`/`@audio/eq-parametric`/`@audio/encode-wav` only for the branch actually used.\n\nWorking math happens on an internal log-spaced grid (96 points/octave, ~10 Hz to Nyquist) rather than the linear FFT-bin grid `@audio/spectral-target`'s `smooth()`/`deviation()` use — a linear bin grid is too coarse in octave terms at low frequency (at 40 Hz, `n=8192`, `fs=48000`: ~4 bins/octave, too coarse for a clean 1/6-oct average) to resolve fractional-octave smoothing down to the bottom of the room-EQ or headphone-EQ band. `deviation()` is superseded (not reused) for this reason; `target − measured` and the taper-to-zero-at-the-band-edge shape are carried over from it, and its `target()` presets are reused directly for named `opts.target` values.\n\nA deep, narrow (high-Q) dip is *not* fully flattened by design — regularization exists specifically to prevent the enormous, narrow-band boost that would take, since that boost doesn't generalize across a room's listening positions (matched by REW's and every serious room-correction tool's own advice against fully undoing narrow nulls). `maxBoost`/`maxCut` are hard limits regardless; `regularization` softens how much of the theoretical inverse gets used before those limits even apply.\n\n**Use when:** designing a room, headphone, or speaker correction EQ from a captured measurement — feeds `@audio/eq-fir`'s `firEq`/`@audio/eq-parametric` for real-time application, or `toWavIr()`'s convolution-EQ WAV for Equalizer APO / Roon / CamillaDSP.\n\n---\n\nPart of [@audio/measure](https://github.com/audiojs/measure) — the measure family umbrella.\n\nMIT © [audiojs](https://github.com/audiojs)\n","readmeFilename":"README.md","_rev":"1-0c939cfeff57ebb139798a28a3b38503"}