Fix: update docs about snd

This commit is contained in:
2026-03-06 08:40:41 +01:00
parent f273470eaf
commit d055d2bfc6
23 changed files with 228 additions and 200 deletions

View File

@@ -2,6 +2,34 @@
All notable changes to this project will be documented in this file.
## [0.1.2]
### Forth Language
- Single-letter envelope aliases: `a` (attack), `d` (decay), `s` (sustain), `r` (release).
- `sound` alias changed from `s` to `snd` (frees `s` for sustain).
- New `partials` word: set number of active harmonics for additive oscillator.
- Velocity parameter normalized to 01 float range (was 0127 integer).
### UI / UX
- **Sample Explorer as dedicated page**: the side panel is now a full page (Tab key), with keyboard navigation (j/k, search with `/`, preview with Enter), replacing the old collapsible side panel.
- **Pulsing armed-changes bar** on patterns page: staged play/stop/mute/solo changes shown in a launch bar with animated feedback ("c to launch").
- Pulsing highlight on banks and patterns with staged changes.
- Sample browser shows child count on collapsed folders and uses `+`/`-` tree icons.
- File browser modal: shows audio file counts per directory, colored path segments, and hint bar.
- Audio devices refreshed automatically when entering the Engine page.
- Bank prelude field added to data model (foundation for bank-level Forth scripts).
### Engine
- Audio timing switched from float seconds to integer tick-based scheduling, improving timing precision.
- Stream error handling refined: only `DeviceNotAvailable` and `StreamInvalidated` trigger device-lost recovery (non-fatal errors no longer restart the stream).
- Step traces use `Arc` for cheaper cloning between threads.
### Packaging
- **Windows: NSIS installer** replaces cargo-wix MSI. Includes optional PATH registration, Start Menu shortcut, and proper Add/Remove Programs entry with uninstaller.
- Improved Windows cross-compilation from Unix hosts (MinGW toolchain detection).
- CI build timeouts increased to 60 minutes across all platforms.
- Website download matrix updated.
## [0.1.1]
### Forth Language

View File

@@ -9,8 +9,8 @@ All time values are in **steps**, just like `attack`, `decay`, and `release`. At
Oscillate a parameter between two values.
```forth
saw s 200 4000 4 lfo lpf . ( sweep filter over 4 steps )
saw s 0.3 0.7 2 tlfo pan . ( triangle pan over 2 steps )
saw snd 200 4000 4 lfo lpf . ( sweep filter over 4 steps )
saw snd 0.3 0.7 2 tlfo pan . ( triangle pan over 2 steps )
```
| Word | Shape | Output |
@@ -27,8 +27,8 @@ Stack effect: `( min max period -- str )`
Transition from one value to another over a duration.
```forth
saw s 0 1 0.5 slide gain . ( fade in over half a step )
saw s 200 4000 8 sslide lpf . ( smooth sweep over 8 steps )
saw snd 0 1 0.5 slide gain . ( fade in over half a step )
saw snd 200 4000 8 sslide lpf . ( smooth sweep over 8 steps )
```
| Word | Curve | Output |
@@ -44,9 +44,9 @@ Stack effect: `( start end dur -- str )`
Randomize a parameter within a range, retriggering at a given period.
```forth
saw s 200 4000 2 jit lpf . ( new random value every 2 steps )
saw s 200 4000 2 sjit lpf . ( same but smoothly interpolated )
saw s 200 4000 1 drunk lpf . ( random walk, each step )
saw snd 200 4000 2 jit lpf . ( new random value every 2 steps )
saw snd 200 4000 2 sjit lpf . ( same but smoothly interpolated )
saw snd 200 4000 1 drunk lpf . ( random walk, each step )
```
| Word | Behavior | Output |
@@ -62,7 +62,7 @@ Stack effect: `( min max period -- str )`
Define a multi-segment envelope for a parameter. Provide a start value, then pairs of target and duration.
```forth
saw s 0 1 0.1 0.7 0.5 0 8 env gain .
saw snd 0 1 0.1 0.7 0.5 0 8 env gain .
```
This creates: start at `0`, rise to `1` in `0.1` steps, drop to `0.7` in `0.5` steps, fall to `0` in `8` steps.
@@ -74,7 +74,7 @@ Stack effect: `( start target1 dur1 [target2 dur2 ...] -- str )`
Modulation words return strings, so they compose naturally with the rest of the language. Use them anywhere a parameter value is expected.
```forth
saw s
saw snd
200 4000 4 lfo lpf
0.3 0.7 8 tlfo pan
0 1 0.1 0.7 0.5 0 8 env gain

View File

@@ -7,7 +7,7 @@ Cagire includes an audio engine called `Doux`. No external software is needed to
When you write a Forth script and emit (`.`), the script produces a command string. This command travels to the audio engine, which interprets it and creates a voice. The voice plays until its envelope finishes or until it is killed by another voice. You can also spawn infinite voices, but you will need to manage their lifecycle manually, otherwise they will never stop.
```forth
saw s c4 note 0.8 gain 0.3 verb .
saw snd c4 note 0.8 gain 0.3 verb .
```
## Voices
@@ -24,7 +24,7 @@ Press `r` on the Engine page to reset the peak counter.
After selecting a sound source, you add parameters. Each parameter word takes a value from the stack and stores it in the command register:
```forth
saw s
saw snd
c4 note ;; pitch
0.5 gain ;; volume
0.1 attack ;; envelope attack time
@@ -42,14 +42,14 @@ Use `all` to apply parameters globally. Global parameters persist across all pat
```forth
;; Prospective: set params before emitting
500 lpf 0.5 verb all
kick s 60 note . ;; gets lpf=500 verb=0.5
hat s 70 note . ;; gets lpf=500 verb=0.5
kick snd 60 note . ;; gets lpf=500 verb=0.5
hat snd 70 note . ;; gets lpf=500 verb=0.5
```
```forth
;; Retroactive: patch already-emitted sounds
kick s 60 note .
hat s 70 note .
kick snd 60 note .
hat snd 70 note .
500 lpf 0.5 verb all ;; both outputs get lpf and verb
```
@@ -57,17 +57,17 @@ Per-sound parameters override global ones:
```forth
500 lpf all
kick s 2000 lpf . ;; lpf=2000 (per-sound wins)
hat s . ;; lpf=500 (global)
kick snd 2000 lpf . ;; lpf=2000 (per-sound wins)
hat snd . ;; lpf=500 (global)
```
Use `noall` to clear global parameters:
```forth
500 lpf all
kick s . ;; gets lpf
kick snd . ;; gets lpf
noall
hat s . ;; no lpf
hat snd . ;; no lpf
```
## Controlling Existing Voices

View File

@@ -79,16 +79,16 @@ Top-level files are named by their filename (without extension). Files inside fo
Reference samples by name:
```forth
kick s . ;; play kick.wav
snare s 0.5 gain . ;; play snare at half volume
kick snd . ;; play kick.wav
snare snd 0.5 gain . ;; play snare at half volume
```
For samples in folders, use `n` to select which one:
```forth
hats s 0 n . ;; play hats/closed.wav (index 0)
hats s 1 n . ;; play hats/open.wav (index 1)
hats s 2 n . ;; play hats/pedal.wav (index 2)
hats snd 0 n . ;; play hats/closed.wav (index 0)
hats snd 1 n . ;; play hats/open.wav (index 1)
hats snd 2 n . ;; play hats/pedal.wav (index 2)
```
The index wraps around. If you have 3 samples and request `5 n`, you get index 2 (because 5 % 3 = 2).
@@ -106,9 +106,9 @@ samples/
```
```forth
kick s . ;; plays kick.wav
kick s a bank . ;; plays kick_a.wav
kick s hard bank . ;; plays kick_hard.wav
kick snd . ;; plays kick.wav
kick snd a bank . ;; plays kick_a.wav
kick snd hard bank . ;; plays kick_hard.wav
```
If the banked version does not exist, it falls back to the default.

View File

@@ -1,6 +1,6 @@
# Sources
The audio engine provides a variety of sound sources. Use the `sound` word (or `s` for short) to select one.
The audio engine provides a variety of sound sources. Use the `sound` word (or `snd` for short) to select one.
## Basic Oscillators

View File

@@ -5,7 +5,7 @@ Word definitions let you abstract sound design into reusable units.
## Defining Sounds
```forth
: lead "saw" s 0.3 gain 1200 lpf ;
: lead "saw" snd 0.3 gain 1200 lpf ;
```
Use it with different notes:
@@ -20,8 +20,8 @@ e4 note lead .
Include the emit to make the word play directly:
```forth
: kk "kick" s 1 decay . ;
: hh "hihat" s 0.5 gain 0.5 decay . ;
: kk "kick" snd 1 decay . ;
: hh "hihat" snd 0.5 gain 0.5 decay . ;
```
Steps become simple:
@@ -39,5 +39,5 @@ kk
```
```forth
c4 note saw s dark wet .
c4 note saw snd dark wet .
```

View File

@@ -78,7 +78,7 @@ Because parentheses defer execution, wrapping code in `( ... )` without a consum
.
```
Any word that is not recognized as a built-in or a user definition becomes a string on the stack. This means `kick s` and `"kick" s` are equivalent. You only need quotes when the string contains spaces or when it conflicts with an existing word name.
Any word that is not recognized as a built-in or a user definition becomes a string on the stack. This means `kick snd` and `"kick" snd` are equivalent. You only need quotes when the string contains spaces or when it conflicts with an existing word name.
## The Command Register
@@ -94,7 +94,7 @@ kick sound ;; sets the sound name
. ;; emits the command and clears the register
```
The word `sound` (or its shorthand `s`) sets what sound to play. Parameter words like `gain`, `freq`, `decay`, or `verb` add key-value pairs to the register. Nothing happens until you emit with `.` (dot). At that moment, the register is packaged into a command and sent to the audio engine.
The word `sound` (or its shorthand `snd`) sets what sound to play. Parameter words like `gain`, `freq`, `decay`, or `verb` add key-value pairs to the register. Nothing happens until you emit with `.` (dot). At that moment, the register is packaged into a command and sent to the audio engine.
This design lets you build sounds incrementally:
@@ -110,14 +110,14 @@ c4 note
Each line adds something to the register. The final `.` triggers the sound. You can also write it all on one line:
```forth
"sine" s c4 note 0.5 gain 0.3 decay 0.4 verb .
"sine" snd c4 note 0.5 gain 0.3 decay 0.4 verb .
```
The order of parameters does not matter. You can even emit multiple times in a single step. If you need to discard the register without emitting, use `clear`:
```forth
"kick" s 0.5 gain clear ;; nothing plays, register is emptied
"hat" s . ;; only the hat plays
"kick" snd 0.5 gain clear ;; nothing plays, register is emptied
"hat" snd . ;; only the hat plays
```
This is useful when conditionals might cancel a sound before it emits.

View File

@@ -47,7 +47,7 @@ The outer quotation runs every 4th iteration. Inside, a coin flip picks the note
Wrapping code in a quotation without consuming it is a quick way to disable it:
```forth
( kick s . )
( kick snd . )
```
Nothing will execute this quotation — it just sits on the stack and gets discarded. Useful for temporarily silencing a line while editing.
@@ -63,7 +63,7 @@ Square brackets execute their contents immediately, then push a count of how man
After this runs, the stack holds `60 64 67 3` — three values plus the count `3`. This is useful with words that need to know how many items precede them:
```forth
[ 60 64 67 ] cycle note sine s .
[ 60 64 67 ] cycle note sine snd .
```
The `cycle` word reads the count to know how many values to rotate through. Without brackets you would write `60 64 67 3 cycle` — the brackets save you from counting manually.
@@ -71,8 +71,8 @@ The `cycle` word reads the count to know how many values to rotate through. With
Square brackets work with any word that takes a count:
```forth
[ c4 e4 g4 ] choose note saw s . ;; random note from the list
[ 60 64 67 ] note sine s . ;; 3-note chord (note consumes all)
[ c4 e4 g4 ] choose note saw snd . ;; random note from the list
[ 60 64 67 ] note sine snd . ;; 3-note chord (note consumes all)
```
### Nesting
@@ -88,7 +88,7 @@ Square brackets can nest. Each pair produces its own count:
The contents are compiled and executed normally, so you can use any Forth code:
```forth
[ c4 c4 3 + c4 7 + ] note sine s . ;; root, minor third, fifth
[ c4 c4 3 + c4 7 + ] note sine snd . ;; root, minor third, fifth
```
## { ... } — Curly Braces
@@ -96,13 +96,13 @@ The contents are compiled and executed normally, so you can use any Forth code:
Curly braces are ignored by the compiler. They do nothing. Use them as a visual aid to group related code:
```forth
{ kick s } { 0.5 gain } { 0.3 verb } .
{ kick snd } { 0.5 gain } { 0.3 verb } .
```
This compiles to exactly the same thing as:
```forth
kick s 0.5 gain 0.3 verb .
kick snd 0.5 gain 0.3 verb .
```
They can help readability in dense one-liners but have no semantic meaning.

