Merge branch 'tidalcycles:main' into udels
This commit is contained in:
commit
d23038d386
126 changed files with 4976 additions and 8255 deletions
|
|
@ -147,7 +147,7 @@ Probier `ply` mit einem pattern zu automatisieren, z.b. `"<1 2 1 3>"`
|
|||
.off(1/8, x=>x.add(4))
|
||||
//.off(1/4, x=>x.add(7))
|
||||
).scale("<C5:minor Db5:mixolydian>/4")
|
||||
.s("triangle").room(.5).ds(".1:0").delay(.5)`}
|
||||
.s("triangle").room(.5).dec(.1).delay(.5)`}
|
||||
punchcard
|
||||
/>
|
||||
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ Each filter can receive an additional filter envelope controlling the cutoff val
|
|||
client:idle
|
||||
tune={`note("[c eb g <f bb>](3,8,<0 1>)".sub(12))
|
||||
.s("<sawtooth>/64")
|
||||
.lpf(sine.range(500,3000).slow(16))
|
||||
.lpf(sine.range(300,2000).slow(16))
|
||||
.lpa(0.005)
|
||||
.lpd(perlin.range(.02,.2))
|
||||
.lps(perlin.range(0,.5).slow(3))
|
||||
|
|
@ -106,7 +106,7 @@ Each filter can receive an additional filter envelope controlling the cutoff val
|
|||
.juxBy(.5,rev)
|
||||
.sometimes(add(note(12)))
|
||||
.stack(s("bd*2").bank('RolandTR909'))
|
||||
.gain(.5)`}
|
||||
.gain(.5).fast(2)`}
|
||||
/>
|
||||
|
||||
There is one filter envelope for each filter type and thus one set of envelope filter parameters preceded either by `lp`, `hp` or `bp`:
|
||||
|
|
|
|||
|
|
@ -11,15 +11,15 @@ import { JsDoc } from '../../docs/JsDoc';
|
|||
The following functions will return a pattern.
|
||||
These are the equivalents used by the Mini Notation:
|
||||
|
||||
| function | mini |
|
||||
| ------------------------------ | ---------------- |
|
||||
| `cat(x, y)` | `"<x y>"` |
|
||||
| `seq(x, y)` | `"x y"` |
|
||||
| `stack(x, y)` | `"x,y"` |
|
||||
| `timeCat([3,x],[2,y])` | `"x@3 y@2"` |
|
||||
| `polymeter([a, b, c], [x, y])` | `"{a b c, x y}"` |
|
||||
| `polymeterSteps(2, x, y, z)` | `"{x y z}%2"` |
|
||||
| `silence` | `"~"` |
|
||||
| function | mini |
|
||||
| -------------------------------- | ---------------- |
|
||||
| `cat(x, y)` | `"<x y>"` |
|
||||
| `seq(x, y)` | `"x y"` |
|
||||
| `stack(x, y)` | `"x,y"` |
|
||||
| `s_cat([3,x],[2,y])` | `"x@3 y@2"` |
|
||||
| `s_polymeter([a, b, c], [x, y])` | `"{a b c, x y}"` |
|
||||
| `s_polymeterSteps(2, x, y, z)` | `"{x y z}%2"` |
|
||||
| `silence` | `"~"` |
|
||||
|
||||
## cat
|
||||
|
||||
|
|
@ -45,21 +45,21 @@ As a chained function:
|
|||
|
||||
<JsDoc client:idle name="Pattern.stack" h={0} hideDescription />
|
||||
|
||||
## timeCat
|
||||
## s_cat
|
||||
|
||||
<JsDoc client:idle name="timeCat" h={0} />
|
||||
<JsDoc client:idle name="s_cat" h={0} />
|
||||
|
||||
## arrange
|
||||
|
||||
<JsDoc client:idle name="arrange" h={0} />
|
||||
|
||||
## polymeter
|
||||
## s_polymeter
|
||||
|
||||
<JsDoc client:idle name="polymeter" h={0} />
|
||||
<JsDoc client:idle name="s_polymeter" h={0} />
|
||||
|
||||
## polymeterSteps
|
||||
## s_polymeterSteps
|
||||
|
||||
<JsDoc client:idle name="polymeterSteps" h={0} />
|
||||
<JsDoc client:idle name="s_polymeterSteps" h={0} />
|
||||
|
||||
## silence
|
||||
|
||||
|
|
|
|||
|
|
@ -90,11 +90,13 @@ src(s0).kaleid(H("<4 5 6>"))
|
|||
.modulateScale(osc(2,-0.25,1))
|
||||
.out()
|
||||
//
|
||||
stack(
|
||||
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')
|
||||
).fft(4)
|
||||
.scope({pos:0,smear:.95})`}
|
||||
|
||||
$: 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')
|
||||
|
||||
all(x=>x.fft(4).scope({pos:0,smear:.95}))`}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -20,11 +20,7 @@ Strudel also supports midi via [webmidi](https://npmjs.com/package/webmidi).
|
|||
Either connect a midi device or use the IAC Driver (Mac) or Midi Through Port (Linux) for internal midi messages.
|
||||
If no outputName is given, it uses the first midi output it finds.
|
||||
|
||||
<MiniRepl
|
||||
client:idle
|
||||
tune={`stack("<C^7 A7 Dm7 G7>".voicings('lefthand'), "<C3 A2 D3 G2>").note()
|
||||
.midi()`}
|
||||
/>
|
||||
<MiniRepl client:idle tune={`chord("<C^7 A7 Dm7 G7>").voicing().midi()`} />
|
||||
|
||||
In the console, you will see a log of the available MIDI devices as soon as you run the code, e.g. `Midi connected! Using "Midi Through Port-0".`
|
||||
|
||||
|
|
@ -45,10 +41,8 @@ But you can also control cc messages separately like this:
|
|||
|
||||
<MiniRepl
|
||||
client:idle
|
||||
tune={`stack(
|
||||
note("c a f e"),
|
||||
ccv(sine.segment(16).slow(4)).ccn(74)
|
||||
).midi()`}
|
||||
tune={`$: note("c a f e").midi()
|
||||
$: ccv(sine.segment(16).slow(4)).ccn(74).midi()`}
|
||||
/>
|
||||
|
||||
# SuperDirt API
|
||||
|
|
|
|||
|
|
@ -268,11 +268,10 @@ With it, you can enter any sample name(s) to query from [freesound.org](https://
|
|||
<MiniRepl
|
||||
client:idle
|
||||
tune={`samples('shabda:bass:4,hihat:4,rimshot:2')
|
||||
stack(
|
||||
n("0 1 2 3 0 1 2 3").s('bass'),
|
||||
n("0 1*2 2 3*2").s('hihat'),
|
||||
n("~ 0 ~ 1 ~ 0 0 1").s('rimshot')
|
||||
).clip(1)`}
|
||||
|
||||
$: n("0 1 2 3 0 1 2 3").s('bass')
|
||||
$: n("0 1*2 2 3*2").s('hihat').clip(1)
|
||||
$: n("~ 0 ~ 1 ~ 0 0 1").s('rimshot')`}
|
||||
/>
|
||||
|
||||
You can also generate artificial voice samples with any text, in multiple languages.
|
||||
|
|
@ -282,10 +281,9 @@ Note that the language code and the gender parameters are optional and default t
|
|||
client:idle
|
||||
tune={`samples('shabda/speech:the_drum,forever')
|
||||
samples('shabda/speech/fr-FR/m:magnifique')
|
||||
stack(
|
||||
s("the_drum*2").chop(16).speed(rand.range(0.85,1.1)),
|
||||
s("forever magnifique").slow(4).late(0.125)
|
||||
)`}
|
||||
|
||||
$: s("the_drum*2").chop(16).speed(rand.range(0.85,1.1))
|
||||
$: s("forever magnifique").slow(4).late(0.125)`}
|
||||
/>
|
||||
|
||||
# Sampler Effects
|
||||
|
|
|
|||
|
|
@ -55,4 +55,12 @@ There is also `saw2`, `sine2`, `cosine2`, `tri2`, `square2` and `rand2` which ha
|
|||
|
||||
<JsDoc client:idle name="brandBy" h={0} />
|
||||
|
||||
## mouseX
|
||||
|
||||
<JsDoc client:idle name="mousex" h={0} />
|
||||
|
||||
## mouseY
|
||||
|
||||
<JsDoc client:idle name="mousey" h={0} />
|
||||
|
||||
Next up: [Random Modifiers](/learn/random-modifiers)
|
||||
|
|
|
|||
|
|
@ -112,29 +112,14 @@ Also, samples are always loaded from a URL rather than from the disk, although [
|
|||
## Evaluation
|
||||
|
||||
The Strudel REPL does not support [block based evaluation](https://github.com/tidalcycles/strudel/issues/34) yet.
|
||||
You can use the following "workaround" to create multiple patterns that can be turned on and off:
|
||||
You can use labeled statements and `_` to mute:
|
||||
|
||||
```
|
||||
let a = note("c a f e")
|
||||
<MiniRepl
|
||||
client:visible
|
||||
tune={`$: n("[0 .. 8]*8/9").scale("C:minor:pentatonic")
|
||||
|
||||
let b = s("bd sd")
|
||||
|
||||
stack(
|
||||
a,
|
||||
// b
|
||||
)
|
||||
```
|
||||
|
||||
Alternatively, you could write everything as one `stack` and use `.hush()` to silence a pattern:
|
||||
|
||||
```
|
||||
stack(
|
||||
note("c a f e"),
|
||||
s("bd sd").hush()
|
||||
)
|
||||
```
|
||||
|
||||
Note that strudel will always use the last statement in your code as the pattern for querying
|
||||
\_$: s("bd\*4").bank('RolandTR909')`}
|
||||
/>
|
||||
|
||||
## Tempo
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ The basic waveforms are `sine`, `sawtooth`, `square` and `triangle`, which can b
|
|||
client:idle
|
||||
tune={`note("c2 <eb2 <g2 g1>>".fast(2))
|
||||
.sound("<sawtooth square triangle sine>")
|
||||
.scope()`}
|
||||
._scope()`}
|
||||
/>
|
||||
|
||||
If you don't set a `sound` but a `note` the default value for `sound` is `triangle`!
|
||||
|
|
@ -28,23 +28,23 @@ 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>").scope()`} />
|
||||
<MiniRepl client:idle tune={`sound("<white pink brown>")._scope()`} />
|
||||
|
||||
Here's a more musical example of how to use noise for hihats:
|
||||
|
||||
<MiniRepl
|
||||
client:idle
|
||||
tune={`sound("bd*2,<white pink brown>*8")
|
||||
.decay(.04).sustain(0).scope()`}
|
||||
.decay(.04).sustain(0)._scope()`}
|
||||
/>
|
||||
|
||||
Some amount of pink noise can also be added to any oscillator by using the `noise` paremeter:
|
||||
|
||||
<MiniRepl client:idle tune={`note("c3").noise("<0.1 0.25 0.5>").scope()`} />
|
||||
<MiniRepl client:idle tune={`note("c3").noise("<0.1 0.25 0.5>")._scope()`} />
|
||||
|
||||
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(2)).scope()`} />
|
||||
<MiniRepl client:idle tune={`s("crackle*4").density("<0.01 0.04 0.2 0.5>".slow(2))._scope()`} />
|
||||
|
||||
### Additive Synthesis
|
||||
|
||||
|
|
@ -55,7 +55,7 @@ To tame the harsh sound of the basic waveforms, we can set the `n` control to li
|
|||
tune={`note("c2 <eb2 <g2 g1>>".fast(2))
|
||||
.sound("sawtooth")
|
||||
.n("<32 16 8 4>")
|
||||
.scope()`}
|
||||
._scope()`}
|
||||
/>
|
||||
|
||||
When the `n` control is used on a basic waveform, it defines the number of harmonic partials the sound is getting.
|
||||
|
|
@ -65,7 +65,7 @@ You can also set `n` directly in mini notation with `sound`:
|
|||
client:idle
|
||||
tune={`note("c2 <eb2 <g2 g1>>".fast(2))
|
||||
.sound("sawtooth:<32 16 8 4>")
|
||||
.scope()`}
|
||||
._scope()`}
|
||||
/>
|
||||
|
||||
Note for tidal users: `n` in tidal is synonymous to `note` for synths only.
|
||||
|
|
@ -119,13 +119,14 @@ Any sample preceded by the `wt_` prefix will be loaded as a wavetable. This mean
|
|||
|
||||
<MiniRepl
|
||||
client:idle
|
||||
tune={`samples('github:Bubobubobubobubo/Dough-Waveforms/main/');
|
||||
|
||||
tune={`samples('bubo:waveforms');
|
||||
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(4)`}
|
||||
.cutoff(2000).cutoff("<1000 2000 4000>").fast(4)
|
||||
._scope()
|
||||
`}
|
||||
/>
|
||||
|
||||
## ZZFX
|
||||
|
|
@ -159,7 +160,7 @@ It has 20 parameters in total, here is a snippet that uses all:
|
|||
.tremolo(0) // 0-1 lfo volume modulation amount
|
||||
//.duration(.2) // overwrite strudel event duration
|
||||
//.gain(1) // change volume
|
||||
.scope() // vizualise waveform (not zzfx related)
|
||||
._scope() // vizualise waveform (not zzfx related)
|
||||
`}
|
||||
/>
|
||||
|
||||
|
|
|
|||
|
|
@ -106,4 +106,12 @@ Some of these have equivalent operators in the Mini Notation:
|
|||
|
||||
<JsDoc client:idle name="ribbon" h={0} />
|
||||
|
||||
## swingBy
|
||||
|
||||
<JsDoc client:idle name="swingBy" h={0} />
|
||||
|
||||
## swing
|
||||
|
||||
<JsDoc client:idle name="swing" h={0} />
|
||||
|
||||
Apart from modifying time, there are ways to [Control Parameters](/functions/value-modifiers/).
|
||||
|
|
|
|||
|
|
@ -55,20 +55,6 @@ Transposes notes inside the scale by the number of steps:
|
|||
.note()`}
|
||||
/>
|
||||
|
||||
### voicings(range?)
|
||||
|
||||
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()`}
|
||||
/>
|
||||
|
||||
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.
|
||||
|
|
|
|||
100
website/src/pages/learn/visual-feedback.mdx
Normal file
100
website/src/pages/learn/visual-feedback.mdx
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
---
|
||||
title: Visual Feedback
|
||||
layout: ../../layouts/MainLayout.astro
|
||||
---
|
||||
|
||||
import { MiniRepl } from '../../docs/MiniRepl';
|
||||
import { JsDoc } from '../../docs/JsDoc';
|
||||
|
||||
# Visual Feedback
|
||||
|
||||
There are several function that add visual feedback to your patterns.
|
||||
|
||||
## Mini Notation Highlighting
|
||||
|
||||
When you write mini notation with "double quotes" or \`backticks\`, the active parts of the mini notation will be highlighted:
|
||||
|
||||
<MiniRepl
|
||||
client:idle
|
||||
tune={`n("<0 2 1 3 2>*8")
|
||||
.scale("<A1 D2>/4:minor:pentatonic")
|
||||
.s("supersaw").lpf(300).lpenv("<4 3 2>\*4")`}
|
||||
/>
|
||||
|
||||
You can change the color as well, even pattern it:
|
||||
|
||||
<MiniRepl
|
||||
client:idle
|
||||
tune={`n("<0 2 1 3 2>*8")
|
||||
.scale("<A1 D2>/4:minor:pentatonic")
|
||||
.s("supersaw").lpf(300).lpenv("<4 3 2>*4")
|
||||
.color("cyan magenta")`}
|
||||
/>
|
||||
|
||||
## Global vs Inline Visuals
|
||||
|
||||
The following functions all come with in 2 variants.
|
||||
|
||||
**Without prefix**: renders the visual to the background of the page:
|
||||
|
||||
<MiniRepl client:idle tune={`note("c a f e").color("white").punchcard()`} />
|
||||
|
||||
**With `_` prefix**: renders the visual inside the code. Allows for multiple visuals
|
||||
|
||||
<MiniRepl client:idle tune={`note("c a f e").color("white")._punchcard()`} />
|
||||
|
||||
Here we see the 2 variants for `punchcard`. The same goes for all others below.
|
||||
To improve readability the following demos will all use the inline variant.
|
||||
|
||||
## Punchcard / Pianoroll
|
||||
|
||||
These 2 functions render a pianoroll style visual.
|
||||
The only difference between the 2 is that `pianoroll` will render the pattern directly,
|
||||
while `punchcard` will also take the transformations into account that occur afterwards:
|
||||
|
||||
<MiniRepl
|
||||
client:idle
|
||||
tune={`note("c a f e").color("white")
|
||||
._punchcard()
|
||||
.color("cyan")`}
|
||||
autodraw
|
||||
/>
|
||||
|
||||
Here, the `color` is still visible in the visual, even if it is applied after `_punchcard`.
|
||||
On the contrary, the color is not visible when using `_pianoroll`:
|
||||
|
||||
<MiniRepl
|
||||
client:idle
|
||||
tune={`note("c a f e").color("white")
|
||||
._pianoroll()
|
||||
.color("cyan")`}
|
||||
autodraw
|
||||
/>
|
||||
|
||||
import Box from '@components/Box.astro';
|
||||
|
||||
<br />
|
||||
|
||||
<Box>
|
||||
|
||||
`punchcard` is less resource intensive because it uses the same data as used for the mini notation highlighting.
|
||||
|
||||
</Box>
|
||||
|
||||
The visual can be customized by passing options. Those options are the same for both functions.
|
||||
|
||||
What follows is the API doc of all the options you can pass:
|
||||
|
||||
<JsDoc client:idle name="pianoroll" h={0} />
|
||||
|
||||
## Spiral
|
||||
|
||||
<JsDoc client:idle name="spiral" h={0} />
|
||||
|
||||
## Scope
|
||||
|
||||
<JsDoc client:idle name="scope" h={0} />
|
||||
|
||||
## Pitchwheel
|
||||
|
||||
<JsDoc client:idle name="pitchwheel" h={0} />
|
||||
|
|
@ -308,7 +308,7 @@ Running through different wavetables can also give interesting variations:
|
|||
<MiniRepl
|
||||
client:visible
|
||||
tune={`samples('github:bubobubobubobubo/dough-waveforms')
|
||||
note("c2*8").s("wt_dbass").n(run(8))`}
|
||||
note("c2*8").s("wt_dbass").n(run(8)).fast(2)`}
|
||||
/>
|
||||
|
||||
...adding a filter envelope + reverb:
|
||||
|
|
@ -317,6 +317,6 @@ note("c2*8").s("wt_dbass").n(run(8))`}
|
|||
client:visible
|
||||
tune={`samples('github:bubobubobubobubo/dough-waveforms')
|
||||
note("c2*8").s("wt_dbass").n(run(8))
|
||||
.lpf(perlin.range(200,2000).slow(8))
|
||||
.lpenv(-3).lpa(.1).room(.5)`}
|
||||
.lpf(perlin.range(100,1000).slow(8))
|
||||
.lpenv(-3).lpa(.1).room(.5).fast(2)`}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ following example:
|
|||
|
||||
```js
|
||||
'0 1 2'.add('10 20');
|
||||
('10 [11 21] 20');
|
||||
('10 [11 21] 22');
|
||||
```
|
||||
|
||||
They are similar to the previous example in that the number `1` is split in two, with its two halves added to `10` and `20` respectively. However, the `11` 'remembers' that it is a fragment of that original `1` event, and so is treated as having a duration of a third of a cycle, despite only being active for a sixth of a cycle. Likewise, the `21` is also a fragment of that original `1` event, but a fragment of its second half. Because the start of its event is missing, it wouldn't actually trigger a sound (unless it underwent further pattern transformations/combinations).
|
||||
|
|
@ -41,7 +41,7 @@ This makes way for other ways to align the pattern, and several are already defi
|
|||
- `mix` - structures from both patterns are combined, so that the new events are not fragments but are created at intersections of events from both sides.
|
||||
- `squeeze` - cycles from the pattern on the right are squeezed into events on the left. So that e.g. `"0 1 2".add.squeeze("10 20")` is equivalent to `"[10 20] [11 21] [12 22]"`.
|
||||
- `squeezeout` - as with `squeeze`, but cycles from the left are squeezed into events on the right. So, `"0 1 2".add.squeezeout("10 20")` is equivalent to `[10 11 12] [20 21 22]`.
|
||||
- `reset` is similar to `squeezeout` in that cycles from the right are aligned with events on the left. However those cycles are not 'squeezed', rather they are truncated to fit the event. So `"0 1 2 3 4 5 6 7".add.trig("10 [20 30]")` would be equivalent to `10 11 12 13 20 21 30 31`. In effect, events on the right 'trigger' cycles on the left.
|
||||
- `reset` is similar to `squeezeout` in that cycles from the right are aligned with events on the left. However those cycles are not 'squeezed', rather they are truncated to fit the event. So `"0 1 2 3 4 5 6 7".add.reset("10 [20 30]")` would be equivalent to `10 11 12 13 20 21 30 31`. In effect, events on the right 'reset' cycles on the left.
|
||||
- `restart` is similar to `reset`, but the pattern is 'restarted' from its very first cycle, rather than from the current cycle. `reset` and `restart` therefore only give different results where the leftmost pattern differs from one cycle to the next.
|
||||
|
||||
We will save going deeper into the background, design and practicalities of these alignment functions for future publications. However in the next section, we take them as a case study for looking at the different design affordances offered by Haskell to Tidal, and JavaScript to Strudel.
|
||||
|
|
|
|||
|
|
@ -60,11 +60,10 @@ We will learn how to automate with waves later...
|
|||
|
||||
<MiniRepl
|
||||
client:visible
|
||||
tune={`stack(
|
||||
sound("hh*16").gain("[.25 1]*4"),
|
||||
sound("bd*4,[~ sd:1]*2")
|
||||
) `}
|
||||
punchcard
|
||||
tune={`$: sound("hh*16").gain("[.25 1]*4")
|
||||
|
||||
$: sound("bd*4,[~ sd:1]*2")`}
|
||||
punchcard
|
||||
/>
|
||||
|
||||
<Box>
|
||||
|
|
@ -76,31 +75,21 @@ Rhythm is all about dynamics!
|
|||
|
||||
</Box>
|
||||
|
||||
**stacks within stacks**
|
||||
|
||||
Let's combine all of the above into a little tune:
|
||||
|
||||
<MiniRepl
|
||||
client:visible
|
||||
tune={`stack(
|
||||
stack(
|
||||
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>")
|
||||
.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>")
|
||||
) `}
|
||||
tune={`$: 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>")
|
||||
.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>")`}
|
||||
/>
|
||||
|
||||
<Box>
|
||||
|
||||
Try to identify the individual parts of the stacks, pay attention to where the commas are.
|
||||
The 3 parts (drums, bassline, chords) are exactly as earlier, just stacked together, separated by comma.
|
||||
|
||||
</Box>
|
||||
|
||||
**shape the sound with an adsr envelope**
|
||||
|
||||
<MiniRepl
|
||||
|
|
@ -151,11 +140,10 @@ Can you guess what they do?
|
|||
|
||||
<MiniRepl
|
||||
client:visible
|
||||
tune={`stack(
|
||||
note("[~ [<[d3,a3,f4]!2 [d3,bb3,g4]!2> ~]]*2")
|
||||
.sound("gm_electric_guitar_muted"),
|
||||
sound("<bd rim>").bank("RolandTR707")
|
||||
).delay(".5")`}
|
||||
tune={`$: note("[~ [<[d3,a3,f4]!2 [d3,bb3,g4]!2> ~]]*2")
|
||||
.sound("gm_electric_guitar_muted").delay(.5)
|
||||
|
||||
$: sound("bd rim").bank("RolandTR707").delay(".5")`}
|
||||
/>
|
||||
|
||||
<Box>
|
||||
|
|
@ -168,7 +156,7 @@ What happens if you use `.delay(".8:.06:.8")` ? Can you guess what the third num
|
|||
|
||||
</Box>
|
||||
|
||||
<QA q="Lösung anzeigen" client:visible>
|
||||
<QA q="Click to see solution" client:visible>
|
||||
|
||||
`delay("a:b:c")`:
|
||||
|
||||
|
|
@ -199,31 +187,32 @@ Add a delay too!
|
|||
|
||||
<MiniRepl
|
||||
client:visible
|
||||
tune={`stack(
|
||||
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] ~>")
|
||||
.scale("D4:minor").sound("gm_accordion:2")
|
||||
.room(2).gain(.5)
|
||||
)`}
|
||||
tune={`$: 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] ~>")
|
||||
.scale("D4:minor").sound("gm_accordion:2")
|
||||
.room(2).gain(.5)`}
|
||||
/>
|
||||
|
||||
Let's add a bass to make this complete:
|
||||
|
||||
<MiniRepl
|
||||
client:visible
|
||||
tune={`stack(
|
||||
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] ~>")
|
||||
.scale("D4:minor").sound("gm_accordion:2")
|
||||
.room(2).gain(.4),
|
||||
n("[0 [~ 0] 4 [3 2] [0 ~] [0 ~] <0 2> ~]/2")
|
||||
.scale("D2:minor")
|
||||
.sound("sawtooth,triangle").lpf(800)
|
||||
)`}
|
||||
tune={`$: 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] ~>")
|
||||
.scale("D4:minor").sound("gm_accordion:2")
|
||||
.room(2).gain(.4)
|
||||
|
||||
$: n("[0 [~ 0] 4 [3 2] [0 ~] [0 ~] <0 2> ~]/2")
|
||||
.scale("D2:minor")
|
||||
.sound("sawtooth,triangle").lpf(800)`}
|
||||
/>
|
||||
|
||||
<Box>
|
||||
|
|
@ -237,7 +226,7 @@ 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")`}
|
||||
.pan("0 0.3 .6 1")`}
|
||||
/>
|
||||
|
||||
**speed**
|
||||
|
|
@ -262,11 +251,11 @@ By the way, inside Mini-Notation, `fast` is `*` and `slow` is `/`.
|
|||
|
||||
<MiniRepl client:visible tune={`sound("[bd*4,~ rim ~ cp]*<1 [2 4]>")`} />
|
||||
|
||||
## automation with signals
|
||||
## modulation with signals
|
||||
|
||||
Instead of changing values stepwise, we can also control them with signals:
|
||||
|
||||
<MiniRepl client:visible tune={`sound("hh*32").gain(sine)`} punchcard punchcardLabels={false} />
|
||||
<MiniRepl client:visible tune={`sound("hh*16").gain(sine)`} punchcard punchcardLabels={false} />
|
||||
|
||||
<Box>
|
||||
|
||||
|
|
@ -290,32 +279,33 @@ What happens if you flip the range values?
|
|||
|
||||
</Box>
|
||||
|
||||
We can change the automation speed with slow / fast:
|
||||
We can change the modulation speed with slow / fast:
|
||||
|
||||
<MiniRepl
|
||||
client:visible
|
||||
tune={`note("<[c2 c3]*4 [bb1 bb2]*4 [f2 f3]*4 [eb2 eb3]*4>")
|
||||
.sound("sawtooth")
|
||||
.lpf(sine.range(100, 2000).slow(4))`}
|
||||
.sound("sawtooth")
|
||||
.lpf(sine.range(100, 2000).slow(4))`}
|
||||
/>
|
||||
|
||||
<Box>
|
||||
|
||||
The whole automation will now take 8 cycles to repeat.
|
||||
The whole modulation will now take 8 cycles to repeat.
|
||||
|
||||
</Box>
|
||||
|
||||
## Recap
|
||||
|
||||
| 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))`} /> |
|
||||
| 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>")`} /> |
|
||||
| signals | `sine`, `saw`, `square`, `tri`, `rand`, `perlin`<br/><MiniRepl client:visible tune={`s("hh*16").gain (saw)`} /> |
|
||||
| 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).
|
||||
|
|
|
|||
|
|
@ -314,11 +314,11 @@ Let's recap what we've learned in this chapter:
|
|||
|
||||
New functions:
|
||||
|
||||
| Name | Description | Example |
|
||||
| ----- | ----------------------------------- | --------------------------------------------------------------------------------- |
|
||||
| note | set pitch as number or letter | <MiniRepl client:visible tune={`note("b g e c").sound("piano")`} /> |
|
||||
| scale | interpret `n` as scale degree | <MiniRepl client:visible tune={`n("6 4 2 0").scale("C:minor").sound("piano")`} /> |
|
||||
| stack | play patterns in parallel (read on) | <MiniRepl client:visible tune={`stack(s("bd sd"),note("c eb g"))`} /> |
|
||||
| Name | Description | Example |
|
||||
| ----- | ----------------------------- | --------------------------------------------------------------------------------- |
|
||||
| note | set pitch as number or letter | <MiniRepl client:visible tune={`note("b g e c").sound("piano")`} /> |
|
||||
| scale | interpret `n` as scale degree | <MiniRepl client:visible tune={`n("6 4 2 0").scale("C:minor").sound("piano")`} /> |
|
||||
| $: | play patterns in parallel | <MiniRepl client:visible tune={'$: s("bd sd")\n$: note("c eb g")'} /> |
|
||||
|
||||
## Examples
|
||||
|
||||
|
|
@ -356,25 +356,35 @@ New functions:
|
|||
|
||||
<Box>
|
||||
|
||||
It's called `stack` 😙
|
||||
You can use `$:` 😙
|
||||
|
||||
</Box>
|
||||
|
||||
## Playing multiple patterns
|
||||
|
||||
If you want to play multiple patterns at the same time, make sure to write `$:` before each:
|
||||
|
||||
<MiniRepl
|
||||
client:visible
|
||||
tune={`stack(
|
||||
note("<[c2 c3]*4 [bb1 bb2]*4 [f2 f3]*4 [eb2 eb3]*4>")
|
||||
.sound("gm_synth_bass_1").lpf(800),
|
||||
n(\`<
|
||||
tune={`$: 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]
|
||||
>*4\`).scale("C4:minor")
|
||||
.sound("gm_synth_strings_1"),
|
||||
sound("bd*4, [~ <sd cp>]*2, [~ hh]*4")
|
||||
.bank("RolandTR909")
|
||||
)`}
|
||||
.sound("gm_synth_strings_1")
|
||||
|
||||
$: sound("bd*4, [~ <sd cp>]*2, [~ hh]*4")
|
||||
.bank("RolandTR909")`}
|
||||
/>
|
||||
|
||||
<Box>
|
||||
|
||||
Try changing `$` to `_$` to mute a part!
|
||||
|
||||
</Box>
|
||||
|
||||
This is starting to sound like actual music! We have sounds, we have notes, now the last piece of the puzzle is missing: [effects](/workshop/first-effects)
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ These letter combinations stand for different parts of a drum set:
|
|||
- `mt` = **m**iddle tom
|
||||
- `ht` = **h**igh tom
|
||||
- `rd` = **r**i**d**e cymbal
|
||||
- `rd` = **cr**ash cymbal
|
||||
- `cr` = **cr**ash cymbal
|
||||
|
||||
Try out different drum sounds!
|
||||
|
||||
|
|
@ -268,13 +268,14 @@ This is shorter and more readable than:
|
|||
## Recap
|
||||
|
||||
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:
|
||||
This is what we've learned 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 | - or ~ | <MiniRepl client:visible tune={`sound("metal - jazz jazz:1")`} /> |
|
||||
| Alternate | \<\> | <MiniRepl client:visible tune={`sound("<bd hh rim oh bd rim>")`} /> |
|
||||
| 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")`} /> |
|
||||
|
|
|
|||
|
|
@ -25,20 +25,16 @@ This is the same as:
|
|||
|
||||
<MiniRepl
|
||||
client:visible
|
||||
tune={`stack(
|
||||
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()
|
||||
)`}
|
||||
tune={`$: 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()`}
|
||||
/>
|
||||
|
||||
Let's visualize what happens here:
|
||||
|
||||
<MiniRepl
|
||||
client:visible
|
||||
tune={`stack(
|
||||
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()
|
||||
)`}
|
||||
tune={`$: 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
|
||||
/>
|
||||
|
||||
|
|
@ -56,11 +52,9 @@ This is like doing
|
|||
|
||||
<MiniRepl
|
||||
client:visible
|
||||
tune={`stack(
|
||||
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')
|
||||
)`}
|
||||
tune={`$: 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
|
||||
/>
|
||||
|
||||
|
|
@ -110,17 +104,15 @@ We can add as often as we like:
|
|||
|
||||
<MiniRepl
|
||||
client:visible
|
||||
tune={`stack(
|
||||
n("0 [2 4] <3 5> [~ <4 1>]".add("<0 [0,2,4]>"))
|
||||
tune={`$: n("0 [2 4] <3 5> [~ <4 1>]".add("<0 [0,2,4]>"))
|
||||
.scale("C5:minor")
|
||||
.sound("gm_xylophone")
|
||||
.room(.4).delay(.125),
|
||||
note("c2 [eb3,g3]".add("<0 <1 -1>>"))
|
||||
.room(.4).delay(.125)
|
||||
$: note("c2 [eb3,g3]".add("<0 <1 -1>>"))
|
||||
.adsr("[.1 0]:.2:[1 0]")
|
||||
.sound("gm_acoustic_bass")
|
||||
.room(.5),
|
||||
n("0 1 [2 3] 2").sound("jazz").jux(rev)
|
||||
)`}
|
||||
.room(.5)
|
||||
$: n("0 1 [2 3] 2").sound("jazz").jux(rev)`}
|
||||
/>
|
||||
|
||||
**ply**
|
||||
|
|
@ -145,22 +137,27 @@ Try patterning the `ply` function, for example using `"<1 2 1 3>"`
|
|||
.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)`}
|
||||
.s("triangle").room(.5).dec(.1)`}
|
||||
punchcard
|
||||
/>
|
||||
|
||||
<Box>
|
||||
|
||||
In the notation `x=>x.`, the `x` is the shifted pattern, which where modifying.
|
||||
In the notation `.off(1/16, x=>x.add(4))`, says:
|
||||
|
||||
- take the original pattern named as `x`
|
||||
- modify `x` with `.add(4)`, and
|
||||
- play it offset to the original pattern by `1/16` of a cycle.
|
||||
|
||||
</Box>
|
||||
|
||||
off is also useful for sounds:
|
||||
off is also useful for modifying other sounds, and can even be nested:
|
||||
|
||||
<MiniRepl
|
||||
client:visible
|
||||
tune={`s("bd sd [rim bd] sd,[~ hh]*4").bank("CasioRZ1")
|
||||
.off(1/16, x=>x.speed(1.5).gain(.25))`}
|
||||
.off(2/16, x=>x.speed(1.5).gain(.25)
|
||||
.off(3/16, y=>y.vowel("<a e i o>*8")))`}
|
||||
/>
|
||||
|
||||
| name | description | example |
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ This page is just a listing of all functions covered in the workshop!
|
|||
| --------- | ----------------------------- | --------------------------------------------------------------------------------- |
|
||||
| note | set pitch as number or letter | <MiniRepl client:visible tune={`note("b g e c").sound("piano")`} /> |
|
||||
| n + scale | set note in scale | <MiniRepl client:visible tune={`n("6 4 2 0").scale("C:minor").sound("piano")`} /> |
|
||||
| stack | play patterns in parallel | <MiniRepl client:visible tune={`stack(s("bd sd"),note("c eb g"))`} /> |
|
||||
| $: | play patterns in parallel | <MiniRepl client:visible tune={'$: s("bd sd")\n$: note("c eb g")'} /> |
|
||||
|
||||
## Audio Effects
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue