From 08f154be07687b5f30ad9d947c8e5bc81ea3c08f Mon Sep 17 00:00:00 2001 From: enricobuehler Date: Mon, 17 Aug 2026 12:15:12 +0200 Subject: [PATCH] docs(client): the pad speaker's path byte was pinned on a ~5x sweep, and the on-glass numbers are ~300x speaker_enable_packet's 0x20 was chosen from a sweep that only cleared the pad-mic noise floor by ~5x, and the value was left recorded as unsettled. A second sweep on glass (DS5 wired to a Steam Deck client, 330 Hz into the speaker pair) swept the whole byte: 0x20 and 0x30 sound, 0x10/0x40/0x50 do not, and the margin is ~300x rather than ~5x. So bit 5 is the speaker-path enable and bit 4 alone does nothing. Also records why 0x20 stays the default over the marginally louder 0x30 (0x30 asserts a second path bit whose effect on the headphone leg was never measured), and two properties this one-shot depends on that were measured the same day: the setting persists (unchanged 40 s after a single write, SDL live on the pad) and survives the pad's USB audio stream stopping and restarting, so it needs no re-assertion when the renderer opens its output. Verified end-to-end: forcing the pad to 0x00 dropped the pad mic to the 0.000000 floor and silenced the speaker; a fresh slot open restored it (0.000349, audible). Comment only - no behaviour change. --- crates/pf-client-core/src/gamepad.rs | 33 ++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/crates/pf-client-core/src/gamepad.rs b/crates/pf-client-core/src/gamepad.rs index 342138a38..90225843c 100644 --- a/crates/pf-client-core/src/gamepad.rs +++ b/crates/pf-client-core/src/gamepad.rs @@ -920,10 +920,35 @@ impl Ds5Feedback { /// audio haptics", and asserting either would mute the coils this plane drives. /// /// ⚠ `path` is empirical. Measured on a DualSense (`054c:0ce6`) using the pad's OWN - /// microphone as the detector: `0x20` was loudest (~5× the noise floor at the test tone), - /// `0x30` also sounded, `0x10` was silent. Overridable per-run with - /// `PUNKTFUNK_PAD_SPEAKER_PATH` / `PUNKTFUNK_PAD_SPEAKER_VOLUME` so a field report can - /// bisect it without a rebuild. + /// microphone as the detector, with a tone driven into the speaker pair. The first sweep + /// only cleared the noise floor by ~5× and left the value unsettled; a second sweep + /// (2026-08-17, DS5 wired to a Steam Deck client, 330 Hz) swept the whole byte and is the + /// one to trust — it separates the two sounding values by ~300×: + /// + /// | `ucAudioEnableBits` | 330 Hz energy | | + /// |---|---|---| + /// | `0x00` (power-on) | 0.000001 | silent — the headphone jack | + /// | `0x10` | 0.000002 | silent | + /// | `0x20` | 0.000283 | **speaker sounds** | + /// | `0x30` | 0.000336 | speaker sounds, marginally louder | + /// | `0x40` | 0.000001 | silent | + /// | `0x50` | 0.000002 | silent | + /// + /// So **bit 5 is the speaker-path enable** and bit 4 alone does nothing. We ship `0x20` + /// rather than the marginally louder `0x30` because `0x30` asserts a second path bit whose + /// effect on the HEADPHONE leg was NOT measured, and `0x20` already sounds — a pad with + /// headphones in its jack must not lose them to a default. Two further properties were + /// measured the same day, both of which this one-shot relies on: the setting **persists** + /// (unchanged 40 s after a single write, with SDL live on the pad), and it **survives the + /// pad's USB audio stream stopping and restarting** — so it does not need re-asserting when + /// the renderer opens its output. + /// + /// Verified end-to-end on glass 2026-08-17 by forcing the pad back to `0x00` (pad-mic floor + /// 0.000000, inaudible), then reconnecting: this packet alone restored the speaker + /// (pad-mic 0.000349, and audible to the user). + /// + /// Overridable per-run with `PUNKTFUNK_PAD_SPEAKER_PATH` / `PUNKTFUNK_PAD_SPEAKER_VOLUME` + /// so a field report can bisect it without a rebuild. fn speaker_enable_packet(volume: u8, path: u8) -> [u8; 47] { let mut p = [0u8; 47]; // bit5 = ucSpeakerVolume is valid, bit7 = the audio-control byte is valid. -- 2.54.0