215 lines
5.4 KiB
Markdown
215 lines
5.4 KiB
Markdown
# Oddities
|
|
|
|
Cagire's Forth is not a classic Forth. It borrows the core ideas (stack-based evaluation, postfix notation, word definitions) but adds modern features and domain-specific extensions. If you know traditional Forth, here are the differences.
|
|
|
|
## Comments
|
|
|
|
Classic Forth uses parentheses for comments:
|
|
|
|
```forth
|
|
( this is a comment )
|
|
```
|
|
|
|
Cagire uses double semicolons:
|
|
|
|
```forth
|
|
;; this is a comment
|
|
```
|
|
|
|
Everything after `;;` until the end of the line is ignored.
|
|
|
|
## Quotations
|
|
|
|
Classic Forth has no quotations. Code is not a value you can pass around.
|
|
|
|
Cagire has first-class quotations using curly braces:
|
|
|
|
```forth
|
|
{ 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.
|
|
|
|
## Conditionals
|
|
|
|
Classic Forth uses `IF ... ELSE ... THEN`:
|
|
|
|
```forth
|
|
x 0 > IF 1 ELSE -1 THEN
|
|
```
|
|
|
|
Cagire supports this syntax but also provides quotation-based conditionals:
|
|
|
|
```forth
|
|
{ 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
|
|
```
|
|
|
|
## Strings
|
|
|
|
Classic Forth has limited string support. You print strings with `."`:
|
|
|
|
```forth
|
|
." Hello World"
|
|
```
|
|
|
|
Cagire has first-class strings:
|
|
|
|
```forth
|
|
"hello"
|
|
```
|
|
|
|
This pushes a string value onto the stack. Strings are used for sound names, sample names, and variable keys. You often do not need quotes at all. Any unrecognized word becomes a string automatically:
|
|
|
|
```forth
|
|
kick s . ;; "kick" is not a word, so it becomes the string "kick"
|
|
myweirdname ;; pushes "myweirdname" onto the stack
|
|
```
|
|
|
|
This makes scripts cleaner. You only need quotes when the string contains spaces or conflicts with a real word.
|
|
|
|
## Variables
|
|
|
|
Classic Forth declares variables explicitly:
|
|
|
|
```forth
|
|
VARIABLE x
|
|
10 x !
|
|
x @
|
|
```
|
|
|
|
Cagire uses prefix syntax:
|
|
|
|
```forth
|
|
10 !x ;; store 10 in x
|
|
@x ;; fetch x (returns 0 if undefined)
|
|
```
|
|
|
|
No declaration needed. Variables spring into existence when you store to them.
|
|
|
|
## Floating Point
|
|
|
|
Classic Forth (in its original form) has no floating point. Numbers are integers. Floating point was added later as an optional extension with separate words. Cagire has native floating point:
|
|
|
|
```forth
|
|
3.14159
|
|
0.5 0.3 + ;; 0.8
|
|
```
|
|
|
|
Integers and floats mix freely. Division always produces a float.
|
|
|
|
## Loops
|
|
|
|
Classic Forth has `DO ... LOOP`:
|
|
|
|
```forth
|
|
10 0 DO I . LOOP
|
|
```
|
|
|
|
Cagire uses a quotation-based loop with `times`:
|
|
|
|
```forth
|
|
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
|
|
```
|
|
|
|
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)
|
|
```
|
|
|
|
## The Command Register
|
|
|
|
This is completely unique to Cagire. Traditional Forth programs print text. Cagire programs build sound commands.
|
|
|
|
The command register accumulates a sound name and parameters:
|
|
|
|
```forth
|
|
"sine" sound ;; set sound
|
|
440 freq ;; add parameter
|
|
0.5 gain ;; add parameter
|
|
. ;; emit and clear
|
|
```
|
|
|
|
Nothing is sent to the audio engine until you emit with `.`. This is unlike any classic Forth.
|
|
|
|
## Context Words
|
|
|
|
Cagire provides words that read the current sequencer state:
|
|
|
|
```forth
|
|
step ;; current step index (0-127)
|
|
beat ;; current beat position
|
|
iter ;; pattern iteration count
|
|
tempo ;; current BPM
|
|
phase ;; position in bar (0-1)
|
|
```
|
|
|
|
These have no equivalent in classic Forth. They connect your script to the sequencer's timeline.
|
|
|
|
## Probability
|
|
|
|
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
|
|
```
|
|
|
|
These words take a quotation and execute it probabilistically.
|
|
|
|
## Cycling
|
|
|
|
Cagire has built-in support for cycling through values. Push values onto the stack, then select one based on pattern state:
|
|
|
|
```forth
|
|
60 64 67 3 cycle note
|
|
```
|
|
|
|
Each time the step runs, a different note is selected. The `3` tells `cycle` how many values to pick from.
|
|
|
|
You can also use quotations if you need to execute code:
|
|
|
|
```forth
|
|
{ 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.
|
|
|
|
Three cycling words exist:
|
|
|
|
- `cycle` - selects based on `runs` (how many times this step has played)
|
|
- `pcycle` - selects based on `iter` (how many times the pattern has looped)
|
|
- `tcycle` - creates a cycle list that resolves at emit time
|
|
|
|
The difference between `cycle` and `pcycle` matters when patterns have different lengths. `cycle` counts per-step, `pcycle` counts per-pattern.
|
|
|
|
`tcycle` is special. It does not select immediately. Instead it creates a value that cycles when emitted:
|
|
|
|
```forth
|
|
0.3 0.5 0.7 3 tcycle gain
|
|
```
|
|
|
|
If you emit multiple times in one step (using `at`), each emit gets the next value from the cycle.
|
|
|
|
## Summary
|
|
|
|
Cagire's Forth is a domain-specific language for music. It keeps Forth's elegance (stack, postfix, definitions) but adapts it for live coding.
|