diff --git a/Development.md b/Development.md index fabc975..8b019c2 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 # 1882 editor checks, screenshots in /tmp/gm-e2e-*.png +node tools/seed-e2e.mjs && node tools/e2e.mjs # 1884 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 c234f64..9cfd7d2 100644 --- a/Instruments.md +++ b/Instruments.md @@ -26,7 +26,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, Bitcrusher, Phaser, Flanger, Pan, Compressor, Limiter, Saturation, Tremolo, Vibrato, Reverb | The effects of a [sound FX](Sounds#sound-fx), the same nodes. | +| Gain, Pitch, 5-Band-EQ, Filter, Mix, Delay, Bitcrusher, Phaser, Flanger, Pan, Compressor, Limiter, Saturation, Tremolo, Vibrato, Reverb | The effects of a [sound FX](Sounds#sound-fx), the same nodes, with [Bypass and Wet](Sounds#bypass-and-wet). | **Play** of a Sample: @@ -123,8 +123,8 @@ 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: `frequency`, `Q` and `gain` of a Filter, `pan` of a Pan, `semitones` of a Pitch, `gain` of a Gain, a band of - the 5-Band-EQ, `mix` of a Mix, `bits`, `rate` and `mix` of a Bitcrusher, `frequency` and `mix` - of a Phaser, `offset` and `mix` of a Flanger, and `frequency` and `duty` of a Chip. Not the time + the 5-Band-EQ, the `wet` of these five but the Pitch, `mix` of a Mix, `bits`, `rate` and `wet` of a Bitcrusher, `frequency` and `wet` + of a Phaser, `offset` and `wet` of a Flanger, and `frequency` and `duty` of a Chip. Not the time of a Delay, not the times of an Envelope, not a parameter of a Sound FX node, not the slide or the other numbers of a Chip, not the LFO of a Phaser or Flanger. A cutoff, a Gain, the rate of a Bitcrusher and the frequency of a Phaser or a Chip move in equal ratios (octaves, decibels), everything else evenly. Both ends are held to the range of the number it moves. diff --git a/Sounds.md b/Sounds.md index 2804ced..b027434 100644 --- a/Sounds.md +++ b/Sounds.md @@ -269,37 +269,85 @@ response of a Reverb, and as what the Sound FX tab tries out. Its row means noth | Node | What it does | | --- | --- | | **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. On a [Chip](Instruments#chips) of an instrument it moves the frequency of the Chip itself. | +| **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. On a [Chip](Instruments#chips) of an instrument it moves the frequency of the Chip itself. Its `wet` takes the semitones from 0 up to all of them, see [below](#bypass-and-wet). | | **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** | **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. 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). | -| **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). | -| **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, `mix` (1) is how much is heard. 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 `mix` (1) as on the Phaser. See [below](#phaser-and-flanger). | +| **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. 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). | +| **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. 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. 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. | | **Compressor** | Squeezes the loudness together: what goes above `threshold` (-24 dB by default) comes out only 1/`ratio` (4) as much louder. `knee` (6 dB) eases into it, `attack` (0.003 s) and `release` (0.25 s) say how fast it turns down and lets go. `makeup` (0 dB) raises it afterwards, `auto-gain` (0) blends that with the gain that brings a sound at full scale back to full scale. See [below](#compressor-and-limiter). | | **Limiter** | Keeps every peak below `threshold` (-6 dB): it looks 5 ms ahead, so even a sudden peak never gets through, and comes back up in `release` (0.1 s). `auto-gain` (1) raises the limited sound towards `ceiling` (-1 dB). Nothing ever goes above the ceiling. See [below](#compressor-and-limiter). | -| **Saturation** | Bends the sound, from warmth to a hard distortion. **Type**: *Soft (tanh)* (the default), *Cubic*, *Hard clip*, *Tube*, *Fuzz*, *Foldback*, *Sine fold* or *Rectify*. `drive` (12 dB) is how hard the sound is pushed into it, `tone` (1) a low-pass after it from 1 kHz (0) to wide open (1). `output` (0 dB) and `auto-gain` (1) set the level of the bent sound, `mix` (1) how much of it is heard instead of the sound itself. See [below](#saturation). | +| **Saturation** | Bends the sound, from warmth to a hard distortion. **Type**: *Soft (tanh)* (the default), *Cubic*, *Hard clip*, *Tube*, *Fuzz*, *Foldback*, *Sine fold* or *Rectify*. `drive` (12 dB) is how hard the sound is pushed into it, `tone` (1) a low-pass after it from 1 kHz (0) to wide open (1). `output` (0 dB) and `auto-gain` (1) set the level of the bent sound, `wet` (1) how much of it is heard instead of the sound itself. See [below](#saturation). | | **Tremolo** | Makes the volume swing `rate` times a second (5 Hz by default), from full down by `depth` percent (50) and back. **Shape**: *Sine* (the default), *Triangle*, *Square* or *Saw*. See [below](#tremolo-and-vibrato). | | **Vibrato** | Makes the pitch swing `rate` times a second (5 Hz), `depth` semitones up and as far down (0.5). **Shape** as on the Tremolo; a *Square* jumps between two pitches. See [below](#tremolo-and-vibrato). | -| **Reverb** | The sound in a space. **Type**: *Room* (the default), *Hall*, *Cave*, *Plate*, *Custom* or *Sound*. Custom shows the rows `decay` (s, 1.5 by default), `damping` (0.4) and `pre-delay` (s, 0.01); Sound picks a sound asset as the impulse response of a real space, with `pre-delay`. `mix` (0.3) is how much of the reverb is heard instead of the sound itself. See [below](#reverb). | +| **Reverb** | The sound in a space. **Type**: *Room* (the default), *Hall*, *Cave*, *Plate*, *Custom* or *Sound*. Custom shows the rows `decay` (s, 1.5 by default), `damping` (0.4) and `pre-delay` (s, 0.01); Sound picks a sound asset as the impulse response of a real space, with `pre-delay`. `wet` (0.3) is how much of the reverb is heard instead of the sound itself. See [below](#reverb). | 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 `frequency` 20 to 20000 Hz, `Q` 0.1 to 30 and `gain` -40 to +40 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, -Bitcrusher `bits` 1 to 16, `rate` 100 to 48000 Hz and `mix` 0 to 1, Phaser `frequency` 20 to +`time` 0.01 to 8 and never more than 2 s, `feedback` 0 to 0.95, `damping` 0 to 1, +Bitcrusher `bits` 1 to 16, `rate` 100 to 48000 Hz, Phaser `frequency` 20 to 20000 Hz, `rate` 0 to 10 Hz, `depth` 0 to 6 octaves, Flanger `offset` 0 to 10 ms, `sweep` -125 to -125 ms/s, `rate` 0 to 10 Hz, `depth` 0 to 10 ms, both with `feedback` 0 to 0.95 and `mix` 0 to 1, +125 ms/s, `rate` 0 to 10 Hz, `depth` 0 to 10 ms, both with `feedback` 0 to 0.95, Pan -1 to 1, Compressor `threshold` -100 to 0 dB, `ratio` 1 to 20, `knee` 0 to 40 dB, `attack` and `release` 0 to 1 s, `makeup` -24 to +24 dB, Limiter `threshold` -60 to 0 dB, `ceiling` -30 to 0 dB, -`release` 0.001 to 2 s, both with `auto-gain` 0 to 1, Saturation `drive` 0 to 48 dB, `tone`, -`auto-gain` and `mix` 0 to 1, `output` -24 to +24 dB, Tremolo `rate` 0 to 20 Hz and `depth` 0 to 100 %, -Vibrato `rate` 0.5 to 20 Hz and `depth` 0 to 4 semitones, Reverb `decay` 0.1 to 10 s, `damping` and -`mix` 0 to 1, `pre-delay` 0 to 0.5 s), +`release` 0.001 to 2 s, both with `auto-gain` 0 to 1, Saturation `drive` 0 to 48 dB, `tone` and +`auto-gain` 0 to 1, `output` -24 to +24 dB, Tremolo `rate` 0 to 20 Hz and `depth` 0 to 100 %, +Vibrato `rate` 0.5 to 20 Hz and `depth` 0 to 4 semitones, Reverb `decay` 0.1 to 10 s, `damping` +0 to 1, `pre-delay` 0 to 0.5 s, and every `wet` 0 to 1), whichever way the value arrives. +### Bypass and Wet + +Every effect has a **Bypass** and a **`wet`** (#354), all but the Mix, the Input and the Output. + +- **Bypass** is a setting of the node (a checkbox). A bypassed node is left out when the graph is + compiled, as if it were not there: it costs nothing and holds nothing back. It is drawn faded, + and its body says *Bypass: true* (nothing while it is off). It cannot be switched while a sound + plays; `wet` 0 can. +- **`wet`** is an input like the other numbers: typed in, fed from a parameter, moved with *Set + sound FX parameters* while the sound plays, and in an [instrument](Instruments#envelopes) moved + by an Envelope where the node lets one move its other numbers (Gain, EQ, Filter, Pan, Bitcrusher, + Phaser, Flanger). It blends what the node does with the sound as it came in: + `(1 - wet) * sound + wet * effect`. 1 is the default, and a `wet` typed in at 1 costs nothing. + Typed in at 0 the node is left out; fed from a parameter it stays, at whatever value. +- **A node that is late** (Compressor, Limiter, Vibrato) has the sound as it came in held back + as far, so the two meet in step and nothing is combed out. +- The rows that were called `mix` on six nodes are now `wet`, under the same key: values, + parameters and edges saved before stay as they were. On the **Bitcrusher, Saturation and + Reverb** it means what it did. On the **Phaser and Flanger** the effect itself is half sound and + half copy, since the notches only come from mixing them: `wet` 1 is that, as `mix` 1 was. Their + defaults stay: Delay 0.5, Reverb 0.3, the others 1. + +Two nodes take it their own way: + +| `wet` | **Delay**: sound / echoes | **Pitch**: semitones of a Pitch of 12 | +| --- | --- | --- | +| 0 | 1 / 0 | 0 | +| 0.25 | 1 / 0.5 | 3 | +| 0.5 | 1 / 1 | 6 | +| 0.75 | 0.5 / 1 | 9 | +| 1 | 0 / 1 | 12 | + +- **The Delay crossfades** like the *Both at center* curve of a [Mix](#the-curve-of-a-mix): the + sound stays full up to 0.5 and the echoes from 0.5 on. **A Delay saved before #354 sounds + different**: it had the sound always in full and the echoes at `mix`. It sounds the same again + at half its old value (`mix` 1 → `wet` 0.5, 0.5 → 0.25). +- **The Pitch** takes the semitones by `wet`. An Envelope moves the semitones, not the `wet`. + +Worth knowing: on a **Gain** `wet` only makes it louder or quieter (0.5 of -6 dB is about +-2.5 dB). On a **Tremolo** it acts like a smaller `depth`. On a **Limiter** below 1 the peaks of +the sound as it came in pass its limit. A **Filter**, an **EQ** or a **Vibrato** blended with the +sound gives phase effects, a Vibrato a chorus. + +Measured (e2e 34, Chrome offline): a steady 0.5 through a Gain of 0 at `wet` 0.25 came out 0.375. +A Delay of 0.1 s without feedback on it gave sound / sound with echo 0.5 / 0.75 at `wet` 0.25, +0.25 / 0.75 at 0.75 and 0 / 0.5 at 1. A Compressor at 1:1 blended half and half at 1083 Hz, where +its 6 ms would cancel the sound, came out 0.00 dB, as loud as it went in. + **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 48 kHz, four overlapping), and the spectrum of each is moved up or down, peak by peak with the @@ -368,9 +416,9 @@ crossfader curve: one side only starts to fade once the other is full. ### Delay and the tail of a voice A **Delay** (#327) is a delay line whose output goes through a low-pass (the damping), back into -the line at `feedback`, and out at `mix`. The sound itself goes on past it untouched, so a Delay -never makes the sound quieter: `mix` 0.5 is echoes at half its level. Defaults: `time` 0.25 s, -`feedback` 0.4, `damping` 0.3, `mix` 0.5, Ping-pong off. +the line at `feedback`, and out. `wet` shares out the sound and the echoes (#354): the sound alone +at 0, both in full at 0.5, the echoes alone at 1, see [Bypass and Wet](#bypass-and-wet). +Defaults: `time` 0.25 s, `feedback` 0.4, `damping` 0.3, `wet` 0.5, Ping-pong off. - **`feedback` stops at 0.95**: at 1 the echoes would never fade, above it they would grow. - **`damping`** is the cutoff of the low-pass, evenly in octaves: 0 is 20 kHz (nothing heard), @@ -378,7 +426,7 @@ never makes the sound quieter: `mix` 0.5 is echoes at half its level. Defaults: - **Ping-pong** takes the sound into the left of the line only (a stereo sound mixed to one) and swaps the sides every round: the first echo is left, the second right. It is a setting of the node, not an input, because it changes how the voice is wired. -- A `mix` typed in at 0 leaves the Delay out. Fed from a parameter it stays, at whatever value. +- A `wet` typed in at 0 leaves the Delay out. Fed from a parameter it stays, at whatever value. - **Sync** (#332): with *Seconds* (the default) `time` is seconds. With *Beats* it is quarter notes at the tempo of the voice: 1 is a quarter, 0.5 an eighth, 0.75 a dotted eighth, 0.333 an eighth triplet. A voice started by `Play sound` or `Play note` takes its tempo from their input @@ -394,10 +442,11 @@ never makes the sound quieter: `mix` 0.5 is echoes at half its level. Defaults: **A voice lasts until its echoes have faded** (#324). Without an echo a voice ends with its sound, as it always did. With one, it rings on for its **tail**: until the last echo is 60 dB below the -sound, worked out from `time`, `feedback` and `mix` (echo *k* is `mix * feedback^(k-1)` as loud; +sound, worked out from `time`, `feedback` and `wet` (echo *k* is `echo * feedback^(k-1)` as loud, +`echo` being its share of `wet`; damping only makes it quieter, so it is left out and the tail is never too short). Echoes behind each other add up, and the two ways of a Mix take the longer. A `time` of 0.3 s with `feedback` -0.5 and `mix` 0.5 is nine echoes, 2.7 s. While it rings the voice still counts as playing and is +0.5 and `wet` 0.5 is ten echoes, 3 s. While it rings the voice still counts as playing and is still reached by `Set sound FX parameters`; a change there counts the tail again from where the change ends. The end is timed on the clock of the sound, so a paused run holds a tail where it is. @@ -482,10 +531,10 @@ aliasing. - **`output` and `auto-gain`**: the bent sound gets `(1 - auto-gain) * output + auto-gain * A` dB. `A` is the gain that brings a sine at -12 dBFS, driven and bent, back to the RMS it came in with. - **`tone`** is a low-pass after the curve, from 1 kHz at 0 to 20 kHz at 1, evenly in octaves. -- **`mix`** blends the bent sound with the sound itself. The oversampling makes the bent sound +- **`wet`** blends the bent sound with the sound itself. The oversampling makes the bent sound **192 samples late** (Chrome, at 48 and at 44.1 kHz alike), so the sound itself is held back as far and the two meet without a comb. The node as a whole is late by that much, which a voice, a - Mix and a bus make up for as for a [Compressor](#compressor-and-limiter). A `mix` typed in at 0 + Mix and a bus make up for as for a [Compressor](#compressor-and-limiter). A `wet` typed in at 0 leaves the node out. - **Measured** (2026-10-07, e2e 34, Chrome offline): an impulse came out 192 samples late at 48 and at 44.1 kHz. Half bent and half dry at 1125 Hz, where 192 samples off would cancel, the sine @@ -545,9 +594,9 @@ share of a sound there). - **A sound as the impulse response** is loaded with the voice, or before a bus gets its FX. Web Audio normalizes it, so a loud recording is not louder than a quiet one. A sound that cannot be loaded leaves the reverb silent and the sound dry. -- **`mix`**: `(1 - mix)` of the sound itself, `mix` of the reverb. A bus that only carries reverb - wants 1. A `mix` typed in at 0 leaves the node out. -- **Only `mix` moves while the sound plays.** `decay`, `damping` and `pre-delay` are set when a +- **`wet`**: `(1 - wet)` of the sound itself, `wet` of the reverb. A bus that only carries reverb + wants 1. A `wet` typed in at 0 leaves the node out. +- **Only `wet` moves while the sound plays.** `decay`, `damping` and `pre-delay` are set when a voice starts, on a bus when it gets its FX: a new impulse response would click. - **The voice lasts until the reverb has faded**: its pre-delay and its decay, or as long as its sound. @@ -555,7 +604,7 @@ share of a sound there). sounds at once, each with a long decay, are better sent through one bus. - **Measured** (2026-10-07, e2e 34, Chrome offline): an impulse through a *Custom* reverb of 1 s with 50 ms pre-delay was silent up to 50 ms after it, and fell by 35.9 dB from 0.2-0.3 s to 0.8-0.9 s - after it (36 dB to be expected). At `mix` 0.5 the impulse itself came through at half. With a sound + after it (36 dB to be expected). At `wet` 0.5 the impulse itself came through at half. With a sound as the impulse response that has one sample at 0.2 s, the impulse came back exactly 0.25 s later and nowhere else. @@ -569,7 +618,7 @@ A **Bitcrusher** (#322) runs on the same worklet as Pitch, sample by sample: - **`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 +- **`wet`** blends: at 1 only the crushed sound is heard, at 0.5 half of each. A `wet` 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 @@ -583,9 +632,9 @@ A **Bitcrusher** (#322) runs on the same worklet as Pitch, sample by sample: ### Phaser and Flanger Both (#341) run on the same worklet as Pitch, sample by sample, and both blend the sound with a -shifted copy of itself, so some frequencies cancel. **`mix` 0 leaves the sound as it is, 1 is half +shifted copy of itself, so some frequencies cancel. **`wet` 0 leaves the sound as it is, 1 is half sound and half copy**: there the notches are deepest, and the peaks stay at the level of the sound, -so neither ever makes it louder. A `mix` typed in at 0 leaves the node out, fed from a parameter it +so neither ever makes it louder. A `wet` typed in at 0 leaves the node out, fed from a parameter it stays. - **Phaser**: a chain of first-order allpasses, each turning the phase by 90° at its frequency. @@ -602,11 +651,11 @@ stays. every round exactly one delay later (the worklet needs no render quantum per round, unlike a Delay). - **sfxr's phaser** is this Flanger with `depth`, `feedback` and `rate` at 0. sfxr adds the copy - at the same level as the sound, the Flanger at `mix` 1 at half of each, so the same sound comes + at the same level as the sound, the Flanger at `wet` 1 at half of each, so the same sound comes out 6 dB quieter. sfxr's delay ends at 2.9 ms, the Flanger's at 20 ms, so a long sweep goes on further. - `frequency` and `offset` move in what they hold (the frequency in octaves), and in an - [instrument](Instruments#envelopes) an Envelope can move `frequency`, `offset` and `mix` while a + [instrument](Instruments#envelopes) an Envelope can move `frequency`, `offset` and `wet` while a note plays. The other numbers move with *Set sound FX parameters* as well. - Without `AudioWorklet` the sound goes through both as it is, as through the Bitcrusher. - **Measured** (2026-10-07, e2e 34, Chrome offline on the Windows runner): a 1 kHz sine at 0.8