studio: add Autotune audio effect (real-time pitch correction, Rust/WASM DSP)#321
studio: add Autotune audio effect (real-time pitch correction, Rust/WASM DSP)#321SynthsBack-lab wants to merge 1 commit into
Conversation
📝 WalkthroughWalkthroughAdds a monophonic Autotune audio effect with YIN detection, scale snapping, TD-PSOLA pitch shifting, WASM integration, studio registration, parameter controls, telemetry, and a live tuner display. ChangesAutotune DSP core
Device runtime and studio integration
Studio UI
Estimated code review effort: 5 (Critical) | ~120 minutes Sequence Diagram(s)sequenceDiagram
participant AudioInput
participant AutotuneDevice
participant Autotune
participant Psola
participant Tuner
AudioInput->>AutotuneDevice: provide stereo audio block
AutotuneDevice->>Autotune: feed audio and detect target
AutotuneDevice->>Psola: set period and correction ratio
Psola->>AudioInput: write processed output block
AutotuneDevice->>Tuner: broadcast MIDI, target, and voiced state
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
packages/studio/core-processors/src/devices/audio-effects/AutotuneDeviceProcessor.ts (1)
29-29: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winMove
#tunerconstruction into the constructor for consistency.
#tuneris inline-initialized at the field declaration, while every sibling field (#output,#dsp,#core,#peaks) is constructed inside the constructor body. As per coding guidelines, "Move complex field initializations into the constructor instead of using inline field initializers."♻️ Proposed fix
- readonly `#tuner` = new Float32Array(3) + readonly `#tuner`: Float32Array `#source`: Option<AudioBuffer> = Option.None constructor(context: EngineContext, adapter: AutotuneDeviceBoxAdapter) { super(context) this.#adapter = adapter this.#output = new AudioBuffer() this.#dsp = new Psola(sampleRate) this.#core = new Autotune(sampleRate) this.#peaks = this.own(new PeakBroadcaster(context.broadcaster, adapter.address)) + this.#tuner = new Float32Array(3)Also applies to: 33-39
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/studio/core-processors/src/devices/audio-effects/AutotuneDeviceProcessor.ts` at line 29, Move the Float32Array construction for `#tuner` from its field declaration into the constructor, alongside the existing initialization of `#output`, `#dsp`, `#core`, and `#peaks`. Keep `#tuner` declared as a readonly field and preserve its length of 3.Source: Coding guidelines
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/autotune.md`:
- Around line 449-450: Correct Step 7 in the autotune documentation to reference
packages/studio/core-wasm/build-wasm.sh, removing the incorrect src/ segment
while preserving the instruction to update DEVICE_CRATES.
---
Nitpick comments:
In
`@packages/studio/core-processors/src/devices/audio-effects/AutotuneDeviceProcessor.ts`:
- Line 29: Move the Float32Array construction for `#tuner` from its field
declaration into the constructor, alongside the existing initialization of
`#output`, `#dsp`, `#core`, and `#peaks`. Keep `#tuner` declared as a readonly field and
preserve its length of 3.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 4aea1a52-5f8c-48d1-8992-d3dcdada9a84
⛔ Files ignored due to path filters (2)
crates/Cargo.lockis excluded by!**/*.lockdocs/autotune-device.pngis excluded by!**/*.png
📒 Files selected for processing (32)
crates/dsp/src/autotune.rscrates/dsp/src/lib.rscrates/dsp/src/pitch_shift.rscrates/dsp/src/psola.rscrates/stock-devices/device-autotune/Cargo.tomlcrates/stock-devices/device-autotune/src/lib.rscrates/studio-boxes/src/registry.rsdocs/autotune.mdpackages/app/studio/src/ui/devices/DeviceEditorFactory.tsxpackages/app/studio/src/ui/devices/audio-effects/AutotuneDeviceEditor.sasspackages/app/studio/src/ui/devices/audio-effects/AutotuneDeviceEditor.tsxpackages/app/studio/src/ui/devices/audio-effects/AutotuneTuner.sasspackages/app/studio/src/ui/devices/audio-effects/AutotuneTuner.tsxpackages/app/wasm/test/param-mapping-parity.test.tspackages/lib/dsp/src/autotune.test.tspackages/lib/dsp/src/autotune.tspackages/lib/dsp/src/index.tspackages/lib/dsp/src/pitch-shift.test.tspackages/lib/dsp/src/pitch-shift.tspackages/lib/dsp/src/psola.test.tspackages/lib/dsp/src/psola.tspackages/studio/adapters/src/BoxAdapters.tspackages/studio/adapters/src/DeviceManualUrls.tspackages/studio/adapters/src/devices/audio-effects/AutotuneDeviceBoxAdapter.tspackages/studio/core-processors/src/DeviceProcessorFactory.tspackages/studio/core-processors/src/devices/audio-effects/AutotuneDeviceProcessor.tspackages/studio/core-wasm/build-wasm.shpackages/studio/core-wasm/src/engine-modules.tspackages/studio/core/src/EffectBox.tspackages/studio/core/src/EffectFactories.tspackages/studio/forge-boxes/src/schema/devices/audio-effects/AutotuneDeviceBox.tspackages/studio/forge-boxes/src/schema/devices/index.ts
| 7. **Add the crate to the WASM build:** append its name to `DEVICE_CRATES` in | ||
| `packages/studio/core-wasm/src/build-wasm.sh`. |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Locate the actual build-wasm.sh under core-wasm to confirm the documented path.
fd -a build-wasm.sh packages/studio/core-wasmRepository: andremichelle/openDAW
Length of output: 218
Fix the build-wasm.sh path Step 7 points to packages/studio/core-wasm/src/build-wasm.sh, but the file lives at packages/studio/core-wasm/build-wasm.sh. The extra src/ will send readers to the wrong place.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/autotune.md` around lines 449 - 450, Correct Step 7 in the autotune
documentation to reference packages/studio/core-wasm/build-wasm.sh, removing the
incorrect src/ segment while preserving the instruction to update DEVICE_CRATES.
|
Thanks for this, it is a really strong contribution. The device follows the stock-device conventions closely, the abi One thing needs sorting before we can merge. The branch is based on
They are all additive, both sides just add a new device or entry to the same lists, so it is a matter of keeping both. The one to watch is Once it is rebased and |
A stock audio-effect device: YIN pitch detection (2:1-decimated, f64-exact decisions) drives a scale-mask note snap with hysteresis and octave fold, glided by Retune/Smooth with a separate vibrato-flatten path, rendered through a zero-allocation TD-PSOLA shifter (no doppler, formants preserved). - Rust no_std DSP (crates/dsp: autotune, psola) + device crate compiled to WASM; no TypeScript audio path - key/scale snapping across 8 scales; chromatic always snaps the nearest semitone (hysteresis is diatonic-only), verified by an all-scales nearest-note property test and a golden decision fixture - TS parameter adapter with a param-mapping parity test case - editor UI with live tuner telemetry (detected note, target, cents needle) streamed over the broadcast path - docs/autotune.md: full concept, DSP reference, and integration guide Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
d287489 to
0106cf8
Compare
There was a problem hiding this comment.
🧹 Nitpick comments (1)
crates/dsp/src/autotune.rs (1)
262-266: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueMinor clippy cleanups (cosmetic only).
Static analysis flags a few purely stylistic spots; behavior is unaffected:
- Line 263:
((note % 12) + 12) % 12is a manualrem_euclid—note.rem_euclid(12)is equivalent and clearer.- Lines 275-281: the
if/else ifbodies are identical (best = candidate; best_distance = distance;); could be merged with||, though keeping them separate arguably documents the two distinct tie-break rationales.- Line 349:
f0 >= F0_MIN_HZ && f0 <= F0_MAX_HZcould use(F0_MIN_HZ..=F0_MAX_HZ).contains(&f0).None of these affect correctness.
Also applies to: 268-284, 349-349
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@crates/dsp/src/autotune.rs` around lines 262 - 266, Apply the cosmetic clippy cleanups in the autotuning code: update allowed to use note.rem_euclid(12), merge the identical best/candidate assignment branches around the tie-break logic while preserving their combined condition, and replace the f0 range comparisons with an inclusive range contains check. Preserve all existing behavior and tie-break semantics.Source: Linters/SAST tools
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@crates/dsp/src/autotune.rs`:
- Around line 262-266: Apply the cosmetic clippy cleanups in the autotuning
code: update allowed to use note.rem_euclid(12), merge the identical
best/candidate assignment branches around the tie-break logic while preserving
their combined condition, and replace the f0 range comparisons with an inclusive
range contains check. Preserve all existing behavior and tie-break semantics.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: dda7d2eb-6dbd-4812-93d1-99494488413c
⛔ Files ignored due to path filters (2)
crates/Cargo.lockis excluded by!**/*.lockdocs/autotune-device.pngis excluded by!**/*.png
📒 Files selected for processing (23)
crates/dsp/src/autotune.rscrates/dsp/src/lib.rscrates/dsp/src/psola.rscrates/stock-devices/device-autotune/Cargo.tomlcrates/stock-devices/device-autotune/src/lib.rscrates/studio-boxes/src/registry.rsdocs/autotune.mdpackages/app/studio/src/ui/devices/DeviceEditorFactory.tsxpackages/app/studio/src/ui/devices/audio-effects/AutotuneDeviceEditor.sasspackages/app/studio/src/ui/devices/audio-effects/AutotuneDeviceEditor.tsxpackages/app/studio/src/ui/devices/audio-effects/AutotuneTuner.sasspackages/app/studio/src/ui/devices/audio-effects/AutotuneTuner.tsxpackages/app/wasm/test/param-mapping-parity.test.tspackages/studio/adapters/src/BoxAdapters.tspackages/studio/adapters/src/DeviceManualUrls.tspackages/studio/adapters/src/devices/audio-effects/AutotuneDeviceBoxAdapter.tspackages/studio/core-wasm/build-wasm.shpackages/studio/core-wasm/src/engine-modules.tspackages/studio/core/src/EffectBox.tspackages/studio/core/src/EffectFactories.test.tspackages/studio/core/src/EffectFactories.tspackages/studio/forge-boxes/src/schema/devices/audio-effects/AutotuneDeviceBox.tspackages/studio/forge-boxes/src/schema/devices/index.ts
🚧 Files skipped from review as they are similar to previous changes (15)
- crates/studio-boxes/src/registry.rs
- packages/studio/forge-boxes/src/schema/devices/index.ts
- packages/studio/core/src/EffectBox.ts
- packages/studio/core-wasm/src/engine-modules.ts
- packages/app/studio/src/ui/devices/audio-effects/AutotuneDeviceEditor.tsx
- packages/studio/adapters/src/BoxAdapters.ts
- crates/stock-devices/device-autotune/Cargo.toml
- packages/studio/forge-boxes/src/schema/devices/audio-effects/AutotuneDeviceBox.ts
- packages/app/studio/src/ui/devices/DeviceEditorFactory.tsx
- packages/studio/core/src/EffectFactories.ts
- packages/app/studio/src/ui/devices/audio-effects/AutotuneTuner.tsx
- packages/app/wasm/test/param-mapping-parity.test.ts
- crates/stock-devices/device-autotune/src/lib.rs
- crates/dsp/src/psola.rs
- packages/studio/adapters/src/devices/audio-effects/AutotuneDeviceBoxAdapter.ts
Adds Autotune, a stock audio-effect device for real-time monophonic pitch correction, listed in the Audio Effects browser as "Pitch Correction".
Feature set
Architecture: Rust-only DSP
All DSP is
no_std, zero-allocation Rust compiled to WASM — there is no TypeScript audio path, matching the engine architecture on currentmain:crates/dsp/src/autotune.rs— detection + note decision + correction dynamics (control core, never touches audio)crates/dsp/src/psola.rs— streaming TD-PSOLA shiftercrates/stock-devices/device-autotune/— the device (params, telemetry broadcast, per-block wiring)The TypeScript side contributes only the parameter adapter (UI/automation value mappings) and the editor. Determinism is guarded by a Rust golden decision fixture plus an all-scales nearest-note property test, and the WASM↔adapter parameter mapping by an
autotunecase inparam-mapping-parity.test.ts(EffectFactories.keyOfBoxcoverage included).docs/autotune.mddocuments the full concept, every DSP stage with its constants, the parameters, and a step-by-step integration recipe for a Rust/WASM device.Verification (all on this branch, standalone off
main@d998a2d7)turbo build: 27/27 tasks (all packages incl. studio app + full core-wasm)cargo test -p dsp: 95 passed,-p device-autotune: 3 passedlib-dspvitest: 95 passed;EffectFactories.test.ts: 3 passedpackages/app/wasm): 43 passed, including the newautotuneWASM↔TS-adapter case🤖 Generated with Claude Code
Summary by CodeRabbit