Skip to content

Restore vocal-chord-emulation ("linear") pitch scaling - #9

Open
austek wants to merge 1 commit into
espeak-ng:masterfrom
ZirekHQ:fix/chord-pitch-espeak
Open

Restore vocal-chord-emulation ("linear") pitch scaling#9
austek wants to merge 1 commit into
espeak-ng:masterfrom
ZirekHQ:fix/chord-pitch-espeak

Conversation

@austek

@austek austek commented Aug 23, 2026

Copy link
Copy Markdown

Summary

Same bug, same fix as waywardgeek/sonic#71 — this repo's sonicSetChordPitch/sonicGetChordPitch are the same no-op stubs, and the surrounding code (processStreamInput, sonicCreateStream, the struct definition) is byte-identical, so the fix ports directly.

sonicSetChordPitch/sonicGetChordPitch had nothing to write to — the CLI's -c flag prints "Scaling pitch linearly" but silently produces byte-identical output to not passing -c at all.

Restores adjustPitch, overlapAddWithSeparation, the useChordPitch struct field, and its two call sites in processStreamInput — all the helpers they depend on (moveNewSamplesToPitchBuffer, findPitchPeriod, enlargeOutputBufferIfNeeded, overlapAdd, removePitchSamples, the pitchBuffer/numPitchSamples struct fields) are unchanged and shared with changeSpeed's speed-change path.

Clamps newPeriod (period / pitch) to [1, stream->maxRequired]: at this fork's current pitch-setting range (0.05–20.0), an unclamped newPeriod can hit 0 (dividing by it in overlapAdd) or exceed how many samples are actually buffered ahead of the current position (overlapAddWithSeparation reading past pitchBuffer) — a heap-buffer-overflow, confirmed via ASan.

Adds tests/chord_pitch_test.c, wired into this fork's tests/Makefile.

Also drops sonic.h's "DEPRECATED... never used by anyone" comment on the getter/setter, now inaccurate.

Test plan

  • cd tests && make runtests && ./runtests — passes, new tests included
  • Same build under -fsanitize=address,undefined — no finding from this path; only the separate, already-known findSincCoefficient finding remains
  • Built the real sonic CLI from this fork's code directly and reproduced the fix end-to-end: -c -p 0.5 and -p 0.5 now produce different output (previously byte-identical)

sonicSetChordPitch/sonicGetChordPitch were no-op stubs (same as
upstream) -- the setter had nothing to write to, so the CLI's -c flag
printed "Scaling pitch linearly" but silently produced byte-identical
output to not passing -c at all.

Restores adjustPitch, overlapAddWithSeparation, the useChordPitch
struct field, and its two call sites in processStreamInput -- all
byte-identical to what waywardgeek/sonic had before its 2022 rewrite
dropped them, and all the helpers they depend on
(moveNewSamplesToPitchBuffer, findPitchPeriod,
enlargeOutputBufferIfNeeded, overlapAdd, removePitchSamples, the
pitchBuffer/numPitchSamples struct fields) are unchanged and shared
with changeSpeed's speed-change path.

Clamps newPeriod (period / pitch) to [1, stream->maxRequired]: at this
fork's current SONIC_MIN/MAX_PITCH_SETTING range (0.05-20.0), an
unclamped newPeriod can hit 0 (dividing by it in overlapAdd) or exceed
how many samples are actually buffered ahead of the current position
(overlapAddWithSeparation reading past pitchBuffer) -- a
heap-buffer-overflow, confirmed via ASan, that the pre-2022 code was
never exercised against.

Adds tests/chord_pitch_test.c, wired into this fork's tests/Makefile:
- sonicTestChordPitchChangesOutput: enabling chord pitch must change
  output for the same pitch setting.
- sonicTestChordPitchExtremeRatioDoesNotOverflow: processes audio at
  both ends of the pitch range with chord pitch enabled without
  crashing.

Also drops sonic.h's "DEPRECATED... never used by anyone" comment on
the getter/setter, now inaccurate.

Ported from waywardgeek/sonic#71, which fixes the same bug (also
present here, byte-identical processStreamInput/sonicCreateStream and
the removed helpers' call sites) upstream.
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.

1 participant