@hraness/dawg 0.6.0 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/DAWG.md +338 -51
  3. package/README.md +4 -4
  4. package/core/chords.ts +492 -4
  5. package/core/diff.ts +5 -0
  6. package/core/expression.ts +143 -6
  7. package/core/fx.ts +258 -6
  8. package/core/granular.ts +91 -0
  9. package/core/instruments.ts +161 -0
  10. package/core/keys.ts +573 -4
  11. package/core/resonators.ts +291 -3
  12. package/core/score.ts +349 -3
  13. package/core/sdk/print.ts +78 -3
  14. package/core/sdk/v1.ts +1320 -36
  15. package/core/sections.ts +12 -4
  16. package/core/strings.ts +237 -2
  17. package/core/winds.ts +652 -0
  18. package/guides/automation.md +1 -0
  19. package/guides/chords.md +3 -1
  20. package/guides/effects.md +3 -2
  21. package/guides/media.md +1 -1
  22. package/guides/performance.md +3 -0
  23. package/guides/resample.md +26 -0
  24. package/guides/sounds.md +7 -6
  25. package/package.json +1 -1
  26. package/src/agent/agent.ts +8 -2
  27. package/src/agent/chord-tools.ts +153 -1
  28. package/src/agent/expression-tools.ts +91 -0
  29. package/src/agent/ops.ts +4 -1
  30. package/src/agent/preview-tool.ts +2 -1
  31. package/src/agent/resample-tool.ts +131 -0
  32. package/src/agent/tools.ts +200 -15
  33. package/src/agent/xcb-agent.ts +8 -2
  34. package/src/audio/arrange.ts +21 -0
  35. package/src/audio/dsp/envelope.ts +161 -0
  36. package/src/audio/dsp/shift.ts +256 -0
  37. package/src/audio/effects/chain.ts +18 -3
  38. package/src/audio/effects/common.ts +14 -0
  39. package/src/audio/effects/convolution.ts +106 -1
  40. package/src/audio/effects/gaze.ts +354 -0
  41. package/src/audio/engine.ts +46 -5
  42. package/src/audio/fit.ts +45 -0
  43. package/src/audio/granular.ts +352 -21
  44. package/src/audio/instrument-check.ts +9 -5
  45. package/src/audio/instruments.ts +32 -3
  46. package/src/audio/keys/electric.ts +420 -0
  47. package/src/audio/keys/engine.ts +143 -19
  48. package/src/audio/keys/organ.ts +1335 -0
  49. package/src/audio/keys/piano.ts +50 -6
  50. package/src/audio/keys/sympathetic.ts +127 -0
  51. package/src/audio/live-worker.ts +3 -1
  52. package/src/audio/live.ts +136 -9
  53. package/src/audio/preview.ts +15 -1
  54. package/src/audio/resample.ts +285 -0
  55. package/src/audio/resonators.ts +10 -2
  56. package/src/audio/sampler.ts +168 -21
  57. package/src/audio/samples.ts +26 -1
  58. package/src/audio/strings/body.ts +29 -16
  59. package/src/audio/strings/bow.ts +656 -0
  60. package/src/audio/strings/engine.ts +266 -20
  61. package/src/audio/strings/measure.test-helpers.ts +2 -0
  62. package/src/audio/wav.ts +119 -19
  63. package/src/audio/winds/engine.ts +302 -0
  64. package/src/audio/winds/filters.ts +153 -0
  65. package/src/audio/winds/pitch.ts +104 -0
  66. package/src/audio/winds/trim.ts +80 -0
  67. package/src/audio/winds/trims.ts +917 -0
  68. package/src/audio/winds/voice.ts +479 -0
  69. package/src/commands/expression.ts +103 -22
  70. package/src/commands/fx.ts +4 -1
  71. package/src/commands/granular.ts +7 -2
  72. package/src/commands/help.ts +91 -8
  73. package/src/commands/keys.ts +287 -11
  74. package/src/commands/modal.ts +67 -4
  75. package/src/commands/resample.ts +281 -0
  76. package/src/commands/rig.ts +5 -1
  77. package/src/commands/sample.ts +49 -2
  78. package/src/commands/shift.ts +119 -0
  79. package/src/commands/string.ts +28 -2
  80. package/src/commands/strum.ts +473 -0
  81. package/src/commands/wind.ts +244 -0
  82. package/src/main.ts +129 -7
  83. package/src/project/check.ts +5 -1
  84. package/src/render.ts +16 -0
  85. package/src/session/presence.ts +16 -3
  86. package/src/tui/audition.ts +1 -1
  87. package/src/tui/menu.ts +637 -35
  88. package/src/tui/modal-menu.ts +34 -7
  89. package/src/tui/performance-menu.ts +42 -0
  90. package/src/tui/play-chords.ts +104 -3
  91. package/src/tui/play-mode.ts +1 -0
  92. package/src/tui/play-session.ts +34 -9
  93. package/src/tui/wind-menu.ts +144 -0
package/DAWG.md CHANGED
@@ -332,7 +332,7 @@ Parameters (**bold** effect = shown in the simple menu; Lane = automation lane):
332
332
  | reverb | lowpass (optional) | 200..20000 Hz | 8000 | `roomlp`, `rlp` | |
333
333
  | reverb | dim (optional) | 200..20000 Hz | 3000 | `roomdim`, `rdim` | |
334
334
  | reverb | predelay (optional) | 0..0.5 s | 0.02 | | |
335
- | reverb | ir (optional) | `builtin:room\|hall\|plate`, pack sound or project WAV | off | `iresponse`, `ir` | |
335
+ | reverb | ir (optional) | `builtin:room\|hall\|plate\|reverse\|gate\|spring`, pack sound or project WAV | off | `iresponse`, `ir` | |
336
336
  | orbit | orbit | 1..16 (integer) | 2 | `orbit`, `o` | |
337
337
  | orbit | shared (optional) | on/off | off | | |
338
338
  | duck | orbit | 1..16 (integer) | 1 | `duckorbit`, `duck` | |
@@ -385,6 +385,43 @@ Rig presets (`RIG_PRESETS` in `core/fx.ts`): `clean crunch punk ragged lead meta
385
385
  | **cab** | mic | 0..1 | 0.3 | |
386
386
  | **cab** | mix | 0..1 | 1 | |
387
387
 
388
+ ### Shoegaze (wobble, bloom, swell, double) (0.6.1)
389
+
390
+ Four effects that sit after `cab` and before `tremolo` (`double` runs after `pan`, because it makes the stereo image), in `src/audio/effects/gaze.ts`. They run once per track, never per voice, and use seeded randomness only, so every render is identical.
391
+
392
+ ```text
393
+ fx wobble held tremolo arm: seeded pitch wow and flutter (depth 20 c)
394
+ fx wobble depth 35 rate 0.4 drift 0.5
395
+ fx bloom feedback: the top held note grows a singing harmonic
396
+ fx swell time 0.5 volume swell: each strum fades in, no pick attack
397
+ fx double a second, seeded take a few ms late, spread left and right
398
+ rig shoegaze fuzz + chime head + wobble + bloom + double + a big reverb
399
+ fx reverb ir builtin:reverse reverse-gate swell after the attack, not a pre-verb (also builtin:gate and builtin:spring)
400
+ track shoegaze a new electric guitar track with the shoegaze rig
401
+ ```
402
+
403
+ - **wobble** (`depth` 0..100 cents, `rate` Hz, `drift` 0 periodic .. 1 wandering) is a modulated fractional delay read with a 4-point interpolator, like a held vibrato arm or tape wow. Its peak deviation equals `depth` (a sustained A3 at depth 35 swings ±35 c). `depth` is automatable.
404
+ - **bloom** (`amount`, `harm` 1..4, `delay` s, `time` s) finds the highest held note at each moment (EffectContext.notes) and grows a phase-continuous partial at its `harm`-th harmonic after the note has been held `delay` seconds, the way an amp in feedback picks one note. Each note's partial is seeded by the note id, so it is stable when other notes change.
405
+ - **swell** (`time` s, `mix`) restarts a raised-cosine fade at each note onset: a volume-pedal swell without the pick.
406
+ - **double** (`time` 5..60 ms, `drift` ms, `width`) is automatic double tracking: a second take through a modulated delay whose timing wanders by `drift`, panned against the dry take. Left/right correlation stays between 0.3 and 0.8.
407
+
408
+ Rig presets gain `shoegaze glide dreampop swell ebow` (the `swell` rig is the swell effect plus a clean amp and a room; `ebow` is swell plus a bloom on the note itself). `jangle` now also writes a light `double`; a project that loaded jangle before 0.6.1 keeps its stored stages and renders unchanged until `rig jangle` is applied again. In `song.ts`, `rig("jangle")` and `instrument: "jangle"` keep the 0.6.0 stages (no double) so existing files render unchanged; add `double: {}` for the 0.6.1 sound. `instrument: "shoegaze"`, `"dreampop"` and `"ebow"` (the rig names that are also instrument words; `glide` and `swell` are reached with `rig glide`/`rig swell` or `fx: rig("glide")`) also set the rig's reverb wash, like `track shoegaze`; `rig()` returns effects only, so pair it with `reverb: rigReverb("shoegaze")`. The rigs carry a `postgain` trim so the shoegaze rigs land within 2.5 dB of `clean` on a held chord, and `shoegaze`, `glide` and `dreampop` also on a dense strum. `swell` and `ebow` restart their fade on every onset, so a fast strum through them sits several dB lower; they are made for held notes and slow chords. The built-in impulses `reverse` (energy rising to a hard stop: a reverse-gate swell that rises after each attack, not a pre-verb that swells into the note; no rig preset uses it, so reach it with `fx reverb ir builtin:reverse`), `gate` (a dense, flat 250 ms burst cut short) and `spring` (a dispersive, chirping tank) are generated from seeded noise like `room hall plate`; no recorded IR ships. Menu: **Effects › Shoegaze** and the rig preset row in **Effects › Guitar rig**. Agent: `set_fx` and `set_rig`. SDK: `fx: { ...rig("shoegaze") }` or `fx: { wobble: { depth: 30 } }`. A full shoegaze rig costs under 25 ms per track-second.
409
+
410
+ | Effect | Param | Range | Default | Lane |
411
+ | ---------- | ------ | ------------ | ------- | -------------- |
412
+ | **wobble** | depth | 0..100 cents | 20 | `wobble-depth` |
413
+ | **wobble** | rate | 0.05..8 Hz | 0.5 | |
414
+ | **wobble** | drift | 0..1 | 0.3 | |
415
+ | **bloom** | amount | 0..1 | 0.5 | |
416
+ | **bloom** | harm | 1..4 | 2 | |
417
+ | **bloom** | delay | 0..4 s | 0.6 | |
418
+ | bloom | time | 0.05..4 s | 1 | |
419
+ | **swell** | time | 0.01..4 s | 0.4 | |
420
+ | **swell** | mix | 0..1 | 1 | `swell-mix` |
421
+ | **double** | time | 5..60 ms | 22 | |
422
+ | **double** | drift | 0..10 ms | 3 | |
423
+ | **double** | width | 0..1 | 0.6 | |
424
+
388
425
  ## Master and loudness
389
426
 
390
427
  The song master is an optional chain after every track, orbit bus and duck are summed: **EQ** (low shelf, two bells, high shelf) → **glue** (stereo-linked bus compressor with soft knee, parallel mix and a sidechain high-pass) → **tape** (saturation with bias and a tone roll-off) → **width** (mid/side, mono below a cutoff) → **limiter** (true-peak brickwall with lookahead). A song with no master renders byte-identically to 0.4; an absent unit is skipped and a 0 dB EQ band is skipped.
@@ -441,7 +478,7 @@ Parameters (**bold** unit = shown in the simple menu; the rest are under `advanc
441
478
 
