Repository navigation
Conversation
PSOLA reads each grain at base·φ, φ = 2^(FORM/12), so two source periods land in 2·period/φ output samples: the grain's spectrum, the voice's envelope, moves by φ while the hop keeps the pitch. Grains that no longer overlap (formant up) and the extra overlap of a formant down are gain-matched by energy, keeping the level within 1 dB. Saved as "formant" in a clip's tune (omitted at 0); slabkit audio(..., formant=); a FORM drag on the tune row. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… §Tune) The formant-down gain was sqrt(1/φ) on top of the overlap norm, right only without a pitch change: with TRANSPOSE or a correction it added up to 3 dB, and jumped as the pitch change crossed the formant's. Read at another speed, grains add as energy, so the norm is sqrt(hop/half) whenever FORM isn't 0. A formant down lengthens the grain past TUNE_REACH on ordinary low voices (under ~94 Hz at -12), cutting it short of two periods; φ is now held to what fits, and never pushed up for voices already past it. The ratio is worked out once a block, not once a grain. Co-Authored-By: Claude Opus 5.5 <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.
Tune keeps a voice's formants where they were, which is right for correction but leaves no way to change a voice's timbre. The usual recipe for a synthetic, GLaDOS-style voice is a hard snap (SPEED 0), flattened vibrato, the formants moved up a little, and a room reverb. Slab already had everything except the formant shift, and this PR adds it as FORM (±12 semitones) on the tune row.
How. TD-PSOLA reads each grain at the source's own speed. FORM reads it at φ = 2^(FORM/12) times that speed instead, so a grain's two source periods fit into 2·period/φ output samples. That moves the grain's spectrum, which is the voice's envelope, by φ. The grains stay a target period apart, so the pitch doesn't change. Read at another speed, neighbouring grains no longer line up, so they are normalized by energy (
sqrt(hop/half)) rather than by amplitude. A formant down lengthens the grains, so on low voices it is held back to what fits inTUNE_REACH(at −12, below about 94 Hz). Unsung grains move too, so consonants match the vowels.Saved files. A clip's
"tune"gets"formant": n, which is left out at 0, so existing projects save byte-for-byte the same. slabkit:audio(…, tune="A", formant=3). docs/30 §Tune and the CHANGELOG are updated.Tested on macOS (Apple Silicon) with zig 0.17.0.
zig build testpasses, including two new stretcher tests:End to end (slabkit, then the saved project, then
slab --render) on a synthetic vowel, chromatic, SPEED 0:Not checked: the FORM control in the running app's UI. It uses the same
dragNumas SPEED and HUMAN on the tune row's own plate.🤖 Generated with Claude Code