Describe the Phaser and Flanger nodes (#341)
- Sounds: table rows and ranges for Phaser and Flanger, new section Phaser and Flanger with the measured notches and echoes. - Instruments: Envelope targets, Explosion with a Flanger, Randomize and Mutate on both, new preset Phased Pad. - Development: 1853 checks. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent
f70e4b7bc3
commit
5100f6989e
3 files changed
+63
-15
No files matched your search
+1
-1
@@ -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 # 1852 editor checks, screenshots in /tmp/gm-e2e-*.png
|
||||
node tools/seed-e2e.mjs && node tools/e2e.mjs # 1853 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
|
||||
|
||||
+17
-12
@@ -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 | The effects of a [sound FX](Sounds#sound-fx), the same nodes. |
|
||||
| Gain, Pitch, 5-Band-EQ, Filter, Mix, Delay, Bitcrusher, Phaser, Flanger | The effects of a [sound FX](Sounds#sound-fx), the same nodes. |
|
||||
|
||||
**Play** of a Sample:
|
||||
|
||||
@@ -123,10 +123,11 @@ 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, `mix` of a Mix, `bits`, `rate` and `mix` of a Bitcrusher, 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. A cutoff, a Gain, the rate of a
|
||||
Bitcrusher and the frequency of a Chip 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, `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
|
||||
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.
|
||||
- **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.
|
||||
@@ -182,7 +183,7 @@ from 0 to 1, the Chip counts in Hz, semitones and seconds.
|
||||
- **It ends with its note**, faded out in 10 ms, or under an [Envelope](#envelopes) through its
|
||||
release, and with *Sustain* 0 once the decay is over. Below *Min frequency* it ends by itself.
|
||||
Envelope, Filter and Bitcrusher are nodes of their own; sfxr's punch is a short decay, its phaser
|
||||
comes with #341.
|
||||
is the [Flanger](Sounds#phaser-and-flanger) (#341).
|
||||
- **How it is made:** a worklet of its own per note, next to the Pitch and the Bitcrusher in the
|
||||
same module. Every sample is worked out 8 times and averaged, as sfxr does, which takes the worst
|
||||
of the aliasing off a raw wave. Without the worklet a Chip is silent and its note ends at once.
|
||||
@@ -229,14 +230,17 @@ plays the note last played at once (C4 before any), for up to 2 s.
|
||||
follow the note, so every key plays at its own pitch, and most hold the note while the key is
|
||||
held. They come out the same every time they are picked: Randomize and Mutate make a variant.
|
||||
- **Effects** below the line: *Pickup*, *Laser*, *Explosion*, *Powerup*, *Hit*, *Jump*, *Blip*.
|
||||
Each is Notes for all 128 notes → Chip → Envelope → Filter → Bitcrusher → Output. Every click
|
||||
draws the sound anew within its kind, with sfxr's generator for it. The Chip plays at its own
|
||||
Each is Notes for all 128 notes → Chip → Envelope → Filter → Bitcrusher → Output. One
|
||||
*Explosion* in two has sfxr's phaser as well, a [Flanger](Sounds#phaser-and-flanger) after the
|
||||
Filter, with sfxr's offset and sweep and no LFO (#341). Every click draws the sound anew within its kind, with sfxr's generator for it. The Chip plays at its own
|
||||
frequency, *Follow note* off, so every key plays the same sound, as an effect does; turn it on
|
||||
to play the sound as a melody. The Envelope has *Sustain* 0, so the sound ends by itself.
|
||||
- **Randomize** draws every number of the Chips, Envelopes, Filters and Bitcrushers in the graph
|
||||
anew, as sfxr's randomizer does: most of them wild. It leaves the wave, *Follow note*, the type
|
||||
of a Filter, the *Mix* of a Bitcrusher, an Envelope's *From* and *To* and every other node as
|
||||
they are. An Envelope gets *Sustain* 0. An input with an edge into it keeps what it is fed.
|
||||
- **Randomize** draws every number of the Chips, Envelopes, Filters, Bitcrushers, Phasers and
|
||||
Flangers in the graph anew, as sfxr's randomizer does: most of them wild. A Flanger's offset and
|
||||
sweep come from sfxr's phaser, its LFO and feedback and all of a Phaser, which sfxr has not,
|
||||
within bounds of their own (a rate of 0.05 to 5 Hz, a Phaser at 200 Hz to 4 kHz). It leaves the
|
||||
wave, *Follow note*, the type of a Filter, the *Stages* of a Phaser, every *Mix*, an Envelope's
|
||||
*From* and *To* and every other node as they are. An Envelope gets *Sustain* 0. An input with an edge into it keeps what it is fed.
|
||||
- **Mutate** moves the numbers of those nodes a little, each one in two: a frequency, cutoff or
|
||||
rate by up to a quarter of an octave, the rest by a step and a tenth of its value. A 0 stays 0,
|
||||
so nothing that was off comes on, and *Sustain* stays as it is.
|
||||
@@ -256,6 +260,7 @@ The instruments, all on every note unless the table says otherwise:
|
||||
| *Synth Brass* | Saw → Envelope with a slow attack → Low-pass that an Envelope opens from 400 Hz to 3.5 kHz | held |
|
||||
| *Detuned Saws* | Two saws a tenth of a semitone apart (Pitch 0.1) → Mix → Envelope → Low-pass 7 kHz | held |
|
||||
| *String Pad* | As *Detuned Saws* with vibrato, attack 0.5 s, release 1 s, Low-pass 2.2 kHz | held |
|
||||
| *Phased Pad* | Saw with vibrato → Envelope, attack 0.3 s, release 0.8 s → Low-pass 3 kHz → Phaser of 6 stages at 600 Hz, 2.5 octaves wide, 0.3 times a second | held |
|
||||
| *Organ* | Square and the square an octave up → Mix → Envelope at full sustain → Low-pass 4.5 kHz | held |
|
||||
| *Flute* | Triangle with vibrato, a breath of noise through a Band-pass at 2.5 kHz → Mix → Envelope | held |
|
||||
| *Bell* | Two sines 17.6 semitones apart (a ratio of 2.76), each with its own Envelope → Mix → Delay | dies away in 2 s |
|
||||
|
||||
+45
-2
@@ -172,13 +172,17 @@ Input and the Output once each; their pins carry sound and fit nothing but each
|
||||
| **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). |
|
||||
|
||||
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,
|
||||
Bitcrusher `bits` 1 to 16, `rate` 100 to 48000 Hz and `mix` 0 to 1), whichever way the value
|
||||
arrives.
|
||||
Bitcrusher `bits` 1 to 16, `rate` 100 to 48000 Hz and `mix` 0 to 1, 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),
|
||||
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
|
||||
@@ -313,6 +317,45 @@ A **Bitcrusher** (#322) runs on the same worklet as Pitch, sample by sample:
|
||||
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.
|
||||
|
||||
### 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
|
||||
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
|
||||
stays.
|
||||
|
||||
- **Phaser**: a chain of first-order allpasses, each turning the phase by 90° at its frequency.
|
||||
Where the copy is turned by 180° it cancels the sound: two stages make one notch at `frequency`,
|
||||
four make two, around it, with a peak at `frequency` itself. A sine LFO moves the frequency of
|
||||
every stage `depth` octaves wide around `frequency` (half up, half down), `rate` times a second;
|
||||
at `depth` 0 or `rate` 0 the notches stand still. `feedback` sends what leaves the chain back in,
|
||||
a sample later, which sharpens the notches into a ring. **Stages** is a setting, not an input.
|
||||
- **Flanger**: a delay line, read with linear interpolation. The delay is `offset`, plus what
|
||||
`sweep` has added since the sound started (in ms per second, either way), plus up to `depth` ms
|
||||
from an LFO that starts at 0. **As in sfxr the delay is mirrored at 0**: an `offset` of 1 ms
|
||||
sweeping down at 10 ms/s is 0 after 0.1 s and 1 ms again after 0.2 s. It never goes past 20 ms.
|
||||
At `depth` 0 the copy only sweeps, as sfxr's does. `feedback` sends the copy back into the line,
|
||||
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
|
||||
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
|
||||
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
|
||||
through a Phaser at 1 kHz came out at an RMS of 0.0000 with two stages and 0.5657 with four
|
||||
(0.8 * 0.707, untouched). Swept 4 octaves wide once a second, the RMS over 25 ms windows ran
|
||||
between 0.07 and 0.501 (0.8 * 0.707 * cos(28°) = 0.496 two octaves off). A Flanger at 1 ms gave
|
||||
an impulse back after 48 samples at 0.5. Sweeping 100 ms/s from the start of its voice, an
|
||||
impulse 0.1 s in came back 533.3 samples later, as worked out.
|
||||
- **Cost**: in the same run 64 stereo voices rendered for 2 s say about **47 Phasers** of 12
|
||||
stages with feedback, or about **63 Flangers** with an LFO, fill the audio thread. 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.
|
||||
|
||||
Reference in new issue
Block a user