Skip to content

audioio: increase Linux ALSA/Pulse buffer from 30ms to 80ms - #83

Open
rafael2k wants to merge 1 commit into
mercuryv2from
fix/alsa-buffer-size-pi-crackle
Open

audioio: increase Linux ALSA/Pulse buffer from 30ms to 80ms#83
rafael2k wants to merge 1 commit into
mercuryv2from
fix/alsa-buffer-size-pi-crackle

Conversation

@rafael2k

Copy link
Copy Markdown
Contributor

Raspberry Pi USB audio suffers from isochronous transfer jitter that causes buffer underruns with small 10ms periods. The resulting gaps in TX audio manifest as crackling noise that prevents reliable decoding by remote stations (e.g. VARA HF at ~5% decode rate).

Both ALSA and PulseAudio backends share this buffer length config. Increasing to 80ms (3 periods of ~27ms) gives the Pi's dwc_otg USB driver sufficient headroom to avoid underruns.

Closes #81

Raspberry Pi USB audio suffers from isochronous transfer jitter that
causes buffer underruns with small 10ms periods. The resulting gaps
in TX audio manifest as crackling noise that prevents reliable decoding
by remote stations (e.g. VARA HF at ~5% decode rate).

Both ALSA and PulseAudio backends share this buffer length config.
Increasing to 80ms (3 periods of ~27ms) gives the Pi's dwc_otg USB
driver sufficient headroom to avoid underruns.

Closes #81
rafael2k added a commit that referenced this pull request Jun 14, 2026
The 8 kHz -> 48 kHz playback (TX) upsampler interpolated each read-
period in isolation: at the last sample of every period it set
next=current, flattening the tail, then the next period jumped to its
first sample.  The signal transition across the boundary was never
interpolated, producing a step discontinuity — an audible click once
per audio period.  This matches every report in issue #81: a pop at
the start of each period, its rate scaling with the period count, and
bigger buffers only lowering the pop *rate* (PR #83 masked it, did not
fix it).

Fix: make the interpolator stateful — bridge the PREVIOUS input sample
to the current one and carry it across periods (resamp_prev), so the
output is continuous over period boundaries.  Silence now also ramps
cleanly in/out.  Also widens the interpolation product to 64 bit
(cur-prev spans 2^32 at full scale).

Offline test (tests/audioio/test_resampler.c, no sound card needed):
the old algorithm's worst sample-to-sample jump lands exactly on a
period boundary at 6.0x the smooth signal slope (~71% of full scale);
the new one is 0.41x — continuous — and chunked-vs-whole output is
bit-identical, proving boundaries are invisible.

Does NOT address the separate image-rejection weakness of linear
interpolation (the residual aliasing/'wavetable' quality also noted in

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
pedromessetti pushed a commit to pedromessetti/mercury that referenced this pull request Jul 1, 2026
The 8 kHz -> 48 kHz playback (TX) upsampler interpolated each read-
period in isolation: at the last sample of every period it set
next=current, flattening the tail, then the next period jumped to its
first sample.  The signal transition across the boundary was never
interpolated, producing a step discontinuity — an audible click once
per audio period.  This matches every report in issue Rhizomatica#81: a pop at
the start of each period, its rate scaling with the period count, and
bigger buffers only lowering the pop *rate* (PR Rhizomatica#83 masked it, did not
fix it).

Fix: make the interpolator stateful — bridge the PREVIOUS input sample
to the current one and carry it across periods (resamp_prev), so the
output is continuous over period boundaries.  Silence now also ramps
cleanly in/out.  Also widens the interpolation product to 64 bit
(cur-prev spans 2^32 at full scale).

Offline test (tests/audioio/test_resampler.c, no sound card needed):
the old algorithm's worst sample-to-sample jump lands exactly on a
period boundary at 6.0x the smooth signal slope (~71% of full scale);
the new one is 0.41x — continuous — and chunked-vs-whole output is
bit-identical, proving boundaries are invisible.

Does NOT address the separate image-rejection weakness of linear
interpolation (the residual aliasing/'wavetable' quality also noted in
Rhizomatica#81) — that needs a polyphase anti-imaging filter and follows next.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Crackling noise with Pi/ALSA?

1 participant