diff --git a/tools/aqua-feel/README.md b/tools/aqua-feel/README.md index 87aa094..e20a649 100644 --- a/tools/aqua-feel/README.md +++ b/tools/aqua-feel/README.md @@ -61,6 +61,10 @@ at the shipped renders. They are tripwires, not taste. Current waivers: `sfxr-classic-classic-sfxr-abstract-golf` (+0.9 dBTP, -5.3 LUFS, held noise) and `sfxr-explosion` (3 s of steady noise without decay). Nobody has listened to either to see if the number is the sound. +## Effects shelf + +`SHELF.md` and `shelf.json` list every renderable effect (thruster, Dings, earcon families, playground patches) with params, trigger, render command and duration; `node shelf.mjs check` runs every render command and checks the WAVs are finite and not silent. Nothing on it is heard (`listening: unheard`). + ## Reuse `report.js` imports `mean`, `spearman` and `permutationP` from `../aqua-trial/analyze.mjs` and the variants from diff --git a/tools/aqua-feel/SHELF.md b/tools/aqua-feel/SHELF.md new file mode 100644 index 0000000..3f423bc --- /dev/null +++ b/tools/aqua-feel/SHELF.md @@ -0,0 +1,125 @@ +# Effects shelf + +What AquaSynth can render to a WAV today without a window, an audio device or a server: the thruster, the Dings event sounds, the +earcon workshop's families and the playground's synth patches. `shelf.json` is the machine-readable list (generated); the tables +below are generated from it. Both come from `node tools/aqua-feel/shelf.mjs build`. + +**Nothing on this shelf has been heard.** Every `listening` field is `unheard`. `node tools/aqua-feel/shelf.mjs check` runs each +entry's render command and proves the file is finite, not silent (peak above -70 dBFS) and as long as listed. It cannot say +that anything sounds good, fits an overlay, or is distinguishable on a stream. A person edits `listening` after listening. + +## For overlay packaging + +- **No entry reacts to audio.** Nothing here analyses a signal. Entries react to *events* (Ding event ids, earcon event ids), to a + *control value* (the thruster's `rpm`), or to being *started* (patches). Mapping a StreamPixels event onto any of these is not + done anywhere in the repo; that mapping is the packager's. +- Two event vocabularies exist and do not match: Dings use task-state ids (`task.complete`, `input.required`, ...), the earcon + workshop uses `success, fail, warning, message, done, waiting`. The earcon workshop is a separate JS implementation and + does not sound like the Dings. +- Every command runs from the repo root, needs node >= 20, and writes under `tools/aqua-feel/out/shelf/` (gitignored). Patch and + Ding renders need the faustwasm runtime once: `(cd tools/aqua-playground && npm ci)`. Earcon renders need nothing installed. +- Patch and Ding WAVs are mono float32 at 48 kHz; earcon WAVs are mono 16-bit at 48 kHz. +- `duration_s` for patches is the 3 s render window, not the effect's length: `behaviour` says whether the patch was still sounding + at 3 s (sustained) or had died away. Re-render with `--seconds N` for longer. +- Ding loudness uses command gain 0.6, an assumption carried over from `tools/aqua-feel`. + +## Render one + +```sh +node tools/aqua-feel/shelf.mjs render patch/thruster rpm=2400 --out /tmp/thruster.wav --seconds 5 +node tools/aqua-feel/shelf.mjs render ding/task.complete instrument=glass-chime --out /tmp/done.wav +node tools/earcon-workshop/cli.mjs warm-bell /tmp/earcons tempo=1.2 level=0.6 # six WAVs + pack.json +node tools/aqua-feel/shelf.mjs check # every entry (about two minutes); --only SUBSTR for a subset +``` + +Each entry in `shelf.json` carries its own `render.command` (the exact string `check` runs) and the files it writes. +Sustained patches such as the thruster keep sounding until stopped; the render command cuts them at the window. + +## Entries + + + +### Thruster (1) + +| id | reacts to | params | behaviour | duration | listening | +|---|---|---|---|---|---| +| `patch/thruster` | control: rpm | rpm 300..6000 (default 1200) | sustained | 3 s | unheard | + +### Dings (event sounds) (9) + +| id | reacts to | params | behaviour | duration | listening | +|---|---|---|---|---|---| +| `ding/input.required` | event `input.required` | instrument ∈ {glass-chime, muted-pluck, soft-triangle, warm-bell} (default warm-bell) | decays | 1.76 s | unheard | +| `ding/resource.limit` | event `resource.limit` | instrument ∈ {glass-chime, muted-pluck, soft-triangle, warm-bell} (default warm-bell) | decays | 2.06 s | unheard | +| `ding/session.end` | event `session.end` | instrument ∈ {glass-chime, muted-pluck, soft-triangle, warm-bell} (default warm-bell) | decays | 1.74 s | unheard | +| `ding/session.start` | event `session.start` | instrument ∈ {glass-chime, muted-pluck, soft-triangle, warm-bell} (default warm-bell) | decays | 1.72 s | unheard | +| `ding/task.acknowledge` | event `task.acknowledge` | instrument ∈ {glass-chime, muted-pluck, soft-triangle, warm-bell} (default warm-bell) | decays | 1.5 s | unheard | +| `ding/task.complete` | event `task.complete` | instrument ∈ {glass-chime, muted-pluck, soft-triangle, warm-bell} (default warm-bell) | decays | 1.72 s | unheard | +| `ding/task.error` | event `task.error` | instrument ∈ {glass-chime, muted-pluck, soft-triangle, warm-bell} (default warm-bell) | decays | 1.98 s | unheard | +| `ding/task.progress` | event `task.progress` | instrument ∈ {glass-chime, muted-pluck, soft-triangle, warm-bell} (default warm-bell) | decays | 1.5 s | unheard | +| `ding/user.spam` | event `user.spam` | instrument ∈ {glass-chime, muted-pluck, soft-triangle, warm-bell} (default warm-bell) | decays | 1.88 s | unheard | + +### Earcon workshop (one WAV per event) (4) + +| id | reacts to | params | behaviour | duration | listening | +|---|---|---|---|---|---| +| `earcon/warm-bell` | events: success, fail, warning, message, done, waiting | tempo 0.6..1.6 (default 1); transpose -12..12 (default 0); brightness -0.25..0.25 (default 0); decay 0.5..1.6 (default 1); level 0.1..0.9 (default 0.7) | decays | 1.45 s | unheard | +| `earcon/glass-chime` | events: success, fail, warning, message, done, waiting | tempo 0.6..1.6 (default 1); transpose -12..12 (default 0); brightness -0.25..0.25 (default 0); decay 0.5..1.6 (default 1); level 0.1..0.9 (default 0.7) | decays | 1.35 s | unheard | +| `earcon/soft-triangle` | events: success, fail, warning, message, done, waiting | tempo 0.6..1.6 (default 1); transpose -12..12 (default 0); brightness -0.25..0.25 (default 0); decay 0.5..1.6 (default 1); level 0.1..0.9 (default 0.7) | decays | 1.4 s | unheard | +| `earcon/muted-pluck` | events: success, fail, warning, message, done, waiting | tempo 0.6..1.6 (default 1); transpose -12..12 (default 0); brightness -0.25..0.25 (default 0); decay 0.5..1.6 (default 1); level 0.1..0.9 (default 0.7) | decays | 1.15 s | unheard | + +### Playground patches (one-shot and sustained synth sounds) (41) + +| id | reacts to | params | behaviour | duration | listening | +|---|---|---|---|---|---| +| `patch/808-clap` | start | none | decays | 3 s | unheard | +| `patch/808-cowbell` | start | none | decays | 3 s | unheard | +| `patch/808-hat` | start | none | decays | 3 s | unheard | +| `patch/808-kick` | start | none | decays | 3 s | unheard | +| `patch/808-snare` | start | none | decays | 3 s | unheard | +| `patch/808-tom` | start | none | decays | 3 s | unheard | +| `patch/advanced-alien-multivalve-graph` | start | alien/aperture 0..2 (default 0.85); alien/core/opening 0..1 (default 0.24); alien/core/pressure 0..1.5 (default 0.74); alien/side/opening 0..1 (default 0.3); alien/side/pressure 0..1.5 (default 0.52); curves/core_breath/depth 0..1 (default 0.9); curves/mouth_shape/depth 0..1 (default 0.8); curves/side_breath/depth 0..1 (default 0.9) | decays | 3 s | unheard | +| `patch/advanced-aurora-pad` | start | none | decays | 3 s | unheard | +| `patch/advanced-bird-syrinx` | start | bird/beak/opening 0..1.5 (default 0.95); bird/left/damping 0..2 (default 0.14); bird/left/flow_scale 0..4 (default 1.2); bird/left/load_coupling 0..2 (default 0.42); bird/left/mass 0.02..2 (default 0.32); bird/left/opening 0..1 (default 0.24); bird/left/pressure 0..1 (default 0.82); bird/left/rest_opening 0..1 (default 0.025); bird/left/stiffness 0..1 (default 0.025); bird/left/tension 0..1 (default 0.38); bird/left/tissue_loss 0..1 (default 0.18); bird/right/damping 0..2 (default 0.16); bird/right/flow_scale 0..4 (default 1.1); bird/right/load_coupling 0..2 (default 0.42); bird/right/mass 0.02..2 (default 0.34); bird/right/opening 0..1 (default 0.21); bird/right/pressure 0..1 (default 0.7); bird/right/rest_opening 0..1 (default 0.025); bird/right/stiffness 0..1 (default 0.03); bird/right/tension 0..1 (default 0.45); bird/right/tissue_loss 0..1 (default 0.2); curves/beak_opening/depth 0..1 (default 0.7); curves/left_opening/depth 0..1 (default 0.85); curves/left_pressure/depth 0..1 (default 1); curves/right_opening/depth 0..1 (default 0.85); curves/right_pressure/depth 0..1 (default 1) | decays | 3 s | unheard | +| `patch/advanced-bird-syrinx-graph` | start | bird/beak/opening 0..1.5 (default 0.92); bird/left/opening 0..1 (default 0.2); bird/left/pressure 0..1.5 (default 0.84); bird/left/tension 0..1 (default 0.46); bird/right/opening 0..1 (default 0.18); bird/right/pressure 0..1.5 (default 0.72); bird/right/tension 0..1 (default 0.52); curves/beak_gate/depth 0..1 (default 0.75); curves/left_air/depth 0..1 (default 0.95); curves/left_labium_gate/depth 0..1 (default 0.9); curves/right_air/depth 0..1 (default 0.95); curves/right_labium_gate/depth 0..1 (default 0.9) | decays | 3 s | unheard | +| `patch/advanced-glass-creature` | start | none | decays | 3 s | unheard | +| `patch/advanced-human-larynx-graph` | start | curves/breath_phrase/depth 0..1 (default 0.9); curves/fold_onset/depth 0..1 (default 0.8); curves/lip_vowel/depth 0..1 (default 0.65); human/constriction/diameter 0.02..3 (default 0.95); human/constriction/index 0..6 (default 4.8); human/fold/opening 0..1 (default 0.16); human/fold/tension 0..1 (default 0.58); human/lip/opening 0..2 (default 1.2); human/subglottal 0..1.5 (default 0.78); human/tongue/diameter 0.05..3 (default 1.25); human/tongue/index 0..6 (default 3.3) | decays | 3 s | unheard | +| `patch/advanced-machine-breath` | start | none | decays | 3 s | unheard | +| `patch/advanced-ritual-sequence` | start | none | sustained | 3 s | unheard | +| `patch/advanced-subtractive-drums` | start | none | decays | 3 s | unheard | +| `patch/advanced-syrinx-voice` | start | curves/beak_phrase/depth 0..1 (default 0.72); curves/left_phrase_opening/depth 0..1 (default 0.85); curves/left_phrase_pressure/depth 0..1 (default 0.92); curves/right_phrase_opening/depth 0..1 (default 0.85); curves/right_phrase_pressure/depth 0..1 (default 0.92); voice/beak/opening 0..1.5 (default 0.88); voice/left/opening 0..1 (default 0.23); voice/left/pressure 0..1.5 (default 0.78); voice/left/tension 0..1 (default 0.43); voice/right/opening 0..1 (default 0.19); voice/right/pressure 0..1.5 (default 0.66); voice/right/tension 0..1 (default 0.5) | decays | 3 s | unheard | +| `patch/bfxr-coin-spark` | start | none | decays | 3 s | unheard | +| `patch/bfxr-portal-chirp` | start | none | decays | 3 s | unheard | +| `patch/bfxr-shield-pop` | start | none | decays | 3 s | unheard | +| `patch/bfxr-ui-bloom` | start | none | sustained | 3 s | unheard | +| `patch/dx7-algorithm-32-additive-organ` | start | macro/drawbar 0..1 (default 0.78); macro/shimmer 0..0.3 (default 0.08) | decays | 3 s | unheard | +| `patch/dx7-algorithm-8-bright-pair` | start | macro/brightness 0..5 (default 2.6); macro/strike 0.02..0.6 (default 0.18) | decays | 3 s | unheard | +| `patch/dx7-public-domain-mc-mm-5-3` | start | none | decays | 3 s | unheard | +| `patch/dx7-public-domain-prc-synth1-calibrated` | start | none | decays | 3 s | unheard | +| `patch/examples-language-tour` | start | none | sustained | 3 s | unheard | +| `patch/fm-bell-bell` | start | none | decays | 3 s | unheard | +| `patch/fm-bell-chime` | start | none | decays | 3 s | unheard | +| `patch/fm-bell-coin` | start | none | decays | 3 s | unheard | +| `patch/fm-bell-gong` | start | none | decays | 3 s | unheard | +| `patch/sfxr-blip` | start | none | decays | 3 s | unheard | +| `patch/sfxr-classic-classic-sfxr-abstract-golf` | start | none | sustained | 3 s | unheard | +| `patch/sfxr-explosion` | start | none | sustained | 3 s | unheard | +| `patch/sfxr-hit` | start | none | decays | 3 s | unheard | +| `patch/sfxr-jump` | start | none | decays | 3 s | unheard | +| `patch/sfxr-laser` | start | none | decays | 3 s | unheard | +| `patch/sfxr-pickup` | start | none | decays | 3 s | unheard | +| `patch/sfxr-powerup` | start | none | sustained | 3 s | unheard | +| `patch/wobble-bass-growl` | start | none | decays | 3 s | unheard | +| `patch/wobble-bass-neuro` | start | none | decays | 3 s | unheard | +| `patch/wobble-bass-talker` | start | none | decays | 3 s | unheard | +| `patch/wobble-bass-yoy` | start | none | decays | 3 s | unheard | + + + +## Not on the shelf + +- `tools/aqua-trial`'s `thruster-trial.dsp` (the thruster plus a `noise` percent control): a listening-trial fixture, not an effect. +- `advanced/additive-pad` and `advanced/electro-drop-demo`: they lower to about 1.5 MB of Faust each and are not in the playground. +- The Dings daemon's native libfaust path (`-vec`): the shelf renders through faustwasm, the same host as `tools/aqua-feel`; the two + have not been diffed. +- Nothing is mapped to StreamPixels events, and no overlay-side player exists in this repo. diff --git a/tools/aqua-feel/package.json b/tools/aqua-feel/package.json index 9015ff1..6707152 100644 --- a/tools/aqua-feel/package.json +++ b/tools/aqua-feel/package.json @@ -3,5 +3,5 @@ "private": true, "type": "module", "description": "Headless feel meter for AquaSynth: renders every shipped patch and Ding offline and measures them. Measures; does not listen.", - "scripts": { "test": "node test.mjs", "feel": "node feel.mjs" } + "scripts": { "test": "node test.mjs", "feel": "node feel.mjs", "shelf": "node shelf.mjs build", "shelf:check": "node shelf.mjs check" } } diff --git a/tools/aqua-feel/shelf.json b/tools/aqua-feel/shelf.json new file mode 100644 index 0000000..fbbac7e --- /dev/null +++ b/tools/aqua-feel/shelf.json @@ -0,0 +1,2824 @@ +{ + "schema": "aquasynth.effects-shelf.v0", + "note": "Generated by tools/aqua-feel/shelf.mjs build. Nothing here was heard: every entry's listening status is 'unheard'. Commands run from the repo root.", + "sampleRate": 48000, + "entries": [ + { + "id": "patch/thruster", + "group": "thruster", + "name": "thruster", + "family": "thruster", + "source": "tools/aqua-playground/lowered/thruster.dsp", + "params": [ + { + "name": "rpm", + "kind": "slider", + "min": 300, + "max": 6000, + "default": 1200, + "step": 1 + } + ], + "reacts_to": { + "kind": "control", + "detail": "the rpm slider (300..6000, smoothed over 0.2 s): drive it from whatever number should make the thruster work harder. Nothing in the repo maps a stream metric to rpm." + }, + "behaviour": "sustained: still sounding at the end of the render window, runs until stopped", + "duration_s": 3, + "duration_note": "the render window, not the effect's length", + "render": { + "command": "node tools/aqua-feel/shelf.mjs render patch/thruster --out tools/aqua-feel/out/shelf/patch_thruster.wav", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/patch_thruster.wav", + "duration_s": 3 + } + ] + }, + "check_variants": [ + { + "params": { + "rpm": 300 + }, + "command": "node tools/aqua-feel/shelf.mjs render patch/thruster rpm=300 --out tools/aqua-feel/out/shelf/patch_thruster_rpm300.wav", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/patch_thruster_rpm300.wav", + "duration_s": 3 + } + ] + }, + { + "params": { + "rpm": 6000 + }, + "command": "node tools/aqua-feel/shelf.mjs render patch/thruster rpm=6000 --out tools/aqua-feel/out/shelf/patch_thruster_rpm6000.wav", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/patch_thruster_rpm6000.wav", + "duration_s": 3 + } + ] + } + ], + "listening": "unheard" + }, + { + "id": "patch/808-clap", + "group": "patch", + "name": "808-clap", + "family": "808", + "source": "tools/aqua-playground/lowered/808-clap.dsp (lowered from patches/808/clap.aqua)", + "params": [], + "reacts_to": { + "kind": "start", + "detail": "plays from the moment it is started; no gate, trigger or audio-feature input. Sliders, where listed, are live while it plays." + }, + "behaviour": "decays: dies away inside the render window", + "duration_s": 3, + "duration_note": "the render window, not the effect's length", + "render": { + "command": "node tools/aqua-feel/shelf.mjs render patch/808-clap --out tools/aqua-feel/out/shelf/patch_808-clap.wav", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/patch_808-clap.wav", + "duration_s": 3 + } + ] + }, + "listening": "unheard" + }, + { + "id": "patch/808-cowbell", + "group": "patch", + "name": "808-cowbell", + "family": "808", + "source": "tools/aqua-playground/lowered/808-cowbell.dsp (lowered from patches/808/cowbell.aqua)", + "params": [], + "reacts_to": { + "kind": "start", + "detail": "plays from the moment it is started; no gate, trigger or audio-feature input. Sliders, where listed, are live while it plays." + }, + "behaviour": "decays: dies away inside the render window", + "duration_s": 3, + "duration_note": "the render window, not the effect's length", + "render": { + "command": "node tools/aqua-feel/shelf.mjs render patch/808-cowbell --out tools/aqua-feel/out/shelf/patch_808-cowbell.wav", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/patch_808-cowbell.wav", + "duration_s": 3 + } + ] + }, + "listening": "unheard" + }, + { + "id": "patch/808-hat", + "group": "patch", + "name": "808-hat", + "family": "808", + "source": "tools/aqua-playground/lowered/808-hat.dsp (lowered from patches/808/hat.aqua)", + "params": [], + "reacts_to": { + "kind": "start", + "detail": "plays from the moment it is started; no gate, trigger or audio-feature input. Sliders, where listed, are live while it plays." + }, + "behaviour": "decays: dies away inside the render window", + "duration_s": 3, + "duration_note": "the render window, not the effect's length", + "render": { + "command": "node tools/aqua-feel/shelf.mjs render patch/808-hat --out tools/aqua-feel/out/shelf/patch_808-hat.wav", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/patch_808-hat.wav", + "duration_s": 3 + } + ] + }, + "listening": "unheard" + }, + { + "id": "patch/808-kick", + "group": "patch", + "name": "808-kick", + "family": "808", + "source": "tools/aqua-playground/lowered/808-kick.dsp (lowered from patches/808/kick.aqua)", + "params": [], + "reacts_to": { + "kind": "start", + "detail": "plays from the moment it is started; no gate, trigger or audio-feature input. Sliders, where listed, are live while it plays." + }, + "behaviour": "decays: dies away inside the render window", + "duration_s": 3, + "duration_note": "the render window, not the effect's length", + "render": { + "command": "node tools/aqua-feel/shelf.mjs render patch/808-kick --out tools/aqua-feel/out/shelf/patch_808-kick.wav", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/patch_808-kick.wav", + "duration_s": 3 + } + ] + }, + "listening": "unheard" + }, + { + "id": "patch/808-snare", + "group": "patch", + "name": "808-snare", + "family": "808", + "source": "tools/aqua-playground/lowered/808-snare.dsp (lowered from patches/808/snare.aqua)", + "params": [], + "reacts_to": { + "kind": "start", + "detail": "plays from the moment it is started; no gate, trigger or audio-feature input. Sliders, where listed, are live while it plays." + }, + "behaviour": "decays: dies away inside the render window", + "duration_s": 3, + "duration_note": "the render window, not the effect's length", + "render": { + "command": "node tools/aqua-feel/shelf.mjs render patch/808-snare --out tools/aqua-feel/out/shelf/patch_808-snare.wav", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/patch_808-snare.wav", + "duration_s": 3 + } + ] + }, + "listening": "unheard" + }, + { + "id": "patch/808-tom", + "group": "patch", + "name": "808-tom", + "family": "808", + "source": "tools/aqua-playground/lowered/808-tom.dsp (lowered from patches/808/tom.aqua)", + "params": [], + "reacts_to": { + "kind": "start", + "detail": "plays from the moment it is started; no gate, trigger or audio-feature input. Sliders, where listed, are live while it plays." + }, + "behaviour": "decays: dies away inside the render window", + "duration_s": 3, + "duration_note": "the render window, not the effect's length", + "render": { + "command": "node tools/aqua-feel/shelf.mjs render patch/808-tom --out tools/aqua-feel/out/shelf/patch_808-tom.wav", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/patch_808-tom.wav", + "duration_s": 3 + } + ] + }, + "listening": "unheard" + }, + { + "id": "patch/advanced-alien-multivalve-graph", + "group": "patch", + "name": "advanced-alien-multivalve-graph", + "family": "advanced", + "source": "tools/aqua-playground/lowered/advanced-alien-multivalve-graph.dsp (lowered from patches/advanced/alien-multivalve-graph.aqua)", + "params": [ + { + "name": "alien/aperture", + "kind": "slider", + "min": 0, + "max": 2, + "default": 0.85, + "step": 0.001 + }, + { + "name": "alien/core/opening", + "kind": "slider", + "min": 0, + "max": 1, + "default": 0.24, + "step": 0.001 + }, + { + "name": "alien/core/pressure", + "kind": "slider", + "min": 0, + "max": 1.5, + "default": 0.74, + "step": 0.001 + }, + { + "name": "alien/side/opening", + "kind": "slider", + "min": 0, + "max": 1, + "default": 0.3, + "step": 0.001 + }, + { + "name": "alien/side/pressure", + "kind": "slider", + "min": 0, + "max": 1.5, + "default": 0.52, + "step": 0.001 + }, + { + "name": "curves/core_breath/depth", + "kind": "slider", + "min": 0, + "max": 1, + "default": 0.9, + "step": 0.001 + }, + { + "name": "curves/mouth_shape/depth", + "kind": "slider", + "min": 0, + "max": 1, + "default": 0.8, + "step": 0.001 + }, + { + "name": "curves/side_breath/depth", + "kind": "slider", + "min": 0, + "max": 1, + "default": 0.9, + "step": 0.001 + } + ], + "reacts_to": { + "kind": "start", + "detail": "plays from the moment it is started; no gate, trigger or audio-feature input. Sliders, where listed, are live while it plays." + }, + "behaviour": "decays: dies away inside the render window", + "duration_s": 3, + "duration_note": "the render window, not the effect's length", + "render": { + "command": "node tools/aqua-feel/shelf.mjs render patch/advanced-alien-multivalve-graph --out tools/aqua-feel/out/shelf/patch_advanced-alien-multivalve-graph.wav", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/patch_advanced-alien-multivalve-graph.wav", + "duration_s": 3 + } + ] + }, + "listening": "unheard" + }, + { + "id": "patch/advanced-aurora-pad", + "group": "patch", + "name": "advanced-aurora-pad", + "family": "advanced", + "source": "tools/aqua-playground/lowered/advanced-aurora-pad.dsp (lowered from patches/advanced/aurora-pad.aqua)", + "params": [], + "reacts_to": { + "kind": "start", + "detail": "plays from the moment it is started; no gate, trigger or audio-feature input. Sliders, where listed, are live while it plays." + }, + "behaviour": "decays: dies away inside the render window", + "duration_s": 3, + "duration_note": "the render window, not the effect's length", + "render": { + "command": "node tools/aqua-feel/shelf.mjs render patch/advanced-aurora-pad --out tools/aqua-feel/out/shelf/patch_advanced-aurora-pad.wav", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/patch_advanced-aurora-pad.wav", + "duration_s": 3 + } + ] + }, + "listening": "unheard" + }, + { + "id": "patch/advanced-bird-syrinx", + "group": "patch", + "name": "advanced-bird-syrinx", + "family": "advanced", + "source": "tools/aqua-playground/lowered/advanced-bird-syrinx.dsp (lowered from patches/advanced/bird-syrinx.aqua)", + "params": [ + { + "name": "bird/beak/opening", + "kind": "slider", + "min": 0, + "max": 1.5, + "default": 0.95, + "step": 0.001 + }, + { + "name": "bird/left/damping", + "kind": "slider", + "min": 0, + "max": 2, + "default": 0.14, + "step": 0.001 + }, + { + "name": "bird/left/flow_scale", + "kind": "slider", + "min": 0, + "max": 4, + "default": 1.2, + "step": 0.001 + }, + { + "name": "bird/left/load_coupling", + "kind": "slider", + "min": 0, + "max": 2, + "default": 0.42, + "step": 0.001 + }, + { + "name": "bird/left/mass", + "kind": "slider", + "min": 0.02, + "max": 2, + "default": 0.32, + "step": 0.001 + }, + { + "name": "bird/left/opening", + "kind": "slider", + "min": 0, + "max": 1, + "default": 0.24, + "step": 0.001 + }, + { + "name": "bird/left/pressure", + "kind": "slider", + "min": 0, + "max": 1, + "default": 0.82, + "step": 0.001 + }, + { + "name": "bird/left/rest_opening", + "kind": "slider", + "min": 0, + "max": 1, + "default": 0.025, + "step": 0.001 + }, + { + "name": "bird/left/stiffness", + "kind": "slider", + "min": 0, + "max": 1, + "default": 0.025, + "step": 0.001 + }, + { + "name": "bird/left/tension", + "kind": "slider", + "min": 0, + "max": 1, + "default": 0.38, + "step": 0.001 + }, + { + "name": "bird/left/tissue_loss", + "kind": "slider", + "min": 0, + "max": 1, + "default": 0.18, + "step": 0.001 + }, + { + "name": "bird/right/damping", + "kind": "slider", + "min": 0, + "max": 2, + "default": 0.16, + "step": 0.001 + }, + { + "name": "bird/right/flow_scale", + "kind": "slider", + "min": 0, + "max": 4, + "default": 1.1, + "step": 0.001 + }, + { + "name": "bird/right/load_coupling", + "kind": "slider", + "min": 0, + "max": 2, + "default": 0.42, + "step": 0.001 + }, + { + "name": "bird/right/mass", + "kind": "slider", + "min": 0.02, + "max": 2, + "default": 0.34, + "step": 0.001 + }, + { + "name": "bird/right/opening", + "kind": "slider", + "min": 0, + "max": 1, + "default": 0.21, + "step": 0.001 + }, + { + "name": "bird/right/pressure", + "kind": "slider", + "min": 0, + "max": 1, + "default": 0.7, + "step": 0.001 + }, + { + "name": "bird/right/rest_opening", + "kind": "slider", + "min": 0, + "max": 1, + "default": 0.025, + "step": 0.001 + }, + { + "name": "bird/right/stiffness", + "kind": "slider", + "min": 0, + "max": 1, + "default": 0.03, + "step": 0.001 + }, + { + "name": "bird/right/tension", + "kind": "slider", + "min": 0, + "max": 1, + "default": 0.45, + "step": 0.001 + }, + { + "name": "bird/right/tissue_loss", + "kind": "slider", + "min": 0, + "max": 1, + "default": 0.2, + "step": 0.001 + }, + { + "name": "curves/beak_opening/depth", + "kind": "slider", + "min": 0, + "max": 1, + "default": 0.7, + "step": 0.001 + }, + { + "name": "curves/left_opening/depth", + "kind": "slider", + "min": 0, + "max": 1, + "default": 0.85, + "step": 0.001 + }, + { + "name": "curves/left_pressure/depth", + "kind": "slider", + "min": 0, + "max": 1, + "default": 1, + "step": 0.001 + }, + { + "name": "curves/right_opening/depth", + "kind": "slider", + "min": 0, + "max": 1, + "default": 0.85, + "step": 0.001 + }, + { + "name": "curves/right_pressure/depth", + "kind": "slider", + "min": 0, + "max": 1, + "default": 1, + "step": 0.001 + } + ], + "reacts_to": { + "kind": "start", + "detail": "plays from the moment it is started; no gate, trigger or audio-feature input. Sliders, where listed, are live while it plays." + }, + "behaviour": "decays: dies away inside the render window", + "duration_s": 3, + "duration_note": "the render window, not the effect's length", + "render": { + "command": "node tools/aqua-feel/shelf.mjs render patch/advanced-bird-syrinx --out tools/aqua-feel/out/shelf/patch_advanced-bird-syrinx.wav", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/patch_advanced-bird-syrinx.wav", + "duration_s": 3 + } + ] + }, + "listening": "unheard" + }, + { + "id": "patch/advanced-bird-syrinx-graph", + "group": "patch", + "name": "advanced-bird-syrinx-graph", + "family": "advanced", + "source": "tools/aqua-playground/lowered/advanced-bird-syrinx-graph.dsp (lowered from patches/advanced/bird-syrinx-graph.aqua)", + "params": [ + { + "name": "bird/beak/opening", + "kind": "slider", + "min": 0, + "max": 1.5, + "default": 0.92, + "step": 0.001 + }, + { + "name": "bird/left/opening", + "kind": "slider", + "min": 0, + "max": 1, + "default": 0.2, + "step": 0.001 + }, + { + "name": "bird/left/pressure", + "kind": "slider", + "min": 0, + "max": 1.5, + "default": 0.84, + "step": 0.001 + }, + { + "name": "bird/left/tension", + "kind": "slider", + "min": 0, + "max": 1, + "default": 0.46, + "step": 0.001 + }, + { + "name": "bird/right/opening", + "kind": "slider", + "min": 0, + "max": 1, + "default": 0.18, + "step": 0.001 + }, + { + "name": "bird/right/pressure", + "kind": "slider", + "min": 0, + "max": 1.5, + "default": 0.72, + "step": 0.001 + }, + { + "name": "bird/right/tension", + "kind": "slider", + "min": 0, + "max": 1, + "default": 0.52, + "step": 0.001 + }, + { + "name": "curves/beak_gate/depth", + "kind": "slider", + "min": 0, + "max": 1, + "default": 0.75, + "step": 0.001 + }, + { + "name": "curves/left_air/depth", + "kind": "slider", + "min": 0, + "max": 1, + "default": 0.95, + "step": 0.001 + }, + { + "name": "curves/left_labium_gate/depth", + "kind": "slider", + "min": 0, + "max": 1, + "default": 0.9, + "step": 0.001 + }, + { + "name": "curves/right_air/depth", + "kind": "slider", + "min": 0, + "max": 1, + "default": 0.95, + "step": 0.001 + }, + { + "name": "curves/right_labium_gate/depth", + "kind": "slider", + "min": 0, + "max": 1, + "default": 0.9, + "step": 0.001 + } + ], + "reacts_to": { + "kind": "start", + "detail": "plays from the moment it is started; no gate, trigger or audio-feature input. Sliders, where listed, are live while it plays." + }, + "behaviour": "decays: dies away inside the render window", + "duration_s": 3, + "duration_note": "the render window, not the effect's length", + "render": { + "command": "node tools/aqua-feel/shelf.mjs render patch/advanced-bird-syrinx-graph --out tools/aqua-feel/out/shelf/patch_advanced-bird-syrinx-graph.wav", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/patch_advanced-bird-syrinx-graph.wav", + "duration_s": 3 + } + ] + }, + "listening": "unheard" + }, + { + "id": "patch/advanced-glass-creature", + "group": "patch", + "name": "advanced-glass-creature", + "family": "advanced", + "source": "tools/aqua-playground/lowered/advanced-glass-creature.dsp (lowered from patches/advanced/glass-creature.aqua)", + "params": [], + "reacts_to": { + "kind": "start", + "detail": "plays from the moment it is started; no gate, trigger or audio-feature input. Sliders, where listed, are live while it plays." + }, + "behaviour": "decays: dies away inside the render window", + "duration_s": 3, + "duration_note": "the render window, not the effect's length", + "render": { + "command": "node tools/aqua-feel/shelf.mjs render patch/advanced-glass-creature --out tools/aqua-feel/out/shelf/patch_advanced-glass-creature.wav", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/patch_advanced-glass-creature.wav", + "duration_s": 3 + } + ] + }, + "listening": "unheard" + }, + { + "id": "patch/advanced-human-larynx-graph", + "group": "patch", + "name": "advanced-human-larynx-graph", + "family": "advanced", + "source": "tools/aqua-playground/lowered/advanced-human-larynx-graph.dsp (lowered from patches/advanced/human-larynx-graph.aqua)", + "params": [ + { + "name": "curves/breath_phrase/depth", + "kind": "slider", + "min": 0, + "max": 1, + "default": 0.9, + "step": 0.001 + }, + { + "name": "curves/fold_onset/depth", + "kind": "slider", + "min": 0, + "max": 1, + "default": 0.8, + "step": 0.001 + }, + { + "name": "curves/lip_vowel/depth", + "kind": "slider", + "min": 0, + "max": 1, + "default": 0.65, + "step": 0.001 + }, + { + "name": "human/constriction/diameter", + "kind": "slider", + "min": 0.02, + "max": 3, + "default": 0.95, + "step": 0.001 + }, + { + "name": "human/constriction/index", + "kind": "slider", + "min": 0, + "max": 6, + "default": 4.8, + "step": 0.001 + }, + { + "name": "human/fold/opening", + "kind": "slider", + "min": 0, + "max": 1, + "default": 0.16, + "step": 0.001 + }, + { + "name": "human/fold/tension", + "kind": "slider", + "min": 0, + "max": 1, + "default": 0.58, + "step": 0.001 + }, + { + "name": "human/lip/opening", + "kind": "slider", + "min": 0, + "max": 2, + "default": 1.2, + "step": 0.001 + }, + { + "name": "human/subglottal", + "kind": "slider", + "min": 0, + "max": 1.5, + "default": 0.78, + "step": 0.001 + }, + { + "name": "human/tongue/diameter", + "kind": "slider", + "min": 0.05, + "max": 3, + "default": 1.25, + "step": 0.001 + }, + { + "name": "human/tongue/index", + "kind": "slider", + "min": 0, + "max": 6, + "default": 3.3, + "step": 0.001 + } + ], + "reacts_to": { + "kind": "start", + "detail": "plays from the moment it is started; no gate, trigger or audio-feature input. Sliders, where listed, are live while it plays." + }, + "behaviour": "decays: dies away inside the render window", + "duration_s": 3, + "duration_note": "the render window, not the effect's length", + "render": { + "command": "node tools/aqua-feel/shelf.mjs render patch/advanced-human-larynx-graph --out tools/aqua-feel/out/shelf/patch_advanced-human-larynx-graph.wav", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/patch_advanced-human-larynx-graph.wav", + "duration_s": 3 + } + ] + }, + "listening": "unheard" + }, + { + "id": "patch/advanced-machine-breath", + "group": "patch", + "name": "advanced-machine-breath", + "family": "advanced", + "source": "tools/aqua-playground/lowered/advanced-machine-breath.dsp (lowered from patches/advanced/machine-breath.aqua)", + "params": [], + "reacts_to": { + "kind": "start", + "detail": "plays from the moment it is started; no gate, trigger or audio-feature input. Sliders, where listed, are live while it plays." + }, + "behaviour": "decays: dies away inside the render window", + "duration_s": 3, + "duration_note": "the render window, not the effect's length", + "render": { + "command": "node tools/aqua-feel/shelf.mjs render patch/advanced-machine-breath --out tools/aqua-feel/out/shelf/patch_advanced-machine-breath.wav", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/patch_advanced-machine-breath.wav", + "duration_s": 3 + } + ] + }, + "listening": "unheard" + }, + { + "id": "patch/advanced-ritual-sequence", + "group": "patch", + "name": "advanced-ritual-sequence", + "family": "advanced", + "source": "tools/aqua-playground/lowered/advanced-ritual-sequence.dsp (lowered from patches/advanced/ritual-sequence.aqua)", + "params": [], + "reacts_to": { + "kind": "start", + "detail": "plays from the moment it is started; no gate, trigger or audio-feature input. Sliders, where listed, are live while it plays." + }, + "behaviour": "sustained: still sounding at the end of the render window, runs until stopped", + "duration_s": 3, + "duration_note": "the render window, not the effect's length", + "render": { + "command": "node tools/aqua-feel/shelf.mjs render patch/advanced-ritual-sequence --out tools/aqua-feel/out/shelf/patch_advanced-ritual-sequence.wav", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/patch_advanced-ritual-sequence.wav", + "duration_s": 3 + } + ] + }, + "listening": "unheard" + }, + { + "id": "patch/advanced-subtractive-drums", + "group": "patch", + "name": "advanced-subtractive-drums", + "family": "advanced", + "source": "tools/aqua-playground/lowered/advanced-subtractive-drums.dsp (lowered from patches/advanced/subtractive-drums.aqua)", + "params": [], + "reacts_to": { + "kind": "start", + "detail": "plays from the moment it is started; no gate, trigger or audio-feature input. Sliders, where listed, are live while it plays." + }, + "behaviour": "decays: dies away inside the render window", + "duration_s": 3, + "duration_note": "the render window, not the effect's length", + "render": { + "command": "node tools/aqua-feel/shelf.mjs render patch/advanced-subtractive-drums --out tools/aqua-feel/out/shelf/patch_advanced-subtractive-drums.wav", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/patch_advanced-subtractive-drums.wav", + "duration_s": 3 + } + ] + }, + "listening": "unheard" + }, + { + "id": "patch/advanced-syrinx-voice", + "group": "patch", + "name": "advanced-syrinx-voice", + "family": "advanced", + "source": "tools/aqua-playground/lowered/advanced-syrinx-voice.dsp (lowered from patches/advanced/syrinx-voice.aqua)", + "params": [ + { + "name": "curves/beak_phrase/depth", + "kind": "slider", + "min": 0, + "max": 1, + "default": 0.72, + "step": 0.001 + }, + { + "name": "curves/left_phrase_opening/depth", + "kind": "slider", + "min": 0, + "max": 1, + "default": 0.85, + "step": 0.001 + }, + { + "name": "curves/left_phrase_pressure/depth", + "kind": "slider", + "min": 0, + "max": 1, + "default": 0.92, + "step": 0.001 + }, + { + "name": "curves/right_phrase_opening/depth", + "kind": "slider", + "min": 0, + "max": 1, + "default": 0.85, + "step": 0.001 + }, + { + "name": "curves/right_phrase_pressure/depth", + "kind": "slider", + "min": 0, + "max": 1, + "default": 0.92, + "step": 0.001 + }, + { + "name": "voice/beak/opening", + "kind": "slider", + "min": 0, + "max": 1.5, + "default": 0.88, + "step": 0.001 + }, + { + "name": "voice/left/opening", + "kind": "slider", + "min": 0, + "max": 1, + "default": 0.23, + "step": 0.001 + }, + { + "name": "voice/left/pressure", + "kind": "slider", + "min": 0, + "max": 1.5, + "default": 0.78, + "step": 0.001 + }, + { + "name": "voice/left/tension", + "kind": "slider", + "min": 0, + "max": 1, + "default": 0.43, + "step": 0.001 + }, + { + "name": "voice/right/opening", + "kind": "slider", + "min": 0, + "max": 1, + "default": 0.19, + "step": 0.001 + }, + { + "name": "voice/right/pressure", + "kind": "slider", + "min": 0, + "max": 1.5, + "default": 0.66, + "step": 0.001 + }, + { + "name": "voice/right/tension", + "kind": "slider", + "min": 0, + "max": 1, + "default": 0.5, + "step": 0.001 + } + ], + "reacts_to": { + "kind": "start", + "detail": "plays from the moment it is started; no gate, trigger or audio-feature input. Sliders, where listed, are live while it plays." + }, + "behaviour": "decays: dies away inside the render window", + "duration_s": 3, + "duration_note": "the render window, not the effect's length", + "render": { + "command": "node tools/aqua-feel/shelf.mjs render patch/advanced-syrinx-voice --out tools/aqua-feel/out/shelf/patch_advanced-syrinx-voice.wav", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/patch_advanced-syrinx-voice.wav", + "duration_s": 3 + } + ] + }, + "listening": "unheard" + }, + { + "id": "patch/bfxr-coin-spark", + "group": "patch", + "name": "bfxr-coin-spark", + "family": "bfxr", + "source": "tools/aqua-playground/lowered/bfxr-coin-spark.dsp (lowered from patches/bfxr/coin-spark.aqua)", + "params": [], + "reacts_to": { + "kind": "start", + "detail": "plays from the moment it is started; no gate, trigger or audio-feature input. Sliders, where listed, are live while it plays." + }, + "behaviour": "decays: dies away inside the render window", + "duration_s": 3, + "duration_note": "the render window, not the effect's length", + "render": { + "command": "node tools/aqua-feel/shelf.mjs render patch/bfxr-coin-spark --out tools/aqua-feel/out/shelf/patch_bfxr-coin-spark.wav", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/patch_bfxr-coin-spark.wav", + "duration_s": 3 + } + ] + }, + "listening": "unheard" + }, + { + "id": "patch/bfxr-portal-chirp", + "group": "patch", + "name": "bfxr-portal-chirp", + "family": "bfxr", + "source": "tools/aqua-playground/lowered/bfxr-portal-chirp.dsp (lowered from patches/bfxr/portal-chirp.aqua)", + "params": [], + "reacts_to": { + "kind": "start", + "detail": "plays from the moment it is started; no gate, trigger or audio-feature input. Sliders, where listed, are live while it plays." + }, + "behaviour": "decays: dies away inside the render window", + "duration_s": 3, + "duration_note": "the render window, not the effect's length", + "render": { + "command": "node tools/aqua-feel/shelf.mjs render patch/bfxr-portal-chirp --out tools/aqua-feel/out/shelf/patch_bfxr-portal-chirp.wav", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/patch_bfxr-portal-chirp.wav", + "duration_s": 3 + } + ] + }, + "listening": "unheard" + }, + { + "id": "patch/bfxr-shield-pop", + "group": "patch", + "name": "bfxr-shield-pop", + "family": "bfxr", + "source": "tools/aqua-playground/lowered/bfxr-shield-pop.dsp (lowered from patches/bfxr/shield-pop.aqua)", + "params": [], + "reacts_to": { + "kind": "start", + "detail": "plays from the moment it is started; no gate, trigger or audio-feature input. Sliders, where listed, are live while it plays." + }, + "behaviour": "decays: dies away inside the render window", + "duration_s": 3, + "duration_note": "the render window, not the effect's length", + "render": { + "command": "node tools/aqua-feel/shelf.mjs render patch/bfxr-shield-pop --out tools/aqua-feel/out/shelf/patch_bfxr-shield-pop.wav", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/patch_bfxr-shield-pop.wav", + "duration_s": 3 + } + ] + }, + "listening": "unheard" + }, + { + "id": "patch/bfxr-ui-bloom", + "group": "patch", + "name": "bfxr-ui-bloom", + "family": "bfxr", + "source": "tools/aqua-playground/lowered/bfxr-ui-bloom.dsp (lowered from patches/bfxr/ui-bloom.aqua)", + "params": [], + "reacts_to": { + "kind": "start", + "detail": "plays from the moment it is started; no gate, trigger or audio-feature input. Sliders, where listed, are live while it plays." + }, + "behaviour": "sustained: still sounding at the end of the render window, runs until stopped", + "duration_s": 3, + "duration_note": "the render window, not the effect's length", + "render": { + "command": "node tools/aqua-feel/shelf.mjs render patch/bfxr-ui-bloom --out tools/aqua-feel/out/shelf/patch_bfxr-ui-bloom.wav", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/patch_bfxr-ui-bloom.wav", + "duration_s": 3 + } + ] + }, + "listening": "unheard" + }, + { + "id": "patch/dx7-algorithm-32-additive-organ", + "group": "patch", + "name": "dx7-algorithm-32-additive-organ", + "family": "dx7", + "source": "tools/aqua-playground/lowered/dx7-algorithm-32-additive-organ.dsp (lowered from patches/dx7/algorithm-32-additive-organ.aqua)", + "params": [ + { + "name": "macro/drawbar", + "kind": "slider", + "min": 0, + "max": 1, + "default": 0.78, + "step": 0.001 + }, + { + "name": "macro/shimmer", + "kind": "slider", + "min": 0, + "max": 0.3, + "default": 0.08, + "step": 0.001 + } + ], + "reacts_to": { + "kind": "start", + "detail": "plays from the moment it is started; no gate, trigger or audio-feature input. Sliders, where listed, are live while it plays." + }, + "behaviour": "decays: dies away inside the render window", + "duration_s": 3, + "duration_note": "the render window, not the effect's length", + "render": { + "command": "node tools/aqua-feel/shelf.mjs render patch/dx7-algorithm-32-additive-organ --out tools/aqua-feel/out/shelf/patch_dx7-algorithm-32-additive-organ.wav", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/patch_dx7-algorithm-32-additive-organ.wav", + "duration_s": 3 + } + ] + }, + "listening": "unheard" + }, + { + "id": "patch/dx7-algorithm-8-bright-pair", + "group": "patch", + "name": "dx7-algorithm-8-bright-pair", + "family": "dx7", + "source": "tools/aqua-playground/lowered/dx7-algorithm-8-bright-pair.dsp (lowered from patches/dx7/algorithm-8-bright-pair.aqua)", + "params": [ + { + "name": "macro/brightness", + "kind": "slider", + "min": 0, + "max": 5, + "default": 2.6, + "step": 0.001 + }, + { + "name": "macro/strike", + "kind": "slider", + "min": 0.02, + "max": 0.6, + "default": 0.18, + "step": 0.001 + } + ], + "reacts_to": { + "kind": "start", + "detail": "plays from the moment it is started; no gate, trigger or audio-feature input. Sliders, where listed, are live while it plays." + }, + "behaviour": "decays: dies away inside the render window", + "duration_s": 3, + "duration_note": "the render window, not the effect's length", + "render": { + "command": "node tools/aqua-feel/shelf.mjs render patch/dx7-algorithm-8-bright-pair --out tools/aqua-feel/out/shelf/patch_dx7-algorithm-8-bright-pair.wav", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/patch_dx7-algorithm-8-bright-pair.wav", + "duration_s": 3 + } + ] + }, + "listening": "unheard" + }, + { + "id": "patch/dx7-public-domain-mc-mm-5-3", + "group": "patch", + "name": "dx7-public-domain-mc-mm-5-3", + "family": "dx7", + "source": "tools/aqua-playground/lowered/dx7-public-domain-mc-mm-5-3.dsp (lowered from patches/dx7/public-domain-mc-mm-5-3.aqua)", + "params": [], + "reacts_to": { + "kind": "start", + "detail": "plays from the moment it is started; no gate, trigger or audio-feature input. Sliders, where listed, are live while it plays." + }, + "behaviour": "decays: dies away inside the render window", + "duration_s": 3, + "duration_note": "the render window, not the effect's length", + "render": { + "command": "node tools/aqua-feel/shelf.mjs render patch/dx7-public-domain-mc-mm-5-3 --out tools/aqua-feel/out/shelf/patch_dx7-public-domain-mc-mm-5-3.wav", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/patch_dx7-public-domain-mc-mm-5-3.wav", + "duration_s": 3 + } + ] + }, + "listening": "unheard" + }, + { + "id": "patch/dx7-public-domain-prc-synth1-calibrated", + "group": "patch", + "name": "dx7-public-domain-prc-synth1-calibrated", + "family": "dx7", + "source": "tools/aqua-playground/lowered/dx7-public-domain-prc-synth1-calibrated.dsp (lowered from patches/dx7/public-domain/prc-synth1-calibrated.aqua)", + "params": [], + "reacts_to": { + "kind": "start", + "detail": "plays from the moment it is started; no gate, trigger or audio-feature input. Sliders, where listed, are live while it plays." + }, + "behaviour": "decays: dies away inside the render window", + "duration_s": 3, + "duration_note": "the render window, not the effect's length", + "render": { + "command": "node tools/aqua-feel/shelf.mjs render patch/dx7-public-domain-prc-synth1-calibrated --out tools/aqua-feel/out/shelf/patch_dx7-public-domain-prc-synth1-calibrated.wav", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/patch_dx7-public-domain-prc-synth1-calibrated.wav", + "duration_s": 3 + } + ] + }, + "listening": "unheard" + }, + { + "id": "patch/examples-language-tour", + "group": "patch", + "name": "examples-language-tour", + "family": "examples", + "source": "tools/aqua-playground/lowered/examples-language-tour.dsp (lowered from patches/examples/language-tour.aqua)", + "params": [], + "reacts_to": { + "kind": "start", + "detail": "plays from the moment it is started; no gate, trigger or audio-feature input. Sliders, where listed, are live while it plays." + }, + "behaviour": "sustained: still sounding at the end of the render window, runs until stopped", + "duration_s": 3, + "duration_note": "the render window, not the effect's length", + "render": { + "command": "node tools/aqua-feel/shelf.mjs render patch/examples-language-tour --out tools/aqua-feel/out/shelf/patch_examples-language-tour.wav", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/patch_examples-language-tour.wav", + "duration_s": 3 + } + ] + }, + "listening": "unheard" + }, + { + "id": "patch/fm-bell-bell", + "group": "patch", + "name": "fm-bell-bell", + "family": "fm", + "source": "tools/aqua-playground/lowered/fm-bell-bell.dsp (lowered from patches/fm-bell/bell.aqua)", + "params": [], + "reacts_to": { + "kind": "start", + "detail": "plays from the moment it is started; no gate, trigger or audio-feature input. Sliders, where listed, are live while it plays." + }, + "behaviour": "decays: dies away inside the render window", + "duration_s": 3, + "duration_note": "the render window, not the effect's length", + "render": { + "command": "node tools/aqua-feel/shelf.mjs render patch/fm-bell-bell --out tools/aqua-feel/out/shelf/patch_fm-bell-bell.wav", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/patch_fm-bell-bell.wav", + "duration_s": 3 + } + ] + }, + "listening": "unheard" + }, + { + "id": "patch/fm-bell-chime", + "group": "patch", + "name": "fm-bell-chime", + "family": "fm", + "source": "tools/aqua-playground/lowered/fm-bell-chime.dsp (lowered from patches/fm-bell/chime.aqua)", + "params": [], + "reacts_to": { + "kind": "start", + "detail": "plays from the moment it is started; no gate, trigger or audio-feature input. Sliders, where listed, are live while it plays." + }, + "behaviour": "decays: dies away inside the render window", + "duration_s": 3, + "duration_note": "the render window, not the effect's length", + "render": { + "command": "node tools/aqua-feel/shelf.mjs render patch/fm-bell-chime --out tools/aqua-feel/out/shelf/patch_fm-bell-chime.wav", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/patch_fm-bell-chime.wav", + "duration_s": 3 + } + ] + }, + "listening": "unheard" + }, + { + "id": "patch/fm-bell-coin", + "group": "patch", + "name": "fm-bell-coin", + "family": "fm", + "source": "tools/aqua-playground/lowered/fm-bell-coin.dsp (lowered from patches/fm-bell/coin.aqua)", + "params": [], + "reacts_to": { + "kind": "start", + "detail": "plays from the moment it is started; no gate, trigger or audio-feature input. Sliders, where listed, are live while it plays." + }, + "behaviour": "decays: dies away inside the render window", + "duration_s": 3, + "duration_note": "the render window, not the effect's length", + "render": { + "command": "node tools/aqua-feel/shelf.mjs render patch/fm-bell-coin --out tools/aqua-feel/out/shelf/patch_fm-bell-coin.wav", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/patch_fm-bell-coin.wav", + "duration_s": 3 + } + ] + }, + "listening": "unheard" + }, + { + "id": "patch/fm-bell-gong", + "group": "patch", + "name": "fm-bell-gong", + "family": "fm", + "source": "tools/aqua-playground/lowered/fm-bell-gong.dsp (lowered from patches/fm-bell/gong.aqua)", + "params": [], + "reacts_to": { + "kind": "start", + "detail": "plays from the moment it is started; no gate, trigger or audio-feature input. Sliders, where listed, are live while it plays." + }, + "behaviour": "decays: dies away inside the render window", + "duration_s": 3, + "duration_note": "the render window, not the effect's length", + "render": { + "command": "node tools/aqua-feel/shelf.mjs render patch/fm-bell-gong --out tools/aqua-feel/out/shelf/patch_fm-bell-gong.wav", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/patch_fm-bell-gong.wav", + "duration_s": 3 + } + ] + }, + "listening": "unheard" + }, + { + "id": "patch/sfxr-blip", + "group": "patch", + "name": "sfxr-blip", + "family": "sfxr", + "source": "tools/aqua-playground/lowered/sfxr-blip.dsp (lowered from patches/sfxr/blip.aqua)", + "params": [], + "reacts_to": { + "kind": "start", + "detail": "plays from the moment it is started; no gate, trigger or audio-feature input. Sliders, where listed, are live while it plays." + }, + "behaviour": "decays: dies away inside the render window", + "duration_s": 3, + "duration_note": "the render window, not the effect's length", + "render": { + "command": "node tools/aqua-feel/shelf.mjs render patch/sfxr-blip --out tools/aqua-feel/out/shelf/patch_sfxr-blip.wav", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/patch_sfxr-blip.wav", + "duration_s": 3 + } + ] + }, + "listening": "unheard" + }, + { + "id": "patch/sfxr-classic-classic-sfxr-abstract-golf", + "group": "patch", + "name": "sfxr-classic-classic-sfxr-abstract-golf", + "family": "sfxr", + "source": "tools/aqua-playground/lowered/sfxr-classic-classic-sfxr-abstract-golf.dsp (lowered from patches/sfxr/classic/classic-sfxr-abstract-golf.aqua)", + "params": [], + "reacts_to": { + "kind": "start", + "detail": "plays from the moment it is started; no gate, trigger or audio-feature input. Sliders, where listed, are live while it plays." + }, + "behaviour": "sustained: still sounding at the end of the render window, runs until stopped", + "duration_s": 3, + "duration_note": "the render window, not the effect's length", + "render": { + "command": "node tools/aqua-feel/shelf.mjs render patch/sfxr-classic-classic-sfxr-abstract-golf --out tools/aqua-feel/out/shelf/patch_sfxr-classic-classic-sfxr-abstract-golf.wav", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/patch_sfxr-classic-classic-sfxr-abstract-golf.wav", + "duration_s": 3 + } + ] + }, + "listening": "unheard" + }, + { + "id": "patch/sfxr-explosion", + "group": "patch", + "name": "sfxr-explosion", + "family": "sfxr", + "source": "tools/aqua-playground/lowered/sfxr-explosion.dsp (lowered from patches/sfxr/explosion.aqua)", + "params": [], + "reacts_to": { + "kind": "start", + "detail": "plays from the moment it is started; no gate, trigger or audio-feature input. Sliders, where listed, are live while it plays." + }, + "behaviour": "sustained: still sounding at the end of the render window, runs until stopped", + "duration_s": 3, + "duration_note": "the render window, not the effect's length", + "render": { + "command": "node tools/aqua-feel/shelf.mjs render patch/sfxr-explosion --out tools/aqua-feel/out/shelf/patch_sfxr-explosion.wav", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/patch_sfxr-explosion.wav", + "duration_s": 3 + } + ] + }, + "listening": "unheard" + }, + { + "id": "patch/sfxr-hit", + "group": "patch", + "name": "sfxr-hit", + "family": "sfxr", + "source": "tools/aqua-playground/lowered/sfxr-hit.dsp (lowered from patches/sfxr/hit.aqua)", + "params": [], + "reacts_to": { + "kind": "start", + "detail": "plays from the moment it is started; no gate, trigger or audio-feature input. Sliders, where listed, are live while it plays." + }, + "behaviour": "decays: dies away inside the render window", + "duration_s": 3, + "duration_note": "the render window, not the effect's length", + "render": { + "command": "node tools/aqua-feel/shelf.mjs render patch/sfxr-hit --out tools/aqua-feel/out/shelf/patch_sfxr-hit.wav", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/patch_sfxr-hit.wav", + "duration_s": 3 + } + ] + }, + "listening": "unheard" + }, + { + "id": "patch/sfxr-jump", + "group": "patch", + "name": "sfxr-jump", + "family": "sfxr", + "source": "tools/aqua-playground/lowered/sfxr-jump.dsp (lowered from patches/sfxr/jump.aqua)", + "params": [], + "reacts_to": { + "kind": "start", + "detail": "plays from the moment it is started; no gate, trigger or audio-feature input. Sliders, where listed, are live while it plays." + }, + "behaviour": "decays: dies away inside the render window", + "duration_s": 3, + "duration_note": "the render window, not the effect's length", + "render": { + "command": "node tools/aqua-feel/shelf.mjs render patch/sfxr-jump --out tools/aqua-feel/out/shelf/patch_sfxr-jump.wav", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/patch_sfxr-jump.wav", + "duration_s": 3 + } + ] + }, + "listening": "unheard" + }, + { + "id": "patch/sfxr-laser", + "group": "patch", + "name": "sfxr-laser", + "family": "sfxr", + "source": "tools/aqua-playground/lowered/sfxr-laser.dsp (lowered from patches/sfxr/laser.aqua)", + "params": [], + "reacts_to": { + "kind": "start", + "detail": "plays from the moment it is started; no gate, trigger or audio-feature input. Sliders, where listed, are live while it plays." + }, + "behaviour": "decays: dies away inside the render window", + "duration_s": 3, + "duration_note": "the render window, not the effect's length", + "render": { + "command": "node tools/aqua-feel/shelf.mjs render patch/sfxr-laser --out tools/aqua-feel/out/shelf/patch_sfxr-laser.wav", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/patch_sfxr-laser.wav", + "duration_s": 3 + } + ] + }, + "listening": "unheard" + }, + { + "id": "patch/sfxr-pickup", + "group": "patch", + "name": "sfxr-pickup", + "family": "sfxr", + "source": "tools/aqua-playground/lowered/sfxr-pickup.dsp (lowered from patches/sfxr/pickup.aqua)", + "params": [], + "reacts_to": { + "kind": "start", + "detail": "plays from the moment it is started; no gate, trigger or audio-feature input. Sliders, where listed, are live while it plays." + }, + "behaviour": "decays: dies away inside the render window", + "duration_s": 3, + "duration_note": "the render window, not the effect's length", + "render": { + "command": "node tools/aqua-feel/shelf.mjs render patch/sfxr-pickup --out tools/aqua-feel/out/shelf/patch_sfxr-pickup.wav", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/patch_sfxr-pickup.wav", + "duration_s": 3 + } + ] + }, + "listening": "unheard" + }, + { + "id": "patch/sfxr-powerup", + "group": "patch", + "name": "sfxr-powerup", + "family": "sfxr", + "source": "tools/aqua-playground/lowered/sfxr-powerup.dsp (lowered from patches/sfxr/powerup.aqua)", + "params": [], + "reacts_to": { + "kind": "start", + "detail": "plays from the moment it is started; no gate, trigger or audio-feature input. Sliders, where listed, are live while it plays." + }, + "behaviour": "sustained: still sounding at the end of the render window, runs until stopped", + "duration_s": 3, + "duration_note": "the render window, not the effect's length", + "render": { + "command": "node tools/aqua-feel/shelf.mjs render patch/sfxr-powerup --out tools/aqua-feel/out/shelf/patch_sfxr-powerup.wav", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/patch_sfxr-powerup.wav", + "duration_s": 3 + } + ] + }, + "listening": "unheard" + }, + { + "id": "patch/wobble-bass-growl", + "group": "patch", + "name": "wobble-bass-growl", + "family": "wobble", + "source": "tools/aqua-playground/lowered/wobble-bass-growl.dsp (lowered from patches/wobble-bass/growl.aqua)", + "params": [], + "reacts_to": { + "kind": "start", + "detail": "plays from the moment it is started; no gate, trigger or audio-feature input. Sliders, where listed, are live while it plays." + }, + "behaviour": "decays: dies away inside the render window", + "duration_s": 3, + "duration_note": "the render window, not the effect's length", + "render": { + "command": "node tools/aqua-feel/shelf.mjs render patch/wobble-bass-growl --out tools/aqua-feel/out/shelf/patch_wobble-bass-growl.wav", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/patch_wobble-bass-growl.wav", + "duration_s": 3 + } + ] + }, + "listening": "unheard" + }, + { + "id": "patch/wobble-bass-neuro", + "group": "patch", + "name": "wobble-bass-neuro", + "family": "wobble", + "source": "tools/aqua-playground/lowered/wobble-bass-neuro.dsp (lowered from patches/wobble-bass/neuro.aqua)", + "params": [], + "reacts_to": { + "kind": "start", + "detail": "plays from the moment it is started; no gate, trigger or audio-feature input. Sliders, where listed, are live while it plays." + }, + "behaviour": "decays: dies away inside the render window", + "duration_s": 3, + "duration_note": "the render window, not the effect's length", + "render": { + "command": "node tools/aqua-feel/shelf.mjs render patch/wobble-bass-neuro --out tools/aqua-feel/out/shelf/patch_wobble-bass-neuro.wav", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/patch_wobble-bass-neuro.wav", + "duration_s": 3 + } + ] + }, + "listening": "unheard" + }, + { + "id": "patch/wobble-bass-talker", + "group": "patch", + "name": "wobble-bass-talker", + "family": "wobble", + "source": "tools/aqua-playground/lowered/wobble-bass-talker.dsp (lowered from patches/wobble-bass/talker.aqua)", + "params": [], + "reacts_to": { + "kind": "start", + "detail": "plays from the moment it is started; no gate, trigger or audio-feature input. Sliders, where listed, are live while it plays." + }, + "behaviour": "decays: dies away inside the render window", + "duration_s": 3, + "duration_note": "the render window, not the effect's length", + "render": { + "command": "node tools/aqua-feel/shelf.mjs render patch/wobble-bass-talker --out tools/aqua-feel/out/shelf/patch_wobble-bass-talker.wav", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/patch_wobble-bass-talker.wav", + "duration_s": 3 + } + ] + }, + "listening": "unheard" + }, + { + "id": "patch/wobble-bass-yoy", + "group": "patch", + "name": "wobble-bass-yoy", + "family": "wobble", + "source": "tools/aqua-playground/lowered/wobble-bass-yoy.dsp (lowered from patches/wobble-bass/yoy.aqua)", + "params": [], + "reacts_to": { + "kind": "start", + "detail": "plays from the moment it is started; no gate, trigger or audio-feature input. Sliders, where listed, are live while it plays." + }, + "behaviour": "decays: dies away inside the render window", + "duration_s": 3, + "duration_note": "the render window, not the effect's length", + "render": { + "command": "node tools/aqua-feel/shelf.mjs render patch/wobble-bass-yoy --out tools/aqua-feel/out/shelf/patch_wobble-bass-yoy.wav", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/patch_wobble-bass-yoy.wav", + "duration_s": 3 + } + ] + }, + "listening": "unheard" + }, + { + "id": "ding/input.required", + "group": "ding", + "name": "input.required", + "family": "dings", + "source": "tools/aqua-feel/lowered-dings (lowered from src DingCatalog)", + "params": [ + { + "name": "instrument", + "kind": "enum", + "values": [ + "glass-chime", + "muted-pluck", + "soft-triangle", + "warm-bell" + ], + "default": "warm-bell", + "note": "no instrument is the shipped default in the catalog; warm-bell is the shelf's choice" + } + ], + "reacts_to": { + "kind": "event", + "event_id": "input.required", + "detail": "Ding event \"input.required\": Input requested. A Ding event is 2 note(s) at semitones 12, 5 above 261.6256 Hz. Mapping stream events onto Ding events is not done anywhere." + }, + "behaviour": "decays", + "duration_s": 1.76, + "duration_note": "1.5 s per note plus the last note's delay; command gain 0.6 is an assumption (aqua-feel README)", + "render": { + "command": "node tools/aqua-feel/shelf.mjs render ding/input.required instrument=warm-bell --out tools/aqua-feel/out/shelf/ding_input.required_warm-bell.wav", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/ding_input.required_warm-bell.wav", + "duration_s": 1.76 + } + ] + }, + "check_variants": [ + { + "params": { + "instrument": "glass-chime" + }, + "command": "node tools/aqua-feel/shelf.mjs render ding/input.required instrument=glass-chime --out tools/aqua-feel/out/shelf/ding_input.required_glass-chime.wav", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/ding_input.required_glass-chime.wav", + "duration_s": 1.76 + } + ] + }, + { + "params": { + "instrument": "muted-pluck" + }, + "command": "node tools/aqua-feel/shelf.mjs render ding/input.required instrument=muted-pluck --out tools/aqua-feel/out/shelf/ding_input.required_muted-pluck.wav", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/ding_input.required_muted-pluck.wav", + "duration_s": 1.76 + } + ] + }, + { + "params": { + "instrument": "soft-triangle" + }, + "command": "node tools/aqua-feel/shelf.mjs render ding/input.required instrument=soft-triangle --out tools/aqua-feel/out/shelf/ding_input.required_soft-triangle.wav", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/ding_input.required_soft-triangle.wav", + "duration_s": 1.76 + } + ] + } + ], + "listening": "unheard" + }, + { + "id": "ding/resource.limit", + "group": "ding", + "name": "resource.limit", + "family": "dings", + "source": "tools/aqua-feel/lowered-dings (lowered from src DingCatalog)", + "params": [ + { + "name": "instrument", + "kind": "enum", + "values": [ + "glass-chime", + "muted-pluck", + "soft-triangle", + "warm-bell" + ], + "default": "warm-bell", + "note": "no instrument is the shipped default in the catalog; warm-bell is the shelf's choice" + } + ], + "reacts_to": { + "kind": "event", + "event_id": "resource.limit", + "detail": "Ding event \"resource.limit\": Resource is holding. A Ding event is 3 note(s) at semitones 0, 0, 0 above 261.6256 Hz. Mapping stream events onto Ding events is not done anywhere." + }, + "behaviour": "decays", + "duration_s": 2.06, + "duration_note": "1.5 s per note plus the last note's delay; command gain 0.6 is an assumption (aqua-feel README)", + "render": { + "command": "node tools/aqua-feel/shelf.mjs render ding/resource.limit instrument=warm-bell --out tools/aqua-feel/out/shelf/ding_resource.limit_warm-bell.wav", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/ding_resource.limit_warm-bell.wav", + "duration_s": 2.06 + } + ] + }, + "check_variants": [ + { + "params": { + "instrument": "glass-chime" + }, + "command": "node tools/aqua-feel/shelf.mjs render ding/resource.limit instrument=glass-chime --out tools/aqua-feel/out/shelf/ding_resource.limit_glass-chime.wav", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/ding_resource.limit_glass-chime.wav", + "duration_s": 2.06 + } + ] + }, + { + "params": { + "instrument": "muted-pluck" + }, + "command": "node tools/aqua-feel/shelf.mjs render ding/resource.limit instrument=muted-pluck --out tools/aqua-feel/out/shelf/ding_resource.limit_muted-pluck.wav", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/ding_resource.limit_muted-pluck.wav", + "duration_s": 2.06 + } + ] + }, + { + "params": { + "instrument": "soft-triangle" + }, + "command": "node tools/aqua-feel/shelf.mjs render ding/resource.limit instrument=soft-triangle --out tools/aqua-feel/out/shelf/ding_resource.limit_soft-triangle.wav", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/ding_resource.limit_soft-triangle.wav", + "duration_s": 2.06 + } + ] + } + ], + "listening": "unheard" + }, + { + "id": "ding/session.end", + "group": "ding", + "name": "session.end", + "family": "dings", + "source": "tools/aqua-feel/lowered-dings (lowered from src DingCatalog)", + "params": [ + { + "name": "instrument", + "kind": "enum", + "values": [ + "glass-chime", + "muted-pluck", + "soft-triangle", + "warm-bell" + ], + "default": "warm-bell", + "note": "no instrument is the shipped default in the catalog; warm-bell is the shelf's choice" + } + ], + "reacts_to": { + "kind": "event", + "event_id": "session.end", + "detail": "Ding event \"session.end\": Session closure. A Ding event is 2 note(s) at semitones 7, 0 above 261.6256 Hz. Mapping stream events onto Ding events is not done anywhere." + }, + "behaviour": "decays", + "duration_s": 1.74, + "duration_note": "1.5 s per note plus the last note's delay; command gain 0.6 is an assumption (aqua-feel README)", + "render": { + "command": "node tools/aqua-feel/shelf.mjs render ding/session.end instrument=warm-bell --out tools/aqua-feel/out/shelf/ding_session.end_warm-bell.wav", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/ding_session.end_warm-bell.wav", + "duration_s": 1.74 + } + ] + }, + "check_variants": [ + { + "params": { + "instrument": "glass-chime" + }, + "command": "node tools/aqua-feel/shelf.mjs render ding/session.end instrument=glass-chime --out tools/aqua-feel/out/shelf/ding_session.end_glass-chime.wav", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/ding_session.end_glass-chime.wav", + "duration_s": 1.74 + } + ] + }, + { + "params": { + "instrument": "muted-pluck" + }, + "command": "node tools/aqua-feel/shelf.mjs render ding/session.end instrument=muted-pluck --out tools/aqua-feel/out/shelf/ding_session.end_muted-pluck.wav", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/ding_session.end_muted-pluck.wav", + "duration_s": 1.74 + } + ] + }, + { + "params": { + "instrument": "soft-triangle" + }, + "command": "node tools/aqua-feel/shelf.mjs render ding/session.end instrument=soft-triangle --out tools/aqua-feel/out/shelf/ding_session.end_soft-triangle.wav", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/ding_session.end_soft-triangle.wav", + "duration_s": 1.74 + } + ] + } + ], + "listening": "unheard" + }, + { + "id": "ding/session.start", + "group": "ding", + "name": "session.start", + "family": "dings", + "source": "tools/aqua-feel/lowered-dings (lowered from src DingCatalog)", + "params": [ + { + "name": "instrument", + "kind": "enum", + "values": [ + "glass-chime", + "muted-pluck", + "soft-triangle", + "warm-bell" + ], + "default": "warm-bell", + "note": "no instrument is the shipped default in the catalog; warm-bell is the shelf's choice" + } + ], + "reacts_to": { + "kind": "event", + "event_id": "session.start", + "detail": "Ding event \"session.start\": Opening welcome. A Ding event is 2 note(s) at semitones 0, 7 above 261.6256 Hz. Mapping stream events onto Ding events is not done anywhere." + }, + "behaviour": "decays", + "duration_s": 1.72, + "duration_note": "1.5 s per note plus the last note's delay; command gain 0.6 is an assumption (aqua-feel README)", + "render": { + "command": "node tools/aqua-feel/shelf.mjs render ding/session.start instrument=warm-bell --out tools/aqua-feel/out/shelf/ding_session.start_warm-bell.wav", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/ding_session.start_warm-bell.wav", + "duration_s": 1.72 + } + ] + }, + "check_variants": [ + { + "params": { + "instrument": "glass-chime" + }, + "command": "node tools/aqua-feel/shelf.mjs render ding/session.start instrument=glass-chime --out tools/aqua-feel/out/shelf/ding_session.start_glass-chime.wav", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/ding_session.start_glass-chime.wav", + "duration_s": 1.72 + } + ] + }, + { + "params": { + "instrument": "muted-pluck" + }, + "command": "node tools/aqua-feel/shelf.mjs render ding/session.start instrument=muted-pluck --out tools/aqua-feel/out/shelf/ding_session.start_muted-pluck.wav", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/ding_session.start_muted-pluck.wav", + "duration_s": 1.72 + } + ] + }, + { + "params": { + "instrument": "soft-triangle" + }, + "command": "node tools/aqua-feel/shelf.mjs render ding/session.start instrument=soft-triangle --out tools/aqua-feel/out/shelf/ding_session.start_soft-triangle.wav", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/ding_session.start_soft-triangle.wav", + "duration_s": 1.72 + } + ] + } + ], + "listening": "unheard" + }, + { + "id": "ding/task.acknowledge", + "group": "ding", + "name": "task.acknowledge", + "family": "dings", + "source": "tools/aqua-feel/lowered-dings (lowered from src DingCatalog)", + "params": [ + { + "name": "instrument", + "kind": "enum", + "values": [ + "glass-chime", + "muted-pluck", + "soft-triangle", + "warm-bell" + ], + "default": "warm-bell", + "note": "no instrument is the shipped default in the catalog; warm-bell is the shelf's choice" + } + ], + "reacts_to": { + "kind": "event", + "event_id": "task.acknowledge", + "detail": "Ding event \"task.acknowledge\": Quiet ongoing acknowledgement. A Ding event is 1 note(s) at semitones 7 above 261.6256 Hz. Mapping stream events onto Ding events is not done anywhere." + }, + "behaviour": "decays", + "duration_s": 1.5, + "duration_note": "1.5 s per note plus the last note's delay; command gain 0.6 is an assumption (aqua-feel README)", + "render": { + "command": "node tools/aqua-feel/shelf.mjs render ding/task.acknowledge instrument=warm-bell --out tools/aqua-feel/out/shelf/ding_task.acknowledge_warm-bell.wav", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/ding_task.acknowledge_warm-bell.wav", + "duration_s": 1.5 + } + ] + }, + "check_variants": [ + { + "params": { + "instrument": "glass-chime" + }, + "command": "node tools/aqua-feel/shelf.mjs render ding/task.acknowledge instrument=glass-chime --out tools/aqua-feel/out/shelf/ding_task.acknowledge_glass-chime.wav", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/ding_task.acknowledge_glass-chime.wav", + "duration_s": 1.5 + } + ] + }, + { + "params": { + "instrument": "muted-pluck" + }, + "command": "node tools/aqua-feel/shelf.mjs render ding/task.acknowledge instrument=muted-pluck --out tools/aqua-feel/out/shelf/ding_task.acknowledge_muted-pluck.wav", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/ding_task.acknowledge_muted-pluck.wav", + "duration_s": 1.5 + } + ] + }, + { + "params": { + "instrument": "soft-triangle" + }, + "command": "node tools/aqua-feel/shelf.mjs render ding/task.acknowledge instrument=soft-triangle --out tools/aqua-feel/out/shelf/ding_task.acknowledge_soft-triangle.wav", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/ding_task.acknowledge_soft-triangle.wav", + "duration_s": 1.5 + } + ] + } + ], + "listening": "unheard" + }, + { + "id": "ding/task.complete", + "group": "ding", + "name": "task.complete", + "family": "dings", + "source": "tools/aqua-feel/lowered-dings (lowered from src DingCatalog)", + "params": [ + { + "name": "instrument", + "kind": "enum", + "values": [ + "glass-chime", + "muted-pluck", + "soft-triangle", + "warm-bell" + ], + "default": "warm-bell", + "note": "no instrument is the shipped default in the catalog; warm-bell is the shelf's choice" + } + ], + "reacts_to": { + "kind": "event", + "event_id": "task.complete", + "detail": "Ding event \"task.complete\": Satisfying closure. A Ding event is 2 note(s) at semitones 7, 12 above 261.6256 Hz. Mapping stream events onto Ding events is not done anywhere." + }, + "behaviour": "decays", + "duration_s": 1.72, + "duration_note": "1.5 s per note plus the last note's delay; command gain 0.6 is an assumption (aqua-feel README)", + "render": { + "command": "node tools/aqua-feel/shelf.mjs render ding/task.complete instrument=warm-bell --out tools/aqua-feel/out/shelf/ding_task.complete_warm-bell.wav", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/ding_task.complete_warm-bell.wav", + "duration_s": 1.72 + } + ] + }, + "check_variants": [ + { + "params": { + "instrument": "glass-chime" + }, + "command": "node tools/aqua-feel/shelf.mjs render ding/task.complete instrument=glass-chime --out tools/aqua-feel/out/shelf/ding_task.complete_glass-chime.wav", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/ding_task.complete_glass-chime.wav", + "duration_s": 1.72 + } + ] + }, + { + "params": { + "instrument": "muted-pluck" + }, + "command": "node tools/aqua-feel/shelf.mjs render ding/task.complete instrument=muted-pluck --out tools/aqua-feel/out/shelf/ding_task.complete_muted-pluck.wav", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/ding_task.complete_muted-pluck.wav", + "duration_s": 1.72 + } + ] + }, + { + "params": { + "instrument": "soft-triangle" + }, + "command": "node tools/aqua-feel/shelf.mjs render ding/task.complete instrument=soft-triangle --out tools/aqua-feel/out/shelf/ding_task.complete_soft-triangle.wav", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/ding_task.complete_soft-triangle.wav", + "duration_s": 1.72 + } + ] + } + ], + "listening": "unheard" + }, + { + "id": "ding/task.error", + "group": "ding", + "name": "task.error", + "family": "dings", + "source": "tools/aqua-feel/lowered-dings (lowered from src DingCatalog)", + "params": [ + { + "name": "instrument", + "kind": "enum", + "values": [ + "glass-chime", + "muted-pluck", + "soft-triangle", + "warm-bell" + ], + "default": "warm-bell", + "note": "no instrument is the shipped default in the catalog; warm-bell is the shelf's choice" + } + ], + "reacts_to": { + "kind": "event", + "event_id": "task.error", + "detail": "Ding event \"task.error\": Gentle failure notice. A Ding event is 3 note(s) at semitones 7, 4, 0 above 261.6256 Hz. Mapping stream events onto Ding events is not done anywhere." + }, + "behaviour": "decays", + "duration_s": 1.98, + "duration_note": "1.5 s per note plus the last note's delay; command gain 0.6 is an assumption (aqua-feel README)", + "render": { + "command": "node tools/aqua-feel/shelf.mjs render ding/task.error instrument=warm-bell --out tools/aqua-feel/out/shelf/ding_task.error_warm-bell.wav", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/ding_task.error_warm-bell.wav", + "duration_s": 1.98 + } + ] + }, + "check_variants": [ + { + "params": { + "instrument": "glass-chime" + }, + "command": "node tools/aqua-feel/shelf.mjs render ding/task.error instrument=glass-chime --out tools/aqua-feel/out/shelf/ding_task.error_glass-chime.wav", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/ding_task.error_glass-chime.wav", + "duration_s": 1.98 + } + ] + }, + { + "params": { + "instrument": "muted-pluck" + }, + "command": "node tools/aqua-feel/shelf.mjs render ding/task.error instrument=muted-pluck --out tools/aqua-feel/out/shelf/ding_task.error_muted-pluck.wav", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/ding_task.error_muted-pluck.wav", + "duration_s": 1.98 + } + ] + }, + { + "params": { + "instrument": "soft-triangle" + }, + "command": "node tools/aqua-feel/shelf.mjs render ding/task.error instrument=soft-triangle --out tools/aqua-feel/out/shelf/ding_task.error_soft-triangle.wav", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/ding_task.error_soft-triangle.wav", + "duration_s": 1.98 + } + ] + } + ], + "listening": "unheard" + }, + { + "id": "ding/task.progress", + "group": "ding", + "name": "task.progress", + "family": "dings", + "source": "tools/aqua-feel/lowered-dings (lowered from src DingCatalog)", + "params": [ + { + "name": "instrument", + "kind": "enum", + "values": [ + "glass-chime", + "muted-pluck", + "soft-triangle", + "warm-bell" + ], + "default": "warm-bell", + "note": "no instrument is the shipped default in the catalog; warm-bell is the shelf's choice" + } + ], + "reacts_to": { + "kind": "event", + "event_id": "task.progress", + "detail": "Ding event \"task.progress\": Faint ignorable progress. A Ding event is 1 note(s) at semitones -5 above 261.6256 Hz. Mapping stream events onto Ding events is not done anywhere." + }, + "behaviour": "decays", + "duration_s": 1.5, + "duration_note": "1.5 s per note plus the last note's delay; command gain 0.6 is an assumption (aqua-feel README)", + "render": { + "command": "node tools/aqua-feel/shelf.mjs render ding/task.progress instrument=warm-bell --out tools/aqua-feel/out/shelf/ding_task.progress_warm-bell.wav", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/ding_task.progress_warm-bell.wav", + "duration_s": 1.5 + } + ] + }, + "check_variants": [ + { + "params": { + "instrument": "glass-chime" + }, + "command": "node tools/aqua-feel/shelf.mjs render ding/task.progress instrument=glass-chime --out tools/aqua-feel/out/shelf/ding_task.progress_glass-chime.wav", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/ding_task.progress_glass-chime.wav", + "duration_s": 1.5 + } + ] + }, + { + "params": { + "instrument": "muted-pluck" + }, + "command": "node tools/aqua-feel/shelf.mjs render ding/task.progress instrument=muted-pluck --out tools/aqua-feel/out/shelf/ding_task.progress_muted-pluck.wav", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/ding_task.progress_muted-pluck.wav", + "duration_s": 1.5 + } + ] + }, + { + "params": { + "instrument": "soft-triangle" + }, + "command": "node tools/aqua-feel/shelf.mjs render ding/task.progress instrument=soft-triangle --out tools/aqua-feel/out/shelf/ding_task.progress_soft-triangle.wav", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/ding_task.progress_soft-triangle.wav", + "duration_s": 1.5 + } + ] + } + ], + "listening": "unheard" + }, + { + "id": "ding/user.spam", + "group": "ding", + "name": "user.spam", + "family": "dings", + "source": "tools/aqua-feel/lowered-dings (lowered from src DingCatalog)", + "params": [ + { + "name": "instrument", + "kind": "enum", + "values": [ + "glass-chime", + "muted-pluck", + "soft-triangle", + "warm-bell" + ], + "default": "warm-bell", + "note": "no instrument is the shipped default in the catalog; warm-bell is the shelf's choice" + } + ], + "reacts_to": { + "kind": "event", + "event_id": "user.spam", + "detail": "Ding event \"user.spam\": Curt rate warning. A Ding event is 3 note(s) at semitones 9, 9, 9 above 261.6256 Hz. Mapping stream events onto Ding events is not done anywhere." + }, + "behaviour": "decays", + "duration_s": 1.88, + "duration_note": "1.5 s per note plus the last note's delay; command gain 0.6 is an assumption (aqua-feel README)", + "render": { + "command": "node tools/aqua-feel/shelf.mjs render ding/user.spam instrument=warm-bell --out tools/aqua-feel/out/shelf/ding_user.spam_warm-bell.wav", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/ding_user.spam_warm-bell.wav", + "duration_s": 1.88 + } + ] + }, + "check_variants": [ + { + "params": { + "instrument": "glass-chime" + }, + "command": "node tools/aqua-feel/shelf.mjs render ding/user.spam instrument=glass-chime --out tools/aqua-feel/out/shelf/ding_user.spam_glass-chime.wav", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/ding_user.spam_glass-chime.wav", + "duration_s": 1.88 + } + ] + }, + { + "params": { + "instrument": "muted-pluck" + }, + "command": "node tools/aqua-feel/shelf.mjs render ding/user.spam instrument=muted-pluck --out tools/aqua-feel/out/shelf/ding_user.spam_muted-pluck.wav", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/ding_user.spam_muted-pluck.wav", + "duration_s": 1.88 + } + ] + }, + { + "params": { + "instrument": "soft-triangle" + }, + "command": "node tools/aqua-feel/shelf.mjs render ding/user.spam instrument=soft-triangle --out tools/aqua-feel/out/shelf/ding_user.spam_soft-triangle.wav", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/ding_user.spam_soft-triangle.wav", + "duration_s": 1.88 + } + ] + } + ], + "listening": "unheard" + }, + { + "id": "earcon/warm-bell", + "group": "earcon", + "name": "warm-bell", + "family": "earcon-workshop", + "source": "tools/earcon-workshop/web/earcon.js (plain JS reimplementation; not the Dings .aqua scripts, so it does not sound like the Dings)", + "params": [ + { + "name": "tempo", + "kind": "slider", + "min": 0.6, + "max": 1.6, + "step": 0.01, + "default": 1 + }, + { + "name": "transpose", + "kind": "slider", + "min": -12, + "max": 12, + "step": 1, + "default": 0 + }, + { + "name": "brightness", + "kind": "slider", + "min": -0.25, + "max": 0.25, + "step": 0.01, + "default": 0 + }, + { + "name": "decay", + "kind": "slider", + "min": 0.5, + "max": 1.6, + "step": 0.01, + "default": 1 + }, + { + "name": "level", + "kind": "slider", + "min": 0.1, + "max": 0.9, + "step": 0.01, + "default": 0.7 + } + ], + "reacts_to": { + "kind": "event", + "events": [ + { + "event_id": "success", + "detail": "It worked: rising fifth then octave" + }, + { + "event_id": "fail", + "detail": "It broke: falling minor figure, low landing" + }, + { + "event_id": "warning", + "detail": "Look at this: tritone zigzag, three quick notes" + }, + { + "event_id": "message", + "detail": "Someone spoke: quick two-note lift high in the register" + }, + { + "event_id": "done", + "detail": "Finished: falling resolve onto the root, long tail" + }, + { + "event_id": "waiting", + "detail": "Needs you: quiet, sparse, slow low sway, three soft notes" + } + ], + "detail": "one WAV per event; the caller picks the file for the event it has. Voice: soft fundamental, restrained upper partial" + }, + "behaviour": "decays", + "duration_s": 1.45, + "duration_note": "longest of the six event WAVs at default sliders", + "render": { + "command": "node tools/earcon-workshop/cli.mjs warm-bell tools/aqua-feel/out/shelf/earcon/warm-bell", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/earcon/warm-bell/warm-bell-success.wav", + "duration_s": 0.77 + }, + { + "file": "tools/aqua-feel/out/shelf/earcon/warm-bell/warm-bell-fail.wav", + "duration_s": 0.87 + }, + { + "file": "tools/aqua-feel/out/shelf/earcon/warm-bell/warm-bell-warning.wav", + "duration_s": 0.77 + }, + { + "file": "tools/aqua-feel/out/shelf/earcon/warm-bell/warm-bell-message.wav", + "duration_s": 0.455 + }, + { + "file": "tools/aqua-feel/out/shelf/earcon/warm-bell/warm-bell-done.wav", + "duration_s": 1.17 + }, + { + "file": "tools/aqua-feel/out/shelf/earcon/warm-bell/warm-bell-waiting.wav", + "duration_s": 1.45 + } + ] + }, + "listening": "unheard" + }, + { + "id": "earcon/glass-chime", + "group": "earcon", + "name": "glass-chime", + "family": "earcon-workshop", + "source": "tools/earcon-workshop/web/earcon.js (plain JS reimplementation; not the Dings .aqua scripts, so it does not sound like the Dings)", + "params": [ + { + "name": "tempo", + "kind": "slider", + "min": 0.6, + "max": 1.6, + "step": 0.01, + "default": 1 + }, + { + "name": "transpose", + "kind": "slider", + "min": -12, + "max": 12, + "step": 1, + "default": 0 + }, + { + "name": "brightness", + "kind": "slider", + "min": -0.25, + "max": 0.25, + "step": 0.01, + "default": 0 + }, + { + "name": "decay", + "kind": "slider", + "min": 0.5, + "max": 1.6, + "step": 0.01, + "default": 1 + }, + { + "name": "level", + "kind": "slider", + "min": 0.1, + "max": 0.9, + "step": 0.01, + "default": 0.7 + } + ], + "reacts_to": { + "kind": "event", + "events": [ + { + "event_id": "success", + "detail": "It worked: rising fifth then octave" + }, + { + "event_id": "fail", + "detail": "It broke: falling minor figure, low landing" + }, + { + "event_id": "warning", + "detail": "Look at this: tritone zigzag, three quick notes" + }, + { + "event_id": "message", + "detail": "Someone spoke: quick two-note lift high in the register" + }, + { + "event_id": "done", + "detail": "Finished: falling resolve onto the root, long tail" + }, + { + "event_id": "waiting", + "detail": "Needs you: quiet, sparse, slow low sway, three soft notes" + } + ], + "detail": "one WAV per event; the caller picks the file for the event it has. Voice: clear and precise" + }, + "behaviour": "decays", + "duration_s": 1.35, + "duration_note": "longest of the six event WAVs at default sliders", + "render": { + "command": "node tools/earcon-workshop/cli.mjs glass-chime tools/aqua-feel/out/shelf/earcon/glass-chime", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/earcon/glass-chime/glass-chime-success.wav", + "duration_s": 0.67 + }, + { + "file": "tools/aqua-feel/out/shelf/earcon/glass-chime/glass-chime-fail.wav", + "duration_s": 0.77 + }, + { + "file": "tools/aqua-feel/out/shelf/earcon/glass-chime/glass-chime-warning.wav", + "duration_s": 0.67 + }, + { + "file": "tools/aqua-feel/out/shelf/earcon/glass-chime/glass-chime-message.wav", + "duration_s": 0.385 + }, + { + "file": "tools/aqua-feel/out/shelf/earcon/glass-chime/glass-chime-done.wav", + "duration_s": 1.03 + }, + { + "file": "tools/aqua-feel/out/shelf/earcon/glass-chime/glass-chime-waiting.wav", + "duration_s": 1.35 + } + ] + }, + "listening": "unheard" + }, + { + "id": "earcon/soft-triangle", + "group": "earcon", + "name": "soft-triangle", + "family": "earcon-workshop", + "source": "tools/earcon-workshop/web/earcon.js (plain JS reimplementation; not the Dings .aqua scripts, so it does not sound like the Dings)", + "params": [ + { + "name": "tempo", + "kind": "slider", + "min": 0.6, + "max": 1.6, + "step": 0.01, + "default": 1 + }, + { + "name": "transpose", + "kind": "slider", + "min": -12, + "max": 12, + "step": 1, + "default": 0 + }, + { + "name": "brightness", + "kind": "slider", + "min": -0.25, + "max": 0.25, + "step": 0.01, + "default": 0 + }, + { + "name": "decay", + "kind": "slider", + "min": 0.5, + "max": 1.6, + "step": 0.01, + "default": 1 + }, + { + "name": "level", + "kind": "slider", + "min": 0.1, + "max": 0.9, + "step": 0.01, + "default": 0.7 + } + ], + "reacts_to": { + "kind": "event", + "events": [ + { + "event_id": "success", + "detail": "It worked: rising fifth then octave" + }, + { + "event_id": "fail", + "detail": "It broke: falling minor figure, low landing" + }, + { + "event_id": "warning", + "detail": "Look at this: tritone zigzag, three quick notes" + }, + { + "event_id": "message", + "detail": "Someone spoke: quick two-note lift high in the register" + }, + { + "event_id": "done", + "detail": "Finished: falling resolve onto the root, long tail" + }, + { + "event_id": "waiting", + "detail": "Needs you: quiet, sparse, slow low sway, three soft notes" + } + ], + "detail": "one WAV per event; the caller picks the file for the event it has. Voice: rounded, calm" + }, + "behaviour": "decays", + "duration_s": 1.4, + "duration_note": "longest of the six event WAVs at default sliders", + "render": { + "command": "node tools/earcon-workshop/cli.mjs soft-triangle tools/aqua-feel/out/shelf/earcon/soft-triangle", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/earcon/soft-triangle/soft-triangle-success.wav", + "duration_s": 0.72 + }, + { + "file": "tools/aqua-feel/out/shelf/earcon/soft-triangle/soft-triangle-fail.wav", + "duration_s": 0.82 + }, + { + "file": "tools/aqua-feel/out/shelf/earcon/soft-triangle/soft-triangle-warning.wav", + "duration_s": 0.72 + }, + { + "file": "tools/aqua-feel/out/shelf/earcon/soft-triangle/soft-triangle-message.wav", + "duration_s": 0.42 + }, + { + "file": "tools/aqua-feel/out/shelf/earcon/soft-triangle/soft-triangle-done.wav", + "duration_s": 1.1 + }, + { + "file": "tools/aqua-feel/out/shelf/earcon/soft-triangle/soft-triangle-waiting.wav", + "duration_s": 1.4 + } + ] + }, + "listening": "unheard" + }, + { + "id": "earcon/muted-pluck", + "group": "earcon", + "name": "muted-pluck", + "family": "earcon-workshop", + "source": "tools/earcon-workshop/web/earcon.js (plain JS reimplementation; not the Dings .aqua scripts, so it does not sound like the Dings)", + "params": [ + { + "name": "tempo", + "kind": "slider", + "min": 0.6, + "max": 1.6, + "step": 0.01, + "default": 1 + }, + { + "name": "transpose", + "kind": "slider", + "min": -12, + "max": 12, + "step": 1, + "default": 0 + }, + { + "name": "brightness", + "kind": "slider", + "min": -0.25, + "max": 0.25, + "step": 0.01, + "default": 0 + }, + { + "name": "decay", + "kind": "slider", + "min": 0.5, + "max": 1.6, + "step": 0.01, + "default": 1 + }, + { + "name": "level", + "kind": "slider", + "min": 0.1, + "max": 0.9, + "step": 0.01, + "default": 0.7 + } + ], + "reacts_to": { + "kind": "event", + "events": [ + { + "event_id": "success", + "detail": "It worked: rising fifth then octave" + }, + { + "event_id": "fail", + "detail": "It broke: falling minor figure, low landing" + }, + { + "event_id": "warning", + "detail": "Look at this: tritone zigzag, three quick notes" + }, + { + "event_id": "message", + "detail": "Someone spoke: quick two-note lift high in the register" + }, + { + "event_id": "done", + "detail": "Finished: falling resolve onto the root, long tail" + }, + { + "event_id": "waiting", + "detail": "Needs you: quiet, sparse, slow low sway, three soft notes" + } + ], + "detail": "one WAV per event; the caller picks the file for the event it has. Voice: short, dry" + }, + "behaviour": "decays", + "duration_s": 1.15, + "duration_note": "longest of the six event WAVs at default sliders", + "render": { + "command": "node tools/earcon-workshop/cli.mjs muted-pluck tools/aqua-feel/out/shelf/earcon/muted-pluck", + "outputs": [ + { + "file": "tools/aqua-feel/out/shelf/earcon/muted-pluck/muted-pluck-success.wav", + "duration_s": 0.47 + }, + { + "file": "tools/aqua-feel/out/shelf/earcon/muted-pluck/muted-pluck-fail.wav", + "duration_s": 0.57 + }, + { + "file": "tools/aqua-feel/out/shelf/earcon/muted-pluck/muted-pluck-warning.wav", + "duration_s": 0.47 + }, + { + "file": "tools/aqua-feel/out/shelf/earcon/muted-pluck/muted-pluck-message.wav", + "duration_s": 0.245 + }, + { + "file": "tools/aqua-feel/out/shelf/earcon/muted-pluck/muted-pluck-done.wav", + "duration_s": 0.75 + }, + { + "file": "tools/aqua-feel/out/shelf/earcon/muted-pluck/muted-pluck-waiting.wav", + "duration_s": 1.15 + } + ] + }, + "listening": "unheard" + } + ] +} diff --git a/tools/aqua-feel/shelf.mjs b/tools/aqua-feel/shelf.mjs new file mode 100644 index 0000000..45bdea0 --- /dev/null +++ b/tools/aqua-feel/shelf.mjs @@ -0,0 +1,180 @@ +#!/usr/bin/env node +// The effects shelf: every sound AquaSynth can render headless today, as one machine-readable list (shelf.json) and a +// human page (SHELF.md), plus a check that runs each entry's render command and measures what it wrote. +// NOTHING HERE HEARS ANYTHING. `listening` stays "unheard" until a person edits it; the check proves a render is +// finite and not silent, which says nothing about whether it sounds good. +// Usage (from the repo root): +// node tools/aqua-feel/shelf.mjs build regenerate tools/aqua-feel/shelf.json and the table block of SHELF.md +// node tools/aqua-feel/shelf.mjs check [--only S] run every entry's render command, read the WAVs back, fail on silence/NaN/drift +// node tools/aqua-feel/shelf.mjs render ID [k=v ...] --out FILE.wav [--seconds N] render one patch or ding (what the entries call) +import { readFileSync, writeFileSync, mkdirSync, existsSync } from "node:fs"; +import { execSync } from "node:child_process"; +import { dirname, join, resolve } from "node:path"; +import { fileURLToPath } from "node:url"; +import { SR, SILENT_PEAK, samplePeak, measure } from "./metrics.js"; +import { loadRuntime, compile, renderOnce, renderDing, writeWav, readText, playground } from "./render.js"; +import { PATCH_SECONDS, DING_COMMAND_GAIN } from "./catalog.js"; +import { EVENTS, IDENTITIES, DEFAULT_PARAMS, PARAM_RANGES, renderFamily, fileName } from "../earcon-workshop/web/earcon.js"; + +const here = dirname(fileURLToPath(import.meta.url)), root = resolve(here, "../.."); +const SHELF_JSON = join(here, "shelf.json"), SHELF_MD = join(here, "SHELF.md"); +const OUT = "tools/aqua-feel/out/shelf"; // relative to the repo root, gitignored +const BEGIN = "", END = ""; +const dingsDir = join(here, "lowered-dings"); +const r3 = (x) => Math.round(x * 1000) / 1000; + +const args = process.argv.slice(2), cmd = args.shift(); +const flag = (n) => { const i = args.indexOf(n); if (i < 0) return undefined; return args.splice(i, 2)[1]; }; + +function controlsOf(entry) { // Faust UI -> shelf params; the ranges are the DSP's own declarations + const out = []; + const walk = (items) => { for (const it of items ?? []) { + if (it.items) walk(it.items); + else if (it.address) { + const name = it.label.replace(/^\//, ""); + if (/slider|nentry/i.test(it.type)) out.push({ name, kind: "slider", min: Number(it.min), max: Number(it.max), default: Number(it.init), step: Number(it.step) }); + else out.push({ name, kind: it.type }); // button / checkbox: reported as declared, not interpreted + } } }; + walk(JSON.parse(entry.g.factory.json).ui); + return out; +} + +async function build() { + const rt = await loadRuntime(), entries = []; + const dir = join(playground, "lowered"), cat = JSON.parse(readText(join(dir, "catalog.json"))); + for (const e of cat) { + const entry = await compile(rt, e.name, readText(join(dir, e.dsp))); + const params = controlsOf(entry), r = await renderOnce(entry, {}, PATCH_SECONDS), x = r.samples, tail = x.slice(x.length - Math.round(SR * 0.2)); + const m = measure(x), sustained = samplePeak(tail) >= 0.1 * samplePeak(x); + const isThruster = e.name === "thruster"; + entries.push({ + id: `patch/${e.name}`, group: isThruster ? "thruster" : "patch", name: e.name, family: e.name.split("-")[0], + source: e.kind === "faust" ? `tools/aqua-playground/lowered/${e.dsp}` : `tools/aqua-playground/lowered/${e.dsp} (lowered from patches/${e.origin})`, + params, + reacts_to: isThruster + ? { kind: "control", detail: "the rpm slider (300..6000, smoothed over 0.2 s): drive it from whatever number should make the thruster work harder. Nothing in the repo maps a stream metric to rpm." } + : { kind: "start", detail: "plays from the moment it is started; no gate, trigger or audio-feature input. Sliders, where listed, are live while it plays." }, + behaviour: sustained ? "sustained: still sounding at the end of the render window, runs until stopped" : "decays: dies away inside the render window", + duration_s: PATCH_SECONDS, duration_note: "the render window, not the effect's length", + render: { command: `node tools/aqua-feel/shelf.mjs render patch/${e.name} --out ${OUT}/patch_${e.name}.wav`, outputs: [{ file: `${OUT}/patch_${e.name}.wav`, duration_s: PATCH_SECONDS }] }, + ...(isThruster ? { check_variants: [300, 6000].map((rpm) => ({ params: { rpm }, command: `node tools/aqua-feel/shelf.mjs render patch/${e.name} rpm=${rpm} --out ${OUT}/patch_${e.name}_rpm${rpm}.wav`, outputs: [{ file: `${OUT}/patch_${e.name}_rpm${rpm}.wav`, duration_s: PATCH_SECONDS }] })) } : {}), + listening: "unheard", + }); + } + const d = JSON.parse(readText(join(dingsDir, "dings.json"))), instruments = d.instruments.map((i) => i.id), DEF_INS = "warm-bell"; + for (const ev of d.events) { + const dur = r3(d.noteSeconds + Math.max(...ev.notes.map((n) => n.delayMilliseconds)) / 1000); + const one = (ins) => ({ command: `node tools/aqua-feel/shelf.mjs render ding/${ev.id} instrument=${ins} --out ${OUT}/ding_${ev.id}_${ins}.wav`, outputs: [{ file: `${OUT}/ding_${ev.id}_${ins}.wav`, duration_s: dur }] }); + entries.push({ + id: `ding/${ev.id}`, group: "ding", name: ev.id, family: "dings", + source: "tools/aqua-feel/lowered-dings (lowered from src DingCatalog)", + params: [{ name: "instrument", kind: "enum", values: instruments, default: DEF_INS, note: `no instrument is the shipped default in the catalog; ${DEF_INS} is the shelf's choice` }], + reacts_to: { kind: "event", event_id: ev.id, detail: `Ding event "${ev.id}": ${ev.meaning}. A Ding event is ${ev.notes.length} note(s) at semitones ${ev.notes.map((n) => n.semitones).join(", ")} above ${d.instruments[0].rootFrequency} Hz. Mapping stream events onto Ding events is not done anywhere.` }, + behaviour: "decays", + duration_s: dur, duration_note: `${d.noteSeconds} s per note plus the last note's delay; command gain ${DING_COMMAND_GAIN} is an assumption (aqua-feel README)`, + render: one(DEF_INS), + check_variants: instruments.filter((i) => i !== DEF_INS).map((i) => ({ params: { instrument: i }, ...one(i) })), + listening: "unheard", + }); + } + for (const [id, ident] of Object.entries(IDENTITIES)) { + const fam = renderFamily(id), outDir = `${OUT}/earcon/${id}`; + entries.push({ + id: `earcon/${id}`, group: "earcon", name: id, family: "earcon-workshop", + source: "tools/earcon-workshop/web/earcon.js (plain JS reimplementation; not the Dings .aqua scripts, so it does not sound like the Dings)", + params: Object.entries(PARAM_RANGES).map(([name, [min, max, step]]) => ({ name, kind: "slider", min, max, step, default: DEFAULT_PARAMS[name] })), + reacts_to: { kind: "event", events: Object.entries(EVENTS).map(([k, v]) => ({ event_id: k, detail: v.meaning })), detail: "one WAV per event; the caller picks the file for the event it has. Voice: " + ident.note }, + behaviour: "decays", + duration_s: r3(Math.max(...fam.items.map((i) => i.durationMs)) / 1000), duration_note: "longest of the six event WAVs at default sliders", + render: { command: `node tools/earcon-workshop/cli.mjs ${id} ${outDir}`, outputs: fam.items.map((i) => ({ file: `${outDir}/${fileName(id, i.event)}`, duration_s: r3(i.durationMs / 1000) })) }, + listening: "unheard", + }); + } + return { schema: "aquasynth.effects-shelf.v0", note: "Generated by tools/aqua-feel/shelf.mjs build. Nothing here was heard: every entry's listening status is 'unheard'. Commands run from the repo root.", sampleRate: SR, entries }; +} + +function tableBlock(shelf) { + const rng = (p) => p.kind === "slider" ? `${p.name} ${p.min}..${p.max} (default ${p.default})` : p.kind === "enum" ? `${p.name} ∈ {${p.values.join(", ")}} (default ${p.default})` : `${p.name} (${p.kind})`; + const L = [BEGIN, ""]; + for (const [title, pick] of [["Thruster", (e) => e.group === "thruster"], ["Dings (event sounds)", (e) => e.group === "ding"], ["Earcon workshop (one WAV per event)", (e) => e.group === "earcon"], ["Playground patches (one-shot and sustained synth sounds)", (e) => e.group === "patch"]]) { + const es = shelf.entries.filter(pick); + L.push(`### ${title} (${es.length})`, "", "| id | reacts to | params | behaviour | duration | listening |", "|---|---|---|---|---|---|"); + for (const e of es) { + const re = e.reacts_to.kind === "event" && e.reacts_to.events ? `events: ${e.reacts_to.events.map((v) => v.event_id).join(", ")}` : e.reacts_to.kind === "event" ? `event \`${e.reacts_to.event_id}\`` : e.reacts_to.kind === "control" ? "control: rpm" : "start"; + L.push(`| \`${e.id}\` | ${re} | ${e.params.map(rng).join("; ") || "none"} | ${e.behaviour.split(":")[0]} | ${e.duration_s} s | ${e.listening} |`); + } + L.push(""); + } + L.push(END); + return L.join("\n"); +} + +function writeShelf(shelf) { + writeFileSync(SHELF_JSON, JSON.stringify(shelf, null, 1) + "\n"); + const md = readFileSync(SHELF_MD, "utf8"), a = md.indexOf(BEGIN), b = md.indexOf(END); + if (a < 0 || b < 0) throw new Error("SHELF.md has no generated block markers"); + writeFileSync(SHELF_MD, md.slice(0, a) + tableBlock(shelf) + md.slice(b + END.length)); +} + +// ---- render: what the entries' commands call ------------------------------------------------------------------------ +async function render() { + const out = flag("--out"), seconds = flag("--seconds"), [id, ...kv] = args; + if (!id || !out) { console.error("usage: shelf.mjs render ID [k=v ...] --out FILE.wav [--seconds N]"); process.exit(2); } + const params = Object.fromEntries(kv.map((s) => s.split("=")).map(([k, v]) => [k, isNaN(Number(v)) ? v : Number(v)])); + const rt = await loadRuntime(); let samples; + if (id.startsWith("patch/")) { + const name = id.slice(6), dir = join(playground, "lowered"), e = JSON.parse(readText(join(dir, "catalog.json"))).find((x) => x.name === name); + if (!e) { console.error(`no patch ${name}`); process.exit(2); } + samples = (await renderOnce(await compile(rt, name, readText(join(dir, e.dsp))), params, seconds ? Number(seconds) : PATCH_SECONDS)).samples; + } else if (id.startsWith("ding/")) { + const d = JSON.parse(readText(join(dingsDir, "dings.json"))), ev = d.events.find((x) => x.id === id.slice(5)), ins = d.instruments.find((x) => x.id === (params.instrument ?? "warm-bell")); + if (!ev || !ins) { console.error(`no ding event ${id.slice(5)} / instrument ${params.instrument}`); process.exit(2); } + samples = (await renderDing(rt, ins, readText(join(dingsDir, ins.dsp)), ev, { noteSeconds: d.noteSeconds, commandGain: DING_COMMAND_GAIN })).samples; + } else { console.error("render handles patch/ and ding/ ids; earcon entries use tools/earcon-workshop/cli.mjs"); process.exit(2); } + writeWav(resolve(out), samples); + console.log(`wrote ${out} (${(samples.length / SR).toFixed(3)} s)`); +} + +// ---- check ----------------------------------------------------------------------------------------------------------- +function readWav(path) { // PCM16 or float32 mono, as this repo's two writers produce + const b = readFileSync(path), v = new DataView(b.buffer, b.byteOffset, b.byteLength); + if (b.toString("latin1", 0, 4) !== "RIFF" || b.toString("latin1", 8, 12) !== "WAVE") throw new Error("not a RIFF/WAVE file"); + const tag = v.getUint16(20, true), ch = v.getUint16(22, true), sr = v.getUint32(24, true), bits = v.getUint16(34, true), n = v.getUint32(40, true) / (bits / 8); + if (ch !== 1 || !((tag === 1 && bits === 16) || (tag === 3 && bits === 32))) throw new Error(`unsupported wav tag ${tag} bits ${bits} channels ${ch}`); + const x = new Float32Array(n); + for (let i = 0; i < n; i++) x[i] = tag === 3 ? v.getFloat32(44 + i * 4, true) : v.getInt16(44 + i * 2, true) / 32768; + return { sr, x }; +} + +async function check() { + const only = flag("--only"), problems = [], rows = []; + mkdirSync(join(root, OUT), { recursive: true }); + const fresh = await build(), onDisk = existsSync(SHELF_JSON) ? readFileSync(SHELF_JSON, "utf8") : ""; + if (onDisk !== JSON.stringify(fresh, null, 1) + "\n") problems.push("shelf.json is stale: run `node tools/aqua-feel/shelf.mjs build`"); + const md = readFileSync(SHELF_MD, "utf8"), a = md.indexOf(BEGIN), b = md.indexOf(END); + if (a < 0 || md.slice(a, b + END.length) !== tableBlock(fresh)) problems.push("SHELF.md table block is stale: run `node tools/aqua-feel/shelf.mjs build`"); + for (const e of fresh.entries.filter((x) => !only || x.id.includes(only))) { + if (e.listening !== "unheard") problems.push(`${e.id}: listening is '${e.listening}'; this check cannot confirm that`); + for (const r of [e.render, ...(e.check_variants ?? [])]) { + try { + execSync(r.command, { cwd: root, stdio: ["ignore", "pipe", "pipe"] }); + for (const o of r.outputs) { + const { sr, x } = readWav(join(root, o.file)), peak = samplePeak(x), dur = x.length / sr; + if (sr !== SR) throw new Error(`${o.file}: sample rate ${sr}`); + if (!x.every(Number.isFinite)) throw new Error(`${o.file}: non-finite samples`); + if (peak < SILENT_PEAK) throw new Error(`${o.file}: silent (peak ${peak}, floor ${SILENT_PEAK.toFixed(6)})`); + if (Math.abs(dur - o.duration_s) > 0.01) throw new Error(`${o.file}: ${dur.toFixed(3)} s, shelf says ${o.duration_s} s`); + rows.push(`ok ${o.file.replace(OUT + "/", "")} peak ${(20 * Math.log10(peak)).toFixed(1)} dBFS ${dur.toFixed(3)} s [${r.command}]`); + } + } catch (err) { problems.push(`${e.id}: ${r.command}\n ${String(err.message ?? err).split("\n")[0]}`); } + } + } + console.log(rows.join("\n")); + console.log(`\n${rows.length} rendered file(s) checked across ${fresh.entries.filter((x) => !only || x.id.includes(only)).length} entries. Nothing here was heard.`); + if (problems.length) { console.log(`\nFAIL (${problems.length}):\n` + problems.map((p) => " " + p).join("\n")); process.exit(1); } + console.log("PASS: every render command ran, every WAV is finite, not silent, and as long as the shelf says; shelf.json and SHELF.md are current."); +} + +const cmds = { build: async () => { const s = await build(); writeShelf(s); console.log(`wrote ${SHELF_JSON}: ${s.entries.length} entries`); }, render, check }; +if (!cmds[cmd]) { console.error(readFileSync(fileURLToPath(import.meta.url), "utf8").split("\n").slice(1, 9).join("\n")); process.exit(2); } +await cmds[cmd]();