higgs_audio_tts: give the codec decoder right-hand context at the end of the stream - #454
Merged
Merged
Conversation
… of the stream
The Higgs codec decoder is a non-causal conv stack, so the last frames of a
stream are decoded against zero padding on their right instead of real
context. That decodes as a rising hiss over the final ~300 ms, clearly
audible on short utterances ("Hello, how are you doing?" with a cloned
voice ends in a swell that is cut off). This is the same mechanism as the
periodic click at chunk seams (0xShug0#429) but at the end of the stream, where
the chunked path's context frames do not apply.
Repeat the last frame kCodecTailContextFrames (8) times before decoding
and trim the extra samples again. 16 and 32 frames give sample-identical
output, so 8 is enough. decode_codes() keeps its contract (same sample
count as before); the previous body becomes decode_codes_impl().
Measured on Metal (M4), Q8_0, voice clone, same seed before/after,
RMS of the last three 40 ms frames and peak of the last 100 ms:
short, seed 1: -39 -44 -34 dBFS, peak 3990 -> -41 -48 -46, peak 864
short, seed 2: -39 -46 -32 dBFS, peak 3951 -> -40 -47 -41, peak 1121
long (11.4 s): -48 -53 -46 dBFS -> -48 -53 -53, peak 334
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Owner
|
@niksedk Thanks for the PR! I will test it after wrapping up release 0.7.2 |
Contributor
Author
thx :) |
Owner
|
@niksedk PR merged. Thanks! |
oiomaker
pushed a commit
to oiomaker/subtitleedit
that referenced
this pull request
Sep 5, 2026
Rebuilt in support-files from upstream main a8fccb47, which includes 0xShug0/audio.cpp#454: the Higgs Audio v3 codec decoder now gets right-hand context at the end of the stream, removing the rising hiss that ended every clip. Same three families as before (index_tts2, higgs_audio_tts, fish_audio). New archive hashes go in at index 0, so existing installs show the amber 'update available' status and the Update button in the audio.cpp settings. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Higgs Audio v3 TTS output ends with a rising hiss over the final ~300 ms that is cut off abruptly. It is most audible on short utterances (e.g.
Hello, how are you doing?with a cloned voice) but a faint version is there on long ones too. It is independent of sampling settings, seed,reference_text, punctuation, and it reproduces on v0.7.1 and currentmain.The codec decoder is a non-causal conv stack. At the end of the stream the last frames see zero padding on their right instead of real context and decode to garbage that ramps up towards the edge. This is the same mechanism as the periodic click at chunk seams (#429 / #436), but at the end of the stream, where the chunked path's context frames do not help.
Fix
HiggsCodecRuntime::decode_codes()now repeats the last framekCodecTailContextFrames(8) times before decoding and trims the extra samples again, so the public contract (sample count) is unchanged. The previous body becomesdecode_codes_impl(). 16 and 32 context frames give sample-identical output to 8, so 8 is enough. Cost is 8 extra frames per decode.Measurements
Metal (Apple M4), Q8_0 GGUF,
higgs_audio_ttsclone with a fixed seed, before → after. RMS of the last three 40 ms frames (dBFS) and peak sample of the last 100 ms:The delayed/raw code tail was dumped to rule out stray BOC/EOC ids in the kept frames (there are none), and forcing EOC on finished codebooks during the delay flush like the reference implementation does gave bit-identical output, so the issue is purely in the codec decode edge.
Tested with
scripts/build_metal.sh --model-set custom --models higgs_audio_tts --deployment-build, server mode, multiple requests in one session.🤖 Generated with Claude Code