Feat: UI / UX
This commit is contained in:
185
docs/control_flow.md
Normal file
185
docs/control_flow.md
Normal file
@@ -0,0 +1,185 @@
|
||||
# Control Flow
|
||||
|
||||
A drum pattern that plays the same sound on every step is not very interesting. You want kicks on the downbeats, snares on the backbeats, hats filling the gaps. Control flow is how you make decisions inside a step.
|
||||
|
||||
## if / else / then
|
||||
|
||||
The simplest branch. Push a condition, then `if`:
|
||||
|
||||
```forth
|
||||
step 4 mod 0 = if kick s . then
|
||||
```
|
||||
|
||||
Every fourth step gets a kick. The rest do nothing. Add `else` for a two-way split:
|
||||
|
||||
```forth
|
||||
step 2 mod 0 = if
|
||||
kick s 0.8 gain .
|
||||
else
|
||||
hat s 0.3 gain .
|
||||
then
|
||||
```
|
||||
|
||||
These are compiler syntax -- you won't find them in the dictionary. Think nothing of it.
|
||||
|
||||
## ? and !?
|
||||
|
||||
When you already have a quotation, `?` executes it if the condition is truthy:
|
||||
|
||||
```forth
|
||||
{ snare s . } coin ?
|
||||
```
|
||||
|
||||
`!?` is the opposite -- executes when falsy:
|
||||
|
||||
```forth
|
||||
{ hat s 0.2 gain . } coin !?
|
||||
```
|
||||
|
||||
These pair well with `chance`, `prob`, and the other probability words:
|
||||
|
||||
```forth
|
||||
{ rim s . } fill ? ;; rim only during fills
|
||||
{ 0.5 verb } 0.3 chance ? ;; occasional reverb wash
|
||||
```
|
||||
|
||||
## ifelse
|
||||
|
||||
Two quotations, one condition. The true branch comes first:
|
||||
|
||||
```forth
|
||||
{ kick s . } { hat s . } step 2 mod 0 = ifelse
|
||||
```
|
||||
|
||||
Reads naturally: "kick or hat, depending on whether it's an even step."
|
||||
|
||||
```forth
|
||||
{ c3 note } { c4 note } coin ifelse
|
||||
saw s 0.6 gain . ;; bass or lead, coin flip
|
||||
```
|
||||
|
||||
## pick
|
||||
|
||||
Choose the nth option from a list of quotations:
|
||||
|
||||
```forth
|
||||
{ kick s . } { snare s . } { hat s . } step 3 mod pick
|
||||
```
|
||||
|
||||
Step 0 plays kick, step 1 plays snare, step 2 plays hat. The index is 0-based.
|
||||
|
||||
```forth
|
||||
{ c4 } { e4 } { g4 } { b4 } step 4 mod pick
|
||||
note sine s 0.5 decay .
|
||||
```
|
||||
|
||||
Four notes cycling through a major seventh chord, one per step.
|
||||
|
||||
## case / of / endof / endcase
|
||||
|
||||
For matching a value against several options. Cleaner than a chain of `if`s when you have more than two branches:
|
||||
|
||||
```forth
|
||||
step 8 mod case
|
||||
0 of kick s . endof
|
||||
4 of snare s . endof
|
||||
endcase
|
||||
```
|
||||
|
||||
Steps 0 and 4 get sounds. Everything else falls through to `endcase` and nothing happens.
|
||||
|
||||
A fuller pattern:
|
||||
|
||||
```forth
|
||||
step 8 mod case
|
||||
0 of kick s 0.9 gain . endof
|
||||
2 of hat s 0.3 gain . endof
|
||||
4 of snare s 0.7 gain . endof
|
||||
6 of hat s 0.3 gain . endof
|
||||
hat s 0.15 gain .
|
||||
endcase
|
||||
```
|
||||
|
||||
The last line before `endcase` is the default -- it runs when no `of` matched. Here it gives unmatched steps a ghost hat.
|
||||
|
||||
The `of` value can be any expression:
|
||||
|
||||
```forth
|
||||
step 16 mod case
|
||||
0 of kick s . endof
|
||||
3 1 + of snare s . endof
|
||||
2 4 * of kick s . snare s . endof
|
||||
endcase
|
||||
```
|
||||
|
||||
## times
|
||||
|
||||
Repeat a quotation n times. `@i` holds the current iteration (starting from 0):
|
||||
|
||||
```forth
|
||||
4 { @i 4 / at hat s . } times ;; four hats, evenly spaced
|
||||
```
|
||||
|
||||
Build chords:
|
||||
|
||||
```forth
|
||||
3 { c4 @i 4 * + note } times
|
||||
sine s 0.4 gain 0.5 verb . ;; c4, e4, g#4
|
||||
```
|
||||
|
||||
Subdivide and accent:
|
||||
|
||||
```forth
|
||||
8 {
|
||||
@i 8 / at
|
||||
@i 4 mod 0 = if 0.7 else 0.2 then gain
|
||||
hat s .
|
||||
} times
|
||||
```
|
||||
|
||||
Eight hats per step. Every fourth one louder.
|
||||
|
||||
## Putting It Together
|
||||
|
||||
A basic drum pattern using `case`:
|
||||
|
||||
```forth
|
||||
step 8 mod case
|
||||
0 of kick s . endof
|
||||
2 of { hat s . } often endof
|
||||
4 of snare s . endof
|
||||
6 of { rim s . } sometimes endof
|
||||
{ hat s 0.15 gain . } coin ?
|
||||
endcase
|
||||
```
|
||||
|
||||
Kicks and snares on the strong beats. Hats and rims show up probabilistically. The default sprinkles ghost hats.
|
||||
|
||||
A melodic step that picks a scale degree and adds micro-timing:
|
||||
|
||||
```forth
|
||||
{ c4 } { d4 } { e4 } { g4 } { a4 } step 5 mod pick
|
||||
note
|
||||
|
||||
step 3 mod 0 = if
|
||||
0 0.33 0.66 at ;; triplet feel on every third step
|
||||
then
|
||||
|
||||
saw s 0.4 gain 0.3 decay 0.2 verb .
|
||||
```
|
||||
|
||||
A `times` loop paired with `case` for a drum machine in one step:
|
||||
|
||||
```forth
|
||||
4 {
|
||||
@i case
|
||||
0 of kick s . endof
|
||||
1 of hat s 0.3 gain . endof
|
||||
2 of snare s . endof
|
||||
3 of { rim s . } 0.5 chance endof
|
||||
endcase
|
||||
@i 4 / at
|
||||
} times
|
||||
```
|
||||
|
||||
Four voices, four sub-positions, one step.
|
||||
@@ -89,9 +89,10 @@ Cagire uses prefix syntax:
|
||||
```forth
|
||||
10 !x ;; store 10 in x
|
||||
@x ;; fetch x (returns 0 if undefined)
|
||||
10 ,x ;; store 10 in x, keep on stack
|
||||
```
|
||||
|
||||
No declaration needed. Variables spring into existence when you store to them.
|
||||
No declaration needed. Variables spring into existence when you store to them. `,x` stores and keeps the value on the stack.
|
||||
|
||||
## Floating Point
|
||||
|
||||
|
||||
71
docs/tutorial_variables.md
Normal file
71
docs/tutorial_variables.md
Normal file
@@ -0,0 +1,71 @@
|
||||
# Using Variables
|
||||
|
||||
Variables let you name values and share data between steps. They are global -- any step can read what another step wrote.
|
||||
|
||||
## Store and Fetch
|
||||
|
||||
`!name` stores the top of the stack into a variable. `@name` fetches it back. Variables spring into existence when you first store to them. Fetching a variable that was never stored returns 0.
|
||||
|
||||
```forth
|
||||
10 !x ;; store 10 in x
|
||||
@x ;; pushes 10
|
||||
@y ;; pushes 0 (never stored)
|
||||
```
|
||||
|
||||
## Store and Keep
|
||||
|
||||
`,name` stores just like `!name` but keeps the value on the stack. Useful when you want to name something and keep using it:
|
||||
|
||||
```forth
|
||||
440 ,freq sine s . ;; stores 440 in freq AND passes it to the pipeline
|
||||
```
|
||||
|
||||
Without `,`, you'd need `dup`:
|
||||
|
||||
```forth
|
||||
440 dup !freq sine s . ;; equivalent, but noisier
|
||||
```
|
||||
|
||||
## Sharing Between Steps
|
||||
|
||||
Variables are shared across all steps. One step can store a value that another reads:
|
||||
|
||||
```forth
|
||||
;; step 0: pick a root note
|
||||
c4 iter 7 mod + !root
|
||||
|
||||
;; step 4: read it
|
||||
@root 7 + note sine s .
|
||||
```
|
||||
|
||||
Every time the pattern loops, step 0 picks a new root. Step 4 always harmonizes with it.
|
||||
|
||||
## Accumulators
|
||||
|
||||
Fetch, modify, store back. A classic pattern for evolving values:
|
||||
|
||||
```forth
|
||||
@n 1 + !n ;; increment n each time this step runs
|
||||
@n 12 mod note sine s . ;; cycle through 12 notes
|
||||
```
|
||||
|
||||
Reset on some condition:
|
||||
|
||||
```forth
|
||||
@n 1 + !n
|
||||
{ 0 !n } @n 16 > ? ;; reset after 16
|
||||
```
|
||||
|
||||
## Naming Sounds
|
||||
|
||||
Store a sound name in a variable, reuse it across steps:
|
||||
|
||||
```forth
|
||||
;; step 0: choose the sound
|
||||
"sine" !synth
|
||||
|
||||
;; step 1, 2, 3...
|
||||
c4 note @synth s .
|
||||
```
|
||||
|
||||
Change one step, all steps follow.
|
||||
Reference in New Issue
Block a user