# 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`](./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:
```sh
cargo test --workspace
```
Build the WASM the browser instantiates:
```sh
wasm-pack build --target web --release --features wasm
```
Check the native ABI and header:
```sh
scripts/check-record-player-capi.sh
```
## Evidence and design records
- [`docs/RENDERER_ARCHITECTURE_DECISION_LOG.md`](./docs/RENDERER_ARCHITECTURE_DECISION_LOG.md)
records the renderer's design and the transparent-playback rule.
- [`docs/SCRATCH_FEEL_DECISION_LOG.md`](./docs/SCRATCH_FEEL_DECISION_LOG.md)
is the scratch-feel investigation and its live A/B evidence.
- [`docs/REFERENCE_ENGINE_GAP_AUDIT.md`](./docs/REFERENCE_ENGINE_GAP_AUDIT.md)
compares this engine against the reference implementation.
- [`docs/PERCEPTUAL_ACCURACY_REPORT.md`](./docs/PERCEPTUAL_ACCURACY_REPORT.md)
separates confirmed audible behavior from work that still needs listening
evidence.
- [`docs/PHYSICS_INVESTIGATION_LOG.md`](./docs/PHYSICS_INVESTIGATION_LOG.md)
tracks model evidence, uncertainty, and rejected assumptions.
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.