make 0.5hz cps the default (#931)
* 0.5 default cps * 1 -> 0.5 cps defaults * start moving examples to 2Hz * more 2Hz doc edits * small tweaks * format * adapt cycles page * adapt pitch page * tonal page * accumulation * synth page * adapt conditional-modifiers * audio effects page * adapt signals doc * fix: errors for signals * adapt signals page * start time modifiers * adapt time modifiers * adapt factories * hydra + pattern intro * adapt mini notation page * start recipes * adapt recipes page * use code_v1 table * delete old dbdump + add new csv based tool * fix: tests * fix: cpm * shuffle featured patterns * fix: snapshot --------- Co-authored-by: Felix Roos <flix91@gmail.com>
This commit is contained in:
parent
46c2c72637
commit
6422047cff
40 changed files with 3852 additions and 2386 deletions
|
|
@ -33,7 +33,7 @@ While the Mini Notation is a powerful way to write rhythms concisely, it also ha
|
|||
client:idle
|
||||
tune={`stack(
|
||||
note("c2 eb2(3,8)").s('sawtooth').cutoff(800),
|
||||
s("bd,~ sd,hh*4")
|
||||
s("bd(5,8), hh*8")
|
||||
)`}
|
||||
/>
|
||||
|
||||
|
|
|
|||
|
|
@ -28,6 +28,10 @@ import { JsDoc } from '../../docs/JsDoc';
|
|||
|
||||
<JsDoc client:idle name="Pattern.chunkBack" h={0} />
|
||||
|
||||
### fastChunk
|
||||
|
||||
<JsDoc client:idle name="Pattern.fastChunk" h={0} />
|
||||
|
||||
## arp
|
||||
|
||||
<JsDoc client:idle name="Pattern#arp" h={0} />
|
||||
|
|
|
|||
|
|
@ -150,7 +150,7 @@ Pitch envelopes can breathe life into static sounds:
|
|||
.s("gm_electric_guitar_jazz")
|
||||
.penv("<.5 0 7 -2>*2").vib("4:.1")
|
||||
.phaser(2).delay(.25).room(.3)
|
||||
.size(4).fast(.75)`}
|
||||
.size(4).fast(1.5)`}
|
||||
/>
|
||||
|
||||
You also create some lovely chiptune-style sounds:
|
||||
|
|
@ -163,7 +163,7 @@ You also create some lovely chiptune-style sounds:
|
|||
.voicing().add(note("<0 1>/8"))
|
||||
.dec(.1).room(.2)
|
||||
.segment("<4 [2 8]>")
|
||||
.penv("<0 <2 -2>>").patt(.02)`}
|
||||
.penv("<0 <2 -2>>").patt(.02).fast(2)`}
|
||||
/>
|
||||
|
||||
Let's break down all pitch envelope controls:
|
||||
|
|
|
|||
|
|
@ -36,7 +36,8 @@ osc(1, -0.9, 300)
|
|||
.scale(2)
|
||||
.out()
|
||||
|
||||
note("[a,c,e,<a4 ab4 g4 gb4>,b4]/4").s("sawtooth").vib(2)
|
||||
note("[a,c,e,<a4 ab4 g4 gb4>,b4]/2")
|
||||
.s("sawtooth").vib(2)
|
||||
.lpf(600).lpa(2).lpenv(6)
|
||||
`}
|
||||
/>
|
||||
|
|
@ -90,7 +91,7 @@ src(s0).kaleid(H("<4 5 6>"))
|
|||
.out()
|
||||
//
|
||||
stack(
|
||||
s("bd*2,[hh:0:<.5 1>]*4,~ rim").bank("RolandTR909").speed(.9),
|
||||
s("bd*4,[hh:0:<.5 1>]*8,~ rim").bank("RolandTR909").speed(.9),
|
||||
note("[<g1!3 <bb1 <f1 d1>>>]*3").s("sawtooth")
|
||||
.room(.75).sometimes(add(note(12))).clip(.3)
|
||||
.lpa(.05).lpenv(-4).lpf(2000).lpq(8).ftype('24db')
|
||||
|
|
|
|||
|
|
@ -22,27 +22,25 @@ Before diving deeper into the details, here is a flavour of how the Mini-Notatio
|
|||
|
||||
<MiniRepl
|
||||
client:idle
|
||||
tune={`note(\`[
|
||||
[
|
||||
[e5 [b4 c5] d5 [c5 b4]]
|
||||
[a4 [a4 c5] e5 [d5 c5]]
|
||||
[b4 [~ c5] d5 e5]
|
||||
[c5 a4 a4 ~]
|
||||
[[~ d5] [~ f5] a5 [g5 f5]]
|
||||
[e5 [~ c5] e5 [d5 c5]]
|
||||
[b4 [b4 c5] d5 e5]
|
||||
[c5 a4 a4 ~]
|
||||
],[
|
||||
[[e2 e3]*4]
|
||||
[[a2 a3]*4]
|
||||
[[g#2 g#3]*2 [e2 e3]*2]
|
||||
[a2 a3 a2 a3 a2 a3 b1 c2]
|
||||
[[d2 d3]*4]
|
||||
[[c2 c3]*4]
|
||||
[[b1 b2]*2 [e2 e3]*2]
|
||||
[[a1 a2]*4]
|
||||
]
|
||||
]/16\`)`}
|
||||
tune={`note(\`<
|
||||
[e5 [b4 c5] d5 [c5 b4]]
|
||||
[a4 [a4 c5] e5 [d5 c5]]
|
||||
[b4 [~ c5] d5 e5]
|
||||
[c5 a4 a4 ~]
|
||||
[[~ d5] [~ f5] a5 [g5 f5]]
|
||||
[e5 [~ c5] e5 [d5 c5]]
|
||||
[b4 [b4 c5] d5 e5]
|
||||
[c5 a4 a4 ~]
|
||||
,
|
||||
[[e2 e3]*4]
|
||||
[[a2 a3]*4]
|
||||
[[g#2 g#3]*2 [e2 e3]*2]
|
||||
[a2 a3 a2 a3 a2 a3 b1 c2]
|
||||
[[d2 d3]*4]
|
||||
[[c2 c3]*4]
|
||||
[[b1 b2]*2 [e2 e3]*2]
|
||||
[[a1 a2]*4]
|
||||
>\`)`}
|
||||
/>
|
||||
|
||||
## Mini Notation Format
|
||||
|
|
@ -74,9 +72,21 @@ Taking the two examples above, we have four and eight events respectively, and s
|
|||
This is perhaps counter-intuitive if you are used to adding notes in a sequencer or piano roll and the overall length increasing.
|
||||
But, it will begin to make sense as we go through more elements of mini-notation.
|
||||
|
||||
## Multiplication
|
||||
|
||||
A sequence can be sped up by multiplying it by a number using the asterisk symbol (`*`):
|
||||
|
||||
<MiniRepl client:idle tune={`note("[e5 b4 d5 c5]*2")`} punchcard />
|
||||
|
||||
The multiplication by two here means that the sequence will play twice per cycle.
|
||||
|
||||
Multiplications can also be decimal (`*2.75`):
|
||||
|
||||
<MiniRepl client:idle tune={`note("[e5 b4 d5 c5]*2.75")`} punchcard />
|
||||
|
||||
## Division
|
||||
|
||||
We can slow the sequence down by enclosing it in brackets and dividing it by a number (`/2`):
|
||||
Contrary to multiplication, division can slow the sequence down by enclosing it in brackets and dividing it by a number (`/2`):
|
||||
|
||||
<MiniRepl client:idle tune={`note("[e5 b4 d5 c5]/2")`} punchcard />
|
||||
|
||||
|
|
@ -102,18 +112,11 @@ The advantage of the angle brackets, is that we can add more events without need
|
|||
<MiniRepl client:idle tune={`note("<e5 b4 d5 c5 e5 b4>")`} punchcard />
|
||||
|
||||
This is more similar to traditional music sequencers and piano rolls, where adding a note increases the perceived overall duration.
|
||||
We can also play a certain number of notes per cycle by using angle brackets with multiplication:
|
||||
|
||||
## Multiplication
|
||||
<MiniRepl client:idle tune={`note("<e5 b4 d5 c5 a4 c5>*8")`} punchcard />
|
||||
|
||||
Contrary to division, a sequence can be sped up by multiplying it by a number using the asterisk symbol (`*`):
|
||||
|
||||
<MiniRepl client:idle tune={`note("[e5 b4 d5 c5]*2")`} punchcard />
|
||||
|
||||
The multiplication by two here means that the sequence will play twice per cycle.
|
||||
|
||||
As with divisions, multiplications can be decimal (`*2.75`):
|
||||
|
||||
<MiniRepl client:idle tune={`note("[e5 b4 d5 c5]*2.75")`} punchcard />
|
||||
Now we are playing 8 notes per cycle!
|
||||
|
||||
## Subdividing time with bracket nesting
|
||||
|
||||
|
|
@ -149,13 +152,13 @@ The following are the same:
|
|||
|
||||
But to play multiple chords in a sequence, we have to wrap them in brackets:
|
||||
|
||||
<MiniRepl client:idle tune={`note("<[g3,b3,e4] [a3,c3,e4] [b3,d3,f#4] [b3,e4,g4]>")`} punchcard />
|
||||
<MiniRepl client:idle tune={`note("<[g3,b3,e4] [a3,c3,e4] [b3,d3,f#4] [b3,e4,g4]>*2")`} punchcard />
|
||||
|
||||
## Elongation
|
||||
|
||||
With the "@" symbol, we can specify temporal "weight" of a sequence child:
|
||||
|
||||
<MiniRepl client:idle tune={`note("<[g3,b3,e4]@2 [a3,c3,e4] [b3,d3,f#4]>")`} punchcard />
|
||||
<MiniRepl client:idle tune={`note("<[g3,b3,e4]@2 [a3,c3,e4] [b3,d3,f#4]>*2")`} punchcard />
|
||||
|
||||
Here, the first chord has a weight of 2, making it twice the length of the other chords. The default weight is 1.
|
||||
|
||||
|
|
@ -163,19 +166,19 @@ Here, the first chord has a weight of 2, making it twice the length of the other
|
|||
|
||||
Using "!" we can repeat without speeding up:
|
||||
|
||||
<MiniRepl client:idle tune={`note("<[g3,b3,e4]!2 [a3,c3,e4] [b3,d3,f#4]>")`} punchcard />
|
||||
<MiniRepl client:idle tune={`note("<[g3,b3,e4]!2 [a3,c3,e4] [b3,d3,f#4]>*2")`} punchcard />
|
||||
|
||||
## Mini-notation review
|
||||
|
||||
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]>")`} />
|
||||
<MiniRepl client:idle tune={`note("<[g3,b3,e4] [a3,c3,e4] [b3,d3,f#4]>")`} />
|
||||
<MiniRepl client:idle tune={`note("<[g3,b3,e4]/2 [a3,c3,e4] [b3,d3,f#4]>")`} />
|
||||
<MiniRepl client:idle tune={`note("<[g3,b3,e4]*2 [a3,c3,e4] [b3,d3,f#4]>")`} />
|
||||
<MiniRepl client:idle tune={`note("<[g3,b3,e4] _ [a3,c3,e4] [b3,d3,f#4]>")`} />
|
||||
<MiniRepl client:idle tune={`note("<[g3,b3,e4]@2 [a3,c3,e4] [b3,d3,f#4]>")`} />
|
||||
<MiniRepl client:idle tune={`note("<[g3,b3,e4]!2 [a3,c3,e4] [b3,d3,f#4]>")`} />
|
||||
<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")`} />
|
||||
<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]@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")`} />
|
||||
|
||||
## Euclidian rhythms
|
||||
|
||||
|
|
@ -196,7 +199,7 @@ But using the Euclidian rhythm notation, we only need to express "3 beats over 8
|
|||
|
||||
This makes it easy to write patterns with interesting rhythmic structures and variations that still sound familiar:
|
||||
|
||||
<MiniRepl client:idle tune={`note("e5(2,8) b4(3,8) d5(2,8) c5(3,8)").slow(4)`} punchcard canvasHeight={50} />
|
||||
<MiniRepl client:idle tune={`note("e5(2,8) b4(3,8) d5(2,8) c5(3,8)").slow(2)`} punchcard canvasHeight={50} />
|
||||
|
||||
Note that since the example above does not use the third `offset` parameter, it can be written simply as `"(3,8)"`.
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ Strudel allows loading samples in the form of audio files of various formats (wa
|
|||
|
||||
By default, strudel comes with a built-in "sample map", providing a solid base to play with.
|
||||
|
||||
<MiniRepl client:idle tune={`s("bd sd,hh*8, misc/2")`} />
|
||||
<MiniRepl client:idle tune={`s("bd sd [~ bd] sd,hh*16, misc")`} />
|
||||
|
||||
Here, we are using the `s` function to play back different default samples (`bd`, `sd`, `hh` and `misc`) to get a drum beat.
|
||||
|
||||
|
|
@ -59,15 +59,15 @@ If we open the `sounds` tab and then `drum machines`, we can see that the drum s
|
|||
|
||||
We _could_ use them like this:
|
||||
|
||||
<MiniRepl client:idle tune={`s("RolandTR808_bd RolandTR808_sd,RolandTR808_hh*8")`} />
|
||||
<MiniRepl client:idle tune={`s("RolandTR808_bd RolandTR808_sd,RolandTR808_hh*16")`} />
|
||||
|
||||
... but thats obviously a bit much to write. Using the `bank` function, we can shorten this to:
|
||||
|
||||
<MiniRepl client:idle tune={`s("bd sd,hh*8").bank("RolandTR808")`} />
|
||||
<MiniRepl client:idle tune={`s("bd sd bd sd,hh*16").bank("RolandTR808")`} />
|
||||
|
||||
You could even pattern the bank to switch between different drum machines:
|
||||
|
||||
<MiniRepl client:idle tune={`s("bd sd,hh*8").bank("<RolandTR808 RolandTR909>")`} />
|
||||
<MiniRepl client:idle tune={`s("bd sd bd sd,hh*16").bank("RolandTR808 RolandTR909")`} />
|
||||
|
||||
Behind the scenes, `bank` will just prepend the drum machine name to the sample name with `_` to get the full name.
|
||||
This of course only works because the name after `_` (`bd`, `sd` etc..) is standardized.
|
||||
|
|
@ -79,17 +79,21 @@ If we open the `sounds` tab again, followed by tab `drum machines`, there is als
|
|||
For example `RolandTR909_hh(4)` means there are 4 samples of a TR909 hihat available.
|
||||
By default, `s` will play the first sample, but we can select the other ones using `n`, starting from 0:
|
||||
|
||||
<MiniRepl client:idle tune={`s("hh*4").bank("RolandTR909").n("<0 1 2 3>")`} />
|
||||
<MiniRepl client:idle tune={`s("hh*8").bank("RolandTR909").n("0 1 2 3")`} />
|
||||
|
||||
Numbers that are too high will just wrap around to the beginning
|
||||
|
||||
<MiniRepl client:idle tune={`s("hh*4").bank("RolandTR909").n("<0 1 2 3 4 5 6 7>")`} />
|
||||
<MiniRepl client:idle tune={`s("hh*8").bank("RolandTR909").n("0 1 2 3 4 5 6 7")`} />
|
||||
|
||||
Here, 0-3 will play the same sounds as 4-7, because `RolandTR909_hh` only has 4 sounds.
|
||||
|
||||
Selecting sounds also works inside the mini notation, using "`:`" like this:
|
||||
|
||||
<MiniRepl client:idle tune={`s("bd:1 bd:2,hh:0 hh:1 hh:2 hh:3").bank("RolandTR909")`} />
|
||||
<MiniRepl
|
||||
client:idle
|
||||
tune={`s("bd*4,hh:0 hh:1 hh:2 hh:3 hh:4 hh:5 hh:6 hh:7")
|
||||
.bank("RolandTR909")`}
|
||||
/>
|
||||
|
||||
# Loading Custom Samples
|
||||
|
||||
|
|
@ -103,7 +107,7 @@ In this example we create a map using sounds from the default sample map:
|
|||
sd: 'sd/rytm-01-classic.wav',
|
||||
hh: 'hh27/000_hh27closedhh.wav',
|
||||
}, 'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/');
|
||||
s("bd sd,hh*8")`}
|
||||
s("bd sd bd sd,hh*16")`}
|
||||
/>
|
||||
|
||||
When you load your own samples, you can choose the names that you will then refer to in your pattern string inside the `s` function.
|
||||
|
|
@ -116,7 +120,7 @@ Compare with this example which uses the same samples, but with different names.
|
|||
snaredrum: 'sd/rytm-01-classic.wav',
|
||||
hihat: 'hh27/000_hh27closedhh.wav',
|
||||
}, 'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/');
|
||||
s("bassdrum snaredrum, hihat*8")`}
|
||||
s("bassdrum snaredrum bassdrum snaredrum, hihat*16")`}
|
||||
/>
|
||||
|
||||
Here we have changed the "map" to include longer sample names.
|
||||
|
|
@ -140,7 +144,7 @@ Because GitHub is a popular place for uploading open source samples, it has its
|
|||
sd: 'sd/rytm-01-classic.wav',
|
||||
hh: 'hh27/000_hh27closedhh.wav',
|
||||
}, 'github:tidalcycles/Dirt-Samples/master/');
|
||||
s("bd sd,hh*8")`}
|
||||
s("bd sd bd sd,hh*16")`}
|
||||
/>
|
||||
|
||||
The format is `github:user/repo/branch/`.
|
||||
|
|
@ -157,7 +161,7 @@ We can see there are some guitar samples inside the `/samples` folder, so let's
|
|||
g3: 'samples/guitar/guitar_3.wav',
|
||||
g4: 'samples/guitar/guitar_4.wav'
|
||||
}, 'github:jarmitage/jarmitage.github.io/master/');
|
||||
s("[g0 g1 g2 g3 g4]/5")`}
|
||||
s("<g0 g1 g2 g3 g4>/2")`}
|
||||
/>
|
||||
|
||||
## Multiple Samples per Sound
|
||||
|
|
@ -171,7 +175,7 @@ It is also possible, to declare multiple files for one sound, using the array no
|
|||
sd: ['sd/rytm-01-classic.wav','sd/rytm-00-hard.wav'],
|
||||
hh: ['hh27/000_hh27closedhh.wav','hh/000_hh3closedhh.wav'],
|
||||
}, 'github:tidalcycles/Dirt-Samples/master/');
|
||||
s("<bd:0 bd:1>,~ <sd:0 sd:1>,[hh:0 hh:1]*2")`}
|
||||
s("bd:0 bd:1,~ <sd:0 sd:1> ~ sd:0,[hh:0 hh:1]*4")`}
|
||||
/>
|
||||
|
||||
The `:0` `:1` etc. are the indices of the array.
|
||||
|
|
@ -184,7 +188,7 @@ The sample number can also be set using `n`:
|
|||
sd: ['sd/rytm-01-classic.wav','sd/rytm-00-hard.wav'],
|
||||
hh: ['hh27/000_hh27closedhh.wav','hh/000_hh3closedhh.wav'],
|
||||
}, 'github:tidalcycles/Dirt-Samples/master/');
|
||||
s("bd,~ sd,hh*4").n("<0 1>")`}
|
||||
s("bd bd,~ sd ~ sd,hh*8").n("<0 1>")`}
|
||||
/>
|
||||
|
||||
In that case, we might load our guitar sample map a different way:
|
||||
|
|
@ -200,7 +204,7 @@ In that case, we might load our guitar sample map a different way:
|
|||
'samples/guitar/guitar_4.wav'
|
||||
]
|
||||
}, 'github:jarmitage/jarmitage.github.io/master/');
|
||||
s("[guitar:0 guitar:1 guitar:2 guitar:3 guitar:4]/5")`}
|
||||
s("<guitar:0 guitar:1 guitar:2 guitar:3 guitar:4>*2")`}
|
||||
/>
|
||||
|
||||
And as above, we can choose the sample number using `n` for even more flexibility:
|
||||
|
|
@ -216,7 +220,7 @@ And as above, we can choose the sample number using `n` for even more flexibilit
|
|||
'samples/guitar/guitar_4.wav'
|
||||
]
|
||||
}, 'github:jarmitage/jarmitage.github.io/master/');
|
||||
n("<0 1 2 3 4>").s("guitar")`}
|
||||
n("<0 1 2 3 4>*2").s("guitar")`}
|
||||
/>
|
||||
|
||||
## Pitched Sounds
|
||||
|
|
@ -271,7 +275,7 @@ We can also declare different samples for different regions of the keyboard:
|
|||
}}, 'github:tidalcycles/Dirt-Samples/master/');
|
||||
note("g2!2 <bb2 c3>!2, <c4@3 [<eb4 bb3> g4 f4]>")
|
||||
.s('moog').clip(1)
|
||||
.gain(.5)`}
|
||||
.gain(.5).cpm(60)`}
|
||||
/>
|
||||
|
||||
The sampler will always pick the closest matching sample for the current note!
|
||||
|
|
@ -285,9 +289,9 @@ With it, you can enter any sample name(s) to query from [freesound.org](https://
|
|||
client:idle
|
||||
tune={`await samples('shabda:bass:4,hihat:4,rimshot:2')
|
||||
stack(
|
||||
n("0 1 2 3").s('bass').slow(2),
|
||||
n("0 1 2 3 0 1 2 3").s('bass'),
|
||||
n("0 1*2 2 3*2").s('hihat'),
|
||||
n("~ 0 ~ 1").s('rimshot')
|
||||
n("~ 0 ~ 1 ~ 0 0 1").s('rimshot')
|
||||
).clip(1)`}
|
||||
/>
|
||||
|
||||
|
|
@ -299,8 +303,8 @@ Note that the language code and the gender parameters are optional and default t
|
|||
tune={`await samples('shabda/speech:the_drum,forever')
|
||||
await samples('shabda/speech/fr-FR/m:magnifique')
|
||||
stack(
|
||||
s("the_drum").chop(16).speed(rand.range(0.85,1.1)),
|
||||
s("forever magnifique").slow(8).late(0.25)
|
||||
s("the_drum*2").chop(16).speed(rand.range(0.85,1.1)),
|
||||
s("forever magnifique").slow(4).late(0.125)
|
||||
)`}
|
||||
/>
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ The basic waveforms are `sine`, `sawtooth`, `square` and `triangle`, which can b
|
|||
|
||||
<MiniRepl
|
||||
client:idle
|
||||
tune={`note("c2 <eb2 <g2 g1>>")
|
||||
tune={`note("c2 <eb2 <g2 g1>>".fast(2))
|
||||
.sound("<sawtooth square triangle sine>")
|
||||
.scope()`}
|
||||
/>
|
||||
|
|
@ -28,7 +28,7 @@ If you don't set a `sound` but a `note` the default value for `sound` is `triang
|
|||
You can also use noise as a source by setting the waveform to: `white`, `pink` or `brown`. These are different
|
||||
flavours of noise, here written from hard to soft.
|
||||
|
||||
<MiniRepl client:idle tune={`sound("<white pink brown>/2").scope()`} />
|
||||
<MiniRepl client:idle tune={`sound("<white pink brown>").scope()`} />
|
||||
|
||||
Here's a more musical example of how to use noise for hihats:
|
||||
|
||||
|
|
@ -44,7 +44,7 @@ Some amount of pink noise can also be added to any oscillator by using the `nois
|
|||
|
||||
You can also use the `crackle` type to play some subtle noise crackles. You can control noise amount by using the `density` parameter:
|
||||
|
||||
<MiniRepl client:idle tune={`s("crackle*4").density("<0.01 0.04 0.2 0.5>".slow(4)).scope()`} />
|
||||
<MiniRepl client:idle tune={`s("crackle*4").density("<0.01 0.04 0.2 0.5>".slow(2)).scope()`} />
|
||||
|
||||
### Additive Synthesis
|
||||
|
||||
|
|
@ -52,7 +52,7 @@ To tame the harsh sound of the basic waveforms, we can set the `n` control to li
|
|||
|
||||
<MiniRepl
|
||||
client:idle
|
||||
tune={`note("c2 <eb2 <g2 g1>>")
|
||||
tune={`note("c2 <eb2 <g2 g1>>".fast(2))
|
||||
.sound("sawtooth")
|
||||
.n("<32 16 8 4>")
|
||||
.scope()`}
|
||||
|
|
@ -63,7 +63,7 @@ You can also set `n` directly in mini notation with `sound`:
|
|||
|
||||
<MiniRepl
|
||||
client:idle
|
||||
tune={`note("c2 <eb2 <g2 g1>>")
|
||||
tune={`note("c2 <eb2 <g2 g1>>".fast(2))
|
||||
.sound("sawtooth:<32 16 8 4>")
|
||||
.scope()`}
|
||||
/>
|
||||
|
|
@ -125,7 +125,7 @@ note("<[g3,b3,e4]!2 [a3,c3,e4] [b3,d3,f#4]>")
|
|||
.n("<1 2 3 4 5 6 7 8 9 10>/2").room(0.5).size(0.9)
|
||||
.s('wt_flute').velocity(0.25).often(n => n.ply(2))
|
||||
.release(0.125).decay("<0.1 0.25 0.3 0.4>").sustain(0)
|
||||
.cutoff(2000).scope({}).cutoff("<1000 2000 4000>").fast(2)`}
|
||||
.cutoff(2000).scope({}).cutoff("<1000 2000 4000>").fast(4)`}
|
||||
/>
|
||||
|
||||
## ZZFX
|
||||
|
|
@ -137,8 +137,8 @@ It has 20 parameters in total, here is a snippet that uses all:
|
|||
|
||||
<MiniRepl
|
||||
client:idle
|
||||
tune={`note("<c2 eb2 f2 g2>") // also supports freq
|
||||
.s("<z_sawtooth z_tan z_noise z_sine z_square>")
|
||||
tune={`note("c2 eb2 f2 g2") // also supports freq
|
||||
.s("{z_sawtooth z_tan z_noise z_sine z_square}%4")
|
||||
.zrand(0) // randomization
|
||||
// zzfx envelope
|
||||
.attack(0.001)
|
||||
|
|
|
|||
|
|
@ -14,6 +14,19 @@ These functions use [tonaljs](https://github.com/tonaljs/tonal) to provide helpe
|
|||
|
||||
<JsDoc client:idle name="voicing" h={0} />
|
||||
|
||||
Here's an example of how you can play chords and a bassline:
|
||||
|
||||
<MiniRepl
|
||||
client:idle
|
||||
tune={`chord("<C^7 A7b13 Dm7 G7>*2")
|
||||
.dict('ireal').layer(
|
||||
x=>x.struct("[~ x]*2").voicing()
|
||||
,
|
||||
x=>n("0*4").set(x).mode("root:g2").voicing()
|
||||
.s('sawtooth').cutoff("800:4:2")
|
||||
)`}
|
||||
/>
|
||||
|
||||
### scale(name)
|
||||
|
||||
<JsDoc client:idle name="scale" h={0} />
|
||||
|
|
@ -22,13 +35,13 @@ These functions use [tonaljs](https://github.com/tonaljs/tonal) to provide helpe
|
|||
|
||||
Transposes all notes to the given number of semitones:
|
||||
|
||||
<MiniRepl client:only="react" tune={`"c2 c3".fast(2).transpose("<0 -2 5 3>".slow(2)).note()`} />
|
||||
<MiniRepl client:only="react" tune={`"[c2 c3]*4".transpose("<0 -2 5 3>").note()`} />
|
||||
|
||||
This method gets really exciting when we use it with a pattern as above.
|
||||
|
||||
Instead of numbers, scientific interval notation can be used as well:
|
||||
|
||||
<MiniRepl client:only="react" tune={`"c2 c3".fast(2).transpose("<1P -2M 4P 3m>".slow(2)).note()`} />
|
||||
<MiniRepl client:only="react" tune={`"[c2 c3]*4".transpose("<1P -2M 4P 3m>").note()`} />
|
||||
|
||||
### scaleTranspose(steps)
|
||||
|
||||
|
|
@ -36,9 +49,9 @@ Transposes notes inside the scale by the number of steps:
|
|||
|
||||
<MiniRepl
|
||||
client:idle
|
||||
tune={`"-8 [2,4,6]"
|
||||
tune={`"[-8 [2,4,6]]*2"
|
||||
.scale('C4 bebop major')
|
||||
.scaleTranspose("<0 -1 -2 -3 -4 -5 -6 -4>")
|
||||
.scaleTranspose("<0 -1 -2 -3 -4 -5 -6 -4>*2")
|
||||
.note()`}
|
||||
/>
|
||||
|
||||
|
|
@ -46,22 +59,28 @@ Transposes notes inside the scale by the number of steps:
|
|||
|
||||
Turns chord symbols into voicings, using the smoothest voice leading possible:
|
||||
|
||||
<MiniRepl client:only="react" tune={`stack("<C^7 A7 Dm7 G7>".voicings('lefthand'), "<C3 A2 D3 G2>").note()`} />
|
||||
<MiniRepl
|
||||
client:only="react"
|
||||
tune={`stack(
|
||||
"<C^7 A7 Dm7 G7>".voicings('lefthand'),
|
||||
"<C3 A2 D3 G2>"
|
||||
).note()`}
|
||||
/>
|
||||
|
||||
Note: This function might be removed, as `voicing` (without s) is a newer implementation.
|
||||
|
||||
### rootNotes(octave = 2)
|
||||
|
||||
Turns chord symbols into root notes of chords in given octave.
|
||||
|
||||
<MiniRepl client:only="react" tune={`"<C^7 A7b13 Dm7 G7>".rootNotes(3).note()`} />
|
||||
<MiniRepl client:only="react" tune={`"<C^7 A7b13 Dm7 G7>*2".rootNotes(3).note()`} />
|
||||
|
||||
Together with layer, struct and voicings, this can be used to create a basic backing track:
|
||||
|
||||
<MiniRepl
|
||||
client:idle
|
||||
tune={`"<C^7 A7b13 Dm7 G7>".layer(
|
||||
x => x.voicings('lefthand').struct("~ x").note(),
|
||||
tune={`"<C^7 A7b13 Dm7 G7>*2".layer(
|
||||
x => x.voicings('lefthand').struct("[~ x]*2").note(),
|
||||
x => x.rootNotes(2).note().s('sawtooth').cutoff(800)
|
||||
)`}
|
||||
/>
|
||||
|
||||
So far, we've stayed within the browser. [MIDI and OSC](/learn/input-output/) are ways to break out of it.
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ 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)`}
|
||||
s("amen/4").fit().chop(32)`}
|
||||
punchcard
|
||||
/>
|
||||
|
||||
|
|
@ -72,9 +72,9 @@ 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)))`}
|
||||
s("amen/4").fit().chop(16).cut(1)
|
||||
.sometimesBy(.5, ply("2"))
|
||||
.sometimesBy(.25, mul(speed("-1")))`}
|
||||
punchcard
|
||||
/>
|
||||
|
||||
|
|
@ -83,9 +83,9 @@ 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))`}
|
||||
s("amen/4").fit()
|
||||
.slice(8, "<0 1 2 3 4*2 5 6 [6 7]>*2")
|
||||
.cut(1).rarely(ply("2"))`}
|
||||
punchcard
|
||||
/>
|
||||
|
||||
|
|
@ -95,8 +95,8 @@ If we use `splice` instead of `slice`, the speed adjusts to the duration of the
|
|||
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))`}
|
||||
.splice(8, "<0 1 2 3 4*2 5 6 [6 7]>*2")
|
||||
.cut(1).rarely(ply("2"))`}
|
||||
punchcard
|
||||
/>
|
||||
|
||||
|
|
@ -104,26 +104,38 @@ Note that we don't need `fit`, because `splice` will do that by itself.
|
|||
|
||||
## Filter Envelopes
|
||||
|
||||
A minimal filter envelope looks like this:
|
||||
Using `lpenv`, we can make the filter move:
|
||||
|
||||
<MiniRepl
|
||||
client:visible
|
||||
tune={`note("g1 bb1 <c2 eb2> d2")
|
||||
.s("sawtooth")
|
||||
.lpf(400).lpa(.2).lpenv(4)
|
||||
.lpf(400).lpenv(4)
|
||||
.scope()`}
|
||||
/>
|
||||
|
||||
We can flip the envelope by setting `lpenv` negative + add some resonance `lpq`:
|
||||
The type of envelope depends on the methods you're setting. Let's set `lpa`:
|
||||
|
||||
<MiniRepl
|
||||
client:visible
|
||||
tune={`note("g1 bb1 <c2 eb2> d2")
|
||||
.s("sawtooth").lpq(8)
|
||||
.lpf(400).lpa(.2).lpenv(-4)
|
||||
.lpf(400).lpa(.2).lpenv(4)
|
||||
.scope()`}
|
||||
/>
|
||||
|
||||
Now the filter is attacking, rather than decaying as before (decay is the default). We can also do both
|
||||
|
||||
<MiniRepl
|
||||
client:visible
|
||||
tune={`note("g1 bb1 <c2 eb2> d2")
|
||||
.s("sawtooth").lpq(8)
|
||||
.lpf(400).lpa(.1).lpd(.1).lpenv(4)
|
||||
.scope()`}
|
||||
/>
|
||||
|
||||
You can play around with `lpa` | `lpd` | `lps` | `lpd` to see what the filter envelope will do.
|
||||
|
||||
## Layering Sounds
|
||||
|
||||
We can layer sounds by separating them with ",":
|
||||
|
|
@ -183,7 +195,7 @@ A polyrhythm is when 2 different tempos happen at the same time.
|
|||
|
||||
This is a polymeter:
|
||||
|
||||
<MiniRepl client:visible tune={`s("<bd rim>,<hh hh oh>").fast(2)`} punchcard />
|
||||
<MiniRepl client:visible tune={`s("<bd rim, hh hh oh>*4")`} punchcard />
|
||||
|
||||
A polymeter is when 2 different bar lengths play at the same tempo.
|
||||
|
||||
|
|
@ -201,8 +213,8 @@ 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")`}
|
||||
tune={`await samples('bubo:fox')
|
||||
n(run(8)).s("ftabla")`}
|
||||
punchcard
|
||||
/>
|
||||
|
||||
|
|
@ -212,17 +224,17 @@ In this case, I hear the beginning at the third sample, which can be accounted f
|
|||
|
||||
<MiniRepl
|
||||
client:visible
|
||||
tune={`await samples('github:Bubobubobubobubo/Dough-Fox/main')
|
||||
n(run(8)).s("ftabla").early(2/8)`}
|
||||
tune={`await samples('bubo:fox')
|
||||
n(run(8)).s("ftabla").early(2/8)`}
|
||||
/>
|
||||
|
||||
Let's add some randomness:
|
||||
|
||||
<MiniRepl
|
||||
client:visible
|
||||
tune={`await samples('github:Bubobubobubobubo/Dough-Fox/main')
|
||||
tune={`await samples('bubo:fox')
|
||||
n(run(8)).s("ftabla").early(2/8)
|
||||
.sometimes(mul(speed(1.5)))`}
|
||||
.sometimes(mul(speed("1.5")))`}
|
||||
/>
|
||||
|
||||
## Tape Warble
|
||||
|
|
@ -231,7 +243,7 @@ We can emulate a pitch warbling effect like this:
|
|||
|
||||
<MiniRepl
|
||||
client:visible
|
||||
tune={`note("c4 bb f eb")
|
||||
tune={`note("<c4 bb f eb>*8")
|
||||
.add(note(perlin.range(0,.5))) // <------ warble
|
||||
.clip(2).s("gm_electric_guitar_clean")`}
|
||||
/>
|
||||
|
|
@ -243,7 +255,7 @@ 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")`}
|
||||
.clip("<2 1 .5 .25>")`}
|
||||
/>
|
||||
|
||||
The value of clip is relative to the duration of each event.
|
||||
|
|
@ -252,20 +264,18 @@ We can also create overlaps using release:
|
|||
<MiniRepl
|
||||
client:visible
|
||||
tune={`note("f ab bb c")
|
||||
.release("<2 1 .5 .002>/2")`}
|
||||
.release("<2 1 .5 .25>")`}
|
||||
/>
|
||||
|
||||
This will smoothly fade out each sound for the given number of seconds.
|
||||
We could also make the notes shorter with decay / sustain:
|
||||
We could also make the notes shorter by using a decay envelope:
|
||||
|
||||
<MiniRepl
|
||||
client:visible
|
||||
tune={`note("f ab bb c")
|
||||
.decay("<.2 .1 .02>/2").sustain(0)`}
|
||||
.decay("<2 1 .5 .25>")`}
|
||||
/>
|
||||
|
||||
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>")`} />
|
||||
|
|
@ -274,9 +284,9 @@ Compare that to clip:
|
|||
|
||||
<MiniRepl client:visible tune={`s("oh*4").clip("<1 .5 .25 .1>")`} />
|
||||
|
||||
or decay / sustain
|
||||
or decay:
|
||||
|
||||
<MiniRepl client:visible tune={`s("oh*4").decay("<.2 .12 .06 .01>").sustain(0)`} />
|
||||
<MiniRepl client:visible tune={`s("oh*4").decay("<1 .5 .25 .1>")`} />
|
||||
|
||||
## Wavetable Synthesis
|
||||
|
||||
|
|
|
|||
|
|
@ -15,20 +15,20 @@ Strudel's mother language, TidalCycles, even has it in its name.
|
|||
## Cycles and BPM
|
||||
|
||||
In most music software, the unit BPM (beats per minute) is used to set the tempo.
|
||||
Strudel expresses tempo as CPS (cycles per second), with a default of 1CPS:
|
||||
Strudel expresses tempo as CPS (cycles per second), with a default of 0.5 CPS:
|
||||
|
||||
<MiniRepl client:visible tune={`s("bd")`} />
|
||||
|
||||
Here we can hear the 1CPS in action: The kick repeats once per second like a clock.
|
||||
We could say 1CPS = 1BPS (beats per second) = 60BPM. Let's add another kick:
|
||||
Here we can hear the 0.5CPS in action: The kick repeats once every two seconds.
|
||||
Let's make it 4 kicks:
|
||||
|
||||
<MiniRepl client:visible tune={`s("bd bd")`} />
|
||||
<MiniRepl client:visible tune={`s("bd bd bd bd")`} />
|
||||
|
||||
Now we have 2 kicks per second, but the whole pattern still plays at 1CPS.
|
||||
Now we have 4 kicks per cycle, but the whole pattern still plays at 0.5CPS.
|
||||
In terms of BPM, most musicians would tell you this is playing at 120bpm.
|
||||
What about this one:
|
||||
|
||||
<MiniRepl client:visible tune={`s("bd hh")`} />
|
||||
<MiniRepl client:visible tune={`s("bd hh bd hh")`} />
|
||||
|
||||
Because the second sound is now a hihat, the tempo feels slower again.
|
||||
This brings us to an important realization:
|
||||
|
|
@ -103,7 +103,7 @@ To get a time signature, just change the number of elements per bar. Here is a r
|
|||
|
||||
or with 5:
|
||||
|
||||
<MiniRepl client:visible tune={`s("<bd hh hh bd hh hh bd rim bd hh>*5")`} />
|
||||
<MiniRepl client:visible tune={`s("bd hh hh bd hh hh bd rim bd hh")`} />
|
||||
|
||||
We could also write multiple bars with different time signatures:
|
||||
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ The upper limit decreases with age. What's your upper limit?
|
|||
|
||||
In Strudel, we can play frequencies directly with the `freq` control:
|
||||
|
||||
<MiniRepl client:visible tune={`freq("200 [300,500] 400 [500,<600 670 712 670>]")`} />
|
||||
<MiniRepl client:visible tune={`freq("<200 [300,500] 400 [500,<600 670 712 670>]>*8")`} />
|
||||
|
||||
## Frequency vs Pitch Perception
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ We have sounds, we have notes, now let's look at effects!
|
|||
|
||||
<MiniRepl
|
||||
client:visible
|
||||
tune={`note("<[c2 c3]*4 [bb1 bb2]*4 [f2 f3]*4 [eb2 eb3]*4>/2")
|
||||
tune={`note("<[c2 c3]*4 [bb1 bb2]*4 [f2 f3]*4 [eb2 eb3]*4>")
|
||||
.sound("sawtooth").lpf(800)`}
|
||||
/>
|
||||
|
||||
|
|
@ -35,8 +35,8 @@ lpf = **l**ow **p**ass **f**ilter
|
|||
|
||||
<MiniRepl
|
||||
client:visible
|
||||
tune={`note("<[c2 c3]*4 [bb1 bb2]*4 [f2 f3]*4 [eb2 eb3]*4>/2")
|
||||
.sound("sawtooth").lpf("200 1000")`}
|
||||
tune={`note("<[c2 c3]*4 [bb1 bb2]*4 [f2 f3]*4 [eb2 eb3]*4>")
|
||||
.sound("sawtooth").lpf("200 1000 200 1000")`}
|
||||
/>
|
||||
|
||||
<Box>
|
||||
|
|
@ -52,8 +52,8 @@ We will learn how to automate with waves later...
|
|||
|
||||
<MiniRepl
|
||||
client:visible
|
||||
tune={`note("<[c3,g3,e4] [bb2,f3,d4] [a2,f3,c4] [bb2,g3,eb4]>/2")
|
||||
.sound("sawtooth").vowel("<a e i o>/2")`}
|
||||
tune={`note("<[c3,g3,e4] [bb2,f3,d4] [a2,f3,c4] [bb2,g3,eb4]>")
|
||||
.sound("sawtooth").vowel("<a e i o>")`}
|
||||
/>
|
||||
|
||||
**gain**
|
||||
|
|
@ -61,8 +61,8 @@ We will learn how to automate with waves later...
|
|||
<MiniRepl
|
||||
client:visible
|
||||
tune={`stack(
|
||||
sound("hh*8").gain("[.25 1]*2"),
|
||||
sound("bd*2,~ sd:1")
|
||||
sound("hh*16").gain("[.25 1]*4"),
|
||||
sound("bd*4,[~ sd:1]*2")
|
||||
) `}
|
||||
punchcard
|
||||
/>
|
||||
|
|
@ -84,13 +84,13 @@ Let's combine all of the above into a little tune:
|
|||
client:visible
|
||||
tune={`stack(
|
||||
stack(
|
||||
sound("hh*8").gain("[.25 1]*2"),
|
||||
sound("bd*2,~ sd:1")
|
||||
sound("hh*8").gain("[.25 1]*4"),
|
||||
sound("bd*4,[~ sd:1]*2")
|
||||
),
|
||||
note("<[c2 c3]*4 [bb1 bb2]*4 [f2 f3]*4 [eb2 eb3]*4>/2")
|
||||
.sound("sawtooth").lpf("200 1000"),
|
||||
note("<[c3,g3,e4] [bb2,f3,d4] [a2,f3,c4] [bb2,g3,eb4]>/2")
|
||||
.sound("sawtooth").vowel("<a e i o>/2")
|
||||
note("<[c2 c3]*4 [bb1 bb2]*4 [f2 f3]*4 [eb2 eb3]*4>")
|
||||
.sound("sawtooth").lpf("200 1000 200 1000"),
|
||||
note("<[c3,g3,e4] [bb2,f3,d4] [a2,f3,c4] [bb2,g3,eb4]>")
|
||||
.sound("sawtooth").vowel("<a e i o>")
|
||||
) `}
|
||||
/>
|
||||
|
||||
|
|
@ -105,7 +105,7 @@ The 3 parts (drums, bassline, chords) are exactly as earlier, just stacked toget
|
|||
|
||||
<MiniRepl
|
||||
client:visible
|
||||
tune={`note("<c3 bb2 f3 eb3>")
|
||||
tune={`note("c3 bb2 f3 eb3")
|
||||
.sound("sawtooth").lpf(600)
|
||||
.attack(.1)
|
||||
.decay(.1)
|
||||
|
|
@ -141,7 +141,7 @@ Can you guess what they do?
|
|||
|
||||
<MiniRepl
|
||||
client:visible
|
||||
tune={`note("<c3 bb2 f3 eb3>")
|
||||
tune={`note("c3 bb2 f3 eb3")
|
||||
.sound("sawtooth").lpf(600)
|
||||
.adsr(".1:.1:.5:.2")
|
||||
`}
|
||||
|
|
@ -152,7 +152,7 @@ Can you guess what they do?
|
|||
<MiniRepl
|
||||
client:visible
|
||||
tune={`stack(
|
||||
note("~ [<[d3,a3,f4]!2 [d3,bb3,g4]!2> ~]")
|
||||
note("[~ [<[d3,a3,f4]!2 [d3,bb3,g4]!2> ~]]*2")
|
||||
.sound("gm_electric_guitar_muted"),
|
||||
sound("<bd rim>").bank("RolandTR707")
|
||||
).delay(".5")`}
|
||||
|
|
@ -182,7 +182,7 @@ What happens if you use `.delay(".8:.06:.8")` ? Can you guess what the third num
|
|||
|
||||
<MiniRepl
|
||||
client:visible
|
||||
tune={`n("<4 [3@3 4] [<2 0> ~@16] ~>/2")
|
||||
tune={`n("<4 [3@3 4] [<2 0> ~@16] ~>")
|
||||
.scale("D4:minor").sound("gm_accordion:2")
|
||||
.room(2)`}
|
||||
/>
|
||||
|
|
@ -200,10 +200,10 @@ Add a delay too!
|
|||
<MiniRepl
|
||||
client:visible
|
||||
tune={`stack(
|
||||
note("~ [<[d3,a3,f4]!2 [d3,bb3,g4]!2> ~]")
|
||||
note("[~ [<[d3,a3,f4]!2 [d3,bb3,g4]!2> ~]]*2")
|
||||
.sound("gm_electric_guitar_muted").delay(.5),
|
||||
sound("<bd rim>").bank("RolandTR707").delay(.5),
|
||||
n("<4 [3@3 4] [<2 0> ~@16] ~>/2")
|
||||
n("<4 [3@3 4] [<2 0> ~@16] ~>")
|
||||
.scale("D4:minor").sound("gm_accordion:2")
|
||||
.room(2).gain(.5)
|
||||
)`}
|
||||
|
|
@ -214,13 +214,13 @@ Let's add a bass to make this complete:
|
|||
<MiniRepl
|
||||
client:visible
|
||||
tune={`stack(
|
||||
note("~ [<[d3,a3,f4]!2 [d3,bb3,g4]!2> ~]")
|
||||
note("[~ [<[d3,a3,f4]!2 [d3,bb3,g4]!2> ~]]*2")
|
||||
.sound("gm_electric_guitar_muted").delay(.5),
|
||||
sound("<bd rim>").bank("RolandTR707").delay(.5),
|
||||
n("<4 [3@3 4] [<2 0> ~@16] ~>/2")
|
||||
n("<4 [3@3 4] [<2 0> ~@16] ~>")
|
||||
.scale("D4:minor").sound("gm_accordion:2")
|
||||
.room(2).gain(.4),
|
||||
n("<0 [~ 0] 4 [3 2] [0 ~] [0 ~] <0 2> ~>*2")
|
||||
n("[0 [~ 0] 4 [3 2] [0 ~] [0 ~] <0 2> ~]/2")
|
||||
.scale("D2:minor")
|
||||
.sound("sawtooth,triangle").lpf(800)
|
||||
)`}
|
||||
|
|
@ -237,19 +237,18 @@ Try adding `.hush()` at the end of one of the patterns in the stack...
|
|||
<MiniRepl
|
||||
client:visible
|
||||
tune={`sound("numbers:1 numbers:2 numbers:3 numbers:4")
|
||||
.pan("0 0.3 .6 1")
|
||||
.slow(2)`}
|
||||
.pan("0 0.3 .6 1")`}
|
||||
/>
|
||||
|
||||
**speed**
|
||||
|
||||
<MiniRepl client:visible tune={`sound("bd rim").speed("<1 2 -1 -2>").room(.2)`} />
|
||||
<MiniRepl client:visible tune={`sound("bd rim [~ bd] rim").speed("<1 2 -1 -2>").room(.2)`} />
|
||||
|
||||
**fast and slow**
|
||||
|
||||
We can use `fast` and `slow` to change the tempo of a pattern outside of Mini-Notation:
|
||||
|
||||
<MiniRepl client:visible tune={`sound("bd*2,~ rim").slow(2)`} />
|
||||
<MiniRepl client:visible tune={`sound("bd*4,~ rim ~ cp").slow(2)`} />
|
||||
|
||||
<Box>
|
||||
|
||||
|
|
@ -261,13 +260,13 @@ What happens if you use a pattern like `.fast("<1 [2 4]>")`?
|
|||
|
||||
By the way, inside Mini-Notation, `fast` is `*` and `slow` is `/`.
|
||||
|
||||
<MiniRepl client:visible tune={`sound("[bd*2,~ rim]*<1 [2 4]>")`} />
|
||||
<MiniRepl client:visible tune={`sound("[bd*4,~ rim ~ cp]*<1 [2 4]>")`} />
|
||||
|
||||
## automation with signals
|
||||
|
||||
Instead of changing values stepwise, we can also control them with signals:
|
||||
|
||||
<MiniRepl client:visible tune={`sound("hh*16").gain(sine)`} punchcard punchcardLabels={false} />
|
||||
<MiniRepl client:visible tune={`sound("hh*32").gain(sine)`} punchcard punchcardLabels={false} />
|
||||
|
||||
<Box>
|
||||
|
||||
|
|
@ -283,7 +282,7 @@ The gain is visualized as transparency in the pianoroll.
|
|||
|
||||
By default, waves oscillate between 0 to 1. We can change that with `range`:
|
||||
|
||||
<MiniRepl client:visible tune={`sound("hh*8").lpf(saw.range(500, 2000))`} />
|
||||
<MiniRepl client:visible tune={`sound("hh*16").lpf(saw.range(500, 2000))`} />
|
||||
|
||||
<Box>
|
||||
|
||||
|
|
@ -295,9 +294,9 @@ We can change the automation speed with slow / fast:
|
|||
|
||||
<MiniRepl
|
||||
client:visible
|
||||
tune={`note("<[c2 c3]*4 [bb1 bb2]*4 [f2 f3]*4 [eb2 eb3]*4>/2")
|
||||
tune={`note("<[c2 c3]*4 [bb1 bb2]*4 [f2 f3]*4 [eb2 eb3]*4>")
|
||||
.sound("sawtooth")
|
||||
.lpf(sine.range(100, 2000).slow(8))`}
|
||||
.lpf(sine.range(100, 2000).slow(4))`}
|
||||
/>
|
||||
|
||||
<Box>
|
||||
|
|
@ -308,15 +307,15 @@ The whole automation will now take 8 cycles to repeat.
|
|||
|
||||
## Recap
|
||||
|
||||
| name | example |
|
||||
| ----- | --------------------------------------------------------------------------------------- |
|
||||
| lpf | <MiniRepl client:visible tune={`note("c2 c3").s("sawtooth").lpf("<400 2000>")`} /> |
|
||||
| vowel | <MiniRepl client:visible tune={`note("c3 eb3 g3").s("sawtooth").vowel("<a e i o>")`} /> |
|
||||
| gain | <MiniRepl client:visible tune={`s("hh*8").gain("[.25 1]*2")`} /> |
|
||||
| delay | <MiniRepl client:visible tune={`s("bd rim").delay(.5)`} /> |
|
||||
| room | <MiniRepl client:visible tune={`s("bd rim").room(.5)`} /> |
|
||||
| pan | <MiniRepl client:visible tune={`s("bd rim").pan("0 1")`} /> |
|
||||
| speed | <MiniRepl client:visible tune={`s("bd rim").speed("<1 2 -1 -2>")`} /> |
|
||||
| range | <MiniRepl client:visible tune={`s("hh*16").lpf(saw.range(200,4000))`} /> |
|
||||
| name | example |
|
||||
| ----- | ---------------------------------------------------------------------------------------- |
|
||||
| lpf | <MiniRepl client:visible tune={`note("c2 c3 c2 c3").s("sawtooth").lpf("<400 2000>")`} /> |
|
||||
| vowel | <MiniRepl client:visible tune={`note("c3 eb3 g3").s("sawtooth").vowel("<a e i o>")`} /> |
|
||||
| gain | <MiniRepl client:visible tune={`s("hh*16").gain("[.25 1]*2")`} /> |
|
||||
| delay | <MiniRepl client:visible tune={`s("bd rim bd cp").delay(.5)`} /> |
|
||||
| room | <MiniRepl client:visible tune={`s("bd rim bd cp").room(.5)`} /> |
|
||||
| pan | <MiniRepl client:visible tune={`s("bd rim bd cp").pan("0 1")`} /> |
|
||||
| speed | <MiniRepl client:visible tune={`s("bd rim bd cp").speed("<1 2 -1 -2>")`} /> |
|
||||
| range | <MiniRepl client:visible tune={`s("hh*16").lpf(saw.range(200,4000))`} /> |
|
||||
|
||||
Let us now take a look at some of Tidal's typical [pattern effects](/workshop/pattern-effects).
|
||||
|
|
|
|||
|
|
@ -175,11 +175,11 @@ Try adding more notes inside the brackets and notice how it does **not** get fas
|
|||
|
||||
**Play one sequence per cycle**
|
||||
|
||||
{/* <[c2 c3]*4 [bb1 bb2]*4 [f2 f3]*4 [eb2 eb3]*4>/2 */}
|
||||
{/* <[c2 c3]*4 [bb1 bb2]*4 [f2 f3]*4 [eb2 eb3]*4> */}
|
||||
|
||||
<MiniRepl
|
||||
client:visible
|
||||
tune={`note("<[36 48]*4 [34 46]*4 [41 53]*4 [39 51]*4>/2")
|
||||
tune={`note("<[36 48]*4 [34 46]*4 [41 53]*4 [39 51]*4>")
|
||||
.sound("gm_acoustic_bass")`}
|
||||
punchcard
|
||||
/>
|
||||
|
|
@ -197,7 +197,7 @@ This is also useful for unpitched sounds:
|
|||
|
||||
<MiniRepl
|
||||
client:visible
|
||||
tune={`sound("bd*2, ~ <sd cp>, [~ hh]*2")
|
||||
tune={`sound("bd*4, [~ <sd cp>]*2, [~ hh]*4")
|
||||
.bank("RolandTR909")`}
|
||||
punchcard
|
||||
/>
|
||||
|
|
@ -209,7 +209,7 @@ Finding the right notes can be difficult.. Scales are here to help:
|
|||
<MiniRepl
|
||||
client:visible
|
||||
tune={`n("0 2 4 <[6,8] [7,9]>")
|
||||
.scale("C:minor").sound("piano")`}
|
||||
.scale("C:minor").sound("piano").cpm(60)`}
|
||||
punchcard
|
||||
/>
|
||||
|
||||
|
|
@ -236,7 +236,7 @@ Just like anything, we can automate the scale with a pattern:
|
|||
client:visible
|
||||
tune={`n("<0 -3>, 2 4 <[6,8] [7,9]>")
|
||||
.scale("<C:major D:mixolydian>/4")
|
||||
.sound("piano")`}
|
||||
.sound("piano").cpm(60)`}
|
||||
punchcard
|
||||
/>
|
||||
|
||||
|
|
@ -269,7 +269,7 @@ Try changing that number!
|
|||
client:visible
|
||||
tune={`n("<[4@2 4] [5@2 5] [6@2 6] [5@2 5]>*2")
|
||||
.scale("<C2:mixolydian F2:mixolydian>/4")
|
||||
.sound("gm_acoustic_bass")`}
|
||||
.sound("gm_acoustic_bass").cpm(60)`}
|
||||
punchcard
|
||||
/>
|
||||
|
||||
|
|
@ -283,7 +283,7 @@ This is also sometimes called triplet swing. You'll often find it in blues and j
|
|||
|
||||
**Replicate**
|
||||
|
||||
<MiniRepl client:visible tune={`note("c!2 [eb,<g a bb a>]").sound("piano")`} punchcard />
|
||||
<MiniRepl client:visible tune={`note("c!2 [eb,<g a bb a>]").sound("piano").cpm(60)`} punchcard />
|
||||
|
||||
<Box>
|
||||
|
||||
|
|
@ -300,7 +300,7 @@ Let's recap what we've learned in this chapter:
|
|||
| Concept | Syntax | Example |
|
||||
| --------- | ------ | -------------------------------------------------------- |
|
||||
| Slow down | \/ | <MiniRepl client:visible tune={`note("[c a f e]/2")`} /> |
|
||||
| Alternate | \<\> | <MiniRepl client:visible tune={`note("c <e g>")`} /> |
|
||||
| Alternate | \<\> | <MiniRepl client:visible tune={`note("c a f <e g>")`} /> |
|
||||
| Elongate | @ | <MiniRepl client:visible tune={`note("c@3 e")`} /> |
|
||||
| Replicate | ! | <MiniRepl client:visible tune={`note("c!3 e")`} /> |
|
||||
|
||||
|
|
@ -318,7 +318,7 @@ New functions:
|
|||
|
||||
<MiniRepl
|
||||
client:visible
|
||||
tune={`note("<[c2 c3]*4 [bb1 bb2]*4 [f2 f3]*4 [eb2 eb3]*4>/2")
|
||||
tune={`note("<[c2 c3]*4 [bb1 bb2]*4 [f2 f3]*4 [eb2 eb3]*4>")
|
||||
.sound("gm_synth_bass_1")
|
||||
.lpf(800) // <-- we'll learn about this soon`}
|
||||
/>
|
||||
|
|
@ -332,7 +332,7 @@ New functions:
|
|||
[~ 0] 1 [0 1] [~ 1]
|
||||
[~ 0] 3 [0 3] [~ 3]
|
||||
[~ 0] 2 [0 2] [~ 2]
|
||||
>*2\`).scale("C4:minor")
|
||||
>*4\`).scale("C4:minor")
|
||||
.sound("gm_synth_strings_1")`}
|
||||
/>
|
||||
|
||||
|
|
@ -340,7 +340,7 @@ New functions:
|
|||
|
||||
<MiniRepl
|
||||
client:visible
|
||||
tune={`sound("bd*2, ~ <sd cp>, [~ hh]*2")
|
||||
tune={`sound("bd*4, [~ <sd cp>]*2, [~ hh]*4")
|
||||
.bank("RolandTR909")`}
|
||||
/>
|
||||
|
||||
|
|
@ -355,16 +355,16 @@ It's called `stack` 😙
|
|||
<MiniRepl
|
||||
client:visible
|
||||
tune={`stack(
|
||||
note("<[c2 c3]*4 [bb1 bb2]*4 [f2 f3]*4 [eb2 eb3]*4>/2")
|
||||
note("<[c2 c3]*4 [bb1 bb2]*4 [f2 f3]*4 [eb2 eb3]*4>")
|
||||
.sound("gm_synth_bass_1").lpf(800),
|
||||
n(\`<
|
||||
[~ 0] 2 [0 2] [~ 2]
|
||||
[~ 0] 1 [0 1] [~ 1]
|
||||
[~ 0] 3 [0 3] [~ 3]
|
||||
[~ 0] 2 [0 2] [~ 2]
|
||||
>*2\`).scale("C4:minor")
|
||||
>*4\`).scale("C4:minor")
|
||||
.sound("gm_synth_strings_1"),
|
||||
sound("bd*2, ~ <sd cp>, [~ hh]*2")
|
||||
sound("bd*4, [~ <sd cp>]*2, [~ hh]*4")
|
||||
.bank("RolandTR909")
|
||||
)`}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -147,11 +147,11 @@ We will look at other ways to change the tempo later!
|
|||
|
||||
**Add a rests in a sequence with '~'**
|
||||
|
||||
<MiniRepl client:visible tune={`sound("bd hh ~ rim")`} punchcard />
|
||||
<MiniRepl client:visible tune={`sound("bd hh ~ rim ~ bd hh rim")`} punchcard />
|
||||
|
||||
**Sub-Sequences with [brackets]**
|
||||
|
||||
<MiniRepl client:visible tune={`sound("bd [hh hh] sd [hh bd]")`} punchcard />
|
||||
<MiniRepl client:visible tune={`sound("bd [hh hh] sd [hh bd] bd ~ [hh sd] cp")`} punchcard />
|
||||
|
||||
<Box>
|
||||
|
||||
|
|
@ -163,15 +163,15 @@ Similar to the whole sequence, the content of a sub-sequence will be squished to
|
|||
|
||||
**Multiplication: Speed things up**
|
||||
|
||||
<MiniRepl client:visible tune={`sound("bd hh*2 rim hh*3")`} punchcard />
|
||||
<MiniRepl client:visible tune={`sound("bd hh*2 rim hh*3 bd [~ hh*2] rim hh*2")`} punchcard />
|
||||
|
||||
**Multiplication: Speed up sequences**
|
||||
**Multiplication: Speed up subsequences**
|
||||
|
||||
<MiniRepl client:visible tune={`sound("bd [hh rim]*2")`} punchcard />
|
||||
<MiniRepl client:visible tune={`sound("bd [hh rim]*2 bd [hh rim]*1.5")`} punchcard />
|
||||
|
||||
**Multiplication: Speeeeeeeeed things up**
|
||||
|
||||
<MiniRepl client:visible tune={`sound("bd hh*16 rim hh*8")`} punchcard />
|
||||
<MiniRepl client:visible tune={`sound("bd hh*32 rim hh*16")`} punchcard />
|
||||
|
||||
<Box>
|
||||
|
||||
|
|
@ -181,7 +181,7 @@ Pitch = really fast rhythm
|
|||
|
||||
**Sub-Sub-Sequences with [[brackets]]**
|
||||
|
||||
<MiniRepl client:visible tune={`sound("bd [[rim rim] hh]")`} punchcard />
|
||||
<MiniRepl client:visible tune={`sound("bd [[rim rim] hh] bd cp")`} punchcard />
|
||||
|
||||
<Box>
|
||||
|
||||
|
|
@ -234,34 +234,39 @@ This is shorter and more readable than:
|
|||
Now we've learned the basics of the so called Mini-Notation, the rhythm language of Tidal.
|
||||
This is what we've leared so far:
|
||||
|
||||
| Concept | Syntax | Example |
|
||||
| ----------------- | -------- | --------------------------------------------------------------------- |
|
||||
| Sequence | space | <MiniRepl client:visible tune={`sound("bd bd sd hh")`} /> |
|
||||
| Sample Number | :x | <MiniRepl client:visible tune={`sound("hh:0 hh:1 hh:2 hh:3")`} /> |
|
||||
| Rests | ~ | <MiniRepl client:visible tune={`sound("metal ~ jazz jazz:1")`} /> |
|
||||
| Sub-Sequences | \[\] | <MiniRepl client:visible tune={`sound("bd wind [metal jazz] hh")`} /> |
|
||||
| Sub-Sub-Sequences | \[\[\]\] | <MiniRepl client:visible tune={`sound("bd [metal [jazz sd]]")`} /> |
|
||||
| Speed up | \* | <MiniRepl client:visible tune={`sound("bd sd*2 cp*3")`} /> |
|
||||
| Parallel | , | <MiniRepl client:visible tune={`sound("bd*2, hh*2 [hh oh]")`} /> |
|
||||
| Concept | Syntax | Example |
|
||||
| ----------------- | -------- | ----------------------------------------------------------------------- |
|
||||
| Sequence | space | <MiniRepl client:visible tune={`sound("bd bd sd hh")`} /> |
|
||||
| Sample Number | :x | <MiniRepl client:visible tune={`sound("hh:0 hh:1 hh:2 hh:3")`} /> |
|
||||
| Rests | ~ | <MiniRepl client:visible tune={`sound("metal ~ jazz jazz:1")`} /> |
|
||||
| Sub-Sequences | \[\] | <MiniRepl client:visible tune={`sound("bd wind [metal jazz] hh")`} /> |
|
||||
| Sub-Sub-Sequences | \[\[\]\] | <MiniRepl client:visible tune={`sound("bd [metal [jazz [sd cp]]]")`} /> |
|
||||
| Speed up | \* | <MiniRepl client:visible tune={`sound("bd sd*2 cp*3")`} /> |
|
||||
| Parallel | , | <MiniRepl client:visible tune={`sound("bd*2, hh*2 [hh oh]")`} /> |
|
||||
|
||||
The Mini-Notation is usually used inside some function. These are the functions we've seen so far:
|
||||
|
||||
| Name | Description | Example |
|
||||
| ----- | ----------------------------------- | ----------------------------------------------------------------------- |
|
||||
| sound | plays the sound of the given name | <MiniRepl client:visible tune={`sound("bd sd")`} /> |
|
||||
| bank | selects the sound bank | <MiniRepl client:visible tune={`sound("bd sd").bank("RolandTR909")`} /> |
|
||||
| cpm | sets the tempo in cycles per minute | <MiniRepl client:visible tune={`sound("bd sd").cpm(90)`} /> |
|
||||
| n | select sample number | <MiniRepl client:visible tune={`n("0 1 4 2").sound("jazz")`} /> |
|
||||
| Name | Description | Example |
|
||||
| ----- | ----------------------------------- | --------------------------------------------------------------------------------- |
|
||||
| sound | plays the sound of the given name | <MiniRepl client:visible tune={`sound("bd sd [~ bd] sd")`} /> |
|
||||
| bank | selects the sound bank | <MiniRepl client:visible tune={`sound("bd sd [~ bd] sd").bank("RolandTR909")`} /> |
|
||||
| cpm | sets the tempo in cycles per minute | <MiniRepl client:visible tune={`sound("bd sd [~ bd] sd").cpm(45)`} /> |
|
||||
| n | select sample number | <MiniRepl client:visible tune={`n("0 1 4 2 0 6 3 2").sound("jazz")`} /> |
|
||||
|
||||
## Examples
|
||||
|
||||
**Basic rock beat**
|
||||
|
||||
<MiniRepl client:visible tune={`sound("bd sd, hh*4").bank("RolandTR505").cpm(100/2)`} punchcard />
|
||||
<MiniRepl
|
||||
client:visible
|
||||
tune={`sound("[bd sd]*2, hh*8").bank("RolandTR505")
|
||||
.cpm(100/4)`}
|
||||
punchcard
|
||||
/>
|
||||
|
||||
**Classic house**
|
||||
|
||||
<MiniRepl client:visible tune={`sound("bd*2, ~ cp, [~ hh]*2").bank("RolandTR909")`} punchcard />
|
||||
<MiniRepl client:visible tune={`sound("bd*4, [~ cp]*2, [~ hh]*4").bank("RolandTR909")`} punchcard />
|
||||
|
||||
<Box>
|
||||
|
||||
|
|
@ -279,7 +284,7 @@ We Will Rock you
|
|||
<MiniRepl
|
||||
client:visible
|
||||
tune={`sound("bd sd, ~ ~ ~ hh ~ hh ~ ~, ~ perc ~ perc:1*2")
|
||||
.bank("RolandCompurhythm1000")`}
|
||||
.bank("RolandCompurhythm1000").cpm(120/2)`}
|
||||
punchcard
|
||||
/>
|
||||
|
||||
|
|
|
|||
|
|
@ -15,19 +15,19 @@ In this chapter, we are going to look at functions that are more unique to tidal
|
|||
|
||||
**reverse patterns with rev**
|
||||
|
||||
<MiniRepl client:visible tune={`n("0 1 [4 3] 2").sound("jazz").rev()`} />
|
||||
<MiniRepl client:visible tune={`n("0 1 [4 3] 2 0 2 [~ 3] 4").sound("jazz").rev()`} />
|
||||
|
||||
**play pattern left and modify it right with jux**
|
||||
|
||||
<MiniRepl client:visible tune={`n("0 1 [4 3] 2").sound("jazz").jux(rev)`} />
|
||||
<MiniRepl client:visible tune={`n("0 1 [4 3] 2 0 2 [~ 3] 4").sound("jazz").jux(rev)`} />
|
||||
|
||||
This is the same as:
|
||||
|
||||
<MiniRepl
|
||||
client:visible
|
||||
tune={`stack(
|
||||
n("0 1 [4 3] 2").sound("jazz").pan(0),
|
||||
n("0 1 [4 3] 2").sound("jazz").pan(1).rev()
|
||||
n("0 1 [4 3] 2 0 2 [~ 3] 4").sound("jazz").pan(0),
|
||||
n("0 1 [4 3] 2 0 2 [~ 3] 4").sound("jazz").pan(1).rev()
|
||||
)`}
|
||||
/>
|
||||
|
||||
|
|
@ -36,8 +36,8 @@ Let's visualize what happens here:
|
|||
<MiniRepl
|
||||
client:visible
|
||||
tune={`stack(
|
||||
n("0 1 [4 3] 2").sound("jazz").pan(0).color("cyan"),
|
||||
n("0 1 [4 3] 2").sound("jazz").pan(1).color("magenta").rev()
|
||||
n("0 1 [4 3] 2 0 2 [~ 3] 4").sound("jazz").pan(0).color("cyan"),
|
||||
n("0 1 [4 3] 2 0 2 [~ 3] 4").sound("jazz").pan(1).color("magenta").rev()
|
||||
)`}
|
||||
punchcard
|
||||
/>
|
||||
|
|
@ -50,16 +50,16 @@ Try commenting out one of the two by adding `//` before a line
|
|||
|
||||
**multiple tempos**
|
||||
|
||||
<MiniRepl client:visible tune={`note("c2, eb3 g3 [bb3 c4]").sound("piano").slow("1,2,3")`} />
|
||||
<MiniRepl client:visible tune={`note("c2, eb3 g3 [bb3 c4]").sound("piano").slow("0.5,1,1.5")`} />
|
||||
|
||||
This is like doing
|
||||
|
||||
<MiniRepl
|
||||
client:visible
|
||||
tune={`stack(
|
||||
note("c2, eb3 g3 [bb3 c4]").s("piano").slow(1).color('cyan'),
|
||||
note("c2, eb3 g3 [bb3 c4]").s("piano").slow(2).color('magenta'),
|
||||
note("c2, eb3 g3 [bb3 c4]").s("piano").slow(3).color('yellow')
|
||||
note("c2, eb3 g3 [bb3 c4]").s("piano").slow(0.5).color('cyan'),
|
||||
note("c2, eb3 g3 [bb3 c4]").s("piano").slow(1).color('magenta'),
|
||||
note("c2, eb3 g3 [bb3 c4]").s("piano").slow(1.5).color('yellow')
|
||||
)`}
|
||||
punchcard
|
||||
/>
|
||||
|
|
@ -74,9 +74,9 @@ Try commenting out one or more by adding `//` before a line
|
|||
|
||||
<MiniRepl
|
||||
client:visible
|
||||
tune={`note("c2 [eb3,g3]".add("<0 <1 -1>>"))
|
||||
tune={`note("c2 [eb3,g3] ".add("<0 <1 -1>>"))
|
||||
.color("<cyan <magenta yellow>>").adsr("[.1 0]:.2:[1 0]")
|
||||
.sound("gm_acoustic_bass").room(.5)`}
|
||||
.sound("gm_acoustic_bass").room(.5).cpm(60)`}
|
||||
punchcard
|
||||
/>
|
||||
|
||||
|
|
@ -92,7 +92,7 @@ We can add as often as we like:
|
|||
client:visible
|
||||
tune={`note("c2 [eb3,g3]".add("<0 <1 -1>>").add("0,7"))
|
||||
.color("<cyan <magenta yellow>>").adsr("[.1 0]:.2:[1 0]")
|
||||
.sound("gm_acoustic_bass").room(.5)`}
|
||||
.sound("gm_acoustic_bass").room(.5).cpm(60)`}
|
||||
punchcard
|
||||
/>
|
||||
|
||||
|
|
@ -100,7 +100,7 @@ We can add as often as we like:
|
|||
|
||||
<MiniRepl
|
||||
client:visible
|
||||
tune={`n("<0 [2 4] <3 5> [~ <4 1>]>*2".add("<0 [0,2,4]>/4"))
|
||||
tune={`n("0 [2 4] <3 5> [~ <4 1>]".add("<0 [0,2,4]>"))
|
||||
.scale("C5:minor").release(.5)
|
||||
.sound("gm_xylophone").room(.5)`}
|
||||
punchcard
|
||||
|
|
@ -111,7 +111,7 @@ We can add as often as we like:
|
|||
<MiniRepl
|
||||
client:visible
|
||||
tune={`stack(
|
||||
n("<0 [2 4] <3 5> [~ <4 1>]>*2".add("<0 [0,2,4]>/4"))
|
||||
n("0 [2 4] <3 5> [~ <4 1>]".add("<0 [0,2,4]>"))
|
||||
.scale("C5:minor")
|
||||
.sound("gm_xylophone")
|
||||
.room(.4).delay(.125),
|
||||
|
|
@ -119,17 +119,17 @@ We can add as often as we like:
|
|||
.adsr("[.1 0]:.2:[1 0]")
|
||||
.sound("gm_acoustic_bass")
|
||||
.room(.5),
|
||||
n("0 1 [2 3] 2").sound("jazz").jux(rev).slow(2)
|
||||
n("0 1 [2 3] 2").sound("jazz").jux(rev)
|
||||
)`}
|
||||
/>
|
||||
|
||||
**ply**
|
||||
|
||||
<MiniRepl client:visible tune={`sound("hh, bd rim").bank("RolandTR707").ply(2)`} punchcard />
|
||||
<MiniRepl client:visible tune={`sound("hh hh, bd rim [~ cp] rim").bank("RolandTR707").ply(2)`} punchcard />
|
||||
|
||||
this is like writing:
|
||||
|
||||
<MiniRepl client:visible tune={`sound("hh*2, bd*2 rim*2").bank("RolandTR707")`} punchcard />
|
||||
<MiniRepl client:visible tune={`sound("hh*2 hh*2, bd*2 rim*2 [~ cp*2] rim*2").bank("RolandTR707")`} punchcard />
|
||||
|
||||
<Box>
|
||||
|
||||
|
|
@ -141,10 +141,10 @@ Try patterning the `ply` function, for example using `"<1 2 1 3>"`
|
|||
|
||||
<MiniRepl
|
||||
client:visible
|
||||
tune={`n("<0 [4 <3 2>] <2 3> [~ 1]>"
|
||||
.off(1/8, x=>x.add(4))
|
||||
//.off(1/4, x=>x.add(7))
|
||||
).scale("<C5:minor Db5:mixolydian>/4")
|
||||
tune={`n("0 [4 <3 2>] <2 3> [~ 1]"
|
||||
.off(1/16, x=>x.add(4))
|
||||
//.off(1/8, x=>x.add(7))
|
||||
).scale("<C5:minor Db5:mixolydian>/2")
|
||||
.s("triangle").room(.5).ds(".1:0").delay(.5)`}
|
||||
punchcard
|
||||
/>
|
||||
|
|
@ -159,14 +159,14 @@ off is also useful for sounds:
|
|||
|
||||
<MiniRepl
|
||||
client:visible
|
||||
tune={`s("bd sd,[~ hh]*2").bank("CasioRZ1")
|
||||
.off(1/8, x=>x.speed(1.5).gain(.25))`}
|
||||
tune={`s("bd sd [rim bd] sd,[~ hh]*4").bank("CasioRZ1")
|
||||
.off(1/16, x=>x.speed(1.5).gain(.25))`}
|
||||
/>
|
||||
|
||||
| name | description | example |
|
||||
| ---- | ------------------------------ | ----------------------------------------------------------------------------------- |
|
||||
| rev | reverse | <MiniRepl client:visible tune={`n("0 2 4 6").scale("C:minor").rev()`} /> |
|
||||
| jux | split left/right, modify right | <MiniRepl client:visible tune={`n("0 2 4 6").scale("C:minor").jux(rev)`} /> |
|
||||
| add | add numbers / notes | <MiniRepl client:visible tune={`n("0 2 4 6".add("<0 1 2 1>")).scale("C:minor")`} /> |
|
||||
| ply | speed up each event n times | <MiniRepl client:visible tune={`s("bd sd").ply("<1 2 3>")`} /> |
|
||||
| off | copy, shift time & modify | <MiniRepl client:visible tune={`s("bd sd, hh*4").off(1/8, x=>x.speed(2))`} /> |
|
||||
| name | description | example |
|
||||
| ---- | ------------------------------ | ------------------------------------------------------------------------------------------- |
|
||||
| rev | reverse | <MiniRepl client:visible tune={`n("0 2 4 6 ~ 7 9 5").scale("C:minor").rev()`} /> |
|
||||
| jux | split left/right, modify right | <MiniRepl client:visible tune={`n("0 2 4 6 ~ 7 9 5").scale("C:minor").jux(rev)`} /> |
|
||||
| add | add numbers / notes | <MiniRepl client:visible tune={`n("0 2 4 6 ~ 7 9 5".add("<0 1 2 1>")).scale("C:minor")`} /> |
|
||||
| ply | speed up each event n times | <MiniRepl client:visible tune={`s("bd sd [~ bd] sd").ply("<1 2 3>")`} /> |
|
||||
| off | copy, shift time & modify | <MiniRepl client:visible tune={`s("bd sd [~ bd] sd, hh*8").off(1/16, x=>x.speed(2))`} /> |
|
||||
|
|
|
|||
|
|
@ -13,12 +13,12 @@ This page is just a listing of all functions covered in the workshop!
|
|||
|
||||
| Concept | Syntax | Example |
|
||||
| ----------------- | -------- | --------------------------------------------------------------------- |
|
||||
| Sequence | space | <MiniRepl client:visible tune={`sound("bd bd sn hh")`} /> |
|
||||
| Sequence | space | <MiniRepl client:visible tune={`sound("bd bd sd hh bd cp sd hh")`} /> |
|
||||
| Sample Number | :x | <MiniRepl client:visible tune={`sound("hh:0 hh:1 hh:2 hh:3")`} /> |
|
||||
| Rests | ~ | <MiniRepl client:visible tune={`sound("metal ~ jazz jazz:1")`} /> |
|
||||
| Sub-Sequences | \[\] | <MiniRepl client:visible tune={`sound("bd wind [metal jazz] hh")`} /> |
|
||||
| Sub-Sub-Sequences | \[\[\]\] | <MiniRepl client:visible tune={`sound("bd [metal [jazz sn]]")`} /> |
|
||||
| Speed up | \* | <MiniRepl client:visible tune={`sound("bd sn*2 cp*3")`} /> |
|
||||
| Sub-Sub-Sequences | \[\[\]\] | <MiniRepl client:visible tune={`sound("bd [metal [jazz sd]]")`} /> |
|
||||
| Speed up | \* | <MiniRepl client:visible tune={`sound("bd sd*2 cp*3")`} /> |
|
||||
| Parallel | , | <MiniRepl client:visible tune={`sound("bd*2, hh*2 [hh oh]")`} /> |
|
||||
| Slow down | \/ | <MiniRepl client:visible tune={`note("[c a f e]/2")`} /> |
|
||||
| Alternate | \<\> | <MiniRepl client:visible tune={`note("c <e g>")`} /> |
|
||||
|
|
@ -45,22 +45,22 @@ This page is just a listing of all functions covered in the workshop!
|
|||
|
||||
| name | example |
|
||||
| ----- | --------------------------------------------------------------------------------------- |
|
||||
| lpf | <MiniRepl client:visible tune={`note("c2 c3").s("sawtooth").lpf("<400 2000>")`} /> |
|
||||
| lpf | <MiniRepl client:visible tune={`note("c2 c3 c2 c3").s("sawtooth").lpf("400 2000")`} /> |
|
||||
| vowel | <MiniRepl client:visible tune={`note("c3 eb3 g3").s("sawtooth").vowel("<a e i o>")`} /> |
|
||||
| gain | <MiniRepl client:visible tune={`s("hh*8").gain("[.25 1]*2")`} /> |
|
||||
| delay | <MiniRepl client:visible tune={`s("bd rim").delay(.5)`} /> |
|
||||
| room | <MiniRepl client:visible tune={`s("bd rim").room(.5)`} /> |
|
||||
| pan | <MiniRepl client:visible tune={`s("bd rim").pan("0 1")`} /> |
|
||||
| speed | <MiniRepl client:visible tune={`s("bd rim").speed("<1 2 -1 -2>")`} /> |
|
||||
| range | <MiniRepl client:visible tune={`s("hh*16").lpf(saw.range(200,4000))`} /> |
|
||||
| gain | <MiniRepl client:visible tune={`s("hh*16").gain("[.25 1]*4")`} /> |
|
||||
| delay | <MiniRepl client:visible tune={`s("bd rim bd cp").delay(.5)`} /> |
|
||||
| room | <MiniRepl client:visible tune={`s("bd rim bd cp").room(.5)`} /> |
|
||||
| pan | <MiniRepl client:visible tune={`s("bd rim bd cp").pan("0 1")`} /> |
|
||||
| speed | <MiniRepl client:visible tune={`s("bd rim bd cp").speed("<1 2 -1 -2>")`} /> |
|
||||
| range | <MiniRepl client:visible tune={`s("hh*32").lpf(saw.range(200,4000))`} /> |
|
||||
|
||||
## Pattern Effects
|
||||
|
||||
| name | description | example |
|
||||
| ---- | ----------------------------------- | ----------------------------------------------------------------------------------- |
|
||||
| cpm | sets the tempo in cycles per minute | <MiniRepl client:visible tune={`sound("bd sd").cpm(90)`} /> |
|
||||
| fast | speed up | <MiniRepl client:visible tune={`sound("bd sd").fast(2)`} /> |
|
||||
| slow | slow down | <MiniRepl client:visible tune={`sound("bd sd").slow(2)`} /> |
|
||||
| cpm | sets the tempo in cycles per minute | <MiniRepl client:visible tune={`sound("bd sd [~ bd] sd").cpm(45)`} /> |
|
||||
| fast | speed up | <MiniRepl client:visible tune={`sound("bd sd [~ bd] sd").fast(2)`} /> |
|
||||
| slow | slow down | <MiniRepl client:visible tune={`sound("bd sd [~ bd] sd").slow(2)`} /> |
|
||||
| rev | reverse | <MiniRepl client:visible tune={`n("0 2 4 6").scale("C:minor").rev()`} /> |
|
||||
| jux | split left/right, modify right | <MiniRepl client:visible tune={`n("0 2 4 6").scale("C:minor").jux(rev)`} /> |
|
||||
| add | add numbers / notes | <MiniRepl client:visible tune={`n("0 2 4 6".add("<0 1 2 1>")).scale("C:minor")`} /> |
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@ import { getRandomTune, initCode, loadModules, shareCode, ReplContext } from './
|
|||
import PlayCircleIcon from '@heroicons/react/20/solid/PlayCircleIcon';
|
||||
import './Repl.css';
|
||||
|
||||
const { code: randomTune, name } = getRandomTune();
|
||||
const { latestCode } = settingsMap.get();
|
||||
|
||||
let modulesLoading, presets, drawContext, clearCanvas, isIframe;
|
||||
|
|
@ -98,7 +97,7 @@ export function Repl({ embedded = false }) {
|
|||
|
||||
// init settings
|
||||
|
||||
initCode().then((decoded) => {
|
||||
initCode().then(async (decoded) => {
|
||||
let msg;
|
||||
if (decoded) {
|
||||
editor.setCode(decoded);
|
||||
|
|
@ -107,6 +106,7 @@ export function Repl({ embedded = false }) {
|
|||
editor.setCode(latestCode);
|
||||
msg = `Your last session has been loaded!`;
|
||||
} else {
|
||||
const { code: randomTune, name } = await getRandomTune();
|
||||
editor.setCode(randomTune);
|
||||
msg = `A random code snippet named "${name}" has been loaded!`;
|
||||
}
|
||||
|
|
@ -159,7 +159,7 @@ export function Repl({ embedded = false }) {
|
|||
const resetEditor = async () => {
|
||||
clearCanvas();
|
||||
resetLoadedSounds();
|
||||
editorRef.current.repl.setCps(1);
|
||||
editorRef.current.repl.setCps(0.5);
|
||||
await prebake(); // declare default samples
|
||||
};
|
||||
|
||||
|
|
@ -176,7 +176,7 @@ export function Repl({ embedded = false }) {
|
|||
editorRef.current.evaluate();
|
||||
};
|
||||
const handleShuffle = async () => {
|
||||
const patternData = getRandomTune();
|
||||
const patternData = await getRandomTune();
|
||||
const code = patternData.code;
|
||||
logger(`[repl] ✨ loading random tune "${patternData.id}"`);
|
||||
setActivePattern(patternData.id);
|
||||
|
|
|
|||
|
|
@ -314,7 +314,7 @@ stack(
|
|||
)
|
||||
.fast(2/3)
|
||||
.pianoroll()`;
|
||||
|
||||
/*
|
||||
export const bridgeIsOver = `// "Bridge is over"
|
||||
// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
// @by Felix Roos, bassline by BDP - The Bridge Is Over
|
||||
|
|
@ -333,7 +333,7 @@ stack(
|
|||
s("mad").slow(2)
|
||||
).cpm(78).slow(4)
|
||||
.pianoroll()
|
||||
`;
|
||||
`; */
|
||||
|
||||
export const goodTimes = `// "Good times"
|
||||
// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
|
@ -709,6 +709,8 @@ export const dinofunk = `// "Dinofunk"
|
|||
// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
// @by Felix Roos
|
||||
|
||||
setcps(1)
|
||||
|
||||
samples({bass:'https://cdn.freesound.org/previews/614/614637_2434927-hq.mp3',
|
||||
dino:{b4:'https://cdn.freesound.org/previews/316/316403_5123851-hq.mp3'}})
|
||||
setVoicingRange('lefthand', ['c3','a4'])
|
||||
|
|
|
|||
|
|
@ -9,8 +9,7 @@ import { createClient } from '@supabase/supabase-js';
|
|||
import { nanoid } from 'nanoid';
|
||||
import { writeText } from '@tauri-apps/api/clipboard';
|
||||
import { createContext } from 'react';
|
||||
import { stockPatterns } from './useExamplePatterns';
|
||||
import { loadDBPatterns } from '@src/user_pattern_utils.mjs';
|
||||
import { $featuredPatterns, loadDBPatterns } from '@src/user_pattern_utils.mjs';
|
||||
|
||||
// Create a single supabase client for interacting with your database
|
||||
export const supabase = createClient(
|
||||
|
|
@ -18,8 +17,9 @@ export const supabase = createClient(
|
|||
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InBpZHhkc3hwaGxoempuem1pZnRoIiwicm9sZSI6ImFub24iLCJpYXQiOjE2NTYyMzA1NTYsImV4cCI6MTk3MTgwNjU1Nn0.bqlw7802fsWRnqU5BLYtmXk_k-D1VFmbkHMywWc15NM',
|
||||
);
|
||||
|
||||
let dbLoaded;
|
||||
if (typeof window !== 'undefined') {
|
||||
loadDBPatterns();
|
||||
dbLoaded = loadDBPatterns();
|
||||
}
|
||||
|
||||
export async function initCode() {
|
||||
|
|
@ -34,7 +34,7 @@ export async function initCode() {
|
|||
return hash2code(codeParam);
|
||||
} else if (hash) {
|
||||
return supabase
|
||||
.from('code')
|
||||
.from('code_v1')
|
||||
.select('code')
|
||||
.eq('hash', hash)
|
||||
.then(({ data, error }) => {
|
||||
|
|
@ -61,10 +61,11 @@ export const parseJSON = (json) => {
|
|||
}
|
||||
};
|
||||
|
||||
export function getRandomTune() {
|
||||
const allTunes = Object.entries(stockPatterns);
|
||||
export async function getRandomTune() {
|
||||
await dbLoaded;
|
||||
const featuredTunes = Object.entries($featuredPatterns.get());
|
||||
const randomItem = (arr) => arr[Math.floor(Math.random() * arr.length)];
|
||||
const [id, data] = randomItem(allTunes);
|
||||
const [_, data] = randomItem(featuredTunes);
|
||||
return data;
|
||||
}
|
||||
|
||||
|
|
@ -111,7 +112,7 @@ export async function shareCode(codeToShare) {
|
|||
// generate uuid in the browser
|
||||
const hash = nanoid(12);
|
||||
const shareUrl = window.location.origin + window.location.pathname + '?' + hash;
|
||||
const { error } = await supabase.from('code').insert([{ code: codeToShare, hash, ['public']: isPublic }]);
|
||||
const { error } = await supabase.from('code_v1').insert([{ code: codeToShare, hash, ['public']: isPublic }]);
|
||||
if (!error) {
|
||||
lastShared = codeToShare;
|
||||
// copy shareUrl to clipboard
|
||||
|
|
|
|||
|
|
@ -44,11 +44,11 @@ export const setViewingPatternData = (data) => {
|
|||
};
|
||||
|
||||
export function loadPublicPatterns() {
|
||||
return supabase.from('code').select().eq('public', true).limit(20).order('id', { ascending: false });
|
||||
return supabase.from('code_v1').select().eq('public', true).limit(20).order('id', { ascending: false });
|
||||
}
|
||||
|
||||
export function loadFeaturedPatterns() {
|
||||
return supabase.from('code').select().eq('featured', true).limit(20).order('id', { ascending: false });
|
||||
return supabase.from('code_v1').select().eq('featured', true).limit(20).order('id', { ascending: false });
|
||||
}
|
||||
|
||||
export async function loadDBPatterns() {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue