From 0ea28c52be13f208201cfc9c844a96efbda5f42a Mon Sep 17 00:00:00 2001 From: MelekTaus Date: Sat, 10 Oct 2026 22:06:01 +0200 Subject: [PATCH] Describe the Bitcrusher device and its pixel screen (#399) - Sounds: the table row names the device. The Bitcrusher section says what the plate holds, how the screen draws a sine in cells of steps and holds, its texts and the 16 lamps of the bits kept. - Architecture: CrusherPanel, CrusherFace and crusherView. - Development: 1975 editor checks. Co-Authored-By: Claude Opus 5.5 --- Architecture.md | 3 +++ Development.md | 2 +- Sounds.md | 22 +++++++++++++++++++++- 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/Architecture.md b/Architecture.md index 4269e2a..4c218a2 100644 --- a/Architecture.md +++ b/Architecture.md @@ -450,6 +450,9 @@ src/editor/soundfx/ SoundFxEditor (#311: the graph, a sound to try it on, Pla Vibrato, the Phaser and the Flanger as one kind of device, the volume or the pitch over time, or the response with a lane of where it goes, worked out apart from the drawing against the worklets' own numbers), + CrusherPanel + CrusherFace + crusherView (#399: the Bitcrusher as a device, + a sine sent through the node's own `Crusher` and drawn in cells of its steps + and holds, and the bits it keeps, worked out apart from the drawing), nodeParamDrag (a knob's drag as one undo step, for the tab and the node, several settings at once since #389), nodeTabs (which nodes open a tab of their own) diff --git a/Development.md b/Development.md index 4864e49..69f5c53 100644 --- a/Development.md +++ b/Development.md @@ -19,7 +19,7 @@ php tests/php/accounts.test.php # the API's accoun 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 php tests/php/files.test.php # uploaded files in a folder per account (#344), the same way -node tools/seed-e2e.mjs && node tools/e2e.mjs # 1974 editor checks, screenshots in /tmp/gm-e2e-*.png +node tools/seed-e2e.mjs && node tools/e2e.mjs # 1975 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/Sounds.md b/Sounds.md index adb1dbc..4b09a23 100644 --- a/Sounds.md +++ b/Sounds.md @@ -430,7 +430,7 @@ response of a Reverb, and as what the Sound FX tab tries out. Its row means noth | **Filter** | **Type** *Low-pass* (the default) takes away what is above `frequency` (Hz, 1000 by default), *High-pass* what is below it, *Band-pass* all but a band around it and *Notch* just that band. *Low shelf* and *High shelf* raise or lower everything below or above it by `gain` (dB), *Peaking* a band around it; only these three have the `gain` row. *All-pass* leaves every frequency as loud as it was and only turns its phase. `Q` (0.707 by default) says how sharp it is: at 0.707 a low- or high-pass has no bump, higher it rings at the frequency, and a band, a notch or a peak gets narrower. **Slope** makes a low-pass, high-pass, band-pass or notch steeper: *12 dB/oct* is one filter, *24* two and *48* four in a row, and only the last of them has the Q. In an [instrument](Instruments#envelopes) an Envelope can move all three numbers while a note plays. The node draws itself as a curve and is edited right in the graph, and a **double-click on the node's title** opens the same in a tab. See [below](#filter). | | **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). In the graph the node is drawn as a blue device of 180x200 graph units (#390): a lever for **Curve** on top, down for *Crossfade* and up, with its lamp lit, for *Both at center*, and below it one knob for `Mix` with *A* and *B* engraved at the ends of its turn. A flip of the lever is one undo step. A linked `Mix` greys the knob. | | **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. `wet` (0.5) is the sound alone at 0, the sound and its echoes in full at 0.5, the echoes alone at 1. **Ping-pong** sends the echoes left and right in turn. The node is drawn as a device with its echoes on a screen (#393). 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), `wet` is how much of the crushed sound is heard instead of the sound itself (1 by default). See [below](#bitcrusher). | +| **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), `wet` is how much of the crushed sound is heard instead of the sound itself (1 by default). The node is drawn as a pink device whose screen draws a sine in the pixels of its bits and its rate (#399). See [below](#bitcrusher). | | **Phaser** | Sweeps notches through the sound, the swirl of a phaser pedal. **Stages** (2, 4, 6, 8 or 12, 4 by default) is how many allpass stages it has, every two make one notch. They sit around `frequency` (800 Hz by default), and an LFO moves them `depth` octaves wide (2), `rate` times a second (0.5 Hz). `feedback` (0.4) sharpens the notches, `wet` (1) is how much is heard. The node is drawn as a mustard device whose screen swirls its notches (#398). See [below](#phaser-and-flanger). | | **Flanger** | Blends the sound with a copy a few ms late: the jet sound of a flanger, and what sfxr calls its phaser. `offset` is how late the copy is (1 ms by default), `sweep` moves that on by so many ms a second from the start of the sound (0), an LFO adds up to `depth` ms (2) `rate` times a second (0.25 Hz). `feedback` (0.5) and `wet` (1) as on the Phaser. The node is drawn as a steel blue device whose screen draws its comb (#398). See [below](#phaser-and-flanger). | | **Pan** | Moves the sound left or right: `pan` -1 is all left, 1 all right, 0 (the default) leaves it in the middle. A mono sound is spread on both sides and then moved (each side 0.707 at 0). A stereo sound keeps the side it goes to and the other side moves over into it, as Web Audio's `StereoPannerNode` does: at 1 both sides are heard on the right. In an [instrument](Instruments#envelopes) an Envelope can move it. Measured (e2e 34, Chrome offline): a mono sine at 0.5 came out 0.5 / 0 at -1 and 0.354 / 0.354 at 0, a stereo one at 0.5 came out 0.354 / 0.854. In the graph the node is drawn as the Gain's device in cyan (#392), with one knob for `Pan`: the middle stands straight up, the turn goes evenly to *L* and *R* engraved at its ends. A linked `Pan` greys the knob. | @@ -1069,6 +1069,26 @@ A **Bitcrusher** (#322) runs on the same worklet as Pitch, sample by sample: - 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. +- **The device** (#399): in the graph a Bitcrusher is a plate of 680x280 graph units in bubblegum + pink, its inputs on the left and its output on the right. `Bits` and `Rate` are big knobs, `Wet` + a small one. `Rate` gives its low end more of the turn (8 kHz just past the middle). Each turn + is one undo step, a wired number locks its knob, and at `wet` 0 the other two are drawn faint. + - **The screen** sends a 440 Hz sine at 0 dBFS through the node's own crush at 48 kHz, so the + steps and holds drawn are the ones heard. What comes out is drawn in **cells**: each as tall + as a step of the bits and as wide as a hold of the rate, so the coarser the crush, the coarser + the picture. Where a step or a hold is 5 pixels or more, a grid of them lies behind, and the + cells get a gap round them. Where the steps are finer, a hold is a thin bar on its level. A + cell is never more than twice as tall as it is wide, so 1 bit gives bars at -1, 0 and 1. The + sine going in is a grey ghost behind it. Below 1 `wet` the line that is heard is drawn over + the cells. + - The screen shows two periods of the sine (4.5 ms), or 6 holds where the rate is so low that + fewer would show (20 ms at 300 Hz). Its span is written in the corner. + - Above the screen how crushed it is, from `CLEAN` over `GRITTY`, `CRUNCHY` and `CRUSHED` to + `BROKEN`: whichever of the bits (16 to 1) or the rate (48 kHz to 100 Hz, in octaves) takes more + of the sound, times `wet`. Under it `NOISE -50 dB` (6 dB a bit, for a sine at full scale) and + `FOLDS AT 4 kHz` (half the rate: above it the highs fold back down). At `wet` 0 it says `DRY`. + - **Bits kept**: 16 lamps, the highest bit on the left, lit for each bit that is kept and partly + for a fraction. The *Crush* lamp beside the name glows the more it crushes. - 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