mirror of
https://github.com/eliasstepanik/strudel.git
synced 2026-01-11 21:58:37 +00:00
add recipes
This commit is contained in:
parent
4fa0a9064b
commit
d9db5263e8
313
website/src/pages/recipes/recipes.mdx
Normal file
313
website/src/pages/recipes/recipes.mdx
Normal file
@ -0,0 +1,313 @@
|
||||
---
|
||||
title: Recipes
|
||||
layout: ../../layouts/MainLayout.astro
|
||||
---
|
||||
|
||||
import { MiniRepl } from '../../docs/MiniRepl';
|
||||
|
||||
# Recipes
|
||||
|
||||
This page shows possible ways to achieve common (or not so common) musical goals.
|
||||
There are often many ways to do a thing and there is no right or wrong.
|
||||
The fun part is that each representation will give you different impulses when improvising.
|
||||
|
||||
## Arpeggios
|
||||
|
||||
An arpeggio is when the notes of a chord are played in sequence.
|
||||
We can either write the notes by hand:
|
||||
|
||||
<MiniRepl
|
||||
client:visible
|
||||
tune={`note("c eb g c4")
|
||||
.clip(2).s("gm_electric_guitar_clean")`}
|
||||
punchcard
|
||||
/>
|
||||
|
||||
...or use scales:
|
||||
|
||||
<MiniRepl
|
||||
client:visible
|
||||
tune={`n("0 2 4 7").scale("C:minor")
|
||||
.clip(2).s("gm_electric_guitar_clean")`}
|
||||
punchcard
|
||||
/>
|
||||
|
||||
...or chord symbols:
|
||||
|
||||
<MiniRepl
|
||||
client:visible
|
||||
tune={`n("0 1 2 3").chord("Cm").mode("above:c3").voicing()
|
||||
.clip(2).s("gm_electric_guitar_clean")`}
|
||||
punchcard
|
||||
/>
|
||||
|
||||
...using off:
|
||||
|
||||
<MiniRepl
|
||||
client:visible
|
||||
tune={`"0"
|
||||
.off(1/3, add(2))
|
||||
.off(1/2, add(4))
|
||||
.n()
|
||||
.scale("C:minor")
|
||||
.s("gm_electric_guitar_clean")`}
|
||||
punchcard
|
||||
/>
|
||||
|
||||
## Chopping Breaks
|
||||
|
||||
A sample can be looped and chopped like this:
|
||||
|
||||
<MiniRepl
|
||||
client:visible
|
||||
tune={`await samples('github:yaxu/clean-breaks/main')
|
||||
s("amen/8").fit().chop(16)`}
|
||||
punchcard
|
||||
/>
|
||||
|
||||
This fits the break into 8 cycles + chops it in 16 pieces.
|
||||
The chops are not audible yet, because we're not doing any manipulation.
|
||||
Let's add randmized doubling + reversing:
|
||||
|
||||
<MiniRepl
|
||||
client:visible
|
||||
tune={`await samples('github:yaxu/clean-breaks/main')
|
||||
s("amen/8").fit().chop(16).cut(1)
|
||||
.sometimesBy(.5, ply(2))
|
||||
.sometimesBy(.25, mul(speed(-1)))`}
|
||||
punchcard
|
||||
/>
|
||||
|
||||
If we want to specify the order of samples, we can replace `chop` with `slice`:
|
||||
|
||||
<MiniRepl
|
||||
client:visible
|
||||
tune={`await samples('github:yaxu/clean-breaks/main')
|
||||
s("amen/8").fit()
|
||||
.slice(8, "<0 1 2 3 4*2 5 6 [6 7]>")
|
||||
.cut(1).rarely(ply(2))`}
|
||||
punchcard
|
||||
/>
|
||||
|
||||
If we use `splice` instead of `slice`, the speed adjusts to the duration of the event:
|
||||
|
||||
<MiniRepl
|
||||
client:visible
|
||||
tune={`await samples('github:yaxu/clean-breaks/main')
|
||||
s("amen")
|
||||
.splice(8, "<0 1 2 3 4*2 5 6 [6 7]>")
|
||||
.cut(1).rarely(ply(2))`}
|
||||
punchcard
|
||||
/>
|
||||
|
||||
Note that we don't need `fit`, because `splice` will do that by itself.
|
||||
|
||||
## Filter Envelopes
|
||||
|
||||
A minimal filter envelope looks like this:
|
||||
|
||||
<MiniRepl
|
||||
client:visible
|
||||
tune={`note("g1 bb1 <c2 eb2> d2")
|
||||
.s("sawtooth")
|
||||
.lpf(400).lpa(.2).lpenv(4)
|
||||
.scope()`}
|
||||
/>
|
||||
|
||||
We can flip the envelope by setting `lpenv` negative + add some resonance `lpq`:
|
||||
|
||||
<MiniRepl
|
||||
client:visible
|
||||
tune={`note("g1 bb1 <c2 eb2> d2")
|
||||
.s("sawtooth").lpq(8)
|
||||
.lpf(400).lpa(.2).lpenv(-4)
|
||||
.scope()`}
|
||||
/>
|
||||
|
||||
## Layering Sounds
|
||||
|
||||
We can layer sounds by separating them with ",":
|
||||
|
||||
<MiniRepl
|
||||
client:visible
|
||||
tune={`note("<g1 bb1 d2 f1>")
|
||||
.s("sawtooth, square") // <------
|
||||
.scope()`}
|
||||
/>
|
||||
|
||||
We can control the gain of individual sounds like this:
|
||||
|
||||
<MiniRepl
|
||||
client:visible
|
||||
tune={`note("<g1 bb1 d2 f1>")
|
||||
.s("sawtooth, square:0:.5") // <--- "name:number:gain"
|
||||
.scope()`}
|
||||
/>
|
||||
|
||||
For more control over each voice, we can use `layer`:
|
||||
|
||||
<MiniRepl
|
||||
client:visible
|
||||
tune={`note("<g1 bb1 d2 f1>").layer(
|
||||
x=>x.s("sawtooth").vib(4),
|
||||
x=>x.s("square").add(note(12))
|
||||
).scope()`}
|
||||
/>
|
||||
|
||||
Here, we give the sawtooth a vibrato and the square is moved an octave up.
|
||||
With `layer`, you can use any pattern method available on each voice, so sky is the limit..
|
||||
|
||||
## Oscillator Detune
|
||||
|
||||
We can fatten a sound by adding a detuned version to itself:
|
||||
|
||||
<MiniRepl
|
||||
client:visible
|
||||
tune={`note("<g1 bb1 d2 f1>")
|
||||
.add(note("0,.1")) // <------ chorus
|
||||
.s("sawtooth").scope()`}
|
||||
punchcard
|
||||
/>
|
||||
|
||||
Try out different values, or add another voice!
|
||||
|
||||
## Polyrhythms
|
||||
|
||||
Here is a simple example of a polyrhythm:
|
||||
|
||||
<MiniRepl client:visible tune={`s("bd*2,hh*3")`} punchcard />
|
||||
|
||||
A polyrhythm is when 2 different tempos happen at the same time.
|
||||
|
||||
## Polymeter
|
||||
|
||||
This is a polymeter:
|
||||
|
||||
<MiniRepl client:visible tune={`s("<bd rim>,<hh hh oh>").fast(2)`} punchcard />
|
||||
|
||||
A polymeter is when 2 different bar lengths play at the same tempo.
|
||||
|
||||
## Phasing
|
||||
|
||||
This is a phasing:
|
||||
|
||||
<MiniRepl client:visible tune={`note("<C D G A Bb D C A G D Bb A>*[6,6.1]").piano()`} punchcard />
|
||||
|
||||
Phasing happens when the same sequence plays at slightly different tempos.
|
||||
|
||||
## Running through samples
|
||||
|
||||
Using `run` with `n`, we can rush through a sample bank:
|
||||
|
||||
<MiniRepl
|
||||
client:visible
|
||||
tune={`await samples('github:Bubobubobubobubo/Dough-Fox/main')
|
||||
n(run(8)).s("ftabla")`}
|
||||
punchcard
|
||||
/>
|
||||
|
||||
This works great with sample banks that contain similar sounds, like in this case different recordings of a tabla.
|
||||
Often times, you'll hear the beginning of the phrase not where the pattern begins.
|
||||
In this case, I hear the beginning at the third sample, which can be accounted for with `early`.
|
||||
|
||||
<MiniRepl
|
||||
client:visible
|
||||
tune={`await samples('github:Bubobubobubobubo/Dough-Fox/main')
|
||||
n(run(8)).s("ftabla").early(2/8)`}
|
||||
/>
|
||||
|
||||
Let's add some randomness:
|
||||
|
||||
<MiniRepl
|
||||
client:visible
|
||||
tune={`await samples('github:Bubobubobubobubo/Dough-Fox/main')
|
||||
n(run(8)).s("ftabla").early(2/8)
|
||||
.sometimes(mul(speed(1.5)))`}
|
||||
/>
|
||||
|
||||
## Tape Warble
|
||||
|
||||
We can emulate a pitch warbling effect like this:
|
||||
|
||||
<MiniRepl
|
||||
client:visible
|
||||
tune={`note("c4 bb f eb")
|
||||
.add(note(perlin.range(0,.5))) // <------ warble
|
||||
.clip(2).s("gm_electric_guitar_clean")`}
|
||||
/>
|
||||
|
||||
## Sound Duration
|
||||
|
||||
There are a number of ways to change the sound duration. Using clip:
|
||||
|
||||
<MiniRepl
|
||||
client:visible
|
||||
tune={`note("f ab bb c")
|
||||
.clip("<2 1 .5 .25>/2")`}
|
||||
/>
|
||||
|
||||
The value of clip is relative to the duration of each event.
|
||||
We can also create overlaps using release:
|
||||
|
||||
<MiniRepl
|
||||
client:visible
|
||||
tune={`note("f ab bb c")
|
||||
.release("<2 1 .5 .002>/2")`}
|
||||
/>
|
||||
|
||||
This will smoothly fade out each sound for the given number of seconds.
|
||||
We could also make the notes shorter with decay / sustain:
|
||||
|
||||
<MiniRepl
|
||||
client:visible
|
||||
tune={`note("f ab bb c")
|
||||
.decay("<.2 .1 .02>/2").sustain(0)`}
|
||||
/>
|
||||
|
||||
For now, there is a limitation where decay values that exceed the event duration may cause little cracks, so use higher numbers with caution..
|
||||
|
||||
When using samples, we also have `.end` to cut relative to the sample length:
|
||||
|
||||
<MiniRepl client:visible tune={`s("oh*4").end("<1 .5 .25 .1>")`} />
|
||||
|
||||
Compare that to clip:
|
||||
|
||||
<MiniRepl client:visible tune={`s("oh*4").clip("<1 .5 .25 .1>")`} />
|
||||
|
||||
or decay / sustain
|
||||
|
||||
<MiniRepl client:visible tune={`s("oh*4").decay("<.2 .12 .06 .01>").sustain(0)`} />
|
||||
|
||||
## Wavetable Synthesis
|
||||
|
||||
You can loop a sample with `loop` / `loopEnd`:
|
||||
|
||||
<MiniRepl client:visible tune={`note("<c eb g f>").s("bd").loop(1).loopEnd(.05)`} />
|
||||
|
||||
This allows us to play the first 5% of the bass drum as a synth!
|
||||
To simplify loading wavetables, any sample that starts with `wt_` will be looped automatically:
|
||||
|
||||
<MiniRepl
|
||||
client:visible
|
||||
tune={`await samples('github:bubobubobubobubo/dough-waveforms/main')
|
||||
note("c eb g bb").s("wt_dbass").clip(2)`}
|
||||
/>
|
||||
|
||||
Running through different wavetables can also give interesting variations:
|
||||
|
||||
<MiniRepl
|
||||
client:visible
|
||||
tune={`await samples('github:bubobubobubobubo/dough-waveforms/main')
|
||||
note("c2*8").s("wt_dbass").n(run(8))`}
|
||||
/>
|
||||
|
||||
...adding a filter envelope + reverb:
|
||||
|
||||
|
||||
<MiniRepl
|
||||
client:visible
|
||||
tune={`await samples('github:bubobubobubobubo/dough-waveforms/main')
|
||||
note("c2*8").s("wt_dbass").n(run(8))
|
||||
.lpf(perlin.range(200,2000).slow(8))
|
||||
.lpenv(-3).lpa(.1).room(.5)`}
|
||||
/>
|
||||
Loading…
x
Reference in New Issue
Block a user