442
479
  <!-- master-params:end -->
443
480
 
444
- A song with a master renders at 48 kHz; a song without one keeps the engine's 22,050 Hz, as dawg 0.4 wrote it, so older projects export byte-identically. `--rate 48000` (or 44100) picks the rate for any render. `dawg render out.wav --normalize streaming` (or a LUFS number) applies a target for that export only, without changing the song; `--measure` prints the loudness line after any render. While the loop plays, the header shows `-14.1 LUFS (-14) · TP -1.0` for the last rendered loop, with or without a master, so you can read a mix before mastering it. The bracket is the target, and the reading turns to a warning colour when it is more than 0.5 LU off the target or the true peak passes the limiter's ceiling (-1 dBTP without one). With a master the loop monitors at the engine's 22,050 Hz while exports and `master measure` run at 48 kHz; the header shows the 48 kHz reading once it is measured in the background (a `~` marks the monitor estimate until then). EQ above about 9.9 kHz is not audible while monitoring but is in the export. The menu has it under **Mix & automation › master** (`/menu master`), where `Space` stages master changes for A/B like other sound edits. The agent has `set_master` and `measure_mix` (integrated, short-term and momentary LUFS, loudness range, true peak, spectral balance in five bands (sub, bass, low-mid, high-mid, high) and stereo correlation, with `bypass_master` to compare); it masters only when asked and measures before and after. In the SDK: `song({ master: { glue: { ratio: 2 }, limiter: { ceiling: -1 }, target: -14 } })` (SDK 1.17.0).
481
+ A song with a master renders at 48 kHz; a song without one keeps the engine's 22,050 Hz, as dawg 0.4 wrote it, so older projects export byte-identically. `--rate 48000` (or 44100) picks the rate for any render. `dawg render out.wav --normalize streaming` (or a LUFS number) applies a target for that export only, without changing the song; `--measure` prints the loudness line after any render. When samples hit 16-bit full scale, `dawg render` prints a `warning · N samples clip` line on stderr with the fix (lower volumes, or a master with a limiter). While the loop plays, the header shows `-14.1 LUFS (-14) · TP -1.0` for the last rendered loop, with or without a master, so you can read a mix before mastering it. The bracket is the target, and the reading turns to a warning colour when it is more than 0.5 LU off the target or the true peak passes the limiter's ceiling (-1 dBTP without one). With a master the loop monitors at the engine's 22,050 Hz while exports and `master measure` run at 48 kHz; the header shows the 48 kHz reading once it is measured in the background (a `~` marks the monitor estimate until then). EQ above about 9.9 kHz is not audible while monitoring but is in the export. The menu has it under **Mix & automation › master** (`/menu master`), where `Space` stages master changes for A/B like other sound edits. The agent has `set_master` and `measure_mix` (integrated, short-term and momentary LUFS, loudness range, true peak, spectral balance in five bands (sub, bass, low-mid, high-mid, high) and stereo correlation, with `bypass_master` to compare); it masters only when asked and measures before and after. In the SDK: `song({ master: { glue: { ratio: 2 }, limiter: { ceiling: -1 }, target: -14 } })` (SDK 1.17.0).
445
482
 
446
483
  ## Synth
447
484
 
@@ -550,37 +587,37 @@ FM operators 2–8 repeat the `fm` rows with a suffix (`fm2`, `fmh2`, `fmattack2
550
587
 
551
588
  ### Strudel parity
552
589
 
553
- | Strudel | dawg | Status |
554
- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------- | ---------------------------------------------------- |
555
- | `s`/`sound` sine, sawtooth, square, triangle, supersaw, pulse, user, white, pink, brown, crackle | `instrument` | done |
556
- | `noise`, `density` | `synth.noise`, `synth.density` | done |
557
- | `unison`, `spread`, `detune` | `synth.*` | done |
558
- | `pw`, `pwrate`, `pwsweep` | `synth.*` | done |
559
- | `fm`/`fmi`, `fmh`, `fmattack/fmdecay/fmsustain/fmrelease`, `fmenv`, `fmwave`, operators 2–8 | `synth.*` | done |
560
- | `attack/decay/sustain/release`, `adsr`, `gain`, `velocity` | `synth.*`; `adsr` is command shorthand; velocity is the note's | done |
561
- | `penv`, `pattack/pdecay/psustain/prelease`, `pcurve`, `panchor` | `synth.*` | done |
562
- | `vib`/`vibrato`, `vibmod` | `synth.*` | done |
563
- | `lpf/hpf/bpf`, `lpq/hpq/bpq`, `lpenv/hpenv/bpenv` and their ADSRs, `ftype`, `fanchor` | `synth.*` (per voice); also the track `filter` effect | done |
564
- | `partials`, `phases` | `synth.partials`, `synth.phases` | done |
565
- | `vowel`, `coarse`, `crush`, `shape`, `distort`, `djf` | effects `vowel`, `crush`, `distort`, `djf` | done (see Effects) |
566
- | `phaser*`, `tremolo*`, `leslie`/`lrate`/`lsize`, `compressor*`, `postgain` | effects of the same names | done |
567
- | `room`, `size`, `roomfade`, `roomlp`, `roomdim` | `reverb` | done |
568
- | `delay`, `delaytime`, `delayfeedback` | `delay` | done |
569
- | `pan` | track `pan` | done |
570
- | `orbit`, `duckorbit`/`duckdepth`/`duckattack`/`duckonset` | effects `orbit` (+ `shared`), `duck` | done: `shared` sends to one delay + reverb per orbit |
571
- | `iresponse`/`ir` | `reverb.ir` | done: FFT convolution; built-ins or a pinned sample |
572
- | `z_sine`…`z_noise`; `zrand`, `curve`, `slide`, `deltaSlide`, `pitchJump`, `pitchJumpTime`, `lfo`, `noise`, `zmod`, `zcrush`, `zdelay`, `tremolo` | ZzFX sounds, `synth.*` | done (clean-room; units documented above) |
573
- | zzfx `duration` | note length | done: a note's length is its duration |
574
- | raw `zzfx([...])` parameter array | `synth zzfx …`, SDK `zzfx([...])`, `set_synth {zzfx}` | done: ZzFX's documented layout → named controls |
575
- | soundfonts `gm_*`, drum banks, dirt-samples | sampler and sample packs | not this engine: hosted samples, see Sample packs |
576
- | sample controls `begin`, `end`, `speed`, `unit`, `loop`, `loopBegin`/`loopb`, `loopEnd`/`loope`, `clip`/`legato`, `fit`, `loopAt`, `accelerate`, `squiz`, `cut`, `gain` | sampler voice fields; `/sample set`, `set_sample` | done (see Samples) |
577
- | fitting to tempo (Ableton Repitch/Beats/Tones; Strudel `fit`) | `bpm` `fitmode` `len`; `/fitmode`, `fit_sample` | done (see Fitting samples) |
590
+ | Strudel | dawg | Status |
591
+ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------- | ---------------------------------------------------- |
592
+ | `s`/`sound` sine, sawtooth, square, triangle, supersaw, pulse, user, white, pink, brown, crackle | `instrument` | done |
593
+ | `noise`, `density` | `synth.noise`, `synth.density` | done |
594
+ | `unison`, `spread`, `detune` | `synth.*` | done |
595
+ | `pw`, `pwrate`, `pwsweep` | `synth.*` | done |
596
+ | `fm`/`fmi`, `fmh`, `fmattack/fmdecay/fmsustain/fmrelease`, `fmenv`, `fmwave`, operators 2–8 | `synth.*` | done |
597
+ | `attack/decay/sustain/release`, `adsr`, `gain`, `velocity` | `synth.*`; `adsr` is command shorthand; velocity is the note's | done |
598
+ | `penv`, `pattack/pdecay/psustain/prelease`, `pcurve`, `panchor` | `synth.*` | done |
599
+ | `vib`/`vibrato`, `vibmod` | `synth.*` | done |
600
+ | `lpf/hpf/bpf`, `lpq/hpq/bpq`, `lpenv/hpenv/bpenv` and their ADSRs, `ftype`, `fanchor` | `synth.*` (per voice); also the track `filter` effect | done |
601
+ | `partials`, `phases` | `synth.partials`, `synth.phases` | done |
602
+ | `vowel`, `coarse`, `crush`, `shape`, `distort`, `djf` | effects `vowel`, `crush`, `distort`, `djf` | done (see Effects) |
603
+ | `phaser*`, `tremolo*`, `leslie`/`lrate`/`lsize`, `compressor*`, `postgain` | effects of the same names | done |
604
+ | `room`, `size`, `roomfade`, `roomlp`, `roomdim` | `reverb` | done |
605
+ | `delay`, `delaytime`, `delayfeedback` | `delay` | done |
606
+ | `pan` | track `pan` | done |
607
+ | `orbit`, `duckorbit`/`duckdepth`/`duckattack`/`duckonset` | effects `orbit` (+ `shared`), `duck` | done: `shared` sends to one delay + reverb per orbit |
608
+ | `iresponse`/`ir` | `reverb.ir` | done: FFT convolution; built-ins or a pinned sample |
609
+ | `z_sine`…`z_noise`; `zrand`, `curve`, `slide`, `deltaSlide`, `pitchJump`, `pitchJumpTime`, `lfo`, `noise`, `zmod`, `zcrush`, `zdelay`, `tremolo` | ZzFX sounds, `synth.*` | done (clean-room; units documented above) |
610
+ | zzfx `duration` | note length | done: a note's length is its duration |
611
+ | raw `zzfx([...])` parameter array | `synth zzfx …`, SDK `zzfx([...])`, `set_synth {zzfx}` | done: ZzFX's documented layout → named controls |
612
+ | soundfonts `gm_*`, drum banks, dirt-samples | sampler and sample packs | not this engine: hosted samples, see Sample packs |
613
+ | sample controls `begin`, `end`, `speed`, `unit`, `loop`, `loopBegin`/`loopb`, `loopEnd`/`loope`, `clip`/`legato`, `fit`, `loopAt`, `accelerate`, `squiz`, `cut`, `gain`, `vel`, `rr` | sampler voice fields; `/sample set`, `set_sample` | done (see Samples) |
614
+ | fitting to tempo (Ableton Repitch/Beats/Tones; Strudel `fit`) | `bpm` `fitmode` `len`; `/fitmode`, `fit_sample` | done (see Fitting samples) |
578
615
 
579
616
  ## Keys (modelled piano)
580
617
 
581
618
  A track whose `instrument` is a piano family (`grand`, `upright`, `felt`, `honkytonk`, `prepared`) and which has a `keys` field plays dawg's modelled piano (`src/audio/keys/`): a felt hammer of the chosen hardness strikes a bank of stretched, inharmonic string modes (two or three detuned unison strings per key, with a fast first stage and a slow aftersound), a soundboard knock, dampers that stop a released key in about a second, and a small body EQ per family. The 0.5 sustain pedal (down, half, up) holds the dampers off. It is built in: nothing downloads and every render is byte-identical.
582
619
 
583
- `piano` keeps two meanings on purpose. A project already stored as `instrument: "piano"` keeps the legacy tone forever. Every new write of the word (`piano`, `instrument piano`, `set_instrument piano`, the menu) stores `instrument: "grand"` with `keys: { preset: "grand" }`. `organ` stays the synth preset. The sampled Salamander grand is still in the browser under instruments.
620
+ `piano` keeps two meanings on purpose. A project already stored as `instrument: "piano"` keeps the legacy tone forever. Every new write of the word (`piano`, `instrument piano`, `set_instrument piano`, the menu) stores `instrument: "grand"` with `keys: { preset: "grand" }`. `organ` stays the synth preset (the modelled organs are `tonewheel`, `combo` and `pipe`, below). The sampled Salamander grand is still in the browser under instruments.
584
621
 
585
622
  Tuning: each key's first partial sits on the track's tuning (12-TET or any table, 19-EDO included; an unmapped degree is silent). By default the octaves are stretched from the strings' own inharmonicity, as a piano tuner would: low octaves are tuned between the 2:1 and 4:2 beats and the treble is beatless 2:1 to the stretched note below, so the octave from A3 to A4 beats under 1 Hz. `keys stretch 0` keeps every key exactly on the tuning. Bends and glides keep each string mode under the Nyquist limit (modes that would alias are muted), and each note fades over its last 250 ms so it ends inside the 8 s loop-tail window.
586
623
 
@@ -603,7 +640,7 @@ automate keys-hardness points 0:0.2 8:0.8 automatable parameters have lanes
603
640
 
604
641
  Presets: `grand` (concert grand, bright and long, three-string unisons), `ballad` (darker grand, softer hammer, more aftersound, plus a room reverb), `upright` (boxy, more inharmonic, shorter), `felt` (felt strip down, muted and intimate, audible mechanics, a small room), `lofi` (felt piano with tape wow, a 3.5 kHz low-pass filter and a 10-bit crush), `honkytonk` (16-cent unisons, bright saloon upright), `prepared` (bolts, rubber and screws on 60% of keys, seeded per key, so the same key always carries the same preparation). A preset is stored as `keys.preset`; its values are read at render, so overrides stay small. The effects a preset brings (`ballad`, `felt`, `lofi`) are ordinary track fields (`reverb`, `filter`, `fx.crush`) and stay editable; switching presets or `keys reset` removes them while they still hold the preset's values, and the same preset word in `song.ts` (`instrument: "lofi"`) brings the same effects. A bare `lofi` stays the drum kit and crush preset word; type `piano lofi`.
605
642
 
606
- The menu has the pianos under **Sound > browse sounds > Keys**, and for a piano track a **Sound > Keys** page and the simple rows (preset, hardness, decay, release, felt) in **Sound > Parameters**. The agent's `set_keys` tool takes the same presets and names; `set_instrument` and `create_track` take the piano words. In the SDK: `track({ instrument: "grand", keys: { hardness: 0.3 } })`.
643
+ The menu has the pianos under **Sound > browse sounds > Keys**, and for a piano track a **Sound > Keys** page and the simple rows (preset, hardness, decay, release, felt) on the **Sound** page. The agent's `set_keys` tool takes the same presets and names; `set_instrument` and `create_track` take the piano words. In the SDK: `track({ instrument: "grand", keys: { hardness: 0.3 } })`.
607
644
 
608
645
  | Param | Range | Default | Lane | What it does |
609
646
  | ------------ | ------------------------------------- | ------------------ | --------------- | -------------------------------------------------------------------- |
@@ -624,9 +661,107 @@ The menu has the pianos under **Sound > browse sounds > Keys**, and for a piano
624
661
  | **body** | grand upright felt honkytonk prepared | the family's own | | body EQ voicing |
625
662
  | **vib** | 0..64 Hz | 0 | | pitch wobble rate (tape wow); note vibrato replaces it |
626
663
  | **vibmod** | 0..24 semitones | 0.5 | | pitch wobble depth |
664
+ | **sym** | 0..1 | 0 | | sympathetic string resonance while the sustain pedal is down |
627
665
 
628
666
  Lanes are read at each note's onset. The model is dawg's own, from public literature (Fletcher's inharmonicity B·n² law, Railsback stretch, Weinreich's coupled unison strings and two-stage decay, Chaigne and Askenfelt's felt-hammer model, Bank's modal piano synthesis), with no sampled audio.
629
667
 
668
+ `sym` (0.6.1) adds a per-track bank of 36 tuned strings (C2..B4) that ring along with what you play while the sustain pedal is down, as the undamped strings of a real piano do. It costs nothing when `sym` is 0 or the track has no sustain pedal, and runs at half rate at 44.1 and 48 kHz.
669
+
670
+ ### Soft pedal and sostenuto (0.6.1)
671
+
672
+ The modelled pianos have the other two pedals of a grand. Both are pedal lanes like the sustain pedal (`[{ tick, state }]`, at most 1024 events) and absent means today's sound:
673
+
674
+ - **Soft pedal** (`softPedal`, una corda, the left pedal): while it is down each note's hammer is shifted so it strikes fewer strings with a softer part of the felt: the unison narrows, the hammer's high partials are rolled off and the level drops about 3 dB, so the note is quieter and darker (a 10%+ lower spectral centroid and at least 3 dB less 2-4 kHz energy on middle C). `half` is half the shift. It is read at each note's onset, so a note struck before the pedal keeps its tone.
675
+ - **Sostenuto** (`sostenuto`, the middle pedal, `down` and `up` only): keys already held when it goes down keep their dampers up until it lifts; notes struck afterwards damp at their own release. A held key struck again while the pedal is down keeps ringing to the lift (the rod keeps its damper up), and a key still held through a lift is caught again by the next press. It works alongside the sustain pedal. Only the modelled pianos with a `keys` object hear the soft pedal; `pedal soft` says so on any other track.
676
+
677
+ ```text
678
+ pedal soft 0-8 una corda from beat 0 to 8 (also: down|half|up <beat>, bars, off)
679
+ pedal sost 0-4 sostenuto down at 0, up at 4 (holds the keys down at 0)
680
+ pedal soft list the lane; pedal sost off clears it
681
+ ```
682
+
683
+ Menu: **Sound › performance** has **soft pedal** and **sostenuto** rows (off, or held over every bar) on a modelled piano track. Agent: `set_piano_pedals` (`soft`, `sostenuto`: events, `"bars"` or null). SDK (1.26.0): `track({ instrument: "grand", softPedal: [[0, "down"], [8, "up"]], sostenuto: [[1, "down"], [4, "up"]] })`.
684
+
685
+ ### Electric keys (0.6.1)
686
+
687
+ Three electric keyboard families on the same `keys` field, built in and byte-identical across renders:
688
+
689
+ - **epiano** (`rhodes`): a tine piano. Each hammer strikes a tine cantilever (three modes: the fundamental, the bell partial and the clang), read by an electromagnetic pickup whose nonlinear response is computed at 2x oversampling, so `bark` growls when played hard without aliasing (aliases of a hard-driven key 96 stay below -50 dB). `vibe` is the suitcase stereo vibrato: the left and right channels swap in antiphase at `vibehz`.
690
+ - **wurli** (`wurlitzer`): a reed piano with a capacitive pickup: nasal, with a growl on loud notes; `trem` is the built-in 5.6 Hz tremolo.
691
+ - **clav** (`clavinet`): struck strings read by neck and bridge pickups. `pickup` chooses `neck`, `bridge`, `both` or `out` (both, out of phase: thin and funky) and `mute` is the mute slider. Pickup positions vary slightly per track (seeded from the track id, so the same track always sounds the same). Releasing a key damps it with the yarn damper and a small release plunk.
692
+
693
+ Presets: `epiano` (stage tine piano), `suitcase` (with the stereo vibrato), `dyno` (bright, bell-heavy), `wurli`, `clav` (both pickups) and `funkclav` (pickups out of phase, mute up). The preset word alone loads it (`suitcase`, `funkclav`); `keys` stays the legacy word.
694
+
695
+ ```text
696
+ epiano | wurli | clav the family (also rhodes wurlitzer clavinet)
697
+ epiano preset suitcase a preset: epiano suitcase dyno | wurli | clav funkclav
698
+ epiano vibe 0.6 bark 0.5 any parameter of the family
699
+ clav pickup bridge mute 0.4
700
+ automate keys-vibe points 0:0 8:0.8 automatable parameters have lanes
701
+ ```
702
+
703
+ | Param | Families | Range | Default | Lane | What it does |
704
+ | ---------- | ------------- | -------------------- | ------- | ----------- | ------------------------------------- |
705
+ | **bark** | epiano, wurli | 0..1 | 0.35 | | pickup drive: growl when played hard |
706
+ | **bell** | epiano, wurli | 0..1 | 0.5 | | tine or reed bell ping |
707
+ | **tone** | all three | 0..12000 Hz | 0 (off) | `keys-tone` | output low-pass |
708
+ | **vibe** | epiano | 0..1 | 0 | `keys-vibe` | suitcase stereo vibrato depth |
709
+ | **vibehz** | epiano | 0.5..12 Hz | 4 | | suitcase vibrato rate |
710
+ | **trem** | wurli | 0..1 | 0 | `keys-trem` | tremolo depth at 5.6 Hz |
711
+ | **pickup** | clav | neck bridge both out | both | | pickup switch |
712
+ | **mute** | clav | 0..1 | 0 | | mute slider: damps the upper partials |
713
+
714
+ `hardness`, `touch`, `decay`, `release`, `width`, `vib` and `vibmod` apply to the electric families too. The menu has them under **Sound › browse sounds › Keys › Electric**, with their rows on the **Sound** page; the agent's `set_instrument` and `set_keys` take the same words; the SDK takes `track({ instrument: "epiano", keys: { vibe: 0.6 } })` or `track({ instrument: "suitcase" })`. The models are dawg's own, from public descriptions of the instruments (tine and tone-bar cantilever, electromagnetic and electrostatic pickups, the Clavinet's pickup switching), with no sampled audio.
715
+
716
+ ### Organs (tonewheel, combo, pipe)
717
+
718
+ Three organ families run on the same keys engine (`src/audio/keys/organ.ts`) when the track's `instrument` is `tonewheel`, `combo` or `pipe` and it carries `keys`. `organ` stays the legacy sine preset and renders byte-identically; reach the engine with the verbs or presets below, or the aliases `hammond`, `b3`, `farfisa`, `church`, `pipeorgan`.
719
+
720
+ - **tonewheel**: 91 free-running tonewheels at the gear ratios of the classic organ, phase-locked to song time (a key opens a wheel already turning, so the same chord sounds the same wherever it lands and two keys sharing a wheel share its phase). Nine drawbars `16' 5⅓' 8' 4' 2⅔' 2' 1⅗' 1⅓' 1'` stored as nine digits 0-8 (`888000000`). Single-trigger percussion (2nd or 3rd harmonic, fast or slow) fires only when every key was up and, as on the original, mutes the 1' bar while it is on. Key click, a scanner vibrato/chorus (V1-V3, C1-C3), a preamp drive and a two-rotor rotary speaker (horn and drum, slow, fast or stop) whose rotors glide between speeds with their own inertia: about a second for the horn and several for the drum.
721
+ - **combo**: divider-style combo organ with five registers `16' 8' 4' 2⅔' 2'` (five digits), a flute, reed or bright voice and a vibrato.
722
+ - **pipe**: band-limited additive pipe ranks with chiff, wind unsteadiness and a tremulant. `stops` lists stop names (`subbass16 bourdon16 principal8 flute8 gedackt8 gamba8 celeste8 octave4 flute4 nazard fifteenth2 piccolo2 tierce larigot mixture trombone16 trumpet8 oboe8 krummhorn8`) or registrations (`plenum flutes cornet reeds strings full`). Each rank sits on the track's tuning (12-TET or a table such as 19-EDO); mutation and mixture ranks are tuned pure (quints 3·f, tierces 5·f) so they fuse with the foundation. Drawbar and rank footages are octaves of the table, so a 19-EDO organ keeps its octaves.
723
+
724
+ A row belongs to its family: `rotary fast` on a pipe organ or `keys drawbars` on a grand is refused with the families that read it, and `keys` on an organ lists its own rows. Single-trigger percussion is one envelope per track: every key struck together sounds it, and a key added while another is held gets the envelope's decayed level. Drive changes the tone at roughly steady loudness.
725
+
726
+ The scanner, drive and rotary run once per track after its voices (the keys per-track post hook), so chords share one rotor; in play mode the live synth keeps one per track and shares its wheel and rotor clock. Rotary and drive are lanes: `keys-rotary` (0 stop, 1 slow, 2 fast; the rotors spin up or down with inertia) and `keys-drive`.
727
+
728
+ ```text
729
+ tonewheel the tonewheel organ (also: hammond, b3)
730
+ tonewheel 888800008 the organ with those drawbars
731
+ gospel | jazzorgan tonewheel presets
732
+ combo | combo 08880 | farfisa | vox the combo organ
733
+ pipe | pipe flutes | pipe principal8 octave4 the pipe organ with a registration or stops
734
+ flutes | cornet | reeds | celeste pipe presets
735
+ tonewheel 888800008 perc 3rd a verb takes more rows (combo 08880 flute)
736
+ rotary slow | fast | stop the rotary speaker
737
+ rotary fast at 16 switch it at beat 16 (a keys-rotary lane point)
738
+ keys drawbars 888000000 any organ row (keys perc 3rd, keys scanner v2, keys stops plenum)
739
+ automate keys-rotary points 0:1 4:2 spin the rotor up at beat 4
740
+ ```
741
+
742
+ Presets: `tonewheel` (888000000, scanner C3, slow rotary), `gospel` (888800008, 3rd percussion, fast rotary, driven), `jazzorgan` (888000000 with soft 3rd percussion), `combo` (reed registers 08800 with vibrato), `vox` (bright 08880), `pipe` (plenum in a church reverb), `flutes` (gedackt 8' and flute 4' with tremulant), `cornet`, `reeds`, `celeste` (gamba and celeste beating).
743
+
744
+ The menu has them under **Sound > browse sounds > Keys > Organs**; for an organ track the **Sound** page shows the preset, a **Drawbars** (tonewheel), **Registers** (combo) or **Stops** (pipe) sub-menu with one row per footage or stop, and the family's rows. The agent's `set_keys` takes `drawbars`, `registers`, `stops` and `rotary` next to `params`. In the SDK: `track({ instrument: "tonewheel", keys: { drawbars: "888800008", rotary: "fast" } })` or `keys: { stops: ["principal8", "octave4"] }`.
745
+
746
+ | Param | Family | Range | Default | Lane | What it does |
747
+ | ------------- | --------------- | --------------------------- | ------------------------------------- | ------------- | ---------------------------------------------- |
748
+ | **drawbars** | tonewheel | nine digits 0-8 | 888000000 | | drawbar registration, 16' to 1' |
749
+ | **perc** | tonewheel | off 2nd 3rd | off | | single-trigger percussion; on mutes the 1' bar |
750
+ | **percdecay** | tonewheel | fast slow | fast | | percussion decay (0.6 s or 1.8 s) |
751
+ | **percvol** | tonewheel | normal soft | normal | | soft: percussion 6 dB down, drawbars unmuted |
752
+ | **click** | tonewheel | 0..1 | 0.5 | | key click |
753
+ | **scanner** | tonewheel | off v1 v2 v3 c1 c2 c3 | c3 | | scanner vibrato or chorus |
754
+ | **drive** | tonewheel combo | 0..1 | 0.15 (combo 0) | `keys-drive` | preamp overdrive |
755
+ | **rotary** | tonewheel combo | slow fast stop | slow (combo stop) | `keys-rotary` | rotary speaker speed |
756
+ | **registers** | combo | five digits 0-8 | 08800 | | combo registers, 16' to 2' |
757
+ | **voice** | combo | flute reed bright | reed | | register timbre |
758
+ | **stops** | pipe | stop names or registrations | principal8 octave4 fifteenth2 mixture | | drawn stops |
759
+ | **chiff** | pipe | 0..1 | 0.4 | | flue pipe attack noise |
760
+ | **wind** | pipe | 0..1 | 0.3 | | wind instability |
761
+ | **trem** | pipe | 0..1 | 0 | | tremulant depth |
762
+
763
+ The organ models are dawg's own, from public descriptions of the tonewheel generator (91 wheels, the 2:1 gearing per octave and its 1' foldback at the top), the scanner vibrato, the rotary speaker's horn and drum rotor speeds, and additive pipe-organ synthesis; no sampled audio.
764
+
630
765
  ## Samples
631
766
 
632
767
  A track whose instrument is `sampler(...)` plays audio files instead of a synth. Voices live in `tracks/<slug>/samples/` and `src` is relative to the track directory (`samples/kick.wav`); a project-relative `tracks/<slug>/samples/kick.wav` works too.
@@ -673,6 +808,17 @@ Semantics follow Strudel's sampler:
673
808
 
674
809
  `/sample set <voice> <control> <value>…` edits these on the focused sampler track (`/sample set brk fit on clip 1`, `/sample set hat cut hats`, `off` unsets one), each voice in the menu's Parameters section has the same controls, and the agent's `set_sample` tool takes them by name.
675
810
 
811
+ ### Velocity layers and round robin (0.6.1)
812
+
813
+ Two optional voice fields borrowed from SFZ make a multisampled instrument:
814
+
815
+ | Field | Values | What it does |
816
+ | ----- | ----------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
817
+ | `vel` | `[lo, hi]`, MIDI 0..127 | the velocity range this voice plays (SFZ `lovel`/`hivel`). Keyed voices with the same root are layers: a note plays the one whose range holds its velocity. One-shot layers on a kit share a pad only through an `rr` group (below); a one-shot voice with `vel` and no `rr` keeps its own pad and plays at every velocity |
818
+ | `rr` | group name | round robin (SFZ `seq_length`): voices in a group with the same root and a matching layer take turns, A B A B, in note order, so a repeated hit never sounds machine-gunned |
819
+
820
+ The picker chooses the layer by velocity first (when no layer of the group holds the velocity, the nearest layer plays), then the next voice in the group from a counter that starts at a turn seeded by the track id and the group, so renders stay deterministic but two tracks with the same samples do not alternate in lockstep. For a kit pad with soft and hard hits, put both voices in one group: `sample snare-soft vel 0-63 rr sn` and `sample snare-hard vel 64-127 rr sn`; either pad then plays the layer the velocity asks for. A note's velocity maps to MIDI as `round(velocity x 127)`; a boundary velocity belongs to the layer whose range contains it (`[0,63]` and `[64,127]` switch at 64). `/sample set snare1 vel 0-63 rr sn`, the menu's **Velocity layer** and **Round robin** rows on each voice, `set_sample {params: {vel: [64,127], rr: "sn"}}` and `sample("samples/sn1.wav", { vel: [0, 63], rr: "sn" })` set them; `off` clears. Voices without them play as before.
821
+
676
822
  ### Fitting samples to the song (0.6)
