Merge branch 'main' into feature/592-sound-alias
This commit is contained in:
commit
e57bd98da0
70 changed files with 2125 additions and 208 deletions
|
|
@ -44,7 +44,7 @@ xxx("foo").yyy("bar")
|
|||
|
||||
Generally, `xxx` and `yyy` are called [_functions_](<https://en.wikipedia.org/wiki/Function_(computer_programming)>), while `foo` and `bar` are called function [_arguments_ or _parameters_](<https://en.wikipedia.org/wiki/Parameter_(computer_programming)>).
|
||||
So far, we've used the functions to declare which aspect of the sound we want to control, and their arguments for the actual data.
|
||||
The `yyy` function is called a [_chained_ function](https://en.wikipedia.org/wiki/Method_chaining), because it is appended with a dot (`.`).
|
||||
The `yyy` function is called a [_chained_ function](https://en.wikipedia.org/wiki/Method_chaining), because it is preceded with a dot (`.`).
|
||||
|
||||
Generally, the idea with chaining is that code such as `a("this").b("that").c("other")` allows `a`, `b` and `c` functions to happen in a specified order, without needing to write them as three separate lines of code.
|
||||
You can think of this as being similar to chaining audio effects together using guitar pedals or digital audio effects.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
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 are an essential building block of [subtractive synthesis](https://en.wikipedia.org/wiki/Subtractive_synthesis).
|
||||
|
|
|
|||
|
|
@ -168,6 +168,20 @@ Using "!" we can repeat without speeding up:
|
|||
|
||||
<MiniRepl client:idle tune={`note("<[g3,b3,e4]!2 [a3,c3,e4] [b3,d3,f#4]>*2")`} punchcard />
|
||||
|
||||
## Randomness
|
||||
|
||||
Events with a "?" placed after them will have a 50% chance of being removed from the pattern:
|
||||
|
||||
<MiniRepl client:idle tune={`note("[g3,b3,e4]*8?")`} punchcard />
|
||||
|
||||
Adding a number between 0 and 1 after the "?" will affect the likelihood of the event being removed. For example, events with "?0.1" placed after them will have a 10% chance of being removed:
|
||||
|
||||
<MiniRepl client:idle tune={`note("[g3,b3,e4]*8?0.1")`} punchcard />
|
||||
|
||||
Events separated by a "|" will be chosen from at random:
|
||||
|
||||
<MiniRepl client:idle tune={`note("[g3,b3,e4] | [a3,c3,e4] | [b3,d3,f#4]")`} punchcard />
|
||||
|
||||
## Mini-notation review
|
||||
|
||||
To recap what we've learned so far, compare the following patterns:
|
||||
|
|
@ -179,6 +193,8 @@ To recap what we've learned so far, compare the following patterns:
|
|||
<MiniRepl client:idle tune={`note("<[g3,b3,e4] _ [a3,c3,e4] [b3,d3,f#4]>*2")`} />
|
||||
<MiniRepl client:idle tune={`note("<[g3,b3,e4]@2 [a3,c3,e4] [b3,d3,f#4]>*2")`} />
|
||||
<MiniRepl client:idle tune={`note("<[g3,b3,e4]!2 [a3,c3,e4] [b3,d3,f#4]>*2")`} />
|
||||
<MiniRepl client:idle tune={`note("<[g3,b3,e4]? [a3,c3,e4] [b3,d3,f#4]>*2")`} />
|
||||
<MiniRepl client:idle tune={`note("<[g3|b3|e4] [a3,c3,e4] [b3,d3,f#4]>*2")`} />
|
||||
|
||||
## Euclidian rhythms
|
||||
|
||||
|
|
|
|||
95
website/src/pages/learn/xen.mdx
Normal file
95
website/src/pages/learn/xen.mdx
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
---
|
||||
title: Xen Harmonic Functions
|
||||
layout: ../../layouts/MainLayout.astro
|
||||
---
|
||||
|
||||
import { MiniRepl } from '../../docs/MiniRepl';
|
||||
import { JsDoc } from '../../docs/JsDoc';
|
||||
|
||||
# Xen Harmonic Functions
|
||||
|
||||
These functions allow the use of scales other than your typical chromatic 12 based ones.
|
||||
|
||||
### tune(scale)
|
||||
|
||||
<JsDoc client:idle name="tune" h={0} />
|
||||
|
||||
Here's an example of how to configure a basic hexany scale:
|
||||
|
||||
<MiniRepl client:idle tune={`"0 1 2 3 4 5".tune("hexany15").mul("220").freq()`} />
|
||||
|
||||
Try other scales like `hexany1`, `iraq`, `gumbeng`, `gunkali`, or `tranh3`
|
||||
|
||||
For a full list of available scales from tunejs, see http://abbernie.github.io/tune/scales.html
|
||||
|
||||
You can set your root to be a particular note with `getFreq`
|
||||
|
||||
<MiniRepl
|
||||
client:idle
|
||||
tune={`"4 8 9 10 - - 5 7 9 11 - -".tune("tranh3")
|
||||
.mul(getFreq('c3'))
|
||||
.freq().clip(.5).room(1)`}
|
||||
/>
|
||||
|
||||
Some tunings become more pronounced with a longer reverb decay:
|
||||
|
||||
<MiniRepl
|
||||
client:idle
|
||||
tune={`"<[5 6 8 10] - [5 7 9 12] -> -".tune("gumbeng")
|
||||
.mul(getFreq('c3'))
|
||||
.freq().clip(.8).room("3:10").rdim(10000).rfade(5)`}
|
||||
/>
|
||||
|
||||
Additionally, you can combo this with `fmap` so that the base note changes:
|
||||
|
||||
<MiniRepl
|
||||
client:idle
|
||||
tune={`"9 11 12 10 - - -".tune("gunkali")
|
||||
.mul("<c3 c3 a3 d#3>".fmap(getFreq))
|
||||
.freq().legato("2 .7").room("1:15").rdim(8500).rlp(14000).rfade(8)`}
|
||||
/>
|
||||
|
||||
Combining this with various polyrhythm tricks can become very evocative:
|
||||
|
||||
<MiniRepl
|
||||
client:idle
|
||||
tune={`"<[0 3 1 -] [-1 4 2 8]> ~ ~,<-4 -5>"
|
||||
.transpose(4)
|
||||
.tune("iraq")
|
||||
.mul("<c3 d3 c#3>".fmap(getFreq))
|
||||
.freq().clip(.5).room(1).rfade(9)`}
|
||||
/>
|
||||
|
||||
Another helpful trick when exploring new tunings is to strum them.
|
||||
Many have a much more enchanting sound that was chosen over many generations of musicians for being strummed.
|
||||
|
||||
Take the `sanza` tuning:
|
||||
|
||||
<MiniRepl
|
||||
client:idle
|
||||
tune={`"4 5 6 7 8 9".tune("sanza")
|
||||
.mul(getFreq('c3'))
|
||||
.freq()`}
|
||||
/>
|
||||
|
||||
Notes 7 and 9 will clash quite a bit if you arp them normally. Many tunings will have this sort of sound, and it can feel distracting on its own.
|
||||
See how close they are on the pitch wheel?
|
||||
|
||||
<MiniRepl client:idle tune={`"[7 9]!3".tune("sanza").mul(getFreq('c3')).freq()._pitchwheel()`} />
|
||||
|
||||
This quality is often due to how the tunings were formed with instruments that were played differently than a piano.
|
||||
As such, some tunings are much better strummed, with the subtle clash of the detuned notes actually making the sound much more magical:
|
||||
|
||||
<MiniRepl
|
||||
client:idle
|
||||
tune={`"[0 1 2 3 4 5 6]@0.3 -"
|
||||
.transpose("<2 5 8 1>")
|
||||
.tune("sanza")
|
||||
.mul(getFreq('c3')).freq()
|
||||
.legato("3").room(1).rfade(5)`}
|
||||
/>
|
||||
|
||||
Note the legato and reverb effects make sure the sound of the strumming gets to wash together. Alternating the direction of the strum can make the
|
||||
tones sound even more alive, too.
|
||||
|
||||
The `tranh3` tuning has a similar set of notes, with two clashing. You might trying plugging that in above and see if you find a favorite strumming pattern.
|
||||
Loading…
Add table
Add a link
Reference in a new issue