lfo documentation
This commit is contained in:
parent
daf27ed971
commit
d930057000
1 changed files with 294 additions and 0 deletions
294
website/src/pages/learn/lfo.mdx
Normal file
294
website/src/pages/learn/lfo.mdx
Normal file
|
|
@ -0,0 +1,294 @@
|
|||
---
|
||||
title: Low-frequency oscillators (LFO)
|
||||
layout: ../../layouts/MainLayout.astro
|
||||
---
|
||||
|
||||
import { MiniRepl } from '../../docs/MiniRepl';
|
||||
import { JsDoc } from '../../docs/JsDoc';
|
||||
|
||||
# Low frequency oscillators (LFO)
|
||||
|
||||
A low frequency oscillator (or short LFO) is a common way on synthesizers to continuously modulate various signals.
|
||||
|
||||
This documentation is an interactive version of glossing's tutorial https://www.youtube.com/watch?v=11frBA9L638
|
||||
|
||||
## Applying an LFO
|
||||
|
||||
Here, the LFO will change the frequency of the `saw`. Put a comment like this `//.lfo()` to see and hear how it changes, and remove the comment again.
|
||||
|
||||
<MiniRepl
|
||||
client:idle
|
||||
tune={`
|
||||
s("saw").lfo()
|
||||
.lpf(800)
|
||||
._spectrum({height: 300, width: 800})`}
|
||||
/>
|
||||
|
||||
By default, the LFO will modulate the control parameter which is right before `.lfo()`:
|
||||
|
||||
<MiniRepl
|
||||
client:idle
|
||||
tune={`
|
||||
s("saw")
|
||||
.lpf(800).lfo()
|
||||
._spectrum({height: 300, width: 800})`}
|
||||
/>
|
||||
|
||||
Here, the LFO will modulate the low pass filter `.lpf`.
|
||||
|
||||
## Moving away from the default
|
||||
|
||||
The following sections explain how pass parameters to `.lfo`. Similar to `._spectrum` above, almost all the configuration of `lfo` lives inside a json object, starting with `{` and ending with `}`.
|
||||
All the parameters (except `id`) are written as `key: value` inside and separated by `,`.
|
||||
|
||||
The reference refers to them as `config.key`, i.e. for the following one as `config.control` but you use them like below.
|
||||
|
||||
## Control
|
||||
|
||||
`control` determines which parameter will be modulated. This allows you to place your `lfo` at different places,
|
||||
not necessarily immediately after the controlled parameter.
|
||||
|
||||
Here, we place `lfo` after the `s`, but it modulates the low pass filter.
|
||||
|
||||
<MiniRepl
|
||||
client:idle
|
||||
tune={`
|
||||
s("saw")
|
||||
.lfo({control:'lpf'})
|
||||
.lpf(800)
|
||||
._spectrum({height: 300, width: 800})`}
|
||||
/>
|
||||
You can even influence parameters which are always present, even if you haven't explicitly written them, like `gain`.
|
||||
|
||||
<MiniRepl
|
||||
client:idle
|
||||
tune={`
|
||||
s("saw")
|
||||
.lfo({control:'gain'})
|
||||
.lpf(800)
|
||||
._spectrum({height: 300, width: 800})`}
|
||||
/>
|
||||
|
||||
`control` has an alias `c`.
|
||||
|
||||
## Rate
|
||||
|
||||
`rate` determines how often the `lfo` oscillates per second:
|
||||
|
||||
<MiniRepl
|
||||
client:idle
|
||||
tune={`
|
||||
s("saw")
|
||||
.lfo({c:'gain', rate:"<2 4>"})
|
||||
.lpf(800)
|
||||
._spectrum({height: 300, width: 800})`}
|
||||
/>
|
||||
The alias of `rate` is `r`.{' '}
|
||||
|
||||
## Sync
|
||||
|
||||
Instead of controlling the frequency with `rate` by setting a frequency in Hz, you can use `sync`
|
||||
to snychronize your lfo with your other patterns.
|
||||
|
||||
`sync` expresses this frequency as "times per cycle"
|
||||
|
||||
Try removing the `sync: "<2 4 8 0.5 >"` from the pattern and notice that there is something not in sync.
|
||||
|
||||
<MiniRepl
|
||||
client:idle
|
||||
tune={`
|
||||
$: s("bd*4").bank("TR909").postgain(0.5)
|
||||
$: s("saw")
|
||||
.lpf(800)
|
||||
.lfo({sync: "<2 4 8 0.5 >"})
|
||||
._spectrum({height: 300, width: 800})`}
|
||||
/>
|
||||
|
||||
You can put patterns into the parameters of `lfo` if you want them to change over time, as seen above.
|
||||
|
||||
## Relative Depth
|
||||
|
||||
`.depth` is relative depth, a value of 1 (the default) means that
|
||||
the value goes above and below by half of the value which is being modulated
|
||||
|
||||
E.g. for depth `1`, it modulates the frequency to oscillate between 32 = (64/2) and 96 (= 64 + 64/2).
|
||||
|
||||
<MiniRepl
|
||||
client:idle
|
||||
tune={`
|
||||
s("saw").freq(64)
|
||||
.lfo({r: 2, depth: "<1 2 3>"})
|
||||
.lpf(800)
|
||||
._spectrum({height: 300, width: 800})`}
|
||||
/>
|
||||
The `freq` is not needed here, as this is the default frequency, it's just for instructive purposes.
|
||||
|
||||
The aliases of `depth` are `dr` and `dep`.
|
||||
|
||||
## Absolute Depth
|
||||
|
||||
`depthabs` controls the absolute modulation depth. For example you can modulate
|
||||
the low pass filter by exactly 250 Hz up and below:
|
||||
|
||||
<MiniRepl
|
||||
client:idle
|
||||
tune={`
|
||||
s("saw")
|
||||
.lpf(800)
|
||||
.lfo({r: 2, depthabs: "250"})`}
|
||||
/>
|
||||
|
||||
The alias of `depthabs` is `da`.
|
||||
|
||||
## DC offset
|
||||
|
||||
If you don't want to go up or down by the same amount with your modulation, then you can shift the center of the modulation with `dcoffset`.
|
||||
The default value is -0.5, which is the middle point between:
|
||||
"dcoffset = 0: All modulations increase the control parameter (or keep it constant)"
|
||||
"dcoffset = -1: All modulations decrease the control parameter (or keep it constant)"
|
||||
|
||||
Other values will work as well.
|
||||
|
||||
<MiniRepl
|
||||
client:idle
|
||||
tune={`
|
||||
s("saw")
|
||||
.lpf(600)
|
||||
.lfo({r: 2, da: "200", dcoffset: "<-0.5 -1 -0.5 0>"})`}
|
||||
/>
|
||||
The marvellous alias of `dcoffset` is `dc`.
|
||||
|
||||
## Shape
|
||||
|
||||
You can change the shape of the modulation with `shape`. The default is `triangle`, but other shapes are available too:
|
||||
|
||||
<MiniRepl
|
||||
client:idle
|
||||
tune={`
|
||||
s("saw")
|
||||
.lpf(800)
|
||||
.lfo({r: 2, shape: "<triangle sine ramp saw square>"}) `}
|
||||
/>
|
||||
You can add `._spectrum()` to see the shape of the modulations in the spectrum.
|
||||
|
||||
You can also get these shapes by using numbers:
|
||||
|
||||
| Shape | number |
|
||||
| -------- | ------ |
|
||||
| triangle | 0 |
|
||||
| sine | 1 |
|
||||
| ramp | 2 |
|
||||
| saw | 3 |
|
||||
| square | 4 |
|
||||
|
||||
this way, you can use a function like `irand` to generate numbers:
|
||||
|
||||
<MiniRepl
|
||||
client:idle
|
||||
tune={`
|
||||
s("saw")
|
||||
.lpf(800)
|
||||
.lfo({r: 2, shape: irand(4)}) `}
|
||||
/>
|
||||
|
||||
The alias of `shape` is `sh`.
|
||||
|
||||
## Skewing some shapes
|
||||
|
||||
You can influence some of the shapes (`triangle` and `square`) in more detail.
|
||||
|
||||
The default skew is 0.5, it does different things for these two.
|
||||
|
||||
For `triangle`, it skews the top of the triangle to the left or right,
|
||||
where 0 makes it look like `saw` and 1 makes it look like `ramp`.
|
||||
|
||||
For `square`, the skew influences the pulse width (see reference for `pulse` and `.pw`):
|
||||
|
||||
<MiniRepl
|
||||
client:idle
|
||||
tune={`
|
||||
s("saw")
|
||||
.lpf(800)
|
||||
.lfo({r: 2, sh: "<triangle square>/5",
|
||||
skew: "<0 0.25 0.5 0.75 1>"}) `}
|
||||
/>
|
||||
The alias of `skew` is `sk`.{' '}
|
||||
|
||||
## Curve
|
||||
|
||||
You can change the curves of your lfo and can make it more intense.
|
||||
The default value is 1. Writing numbers greater than one can make it more intense,
|
||||
numbers between 0 and 1 will make it less intense.
|
||||
This will raise the lfo to the power of curve, so larger numbers (such as 10) can have very unexpected results.
|
||||
|
||||
<MiniRepl
|
||||
client:idle
|
||||
tune={`
|
||||
s("saw")
|
||||
.lpf(800)
|
||||
.lfo({r: 2, sh: "<triangle>", curve: "<1.3 1 0.75 1>"}) `}
|
||||
/>
|
||||
## Referencing your lfos with id
|
||||
|
||||
All the lfos are numbered from the first starting with 0, the second having an `id` of 1 and so on.
|
||||
|
||||
You can refer to this in a later call if you want to modify a specific `lfo`.
|
||||
|
||||
The ´id´ is outside of the config json (which is different from the other parameters of `lfo()`
|
||||
|
||||
Try out how the sound changes when you replace the 0 with a 1.
|
||||
|
||||
<MiniRepl
|
||||
client:idle
|
||||
tune={`
|
||||
s("saw").lfo().lpf(800)
|
||||
.lfo({s: "<4 8 0.5>"})
|
||||
.sometimes(x => x.lfo({dr: "4"},0))`}
|
||||
/>
|
||||
|
||||
You can also name your lfos and refer to them by name, using the `id` parameter
|
||||
|
||||
<MiniRepl
|
||||
client:idle
|
||||
tune={`
|
||||
s("saw").lfo({}, "lfo_freq_saw").lpf(800)
|
||||
.lfo({s: "<4 8 0.5>"}, "lfo_lpf")
|
||||
.sometimes(x => x.lfo({dr: "4"},"<lfo_lpf lfo_freq_saw>"))`}
|
||||
/>
|
||||
|
||||
## FX index
|
||||
|
||||
If you are using `FX()` to reorder your effects, you dont need to write your lfos inside the `FX`,
|
||||
but instead can refer to them by their FX index (starting with 0)
|
||||
|
||||
<MiniRepl
|
||||
client:idle
|
||||
tune={`
|
||||
s("saw").FX(
|
||||
distort(3),
|
||||
gain(0.3), // this has the fx index 1
|
||||
lpf(400)
|
||||
).lfo({s: 16, dr:2, c:"gain", fxi: 1})`}
|
||||
/>
|
||||
|
||||
## Modulating other LFOs with Sub-control
|
||||
|
||||
LFOs can modulate other lfos and will modulate their frequency (given by `r` or `s`):
|
||||
|
||||
<MiniRepl
|
||||
client:idle
|
||||
tune={`
|
||||
s("saw").lpf(400).gain(0.8)
|
||||
.lfo({s: 16, dr:2, c:"gain"})
|
||||
.lfo({s: 0.3, dc:-1, dr: 0.8})`}
|
||||
/>
|
||||
To modulate other parameters of the first lfo (like `skew`, `depth` and so on), we can specify this with `subControl`or
|
||||
its alias `sc`
|
||||
|
||||
<MiniRepl
|
||||
client:idle
|
||||
tune={`
|
||||
s("saw").lpf(400).gain(0.8)
|
||||
.lfo({s: 4, dr:2, c:"gain"})
|
||||
.lfo({s: 0.3, sc: "skew"})`}
|
||||
/>
|
||||
Loading…
Add table
Add a link
Reference in a new issue