677
823
 
678
824
  A voice can follow the song's time instead of its own rate. Give it its own tempo (`bpm`) or a length in beats (`len`), and pick how it changes time with `fitmode`:
@@ -698,6 +844,25 @@ How they combine with Strudel's controls and the 0.5 tempo map:
698
844
 
699
845
  `fitmode beats` or `tones` needs `bpm`, `len` or `fit` (validation error otherwise). `/bpm 174`, `/len 16` and `/fitmode beats` act on the focused sampler voice (name it when the track has several: `/bpm 174 brk`; `off` unsets; song tempo stays the bare word `tempo <n>`, and a bare `bpm <n>` without the slash also sets the song tempo, so only `/bpm` sets the sample's); `/fitmode auto` suggests a mode from the sound (crest factor above 5 and more than 2 onsets a second fit as `beats`, the rest as `tones`). The menu's Sound section lists `bpm`, `fitmode` and `len` on each voice, the agent's `fit_sample` tool takes them, and the SDK is `sample("samples/amen.wav", { bpm: 174, fitmode: "beats" })`.
700
846
 
847
+ ### Shift and fade (0.6.1)
848
+
849
+ `shift <semitones>` moves a sampler voice's pitch without changing its length (−24..24). It is a phase-vocoder stretch by 2^(st/12) followed by a band-limited read-back at that rate (identity phase locking, Laroche and Dolson 1999; the same idea as Strudel's `stretch`), cached like a fit and applied after any `fitmode`, so a fitted loop can also be transposed. By default the formants move with the pitch, like a tape; `shift 7 formant keep` (stored `formant: 0`) keeps them where they were, so a voice or a guitar keeps its body, and `formant <n>` moves them `n` semitones on their own. Formants are kept with an envelope drawn through the harmonic peaks (a cepstral true envelope, Röbel and Rodet 2005, where no peak stands): measured on voices from 110 to 330 Hz, ±7 and +12 st land within 1 cent and keep the first formant peak within 3%. Each frame keeps its energy through the correction, so keeping formants stays within 1.5 dB of the plain shift's level. `shift 0` clears the shift but keeps a formant move (`shift 0 formant 3` moves only the formants); `shift off` clears both.
850
+
851
+ `fade out 0.5` and `fade in 0.05` (Strudel `fadeTime` and `fadeInTime`, stored as `fadeTime` and `fadeInTime`, 0..2 s) shape a voice's start and end in place of the short default declick, and follow the fitted length when the voice is fitted. `fade off` clears both.
852
+
853
+ Both act on the focused sampler voice (`shift 7 vox` names one). The menu's **Sound › Sample** voice rows list Shift, Formant, Fade in and Fade out, the agent's `set_sample` tool takes `shift`, `formant`, `fadeTime` and `fadeInTime`, and the SDK writes `sample("samples/vox.wav", { shift: 7, formant: 0, fadeTime: 0.5 })`.
854
+
855
+ ### Resample (0.6.1)
856
+
857
+ `resample <track>|orbit <n>|master [section <name>|bars a-b] [post] [grain] [as <id>]` renders one track, one orbit or the whole mix to `tracks/<slug>/samples/<name>.wav` through the same offline renderer as `dawg render`, pins its sha256 and adds a track that plays it: a one-shot sampler track with one note across the range, or with `grain` a granular track (the `cloud` preset) holding one note there. The source stays as it is; mute it to hear only the copy. The file ends 20 ms after the sound falls to digital silence, and a source that is silent over the range is refused with a receipt instead of adding a silent track. Like freezing and flattening in a DAW (Ableton's Resampling input, Bitwig's bounce in place), it turns a part into material you can chop, grain or shift.
858
+
859
+ - The render is pre-master (the song master is left out) unless `post` is given or the source is `master`. The same score always gives the same bytes, so the sha256 is stable.
860
+ - The new sampler voice plays the file at gain 2 with no fade in, so it reproduces the source stem within −60 dB.
861
+ - The voice records where it came from in `from: { source: "track:lead" | "orbit:2" | "master", section?, bars?, score }`, `score` being the sha256 of the score it was rendered from. It is informational; the renderer never reads it.
862
+ - Up to 600 s. `section` uses the song's sections; `bars 1-2` is 1-based and inclusive.
863
+
864
+ **Project › Resample** lists each track, orbit and the mix with a `→ sampler` and `→ granular` row. The agent's `resample {source: track|orbit|master, trackId?, orbit?, section?, bars?, post?, grain?, as?}` tool does the same.
865
+
701
866
  Fitted windows are computed once and kept in a 64 MB least-recently-used cache of the played window only. Only the frames a note can reach are fitted (a held keyed or clipped note fits its length plus the release; a one-shot or looped voice fits the whole window). Renders and exports always compute them; in play mode a fit up to 8 s (of source or output, whichever is longer) is computed on the spot (under 160 ms), and a longer one stays silent with "fitting" in the status line until it is ready ("fit ready" then), never at the wrong pitch. Audition previews fit synchronously.
702
867
 
703
868
  Every voice starts and stops with a 1–3 ms fade, so cuts do not click. Without `bpm`, `len` or `fitmode` there is no time-stretch, as in Strudel's default. A sampler track goes through the same volume and pan automation, filter, delay and reverb as any other track and is a cached stem like any other; the stem's cache key includes each voice's sha256, so replacing a file re-renders it.
@@ -849,7 +1014,43 @@ instrument: stringed("sitar", { buzz: 0.8, sym: 0.5 }),
849
1014
  | `string <param> off` · `string reset` | back to the preset's value · drop every override |
850
1015
  | `string off` | back to the legacy `pluck` voice |
851
1016
 
852
- The menu has the presets under Sound › browse sounds › Strings and every string parameter in Sound › Parameters on a string track (left/right adjust, `x` resets, space auditions with staged A/B). The agent's `set_string {trackId?, preset?, params?, reset?, off?}` runs the same command. SDK 1.21.0: `stringed(preset, params)` as a track's `instrument`, or `track({ instrument: "string", string: { preset: "koto", ring: 4 } })`; the printer writes `stringed(...)` back.
1017
+ The menu has the presets under Sound › browse sounds › Strings and every string parameter on the Sound page of a string track (left/right adjust, `x` resets, space auditions with staged A/B). The agent's `set_string {trackId?, preset?, params?, reset?, off?}` runs the same command. SDK 1.21.0: `stringed(preset, params)` as a track's `instrument`, or `track({ instrument: "string", string: { preset: "koto", ring: 4 } })`; the printer writes `stringed(...)` back.
1018
+
1019
+ ### Bowed strings
1020
+
1021
+ `exciter: "bow"` (0.6.1) drives the same string with a bow instead of a pluck: a bowed waveguide after the STK `Bowed` model (Smith; Cook and Scavone), with a friction table whose slope follows bow force and a bridge reflection through the string loss, so the string sticks and slips in Helmholtz motion. A Schelleng guard keeps every setting playable: bow force maps inside the measured minimum and maximum for the note's pitch and bow position (Schelleng 1973), so `pressure 0` is a breathy flautando and `pressure 1` a gritty but still pitched sound, never a squeal or silence; strings with periods under 24 samples run 2x oversampled, and a pitch lock keeps the note within 1 cent from G3 to C7 at 22.05 and 48 kHz. The `violin` body adds the main air and wood resonances (A0, CBR, B1-, B1+ and the bridge hill).
1022
+
1023
+ `bowed` plays the cello preset; `bowed <preset>` (or `string <preset>`) picks one of 13 bowed presets appended to the table (35 in all):
1024
+
1025
+ | Preset | Sound |
1026
+ | ------------------------------------------ | ------------------------------------------------------------------------- |
1027
+ | `violin` `viola` `cello` `contrabass` | solo orchestral strings |
1028
+ | `fiddle` `erhu` `kamancheh` (`kemence`) | folk fiddle, erhu (skin body, wide vibrato), Persian spike fiddle |
1029
+ | `violins` `violas` `cellos` `contrabasses` | sections: seeded unison players with their own detune, vibrato and spread |
1030
+ | `pizz` (`pizzicato`) · `trem` (`tremolo`) | plucked violin section · tremolo section |
1031
+
1032
+ The words `violin`, `viola`, `fiddle`, `erhu`, `kamancheh`, `violins`, `violas`, `cellos`, `contrabasses` and `bowed-cello` switch a track to these presets. The bare legacy words `cello`, `contrabass` and `strings` keep their pre-0.6.1 voices byte-identically; reach the bowed cello with `bowed cello`, `string cello`, `instrument bowed-cello`, `set_string {preset: "cello"}` or `stringed({ preset: "cello" })`.
1033
+
1034
+ | Parameter | Range | Meaning |
1035
+ | ------------------------- | ---------- | --------------------------------------------------------------------------- |
1036
+ | `pressure` | 0..1 | bow force inside the playable range: flautando at 0, gritty at 1 |
1037
+ | `speed` | 0..1 | bow speed at full dynamics (loudness) |
1038
+ | `attack` | 0.005..4 s | bow-speed ramp at the start of a stroke (swells) |
1039
+ | `vib` `vibmod` `vibdelay` | Hz, st, s | vibrato rate, depth and onset delay (a note's own vibrato wins) |
1040
+ | `tremhz` | 0..16 Hz | tremolo bowing: rapid strokes per second (0 off) |
1041
+ | `sord` | 0..1 | con sordino: the practice mute, darker and softer |
1042
+ | `dyn` (`expression`) | 0..1 | dynamics on top of velocity (like MIDI CC11): drives bow speed and pressure |
1043
+
1044
+ Phrasing. A true legato is a slur: a single note that starts while the previous single note is held and that note lets go within a 64th note or 150 ms, or a note with the `legato` articulation. The string retunes within 5-10 ms and keeps the bow, with no new attack (four slurred notes are one onset); the bow point and loss follow the new pitch, so slurs up to two octaves land within a cent at a fresh note's level, and wider leaps start a new stroke. A note held under a moving line (a pedal) keeps sounding. Chords and double stops start new strokes. Velocity sets the stroke's dynamics and presses harder (pressure + 0.3 x (velocity - 0.5)); `staccato` and `ghost` are detache strokes (attack 10 ms, release 30 ms), and `accent` and `marcato` bite (pressure +0.2 for the first 80 ms). Section presets seed each player's vibrato rate (x0.92-1.08), depth (x0.8-1.2) and phase, and start players up to 25 ms apart (the first stays on the grid). `pressure`, `speed`, `sord` and `dyn` automate as `string-<param>` lanes, read every 32 samples, so `automate string-dyn points 0:0.2 4:1` is a crescendo inside held notes; `string-pos` sets each note's bow point (sul ponticello near 0.05, sul tasto near 0.4). Play mode caps a section at two unison players and sounds the first 0.75 s at once, the rest following in the background; renders use every player.
1045
+
1046
+ Measured: tuning within 1 cent to C7 at 22.05 and 48 kHz; 0 of 1296 pressure/speed/position/pitch settings leave Helmholtz motion; the free string after the bow lifts decays within 10% of `ring`; ff is at least 1.15x brighter (spectral centroid) than pp; 8 s of `violins` in play mode renders in under 40 ms.
1047
+
1048
+ | Command | Does |
1049
+ | -------------------------------------------- | ------------------------------------------------------- |
1050
+ | `bowed` · `bowed <preset>` · `bowed presets` | the cello · a bowed preset · the bowed presets |
1051
+ | `bowed <param> <value> …` | the same as `string <param> <value> …` (`bowed sord 1`) |
1052
+
1053
+ The menu lists them under **Sound › browse sounds › Strings › Bowed**, and the **Sound** page on a bowed track shows `pressure speed vib sord dyn bright ring body` first (the rest under advanced). SDK 1.31.0: `stringed("violin", { pressure: 0.7 })` or `stringed({ preset: "cello", sord: 1 })`.
853
1054
 
854
1055
  ## Granular
855
1056
 
@@ -893,6 +1094,21 @@ instrument: granular({ src: "synth:bell@72", grain: 0.08, shimmer: 0.3 }),
893
1094
  instrument: granular("hold", { src: "samples/choir.wav", root: "A3" }),
894
1095
  ```
895
1096
 
1097
+ ### Grain play (0.6.1)
1098
+
1099
+ Four optional parameters make a granular track playable like an instrument rather than a texture. Each is absent by default, and absent renders byte-identically to 0.6.0.
1100
+
1101
+ | Parameter | Values (default) | What it does |
1102
+ | --------- | ---------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
1103
+ | `sync` | `off` `1/64` `1/32` `1/16t` `1/16` `1/16d` `1/8t` `1/8` `1/8d` `1/4t` `1/4` `1/4d` `1/2` `1/1` | Grains start on a note-value grid that follows the song's tempo map (ramps included), as Ableton Granulator II and Output Portal sync their grain rate. `grain` still sets each grain's length; `overlap` is ignored. `jitter` moves onsets off the grid by up to a fraction of a step. Measured within 1 ms of 117.19 ms per 1/16 at 128 BPM. |
1104
+ | `quant` | `off` `scale` `chord` | Snaps each grain's pitch offset (`pitch`, `detune`, `shimmer`) to the nearest pitch of the song key's scale, or of the pitch classes sounding on the song's other pitched tracks at that grain's onset, falling back to the scale when nothing sounds (scale quantise, as on Output Portal and Bitwig's Sampler). The played note itself is never moved. |
1105
+ | `mono` | `on` `off` (off) | One voice: a note that starts before the previous one ends (legato) retargets that voice's pitch and keeps its grain stream and head, so a melody glides through one cloud; a detached note starts a new voice and cuts the old one's tail. |
1106
+ | `pedal` | `on` `off` (off) | The track's sustain pedal freezes the head while it is down (the cloud keeps playing the same spot), as on Mutable Clouds' freeze and the Hologram Microcosm hold. |
1107
+
1108
+ `grain sync 1/16`, `grain quant scale`, `grain mono on` and `grain pedal on` set them (`off` unsets); **Sound › granular** lists them as rows, `set_granular` takes them in `params`, and the SDK writes `granular("cloud", { sync: "1/16", quant: "scale", mono: true })`.
1109
+
1110
+ Lanes: every numeric parameter that moves well over time has a `grain-<param>` automation lane: `grain-pos`, `grain-scan`, `grain-grain`, `grain-overlap`, `grain-jitter`, `grain-spray`, `grain-pitch`, `grain-detune`, `grain-shimmer`, `grain-spread`, `grain-reverse`, `grain-repeat` and `grain-drift`. A lane replaces the parameter's value while it has points (`automate grain-pos points 0:0.1 8:0.9` sweeps the head across the source), is read every 32 frames, and latches per grain at its onset, so a block render equals a whole render. They are in **Mix & automation**'s lane picker on granular tracks and stored in `track.fxAutomation` like the effect lanes.
1111
+
896
1112
  ## Mallets and bells (modal)
897
1113
 
898
1114
  `instrument: "modal"` plays struck bars, tines, bells, bowls and drums on a modal resonator bank (`src/audio/dsp/modal.ts`, `src/audio/resonators.ts`): each note excites a table of measured mode ratios through a mallet pulse, each mode rings as a two-pole resonator with its own decay, and the strike point weights the modes the way it does on a real bar (the node at the centre of a marimba bar mutes the second mode). It is dawg's own engine, ported from the reviewed 0.6 prototype.
@@ -930,7 +1146,55 @@ instrument: modal("marimba", { mallet: "rubber", ring: 2 }),
930
1146
  | `modal reset` | clear overrides, keep the preset |
931
1147
  | `modal off` | leave the engine for the legacy marimba voice |
932
1148
 
933
- The menu's **Sound › browse sounds › Mallets and bells** lists the presets, and **Sound › Parameters** shows the preset, mallet, the simple parameters and an **advanced** group on a modal track. The agent's `set_modal {trackId, preset?, mallet?, params?, reset?}` tool takes the same names.
1149
+ The menu's **Sound › browse sounds › Mallets and bells** lists the presets, and the **Sound** page shows the preset, mallet, the simple parameters and an **advanced** group on a modal track. The agent's `set_modal {trackId, preset?, mallet?, params?, reset?}` tool takes the same names.
1150
+
1151
+ ### Gamelan (0.6.1)
1152
+
1153
+ The modal engine also plays Javanese and Balinese bronzes, small bells and frame drums: `saron` `demung` `slenthem` `gangsa` `gender` `bonang` `kenong` `kethuk` `kempul`, the bells `crotales` `musicbox` `toypiano`, and the drums `daf` `bodhran` `tabla` (aliases `crotale`, `musicalbox`, `framedrum`). `modal gamelan` lists them; the menu has them under **Sound › browse sounds › Mallets and bells › Gamelan**. Gamelan is tuned in slendro or pelog, not 12-TET, so pair the presets with `tuning slendro` or `tuning pelog` (the 0.5 tuning tables).
1154
+
1155
+ Balinese instruments come in pairs: the pengumbang is tuned low and the pengisep a few hertz high, so a unison beats (_ombak_, "wave") at that difference, typically 5 to 8 Hz. `modal pair <track>` makes the focused track the pengisep of the named partner: it sounds `ombak` Hz above it (gangsa's 7 Hz by default), the partner plays one voice at its own pitch, and the two together beat at exactly `ombak` Hz instead of each track beating on its own. `modal pair off` undoes it. `modal ombak 6` or `modal pair t2` on a track that is not modal yet starts it as a `gangsa`. In the SDK: `modal("gangsa", { ombak: 6, pair: "pengumbang" })`.
1156
+
1157
+ Live, an undamped bar (`damp 0`: gongs, kempul, bowls) keeps ringing after you release the key in play mode and the audition loop: up to 32 ringing voices, the oldest faded over 250 ms, and the loop's fold fades a tail that would outlast it the same way. The 15 presets are appended to the table (existing ones unchanged), and `RESONATOR_TABLE_VERSION` is 2, so stems re-render once.
1158
+
1159
+ ## Winds and brass (wind engine)
1160
+
1161
+ `instrument: "wind"` with a `wind` field plays blown instruments on breath-driven digital waveguides (`src/audio/winds/`): a bore delay line tuned exactly with a Thiran allpass, closed by a reed table (clarinet), a conical reed (saxophones, oboe, bassoon), an air jet (flutes) or a lip resonator (brass), with loss and bell filters, breath noise and a breath envelope. Reed and jet run at 2x with first-order antiderivative antialiasing (`src/audio/dsp/shape.ts`, `oversample.ts`); each preset carries per-semitone pitch and level trims for 22.05, 44.1 and 48 kHz, generated by `bun scripts/calibrate-winds.ts`, so every preset plays within 3 cents across its range. It is dawg's own model, after Smith's digital waveguides, Cook's STK reed and jet models and Välimäki's fractional-delay filters, ported from the reviewed 0.6 prototype; no samples.
1162
+
1163
+ Presets (a word picks one): flutes `flute` `recorder` `whistle` `ney` `shakuhachi` `panpipe` `suling` `bansuri`; reeds `clarinet` `bassclarinet` `oboe` `bassoon`; saxophones `sax` (tenor) `altosax` `barisax`; brass `trumpet` `harmon` `plunger` `trombone` `tuba` `horn`. Aliases: `tinwhistle` `pennywhistle` `nay` `panflute` `panpipes` `saxophone` `tenorsax` `tenor` `alto` `bari` `baritonesax` `frenchhorn` `mutedtrumpet` `wahtrumpet`. `instrument flute` (or any preset word) switches the focused track. The bare legacy word `wind` with no `wind` field keeps its pre-0.6 tone byte-identically; `wind flute` gives the engine. `presets wind` (or `wind presets`) lists them; the menu has them under **Sound › browse sounds › Winds and brass**, and the **Sound** page shows the simple rows `breath` `bright` `mute` `players` `growl` with the rest under advanced.
1164
+
1165
+ | Parameter | Range | Meaning |
1166
+ | ------------------ | -------------------------------- | ----------------------------------------------------------------------------- |
1167
+ | `model` | jet reed sax lips | exciter and bore (set by the preset) |
1168
+ | `breath` | 0..1 | blowing pressure: louder and fuller; too little and a reed does not speak |
1169
+ | `noise` | 0..1 | breath noise |
1170
+ | `attack` `release` | 0.001..2 s, 0.005..2 s | breath rise and fall; Strudel `att`/`rel` |
1171
+ | `vib` `vibmod` | 0..12 Hz, 0..1 st | vibrato rate and depth |
1172
+ | `reed` | 0..1 | reed stiffness, jet offset or lip tension |
1173
+ | `bright` | 0..1 | bore loss: dark to bright |
1174
+ | `stopped` | on/off | stopped pipe, odd harmonics (jet only: panpipe) |
1175
+ | `mute` | open straight cup harmon plunger | brass mute |
1176
+ | `wah` `wahenv` | 0..1 | plunger opening, and how much it opens with each note (doo-wah) |
1177
+ | `growl` `flutter` | 0..1 | hum into the horn, flutter tongue |
1178
+ | `players` | 1..8 | section size: extra players double the chord tones, slightly detuned and late |
1179
+ | `gain` | 0..2 | level |
1180
+
1181
+ `breath`, `noise`, `wah`, `growl` and `flutter` have `wind-<param>` automation lanes, read continuously, so a breath lane swells a held note. A single line slurs by default: a lone note that starts under (or right at the end of) a lone held note continues the same breath with a legato pitch change (a track `glide` setting, a `staccato` note or a bend tongues it instead); chords sound as separate voices. Velocity brightens the tone (brass the most, flutes the least), accents and marcato blow harder, and notes honour tuning, `cents`, bends, humanize and the tempo map. Up to 24 voices sound at once; the oldest is stolen with an 80 ms fade.
1182
+
1183
+ ```ts
1184
+ instrument: "flute",
1185
+ instrument: wind("trumpet", { mute: "harmon", players: 3 }),
1186
+ instrument: wind("sax", { breath: 0.8, growl: 0.3 }),
1187
+ ```
1188
+
1189
+ | Command | What it does |
1190
+ | ---------------------------------------- | --------------------------------------------------------------- |
1191
+ | `wind` · `wind presets` · `presets wind` | the focused track's preset and overrides · every preset |
1192
+ | `wind <preset>` | make the focused track a wind track with that preset |
1193
+ | `wind <param> <value> …` | set parameters (`wind breath 0.8 players 3`); `off` clears one |
1194
+ | `wind mute <name>` | `open` `straight` `cup` `harmon` `plunger` |
1195
+ | `wind reset` · `wind off` | clear overrides, keep the preset · back to the legacy wind tone |
1196
+
1197
+ The agent's `set_wind {trackId, preset?, params?, reset?}` tool takes the same names, and `set_instrument` accepts every wind word.
934
1198
 
935
1199
  ## Rhythm (Euclidean rows)
936
1200
 
@@ -1014,6 +1278,7 @@ From Orchid's documentation and reviews:
1014
1278
  - Bass: an optional engine that plays the chord's root under every chord. Its menu (manual 10.2, "How to use Bass on Orchid") has Chords Only (bass only under chords), Unison (single notes play bass and treble together), Single Notes (single notes play only bass; the treble sounds only for chords) and Solo (the treble is muted, even for chords).
1015
1279
  - Performance modes: Strum (and 2-octave), Slop (random timing per note for a humanised feel that varies with every press), Arpeggiator (and 2-octave, tempo-synced; more chord notes make a longer pattern), Pattern (fixed rhythms) and Harp (a sweep across several octaves).
1016
1280
  - "Secret chords" (firmware 3.84+, Orchid manual section 14.8): two type buttons held together play extra chords. dim+sus is a power chord (C5), maj+sus augmented (C+), min+sus Cm(add4); min+dim with the 6 button is Cm(b6), maj+dim with 6 is C(b6), and maj+min with m7 is C7♯9. dawg's `COMBINED_TYPES` is this table.
1281
+ - Typed upper tensions (0.6.1): chord symbols also accept `11 m11 maj11 add11 madd11 13 m13 maj13 7b9 7#11 maj7#11 7b13 13b9` (`strum C11`, `strum_chords`, SDK `strum()`). They are typed-only (no pad buttons) and name back as typed; the guitar voicer drops the 5th, then the 11th beside a 3rd, then the 9th, and never the 3rd or 7th.
1017
1282
  - Orchid has no generator that writes a progression for you. Key mode is its "easy chord progressions" feature: you pick the order, every key is in key.
1018
1283
 
1019
1284
  dawg's own design:
@@ -1119,6 +1384,27 @@ Rendering. Synth and wavetable voices start at the tuned frequency; keyed sample
1119
1384
 
1120
1385
  Recording keeps each note's velocity from `C`/`V`. Sustain is recorded the way Logic's Musical Typing records its `Tab` sustain key: as pedal events (`down` when `Tab` latches or Shift starts holding, `up` when it lets go) on the track, at the playhead and not quantized, while the notes keep the length the key was held. Terminals report key-down only, so `Tab` latches rather than holds. A chord-mode press keeps its held length on its voices instead.
1121
1386
 
1387
+ ### Guitar strumming (0.6.1)
1388
+
1389
+ The `guitar` perform mode, the `strum` command, `strum_chords` and SDK `strum()` share one fretboard voicer and one stroke engine in `core/chords.ts`.
1390
+
1391
+ ```text
1392
+ guitar show the track's fretting (Track.guitar)
1393
+ guitar tune dadgad a tuning name, or open strings low to high: guitar tune D A D G A D
1394
+ guitar capo 2 · hand 5 · ring 0.8 · position 5 · guitar reset
1395
+ strum G D Em C folk chords (symbols or roman numerals), one bar each
1396
+ strum I V vi IV strokes D-DU-UDU speed 30ms each 2 at 4
1397
+ strum strum the block chords already on the track
1398
+ /chords perform guitar play mode chords strum on the fretboard; [ ] change speed
1399
+ ```
1400
+
1401
+ - **Voicer.** Each chord is fitted to the strings within `hand` frets (default 4) above the capo, preferring open strings (`ring` 0 closed shapes .. 1 ringing open strings) and the `position` fret. A barre never lies over a string that plays open, the bass is the chord's root or slash bass, and when a chord has more notes than strings fit it drops the fifth, then the 11th, then the 9th, as guitarists do. Every one of the 96 common shapes (12 roots × 8 qualities) is playable within 4 frets in standard tuning.
1402
+ - **Tunings** (`GUITAR_TUNINGS`): `standard dropd doubledropd dadgad openg opend opene halfdown nashville bass ukulele requinto`, or any 3..12 open-string notes. The capo moves every string up.
1403
+ - **Strokes.** A grid on `step` (an eighth by default) of `D` down, `U` up, `d` `u` light strokes, `x` a muted chuck, and `-` or `.` a rest (the strings ring on), or a named pattern: `down folk pop punk funk reggae waltz jangle island`. Down strokes go low to high, up strokes high to low over three or four strings, and a new stroke cuts the strings it restrikes. Patterns are dawg's own: the classic folk/pop eighth-note patterns of beginner method books.
1404
+ - **Speed.** The time a full six-string down stroke takes, 22 ms by default (0..200 ms), the spread a real pick takes across the strings; it is in milliseconds so it stays the same at any tempo (`speed 1/32b` gives it in beats, converted at the song tempo). At 120 BPM the first-to-last note spread equals `speed` within 1 ms.
1405
+
1406
+ Track.guitar is stored only when set (`{ tune, capo, hand, ring, position }`). Menu: **Sound › guitar** (on guitar-like tracks: tune, capo, hand, ring, position, strum the chords, reset) and **Chords › strokes / speed**. Agent: `set_guitar`, `strum_chords`, and `write_chords` with `perform: "guitar"`, `strokes`, `speed`. SDK: `track({ guitar: { tune: "dadgad", capo: 2 } })` and `strum("G D Em C", { strokes: "folk", speed: 30 })`.
1407
+
1122
1408
  ### Chord mode
1123
1409
 
1124
1410
  Play mode has a chord sub-mode modelled on the Orchid's Key mode. It is `auto` by default when the focused track can play chords (pitched synths, piano, soundfonts, keyed samplers; not tracks whose instrument, name or id says bass, kit, drum or perc) in 12-TET without a mono or legato glide, otherwise `manual`, so a track in pelog, just intonation or another non-12 tuning, or a TB-303-style legato line, records single notes. Choosing a mode by hand (`Q`, `/chords`, the menu) sticks for the session.
@@ -1129,22 +1415,23 @@ Play mode has a chord sub-mode modelled on the Orchid's Key mode. It is `auto` b
1129
1415
 
1130
1416
  Terminals send no key releases, so the Orchid's held left-hand buttons are latches here: press once to latch, again to release, `0` clears them all.
1131
1417
 
1132
- | Key | Does (chord mode on) |
1133
- | --------- | ------------------------------------------------------------------------------- |
1134
- | `Q` | auto ⇄ manual |
1135
- | `1 2 3 4` | latch chord type dim / min / maj / sus (two latched make a combined chord) |
1136
- | `5 6 7 8` | latch extension 6 / m7 / M7 / 9 (any number; on top of the type or auto chord) |
1137
- | `0` | clear every latch |
1138
- | `-` / `=` | voicing dial down / up (-12..12; walks inversions) |
1139
- | `9` | next perform mode (block, strum-up, strum-down, arp-up, …, harp, slop, pattern) |
1140
- | `B` | next bass mode: off, chords, unison, single, solo (bass in C2–B2) |
1141
- | `N` | play the suggested next chord (the `next` chord in the header) |
1418
+ | Key | Does (chord mode on) |
1419
+ | --------- | --------------------------------------------------------------------------------------- |
1420
+ | `Q` | auto ⇄ manual |
1421
+ | `1 2 3 4` | latch chord type dim / min / maj / sus (two latched make a combined chord) |
1422
+ | `5 6 7 8` | latch extension 6 / m7 / M7 / 9 (any number; on top of the type or auto chord) |
1423
+ | `0` | clear every latch |
1424
+ | `-` / `=` | voicing dial down / up (-12..12; walks inversions) |
1425
+ | `9` | next perform mode (block, strum-up, strum-down, arp-up, …, harp, slop, pattern, guitar) |
1426
+ | `[` / `]` | perform guitar: strum slower / faster (5 ms steps, 0..200 ms) |
1427
+ | `B` | next bass mode: off, chords, unison, single, solo (bass in C2–B2) |
1428
+ | `N` | play the suggested next chord (the `next` chord in the header) |
1142
1429
 
1143
1430
  The header gains `AUTO C major · Dm (ii) · next G`: mode, key (`(assumed)` when the score has none and C major is used), the last chord with its numeral, and the suggested next chord. A legend row under the keyboard strip lists the number-row latches (`1 dim 2 min 3 maj 4 sus 5 6 6 m7 7 M7 8 9 0 clear -= voicing 0 9 block b bass off n next q auto`), with latched ones lit; at 80 columns the row ends where it fits. The full chord state is in the `?` panel, in the header's words: `chords AUTO C major · Dm (ii) · next G · min+m7 · voicing +1 · arp-up · bass chords`. The suggestion comes from the progression engine: the next chord of the chosen preset when the last chord is in it, otherwise a seeded step of the style's transition graph.
1144
1431
 
1145
1432
  Each chord is voice-led from the previous one and sounds through the live voice path. Recording quantizes the press like a note and lays the chord out with the perform mode over its held length (arpeggios at `rate`, `grid` by default; patterns from the press's quantized start), plus the bass note. Under `unison`, `single` and `solo` a single note in manual mode also records its bass (and, for `unison`, the note itself); `solo` records chords as bass only; each bar is still one revision and one undo step.
1146
1433
 
1147
- `/chords` with no argument prints the settings; `/chords auto|manual|off`, `voicing <n>`, `spread close|open|wide`, `bass off|chords|unison|single|solo` (`on` means `chords`), `sevenths on|off`, `perform <mode>`, `pattern <1..13|name>` (also selects the pattern perform mode), `rate grid|1/4|1/8|1/16|1/32`, `octaves 1..4`, `preset <name>|none`, `style pop|jazz|modal|classical`. `key <tonic> <mode>` (`key A minor`, `key F# dorian`, `key none`) sets the song key as one score edit. The same settings and the key are in `/menu` under Chords.
1434
+ `/chords` with no argument prints the settings; `/chords auto|manual|off`, `voicing <n>`, `spread close|open|wide`, `bass off|chords|unison|single|solo` (`on` means `chords`), `sevenths on|off`, `perform <mode>`, `pattern <1..13|name>` (also selects the pattern perform mode), `rate grid|1/4|1/8|1/16|1/32`, `octaves 1..4`, `preset <name>|none`, `style pop|jazz|modal|classical`, and for the guitar perform mode `strokes <name|grid>` and `speed <ms|beats>` (`speed 30ms`, `speed 1/32b`). `key <tonic> <mode>` (`key A minor`, `key F# dorian`, `key none`) sets the song key as one score edit. The same settings and the key are in `/menu` under Chords.
1148
1435
 
1149
1436
  The base octave follows the instrument: C3 (MIDI 48) by default, C2 for bass instruments or tracks named bass, C4 for saw/square/triangle/pluck leads. Kits start at C2, so `A` is the GM kick, `S` the snare, `T` the closed hat. On a one-shot sampler track the keys walk the voices in name order from slot 36 (`A` the first voice, `W` the second, chromatically), and the strip shows voice names; a keyed sampler starts at the C below its lowest root and repitches from it.
1150
1437
 
@@ -1267,15 +1554,15 @@ The arrangement strip is one row under the header that shows the sections over t
1267
1554
 
1268
1555
  `/menu` or `Ctrl-K` (on an empty prompt, in play mode too) opens the edit menu, drawn with the same overlay as the model picker. Every edit the agent can make is reachable from it with keys alone. Each row shows a plain label and the current value with its unit (s, Hz, oct, st, dB, BPM, bars); the line under the list describes the focused row and shows, dimmed, the prompt command the row runs, so the menu teaches the commands. `/menu <section>` opens a section directly (`/menu effects`, `/menu arrange`); the old names `parameters`, `sounds`, `track`, `automation` and `transport` still work.
1269
1556
 
1270
- | Section | Rows (most used first) |
1271
- | ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
1272
- | Sound | instrument, preset; a synth's attack, decay, sustain, release, filter cutoff/res/env, detune, vibrato, FM amount, then **advanced** with every synth parameter; a wavetable track's table and wavetable parameters; **granular** (a granular track's preset, source and parameters; **granular (convert)** elsewhere); a sampler's mode and voices; **performance** (glide, pedal, velocity curve, humanize); **browse sounds** (instruments, wavetables, Granular, packs) |
1273
- | Effects | the core effects (filter, auto filter, distortion, tremolo, compressor, chorus, delay, reverb) with presets and simple parameters, **more effects** (dj filter, vowel, bitcrush, phaser, leslie, post gain, orbit, duck), and **advanced** per effect (see Effects) |
1274
- | Rhythm | the euclid editor (`/euclid`), drum patterns (`/pattern`), drum kits (`/kit`, synth then samples) |
1275
- | Chords | play-mode chord mode, key tonic and mode, voicing, spread, bass, sevenths, perform, pattern, arp rate, arp octaves, progression, style |
1276
- | Mix & automation | the focused track's name, mute, solo, volume, pan; **all tracks** (choosing one focuses it); **automation**: each `AUTOMATION_LANES` lane with its points as `beat N value` rows, add points, ramp, clear lane; **master**: target, eq, glue, tape, width, limiter |
1277
- | Project | play, tempo, beats per bar, loop length, grid, click, count-in bars |
1278
- | Arrange | every section (loop, jump, mute, transpose, gain, build, drop, fill, duplicate, move, rename, unmark, delete), mark bars, add section, form, loop off (see Arrange) |
1557
+ | Section | Rows (most used first) |
1558
+ | ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
1559
+ | Sound | instrument, preset; a synth's attack, decay, sustain, release, filter cutoff/res/env, detune, vibrato, FM amount, then **advanced** with every synth parameter; a wavetable track's table and wavetable parameters; **granular** (a granular track's preset, source and parameters; **granular (convert)** elsewhere); a sampler's mode and voices; **performance** (glide, pedal, soft pedal and sostenuto on a piano, velocity curve, humanize); **browse sounds** (instruments, wavetables, Granular, Keys with Electric, packs) |
1560
+ | Effects | the core effects (filter, auto filter, distortion, tremolo, compressor, chorus, delay, reverb) with presets and simple parameters, **more effects** (dj filter, vowel, bitcrush, phaser, leslie, post gain, orbit, duck), and **advanced** per effect (see Effects) |
1561
+ | Rhythm | the euclid editor (`/euclid`), drum patterns (`/pattern`), drum kits (`/kit`, synth then samples) |
1562
+ | Chords | play-mode chord mode, key tonic and mode, voicing, spread, bass, sevenths, perform, pattern, arp rate, arp octaves, progression, style |
1563
+ | Mix & automation | the focused track's name, mute, solo, volume, pan; **all tracks** (choosing one focuses it); **automation**: each `AUTOMATION_LANES` lane with its points as `beat N value` rows, add points, ramp, clear lane; **master**: target, eq, glue, tape, width, limiter |
1564
+ | Project | play, tempo, beats per bar, loop length, grid, click, count-in bars |
1565
+ | Arrange | every section (loop, jump, mute, transpose, gain, build, drop, fill, duplicate, move, rename, unmark, delete), mark bars, add section, form, loop off (see Arrange) |
1279
1566
 
1280
1567
  Every list, picker and editor uses the same keys (see **Keys** below). In the menu:
1281
1568