Loading samples
You have an audio file (a kick drum, a vocal phrase, a synth bounce) and you want to use it in a Builder — in a soundfile node, in a sampler DSP. This section is the workflow. The sample-store + the round-trip from recording → sample also touches FaustWave — Recorder § 2.
What FaustWave accepts
| Format | Notes |
|---|---|
| .wav | Full header parsing — channels / sample rate / duration are populated. The default for FaustWave's own recordings. |
| .flac | Bytes import fine; header parsing for channels / rate / duration is a TODO so those fields land as 0. |
| .aiff | Same as .flac — bytes-only for now. |
Hard limit: 100 MB per sample. Bigger files are rejected at import; chop them externally first.
How samples are addressed
FaustWave doesn't reference samples by path. Every sample lives in the sample store keyed by its sha256 content hash. Two consequences:
- Idempotent imports — importing the same bytes twice is a no-op. The second import returns the existing sha and adds no new file. Drag the same WAV in 50 times; you have one sample.
- Portable documents — a
.builderreferences its samples by sha. Share the DSP with a friend who already has the sample → it just works. Share with a friend who doesn't → they get a "browse for this sha" prompt at compile, with the original filename + channel/rate metadata as hints.
Three ways to import
A) Drag-and-drop onto a Builder canvas
Drop the file onto the Builder canvas. If there's a soundfile node selected, the sample binds to it. If not, FaustWave adds a soundfile node, binds the sample to it, and places it at the drop position.
B) The samples.import MCP action
samples.import { file_path: "<absolute OS path to your .wav/.flac/.aiff>" }
Returns the SampleEntry — { sha256, channels, sampleRate, duration, originalFilename, byteSize }. Idempotent (same bytes twice = same entry).
C) Hub install of a sample-pack
If you don't have the bytes locally but somebody published them to the Hub:
hub.install { item_id: "<sample-pack id from hub.search>" }
The install fetches the bytes + runs the same sha-keyed write path. The sample lands in your store ready to reference. See FaustWave — Hub § 3 for the publishing side.
Using the sample in a graph
1. samples.import { file_path: "<abs path to kick.wav>" } → { sha256, … }
2. documents.add { type: "builder", title: "Sample player" } → module_id
3. builder.graph.node.add { module_id, kind: "soundfile" } → sf node id
4. builder.graph.node.ref.set { module_id, node_id: <sf>, param: "sha256", value: <sha256> }
5. builder.graph.node.add { module_id, kind: "output" } → out node id
6. builder.graph.connect { module_id, source_node_id: <sf>, source_port: "audio_l",
target_node_id: <out>, target_port: "in_l" }
7. dsp.run { module_id }
(Not a click-chain — step 1 needs the absolute OS path of YOUR audio file, the one place paths are expected: the sample import gate. Ask the assistant to run the sequence with a real file.) The soundfile node's sha256 ref is the binding point: once builder.graph.node.ref.set lands, the Builder's compile includes the sample in its worklet bundle, and dsp.run plays it.
The soundfile node is a player
Since the sample-hybrid round (2026-08-29) the node is a one-shot player, not a tape that runs once at patch start:
trig_inrestarts playback on every rising edge — wiremidi_key.gate(one node per drum voice),midi_note.gate, or aclock.tick.freq_in+root_hzmake the sample follow the played note like a sampler zone: the read rate isfreq / root_hz. Measure the root withanalysis.sample(thestrongestLowBinHzfield of its spectrum block) — do not trust the pack's key label.root_hz0 = no tracking, plainrate.- Two read heads. A retrigger starts the other head and crossfades to it in ~5 ms while the old tail runs out; the last 5 ms of the file fade to zero. Both were single-sample jumps before — measured as clicks on every retriggered open hat and at the hard end of a distorted 808 sample. See FaustWave — Analysis § The click hunt.
- Shape a tail with
adsr x mulwhen the sample is longer than the note; nothing else is built (no loop, reverse or start offset — nobody asked).
The kit recipe is midi_key → soundfile → mul(velocity) → gain → add … per voice; the bundled Around the World project's Sample Kit.builder is seven of those summed.
Browsing your sample store
actions:
- action_id: samples.list
input: {}
save_as: store
label: "▶ Enumerate every sample"
Returns an array of SampleEntry — sha, original filename, channels, sample rate, duration, byte size. samples.get { sha256 } returns one entry's metadata (not the bytes — too heavy for MCP). samples.remove { sha256 } deletes (destructive — confirm before calling; DSPs referencing the sha will prompt-to-locate on next compile).
Where the bytes live on disk
| OS | Path |
|---|---|
| Windows | %APPDATA%\FaustWave IDE\samples\<sha>\<original-filename>.<ext> |
| macOS | ~/Library/Application Support/FaustWave IDE/samples/<sha>/<filename>.<ext> |
| Linux | ~/.config/FaustWave IDE/samples/<sha>/<filename>.<ext> |
The folder structure (sha-prefixed) is what lets the import be idempotent + content-addressed.
A common end-to-end task: record → re-import
The round-trip from synth performance to playable sample is one chain (full version in FaustWave — Recorder § 2):
- Press Rec.
- Play the synth via the Keyboard or Sequencer.
- Press Rec to stop —
recorder.stopreturns the WAV path. samples.import { file_path: <path> }— the recording is now sha-keyed in the store.- Drop a fresh
soundfilenode + bind by sha as in the chain above.
From "synth voice" to "playable sample slice" without leaving FaustWave.
Common moves
- "Use the kick I dragged in last week" —
samples.list { search: "kick" }narrows by filename; pick it byfilenameordurationMs, copy the sha, bind it to a freshsoundfilenode viabuilder.graph.node.ref.set. - "Delete every old WAV I dragged in for testing" —
samples.list, filter by sha or filename, iteratesamples.remove. No trash. - "Re-bind a soundfile in an existing Builder" —
builder.graph.node.ref.setwith a new sha. The change is topology-relevant so the engine recompiles; the new sample plays immediately.
Where to go from here
- FaustWave — Builder § 1 — wiring
soundfilenodes into the rest of your graph (envelope, filters, FX). - FaustWave — Recorder § 2 — the round-trip from recording → sample-store.
- FaustWave — Hub § 3 — publishing samples as
hub.publish kind: "sample-pack". - FaustWave — Getting Started § Your first recording — the 5-minute starter flow.