Update effects documentation to include information on signal flow

This commit is contained in:
Aria
2025-08-19 11:10:34 -05:00
parent 8e1e83f3cf
commit 32fe73aba2
2 changed files with 118 additions and 0 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

+118
View File
@@ -11,6 +11,124 @@ import { JsDoc } from '../../docs/JsDoc';
Whether you're using a synth or a sample, you can apply any of the following built-in audio effects.
As you might suspect, the effects can be chained together, and they accept a pattern string as their argument.
# Signal chain
<img src="/img/strudel-signal-flow.png"></img>
The signal chain in Strudel is as follows:
- An sound-generating event is triggered by a pattern
- This has a start time and a duration, which is usually
controlled by the note length and ADSR parameters
- If we exceed the max polyphony, old sounds begin to die off
- Muted sounds (one whose `s` value is `-`, `~`, or `_`) are skipped
- A sound is produced (through, say, a sample or an oscillator)
- This is where detune-based effects (like `detune`, `penv`, etc. occur)
- The following will only occur if their respective parameters are turned on. Note that all of these are
_single use_ effects, meaning that multiple occurrences of them in a pattern will simply override the values
(i.e. you can't (currently) do `s("bd").lpf(100).distort(2).lpf(800)` to lowpass, distort, and then lowpass
again)
- Phase vocoder (`stretch`)
- Gain is applied (`gain`)
- This is where the main (volume) ADSR happens
- A lowpass filter (`lpf`)
- A highpass filter (`hpf`)
- A bandpass filter (`bandpass`)
- A vowel filter (`vowel`)
- Sample rate reduction (`coarse`)
- Bit crushing (`crush`)
- Waveshape distortion (`shape`)
- Normal distortion (`distort`)
- Tremolo (`tremolo`)
- Compressor (`compressor`)
- Panning (`pan`)
- Phaser (`phaser`)
- Postgain (`post`)
- The sound is then split into multiple destinations
- Main output (amount controlled by `dry` parameter)
- This is where the `duck` function will apply sidechain
- Analyzer (used for tooling like `scope` and `spectrum`)
- Per-orbit effects (see the section below)
- Delay send (amount controlled by `delay` parameter)
- Reverb send (amount controlled by `delay` parameter)
## Orbits
Orbits are the way in which outputs are handled in Strudel. If you are listening in
normal circumstances, you will just hear all of them mixed down to stereo at the output. However you can also
use routers like Blackhole 16 to retrieve and record all of the split channels in a DAW for later processing.
By default all orbits are mono, however with the "Multi Channel Orbits" setting (under settings at the right)
you can use them as 2 channel stereo outs.
The default orbit is `1` and it is set with `orbit`. You may send a sound to multiple orbits via mininotation
<MiniRepl client:visible tune={`s("white").orbit("2,3,4").gain(0.2)`} />
but please be careful as this will create three copies of the sound behind the scenes, meaning that if they are mixed
down to a single output, they will triple the volume. We've reduced the gain here to save your ears.
⚠️ There is only one delay and reverb per orbit, so please be aware that if you attempt to change the parameters on two
patterns pointing to the same orbit, it can lead to unpredictable results. Compare, for example, this pretty pluck
with a large reverb:
<MiniRepl
client:visible
tune={`
$: s("triangle*4").decay(0.5).n(irand(12)).scale('C minor')
.room(1).roomsize(10)`}
/>
versus the same pluck with a muted kick drum coming in and overwriting the `roomsize` value (occasionally)
<MiniRepl
client:visible
tune={`
$: s("triangle*4").decay(0.5).n(irand(12)).scale('C minor')
.room(1).roomsize(10)
$: s("bd*4").room(0.01).roomsize(0.01).postgain(0)`}
/>
This is due to them sharing the same orbit (the default of `1`). It can be corrected simply by updating the orbits to be
distinct:
<MiniRepl
client:visible
tune={`
$: s("triangle*4").decay(0.5).n(irand(12)).scale('C minor')
.room(1).roomsize(10).orbit(2)
$: s("bd*4").room(0.01).roomsize(0.01).postgain(0)`}
/>
## Continuous changes
As all of the above is triggered by a _sound occurring_, it is often the case that parameters may not be
modified continuously in time. For example,
<MiniRepl
client:visible
tune={`
s("supersaw").lpf(tri.range(100, 5000).slow(2))`}
/>
Will not produce a continually LFO'd low-pass filter due to the `tri` only being sample every time the note hits
(in this case the default of once per cycle). You can fake it by introducing more sound-generating events, e.g.:
<MiniRepl
client:visible
tune={`
s("supersaw").seg(16).lpf(tri.range(100, 5000).slow(2))`
}
/>
Some parameters _do_ induce continuous variations in time, though:
* The ADSR curve (governed by `attack`, `sustain`, `decay`, `release`)
* The pitch envelope curve (governed by `penv` and its associated ADSR)
* The FM curve (`fmenv`)
* The filter envelopes (`lpenv`, `hpenv`, `bpenv`)
* Tremolo
* Phaser
# Filters
Filters are an essential building block of [subtractive synthesis](https://en.wikipedia.org/wiki/Subtractive_synthesis).