Describe the Bitcrusher effect (#322)

- Sounds: a row in the node table and a section Bitcrusher with the
  ranges and the measured cost on the audio thread.
- Instruments: the Bitcrusher among the effects and Envelope targets.
- Development: 1841 checks.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
adminandClaude Opus 5.5 committed 2026-10-06 22:23:08 +02:00
1 parent eddfd07f5c
commit 5ea149cad0
3 files changed
+30 -7

No files matched your search

+1 -1
@@ -18,7 +18,7 @@ php tests/php/accounts.test.php # the API's accoun
# has and the web server's container has not (SKIP there)
php tests/php/snapshots.test.php # the snapshot store (#231), the same way
php tests/php/releases.test.php # the release store (#266), the same way
node tools/seed-e2e.mjs && node tools/e2e.mjs # 1840 editor checks, screenshots in /tmp/gm-e2e-*.png
node tools/seed-e2e.mjs && node tools/e2e.mjs # 1841 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
+4 -4
@@ -24,7 +24,7 @@ A at 440 Hz, 127 the highest. A note is named with its octave after it and no da
| **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, Filter, Mix, Delay | The effects of a [sound FX](Sounds#sound-fx), the same nodes. |
| Gain, Pitch, 5-Band-EQ, Filter, Mix, Delay, Bitcrusher | The effects of a [sound FX](Sounds#sound-fx), the same nodes. |
**Play** of a Sample:
@@ -117,9 +117,9 @@ sound as it is.
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.
the 5-Band-EQ, `mix` of a Mix, and `bits`, `rate` and `mix` of a Bitcrusher. Not the time of a
Delay, not the times of an Envelope, not a parameter of a Sound FX node. A cutoff, a Gain and the
rate of a Bitcrusher 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.
+25 -2
@@ -148,12 +148,14 @@ Input and the Output once each; their pins carry sound and fit nothing but each
| **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). |
| **Bitcrusher** | Makes the sound rough, like an old console. `bits` rounds it to fewer steps (8 by default), `rate` takes a sample only so many times a second and holds it until the next (8000 Hz by default), `mix` is how much of the crushed sound is heard instead of the sound itself (1 by default). See [below](#bitcrusher). |
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, 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.
`time` 0.01 to 8 and never more than 2 s, `feedback` 0 to 0.95, `damping` and `mix` 0 to 1,
Bitcrusher `bits` 1 to 16, `rate` 100 to 48000 Hz 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
@@ -267,6 +269,27 @@ change ends. The end is timed on the clock of the sound, so a paused run holds a
about 0.3 s, so about **400 of them play at once** (2026-10-06). There is no limit on how many
voices play, also now that they live longer.
### Bitcrusher
A **Bitcrusher** (#322) runs on the same worklet as Pitch, sample by sample:
- **`rate`** is sample-and-hold: a sample is taken `rate` times a second and held until the next.
48000 Hz leaves the sound as it is, 8000 Hz is dull and metallic, a few hundred Hz a buzz of its
own. It never takes samples more often than the audio device makes them.
- **`bits`** rounds what is held to `2^(bits-1)` steps either side of 0: 16 is hardly heard, 8
crackles, 4 and below hiss and buzz, 1 leaves only up, middle and down. Bits need not be whole,
3.5 lies between 3 and 4, so a ramp on them never jumps.
- **`mix`** blends: at 1 only the crushed sound is heard, at 0.5 half of each. A `mix` typed in at
0 leaves the Bitcrusher out. Fed from a parameter it stays, at whatever value.
- All three are numbers of the worklet, so *Set sound FX parameters* moves them while the sound
plays (`rate` in octaves, the other two in what they hold), and in an
[instrument](Instruments#envelopes) an Envelope can move them while a note plays.
- Without `AudioWorklet` (or if it cannot be loaded) the sound goes through it as it is, and the
console says why. The worklet is loaded with the first play that needs it.
- **Cost**: in e2e 34 headless Chrome on the CI's Windows machine rendered 64 stereo voices
through a Bitcrusher for 2 s in 1.9 s, so about **68 of them fill the audio thread**
(2026-10-06). There is no limit on how many play at once.
**Listening in the tab.** The header picks one of the project's sounds and plays it through the
graph as it stands — the same library as a running game, so it sounds the way the game will.
`Stop` there ends only what the tab started. Play is offered only while the graph compiles.