Fix: update docs about snd
This commit is contained in:
28
CHANGELOG.md
28
CHANGELOG.md
@@ -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 0–1 float range (was 0–127 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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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 .
|
||||
```
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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 :)
|
||||
|
||||
@@ -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
|
||||
```
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
```
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
.
|
||||
|
||||
@@ -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
|
||||
.
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user