@audio/decode-dsd

中文文档
1.0.0发布于 2026/08/29MITTypeScriptES Module近 30 天下载 54.6万

Decode DSD (DSF, DFF) audio to PCM samples

原始使用文档
文档目录6 节
  1. Formats
  2. API
  3. decode(src, opts?): AudioData
  4. decoder(opts?): DSDDecoder
  5. Numbers
  6. License

@audio/decode-dsd npm MIT

Decode DSD (DSF, DFF) audio to PCM float samples.

npm install @audio/decode-dsd
import decode, { decoder } from '@audio/decode-dsd'

DSD is a 1-bit-per-sample sigma-delta stream running at 2.8224 MHz and up ("DSD64", "DSD128", …). Getting to PCM is a low-pass + decimate: a Kaiser-windowed-sinc FIR removes the noise-shaped quantization noise pushed above the audio band, then every Nth sample is kept. The first decimation stage (raw bits → 8× that rate) runs directly on the 1-bit stream using per-byte lookup tables — the classic trick from Sebastian Gesemann's dsd2pcm (BSD), also used by ffmpeg's dsd_lsbf_planar/dsd_msbf decoders; this is an independent implementation of the same idea, not a port. A second, ordinary decimating FIR (on the now multi-bit float stream, much cheaper) reaches 44.1/88.2/176.4 kHz.

let { channelData, sampleRate } = decode(dsfOrDffBytes)

let dec = decoder({ sampleRate: 88200 })
let head = dec.decode(chunk1)   // synchronous; partial blocks carry over
let tail = dec.flush()
dec.free()

Both decode() and decoder() are synchronous — no WASM, no async setup.

Formats

DSF (Sony DSD Stream File): DSD /fmt /data chunks, up to 5.1 channels, DSD64/128/256/512 sample rates, 1-bit LSB-first or MSB-first packing (per the fmt chunk's bitsPerSample field, exactly as the spec defines it), data interleaved in fixed 4096-byte-per-channel blocks. Trailing ID3v2 tag (pointed to by the DSD chunk header) via @audio/decode-dsd/meta.

DFF (Philips DSDIFF): FRM8/FVER/PROP (FS, CHNL, CMPR)/DSD chunks, data interleaved byte-per-channel, always MSB-first. DST-compressed files (CMPR = 'DST ') throw Unsupported: DST — DST is a separate lossless codec, not raw DSD. Edited-master chunks (DIIN/DITI/…) are ignored. A non-standard ID3 chunk, if present, is also readable via @audio/decode-dsd/meta.

API

decode(src, opts?): AudioData

Decode a complete Uint8Array or ArrayBuffer.

decoder(opts?): DSDDecoder

  • dec.decode(data): decode a chunk. DSF needs a full 4096 × channels-byte block group per channel before it can decode anything (that's the container's own interleave unit); DFF only needs one channels-byte frame.
  • dec.flush(): zero-pads a short final block to the container's own frame size (matching the DSF spec's own convention for a partial last block) and decodes it — it does not separately drain the FIR's group-delay tail.
  • dec.free(): release state. Idempotent.
OptionDefault
sampleRatedsdRate / 32Output rate. Must equal dsdRate / 8, /16, /32, or /64 (DSD64 → 352.8k / 176.4k / 88.2k / 44.1k) — the byte-lookup-table stage only decimates in whole-byte (8-bit) steps.
cutoff0.45Passband edge, as a fraction of the output rate, for whichever stage sets the final rate.
lengthcomputedFIR taps for that stage. Longer = closer to the stopband target, slower.
stopband100Target stopband attenuation (dB), used to derive the Kaiser β.

AudioData is { channelData: Float32Array[], sampleRate: number }.

DSD's 1-bit ±1 maps directly to PCM full scale — no gain change is applied. SACD material mastered at DSD's nominal "0 dB" can legitimately hit +6 dB relative to PCM full scale; this decoder does not clamp or renormalize, so such material will clip in the Float32 sense (values outside ±1) exactly as it would on any other bit-transparent DSD decoder.

Numbers

  • Bit-domain stage 1 (fixed): 192 taps (96-tap half + symmetry, 12-byte lookup tables), cutoff 0.45×(dsdRate/8), 100 dB target stopband.
  • Stage 2 (built per request): length computed from the Kaiser formula for a truly alias-free transition band (passband edge to the decimation's own mirror point) at the requested stopband.
  • Measured (2nd-order test tone through a properly-synthesized 5th-order 1-bit modulator, test.js): in-band SNR 114–117 dB at 44.1k/88.2k/176.4k (≥ 80 dB required, conservative under the modulator's own ~100+ dB theoretical ceiling — see test.js for the exact citation).
  • Cross-checked against ffmpeg -i x.dsf -f f32le -ar 88200 -: 1 kHz tone amplitude within 0.000 dB, phase within 1.6° after delay alignment, duration exact.
  • Speed: 60 s stereo DSD64 → 88.2 kHz decodes in ≈ 2.1 s (pure JS, single core).

License

ॐ · MIT

Use when: you have raw DSD/SACD-rip material (.dsf/.dff) and need PCM — playback, format conversion, or feeding a conventional DSP chain. Not a DST decoder (DST-compressed DFF throws) and not a DSD encoder.


Part of @audio/decode — the decode family umbrella.

MIT © audiojs

版本与发布记录

@audio/decode-dsd 共发布 1 个版本,首次发布于 2026/08/29;过去 12 个月发布了 1 个版本。

版本发布日期距今
1.0.0latest2026/08/292 个月前

关于 @audio/decode-dsd 的常见问题

@audio/decode-dsd 是什么?

Decode DSD (DSF, DFF) audio to PCM samples

如何安装 @audio/decode-dsd?

在项目目录运行 npm install @audio/decode-dsd,或使用 pnpm add / yarn add / bun add。

@audio/decode-dsd 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@audio/decode-dsd 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@audio/decode-dsd 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=18。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@audio/decode-dsd 可以商用吗?

@audio/decode-dsd 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@audio/decode-dsd 的下载量有多少?

根据 npm 官方下载统计,@audio/decode-dsd 在 2026/10/07 – 2026/11/05 这 30 天内被下载 545,958 次,日均约 18,199 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@audio/decode-dsd 还在维护吗?

最新版本 1.0.0 发布于 2026/08/29(2 个月前);至今共发布 1 个版本,其中过去 12 个月发布了 1 个;首次发布于 2026/08/29。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。