fix: recordings buried under hiss — the cheap resampler was folding it in

Reported precisely: on the air the voice is well clear of the noise; in the
recording the noise is louder than the voice. Same audio, so the fault is in how
it is captured, not in what is captured.

AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY was set alongside AUTOCONVERTPCM. The
name reads like a sensible default and is not: it selects the CHEAP sample-rate
converter, for cases where quality does not matter. Taking a rig's 48 kHz stream
down to our 16 kHz, it folds everything above 8 kHz back into the audio band —
and receiver hiss is mostly high frequencies. The voice keeps its level, the
noise arrives twice.

Dropped, so Windows uses its normal converter, which filters before decimating.
This affects every capture and render path in the app, the voice keyer included.
This commit is contained in:
2026-07-31 21:12:59 +02:00
parent 2b61f43780
commit 5e0bb6e68e
2 changed files with 15 additions and 3 deletions
+11 -1
View File
@@ -80,7 +80,17 @@ func pcmFormat() *wca.WAVEFORMATEX {
}
}
const autoConvert = wca.AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM | wca.AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY
// autoConvert lets WASAPI resample between the device format and ours.
//
// SRC_DEFAULT_QUALITY used to be set alongside it, and that name is misleading:
// it selects the CHEAP converter, meant for cases where quality does not matter.
// Going from a rig 48 kHz stream down to our 16 kHz, it folds everything above
// 8 kHz back into the audio band — and a receiver hiss is mostly high
// frequencies. The result was a recording where the noise sat ON TOP of the
// voice, while the same audio heard live had the voice well clear of it.
//
// Without the flag Windows uses its normal converter, which filters first.
const autoConvert = wca.AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM
// recordPCM captures from a device into 16 kHz mono 16-bit PCM bytes until the
// stop channel is closed.