mirror of
https://github.com/eliasstepanik/strudel-docker.git
synced 2026-01-11 13:48:34 +00:00
368 lines
12 KiB
Plaintext
368 lines
12 KiB
Plaintext
---
|
|
title: Samples
|
|
layout: ../../layouts/MainLayout.astro
|
|
---
|
|
|
|
import { MiniRepl } from '../../docs/MiniRepl';
|
|
import { JsDoc } from '../../docs/JsDoc';
|
|
|
|
# Samples
|
|
|
|
Samples are the most common way to make sound with tidal and strudel.
|
|
A sample is a (commonly short) piece of audio that is used as a basis for sound generation, undergoing various transformations.
|
|
Music that is based on samples can be thought of as a collage of sound. [Read more about Sampling](<https://en.wikipedia.org/wiki/Sampling_(music)>)
|
|
|
|
Strudel allows loading samples in the form of audio files of various formats (wav, mp3, ogg) from any publicly available URL.
|
|
|
|
# Default Samples
|
|
|
|
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")`} />
|
|
|
|
Here, we are using the `s` function to play back different default samples (`bd`, `sd`, `hh` and `misc`) to get a drum beat.
|
|
|
|
For drum sounds, strudel uses the comprehensive [tidal-drum-machines](https://github.com/ritchse/tidal-drum-machines) library, with the following naming convention:
|
|
|
|
| Drum | Abbreviation |
|
|
| ----------------------------------- | ------------ |
|
|
| Bass drum, Kick drum | bd |
|
|
| Snare drum | sd |
|
|
| Rimshot | rim |
|
|
| Clap | cp |
|
|
| Closed hi-hat | hh |
|
|
| Open hi-hat | oh |
|
|
| Crash | cr |
|
|
| Ride | rd |
|
|
| Shakers (and maracas, cabasas, etc) | sh |
|
|
| High tom | ht |
|
|
| Medium tom | mt |
|
|
| Low tom | lt |
|
|
| Cowbell | cb |
|
|
| Tambourine | tb |
|
|
| Other percussions | perc |
|
|
| Miscellaneous samples | misc |
|
|
| Effects | fx |
|
|
|
|
Furthermore, strudel also loads instrument samples from [VCSL](https://github.com/sgossner/VCSL) by default.
|
|
|
|
To see which sample names are available, open the `sounds` tab in the [REPL](https://strudel.cc/).
|
|
|
|
Note that only the sample maps (mapping names to URLs) are loaded initially, while the audio samples themselves are not loaded until they are actually played.
|
|
This behaviour of loading things only when they are needed is also called `lazy loading`.
|
|
While it saves resources, it can also lead to sounds not being audible the first time they are triggered, because the sound is still loading.
|
|
[This might be fixed in the future](https://github.com/tidalcycles/strudel/issues/187)
|
|
|
|
# Sound Banks
|
|
|
|
If we open the `sounds` tab and then `drum machines`, we can see that the drum samples are all prefixed with drum machine names: `RolandTR808_bd`, `RolandTR808_sd`, `RolandTR808_hh` etc..
|
|
|
|
We _could_ use them like this:
|
|
|
|
<MiniRepl client:idle tune={`s("RolandTR808_bd RolandTR808_sd,RolandTR808_hh*8")`} />
|
|
|
|
... 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")`} />
|
|
|
|
You could even pattern the bank to switch between different drum machines:
|
|
|
|
<MiniRepl client:idle tune={`s("bd sd,hh*8").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.
|
|
Also note that some banks won't have samples for all sounds!
|
|
|
|
# Selecting Sounds
|
|
|
|
If we open the `sounds` tab again, followed by tab `drum machines`, there is also a number behind each name, indicating how many individual samples are available.
|
|
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>")`} />
|
|
|
|
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>")`} />
|
|
|
|
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")`} />
|
|
|
|
# Loading Custom Samples
|
|
|
|
You can load your own sample map using the `samples` function.
|
|
In this example we create a map using sounds from the default sample map:
|
|
|
|
<MiniRepl
|
|
client:idle
|
|
tune={`samples({
|
|
bd: 'bd/BT0AADA.wav',
|
|
sd: 'sd/rytm-01-classic.wav',
|
|
hh: 'hh27/000_hh27closedhh.wav',
|
|
}, 'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/');
|
|
s("bd sd,hh*8")`}
|
|
/>
|
|
|
|
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.
|
|
Compare with this example which uses the same samples, but with different names.
|
|
|
|
<MiniRepl
|
|
client:idle
|
|
tune={`samples({
|
|
bassdrum: 'bd/BT0AADA.wav',
|
|
snaredrum: 'sd/rytm-01-classic.wav',
|
|
hihat: 'hh27/000_hh27closedhh.wav',
|
|
}, 'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/');
|
|
s("bassdrum snaredrum, hihat*8")`}
|
|
/>
|
|
|
|
Here we have changed the "map" to include longer sample names.
|
|
|
|
## The `samples` function
|
|
|
|
The `samples` function has two arguments:
|
|
|
|
- A [JavaScript object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object) that maps sound names to audio file paths.
|
|
- A base URL that comes before each path describing where the sample folder can be found online.
|
|
- Make sure your base URL ends with a slash, while your sample paths do **not** begin with one!
|
|
|
|
To see how this looks in practice, compare the [DirtSamples GitHub repo](https://github.com/tidalcycles/Dirt-Samples) with the previous sample map example.
|
|
|
|
Because GitHub is a popular place for uploading open source samples, it has its own shortcut:
|
|
|
|
<MiniRepl
|
|
client:idle
|
|
tune={`samples({
|
|
bd: 'bd/BT0AADA.wav',
|
|
sd: 'sd/rytm-01-classic.wav',
|
|
hh: 'hh27/000_hh27closedhh.wav',
|
|
}, 'github:tidalcycles/Dirt-Samples/master/');
|
|
s("bd sd,hh*8")`}
|
|
/>
|
|
|
|
The format is `github:user/repo/branch/`.
|
|
|
|
Let's see another example, this time based on the following GitHub repo: https://github.com/jarmitage/jarmitage.github.io.
|
|
We can see there are some guitar samples inside the `/samples` folder, so let's try to load them:
|
|
|
|
<MiniRepl
|
|
client:idle
|
|
tune={`samples({
|
|
g0: 'samples/guitar/guitar_0.wav',
|
|
g1: 'samples/guitar/guitar_1.wav',
|
|
g2: 'samples/guitar/guitar_2.wav',
|
|
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")`}
|
|
/>
|
|
|
|
## Multiple Samples per Sound
|
|
|
|
It is also possible, to declare multiple files for one sound, using the array notation:
|
|
|
|
<MiniRepl
|
|
client:idle
|
|
tune={`samples({
|
|
bd: ['bd/BT0AADA.wav','bd/BT0AAD0.wav'],
|
|
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")`}
|
|
/>
|
|
|
|
The `:0` `:1` etc. are the indices of the array.
|
|
The sample number can also be set using `n`:
|
|
|
|
<MiniRepl
|
|
client:idle
|
|
tune={`samples({
|
|
bd: ['bd/BT0AADA.wav','bd/BT0AAD0.wav'],
|
|
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>")`}
|
|
/>
|
|
|
|
In that case, we might load our guitar sample map a different way:
|
|
|
|
<MiniRepl
|
|
client:idle
|
|
tune={`samples({
|
|
guitar: [
|
|
'samples/guitar/guitar_0.wav',
|
|
'samples/guitar/guitar_1.wav',
|
|
'samples/guitar/guitar_2.wav',
|
|
'samples/guitar/guitar_3.wav',
|
|
'samples/guitar/guitar_4.wav'
|
|
]
|
|
}, 'github:jarmitage/jarmitage.github.io/master/');
|
|
s("[guitar:0 guitar:1 guitar:2 guitar:3 guitar:4]/5")`}
|
|
/>
|
|
|
|
And as above, we can choose the sample number using `n` for even more flexibility:
|
|
|
|
<MiniRepl
|
|
client:idle
|
|
tune={`samples({
|
|
guitar: [
|
|
'samples/guitar/guitar_0.wav',
|
|
'samples/guitar/guitar_1.wav',
|
|
'samples/guitar/guitar_2.wav',
|
|
'samples/guitar/guitar_3.wav',
|
|
'samples/guitar/guitar_4.wav'
|
|
]
|
|
}, 'github:jarmitage/jarmitage.github.io/master/');
|
|
n("<0 1 2 3 4>").s("guitar")`}
|
|
/>
|
|
|
|
## Pitched Sounds
|
|
|
|
For pitched sounds, you can use `note`, just like with synths:
|
|
|
|
<MiniRepl
|
|
client:idle
|
|
tune={`samples({
|
|
'gtr': 'gtr/0001_cleanC.wav',
|
|
}, 'github:tidalcycles/Dirt-Samples/master/');
|
|
note("g3 [bb3 c4] <g4 f4 eb4 f3>@2").s('gtr').gain(.5)`}
|
|
/>
|
|
|
|
Here, the guitar samples will overlap, because they always play till the end.
|
|
If we want them to behave more like a synth, we can add `clip(1)`:
|
|
|
|
<MiniRepl
|
|
client:idle
|
|
tune={`samples({
|
|
'gtr': 'gtr/0001_cleanC.wav',
|
|
}, 'github:tidalcycles/Dirt-Samples/master/');
|
|
note("g3 [bb3 c4] <g4 f4 eb4 f3>@2").s('gtr').clip(1)
|
|
.gain(.5)`}
|
|
/>
|
|
|
|
## Base Pitch
|
|
|
|
If we have 2 samples with different base pitches, we can make them in tune by specifying the pitch like this:
|
|
|
|
<MiniRepl
|
|
client:idle
|
|
tune={`samples({
|
|
'gtr': 'gtr/0001_cleanC.wav',
|
|
'moog': { 'g3': 'moog/005_Mighty%20Moog%20G3.wav' },
|
|
}, 'github:tidalcycles/Dirt-Samples/master/');
|
|
note("g3 [bb3 c4] <g4 f4 eb4 f3>@2").s("gtr,moog").clip(1)
|
|
.gain(.5)`}
|
|
/>
|
|
|
|
If a sample has no pitch set, `c3` is the default.
|
|
|
|
We can also declare different samples for different regions of the keyboard:
|
|
|
|
<MiniRepl
|
|
client:idle
|
|
tune={`samples({
|
|
'moog': {
|
|
'g2': 'moog/004_Mighty%20Moog%20G2.wav',
|
|
'g3': 'moog/005_Mighty%20Moog%20G3.wav',
|
|
'g4': 'moog/006_Mighty%20Moog%20G4.wav',
|
|
}}, 'github:tidalcycles/Dirt-Samples/master/');
|
|
note("g2!2 <bb2 c3>!2, <c4@3 [<eb4 bb3> g4 f4]>")
|
|
.s('moog').clip(1)
|
|
.gain(.5)`}
|
|
/>
|
|
|
|
The sampler will always pick the closest matching sample for the current note!
|
|
|
|
## Shabda
|
|
|
|
If you don't want to select samples by hand, there is also the wonderful tool called [shabda](https://shabda.ndre.gr/).
|
|
With it, you can enter any sample name(s) to query from [freesound.org](https://freesound.org/). Example:
|
|
|
|
<MiniRepl
|
|
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 2 3*2").s('hihat'),
|
|
n("~ 0 ~ 1").s('rimshot')
|
|
).clip(1)`}
|
|
/>
|
|
|
|
You can also generate artificial voice samples with any text, in multiple languages.
|
|
Note that the language code and the gender parameters are optional and default to `en-GB` and `f`
|
|
|
|
<MiniRepl
|
|
client:idle
|
|
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)
|
|
)`}
|
|
/>
|
|
|
|
# Sampler Effects
|
|
|
|
Sampler effects are functions that can be used to change the behaviour of sample playback.
|
|
|
|
### begin
|
|
|
|
<JsDoc client:idle name="Pattern.begin" h={0} />
|
|
|
|
### end
|
|
|
|
<JsDoc client:idle name="Pattern.end" h={0} />
|
|
|
|
### loop
|
|
|
|
<JsDoc client:idle name="loop" h={0} />
|
|
|
|
### loopBegin
|
|
|
|
<JsDoc client:idle name="loopBegin" h={0} />
|
|
|
|
### loopEnd
|
|
|
|
<JsDoc client:idle name="loopEnd" h={0} />
|
|
|
|
### cut
|
|
|
|
<JsDoc client:idle name="cut" h={0} />
|
|
|
|
### clip
|
|
|
|
<JsDoc client:idle name="clip" h={0} />
|
|
|
|
### loopAt
|
|
|
|
<JsDoc client:idle name="Pattern.loopAt" h={0} />
|
|
|
|
### fit
|
|
|
|
<JsDoc client:idle name="fit" h={0} />
|
|
|
|
### chop
|
|
|
|
<JsDoc client:idle name="Pattern.chop" h={0} />
|
|
|
|
### striate
|
|
|
|
<JsDoc client:idle name="Pattern.striate" h={0} />
|
|
|
|
### slice
|
|
|
|
<JsDoc client:idle name="Pattern.slice" h={0} />
|
|
|
|
### splice
|
|
|
|
<JsDoc client:idle name="splice" h={0} />
|
|
|
|
### speed
|
|
|
|
<JsDoc client:idle name="speed" h={0} />
|
|
|
|
After samples, let's see what [Synths](/learn/synths) afford us.
|