Skip to content

Complex time-stretch: HQ offline render + real-time STFT play mode#307

Draft
SynthsBack-lab wants to merge 3 commits into
andremichelle:mainfrom
SynthsBack-lab:complex-timestretch
Draft

Complex time-stretch: HQ offline render + real-time STFT play mode#307
SynthsBack-lab wants to merge 3 commits into
andremichelle:mainfrom
SynthsBack-lab:complex-timestretch

Conversation

@SynthsBack-lab

Copy link
Copy Markdown

Complex time-stretch — HQ offline render + real-time STFT play mode

Draft / RFC — opening early for feedback on the approach before polishing.

Adds a phase-vocoder ("Complex") time-stretch alongside the existing granular one, in three logical commits:

  1. Offline HQ render — a Render HQ Stretch region action (right-click → Play Mode context) that renders a warped region through the signalsmith-stretch WASM engine (MIT), following the region's warp markers as a piecewise-linear schedule, and replaces the region with the baked result.
  2. no_std Rust port of the Signalsmith Stretch core (complex FFT, dynamic STFT with a Kaiser PR window, 4-way phase prediction with peak-based frequency map + formant preservation) into crates/engine/src/stretch. Derived from signalsmith-stretch v1.3.2 (MIT, © Signalsmith Audio); credited in the module header. 16 unit tests.
  3. Real-time play modeComplexStretchSequencer drives the ported stretcher live from a region's warp map per block (output pulse span → source-sample span via ppqn_to_seconds; pitch as a semitone transpose). A new algorithm enum field on AudioTimeStretchBox (0 granular, 1 complex, default granular so existing projects are unaffected) routes a region to a parallel per-region sequencer pool that mirrors the granular pool's pre-warm/recycle lifecycle. Exposed as a Complex Engine toggle in the region Play Mode menu.

How to try it

Set an audio region to Timestretch, then Play Mode → Complex Engine. (Real-time playback uses the WASM engine — on the TS engine a Complex region falls back to granular.)

Known limitations (why this is a draft)

  • Latency is not compensated. STFT stretching is inherently ~one block latent (~43 ms at the chosen block size); the engine has no per-region PDC yet, so Complex playback lags granular/native by that much. A delay-compensation pass is the natural follow-up.
  • WASM engine only for the real-time path; the TS engine would need its own port.
  • The offline render's replacement region carries position/duration/gain/label but not yet loop/fade settings.

Testing

104 engine tests pass (incl. the new stretch + sequencer tests); wasm32-unknown-unknown release build clean; verified end-to-end in the browser (region → Complex Engine plays through the WASM engine, no panics, correct pitch-preserving stretch).

🤖 Generated with Claude Code

SynthsBack-lab and others added 3 commits July 10, 2026 19:35
AudioWarpRender renders a time-stretch/pitch-stretch region offline through
the signalsmith-stretch WASM engine, following its warp markers as a
piecewise-linear schedule, then replaces the region with the rendered
result. Adds the "Render HQ Stretch" region context-menu action and the
signalsmith-stretch dependency + typings.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
STFT band phase-prediction time-stretcher ported from signalsmith-stretch
v1.3.2 (MIT, (c) Signalsmith Audio): a complex radix-2 FFT, the DynamicSTFT
(modified half-bin spectrum, Kaiser perfect-reconstruction window,
self-normalising overlap-add), and the stretch core (4-way vertical phase
prediction with channel phase-locking, peak-based frequency map with
tonality limit, formant preservation). no_std, wasm32 + SIMD128, 17 unit
tests. Not yet wired as an engine play mode.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Wire the ported Signalsmith stretcher into the engine as a live play mode
beside the granular one. ComplexStretchSequencer drives the STFT stretcher
from a region's warp map per block (output pulse span -> source-sample span
via ppqn_to_seconds), pitch as a semitone transpose. Adds an 'algorithm'
field (0 granular, 1 complex) to AudioTimeStretchBox, a StretchAlgorithm
enum, a parallel per-region sequencer pool with the same pre-warm/recycle
lifecycle, adapter get/set, math::log2, and a 'Complex Engine' toggle in the
region Play Mode menu. Real-time only in the WASM engine; the TS engine
falls back to granular.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ed6d9b89-0ea9-41ea-b031-7eadeace6a58

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

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