Field Sampler — interface walkthrough
Listen through 23 clips · 0:37
Every sound the walkthrough played, in order, in one file: a soft tick before each clip. Tap a row to jump to it; the row playing is highlighted. Download to listen anywhere.
1Measuring instruments0.3 s
Before measuring the app, the walkthrough's own pitch estimator (analyze.mjs: FFT peaks of the first 8 harmonics; no code shared with the app's pitch detection) is checked on synthetic tones of known pitch: plucks and decaying harmonic tones, 130–880 Hz, with noise, each searched from a hint 100¢ off.
- ✓Estimator error far below the ±2¢ the key checks allow
worst 0.0007¢ over 10 tones: pluck 223.78 Hz +0.000¢, pluck 220.69 Hz +0.000¢, pluck 130.97 Hz +0.000¢, pluck 261.58 Hz -0.000¢, pluck 438.36 Hz -0.000¢, harmonic tone 130.81 Hz +0.001¢, harmonic tone 220 Hz +0.000¢, harmonic tone 261.63 Hz -0.000¢, harmonic tone 440 Hz -0.000¢, harmonic tone 880 Hz -0.000¢
2First launch0.4 s
The app opens on a blank session: no dialogs, a prompt to record or import, and every control in place.
- ✓Empty-state prompt shown
- ✓Fits the screen without scrolling
overflow 0 px wide, 0 px tall - ✓Pads and keys rendered
12 pad slots, 13 keys
3Demo take0.7 s
Demo loads a built-in synthetic recording (knocks, thuds, plucked notes) so the app is playable without a microphone.
- ✓Demo take sliced into hits
12 hits
4Record from the microphone3.1 s
Rec starts recording at once; the waveform scrolls in live. Rec again stops, analyses and saves the take. (The microphone here is a fake device playing the demo file.)
- ✓Recording sliced into hits
6 hits in 0:02 - ✓Saved as a take with its own link
http://localhost:8788/t/2t4G7ZBhJrmA
5Import a file1.0 s
Import opens a file (here the walkthrough take: footsteps, knocks, a plucked A3 29 cents sharp, a quiet knock, a wind gust, glass, bird chirps, dropped keys, a bell and a faint knock). Analysis runs off the main thread and the take is saved.
- ✓Analysis under 1 s for 10 s of audio
sliced in 81 ms - ✓Every broadband hit found (±40 ms)
12/12 - iBird chirp at 7.6 s (narrowband, a known weak spot)
not sliced at the default sensitivity: candidate strength 0.14 vs threshold 0.25; raise sensitivity to get it - ✓No false hit in the wind gust
4.5–5.4 s clean
Ground truth: footstep 0.4s · footstep 1s · footstep 1.6s · knock 2.3s · knock 2.55s · pluck 3.2s · quiet knock 5.8s · glass 6.4s · bird chirp 7.6s · keys 8.3s · footstep 9.3s · bell 10.3s · faint knock 12.1s
6Keys arm the most tonal slice0.6 s
After analysis the keys arm the slice that makes the best instrument (pitch confidence × ring length), not slice 1. Its detected root labels the keys.
- ✓Plucked A3 is armed
KEYS PLAY Slice 6/12 A3 +29¢ - ✓Root label within 2¢ of the true pitch (A3 +29.5¢)
label 223.72 Hz vs true 223.78 Hz (-0.5¢) - ✓A clear pitch is not marked approximate (no ≈)
KEYS PLAY Slice 6/12 A3 +29¢
7Pads play trimmed slices1.3 s
A pad plays its slice from just before the attack to where the sound dies into the background, not to the next hit. Faint regions on the waveform are what gets trimmed.
- ✗Pad 1 plays its own slice (the first footstep)
capture at 44100 Hz, fixture at 48000 - ✓Plays the hit, then stops well before the next one
played 0.34 s; next hit is 0.60 s after this one - ✓No DC offset in playback (removed at import)
mean 0.0005 (the file has +0.010 offset and 6 Hz rumble)
Listen for: A short footstep thump that stops cleanly: no room hiss trailing after it.
8Normalization5.0 s
With Norm on (default), every slice plays at the same peak level, so a distant knock is as playable as a close one, up to a +18 dB lift: a near-silent slice is not turned into loud hiss. Norm off plays slices at their recorded level.
- ✗The faint knock pad plays the faint knock
capture at 44100 Hz, fixture at 48000 - ✓Norm on: both peak near -1 dBFS
knock -1.0 dBFS, quiet knock -1.0 dBFS - ✓Norm off: the quiet knock is ~10 dB softer
knock -4.7 dBFS, quiet knock -15.4 dBFS (10.6 dB apart) - ✓Norm lifts the faint knock by 18 dB and no more (peaks at −1 − shortfall)
Norm off -30.3 dBFS, Norm on -12.3 dBFS: lifted 18.0 dB; −1 dBFS would need 29.3, so it should peak at -12.3
Listen for: A knock at full level.
Listen for: Another knock, as loud as the previous one (it is 10 dB softer in the file).
Listen for: A faint knock (24 dB down in the file), Norm on: lifted, but clearly softer than the knocks before it (the lift stops at +18 dB).
Listen for: Norm off: the knock at its recorded level.
Listen for: Norm off: clearly softer than the previous knock.
Listen for: Norm off: the faint knock at its recorded level, barely there.
9Waveform: tap, double-tap, arrows3.9 s
Tapping a slice selects and auditions it (Delete acts on the selection). Double-tapping arms it on the keys. The ‹ › arrows step the armed slice. A glass and a bell have no clean harmonic series, so their roots are best guesses, marked ≈ with no cents: the glass by its lowest partial, the bell by its hum (the right note, an octave below the strike).
- ✓Tap auditions the slice
peak -1.0 dBFS - ✓Trash button appears under the selected marker
- ✓Double-tap arms the slice
KEYS PLAY Slice 8/12 ≈ A5 - ✓Glass root: ≈ and its lowest partial (A5)
KEYS PLAY Slice 8/12 ≈ A5 - ✓Bell root: ≈ and the prime's note name (A, any octave)
KEYS PLAY Slice 11/12 ≈ A3 (a period detector alone finds 44 Hz, the common divisor) - ✓‹ steps back to the pluck
KEYS PLAY Slice 6/12 A3 +29¢
Listen for: The second knock, auditioned by tapping its slice on the waveform.
10Keys: pitch matches the label8.2 s
Each key plays the armed slice at that key's pitch, tuned against the detected root, cents included: the pluck is 29 cents sharp, and its A3 key plays A3, not A3 +29¢. Touching low on a key plays it dry (no smear). Measured: the pitch of what comes out of the speakers, by the walkthrough's own estimator (step 1), to ±2¢.
- ✓Root key (MIDI 57) sounds its label (±2¢)
heard 220.00 Hz, want 220.00 Hz (-0.01¢; 8 partials) - ✓Lowest key (MIDI 48) sounds its label (±2¢)
heard 130.81 Hz, want 130.81 Hz (-0.02¢; 8 partials) - ✓Highest key (MIDI 60) sounds its label (±2¢)
heard 261.63 Hz, want 261.63 Hz (-0.00¢; 8 partials)
Listen for: The plucked string at A3, in tune (the recording is 29 cents sharp; the key corrects it), steady, no warble.
Listen for: The same pluck lower (C3), same character, no warble.
Listen for: The same pluck higher (C4), same character, no warble.
11Keys: a held note sustains9.6 s
Held past the end of its slice, a pitched note that rings plays its natural decay, then hovers where it has fallen 12 dB: each grain comes from a random in-tune spot there, so there is no fixed loop to hear repeating. Release fades it out. Fast-decaying and unpitched sounds have nothing to sustain: held, they play once and end (see MIDI).
- ✓Still sounding at 3–4 s (slice is ~2 s)
level -10.3 dB below the peak - ✓Sustain is steady (no re-strike or pulsing)
level varies 0.1 dB over 3–3.9 s - ✓The sustain stays in tune (±2¢)
heard 220.00 Hz at 3–3.9 s, key is 220.00 Hz (+0.00¢) - ✓The sustain is a clean tone (≥ 97 % of its power on its harmonics)
99.6 % on the harmonics of 220.00 Hz (±8 Hz) over 3–3.9 s - ✓No fixed loop (the held sound never replays itself)
best 20–500 ms self-match (at whole periods of the 220.00 Hz heard) stands 0.02 above the typical one (the old fixed loop scored 0.41) - ✓Release fades out within 0.4 s
silent 0.07 s after release (released at 4.20 s on the audio clock)
Listen for: The pluck rings, then settles into a steady, slightly grainy tone: no pulse, no audible loop, no re-strike. It fades at release.
12Smear7.2 s
Finger height on a key is the smear: low is dry, high freezes the sound into a grain cloud (live PaulStretch). Smeared notes release more slowly.
- ✓Smeared release is longer (≥ 0.4 s)
sounds 0.87 s after release (at 2.70 s on the audio clock) - iCloud level variation 1–2.4 s
7.1 dB
Listen for: A frozen, washy cloud made from the pluck, with a slow fade after release.
13Computer keyboard3.5 s
With a hardware keyboard: number row plays pads, A…K plays the keys, ← → step the armed slice, Z X shift octave.
- ✗1 plays pad 1 (slice 1, the first footstep)
capture at 44100 Hz, fixture at 48000 - ✓→ arms the next slice
KEYS PLAY Slice 6/12 A3 +29¢ → KEYS PLAY Slice 7/12 Unpitched → C3 - ✓X shifts the keys up an octave
C3 → C4 - ✓A plays the lowest key (MIDI 48) (±2¢)
heard 130.81 Hz, want 130.81 Hz (-0.02¢; 8 partials)
Listen for: Pad 1 (a footstep), from the hardware key 1.
Listen for: The lowest key (C3), from the hardware key A.
14MIDI14.9 s
MIDI channel 1 plays pads from C1 (note 36); channels 2–16 play slices 1–15 pitched; velocity sets level; mod wheel sets smear. (Driven through the hook a native iPad wrapper uses: window.fieldSamplerMidi.)
- ✗Ch 1 note 36 plays pad 1 (slice 1)
capture at 44100 Hz, fixture at 48000 - ✓Velocity 64 is ~12 dB softer than 127 (level = velocity²)
11.9 dB - ✓Two pads at once stay at or under 0 dBFS (master limiter)
peak -0.50 dBFS; one hit alone -1.01 dBFS - ✓Pitched channel plays A4 (±2¢)
heard 440.00 Hz, want 440.00 Hz (-0.00¢; 8 partials) - ✓A three-note chord stays at or under 0 dBFS (master limiter)
peak -2.88 dBFS - ✓A held knock plays once and ends (no sustain)
silent 0.22 s after note on, key still held - ✓Mod wheel smears (long release)
sounds 0.96 s after note off
Listen for: MIDI pad 1 at full velocity.
Listen for: The same pad, clearly softer (velocity 64).
Listen for: The same pad, louder but clean: two hits summed, held under full scale.
Listen for: The pluck an octave up (A4), from a MIDI channel.
Listen for: A three-note chord on the pluck, clean: no crackle where the notes sum.
Listen for: A knock on a MIDI channel, held: it plays once and stops, no sustain.
Listen for: The same note with the mod wheel up: smeared, with a long tail.
15Delete and undo6.3 s
Delete a transient with the trash button under its marker (or the Delete key). Its audio is dropped; Undo brings it back.
- ✓Trash removes the hit
12 → 11 - ✓Delete key removes the selected hit
11 → 10 - ✓Deletions saved to the take: those two hits
server has 2 deleted (1.00 s, 2.55 s; deleted on screen: 2.55 s, 1.00 s); the stored take gives 10 hits, the screen 10 - ✓Undo twice restores both
12 hits - ✓The undo is saved too
server has 0 deleted; the stored take gives 12 hits (screen 12)
16Add a transient6.2 s
Long-press on the waveform adds a transient at the finger. It gets its own natural end like any other hit, and its own pad. Added here in the middle of the ringing pluck, its pad starts mid-note: a 2 ms fade-in keeps that from clicking.
- ✓Long-press adds a hit
12 → 13 - ✓The added hit is saved to the take, where the finger was
server has 1 added (3.900 s); the stored take gives 13 hits - ✓Starts without a click (the first 0.1 ms is faded in)
first 0.1 ms peaks at 0.03 × the RMS 2–7 ms in (-43.3 vs -13.1 dBFS) - ✓Undo removes it
12 hits - ✓The undo is saved: nothing added on the server
server has 0 added; the stored take gives 12 hits
Listen for: A hit added by hand in the middle of the ringing pluck: it starts mid-note, softly (a 2 ms fade-in), with no click.
17Sensitivity7.1 s
The slider beside the waveform filters precomputed candidates: instant, no re-analysis. Short ticks along the bottom show what the next stretch of the slider would add. The setting is saved with the take.
- ✓Higher sensitivity is saved, and the stored take has the hits on screen
server sensitivity 0.950: 146 hits; screen 146 - ✓Lower sensitivity drops the weakest hits
146 at 0.95 / 12 at 0.5 / 11 at 0.29 (weakest hit at the default has strength 0.44) - ✓Lower sensitivity is saved, and the stored take has the hits on screen
server sensitivity 0.294: 11 hits; screen 11 - ✓Back at the middle restores the count, on screen and on the server
12 on screen, 12 stored at sensitivity 0.500 (was 12)
18Name, history and link3.0 s
Tap the name to rename. The ▾ menu lists this browser's takes and copies the take's link. Edits autosave.
- ✓Rename saved to the server
server name: Walkthrough take - ✓History lists all three takes
Walkthrough take · take-1014-2334 · demo - ✓Copy link copies the take URL
http://localhost:8788/t/ZSfVYCOhW9N0
19Shared link: view only, with a preview card0.8 s
Someone opening the link (another browser) gets the same take and can play it, but not change it. Messages and Slack show a preview card with the name and waveform.
- ✓Opens as view only
- ✓Same name
- ✓Link preview has title and image
Walkthrough take · Field Sampler · 12 hits · 0:13. Open it to play on pads and keys. - ✓Preview image served
200 image/png
20Reopen a take from history1.4 s
Choosing a take in the menu opens it (its URL becomes the address), with its own slicing and edits.
- ✓Switched to the recorded take
http://localhost:8788/t/2t4G7ZBhJrmA
21Switching takes keeps each take whole10.1 s
Opening another take, or starting a new one, never writes one take's edits into another, never loses an edit made just before the switch, and never lets a slow upload take over the address of the take on screen.
- ✓Opening a take leaves its stored name alone
the reopened take is named "take-1014-2334" on the server (expected "take-1014-2334") - ✓Edits stay with their own take
opened take on the server: "Walkthrough take", sensitivity 0.5, 0 deleted (was "Walkthrough take", 0.5, 0) - ✓An edit made just before switching is saved
the take left behind is named "Recorded, renamed" on the server - ✓Import, Demo and Rec wait while a take opens
disabled: Import true, Demo true, Rec true - ✓A slow upload does not take over the open take
address /t/ZSfVYCOhW9N0, header "Walkthrough take" (expected /t/ZSfVYCOhW9N0, "Walkthrough take") - ✓The opened take is untouched by it
server name "Walkthrough take" - ✓The new take is still saved and listed
1 → 2 demo takes in the menu
22Edits survive reopening3.7 s
A deletion is part of the saved take: opened again later (here: the page reloaded), the take comes back without the deleted hit, on screen and on the server.
- ✓Trash removes the hit
6 → 5 - ✓After reopening, the deleted hit is still gone (screen and server agree)
5 hits on screen after the reload (6 before the deletion); the stored take gives 5, without the hit at 0.409 s
23Inside the iPad app: the native engine plays5.2 s
The same page with a stand-in for the iPad app's bridge (window.fieldSamplerNative and a message handler that records what it is sent). The page must hand the take to the native engine (instrument.set: its id, slice table, roots and Norm gains, armed slice), send pads and keys as messages, and make no sound of its own. The real bridge is tested in the iPad simulator (ios/scripts/build.sh --self-test-web).
- ✓instrument.set names the take by id
ZSfVYCOhW9N0 - ✓Slice table: start < end, attack and Norm gain set, every slice
12 slices; armed 5; roots 48.0 38.1 38.0 54.6 54.5 57.3 48.0 81.0 90.9 48.0 57.0 48.0 - ✓The armed slice is pitched, with a period
root 57.29, period 4.47 ms - ✓Saved take: no PCM sent
- ✓Key 1 posts pad 1 (slice 0, with its id)
{"v":1,"type":"pad","slice":0,"id":5,"gain":1} - ✓Key A posts note.on on the armed slice (index and id), and note.off
{"v":1,"type":"note.on","key":1,"slice":5,"id":36,"note":48,"smear":0,"gain":0.8} - ✓No Rec button in an app without native recording (no "record" feature)
- ✓engine.status stopped shows in the header; midi.status on the MIDI button
IMPORT DEMO MIDI 1 Walkthrough take Audio engine stopped: interrupted 0:13 View only UNDO - ✓No Web Audio at all
no AudioContext created - ✓Unsaved take: PCM sent once, then the id under the same ref
{"pcm":[{"ref":"mv8r16a0-2","frames":352800,"bytes":1411200}],"first":{"id":null,"local":null,"ref":"mv8r16a0-2","api":"http://localhost:8788","duration":8,"sampleRate":44100,"channels":2},"last":{"id":"Adk8roQaRnLt","local":null,"ref":"mv8r16a0-2","api":"http://localhost:8788","duration":8,"sampleRate":44100,"channels":2},"history":2} - ✓The take list goes to native (takes.history)
2 entries - ✓Plugin: the first instrument.set is the restored one, complete
1 sent; first: 12 slices, armed 36 (saved 36)
24Inside the iPad app: native recording and import3.7 s
The app records and imports natively (features record and import): Rec is back in the app, the recording's live peaks come from native, and on stop the page reads the file through the bridge (capture.read, in slices) and saves it as a take on the server, exactly like an import. Import opens the app's document picker instead of the web file input. A refused microphone shows a message. Nothing uses getUserMedia or Web Audio output. Stand-in bridge here; the real one is tested in the simulator (ios/scripts/build.sh --self-test-record).
- ✓Rec is shown in the app
- ✓A refused microphone says how to fix it
REC IMPORT DEMO MIDI 0 Microphone access is off for Field Sampler. UNDO - ✓Recording shows the time from native
{"on":true,"text":"0:01"} - ✓The recording is read in slices and saved as a take on the server
/t/timEYjpJtTZ1: audio/wav, 13.00 s (fixture 13.00 s), 10 capture.read calls - ✓The recording is sliced
12 hits - ✓Import uses the app's document picker and saves the file as a take
"Field import", audio/wav - ✓No WebKit capture, no web file input, no Web Audio output
getUserMedia 0, file input 0, AudioContext 0
25Inside the iPad app: takes in iCloud Drive7.1 s
With the take library (feature library), new takes go to the person's iCloud Drive through the bridge, never to the server; the menu lists them, then the older server takes, marked by where they live. Switching takes keeps each take whole here too. Sharing uploads that one take on demand and keeps its link current. Stand-in library here; the real one is tested in the simulator (ios/scripts/build.sh --self-test-library).
- ✓New takes go to the library, not the server
2 library takes with their analysis; 0 server creates; address / - ✓instrument.set names the library take (take.local; the demo went as PCM before it was saved)
{"id":null,"local":"B9C148A3-5423-47C1-BE44-42A9C3867D66","ref":"mv8r1buv-2","api":"http://localhost:8788","duration":8,"sampleRate":44100,"channels":2} - ✓The menu lists the iCloud takes, then the server takes
SHARE LINK Uploads this take so anyone with the link can play it. IN ICLOUD DRIVE demo 0:08 · Oct 14 × demo 0:08 · Oct 14 × ON THE SERVER (OLDER TAKES) Walkthrough take 0:10 · Oct 13 · view only × - ✓Library: an edit made just before switching is saved to its own take
renamed take "Library renamed", other "demo"; updates [["B9C1","Library renamed"]] - ✓Library: the opened take shows its own name
demo - ✓Library: an older server take still opens
http://localhost:8788/t/ZSfVYCOhW9N0 - ✓Library: back to the library take, off the server address
http://localhost:8788/ - ✓Sharing uploads the take and stores its link in the library
http://localhost:8788/t/tNdPFgYG64R9; 1 server create - ✓A shared take's edits reach its link
server name "Renamed after sharing" - ✓Deleting removes the take from the library
1 left
26Portrait2.1 s
Portrait works too (secondary): the same single screen, stacked.
- ✓Fits the screen: no scrolling, keys fully visible
overflow 0 px wide, 0 px tall; keys end 14 px above the bottom
27Console0.0 s
Errors the page logged during the whole walkthrough.
- ✓No page errors
none
About the demo take
13 s, stereo, 48 kHz, built by e2e/fixture.mjs. Room tone ~−50 dBFS with a +0.01 DC offset and 6 Hz rumble; a wind gust 4.5–5.4 s.
Hits: footstep 0.4 s · footstep 1 s · footstep 1.6 s · knock 2.3 s · knock 2.55 s · pluck 3.2 s (223.78 Hz) · quiet knock 5.8 s · glass 6.4 s (880.00 Hz) · bird chirp 7.6 s · keys 8.3 s · footstep 9.3 s · bell 10.3 s (440.00 Hz) · faint knock 12.1 s.
























