Work on documentation
This commit is contained in:
214
docs/oddities.md
Normal file
214
docs/oddities.md
Normal file
@@ -0,0 +1,214 @@
|
||||
# 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.
|
||||
Reference in New Issue
Block a user