record-player 0.2.0

Shared Bitneedle transport, record physics, and acoustic scratch engine
Documentation

record-player

record-player is the Rust audio engine behind BITNEEDLE. It turns decoded programme audio and hand motion into the sound of a record on a deck: platter and slipmat motion, scratching, timed controls, and record-surface behavior.

You give the engine bounded PCM windows and sample-timed controls. It gives you host-rate audio, metering, and serializable deck state. Source decoding, audio callbacks, and UI belong to the host application.

ScratchAcousticDsp is the renderer. It owns the deck, the record's acoustic behavior, and the scratch gate in one host-rate path, so a settled record at nominal speed passes the programme through untouched while a hand on the record reads it the way a needle would.

Entry points

  • ScratchAcousticDsp — the production renderer. Bounded PCM windows in, host-rate audio out.
  • ScratchGestureMapper — converts timestamped pointer samples into sample-timed mechanical controls. The C ABI wraps this and this alone.
  • PlayerEngine (exported as WasmPlayerEngine on the web target) — serializable transport and deck state, events, host commands, and view state.
  • DeckMechanicalState, ScratchGate, and the VinylVfx* processor are the pieces the renderer is built from.

The workspace contains two crates:

  • record-player — the Rust library and its optional WASM exports;
  • record-player-capi — ABI version 5, for the scratch gesture mapper. The header is include/record_player.h.

How BITNEEDLE consumes it

  • Phone. bitneedle-native-core wraps one ScratchAcousticDsp in record_player_bridge.rs and exposes it through the bitneedle_native_record_player_* C ABI; the Deck Swift package drives that. The live pointer tracker is BITNEEDLE's own.
  • Browser. web.mk builds this crate's WASM, and the AudioWorklet and take-render worker instantiate ScratchAcousticDsp directly.

PlayerEngine and the gesture-mapper C ABI ship for hosts that drive the deck through them. Consume a revision rather than copying DSP, mechanics, preset behavior, or gesture policy out of this repository into an application.

What the engine models

ScratchAcousticDsp models:

  • platter, record, motor, bearing, slipmat, and hand-contact motion;
  • playback, braking, free spin, pitch, seek, needle lift, and run-out;
  • the Baby, Stab, Chirp, Transform, Flare, Crab, Orbit, and Drum scratch presets;
  • click timing, scratch-gate state, crossfader automation, and deterministic replay;
  • locked grooves, groove wear, pressing defects, stylus effects, and surface foley;
  • velocity gain and RIAA speed tilt away from nominal speed, so a settled 1× pass is bit-exact;
  • bounded window requests, output metering, and real-time recovery diagnostics.

Real-time contract

The audio path is #![forbid(unsafe_code)] and uses bounded, preallocated storage; under cargo test an allocation guard fails a test that allocates on it. Timed controls use absolute frames. The audio callback is for rendering, so keep source decoding, whole-record allocation, network work, and UI work on the host's other threads.

Build and test

Run the complete Rust workspace:

cargo test --workspace

Build the WASM the browser instantiates:

wasm-pack build --target web --release --features wasm

Check the native ABI and header:

scripts/check-record-player-capi.sh

Evidence and design records

The SL-1200MK7 deck mechanics profile is a seed profile. Unit tests establish deterministic software behavior; hardware measurements and independent listening tests remain the reference.