View File

@@ -112,7 +112,7 @@ Reads naturally: "c3 or c5, depending on the coin."
```forth
( 0.8 gain ) ( 0.3 gain ) fill ifelse
tri s c4 note 0.2 decay .
tri snd c4 note 0.2 decay .
```
Loud during fills, quiet otherwise.
@@ -123,7 +123,7 @@ Choose the nth quotation from a list. The index is 0-based:
```forth
( c4 ) ( e4 ) ( g4 ) ( b4 ) 0 3 rand select
note sine s 0.5 decay .
note sine snd 0.5 decay .
```
Four notes of a major seventh chord picked randomly. Note that this is unnecessarily complex :)

View File

@@ -9,13 +9,13 @@ Sequential rotation through values.
`cycle` advances based on `runs` — how many times this particular step has played:
```forth
60 64 67 3 cycle note sine s . ;; 60, 64, 67, 60, 64, 67, ...
60 64 67 3 cycle note sine snd . ;; 60, 64, 67, 60, 64, 67, ...
```
`pcycle` advances based on `iter` — the pattern iteration count:
```forth
kick snare 2 pcycle s . ;; kick on even iterations, snare on odd
kick snare 2 pcycle snd . ;; kick on even iterations, snare on odd
```
The distinction matters when patterns have different lengths or when multiple steps share the same script. `cycle` gives each step its own independent counter. `pcycle` ties all steps to the same global pattern position.
@@ -25,8 +25,8 @@ The distinction matters when patterns have different lengths or when multiple st
Ping-pong instead of wrapping. With 4 values the sequence is 0, 1, 2, 3, 2, 1, 0, 1, 2, ...
```forth
60 64 67 72 4 bounce note sine s . ;; ping-pong by step runs
60 64 67 72 4 pbounce note sine s . ;; ping-pong by pattern iteration
60 64 67 72 4 bounce note sine snd . ;; ping-pong by step runs
60 64 67 72 4 pbounce note sine snd . ;; ping-pong by pattern iteration
```
Same `runs` vs `iter` split as `cycle` / `pcycle`.
@@ -36,7 +36,7 @@ Same `runs` vs `iter` split as `cycle` / `pcycle`.
Uniform random selection:
```forth
kick snare hat 3 choose s . ;; random drum hit each time
kick snare hat 3 choose snd . ;; random drum hit each time
```
Unlike the cycling words, `choose` is nondeterministic — every evaluation picks independently.
@@ -46,7 +46,7 @@ Unlike the cycling words, `choose` is nondeterministic — every evaluation pick
Weighted random. Push value/weight pairs, then the count:
```forth
kick 0.5 snare 0.3 hat 0.2 3 wchoose s .
kick 0.5 snare 0.3 hat 0.2 3 wchoose snd .
```
Kick plays 50% of the time, snare 30%, hat 20%. Weights are normalized automatically — they don't need to sum to 1.
@@ -56,8 +56,8 @@ Kick plays 50% of the time, snare 30%, hat 20%. Weights are normalized automatic
Direct lookup by an explicit index. The index wraps with modulo, so it never goes out of bounds. Negative indices count from the end:
```forth
[ c4 e4 g4 ] step index note sine s . ;; step number picks the note
[ c4 e4 g4 ] iter index note sine s . ;; pattern iteration picks the note
[ c4 e4 g4 ] step index note sine snd . ;; step number picks the note
[ c4 e4 g4 ] iter index note sine snd . ;; pattern iteration picks the note
```
This is useful when you want full control over which value is selected, driven by any expression you like.
@@ -67,9 +67,9 @@ This is useful when you want full control over which value is selected, driven b
All these words take a count argument `n`. Square brackets compute that count for you:
```forth
[ 60 64 67 ] cycle note sine s . ;; no need to write "3"
[ kick snare hat ] choose s .
[ c4 e4 g4 b4 ] bounce note sine s .
[ 60 64 67 ] cycle note sine snd . ;; no need to write "3"
[ kick snare hat ] choose snd .
[ c4 e4 g4 b4 ] bounce note sine snd .
```
Without brackets: `60 64 67 3 cycle`. With brackets: `[ 60 64 67 ] cycle`. Same result, less counting.
@@ -80,7 +80,7 @@ When any of these words selects a quotation, it executes it instead of pushing i
```forth
[ ( c4 note ) ( e4 note ) ( g4 note ) ] cycle
sine s .
sine snd .
```
On the first run the quotation `( c4 note )` executes, setting the note to C4. Next run, E4. Then G4. Then back to C4.
@@ -88,5 +88,5 @@ On the first run the quotation `( c4 note )` executes, setting the note to C4. N
This works with all selection words. Mix plain values and quotations freely:
```forth
[ ( hat s 0.3 gain . ) ( snare s . ) ( kick s . ) ] choose
[ ( hat snd 0.3 gain . ) ( snare snd . ) ( kick snd . ) ] choose
```

View File

@@ -24,7 +24,7 @@ When you define a word in one step, it becomes available to all other steps. Thi
Step 0:
```forth
: bass "saw" s 0.8 gain 800 lpf ;
: bass "saw" snd 0.8 gain 800 lpf ;
```
Step 4:
@@ -75,7 +75,7 @@ This only affects words you defined with `:` ... `;`. Built-in words cannot be f
**Synth definitions** save you from repeating sound design:
```forth
: pad "sine" s 0.3 gain 2 attack 0.5 verb ;
: pad "sine" snd 0.3 gain 2 attack 0.5 verb ;
```
**Transpositions** and musical helpers:
@@ -90,8 +90,8 @@ This only affects words you defined with `:` ... `;`. Built-in words cannot be f
A word can contain `.` to emit sounds directly:
```forth
: kick "kick" s . ;
: hat "hat" s 0.4 gain . ;
: kick "kick" snd . ;
: hat "hat" snd 0.4 gain . ;
```
Then a step becomes trivial:

View File

@@ -33,4 +33,4 @@ Each word entry shows:
- **Description**: What the word does
- **Example**: How to use it
Press `/` to search across all words. The search matches word names, aliases, and descriptions. Press `Esc` to clear and return to browsing. Use the dictionary while writing scripts to check stack effects and study their behavior. Some words also come with shorter aliases (e.g., `sound``s`). You will learn aliases quite naturally, because aliases are usually reserved for very common words.
Press `/` to search across all words. The search matches word names, aliases, and descriptions. Press `Esc` to clear and return to browsing. Use the dictionary while writing scripts to check stack effects and study their behavior. Some words also come with shorter aliases (e.g., `sound``snd`). You will learn aliases quite naturally, because aliases are usually reserved for very common words.

View File

@@ -35,8 +35,8 @@ Cagire supports this syntax but also provides quotation-based conditionals:
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" snd . ) coin ? ;; execute if coin is 1
( "snare" snd . ) coin !? ;; execute if coin is 0
```
## Strings
@@ -56,7 +56,7 @@ Cagire has first-class strings:
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"
kick snd . ;; "kick" is not a word, so it becomes the string "kick"
myweirdname ;; pushes "myweirdname" onto the stack
```
@@ -110,8 +110,8 @@ Cagire uses a quotation-based loop with `times`:
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 snd . ) times ;; hat at 0, 0.25, 0.5, 0.75
4 ( c4 @i + note sine snd . ) times ;; ascending notes
```
For generating sequences without side effects, use `..` or `gen`:
@@ -155,11 +155,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" snd . ) 50 prob ;; 50% chance
( "clap" snd . ) 0.25 chance ;; 25% chance
( "hat" snd . ) often ;; 75% chance
( "rim" snd . ) sometimes ;; 50% chance
( "tom" snd . ) rarely ;; 25% chance
```
These words take a quotation and execute it probabilistically.
@@ -169,9 +169,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" snd . ) 4 every ;; every 4th pattern iteration
( "hat" snd . ) 3 8 bjork ;; Euclidean: 3 hits across 8 step runs
( "hat" snd . ) 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.
@@ -183,13 +183,13 @@ Execute a quotation on specific iterations:
Parameter words like `note`, `freq`, and `gain` consume the entire stack. If you push multiple values before a param word, you get polyphony:
```forth
60 64 67 note sine s . ;; emits 3 voices with notes 60, 64, 67
60 64 67 note sine snd . ;; emits 3 voices with notes 60, 64, 67
```
This works for any param and for the sound word itself:
```forth
440 880 freq sine tri s . ;; 2 voices: sine at 440, tri at 880
440 880 freq sine tri snd . ;; 2 voices: sine at 440, tri at 880
```
When params have different lengths, shorter lists cycle:
@@ -197,7 +197,7 @@ When params have different lengths, shorter lists cycle:
```forth
60 64 67 note ;; 3 notes
0.5 1.0 gain ;; 2 gains (cycles: 0.5, 1.0, 0.5)
sine s . ;; emits 3 voices
sine snd . ;; emits 3 voices
```
Polyphony multiplies with `at` deltas:
@@ -205,7 +205,7 @@ Polyphony multiplies with `at` deltas:
```forth
0 0.5 at ;; 2 time points
60 64 note ;; 2 notes
sine s . ;; emits 4 voices (2 notes × 2 times)
sine snd . ;; emits 4 voices (2 notes × 2 times)
```
## Summary

View File

@@ -42,8 +42,8 @@ Crossfade between two sounds:
```forth
1 1 ccval 127 / ;; normalize to 0.0-1.0
dup saw s swap gain .
1 swap - tri s swap gain .
dup saw snd swap gain .
1 swap - tri snd swap gain .
```
## Scaling Values

View File

@@ -15,7 +15,7 @@ Configure your MIDI devices in the **Options** view. Select input and output dev
The audio engine (`Doux`) and MIDI are independent systems. Use `.` to emit audio commands, use `m.` to emit MIDI messages. You can use both in the same script:
```forth
saw s c4 note 0.5 gain . ;; audio
saw snd c4 note 0.5 gain . ;; audio
60 note 100 velocity m. ;; MIDI
```

View File

@@ -7,19 +7,19 @@ Every step has a duration. By default, sounds emit at the very start of that dur
`at` drains the entire stack and stores the values as timing offsets. Each value is a fraction of the step duration: 0 = start, 0.5 = halfway, 1.0 = next step boundary.
```forth
0.5 at kick s . ;; kick at the midpoint
0.5 at kick snd . ;; kick at the midpoint
```
Push multiple values before calling `at` to get multiple emits from a single `.`:
```forth
0 0.5 at kick s .
0 0.5 at kick snd .
```
Two kicks: one at start, one at midpoint.
```forth
0 0.25 0.5 0.75 at hat s .
0 0.25 0.5 0.75 at hat snd .
```
Four hats, evenly spaced.
@@ -28,10 +28,10 @@ The deltas persist across multiple `.` calls until `clear` or a new `at`:
```forth
0 0.5 at
kick s . ;; 2 kicks
hat s . ;; 2 hats (same timing)
kick snd . ;; 2 kicks
hat snd . ;; 2 hats (same timing)
clear
snare s . ;; 1 snare (deltas cleared)
snare snd . ;; 1 snare (deltas cleared)
```
## Cross-product: at Without arp
@@ -40,7 +40,7 @@ Without `arp`, deltas multiply with polyphonic voices. If you have 3 notes and 2
```forth
0 0.5 at
c4 e4 g4 note 1.5 decay sine s .
c4 e4 g4 note 1.5 decay sine snd .
```
6 emits: 3 notes x 2 deltas. A chord played twice per step.
@@ -51,7 +51,7 @@ c4 e4 g4 note 1.5 decay sine s .
```forth
0 0.33 0.66 at
c4 e4 g4 arp note 0.5 decay sine s .
c4 e4 g4 arp note 0.5 decay sine snd .
```
C4 at 0, E4 at 0.33, G4 at 0.66.
@@ -60,7 +60,7 @@ If the lists differ in length, the shorter one wraps around:
```forth
0 0.25 0.5 0.75 at
c4 e4 arp note 0.3 decay sine s .
c4 e4 arp note 0.3 decay sine snd .
```
C4, E4, C4, E4 — the shorter list wraps to fill 4 time points.
@@ -74,25 +74,25 @@ You rarely type deltas by hand. Use generators:
Evenly spaced via `.,`:
```forth
0 1 0.25 ., at hat s . ;; 0 0.25 0.5 0.75 1.0
0 1 0.25 ., at hat snd . ;; 0 0.25 0.5 0.75 1.0
```
Euclidean distribution via `euclid`:
```forth
3 8 euclid at hat s . ;; 3 hats at positions 0, 3, 5
3 8 euclid at hat snd . ;; 3 hats at positions 0, 3, 5
```
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 snd . ;; 4 hats at random positions
```
Geometric spacing via `geom..`:
```forth
0.0 2.0 4 geom.. at hat s . ;; exponentially spaced
0.0 2.0 4 geom.. at hat snd . ;; exponentially spaced
```
## Gating at
@@ -101,14 +101,14 @@ Wrap `at` expressions in quotations for conditional timing:
```forth
( 0 0.25 0.5 0.75 at ) 2 every
hat s .
hat snd .
```
16th-note hats every other bar.
```forth
( 0 0.5 at ) 0.5 chance
kick s .
kick snd .
```
50% chance of double-hit.

View File

@@ -48,7 +48,7 @@ Contrast with `times`, which executes for side effects and does not collect. `ti
```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 60 + note sine snd . ) times ;; plays 4 notes, collects nothing
```
The distinction: `gen` is for building data. `times` is for doing things.
@@ -124,9 +124,9 @@ c4 4 dupn ;; c4 c4 c4 c4
Build a drone chord -- same note, different octaves:
```forth
c3 note 0.5 gain sine s .
c3 note 12 + 0.5 gain sine s .
c3 note 24 + 0.3 gain sine s .
c3 note 0.5 gain sine snd .
c3 note 12 + 0.5 gain sine snd .
c3 note 24 + 0.3 gain sine snd .
```
Or replicate a value for batch processing:

View File

@@ -7,17 +7,17 @@ This tutorial covers everything pitch-related: notes, intervals, chords, voicing
A note name followed by an octave number compiles to a MIDI integer:
```forth
c4 note sine s .
c4 note sine snd .
```
That plays middle C (MIDI 60). `a4` is concert A (69), `e3` is 52. Sharps use `s` or `#`, flats use `b`:
```forth
fs4 note 0.5 decay saw s .
fs4 note 0.5 decay saw snd .
```
```forth
eb4 note 0.8 decay tri s .
eb4 note 0.8 decay tri snd .
```
`fs4` and `f#4` both mean F sharp 4 (MIDI 66). `bb3` is B flat 3 (58). Octave range is -1 to 9.
@@ -29,13 +29,13 @@ Notes are just integers. They work anywhere an integer works — you can do arit
An interval duplicates the top of the stack and adds semitones. Stack two intervals to build a chord by hand:
```forth
c4 M3 P5 note 1.5 decay sine s .
c4 M3 P5 note 1.5 decay sine snd .
```
That builds a C major triad from scratch: C4 (60), then a major third above (64), then a perfect fifth above the root (67). Three notes on the stack, all played together.
```forth
a3 m3 P5 note 1.2 decay va s .
a3 m3 P5 note 1.2 decay va snd .
```
A minor triad: A3, C4, E4.
@@ -78,7 +78,7 @@ A minor triad: A3, C4, E4.
Custom voicings with wide intervals:
```forth
c3 P5 P8 M10 note 1.5 decay sine s .
c3 P5 P8 M10 note 1.5 decay sine snd .
```
C3, G3, C4, E4 — an open-voiced C major spread across two octaves.
@@ -88,21 +88,21 @@ C3, G3, C4, E4 — an open-voiced C major spread across two octaves.
Chord words replace a root note with all the chord tones. They're shortcuts for what intervals do manually:
```forth
c4 maj note 1.5 decay sine s .
c4 maj note 1.5 decay sine snd .
```
That's the same C major triad, but in one word instead of `M3 P5`. A few more:
```forth
d3 min7 note 1.5 decay va s .
d3 min7 note 1.5 decay va snd .
```
```forth
e3 dom9 note 1.2 decay saw s .
e3 dom9 note 1.2 decay saw snd .
```
```forth
a3 sus2 note 1.5 decay tri s .
a3 sus2 note 1.5 decay tri snd .
```
Common triads:
@@ -140,19 +140,19 @@ Four words reshape chord voicings without changing the harmony.
`inv` moves the bottom note up an octave (inversion):
```forth
c4 maj inv note 1.5 decay sine s .
c4 maj inv note 1.5 decay sine snd .
```
The root C goes up, giving E4 G4 C5 — first inversion. Apply it twice for second inversion:
```forth
c4 maj inv inv note 1.5 decay sine s .
c4 maj inv inv note 1.5 decay sine snd .
```
G4 C5 E5. `dinv` does the opposite — moves the top note down an octave:
```forth
c4 maj dinv note 1.5 decay sine s .
c4 maj dinv note 1.5 decay sine snd .
```
G3 C4 E4. The fifth drops below the root.
@@ -160,13 +160,13 @@ G3 C4 E4. The fifth drops below the root.
`drop2` and `drop3` are jazz voicing techniques for four-note chords. `drop2` takes the second-from-top note and drops it an octave:
```forth
c4 maj7 drop2 note 1.2 decay va s .
c4 maj7 drop2 note 1.2 decay va snd .
```
From C4 E4 G4 B4, the G drops to G3: G3 C4 E4 B4. `drop3` drops the third-from-top:
```forth
c4 maj7 drop3 note 1.2 decay va s .
c4 maj7 drop3 note 1.2 decay va snd .
```
E drops to E3: E3 C4 G4 B4. These create wider, more open voicings common in jazz guitar and piano.
@@ -176,13 +176,13 @@ E drops to E3: E3 C4 G4 B4. These create wider, more open voicings common in jaz
`tp` shifts every note on the stack by N semitones:
```forth
c4 maj 3 tp note 1.5 decay sine s .
c4 maj 3 tp note 1.5 decay sine snd .
```
C major transposed up 3 semitones becomes Eb major. Works with any number of notes:
```forth
c4 min7 -2 tp note 1.5 decay va s .
c4 min7 -2 tp note 1.5 decay va snd .
```
Shifts the whole chord down 2 semitones (Bb minor 7).
@@ -190,14 +190,14 @@ Shifts the whole chord down 2 semitones (Bb minor 7).
`oct` shifts a single note by octaves:
```forth
c4 1 oct note 0.3 decay sine s .
c4 1 oct note 0.3 decay sine snd .
```
C5 (one octave up). Useful for bass lines:
```forth
0 2 4 5 7 5 4 2 8 cycle minor note
-2 oct 0.8 gain sine s .
-2 oct 0.8 gain sine snd .
```
## Scales
@@ -205,7 +205,7 @@ C5 (one octave up). Useful for bass lines:
Scale words convert a degree index into a MIDI note. By default the root is C4 (MIDI 60):
```forth
0 major note 0.5 decay sine s .
0 major note 0.5 decay sine snd .
```
Degree 0 of the major scale: C4. Degrees wrap with octave transposition — degree 7 gives C5 (72), degree -1 gives B3 (59).
@@ -213,13 +213,13 @@ Degree 0 of the major scale: C4. Degrees wrap with octave transposition — degr
Walk through a scale with `cycle`:
```forth
0 1 2 3 4 5 6 7 8 cycle minor note 0.5 decay sine s .
0 1 2 3 4 5 6 7 8 cycle minor note 0.5 decay sine snd .
```
Random notes from a scale:
```forth
0 7 rand pentatonic note 0.8 decay va s .
0 7 rand pentatonic note 0.8 decay va snd .
```
### Setting the key
@@ -227,13 +227,13 @@ Random notes from a scale:
By default scales are rooted at C4. Use `key!` to change the tonal center:
```forth
g3 key! 0 major note 0.5 decay sine s .
g3 key! 0 major note 0.5 decay sine snd .
```
Now degree 0 is G3 (55) instead of C4. The key persists across steps until changed again:
```forth
a3 key! 0 3 5 7 3 cycle minor note 0.8 decay tri s .
a3 key! 0 3 5 7 3 cycle minor note 0.8 decay tri snd .
```
A minor melody starting from A3.
@@ -261,19 +261,19 @@ Jazz, symmetric, and modal variant scales are listed in the Reference section.
`triad` and `seventh` build chords from scale degrees. Instead of specifying a chord type, you get whatever chord the scale produces at that degree:
```forth
0 major triad note 1.5 decay sine s .
0 major triad note 1.5 decay sine snd .
```
Degree 0 of the major scale, stacked in thirds: C E G — a major triad. The scale determines the chord quality automatically. Degree 1 gives D F A (minor), degree 4 gives G B D (major):
```forth
4 major triad note 1.5 decay sine s .
4 major triad note 1.5 decay sine snd .
```
`seventh` adds a fourth note:
```forth
0 major seventh note 1.2 decay va s .
0 major seventh note 1.2 decay va snd .
```
C E G B — Cmaj7. Degree 1 gives Dm7, degree 4 gives G7 (dominant). The diatonic context determines everything.
@@ -281,7 +281,7 @@ C E G B — Cmaj7. Degree 1 gives Dm7, degree 4 gives G7 (dominant). The diatoni
Combine with `key!` to play diatonic chords in any key:
```forth
g3 key! 0 major triad note 1.5 decay sine s .
g3 key! 0 major triad note 1.5 decay sine snd .
```
G major triad rooted at G3.
@@ -291,7 +291,7 @@ A I-vi-IV-V chord progression using `pcycle`:
```forth
( 0 major seventh ) ( 5 major seventh )
( 3 major seventh ) ( 4 major seventh ) 4 pcycle
note 1.2 decay va s .
note 1.2 decay va snd .
```
Combine with voicings for smoother voice leading:
@@ -299,13 +299,13 @@ Combine with voicings for smoother voice leading:
```forth
( 0 major seventh ) ( 5 major seventh inv )
( 3 major seventh ) ( 4 major seventh drop2 ) 4 pcycle
note 1.5 decay va s .
note 1.5 decay va snd .
```
Arpeggiate diatonic chords using `arp` (see the *Timing with at* tutorial for details on `arp`):
```forth
0 major seventh arp note 0.5 decay sine s .
0 major seventh arp note 0.5 decay sine snd .
```
## Frequency Conversion
@@ -313,7 +313,7 @@ Arpeggiate diatonic chords using `arp` (see the *Timing with at* tutorial for de
`mtof` converts a MIDI note to frequency in Hz. `ftom` does the reverse:
```forth
c4 mtof freq sine s .
c4 mtof freq sine snd .
```
Useful when a synth parameter expects Hz rather than MIDI.

View File

@@ -21,7 +21,7 @@ Press `Enter` to focus the editor. Write Forth code as you would in any step. Pr
```forth
;; a simple drone
saw s c2 note 0.3 gain 0.4 verb .
saw snd c2 note 0.3 gain 0.4 verb .
```
## Speed and Length

View File

@@ -17,15 +17,15 @@ sine sound
`rand` takes a range and returns a random value. If both bounds are integers, the result is an integer. If either is a float, you get a float:
```forth
60 72 rand note sine s .5 decay . ;; random MIDI note from 60 to 72
0.3 0.9 rand gain sine s .5 decay . ;; random gain between 0.3 and 0.9
60 72 rand note sine snd 0.5 decay . ;; random MIDI note from 60 to 72
0.3 0.9 rand gain sine snd 0.5 decay . ;; random gain between 0.3 and 0.9
```
`exprand` and `logrand` give you weighted distributions. `exprand` is biased toward the low end, `logrand` toward the high end:
```forth
200.0 8000.0 exprand freq sine s .5 decay . ;; mostly low frequencies
200.0 8000.0 logrand freq sine s .5 decay . ;; mostly high frequencies
200.0 8000.0 exprand freq sine snd 0.5 decay . ;; mostly low frequencies
200.0 8000.0 logrand freq sine snd 0.5 decay . ;; mostly high frequencies
```
These are useful for parameters where perception is logarithmic, like frequency and duration.
@@ -35,8 +35,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
( kick s . ) 75 prob ;; 75% chance
( hat snd . ) 0.25 chance ;; 25% chance
( kick snd . ) 75 prob ;; 75% chance
```
Named probability words save you from remembering numbers:
@@ -52,9 +52,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 snd . ) often ;; 75%
( snare snd . ) sometimes ;; 50%
( clap snd . ) 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.
@@ -62,8 +62,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 snd . ) coin ? ;; execute if coin is 1
( rim snd . ) coin !? ;; execute if coin is 0
```
## Selection
@@ -71,21 +71,21 @@ Use `?` and `!?` with `coin` for quick coin-flip decisions:
`choose` picks randomly from n items on the stack:
```forth
kick snare hat 3 choose s . ;; random drum hit
60 64 67 72 4 choose note sine s .5 decay . ;; random note from a set
kick snare hat 3 choose snd . ;; random drum hit
60 64 67 72 4 choose note sine snd 0.5 decay . ;; random note from a set
```
When a chosen item is a quotation, it gets executed:
```forth
( 0.1 decay ) ( 0.5 decay ) ( 0.9 decay ) 3 choose
sine s .
sine snd .
```
`wchoose` lets you assign weights to each option. Push value/weight pairs:
```forth
kick 0.5 snare 0.3 hat 0.2 3 wchoose s .
kick 0.5 snare 0.3 hat 0.2 3 wchoose snd .
```
Kick plays 50% of the time, snare 30%, hat 20%. Weights don't need to sum to 1 -- they're normalized automatically.
@@ -103,7 +103,7 @@ Combined with `note`, this gives you a random permutation of a chord every time
`every` runs a quotation once every n pattern iterations:
```forth
( crash s . ) 4 every ;; crash cymbal every 4th iteration
( crash snd . ) 4 every ;; crash cymbal every 4th iteration
```
`except` is the inverse -- it runs a quotation on all iterations *except* every nth:
@@ -115,22 +115,22 @@ Combined with `note`, this gives you a random permutation of a chord every time
`every+` and `except+` take an extra offset argument to shift the phase:
```forth
( snare s . ) 4 2 every+ ;; fires at iter 2, 6, 10, 14...
( snare s . ) 4 2 except+ ;; skips at iter 2, 6, 10, 14...
( snare snd . ) 4 2 every+ ;; fires at iter 2, 6, 10, 14...
( snare snd . ) 4 2 except+ ;; skips at iter 2, 6, 10, 14...
```
Without the offset, `every` fires at 0, 4, 8... The offset shifts that by 2, so it fires at 2, 6, 10... This lets you interleave patterns that share the same period:
```forth
( kick s . ) 4 every ;; kick at 0, 4, 8...
( snare s . ) 4 2 every+ ;; snare at 2, 6, 10...
( kick snd . ) 4 every ;; kick at 0, 4, 8...
( snare snd . ) 4 2 every+ ;; snare at 2, 6, 10...
```
`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 snd . ) 3 8 bjork ;; tresillo: x..x..x. (by step runs)
( hat snd . ) 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:
@@ -148,7 +148,7 @@ By default, every run produces different random values. Use `seed` to make rando
```forth
42 seed
60 72 rand note sine s . ;; always the same "random" note
60 72 rand note sine snd . ;; always the same "random" note
```
The seed is set at the start of the script. Same seed, same sequence. Useful when you want a specific random pattern to repeat.
@@ -158,7 +158,7 @@ The seed is set at the start of the script. Same seed, same sequence. Useful whe
The real power comes from mixing techniques. A hi-hat pattern with ghost notes:
```forth
hat s
hat snd
( 0.3 0.6 rand gain ) ( 0.8 gain ) 2 cycle
.
```
@@ -170,16 +170,16 @@ A bass line that changes every 4 bars:
```forth
( c2 note ) ( e2 note ) ( g2 note ) ( a2 note ) 4 pcycle
( 0.5 decay ) often
sine s .
sine snd .
```
Layered percussion with different densities:
```forth
( kick s . ) always
( snare s . ) 2 every
( hat s . ) 5 8 bjork
( rim s . ) rarely
( kick snd . ) always
( snare snd . ) 2 every
( hat snd . ) 5 8 bjork
( rim snd . ) rarely
```
A melodic step with weighted note selection and random timbre:
@@ -188,7 +188,7 @@ A melodic step with weighted note selection and random timbre:
c4 0.4 e4 0.3 g4 0.2 b4 0.1 4 wchoose note
0.3 0.7 rand decay
1.0 4.0 exprand harmonics
modal s .
modal snd .
```
The root note plays most often. Higher chord tones are rarer. Decay and harmonics vary continuously.

View File

@@ -19,7 +19,7 @@ Play something -- a pattern, a live input, anything that makes sound. When you'r
The recording is now available as a sample:
```forth
drums s .
drums snd .
```
## Playback
@@ -27,10 +27,10 @@ drums s .
Recorded samples are ordinary samples. Everything you can do with a loaded sample works here:
```forth
drums s 0.5 speed . ;; half speed
drums s 0.25 begin 0.5 end . ;; slice the middle quarter
drums s 800 lpf 0.3 verb . ;; filter and reverb
drums s -1 speed . ;; reverse
drums snd 0.5 speed . ;; half speed
drums snd 0.25 begin 0.5 end . ;; slice the middle quarter
drums snd 800 lpf 0.3 verb . ;; filter and reverb
drums snd -1 speed . ;; reverse
```
## Overdub
@@ -70,7 +70,7 @@ Record a foundation, then overdub to build up:
"loop" dub
;; 4. play the result
loop s .
loop snd .
```
Each overdub pass adds to what's already there. The buffer wraps, so longer passes layer cyclically over the original length.
@@ -80,16 +80,16 @@ Each overdub pass adds to what's already there. The buffer wraps, so longer pass
Once you have a recording, carve it up:
```forth
loop s 0.0 begin 0.25 end . ;; first quarter
loop s 0.25 begin 0.5 end . ;; second quarter
loop s 0.5 begin 0.75 end . ;; third quarter
loop s 0.75 begin 1.0 end . ;; last quarter
loop snd 0.0 begin 0.25 end . ;; first quarter
loop snd 0.25 begin 0.5 end . ;; second quarter
loop snd 0.5 begin 0.75 end . ;; third quarter
loop snd 0.75 begin 1.0 end . ;; last quarter
```
Combine with randomness for variation:
```forth
loop s
loop snd
0.0 0.25 0.5 0.75 4 choose begin
0.5 speed
.

View File

@@ -11,9 +11,9 @@ Drop an `.sf2` file into one of your samples directories. The engine finds and l
Use `gm` as the sound source. The `n` parameter selects a program by name or number (0-127):
```forth
gm s piano n . ;; acoustic piano
gm s strings n c4 note . ;; strings playing middle C
gm s 0 n e4 note . ;; program 0 (piano) playing E4
gm snd piano n . ;; acoustic piano
gm snd strings n c4 note . ;; strings playing middle C
gm snd 0 n e4 note . ;; program 0 (piano) playing E4
```
## Drums
@@ -21,10 +21,10 @@ gm s 0 n e4 note . ;; program 0 (piano) playing E4
Drums live on a separate bank. Use `drums` or `percussion` as the `n` value. Each MIDI note triggers a different instrument:
```forth
gm s drums n 36 note . ;; kick
gm s drums n 38 note . ;; snare
gm s drums n 42 note . ;; closed hi-hat
gm s percussion n 49 note . ;; crash cymbal
gm snd drums n 36 note . ;; kick
gm snd drums n 38 note . ;; snare
gm snd drums n 42 note . ;; closed hi-hat
gm snd percussion n 49 note . ;; crash cymbal
```
## Envelope
@@ -32,8 +32,8 @@ gm s percussion n 49 note . ;; crash cymbal
The soundfont embeds ADSR envelope data per preset. The engine applies it automatically. Override any parameter explicitly:
```forth
gm s piano n 0.01 attack 0.3 decay .
gm s strings n 0.5 attack 2.0 release .
gm snd piano n 0.01 attack 0.3 decay .
gm snd strings n 0.5 attack 2.0 release .
```
If you set `attack`, `decay`, `sustain`, or `release`, your value wins. Unspecified parameters keep the soundfont default.
@@ -43,9 +43,9 @@ If you set `attack`, `decay`, `sustain`, or `release`, your value wins. Unspecif
All standard engine parameters work on GM voices. Filter, distort, spatialize:
```forth
gm s bass n 800 lpf 0.3 verb .
gm s epiano n 0.5 delay 1.5 distort .
gm s choir n 0.8 pan 2000 hpf .
gm snd bass n 800 lpf 0.3 verb .
gm snd epiano n 0.5 delay 1.5 distort .
gm snd choir n 0.8 pan 2000 hpf .
```
## Preset Names
@@ -79,22 +79,22 @@ A simple GM drum pattern across four steps:
```forth
;; step 1: kick
gm s drums n 36 note .
gm snd drums n 36 note .
;; step 2: closed hat
gm s drums n 42 note 0.6 gain .
gm snd drums n 42 note 0.6 gain .
;; step 3: snare
gm s drums n 38 note .
gm snd drums n 38 note .
;; step 4: closed hat
gm s drums n 42 note 0.6 gain .
gm snd drums n 42 note 0.6 gain .
```
Layer piano chords with randomness:
```forth
gm s piano n
gm snd piano n
c4 e4 g4 3 choose note
0.3 0.8 rand gain
0.1 0.4 rand verb
@@ -104,7 +104,7 @@ c4 e4 g4 3 choose note
A bass line with envelope override:
```forth
gm s bass n
gm snd bass n
c2 e2 g2 a2 4 cycle note
0.01 attack 0.2 decay 0.0 sustain
.

View File

@@ -17,13 +17,13 @@ Variables let you name values and share data between steps. They are global -- a
`,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
440 ,freq sine snd . ;; stores 440 in freq AND passes it to the pipeline
```
Without `,`, you'd need `dup`:
```forth
440 dup !freq sine s . ;; equivalent, but noisier
440 dup !freq sine snd . ;; equivalent, but noisier
```
## Sharing Between Steps
@@ -35,7 +35,7 @@ Variables are shared across all steps. One step can store a value that another r
c4 iter 7 mod + !root
;; step 4: read it
@root 7 + note sine s .
@root 7 + note sine snd .
```
Every time the pattern loops, step 0 picks a new root. Step 4 always harmonizes with it.
@@ -46,7 +46,7 @@ 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
@n 12 mod note sine snd . ;; cycle through 12 notes
```
Reset on some condition:
@@ -69,7 +69,7 @@ Store a sound name in a variable, reuse it across steps:
"sine" !synth
;; step 1, 2, 3...
c4 note @synth s .
c4 note @synth snd .
```
Change one step, all steps follow.