Just another flat file livecoding environment.
Jaffle is a yaml-based syntax for Tidal-cycles, based on Strudel.
It is used to write tunes in yaml instead of JavaScript or Haskel, resulting in a lighter syntax. Its purpose is to make algorithmic music more accessible for people who are not familiar with programming languages.
Under the hood, Jaffle is a transpiler generating JavaScript code, which is then interpreted by Strudel.
This chapter aims to provide an overview of the Jaffle syntax, for people already familiar with Strudel. If necessary, read the Strudel documentation.
Yaml comments starts with a #:
| Strudel | Jaffle |
// I'm a comment |
# I'm a comment |
Most of the time, quotes are optional (although many yaml syntax highlighters sucks are render them correctly):
| Strudel | Jaffle |
note("c@3 eb") |
Note: c@3 eb |
But be careful, some mini-notations could me misinterpreted by the yaml parser, for instance when starting the notation with [ (used to define arrays):
Sound: hh*8
gain: [.25 1]*2 # not workingTo address this, you can use simple or double quotes, or prepend the mini-notation with the / character, which is ignored:
- S: '~ sd ~'
- S: "tb*2 cb*2 ~"
- S: /bd ~ hh*2The chained functions are on the same indentation level:
| Strudel | Jaffle |
note("c@3 eb")
.lpf(600)
.delay(.5)
.gain(2) |
Note: c@3 eb
lpf: 600
delay: .5
gain: 2 |
Also, because dictionnaries are not ordered, the first instruction is capitalized (here Note instead note).
It's totally safe to have a yaml attribute without value (just don't forget the :):
| Strudel | Jaffle |
note("c@3 eb")
.piano()
.log() |
Note: c@3 eb
piano:
log: |
Use yaml arrays:
| Strudel | Jaffle |
stack(
s("oh*2 cb*2 ~"),
s("bd sd hh*2")
) |
Stack:
- S: oh*2 cb*2 ~
- S: bd sd hh*2 |
You could eventually use an inline array:
Stack: [ S: oh*2 cb*2 ~, S: bd sd hh*2 ]If the root node is an array, the surrounding function is Stack by default. The code above can also be written like this:
- S: oh*2 cb*2 ~
- S: bd sd hh*2When applying functions directly to a mini-notation, the M keyword must be used:
| Strudel | Jaffle |
"c3 [eb3,g3]"
.note() |
M: c3 [eb3,g3]
note: |
While Strudel distinguish mini-notations and strings by using simple or double quotes, Jaffle analyses strings as mini-notations by default. You must prepend them by the : sign to avoid this behavior.
| Strudel | Jaffle |
n("1 2 3")
.scale('C minor') |
N: 1 2 3
scale: :C minor |
To pass a dictionnary as a function parameter, you must append the ^ sign to the attribute name.
| Strudel | Jaffle |
s("sd oh*2 hh")
.pianoroll({ fold: 1 }) |
S: sd oh*2 hh
pianoroll^: { fold: 1 } |
You may want to pass a dictionnary on a specific argument, by adding its index next to ^, starting from 1.
| Strudel | Jaffle |
samples({
bd: '...',
sd: '...',
hh: '...' }
, '...') |
samples^1:
- bd: ...
sd: ...
hh: ...
- ... |
Note: the sample example above does not work as is, see below.
Some functions like samples are not part of the main music structure like Stack or Cat. You must prepend their name with the . sign:
| Strudel |
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") |
| Jaffle |
.samples^1:
- 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 |
Not the both use of the prefix . and the suffix ^1 to serialize the first parameter.
You can add an extra . to await functions:
| Strudel | Jaffle |
await samples({
bd: '...',
sd: '...',
hh: '...' }
, '...') |
..samples^1:
- bd: ...
sd: ...
hh: ...
- ... |
Signals are written like they was functions:
| Strudel | Jaffle |
saw
.range(50, 80)
.segment(24)
.note() |
Saw:
range: [50, 80]
segment: 24
note: |
Note the clever use of the inline array in the range function to avoid line returns.
If you want to put an expression in a parameter, prepend it by the = sign:
| Strudel | Jaffle |
"c3 [eb3,g3]"
.add(1/3)
.note() |
M: c3 [eb3,g3]
add: =1/3
note: |
Such expressions are limited to simple mathematics (+, =, *, /).
Use the Set keyword to pass a function as parameter, such as in accumulation modifiers (here with an inline dictionnary):
| Strudel | Jaffle |
note("c3 eb3 g3 a3")
.sometimes(x=>x.gain(8)) |
Note: c3 eb3 g3 a3
sometimes: { Set: , gain: 8 } |
If necessary, the number of additional parameters must be passed to the Set value:
| Strudel |
"<0 [2 4]>"
.echoWith(4, 1/8, (p,n) => p.add(n*2))
.scale('C minor')
.note() |
| Jaffle |
M: <0 [2 4]>
echoWith: [ 4, =1/8, { Set: 1, add: =a*2 } ]
scale: C minor
note: |
Such parameters are named a, then b, then c.
See the contribution guide!
- credits: Nathanaël Jourdane and contributors
- license: AGPL-3.0
- source: https://framagit.org/roipoussiere/jaffle
- credits: Strudel contributors
- license: AGPL-3.0
- source: https://github.com/tidalcycles/strudel
- piano:
- credits: Alexander Holm
- license: CC-by
- source: https://archive.org/details/SalamanderGrandPianoV3
- VCSL:
- credits: Versilian Studios LLC
- license: CC0
- source: https://github.com/sgossner/VCSL
- Tidal drum machines:
- EmuSP12: