Skip to content

8-bit WAV is decoded as signed, but WAV 8-bit PCM is unsigned (silence reads as -128) #12

Description

@thorwhalen

The bug

WAV 8-bit PCM is unsigned (0–255, silence at 128) per the spec. recode decodes it as signed, so every 8-bit sample comes back off by a 128 wrap:

raw payload bytes       [  0,  64, 128,  192, 255]
spec-correct amplitudes [-128, -64,   0,   64, 127]     # unsigned minus 128
recode decode_wav_bytes [   0,  64,-128,  -64,  -1]     # wrong

Digital silence (128) decodes as -128 — full negative.

Why it is only worth filing now

Before #11 the 8-bit path was usually reading from the wrong offset anyway: the old size-subtraction counted the RIFF word-alignment pad byte as header, so a 3-sample 8-bit file returned [2, 3, 0] where the payload was [1, 2, 3]. #11 fixed the alignment, so the 8-bit path now lands on the right bytes for the first time — which makes the sign error the remaining defect and newly reachable.

Why it was kept out of #11

The signedness is not decided in the WAV code. It comes from mk_pcm_audio_codec / num_find_num_type_for picking the struct character, whose blast radius is every recode consumer, not just the WAV path. Non-WAV PCM callers may legitimately want today's signed b.

Suggested shape

For width_bytes == 1 on the WAV path specifically, decode with the unsigned struct char B and subtract 128; the encoder adds it back. Leave generic PCM callers on the current signed behaviour, or give them an explicit signed= choice.

Acceptance test — the probe values above round-trip:

assert decode_wav_bytes(eight_bit_wav)[0] == [-128, -64, 0, 64, 127]
assert encode_wav_bytes([-128, -64, 0, 64, 127], sr, width_bytes=1) == eight_bit_wav

Note _wav(..., width=1) in test_recode.py already builds valid 8-bit fixtures.

Found by adversarial review while fixing #4.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions