Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,19 @@ GitHub are its section here (`tools/release.sh` copies them), so add to
pitch when hit hard, cymbals bloom into a wash, and a closed hat chokes
an open one. Five presets. See docs/41.

- **Fretwire gets pickups, wiring and bodies.** The bass and guitar have
a second page. Choose the neck pickup, the bridge pickup, both, or both
out of phase. Pick single coil, P-90, humbucker or split coil, and set
how close the magnets sit. Real tone and volume pots roll the tone into
the mids and clean up an amp's drive. The strings now share a body,
SOLID, SEMI, HOLLOW or ACOUSTIC, that colors their decay and can be
miked (AIR). There is also an under-saddle piezo, and open strings that
ring in sympathy. New presets include twin-humbucker, p90-crunch,
semi-hollow, out-of-phase and acoustic guitars, and jazz-both, p-bass,
hollow and acoustic basses. Saved bass and guitar parts now sound
slightly different on the default solid body's dead spots; set COUPLE
to 0 for the old sound. See docs/41.

- **Separate STOP and PLAY.** Pressing STOP again while stopped returns
to the loop's start, or to the song's start with the loop off.

Expand Down
10 changes: 5 additions & 5 deletions bench/golden/bass.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# bench goldens for bass: case sha256(f32 L ++ f32 R) [nonharm_db thd_db]
notes 6937fb38af3c6ab2b3f575df95592cb75bfaa4e2ade23b32783fe0673f6625ec
velocity 8f5a032f4c439643181d79611e3c5100dc02797ac9f5d7031fa1a55fd966949d
held a4caf9e0aeeda62291a25bb51a33fef6a531452d7d77156581ca48d9b97aa09c -72.0 -1.0
high 84f46ca1cfca042bd39e28fcba891fa91d158445cb51123e6585f0aaba350f8e -72.8 -29.3
chord 4296a539b9dec08c355bfd665e1ec945bf353d3bdeff374fc2024f2f654fe8a4 2.5 6.5
notes 26c8fbcd88dbabbc9293e7517398a1f47c0541fcf173d9577be80527060133bc
velocity e60975486103d37400cd3dbccc162edc2d735a715ee420e854138f9311b9aff8
held 8125b1ff57d4f10926925f91d130a37e639735d320634c49e9465917fc07247e -72.2 -4.9
high 4b58d8ef0d9247e475265d5bd28b4d393fee6135ab007aab86bb60a33c0a7205 -73.0 -30.3
chord f0e284d9782fc34fdeaad0e3fecc6f463ca87c55a344069b7a6ed4d56fb5db52 2.8 5.4
10 changes: 5 additions & 5 deletions bench/golden/guitar.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# bench goldens for guitar: case sha256(f32 L ++ f32 R) [nonharm_db thd_db]
notes f27519fbf925fbf57bf4fd274367307371289a1fdf90937b267b14889ebcf57d
velocity 089cd20ccd61b8cddcbb6afefe6152e92a7a17da4f780ce44941e5443067fa0c
held aaac8b719a9606f6517274cd64d52951f0b01b0f3be3fda4a29eaec92efcf8eb -73.6 -3.3
high 8cadbe64df4d354ea25f585a7be87a4014bfc5e93a637802ac220d588d9ebe04 -73.0 -14.6
chord 8a259ffabb8aff4de7e3ee795a06933fd11fc4b31f8c588182e32ad9ba398807 2.2 0.8
notes 1e054305a36bbbda110a7127422c00e903ad5dfb591ddc043808769719bb3979
velocity 6180d5c8e7ed78bfb59c802bb6e54d58257caa61d8d6d36ee4d9dbb2666cce49
held 1a969eb89554e1597baf03dec5bfd3aa46b7da92fa843037a8840aae3d40f8aa -73.7 -3.8
high 281079ab8def8d9e675ae3021844ed1b4d4390f41aec4a11c2baedc35e78b80e -73.1 -14.9
chord 968bddfb42b804497d8ac22a62bed88de9514a0d2a842b82de239d0ec510d208 1.9 0.4
59 changes: 46 additions & 13 deletions docs/20-machine-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,22 @@ project or preset stores (docs/19): real units for knobs, the option
| `bs-soft` | PLUCK | SOFT | 0.05 … 6 | 2 | exp |
| `bs-shape` | PLUCK | SHAPE | 0 … 1 | 0 | linear |
| `bs-noise` | PLUCK | NOISE | 0 … 1 | 0.15 | pow |
| `bs-pickup` | PICKUP | POS | 0.04 … 0.5 | 0.2 | linear |
| `bs-hand` | PICKUP | HAND | 0 … 12 | 5 | linear |
| `bs-tone` | PICKUP | TONE | 300 … 12000 | 3200 | exp |
| `bs-res` | PICKUP | RES | 0 … 1 | 0.3 | linear |
| `bs-hand` | PLUCK | HAND | 0 … 12 | 5 | linear |
| `bs-pickup` | PICKUPS | NECK | 0.04 … 0.5 | 0.2 | linear |
| `bs-pickup-b` | PICKUPS | BRIDGE | 0.04 … 0.5 | 0.1 | linear |
| `bs-sel` | PICKUPS | SELECT | 0 NECK / 1 BOTH / 2 BRIDGE / 3 OUT | 0 | switch |
| `bs-type-n` | PICKUPS | N TYPE | 0 SINGLE / 1 SPLIT / 2 HUMBUCK | 0 | switch |
| `bs-type-b` | PICKUPS | B TYPE | 0 SINGLE / 1 SPLIT / 2 HUMBUCK | 0 | switch |
| `bs-height` | PICKUPS | HEIGHT | 0 … 1 | 0 | linear |
| `bs-tone` | WIRING | RESO | 300 … 12000 | 3200 | exp |
| `bs-res` | WIRING | PEAK | 0 … 1 | 0.3 | linear |
| `bs-tpot` | WIRING | TONE | 0 … 1 | 1 | linear |
| `bs-vol` | WIRING | VOL | 0 … 1 | 1 | linear |
| `bs-body` | BODY | BODY | 0 SOLID / 1 HOLLOW / 2 ACOUSTIC | 0 | switch |
| `bs-couple` | BODY | COUPLE | 0 … 2 | 1 | linear |
| `bs-air` | BODY | AIR | 0 … 1 | 0 | pow |
| `bs-piezo` | BODY | PIEZO | 0 … 1 | 0 | pow |
| `bs-symp` | BODY | SYMP | 0 … 1 | 0 | linear |
| `bs-thump` | FEEL | THUMP | 0 … 1 | 0.5 | linear |
| `bs-buzz` | FEEL | BUZZ | 0 … 1 | 0 | linear |
| `bs-motion` | FEEL | MOTION | 0 AUTO / 1 BEND / 2 SLIDE | 0 | switch |
Expand All @@ -74,13 +86,17 @@ project or preset stores (docs/19): real units for knobs, the option

Presets:

- `acoustic` — An acoustic bass guitar, miked, with some piezo and the open strings in sympathy
- `default` — Fingers on the neck pickup: roundwounds, direct
- `fingers-bridge` — Fingers over the bridge pickup: nasal, growly, more mids
- `flatwound` — Old flatwounds, tone rolled off: short, thumpy, dub and Motown
- `hollow` — A hollow violin bass on flatwounds: short, woody, a little air
- `jazz-both` — Both single coils of a Jazz-type bass, fingers: fitted to Karoryfer's Growlybass
- `p-bass` — A split-coil P-type pickup, roundwounds, tone a little back: the punchy middle of a mix
- `palm-mute` — Muted with the palm: a short pick thud
- `pick` — Played with a pick near the bridge: bright attack, click, rounder sustain
- `pop` — Popped string: pulled and snapped, hard push, buzz
- `slap` — Thumb slap over the end of the neck: narrow strike, fret rattle, bright
- `pop` — Popped string over a bridge humbucker: pulled and snapped, hard push, buzz
- `slap` — Thumb slap over the end of the neck, a bridge humbucker: narrow strike, fret rattle, bright

## concoction

Expand Down Expand Up @@ -671,10 +687,22 @@ Presets:
| `gt-soft` | PLUCK | SOFT | 0.05 … 6 | 1 | exp |
| `gt-shape` | PLUCK | SHAPE | 0 … 1 | 0.4 | linear |
| `gt-noise` | PLUCK | NOISE | 0 … 1 | 0.15 | pow |
| `gt-pickup` | PICKUP | POS | 0.04 … 0.5 | 0.24 | linear |
| `gt-hand` | PICKUP | HAND | 0 … 12 | 0 | linear |
| `gt-tone` | PICKUP | TONE | 300 … 12000 | 4500 | exp |
| `gt-res` | PICKUP | RES | 0 … 1 | 0.4 | linear |
| `gt-hand` | PLUCK | HAND | 0 … 12 | 0 | linear |
| `gt-pickup` | PICKUPS | NECK | 0.04 … 0.5 | 0.24 | linear |
| `gt-pickup-b` | PICKUPS | BRIDGE | 0.04 … 0.5 | 0.07 | linear |
| `gt-sel` | PICKUPS | SELECT | 0 NECK / 1 BOTH / 2 BRIDGE / 3 OUT | 0 | switch |
| `gt-type-n` | PICKUPS | N TYPE | 0 SINGLE / 1 P-90 / 2 HUMBUCK | 0 | switch |
| `gt-type-b` | PICKUPS | B TYPE | 0 SINGLE / 1 P-90 / 2 HUMBUCK | 0 | switch |
| `gt-height` | PICKUPS | HEIGHT | 0 … 1 | 0 | linear |
| `gt-tone` | WIRING | RESO | 300 … 12000 | 4500 | exp |
| `gt-res` | WIRING | PEAK | 0 … 1 | 0.4 | linear |
| `gt-tpot` | WIRING | TONE | 0 … 1 | 1 | linear |
| `gt-vol` | WIRING | VOL | 0 … 1 | 1 | linear |
| `gt-body` | BODY | BODY | 0 SOLID / 1 SEMI / 2 HOLLOW / 3 ACOUSTIC | 0 | switch |
| `gt-couple` | BODY | COUPLE | 0 … 2 | 1 | linear |
| `gt-air` | BODY | AIR | 0 … 1 | 0 | pow |
| `gt-piezo` | BODY | PIEZO | 0 … 1 | 0 | pow |
| `gt-symp` | BODY | SYMP | 0 … 1 | 0 | linear |
| `gt-thump` | FEEL | THUMP | 0 … 1 | 0.3 | linear |
| `gt-buzz` | FEEL | BUZZ | 0 … 1 | 0 | linear |
| `gt-motion` | FEEL | MOTION | 0 AUTO / 1 BEND / 2 SLIDE | 0 | switch |
Expand All @@ -685,13 +713,18 @@ Presets:

Presets:

- `acoustic` — A flat-top acoustic, miked, with a little under-saddle piezo and the open strings ringing along
- `bridge` — Picked on the bridge pickup: thin, bright, cutting; for crunch and leads into an amp
- `default` — Picked, neck pickup, open position: the clean electric
- `fingers` — Fingerstyle, thumb and fingers over the neck: round and soft
- `funk` — Bright, tight, short: bridge-and-middle funk chops
- `jazz` — Archtop jazz: neck pickup, tone rolled off, flatwound thump
- `palm-mute` — Palm-muted picking: a short chug, give it a high-gain amp
- `funk` — Middle and bridge single coils together: the bright, quacky funk chop
- `jazz` — Archtop jazz: a hollow body, the neck humbucker, tone rolled back, a little air
- `out-of-phase` — Neck and middle out of phase: the thin, hollow, nasal tone
- `p90-crunch` — A bridge P-90 set close to the strings: fat, raw mids that break up early in an amp
- `palm-mute` — Palm-muted picking on a bridge humbucker: a short, tight chug for a high-gain amp
- `semi-hollow` — A semi-hollow with two humbuckers: warm, woody, a touch of sympathetic ring
- `slide` — Bottleneck slide: long sustain, pitch curves glide fret by fret with the rasp
- `twin-humbucker` — Two humbuckers together, picked near the bridge, direct: fitted to Karoryfer's Emily

## jp8

Expand Down
7 changes: 7 additions & 0 deletions docs/21-production-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,13 @@ Leave pads alone; they're already even.
or `bass-grind`. Guitars: `guitar-clean`, `guitar-crunch`,
`guitar-lead`, `guitar-heavy`. Leave CAB on unless another cabinet
follows, and use BLEND, not a parallel track, to keep the DI's low end.
- **Pick the instrument before the amp.** Fretwire's GUITAR or BASS page
is the instrument: pickups (SELECT, TYPE, HEIGHT), wiring (TONE and VOL
pots) and BODY (docs/41). Start from a preset: `twin-humbucker` or
`p90-crunch` for a driven amp, `funk` for chops, `jazz` or
`semi-hollow` for warm clean parts; on bass, `jazz-both`, `p-bass` or
`hollow`. Roll VOL back to clean up an amp's drive. The `acoustic`
presets are miked bodies with a little piezo: skip Ampstack for them.
- `chorus2`: `juno-i` / `juno-ii` for pads and keys. Never on bass or
kick; it smears the low end out of mono.
- **Share spaces with sends.** Put a fully wet reverb on a bus and send
Expand Down
137 changes: 131 additions & 6 deletions docs/41-physical-models.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# 41 — Physical models: Hammerwork Grand and Skinwork Kit
# 41 — Physical models: Hammerwork Grand, Skinwork Kit, Fretwire bodies

Two machines synthesize their sound by simulating the instrument's
mechanics, sample by sample:
Expand All @@ -8,6 +8,10 @@ mechanics, sample by sample:
- `kit` (**Skinwork Kit**) is a drum kit: sticks and beaters strike
membranes and cymbals.

Fretwire's bass and guitar (`bass`, `guitar`) build the instrument around
their waveguide strings the same way: pickups, wiring and a body every
string shares (§Fretwire: pickups, wiring and bodies).

They share a small layer of physical-modeling kernels,
`kernels/10-physical/`. **Status:** built 2026-10-16 on branch
`claude/physical-piano-drums`.
Expand All @@ -25,6 +29,9 @@ Code:
modes, generated by `tools/fit/bessel.py`.
- `kernels/06-voices/piano.fy` and `machines/grand/`: the piano.
- `kernels/06-voices/kit.fy` and `machines/kit/`: the kit.
- `kernels/06-voices/string.fy` (the strings and pickups),
`kernels/06-voices/string_body.fy` (bridge, body, wiring, open strings)
and `machines/bass/`, `machines/guitar/`: Fretwire.

## The building blocks (`kernels/10-physical`)

Expand Down Expand Up @@ -151,19 +158,137 @@ The lower note of each tom pair, and the second kick, sit a little lower
**Cost:** about 530 ns per sample in Debug for the bench hit sequence.
The render word, like the piano's, renders without NEON lanes.

## Fretwire: pickups, wiring and bodies

**Status:** built 2026-10-16 on branch `claude/fretwire-bodies`, stacked
on `claude/physical-piano-drums` (it needs shared state, docs/04).

Fretwire's strings were already waveguides fitted to recordings. What
they lacked was the instrument: one pickup point and a resonant lowpass
stood for every electric, and nothing joined the strings. Each machine
now has a second page (GUITAR or BASS) with three sections, and every
string drives one shared body through the bridge. The shared word
(`fw-body-render`, period 1) runs after the strings each sample.

### Pickups

Two pickups, NECK and BRIDGE, each at its own point along the string
(a fraction of the open string, from the bridge). A coil hears the string
where it sits, so its comb notches move string to string and up the neck,
as on the instrument. SELECT picks NECK, BOTH, BRIDGE, or OUT (both, the
bridge coil reversed). Two coils in parallel share the output by
inductance, each heard in the proportion of the other's.

| TYPE | Taps | Inductance | Sounds |
|---|---|---|---|
| SINGLE | one point | 1x | the bright, glassy single coil |
| P-90 (guitar) | a wide bobbin's edges, 0.036 of the string apart | 1.8x | fatter, rawer mids |
| HUMBUCK | two coils 18 mm apart | 1.8x | warmer: the two coils' views cancel near an open string's 36th harmonic (3 dB down at the 18th), and the resonance drops to 0.75x |
| SPLIT (bass) | one point, the low strings' half 1.2% further toward the neck | 1.4x | a P-type bass |

HEIGHT moves the magnets toward the strings. The coil's output is the
string's velocity times 1 / [1 - k x]^2, x the string's displacement over
it [Horton and Moore 2009]. A string swinging toward the magnet sees more
flux than swinging away, so loud notes gain even harmonics and some
level.

### Wiring

The coils drive the cable's capacitance, the pots and the amp's input:

H(s) = 1 / (1 + (R + sL) (sC + G + sCt / (1 + s Rt Ct)))

- **RESO** and **PEAK** (the old TONE and RES, same ids) are a single
coil's loaded resonance with the tone pot open. C and G are solved from
them for the selected coils' L and R, so a humbucker or two coils in
parallel move the resonance by the square root of their inductance.
- **TONE** is the tone pot: down from 1 its resistance (250 k, audio
taper) brings in the tone capacitor (22 nF guitar, 47 nF bass). At 0
the resonance drops to around 700 Hz: the "woman tone". At 1 the
branch is open, the filter is the old 2-pole one, and the output nulls
against the old Fretwire's at the 24-bit floor (COUPLE 0).
- **VOL** is the volume pot: an audio taper, plus the treble its wiper
resistance loses into the cable. Turning it down cleans up Ampstack's
drive the way a guitarist does.

The 3rd-order H goes to z by the bilinear transform, prewarped at the
resonance, once a block.

### Body

Every string pushes on the bridge with the wave arriving there and moves
with the bridge's velocity [Gough 1981; Woodhouse 2004]. The bridge is
the body's modes: 8 low modes per body (the air cavity, the first top and
back modes), then 40 dense modes spread evenly to a few kHz with
overlapping bandwidths. A mode takes energy from string partials near it,
so notes there decay faster and swell into the body: dead spots on a
solid body, the wood of a hollow one. The 12-mode board taught us the
dense part matters: a dozen peaks alone sound boxy and honky.

| BODY | Coupling | Character |
|---|---|---|
| SOLID | weak, high Q | neck and body dead spots; almost no air |
| SEMI (guitar) | a centre block | some wood, sustain kept |
| HOLLOW | an archtop, or a violin bass | woody, shorter, an air resonance near 110 Hz (bass 88) |
| ACOUSTIC | a flat-top, or an acoustic bass guitar | strong: 98 Hz air, 196 Hz top (bass 72 / 128) |

The low modes follow published guitar mobility and radiation
measurements in shape, not any one instrument (our own estimates).

- **COUPLE** scales the bridge coupling. 0 is a rigid bridge, the old
Fretwire.
- **AIR** mixes in the body's radiated sound: its modes' acceleration
and, above them, the bridge force as a resistance. At 1 on an acoustic
body it sits at the pickups' level. A solid body radiates about 40 dB
less, as an unplugged electric does.
- **PIEZO** mixes an under-saddle piezo: the bridge force itself, bright
and direct.
- **SYMP** rings the open strings in sympathy. Each open string is a
delay loop in the shared region, driven by the bridge and pushing back
on it. A string a note is played on is muted. The strings are heard
through the pickups and the body.

### Fitted against recordings

`tools/fit/string_fit.py` measures the attack spectrum (harmonics 1-16,
20-80 ms) and each harmonic's T60. A coordinate-descent fit over the
pickup, pluck, wiring and decay knobs, scored on both, set two presets:

| Preset | Reference | Error per harmonic, start → fit |
|---|---|---|
| `guitar` twin-humbucker | Karoryfer Emily, C3, both humbuckers, direct | 11.0 → 7.5 dB |
| `bass` jazz-both | Karoryfer Growlybass, C2 (their c3), both pickups, direct | 12.8 → 7.8 dB |

What still differs: the guitar reference's spectrum falls smoothly where
ours keeps the pluck's and pickups' comb notches. The bass reference
shows them (its 5th harmonic is 30 dB down), so they are real. But a pick
and two pickups fill them in more than the model does.

### Cost

The shared body makes the strings render in lockstep, one voice at a
time. In ReleaseFast the guitar's chord case went from 176 to 480 ns per
sample (2.3% of a core). SYMP adds about 100 ns while it is up.

## Presets

- `grand`: default, bright-pop, felt-ballad, honky-tonk, sustain-wash,
dry-studio.
- `kit`: default, jazz, rock, funk-dry, gong-wash.
- `guitar` (new or reworked here): twin-humbucker, p90-crunch,
semi-hollow, out-of-phase, acoustic; jazz is now a hollow archtop on
the neck humbucker, funk the middle and bridge single coils together.
- `bass`: jazz-both, p-bass, hollow, acoustic; pop and slap are on a
bridge humbucker.

## Next

- **Fretwire and Rhodes.** Fretwire could take `contact-solve` for the
pluck and fret buzz, and moving-bridge coupling for its two-stage decay.
Rhodes could become a struck tine-and-tonebar mode pair with an
implicit hammer.
pluck and fret buzz. Its moving bridge and sympathetic strings are
built (§Fretwire). Rhodes could become a struck tine-and-tonebar mode
pair with an implicit hammer.
- **Lane mode.** Splitting the render into a lane-eligible word, or
raising the stash limit, would roughly halve the cost.
- **Sympathetic strings.** These need a shared board across voices: a
host-side bus or a single-voice piano.
- **Sympathetic strings in the Grand.** Fretwire's open strings show the
way: a shared region holding the undamped strings, driven by the
bridge.
Loading
Loading