Describe the Envelope and the Filter #335

- Instruments: a new section Envelopes (shape, end of a note, the
  value output and what it fits, a filter sweep, Stop sound, the
  measured curve), the Envelope in the node table, the end of a note
  under an Envelope, Play note with Let ring, Not yet.
- Sounds: the Filter node and its ranges, Let ring on a note with an
  Envelope.
- Home: the Envelope in the line of Instruments.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
adminandClaude Opus 5.5 committed 2026-10-06 13:55:00 +02:00
1 parent f2a3834212
commit ea30223538
3 files changed
+61 -9

No files matched your search

+1 -1
@@ -22,7 +22,7 @@ Live: <https://nockal.com/game-maker/> · Widget playground: <https://nockal.com
| [Pixel art](Pixel-Art) | The pixel art asset and its palette, the tools, layers and frames, onion skin and the preview, resizing, how frames are worn and where the pixels are stored |
| [Fonts](Fonts) | Uploading a typeface, what a text wears, what the editor falls back to |
| [Sounds](Sounds) | Uploading a sound, what the asset says, `Play sound` and `Stop sound`, sound FX (gain, pitch, EQ, mix, delay) and how long a voice rings on, what a pause and a stop do to a voice |
| [Instruments](Instruments) | The instrument asset: Notes, Sample, Parameters, Sound FX and Output, triggers, zones and layers, the keys of the Instrument tab, `Play note` |
| [Instruments](Instruments) | The instrument asset: Notes, Sample, Parameters, Sound FX, Envelope and Output, triggers, zones and layers, the keys of the Instrument tab, `Play note` |
| [Animations](Animations) | Animation assets, the Animation tab, how they run |
| [Curves](Curves) | Easings drawn by hand, the Curve tab, using one on a key or a `Lerp` |
| [Tiles](Tiles) | The tile asset, plain tiles and the two autotile kinds, the pictures as animation steps, the Tile tab |
+55 -5
@@ -22,8 +22,9 @@ A at 440 Hz, 127 the highest. A note is named with its octave after it and no da
| **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. The volume of the sound asset counts. |
| **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). |
| **Output** | What is heard. It takes **one** sound, like every other sound input; a second edge replaces the first. To play several together, put a **Mix** in front of it (several Mixes in a row for more than two). One per instrument. |
| Gain, Pitch, 5-Band-EQ, Mix, Delay | The effects of a [sound FX](Sounds#sound-fx), the same nodes. |
| Gain, Pitch, 5-Band-EQ, Filter, Mix, Delay | The effects of a [sound FX](Sounds#sound-fx), the same nodes. |
**Play** of a Sample:
@@ -80,7 +81,8 @@ voice 0.
Sample fades out in 10 ms, *One-shot* ones play on, and *Loop, then release* ones leave their
loop. A buffer source stops looping and plays on by itself. The pitch worklet is told to leave:
it lets the round finish that its newest frame has read into, so nothing already read changes
under the frames still sounding, and plays on from there.
under the frames still sounding, and plays on from there. A Sample under an
[Envelope](#envelopes) does not fade: it plays on through the release.
- **Pitch.** A Sample that follows the note is shifted by the phase vocoder of #317, so a note far
from the root sounds rough, as there. A note at its root is the sound itself, played without the
worklet.
@@ -92,6 +94,53 @@ A node that keeps the instrument from compiling says so, and the tab's header sa
source nothing triggers, an effect nothing comes into. A Sound FX node naming no FX, or one that is
gone, warns and lets the sound through as it is.
## Envelopes
An **Envelope** (#335) shapes a note over its time: from silence up to full in **Attack**, down to
the level **Sustain** in **Decay**, held there as long as the note is, and back to silence in
**Release** once the note ends. A new one is 0.005 / 0.1 / 1 / 0.1: a soft start, otherwise the
sound as it is.
- **The shape is fixed.** The attack is a straight line; the decay and the release ease out, as a
struck string does, and are 60 dB of the way there when their time is up. A release takes 10 ms
at least, so a note never clicks. There is no *Punch*: a short decay to a sustain under 1 is the
same, and a Gain sets how loud it is overall.
- **A note ending early** (shorter than attack and decay) releases from the level it has reached
by then, not from the sustain: mid-attack from halfway up, for one.
- **On the way of the sound** (Sample → Envelope → Output) it is the volume of everything before
it, behind a Mix too. Two in a row multiply. The end of the note goes to it instead of the
10 ms fade: a *Gate* or *Loop* Sample plays on through the release (a loop loops on), a *Loop,
then release* one leaves its loop as well, and the note ends when the release has. A
*One-shot* under an Envelope of its own plays through as it would, the Envelope held at its
sustain. Echoes after it ring on as ever.
- **`value`** moves a number with the same curve: at **From** while the note rests, at **To** at
the top of the attack, and where the sustain puts it between them while held. Its pin is of a kind of its
own, an **envelope**, drawn in coral. It fits only a number the sound itself holds while it
plays: `cutoff` and `resonance` of a Filter, `semitones` of a Pitch, `gain` of a Gain, a band of
the 5-Band-EQ and `mix` of a Mix. Not the time of a Delay, not the times of an Envelope, not a
parameter of a Sound FX node. A cutoff and a Gain move in equal ratios (octaves, decibels),
everything else evenly. Both ends are held to the range of the number it moves.
- **A filter sweep:** Sample → Filter → Envelope → Output, and a second Envelope with its `in` left
open, its `value` into the Filter's `cutoff`, From 200, To 5000. Each Envelope is a curve of its
own; one Envelope can feed several numbers.
- **A number an Envelope moves is the Envelope's.** It is no longer reached by a parameter or by
`Set sound FX parameters`. A Pitch it moves comes on top of the shift the note already has.
- **The numbers of an Envelope count from the moment the note starts.** They can come from
`velocity` or a parameter (a harder stroke, a longer decay), but changing them later does not
bend a note already playing.
- **Stop sound** with *Let ring* lets a note with an Envelope fall away in its release; without it
the note is cut in 10 ms, as is every note the **Stop** of the tab ends.
- **The same note again** while one is still in its release is a voice of its own; the first
plays its release out.
- The curve runs on the audio thread, one `ConstantSourceNode` per Envelope and note; a number it
moves gets it through a `WaveShaper`. Firefox has no `cancelAndHoldAtTime`: there the level a
release starts from is worked out from the shape.
- **Measured** (2026-10-06, e2e 34, Chrome offline): attack 0.1, decay 0.2, sustain 0.5, release
0.3 rendered 0.5 at 0.05 s, 1 at 0.1 s and 0.5005 at 0.3 s; released at 0.5 s it was 0.0158
at 0.65 s and 0.0005 at 0.8 s, released mid-attack at 0.05 s it fell from 0.5 to 0.05 at 0.15 s.
A Gain moved from 0.25 to 1 by that curve was 0.5 halfway up. Live, a looped note of 0.2 s
through an Envelope with a release of 1 s was gone 1.32 s after it started, read every 150 ms.
## The Instrument tab
The graph, and below it **the keys**: all 128 notes, the ones that sound in white and black, the
@@ -133,7 +182,8 @@ heard at once on what is playing. Those values are the tab's own and never writt
Its output `voice` is the number of the note, like `Play sound`'s: `Set sound FX parameters` moves
its parameters while it plays (the bundle of an Instrument parameters node goes into its
`fx params`), `Stop sound` with `voice` ends it — with *Let ring* only the sound, so its echoes
ring on. A note belongs to the object that played it and stops when that object is destroyed.
ring on, and an Envelope plays its release first. A note belongs to the object that played it and
stops when that object is destroyed.
**Instrument parameters** works like `Sound FX parameters`: it names an instrument and picks the
parameters to set, each a number input starting at the default its Parameters node gives it.
@@ -176,6 +226,6 @@ be made of it; nothing in the editor plays a sequence yet, only the check script
## Not yet
No envelope with a release after the note (#335), no oscillators or 8-bit sources (#329), no
patterns or songs (#333, #334), no swing. Notes can not be played from an `.mid` file or a MIDI
No oscillators or 8-bit sources (#329), no patterns or songs (#333, #334), no swing. An Envelope
shapes notes of an instrument only, not a sound played through a sound FX. Notes can not be played from an `.mid` file or a MIDI
keyboard.
+5 -3
@@ -37,7 +37,7 @@ so what the inspector plays is what the graph will play.
| Node | What it does |
| --- | --- |
| **Play sound** | Starts the sound named by its `sound` input. `volume` **multiplies** the asset's own volume (1 leaves it alone), `loop` is a choice of three (*From the asset*, *On*, *Off*), `detached` says the voice belongs to nobody, `fx` names a [sound FX](#sound-fx) to play it through, and `fx params` takes values for that FX's [parameters](#parameters). Its output `voice` is the number of this one play, for changing it [while it plays](#changing-a-playing-sound), `length` how many seconds one run of the sound lasts, and `tail` that length with the [echoes](#delay-and-the-tail-of-a-voice) of its FX after it, at the values it starts with: how long until the voice is quiet. All three are 0 where nothing was played. `tempo` (BPM, 120 where nothing is connected) is what a [Delay synced to beats](#delay-and-the-tail-of-a-voice) in its FX counts by. |
| **Stop sound** | Silences every voice of the sound it names, however many plays started it — a loop included. Naming no sound silences everything the run is playing. With `voice` connected it silences only that one play (the number `Play sound` gave out), and nothing where that is 0. A voice is faded out in 10 ms rather than cut, so it does not click, its echoes with it; **Let ring** stops only the sound and lets the [echoes](#delay-and-the-tail-of-a-voice) fade as they would. |
| **Stop sound** | Silences every voice of the sound it names, however many plays started it — a loop included. Naming no sound silences everything the run is playing. With `voice` connected it silences only that one play (the number `Play sound` gave out), and nothing where that is 0. A voice is faded out in 10 ms rather than cut, so it does not click, its echoes with it; **Let ring** stops only the sound and lets the [echoes](#delay-and-the-tail-of-a-voice) fade as they would, and a note of an instrument with an [Envelope](Instruments#envelopes) falls away in its release first. |
| **Set sound FX parameters** | Hands new values to the [parameters](#changing-a-playing-sound) of one voice that is already playing, by the `voice` number its `Play sound` gave out, at once or over `time` seconds. |
| **Sound** | A constant sound, for either of the two to work on through an edge. |
@@ -104,13 +104,15 @@ Input and the Output once each; their pins carry sound and fit nothing but each
| **Gain** | Louder or quieter, in dB (`Gain (dB)`): 0 leaves it alone, -6 is about half as loud, +6 twice. Above 0 the sound can clip. |
| **Pitch** | Higher or lower, in semitones (12 is an octave, 0.5 a quarter tone). The sound **keeps its length**, also when the pitch changes while it plays. The pitch is made where the sound is read, so an effect before the Pitch acts as if it came after it. |
| **5-Band-EQ** | Five bands in dB: 80 Hz and 12 kHz as shelves, 250 Hz, 1 kHz and 4 kHz as peaks. A band at 0 does nothing. |
| **Filter** | Takes away what is above `cutoff` (Hz, 1000 by default): **Type** *Low-pass*. Or what is below it (*High-pass*), or both, leaving a band around it (*Band-pass*). `resonance` from 0 to 1 raises what is right at the cutoff: a low- or high-pass has no bump at 0 (Q -3 dB) and rises by 20 dB at 1, a band-pass gets narrower (Q 0.7 to 20). In an [instrument](Instruments#envelopes) an Envelope can move both while a note plays. |
| **Mix** | Blends the sounds at `a` and `b`: at 0 only `a` is heard, at 1 only `b` (0.5 is the default). **Curve** says what lies between: *Crossfade* (the default) gives half of each at 0.5, *Both at center* keeps each full up to the middle. See [below](#the-curve-of-a-mix). |
| **Delay** | An echo: the sound comes back after `time`, again and again, each time `feedback` times as loud. **Sync** says what `time` counts: *Seconds*, or *Beats* in quarter notes at the tempo of the voice. `damping` makes every echo duller than the last, `mix` is how loud the echoes are next to the sound, which stays as it is. **Ping-pong** sends the echoes left and right in turn. See [below](#delay-and-the-tail-of-a-voice). |
Every number of these nodes is an **input**: typed in while nothing is connected, or fed from a
parameter of the Input. Each is held to its range (Gain -120 to +24 dB, Pitch -64 to +64, the EQ
bands -60 to +24 dB, Mix 0 to 1, Delay `time` 0.01 to 8 and never more than 2 s, `feedback` 0 to
0.95, `damping` and `mix` 0 to 1), whichever way the value arrives.
bands -60 to +24 dB, Filter `cutoff` 20 to 20000 Hz and `resonance` 0 to 1, Mix 0 to 1, Delay
`time` 0.01 to 8 and never more than 2 s, `feedback` 0 to 0.95, `damping` and `mix` 0 to 1),
whichever way the value arrives.
**How Pitch keeps the length** (#317). A way with a Pitch is played by an `AudioWorklet` on the
audio thread, a **phase vocoder**: the sound is cut into frames of about 43 ms (2048 samples at