Skip to content

v0.8.0

Latest

Choose a tag to compare

@robmorgan robmorgan released this 17 Jul 02:43
4fdc875

What's Changed

This release completes the engine rewrite: the old push-based streaming engine and the hybrid batch stretcher are deleted (ROADMAP Stages 8–9, net −22.9k lines), leaving the pull engine as the only engine — serving real-time and batch through one graph. The vestigial EDM preset system goes with it, beat analysis gets two measured accuracy fixes, and keylock becomes a live, click-free engine parameter. Published on crates.io as timestretch 0.8.0.

Breaking Changes — old engine deleted

  • Removed: StreamProcessor, StreamingEngine, StreamProfile, ControlPath, StreamLatencyReport, StreamPitchQuality, TransientResetStats, HybridStretcher, MultiResolutionStretcher, Wsola, StereoMode, the stream module, and StretchParams::{stereo_mode, with_stereo_mode, with_stream_profile}
  • Batch/offline (stretch, stretch_into, stretch_buffer) is rebased onto the engine graph with exact output length; streaming and offline are now sample-identical by construction (tests/streaming_offline_determinism.rs)
  • timestretch-cli drops --streaming / --chunk-size
  • The live keylock chain drops its phase-vocoder corrector entirely — owner listening rejected the PV at every threshold it was placed behind (measured: PV loses 2.5–3.9 dB top octave vs SOLA's ~1 dB at ±10% rate), so beat-synchronous SOLA carries the whole corrected range and the PV engages only past the correction fade end (22% rate deviation), inaudible by construction. Keylock WCET mean drops ~3× (0.026 vs ~0.08 of budget; p99.9 = 0.30 at 64-frame callbacks, strict CI gate)
  • Offline low-band contract (owner decision): stretch() shares live keylock semantics — within the corrected range (~0.833–1.25) content below the 150 Hz crossover follows tempo in pitch, offline exactly as on a deck; wide ratios render on the batch PV path with full-spectrum pitch preservation
  • Old-engine QA harnesses deleted; the quality dashboard is the engine matrix, re-anchored on absolute thresholds derived from new-engine measurements

Breaking Changes — EDM presets removed

  • Removed: EdmPreset, StretchParams::with_preset, the CLI --preset flag, and the dead tuning fields none of which ever reached the pull engine (hop_size, wsola_*, beat_aware, band_split, multi_resolution, elastic_*, hpss_enabled, residual_*, crossfade_mode, and friends — CrossfadeMode goes with them)
  • Migration: VocalChop's one live effect survives as with_envelope_preset(EnvelopePreset::Vocal), or --envelope vocal on the CLI; the other presets need no replacement
  • The analytic tonal fast path in stretch() (which only fired with a preset set) is deleted; pure tones now render through the real engine

Live Keylock Switching (New)

  • EngineController::set_keylock(bool) / keylock_target(): toggle high-band pitch correction during playback with a ~12 ms per-sample crossfade to delay-matched varispeed — no engine rebuild, no gap; SOLA stays warm while bypassed so re-engage is instant and converged
  • The desktop deck's Tape/Keylock combo now switches instantly at constant latency

Beat Analysis Accuracy

  • Onset/beat detection latency compensated: markers used to sit ~29 ms before the audible attack (FFT-window timestamp convention). Measured bias on a ground-truth 125 BPM kick train: −31.6 ms → −2.6 ms; on a real 320 kbps EDM track: −29 ms → −1.7 ms. PREANALYSIS_VERSION bumps to 4; older cached sidecars regenerate automatically
  • BPM estimation switches to the median of K-beat-baseline intervals, telescoping away a cyclic frame-grid sawtooth that read flat tracks ~0.2% high: 125.23 → 125.03 (synthetic 125.000 train), 125.22 → 124.99 (real 125.0 EDM track) — the displayed number no longer drifts a beat every ~8 minutes when beatmatching

Desktop Deck

  • Audible CDJ-style waveform scrub: dragging the zoomed waveform plays a raw varispeed scratch voice that chases the pointer (pitch follows hand speed, both directions), with release momentum (τ = 150 ms exponential glide) that lands bit-exactly on a pre-computed frame and crossfades back into the engine time-aligned
  • Grid-quantized auto-loop: one-press 4-beat loop snapped to the beat grid, with halve/double resizing from 1/8 to 32 beats
  • README screenshot recapture is now a repeatable skill (desktop/.claude/skills/readme-screenshot)

Toolchain

  • MSRV raised from 1.82 to 1.85; crate and desktop app move to Rust edition 2024 (enables cargo's MSRV-aware resolver v3)
  • Development toolchain pinned to Rust 1.97.0 via rust-toolchain.toml; CI stable jobs build with the pinned compiler (the MSRV job still tests 1.85.0)
  • The web/ WASM demo is removed — it targeted the deleted old-engine API and no longer compiled (last present at 22e5117)

Full Changelog: v0.7.0...v0.8.0