From 5c215d655de23b7218b849da3d7ddb4705aeb7d3 Mon Sep 17 00:00:00 2001 From: MelekTaus Date: Tue, 13 Oct 2026 11:09:01 +0200 Subject: [PATCH] Instruments: the Acid node for 303 bass lines (#421) - A new section Acid with its knobs, accent from velocity 0.9 and slide for notes that touch or overlap. - The node table and the presets list Acid and Acid Bass. - Development counts the 3 new checks in e2e 34. Co-Authored-By: Claude Opus 5.5 --- Development.md | 2 +- Instruments.md | 68 +++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 68 insertions(+), 2 deletions(-) diff --git a/Development.md b/Development.md index 56004a4..874fe73 100644 --- a/Development.md +++ b/Development.md @@ -21,7 +21,7 @@ php tests/php/releases.test.php # the release stor php tests/php/files.test.php # uploaded files in a folder per account (#344), the same way php tests/php/videos.test.php # the video store, its queue and the worker (#402), with the # real ffmpeg: the CI image and game-maker-video have it -node tools/seed-e2e.mjs && node tools/e2e.mjs # 2062 editor checks, screenshots in /tmp/gm-e2e-*.png +node tools/seed-e2e.mjs && node tools/e2e.mjs # 2065 editor checks, screenshots in /tmp/gm-e2e-*.png GM_STEPS=20 node tools/e2e.mjs # or 1-12, or 6,20 — a subset while working on one step ./e2e.sh start [GM_STEPS] # the same run detached, see below ./e2e.sh status # live progress, or the last run's result diff --git a/Instruments.md b/Instruments.md index a72e4ee..ebe1050 100644 --- a/Instruments.md +++ b/Instruments.md @@ -1,6 +1,7 @@ An **instrument** (**+ → Instrument**, #331) makes a note a sound. It is a node graph like a [sound FX](Sounds#sound-fx): **Notes** nodes bring the note in, a **Sample** plays a sound for it -or a **Chip** makes one the way old game consoles did (#329), the effects of a sound FX shape it +or a **Chip** makes one the way old game consoles did (#329), an **Acid** plays a bass line as the +Roland TB-303 does (#421), the effects of a sound FX shape it and the **Output** is what is heard. It is the first piece of the music tools planned in #330: a [pattern](Patterns) (#333) plays one, and a [song](Songs) (#334) lays patterns out. A behavior plays one with **Play note**, and the tab plays it from its keys. @@ -22,6 +23,7 @@ A at 440 Hz, 127 the highest. A note is named with its octave after it and no da | **Notes** | Where the notes come in. `any` triggers what it is connected to for every note from **From** to **To**. `note` is the number of the note played, `frequency` its pitch in Hz (`440 * 2^((note - 69) / 12)`), `velocity` how hard it is struck, 0 to 1. With **Single notes** there is one trigger output for every note in the range as well, and each can have a **name** of its own (*Name of C2* in the inspector): the output shows it, and so do the keys of the [piano roll](Patterns#the-pattern-tab). | | **Sample** | Plays a sound asset when its `trigger` is on. With **Follow note** (on by default) it plays higher or lower by the distance from **Root**, the note it sounds as it is (C4 by default), and **keeps its length** — it is played by the same worklet as a Pitch (#317). Off, every note plays it as it is, as for a drum. **Play** says how it is played while the note is held and once it is let go (table below). **Loop start** and **Loop end** are in seconds, 0 at the end being the end of the sound, counted in the stretch of the [clip](Sounds#clips) when it plays one. The volume of the sound asset counts. | | **Chip** | Makes a raw wave for every note that triggers it, the way sfxr makes its sounds: square, triangle, saw, sine or noise, with a slide, vibrato, an arpeggio and repeat. It needs no sound file. See [Chips](#chips). | +| **Acid** | A bass line in the way of the Roland TB-303: a saw or a square through a resonant low-pass that saturates, swept open on every note, with accent and slide. It needs no sound file. See [Acid](#acid). | | **Parameters** | The instrument's own parameters, each a number output with a default — like the parameters of a sound FX's Input. One per instrument. | | **Sound FX** | Sends the sound through a sound FX asset, as if it were the sound at the FX's Input. Every parameter of that FX is an input here; one left open is the FX's default. The node is titled after the FX, and a double click opens it. | | **Envelope** | Shapes a note as it is played: **Attack**, **Decay** and **Release** in seconds, **Sustain** from 0 to 1. On the way of the sound it is its volume; its output `value` moves a number with the same curve, from **From** to **To**. See [Envelopes](#envelopes). | @@ -260,6 +262,69 @@ from 0 to 1, the Chip counts in Hz, semitones and seconds. a note of 0.2 s through an Envelope with a decay of 0.1 s and sustain 0 was gone 0.26 s after it started, read every 150 ms. +## Acid + +An **Acid** (#421) plays a bass line the way the Roland TB-303 does: one oscillator, a resonant +low-pass that squeals and saturates, a sweep that opens it on every note, accent and slide. Notes +`any` into its `trigger`, its `out` to the Output. It always plays the pitch of the note. + +| Input | Default | What it does | +| --- | --- | --- | +| **Wave** (setting) | Saw | *Saw* or *Square*, band-limited (PolyBLEP), so a high note does not alias. | +| **Tuning (st)** | 0 | Semitones off the note, -12 to 12. | +| **Cutoff (Hz)** | 400 | Where the filter rests, 30 Hz to 12 kHz. | +| **Resonance** | 0.7 | How sharply it rings at the cutoff, 0 to 1. At 1 it is just short of whistling by itself. It takes some of the bass, as the 303's does. | +| **Env mod** | 0.5 | How far every note opens the filter: up to four octaves above the cutoff at 1. | +| **Decay (s)** | 0.5 | How long the filter takes to fall back, 0.2 to 2 s (to 1 % of the sweep). Grey while *Env mod* is 0. | +| **Accent** | 0.6 | How much an accented note stands out, 0 to 1. | +| **Slide time (s)** | 0.06 | How long a slide takes to all but reach its note (95 %). The 303's is about 60 ms. | + +- **Accent comes from the velocity:** a note at **0.9 or more** is accented. The piano roll strikes + at 0.8 unless told otherwise, so a plain note is not. An accented note is up to twice as loud + (+6 dB), its sweep falls in 0.2 s whatever *Decay* says, and the filter opens further, up to two + octaves more with *Accent* and *Resonance* at full. That extra goes through a "capacitor" that + charges with a time constant of 20 ms and empties with one of 0.25 s, as the 303's accent + circuit does: accents a sixteenth apart start each one from what the last left, so a run of + them climbs. +- **Slide:** a note that starts while the note before it on the same Acid still plays, or right + where it ends (within 2 ms), **slides**: the pitch glides there in *Slide time* and nothing is + struck anew, so the sweep and the volume run on. The note before is silent from the first sample + of the new one. Notes that start at the same moment do not slide, they all play. In the piano + roll a slide is two notes that touch or overlap. On the keys it is a key struck while the one + before is still held. +- **Its own volume:** the sound rises in 3 ms and dies away slowly (a time constant of 1.6 s) while + the note is held, and ends with the note, faded out in 10 ms. An **Envelope** behind it starts over + with every note, a slide too, so it is better left out. +- **On the audio thread** (AudioParams): *Cutoff*, *Resonance*, *Env mod*, *Decay* and *Accent*. An + Envelope can move *Cutoff*, `Set sound FX parameters` reaches any of them fed by a parameter. A + **Pitch** behind it moves its frequency. *Wave*, *Tuning* and *Slide time* are fixed when the note + starts. +- **How it is made:** a worklet per note, in the same module as the Chip. The oscillator and the + filter run at twice the rate and are averaged down. The filter is four one-pole low-passes in a + row with feedback, solved without a delay in the loop (Zavalishin's topology-preserving + transform), the signal into it saturated by `tanh`. The notes of one Acid that slide into each + other share one synth on the audio thread: it runs once per block, and each note hears the part of + the block that is its own, so it makes no difference which note the audio thread runs first. +- **The node is a device** (#421), 520x280, in the brushed silver of the 303. The inputs are on the + left, `out` on the right: + - a **button for each wave** at the top, the one playing lit in orange; + - a dark screen, **Filter over a note**: the filter where it rests in dull green, at the top of a + plain note's sweep in acid green, the room between them lit faintly, 20 Hz to 20 kHz, +24 to + -48 dB. It says where it rests and how far a note sweeps it; the bezel says how far a full + accent takes it; + - a **chrome knob** for every number, grouped *Filter* (cutoff, resonance, env mod, decay) and + *Note* (tuning, accent, slide). A drag is one undo step, a double-click goes back to the + default. The tuning has 0 straight up. + + The screen is drawn from the settings, not listened to. The + [presets](#presets-randomize-and-mutate) give an Acid three columns of room; Randomize and + Mutate leave it as it is. +- **Measured** (2026-10-13, e2e 34, Chrome offline on the Windows runner): two notes on one line, + the second sliding in at 0.1 s. The first was heard from sample 0 to 4799, the second from 4800 + to the end. Where it took over, the sound of both together moved by 0.0012 from one sample to + the next, the largest step anywhere else was 0.10. Live, of three notes at 120 BPM the second, + struck where the first ended, slid, the third after half a second's gap did not. + ## The Instrument tab The graph, and below it **the keys**: all 128 notes, the ones that sound in white and black, the @@ -333,6 +398,7 @@ The instruments, all on every note unless the table says otherwise: | *Pluck* | Square at duty 0.3 → Envelope → Low-pass that snaps shut from 6 kHz to 600 Hz | dies away | | *Triangle Bass* | The triangle of the NES → Envelope at full sustain | held | | *Pluck Bass* | Saw → Envelope → resonant Low-pass that snaps open to 2.4 kHz and falls back towards 180 Hz | held | +| *Acid Bass* | [Acid](#acid), a saw at cutoff 300 Hz, resonance 0.8, env mod 0.6, decay 0.4 s, accent 0.7 → Delay, a dotted eighth, a little of it | dies away slowly, slides | | *Drum Kit* | *Single notes* 36 to 46: Kick on C2, Snare on D2, Closed hat on F#2, Open hat on A#2, as in General MIDI | each ends by itself | The kick is a sine that drops from 160 Hz until it is below 30 Hz, the snare a falling triangle and