Files
zhila/docs/P1.md
T

3.3 KiB

P1a · material and the quarry

P0 proved the spine: Rust audio, a session, a protocol, a surface. P1a puts material into it: a file becomes a core, a core becomes sixteen faces, a face becomes a voice in the pattern.

The path of a sound

file input (browser)
  → ArrayBuffer
  → ws: import_core { id, name, seal } + binary audio
  → zhila-material: symphonia decode → mono f32 at the source rate
  → onset analysis: 10 ms energy hops, positive flux, local peaks
  → sixteen faces (sample ranges + RMS + rank)
  → waveform peaks (1400 bins, normalised)
  → zhila-core: Core { summary, Arc<[f32]>, faces }
  → Session::import_core: archive + journal + sync_material
  → engine: Arc<MaterialSnapshot> through the control queue
  → snapshot broadcast → the quarry

The pattern keeps its procedural voices until a row is given a face. set_pattern_face writes the reference and syncs a new material snapshot; the audio thread triggers a sample voice for that row's steps and leaves the other rows procedural. set_pattern_step edits the rhythm; both are journaled. strike_face auditions a face without touching history.

Pieces

Piece What it does
zhila-material decode (symphonia), downmix to mono, onset analysis, sixteen faces, ranks, waveform peaks, content-hash id
zhila-core Core, AudioCore, AudioFace, MaterialSnapshot; archive; pattern face/step commands; journal; engine sync
zhila-engine sample voices alongside procedural voices; a step plan that resolves a row's face to a core/face; rate-correct playback; 4 ms fades
zhila-daemon binary import after a text header, decoded in spawn_blocking; broadcast snapshot; new commands flow through the session
zhila-protocol core/face summaries, face references, import messages, pattern commands/events
ui quarry: import, core strip, waveform, face wall, audition, assign, pattern grid; the descent remains the nave

Verification

  • cargo test --workspace: 10 core tests, 2 material tests, 5 protocol tests.
  • cargo clippy --workspace --all-targets -- -D warnings and cargo fmt --check.
  • node scripts/material-smoke.mjs: a live import of fixtures/clicks-01.wav, sixteen faces, a face laid on row 1, playback, non-zero meters, face_struck.
  • npm --prefix ui run quarry-smoke: the browser imports the fixture, selects a face, assigns it, plays, screenshots the quarry and the nave, checks 80 steps and 16 faces.
  • npm --prefix ui run smoke: the P0 regression still passes.

The screenshots are preview-p1-quarry.png, preview-p1-nave.png and the empty state preview-p1-quarry-empty.png.

Limits

  • In-memory archive and pattern; no project file, no save/load, no asset persistence. A daemon restart loses the material and edits.
  • No recording, no waveform trim, no manual cut/loop points. Seams are automatic.
  • No undo/redo for pattern edits; the journal is written but not exposed.
  • One face per pattern row; no per-step face, pitch or probability yet.
  • Formats are whatever symphonia decodes; WAV is the tested path.
  • The Tauri shell is still blocked on the system development packages (see P0.md).

Next

P1b: a project folder with SQLite, content-addressed assets, autosave and reload, pattern-edit undo, recording, and waveform trim. Then the arrangement and the agent.