Alsa-Devel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* pcm_meter: give the s16 scope a level for DSD streams
       [not found] <alsa-project/alsa-lib/pr/517@alsa-project.org>
@ 2026-07-21 22:27 ` GitHub pull_request - opened
  2026-07-27  7:43 ` GitHub pull_request - edited
  1 sibling, 0 replies; 2+ messages in thread
From: GitHub pull_request - opened @ 2026-07-21 22:27 UTC (permalink / raw)
  To: alsa-devel

alsa-project/alsa-lib pull request #517 was opened from Gjuju:

> **Depends on #516** (`pcm_meter: let the s16 scope degrade instead of killing the
> caller`) — both touch the same `switch`, so this is stacked on it to avoid a textual
> conflict. Only the second commit belongs to this PR.

## The problem

The s16 scope has no conversion for DSD, so `s16_enable()` rejects it and scopes see
nothing: needles sit still on a format that is increasingly common on USB DACs. (Before
the parent PR, they did worse than sit still — the application aborted.)

## The approach

DSD carries no sample values, only a **bit density**: over a short window the proportion
of ones *is* the amplitude, one half being silence. One S16 sample per frame can be
recovered by counting the bits of that frame and smoothing the result — which is what a
scope needs, a level rather than a reconstruction. No filter design, no resampling, no
new dependency.

Counting bits is invariant to their order, so the LE and BE variants share one code path
and only the width of a frame matters.

Two parameters set the quality, and both follow the format's own definition rather than
being tuning choices:

- **the smoothing** — a bit count is noisy (32 bits give σ = 0.5/√32), so each channel
  keeps an exponential average whose time constant is derived from the rate. It is
  therefore a *duration*, and behaves identically from DSD64 to DSD512;
- **the scale** — 0 dBFS in DSD is a 50% modulation index, so a full-scale signal swings
  the density between 25% and 75% only. Referring to the whole 0–100% range would read
  6 dB low.

## Testing

x86-64, Debian 13, DSD-capable USB DAC, playing the **same master in both formats**:

| source | min | max | mean |
|---|---|---|---|
| native DSD64 (`DSD_U32_BE` @ 88200) | 2 | 21 | 7.1 |
| FLAC 96/24 (`S32_LE` @ 96000) | 2 | 22 | 7.6 |

The needle reads the same level on both — the point being that the scale is right, not
merely that the value moves. The DAC keeps receiving `DSD_U32_BE` bit-perfect throughout;
`type meter` is a passive tap and this patch only feeds the scope.

Request URL   : https://github.com/alsa-project/alsa-lib/pull/517
Patch URL     : https://github.com/alsa-project/alsa-lib/pull/517.patch
Repository URL: https://github.com/alsa-project/alsa-lib

^ permalink raw reply	[flat|nested] 2+ messages in thread

* pcm_meter: give the s16 scope a level for DSD streams
       [not found] <alsa-project/alsa-lib/pr/517@alsa-project.org>
  2026-07-21 22:27 ` pcm_meter: give the s16 scope a level for DSD streams GitHub pull_request - opened
@ 2026-07-27  7:43 ` GitHub pull_request - edited
  1 sibling, 0 replies; 2+ messages in thread
From: GitHub pull_request - edited @ 2026-07-27  7:43 UTC (permalink / raw)
  To: alsa-devel

alsa-project/alsa-lib pull request #517 was edited from Gjuju:

> **Depends on #516** (`pcm_meter: let the s16 scope degrade instead of killing the
> caller`) — both touch the same `switch`, so this is stacked on it to avoid a textual
> conflict. Only the second commit belongs to this PR.

## The problem

The s16 scope has no conversion for DSD, so `s16_enable()` rejects it and the s16 buffer
carries nothing for a format that is increasingly common on USB DACs. (Before the parent
PR the outcome was worse than an empty buffer — the application aborted.)

## The approach

DSD carries no sample values, only a **bit density**: over a short window the proportion
of ones *is* the amplitude, one half being silence. One S16 sample per frame can be
recovered by counting the bits of that frame and smoothing the result — which is what a
scope needs, a level rather than a reconstruction. No filter design, no resampling, no
new dependency.

Counting bits is invariant to their order, so the LE and BE variants share one code path
and only the width of a frame matters.

Two parameters set the quality, and both follow the format's own definition rather than
being tuning choices:

- **the smoothing** — a bit count is noisy (32 bits give σ = 0.5/√32), so each channel
  keeps an exponential average whose time constant is derived from the rate. It is
  therefore a *duration*, and behaves identically from DSD64 to DSD512;
- **the scale** — 0 dBFS in DSD is a 50% modulation index, so a full-scale signal swings
  the density between 25% and 75% only. Referring to the whole 0–100% range would read
  6 dB low.

## Testing

x86-64, Debian 13, DSD-capable USB DAC, playing the **same master in both formats** and
sampling the level exposed on the s16 buffer:

| source | min | max | mean |
|---|---|---|---|
| native DSD64 (`DSD_U32_BE` @ 88200) | 2 | 21 | 7.1 |
| FLAC 96/24 (`S32_LE` @ 96000) | 2 | 22 | 7.6 |

The same master reads the same level in either format — the point being that the scale is
right, not merely that the value moves. The DAC keeps receiving `DSD_U32_BE` bit-perfect
throughout; `type meter` is a passive tap and this patch only feeds the scope.

Request URL   : https://github.com/alsa-project/alsa-lib/pull/517
Patch URL     : https://github.com/alsa-project/alsa-lib/pull/517.patch
Repository URL: https://github.com/alsa-project/alsa-lib

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2026-07-27  7:44 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [not found] <alsa-project/alsa-lib/pr/517@alsa-project.org>
2026-07-21 22:27 ` pcm_meter: give the s16 scope a level for DSD streams GitHub pull_request - opened
2026-07-27  7:43 ` GitHub pull_request - edited

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox