[BREAKING] Feat: quotation is now using ()
This commit is contained in:
@@ -54,7 +54,7 @@ Four basic types of values can live on the stack:
|
||||
- **Integers**: `42`, `-7`, `0`
|
||||
- **Floats**: `0.5`, `3.14`, `-1.0`
|
||||
- **Strings**: `"kick"`, `"hello"`
|
||||
- **Quotations**: `{ dup + }` (code as data)
|
||||
- **Quotations**: `( dup + )` (code as data)
|
||||
|
||||
Floats can omit the leading zero: `.25` is the same as `0.25`, and `-.5` is `-0.5`.
|
||||
|
||||
|
||||
@@ -29,22 +29,22 @@ These are compiled directly into branch instructions. For that reason, these wor
|
||||
When you already have a quotation, `?` executes it if the condition is truthy:
|
||||
|
||||
```forth
|
||||
{ 0.4 verb } coin ?
|
||||
( 0.4 verb ) coin ?
|
||||
saw s c4 note 0.5 gain . ;; reverb on half the hits
|
||||
```
|
||||
|
||||
`!?` is the opposite — executes when falsy:
|
||||
|
||||
```forth
|
||||
{ 0.2 gain } coin !?
|
||||
( 0.2 gain ) coin !?
|
||||
saw s c4 note . ;; quiet on half the hits
|
||||
```
|
||||
|
||||
These pair well with `chance`, `prob`, and the other probability words:
|
||||
|
||||
```forth
|
||||
{ 0.5 verb } 0.3 chance ? ;; occasional reverb wash
|
||||
{ 12 + } fill ? ;; octave up during fills
|
||||
( 0.5 verb ) 0.3 chance ? ;; occasional reverb wash
|
||||
( 12 + ) fill ? ;; octave up during fills
|
||||
```
|
||||
|
||||
## ifelse
|
||||
@@ -52,14 +52,14 @@ These pair well with `chance`, `prob`, and the other probability words:
|
||||
Two quotations, one condition. The true branch comes first:
|
||||
|
||||
```forth
|
||||
{ c3 note } { c4 note } coin ifelse
|
||||
( c3 note ) ( c4 note ) coin ifelse
|
||||
saw s 0.6 gain . ;; bass or lead, coin flip
|
||||
```
|
||||
|
||||
Reads naturally: "c3 or c4, depending on the coin."
|
||||
|
||||
```forth
|
||||
{ 0.8 gain } { 0.3 gain } fill ifelse
|
||||
( 0.8 gain ) ( 0.3 gain ) fill ifelse
|
||||
tri s c4 note 0.2 decay . ;; loud during fills, quiet otherwise
|
||||
```
|
||||
|
||||
@@ -68,7 +68,7 @@ tri s c4 note 0.2 decay . ;; loud during fills, quiet otherwise
|
||||
Choose the nth option from a list of quotations:
|
||||
|
||||
```forth
|
||||
{ c4 } { e4 } { g4 } { b4 } iter 4 mod select
|
||||
( c4 ) ( e4 ) ( g4 ) ( b4 ) iter 4 mod select
|
||||
note sine s 0.5 decay .
|
||||
```
|
||||
|
||||
@@ -79,7 +79,7 @@ Four notes cycling through a major seventh chord, one per pattern iteration. The
|
||||
When you have a quotation and want to execute it unconditionally, use `apply`:
|
||||
|
||||
```forth
|
||||
{ dup + } apply ;; doubles the top value
|
||||
( dup + ) apply ;; doubles the top value
|
||||
```
|
||||
|
||||
This is simpler than `?` when there is no condition to check. It pops the quotation and runs it.
|
||||
@@ -115,14 +115,14 @@ saw s c4 note .
|
||||
Repeat a quotation n times. The variable `@i` is automatically set to the current iteration index (starting from 0):
|
||||
|
||||
```forth
|
||||
3 { c4 @i 4 * + note } times
|
||||
3 ( c4 @i 4 * + note ) times
|
||||
sine s 0.4 gain 0.5 verb . ;; c4, e4, g#4 — a chord
|
||||
```
|
||||
|
||||
Subdivide with `at`:
|
||||
|
||||
```forth
|
||||
4 { @i 4 / at sine s c4 note 0.3 gain . } times
|
||||
4 ( @i 4 / at sine s c4 note 0.3 gain . ) times
|
||||
```
|
||||
|
||||
Four evenly spaced notes within the step.
|
||||
@@ -130,11 +130,11 @@ Four evenly spaced notes within the step.
|
||||
Vary intensity per iteration:
|
||||
|
||||
```forth
|
||||
8 {
|
||||
8 (
|
||||
@i 8 / at
|
||||
@i 4 mod 0 = if 0.7 else 0.2 then gain
|
||||
tri s c5 note 0.1 decay .
|
||||
} times
|
||||
) times
|
||||
```
|
||||
|
||||
Eight notes per step. Every fourth one louder.
|
||||
|
||||
@@ -22,10 +22,10 @@ Everything after `;;` until the end of the line is ignored.
|
||||
|
||||
Classic Forth has no quotations. Code is not a value you can pass around.
|
||||
|
||||
Cagire has first-class quotations using curly braces:
|
||||
Cagire has first-class quotations using parentheses:
|
||||
|
||||
```forth
|
||||
{ dup + }
|
||||
( dup + )
|
||||
```
|
||||
|
||||
This pushes a block of code onto the stack. You can store it, pass it to other words, and execute it later. Quotations enable conditionals, probability, and cycling.
|
||||
@@ -41,14 +41,14 @@ x 0 > IF 1 ELSE -1 THEN
|
||||
Cagire supports this syntax but also provides quotation-based conditionals:
|
||||
|
||||
```forth
|
||||
{ 1 } { -1 } x 0 > ifelse
|
||||
( 1 ) ( -1 ) x 0 > ifelse
|
||||
```
|
||||
|
||||
The words `?` and `!?` execute a quotation based on a condition:
|
||||
|
||||
```forth
|
||||
{ "kick" s . } coin ? ;; execute if coin is 1
|
||||
{ "snare" s . } coin !? ;; execute if coin is 0
|
||||
( "kick" s . ) coin ? ;; execute if coin is 1
|
||||
( "snare" s . ) coin !? ;; execute if coin is 0
|
||||
```
|
||||
|
||||
## Strings
|
||||
@@ -116,21 +116,21 @@ Classic Forth has `DO ... LOOP`:
|
||||
Cagire uses a quotation-based loop with `times`:
|
||||
|
||||
```forth
|
||||
4 { @i . } times ;; prints 0 1 2 3
|
||||
4 ( @i . ) times ;; prints 0 1 2 3
|
||||
```
|
||||
|
||||
The loop counter is stored in the variable `i`, accessed with `@i`. This fits Cagire's style where control flow uses quotations.
|
||||
|
||||
```forth
|
||||
4 { @i 4 / at hat s . } times ;; hat at 0, 0.25, 0.5, 0.75
|
||||
4 { c4 @i + note sine s . } times ;; ascending notes
|
||||
4 ( @i 4 / at hat s . ) times ;; hat at 0, 0.25, 0.5, 0.75
|
||||
4 ( c4 @i + note sine s . ) times ;; ascending notes
|
||||
```
|
||||
|
||||
For generating sequences without side effects, use `..` or `gen`:
|
||||
|
||||
```forth
|
||||
1 5 .. ;; pushes 1 2 3 4 5
|
||||
{ dup * } 4 gen ;; pushes 0 1 4 9 (squares)
|
||||
( dup * ) 4 gen ;; pushes 0 1 4 9 (squares)
|
||||
```
|
||||
|
||||
## The Command Register
|
||||
@@ -167,11 +167,11 @@ These have no equivalent in classic Forth. They connect your script to the seque
|
||||
Classic Forth is deterministic. Cagire has built-in randomness:
|
||||
|
||||
```forth
|
||||
{ "snare" s . } 50 prob ;; 50% chance
|
||||
{ "clap" s . } 0.25 chance ;; 25% chance
|
||||
{ "hat" s . } often ;; 75% chance
|
||||
{ "rim" s . } sometimes ;; 50% chance
|
||||
{ "tom" s . } rarely ;; 25% chance
|
||||
( "snare" s . ) 50 prob ;; 50% chance
|
||||
( "clap" s . ) 0.25 chance ;; 25% chance
|
||||
( "hat" s . ) often ;; 75% chance
|
||||
( "rim" s . ) sometimes ;; 50% chance
|
||||
( "tom" s . ) rarely ;; 25% chance
|
||||
```
|
||||
|
||||
These words take a quotation and execute it probabilistically.
|
||||
@@ -181,9 +181,9 @@ These words take a quotation and execute it probabilistically.
|
||||
Execute a quotation on specific iterations:
|
||||
|
||||
```forth
|
||||
{ "snare" s . } 4 every ;; every 4th pattern iteration
|
||||
{ "hat" s . } 3 8 bjork ;; Euclidean: 3 hits across 8 step runs
|
||||
{ "hat" s . } 5 8 pbjork ;; Euclidean: 5 hits across 8 pattern iterations
|
||||
( "snare" s . ) 4 every ;; every 4th pattern iteration
|
||||
( "hat" s . ) 3 8 bjork ;; Euclidean: 3 hits across 8 step runs
|
||||
( "hat" s . ) 5 8 pbjork ;; Euclidean: 5 hits across 8 pattern iterations
|
||||
```
|
||||
|
||||
`every` checks the pattern iteration count. On iteration 0, 4, 8, 12... the quotation runs. On all other iterations it is skipped.
|
||||
@@ -203,7 +203,7 @@ Each time the step runs, a different note is selected. The `3` tells `cycle` how
|
||||
You can also use quotations if you need to execute code:
|
||||
|
||||
```forth
|
||||
{ c4 note } { e4 note } { g4 note } 3 cycle
|
||||
( c4 note ) ( e4 note ) ( g4 note ) 3 cycle
|
||||
```
|
||||
|
||||
When the selected value is a quotation, it gets executed. When it is a plain value, it gets pushed onto the stack.
|
||||
|
||||
@@ -75,7 +75,7 @@ Euclidean distribution via `euclid`:
|
||||
Random timing via `gen`:
|
||||
|
||||
```forth
|
||||
{ 0.0 1.0 rand } 4 gen at hat s . ;; 4 hats at random positions
|
||||
( 0.0 1.0 rand ) 4 gen at hat s . ;; 4 hats at random positions
|
||||
```
|
||||
|
||||
Geometric spacing via `geom..`:
|
||||
@@ -89,10 +89,10 @@ Geometric spacing via `geom..`:
|
||||
Wrap `at` expressions in quotations for conditional timing:
|
||||
|
||||
```forth
|
||||
{ 0 0.25 0.5 0.75 at } 2 every ;; 16th-note hats every other bar
|
||||
( 0 0.25 0.5 0.75 at ) 2 every ;; 16th-note hats every other bar
|
||||
hat s .
|
||||
|
||||
{ 0 0.5 at } 0.5 chance ;; 50% chance of double-hit
|
||||
( 0 0.5 at ) 0.5 chance ;; 50% chance of double-hit
|
||||
kick s .
|
||||
```
|
||||
|
||||
|
||||
@@ -40,15 +40,15 @@ That gives you 110, 220, 440, 880, 1760 (reversed), ready to feed into `freq`.
|
||||
`gen` executes a quotation n times and collects all results. The quotation must push exactly one value per call:
|
||||
|
||||
```forth
|
||||
{ 1 6 rand } 4 gen ;; 4 random values between 1 and 6
|
||||
{ coin } 8 gen ;; 8 random 0s and 1s
|
||||
( 1 6 rand ) 4 gen ;; 4 random values between 1 and 6
|
||||
( coin ) 8 gen ;; 8 random 0s and 1s
|
||||
```
|
||||
|
||||
Contrast with `times`, which executes for side effects and does not collect. `times` sets `@i` to the current index:
|
||||
|
||||
```forth
|
||||
4 { @i } times ;; 0 1 2 3 (pushes @i each iteration)
|
||||
4 { @i 60 + note sine s . } times ;; plays 4 notes, collects nothing
|
||||
4 ( @i ) times ;; 0 1 2 3 (pushes @i each iteration)
|
||||
4 ( @i 60 + note sine s . ) times ;; plays 4 notes, collects nothing
|
||||
```
|
||||
|
||||
The distinction: `gen` is for building data. `times` is for doing things.
|
||||
@@ -109,7 +109,7 @@ c4 e4 g4 b4 4 shuffle ;; random permutation each time
|
||||
Useful for computing averages or accumulating values:
|
||||
|
||||
```forth
|
||||
{ 1 6 rand } 4 gen 4 sum ;; sum of 4 dice rolls
|
||||
( 1 6 rand ) 4 gen 4 sum ;; sum of 4 dice rolls
|
||||
```
|
||||
|
||||
## Replication
|
||||
|
||||
@@ -263,7 +263,7 @@ c4 mtof freq sine s .
|
||||
A chord progression cycling every pattern iteration:
|
||||
|
||||
```forth
|
||||
{ c3 maj7 } { f3 maj7 } { g3 dom7 } { c3 maj7 } 4 pcycle
|
||||
( c3 maj7 ) ( f3 maj7 ) ( g3 dom7 ) ( c3 maj7 ) 4 pcycle
|
||||
note sine s .
|
||||
```
|
||||
|
||||
@@ -290,7 +290,7 @@ Chord voicings with random inversion:
|
||||
|
||||
```forth
|
||||
e3 min9
|
||||
{ } { 1 oct } 2 choose
|
||||
( ) ( 1 oct ) 2 choose
|
||||
note modal s .
|
||||
```
|
||||
|
||||
|
||||
@@ -31,8 +31,8 @@ These are useful for parameters where perception is logarithmic, like frequency
|
||||
The probability words take a quotation and execute it with some chance. `chance` takes a float from 0.0 to 1.0, `prob` takes a percentage from 0 to 100:
|
||||
|
||||
```forth
|
||||
{ hat s . } 0.25 chance ;; 25% chance
|
||||
{ hat s . } 75 prob ;; 75% chance
|
||||
( hat s . ) 0.25 chance ;; 25% chance
|
||||
( hat s . ) 75 prob ;; 75% chance
|
||||
```
|
||||
|
||||
Named probability words save you from remembering numbers:
|
||||
@@ -48,9 +48,9 @@ Named probability words save you from remembering numbers:
|
||||
| `never` | 0% |
|
||||
|
||||
```forth
|
||||
{ hat s . } often ;; 75%
|
||||
{ snare s . } sometimes ;; 50%
|
||||
{ clap s . } rarely ;; 25%
|
||||
( hat s . ) often ;; 75%
|
||||
( snare s . ) sometimes ;; 50%
|
||||
( clap s . ) rarely ;; 25%
|
||||
```
|
||||
|
||||
`always` and `never` are useful when you want to temporarily mute or unmute a voice without deleting code. Change `sometimes` to `never` to silence it, `always` to bring it back.
|
||||
@@ -58,8 +58,8 @@ Named probability words save you from remembering numbers:
|
||||
Use `?` and `!?` with `coin` for quick coin-flip decisions:
|
||||
|
||||
```forth
|
||||
{ hat s . } coin ? ;; execute if coin is 1
|
||||
{ rim s . } coin !? ;; execute if coin is 0
|
||||
( hat s . ) coin ? ;; execute if coin is 1
|
||||
( rim s . ) coin !? ;; execute if coin is 0
|
||||
```
|
||||
|
||||
## Selection
|
||||
@@ -74,7 +74,7 @@ kick snare hat 3 choose s . ;; random drum hit
|
||||
When a chosen item is a quotation, it gets executed:
|
||||
|
||||
```forth
|
||||
{ 0.1 decay } { 0.5 decay } { 0.9 decay } 3 choose
|
||||
( 0.1 decay ) ( 0.5 decay ) ( 0.9 decay ) 3 choose
|
||||
sine s .
|
||||
```
|
||||
|
||||
@@ -115,7 +115,7 @@ The difference matters when patterns have different lengths. `cycle` counts per-
|
||||
Quotations work here too:
|
||||
|
||||
```forth
|
||||
{ c4 note } { e4 note } { g4 note } 3 cycle
|
||||
( c4 note ) ( e4 note ) ( g4 note ) 3 cycle
|
||||
sine s .
|
||||
```
|
||||
|
||||
@@ -130,20 +130,20 @@ sine s .
|
||||
`every` runs a quotation once every n pattern iterations:
|
||||
|
||||
```forth
|
||||
{ crash s . } 4 every ;; crash cymbal every 4th iteration
|
||||
( crash s . ) 4 every ;; crash cymbal every 4th iteration
|
||||
```
|
||||
|
||||
`except` is the inverse -- it runs a quotation on all iterations *except* every nth:
|
||||
|
||||
```forth
|
||||
{ 2 distort } 4 except ;; distort on all iterations except every 4th
|
||||
( 2 distort ) 4 except ;; distort on all iterations except every 4th
|
||||
```
|
||||
|
||||
`bjork` and `pbjork` use Bjorklund's algorithm to distribute k hits across n positions as evenly as possible. Classic Euclidean rhythms:
|
||||
|
||||
```forth
|
||||
{ hat s . } 3 8 bjork ;; tresillo: x..x..x. (by step runs)
|
||||
{ hat s . } 5 8 pbjork ;; cinquillo: x.xx.xx. (by pattern iterations)
|
||||
( hat s . ) 3 8 bjork ;; tresillo: x..x..x. (by step runs)
|
||||
( hat s . ) 5 8 pbjork ;; cinquillo: x.xx.xx. (by pattern iterations)
|
||||
```
|
||||
|
||||
`bjork` counts by step runs (how many times this particular step has played). `pbjork` counts by pattern iterations. Some classic patterns:
|
||||
@@ -172,7 +172,7 @@ The real power comes from mixing techniques. A hi-hat pattern with ghost notes:
|
||||
|
||||
```forth
|
||||
hat s
|
||||
{ 0.3 0.6 rand gain } { 0.8 gain } 2 cycle
|
||||
( 0.3 0.6 rand gain ) ( 0.8 gain ) 2 cycle
|
||||
.
|
||||
```
|
||||
|
||||
@@ -181,18 +181,18 @@ Full volume on even runs, random quiet on odd runs.
|
||||
A bass line that changes every 4 bars:
|
||||
|
||||
```forth
|
||||
{ c2 note } { e2 note } { g2 note } { a2 note } 4 pcycle
|
||||
{ 0.5 decay } often
|
||||
( c2 note ) ( e2 note ) ( g2 note ) ( a2 note ) 4 pcycle
|
||||
( 0.5 decay ) often
|
||||
sine s .
|
||||
```
|
||||
|
||||
Layered percussion with different densities:
|
||||
|
||||
```forth
|
||||
{ kick s . } always
|
||||
{ snare s . } 2 every
|
||||
{ hat s . } 5 8 bjork
|
||||
{ rim s . } rarely
|
||||
( kick s . ) always
|
||||
( snare s . ) 2 every
|
||||
( hat s . ) 5 8 bjork
|
||||
( rim s . ) rarely
|
||||
```
|
||||
|
||||
A melodic step with weighted note selection and random timbre:
|
||||
|
||||
@@ -53,7 +53,7 @@ Reset on some condition:
|
||||
|
||||
```forth
|
||||
@n 1 + !n
|
||||
{ 0 !n } @n 16 > ? ;; reset after 16
|
||||
( 0 !n ) @n 16 > ? ;; reset after 16
|
||||
```
|
||||
|
||||
## When Changes Take Effect
|
||||
|
||||
Reference in New Issue
Block a user