feat(core): pitch shift — a granular shifter as the fifth FX worklet - #3276
Open
vanceingalls wants to merge 1 commit into
Open
feat(core): pitch shift — a granular shifter as the fifth FX worklet#3276vanceingalls wants to merge 1 commit into
vanceingalls wants to merge 1 commit into
Conversation
Adds hf-pitchshift alongside the four existing dynamics worklets: a dual-tap granular delay line, 100 ms grain, taps 180° apart so one is always crossfading in as the other resets — hides the splice each tap makes on wrap. Read-tap speed relative to the write head tracks the semitone ratio, so pitch shifts without changing duration. Registered through the same workletBuilder/dispose-message path the other four use (so shapeOf never rebuilds on a param tweak, and a chain drop retires it), wired into the registry with a plain-language copy entry and a ~0.2s chain tail (two grains). One implementation, shared by preview (Web Audio in the page) and render (the same worklet run inside an OfflineAudioContext in the headless browser) — confirmed by a browser-render test that measures the actual output frequency, not just that it differs from input. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This was referenced Aug 14, 2026
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.
Summary
hf-pitchshift, a fifth AudioWorklet FX processor alongside compressor/limiter/gate/bitcrush: a dual-tap granular delay line (100 ms grain, taps 180° apart) that shifts pitch without changing playback duration.audioFx.ts), the graph builder (audioFxGraph.ts, sameworkletBuilder/dispose-message contract as the other four worklets), plain-language copy (audioFxCopy.ts, no speech words per the audit test), and the chain-tail model (audioFxTail.ts, ~0.2s for two grains).OfflineAudioContextin the headless browser) — no separate ffmpeg filter needed, matching how the other four worklet effects already work.nodeTail's switch into small per-effect helper functions while adding thepitchshiftcase, to keep it under the complexity threshold (fallow was already close before this change).Test plan
bun run build(regeneratespackages/core/src/generated/audio-fx-runtime-inline.tsfrom source — never hand-edited)cd packages/core && bun run test— 2344/2344 pass, including newHfPitchshiftunit tests (semitones:0 exact passthrough at the grain/2 delay, semitones:±12 octave shift via zero-crossing frequency estimate)cd packages/engine && bunx vitest run src/services/audioFxRender.test.ts— 16/16 pass, including a new browser-render test that measures the actual output frequency after an octave-up shift (proves render/preview parity empirically, not just structurally)cd packages/engine && bun run test— 1527 passed, 3 skipped (pre-existing), no regressionsbunx oxfmt/bunx oxlintclean on all touched filesStacks on #3275 (A2) and #3274 (A1) — should merge after both.
🤖 Generated with Claude Code