Merge pull request 'Signal flow documentation' (#1504) from glossing/strudel:glossing/signal-flow-documentation into main
Reviewed-on: https://codeberg.org/uzu/strudel/pulls/1504 Reviewed-by: Switch Angel AKA Jade Rose <daslyfe@noreply.codeberg.org>
This commit is contained in:
commit
f2608e712b
2 changed files with 123 additions and 0 deletions
BIN
website/public/img/strudel-signal-flow.png
Normal file
BIN
website/public/img/strudel-signal-flow.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 36 KiB |
|
|
@ -11,6 +11,129 @@ 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.
|
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.
|
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 occur _in order_ and only if they've been called in the pattern. Note that all of these are
|
||||||
|
single use effects, meaning that multiple occurrences of them in a pattern will simply override the values
|
||||||
|
(e.g. you can't 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
|
||||||
|
- Dry output (amount controlled by `dry` parameter)
|
||||||
|
- The sends
|
||||||
|
- Analyzers
|
||||||
|
- These are used for tooling like `scope` and `spectrum` and their setup usually happens behind the scenes
|
||||||
|
- Delay (amount controlled by `delay` parameter)
|
||||||
|
- Reverb (amount controlled by `room` parameter)
|
||||||
|
- The dry output, delay, and reverb are joined into what is called the "orbit" of the pattern (see more in the section below)
|
||||||
|
- The `duck` effect affects the volume of all signals in the orbit
|
||||||
|
- The orbit is then sent to the mixer
|
||||||
|
|
||||||
|
## Orbits
|
||||||
|
|
||||||
|
Orbits are the way in which outputs are handled in Strudel. They also prescribe which delay and reverb to associate with the dry signal.
|
||||||
|
By default, all orbits are mixed down to channels `1` and `2` in stereo, however with the "Multi Channel Orbits" setting
|
||||||
|
(under Settings at the right) you can use them as individual 2 channel stereo outs (orbit `i` will be mapped to
|
||||||
|
to channels `2i` and `2i + 1`). You can then use routers like Blackhole 16 to retrieve and record all of the channels in a DAW for later processing.
|
||||||
|
|
||||||
|
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:
|
||||||
|
|
||||||
|
<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 sampled 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 (`tremolo`)
|
||||||
|
- Phaser (`phaser`)
|
||||||
|
- Vibrato (`vib`)
|
||||||
|
- Ducking (`duckorbit`)
|
||||||
|
|
||||||
# Filters
|
# Filters
|
||||||
|
|
||||||
Filters are an essential building block of [subtractive synthesis](https://en.wikipedia.org/wiki/Subtractive_synthesis).
|
Filters are an essential building block of [subtractive synthesis](https://en.wikipedia.org/wiki/Subtractive_synthesis).
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue