diff --git a/docs/tutorials/at.md b/docs/tutorials/at.md index c5510f1..aaeea75 100644 --- a/docs/tutorials/at.md +++ b/docs/tutorials/at.md @@ -13,10 +13,17 @@ Every step has a duration. By default, sounds emit at the very start of that dur Push multiple values before calling `at` to get multiple emits from a single `.`: ```forth -0 0.5 at kick s . ;; two kicks: one at start, one at midpoint -0 0.25 0.5 0.75 at hat s . ;; four hats, evenly spaced +0 0.5 at kick s . ``` +Two kicks: one at start, one at midpoint. + +```forth +0 0.25 0.5 0.75 at hat s . +``` + +Four hats, evenly spaced. + The deltas persist across multiple `.` calls until `clear` or a new `at`: ```forth @@ -33,10 +40,10 @@ Without `arp`, deltas multiply with polyphonic voices. If you have 3 notes and 2 ```forth 0 0.5 at -c4 e4 g4 note sine s . ;; 6 emits: 3 notes x 2 deltas +c4 e4 g4 note 1.5 decay sine s . ``` -This is a chord played twice per step. +6 emits: 3 notes x 2 deltas. A chord played twice per step. ## 1:1 Pairing: at With arp @@ -44,16 +51,20 @@ This is a chord played twice per step. ```forth 0 0.33 0.66 at -c4 e4 g4 arp note sine s . ;; c4 at 0, e4 at 0.33, g4 at 0.66 +c4 e4 g4 arp note 0.5 decay sine s . ``` +C4 at 0, E4 at 0.33, G4 at 0.66. + If the lists differ in length, the shorter one wraps around: ```forth 0 0.25 0.5 0.75 at -c4 e4 arp note sine s . ;; c4, e4, c4, e4 at 4 time points +c4 e4 arp note 0.3 decay sine s . ``` +C4, E4, C4, E4 — the shorter list wraps to fill 4 time points. + This is THE key distinction. Without `arp`: every note at every time. With `arp`: one note per time slot. ## Generating Deltas @@ -89,12 +100,18 @@ Geometric spacing via `geom..`: Wrap `at` expressions in quotations for conditional timing: ```forth -( 0 0.25 0.5 0.75 at ) 2 every ;; 16th-note hats every other bar +( 0 0.25 0.5 0.75 at ) 2 every hat s . +``` -( 0 0.5 at ) 0.5 chance ;; 50% chance of double-hit +16th-note hats every other bar. + +```forth +( 0 0.5 at ) 0.5 chance kick s . ``` +50% chance of double-hit. + When the quotation doesn't execute, no deltas are set -- you get the default single emit at beat start. diff --git a/docs/tutorials/harmony.md b/docs/tutorials/harmony.md index 5f4ba82..6d9f9fd 100644 --- a/docs/tutorials/harmony.md +++ b/docs/tutorials/harmony.md @@ -1,46 +1,46 @@ # Notes & Harmony -Cagire speaks music theory. Notes, intervals, chords, and scales are all first-class words that compile to stack operations on MIDI values. This tutorial covers every pitch-related feature. +This tutorial covers everything pitch-related: notes, intervals, chords, voicings, transposition, scales, and diatonic harmony. Each section builds on the previous one. -## MIDI Notes +## Notes -Write a note name followed by an octave number. It compiles to a MIDI integer: +A note name followed by an octave number compiles to a MIDI integer: ```forth -c4 ;; 60 (middle C) -a4 ;; 69 (concert A) -e3 ;; 52 +c4 note sine s . ``` -Sharps use `s` or `#`. Flats use `b`: +That plays middle C (MIDI 60). `a4` is concert A (69), `e3` is 52. Sharps use `s` or `#`, flats use `b`: ```forth -fs4 ;; 66 (F sharp 4) -f#4 ;; 66 (same thing) -bb3 ;; 58 (B flat 3) -eb4 ;; 63 +fs4 note 0.5 decay saw s . ``` -Octave range is -1 to 9. The formula is `(octave + 1) * 12 + base + modifier`, where C=0, D=2, E=4, F=5, G=7, A=9, B=11. - -Note literals push a single integer onto the stack, just like writing `60` directly. They work everywhere an integer works: - ```forth -c4 note sine s . ;; play middle C as a sine -a4 note 0.5 gain modal s . ;; concert A, quieter +eb4 note 0.8 decay tri s . ``` +`fs4` and `f#4` both mean F sharp 4 (MIDI 66). `bb3` is B flat 3 (58). Octave range is -1 to 9. + +Notes are just integers. They work anywhere an integer works — you can do arithmetic on them, store them in variables, pass them to any word that expects a number. + ## Intervals -An interval duplicates the top of the stack and adds semitones. This lets you build chords by stacking: +An interval duplicates the top of the stack and adds semitones. Stack two intervals to build a chord by hand: ```forth -c4 M3 P5 ;; stack: 60 64 67 (C major triad) -c4 m3 P5 ;; stack: 60 63 67 (C minor triad) -a3 P5 ;; stack: 57 64 (A plus a fifth) +c4 M3 P5 note 1.5 decay sine s . ``` -Simple intervals (within one octave): +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 . +``` + +A minor triad: A3, C4, E4. + +**Simple intervals** (within one octave): | Interval | Semitones | Name | |----------|-----------|------| @@ -58,7 +58,7 @@ Simple intervals (within one octave): | `M7` | 11 | Major 7th | | `P8` | 12 | Octave | -Compound intervals (beyond one octave): +**Compound intervals** (beyond one octave): | Interval | Semitones | |----------|-----------| @@ -75,108 +75,333 @@ Compound intervals (beyond one octave): | `M14` | 23 | | `P15` | 24 | -## Chords - -Chord words take a root note and push all the chord tones. They eat the root and replace it with the full voicing: +Custom voicings with wide intervals: ```forth -c4 maj ;; stack: 60 64 67 -c4 min7 ;; stack: 60 63 67 70 -c4 dom9 ;; stack: 60 64 67 70 74 +c3 P5 P8 M10 note 1.5 decay sine s . ``` -**Triads:** +C3, G3, C4, E4 — an open-voiced C major spread across two octaves. -| Word | Intervals | Example (C4) | -|------|-----------|-------------| -| `maj` | 0 4 7 | 60 64 67 | -| `m` | 0 3 7 | 60 63 67 | -| `dim` | 0 3 6 | 60 63 66 | -| `aug` | 0 4 8 | 60 64 68 | -| `sus2` | 0 2 7 | 60 62 67 | -| `sus4` | 0 5 7 | 60 65 67 | +## Chords -**Seventh chords:** - -| Word | Intervals | Example (C4) | -|------|-----------|-------------| -| `maj7` | 0 4 7 11 | 60 64 67 71 | -| `min7` | 0 3 7 10 | 60 63 67 70 | -| `dom7` | 0 4 7 10 | 60 64 67 70 | -| `dim7` | 0 3 6 9 | 60 63 66 69 | -| `m7b5` | 0 3 6 10 | 60 63 66 70 | -| `minmaj7` | 0 3 7 11 | 60 63 67 71 | -| `aug7` | 0 4 8 10 | 60 64 68 70 | - -**Sixth chords:** - -| Word | Intervals | Example (C4) | -|------|-----------|-------------| -| `maj6` | 0 4 7 9 | 60 64 67 69 | -| `min6` | 0 3 7 9 | 60 63 67 69 | - -**Extended chords:** - -| Word | Intervals | Example (C4) | -|------|-----------|-------------| -| `dom9` | 0 4 7 10 14 | 60 64 67 70 74 | -| `maj9` | 0 4 7 11 14 | 60 64 67 71 74 | -| `min9` | 0 3 7 10 14 | 60 63 67 70 74 | -| `dom11` | 0 4 7 10 14 17 | 60 64 67 70 74 77 | -| `min11` | 0 3 7 10 14 17 | 60 63 67 70 74 77 | -| `dom13` | 0 4 7 10 14 21 | 60 64 67 70 74 81 | - -**Add chords:** - -| Word | Intervals | Example (C4) | -|------|-----------|-------------| -| `add9` | 0 4 7 14 | 60 64 67 74 | -| `add11` | 0 4 7 17 | 60 64 67 77 | -| `madd9` | 0 3 7 14 | 60 63 67 74 | - -**Altered dominants:** - -| Word | Intervals | Example (C4) | -|------|-----------|-------------| -| `dom7b9` | 0 4 7 10 13 | 60 64 67 70 73 | -| `dom7s9` | 0 4 7 10 15 | 60 64 67 70 75 | -| `dom7b5` | 0 4 6 10 | 60 64 66 70 | -| `dom7s5` | 0 4 8 10 | 60 64 68 70 | - -Chord tones are varargs -- they eat the entire stack. So a chord word should come right after the root note: +Chord words replace a root note with all the chord tones. They're shortcuts for what intervals do manually: ```forth -c4 maj note sine s . ;; plays all 3 notes as one chord +c4 maj note 1.5 decay sine s . +``` + +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 . +``` + +```forth +e3 dom9 note 1.2 decay saw s . +``` + +```forth +a3 sus2 note 1.5 decay tri s . +``` + +Common triads: + +| Word | Intervals | +|------|-----------| +| `maj` | 0 4 7 | +| `m` | 0 3 7 | +| `dim` | 0 3 6 | +| `aug` | 0 4 8 | +| `sus2` | 0 2 7 | +| `sus4` | 0 5 7 | +| `pwr` | 0 7 | + +Common seventh chords: + +| Word | Intervals | +|------|-----------| +| `maj7` | 0 4 7 11 | +| `min7` | 0 3 7 10 | +| `dom7` | 0 4 7 10 | +| `dim7` | 0 3 6 9 | +| `m7b5` | 0 3 6 10 | +| `minmaj7` | 0 3 7 11 | +| `aug7` | 0 4 8 10 | +| `augmaj7` | 0 4 8 11 | +| `7sus4` | 0 5 7 10 | + +Extended, add, altered, and other chord types are listed in the Reference section at the end. + +## Voicings + +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 . +``` + +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 . +``` + +G4 C5 E5. `dinv` does the opposite — moves the top note down an octave: + +```forth +c4 maj dinv note 1.5 decay sine s . +``` + +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 . +``` + +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 . +``` + +E drops to E3: E3 C4 G4 B4. These create wider, more open voicings common in jazz guitar and piano. + +## Transposition + +`tp` shifts every note on the stack by N semitones: + +```forth +c4 maj 3 tp note 1.5 decay sine s . +``` + +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 . +``` + +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 . +``` + +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 . ``` ## Scales -Scale words convert a degree index into a MIDI note. The base note is C4 (MIDI 60). Degrees wrap around with octave transposition: +Scale words convert a degree index into a MIDI note. By default the root is C4 (MIDI 60): ```forth -0 major ;; 60 (C4 -- degree 0) -4 major ;; 67 (G4 -- degree 4) -7 major ;; 72 (C5 -- degree 7, wraps to next octave) --1 major ;; 59 (B3 -- negative degrees go down) +0 major note 0.5 decay sine s . ``` -Use scales with `cycle` or `rand` to walk through pitches: +Degree 0 of the major scale: C4. Degrees wrap with octave transposition — degree 7 gives C5 (72), degree -1 gives B3 (59). + +Walk through a scale with `cycle`: ```forth -0 1 2 3 4 5 6 7 8 cycle minor note sine s . +0 1 2 3 4 5 6 7 8 cycle minor note 0.5 decay sine s . ``` -**Standard modes:** +Random notes from a scale: -| Word | Pattern (semitones) | -|------|-------------------| +```forth +0 7 rand pentatonic note 0.8 decay va s . +``` + +### Setting the key + +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 . +``` + +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 . +``` + +A minor melody starting from A3. + +**Common modes:** + +| Word | Pattern | +|------|---------| | `major` | 0 2 4 5 7 9 11 | | `minor` | 0 2 3 5 7 8 10 | | `dorian` | 0 2 3 5 7 9 10 | | `phrygian` | 0 1 3 5 7 8 10 | | `lydian` | 0 2 4 6 7 9 11 | | `mixolydian` | 0 2 4 5 7 9 10 | -| `aeolian` | 0 2 3 5 7 8 10 | +| `pentatonic` | 0 2 4 7 9 | +| `minpent` | 0 3 5 7 10 | +| `blues` | 0 3 5 6 7 10 | +| `harmonicminor` | 0 2 3 5 7 8 11 | +| `melodicminor` | 0 2 3 5 7 9 11 | + +Jazz, symmetric, and modal variant scales are listed in the Reference section. + +## Diatonic Harmony + +`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 . +``` + +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 . +``` + +`seventh` adds a fourth note: + +```forth +0 major seventh note 1.2 decay va s . +``` + +C E G B — Cmaj7. Degree 1 gives Dm7, degree 4 gives G7 (dominant). The diatonic context determines everything. + +Combine with `key!` to play diatonic chords in any key: + +```forth +g3 key! 0 major triad note 1.5 decay sine s . +``` + +G major triad rooted at G3. + +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 . +``` + +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 . +``` + +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 . +``` + +## Frequency Conversion + +`mtof` converts a MIDI note to frequency in Hz. `ftom` does the reverse: + +```forth +c4 mtof freq sine s . +``` + +Useful when a synth parameter expects Hz rather than MIDI. + +## Reference + +### All Chords + +**Triads:** + +| Word | Intervals | +|------|-----------| +| `maj` | 0 4 7 | +| `m` | 0 3 7 | +| `dim` | 0 3 6 | +| `aug` | 0 4 8 | +| `sus2` | 0 2 7 | +| `sus4` | 0 5 7 | +| `pwr` | 0 7 | + +**Seventh chords:** + +| Word | Intervals | +|------|-----------| +| `maj7` | 0 4 7 11 | +| `min7` | 0 3 7 10 | +| `dom7` | 0 4 7 10 | +| `dim7` | 0 3 6 9 | +| `m7b5` | 0 3 6 10 | +| `minmaj7` | 0 3 7 11 | +| `aug7` | 0 4 8 10 | +| `augmaj7` | 0 4 8 11 | +| `7sus4` | 0 5 7 10 | + +**Sixth chords:** + +| Word | Intervals | +|------|-----------| +| `maj6` | 0 4 7 9 | +| `min6` | 0 3 7 9 | +| `maj69` | 0 4 7 9 14 | +| `min69` | 0 3 7 9 14 | + +**Extended chords:** + +| Word | Intervals | +|------|-----------| +| `dom9` | 0 4 7 10 14 | +| `maj9` | 0 4 7 11 14 | +| `min9` | 0 3 7 10 14 | +| `9sus4` | 0 5 7 10 14 | +| `dom11` | 0 4 7 10 14 17 | +| `maj11` | 0 4 7 11 14 17 | +| `min11` | 0 3 7 10 14 17 | +| `dom13` | 0 4 7 10 14 21 | +| `maj13` | 0 4 7 11 14 21 | +| `min13` | 0 3 7 10 14 21 | + +**Add chords:** + +| Word | Intervals | +|------|-----------| +| `add9` | 0 4 7 14 | +| `add11` | 0 4 7 17 | +| `madd9` | 0 3 7 14 | + +**Altered dominants:** + +| Word | Intervals | +|------|-----------| +| `dom7b9` | 0 4 7 10 13 | +| `dom7s9` | 0 4 7 10 15 | +| `dom7b5` | 0 4 6 10 | +| `dom7s5` | 0 4 8 10 | +| `dom7s11` | 0 4 7 10 18 | + +### All Scales + +**Modes:** + +| Word | Pattern | +|------|---------| +| `major` | 0 2 4 5 7 9 11 | +| `minor` / `aeolian` | 0 2 3 5 7 8 10 | +| `dorian` | 0 2 3 5 7 9 10 | +| `phrygian` | 0 1 3 5 7 8 10 | +| `lydian` | 0 2 4 6 7 9 11 | +| `mixolydian` | 0 2 4 5 7 9 10 | | `locrian` | 0 1 3 5 6 8 10 | **Pentatonic and blues:** @@ -187,13 +412,6 @@ Use scales with `cycle` or `rand` to walk through pitches: | `minpent` | 0 3 5 7 10 | | `blues` | 0 3 5 6 7 10 | -**Chromatic and whole tone:** - -| Word | Pattern | -|------|---------| -| `chromatic` | 0 1 2 3 4 5 6 7 8 9 10 11 | -| `wholetone` | 0 2 4 6 8 10 | - **Harmonic and melodic minor:** | Word | Pattern | @@ -201,6 +419,13 @@ Use scales with `cycle` or `rand` to walk through pitches: | `harmonicminor` | 0 2 3 5 7 8 11 | | `melodicminor` | 0 2 3 5 7 9 11 | +**Chromatic and whole tone:** + +| Word | Pattern | +|------|---------| +| `chromatic` | 0 1 2 3 4 5 6 7 8 9 10 11 | +| `wholetone` | 0 2 4 6 8 10 | + **Jazz / Bebop:** | Word | Pattern | @@ -229,74 +454,3 @@ Use scales with `cycle` or `rand` to walk through pitches: | `lydianaug` | 0 2 4 6 8 9 11 | | `mixb6` | 0 2 4 5 7 8 10 | | `locrian2` | 0 2 3 5 6 8 10 | - -## Octave Shifting - -`oct` transposes a note by octaves: - -```forth -c4 1 oct ;; 72 (C5) -c4 -1 oct ;; 48 (C3) -c4 2 oct ;; 84 (C6) -``` - -Stack effect: `(note shift -- transposed)`. The shift is multiplied by 12 and added to the note. - -## Frequency Conversion - -`mtof` converts a MIDI note to frequency in Hz. `ftom` does the reverse: - -```forth -69 mtof ;; 440.0 (A4) -60 mtof ;; 261.63 (C4) -440 ftom ;; 69.0 -``` - -Useful when a synth parameter expects Hz rather than MIDI: - -```forth -c4 mtof freq sine s . -``` - -## Putting It Together - -A chord progression cycling every pattern iteration: - -```forth -( c3 maj7 ) ( f3 maj7 ) ( g3 dom7 ) ( c3 maj7 ) 4 pcycle -note sine s . -``` - -Arpeggiate a chord across the step's time divisions: - -```forth -c4 min7 arp note 0.5 decay sine s . -``` - -Random notes from a scale: - -```forth -0 7 rand minor note sine s . -``` - -A bass line walking scale degrees: - -```forth -0 2 4 5 7 5 4 2 8 cycle minor note --2 oct 0.8 gain sine s . -``` - -Chord voicings with random inversion: - -```forth -e3 min9 -( ) ( 1 oct ) 2 choose -note modal s . -``` - -Stacked intervals for custom voicings: - -```forth -c3 P5 P8 M10 ;; C3, G3, C4, E4 -note sine s . -``` \ No newline at end of file diff --git a/docs/tutorials/randomness.md b/docs/tutorials/randomness.md index d0f1903..8f1e754 100644 --- a/docs/tutorials/randomness.md +++ b/docs/tutorials/randomness.md @@ -7,21 +7,25 @@ Music needs surprise. A pattern that plays identically every time gets boring fa `coin` pushes 0 or 1 with equal probability: ```forth -coin note sine s . ;; either 0 or 1 as the note +;; sometimes, reverb +sine sound +( 0.5 verb ) coin ? +1 decay +. ``` `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 . ;; random MIDI note from 60 to 72 -0.3 0.9 rand gain sine s . ;; random gain between 0.3 and 0.9 +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 ``` `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 . ;; mostly low frequencies -200.0 8000.0 logrand freq sine s . ;; mostly high frequencies +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 ``` These are useful for parameters where perception is logarithmic, like frequency and duration. @@ -32,7 +36,7 @@ The probability words take a quotation and execute it with some chance. `chance` ```forth ( hat s . ) 0.25 chance ;; 25% chance -( hat s . ) 75 prob ;; 75% chance +( kick s . ) 75 prob ;; 75% chance ``` Named probability words save you from remembering numbers: @@ -67,8 +71,8 @@ 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 . ;; random note from a set +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 ``` When a chosen item is a quotation, it gets executed: @@ -187,4 +191,4 @@ c4 0.4 e4 0.3 g4 0.2 b4 0.1 4 wchoose note modal s . ``` -The root note plays most often. Higher chord tones are rarer. Decay and harmonics vary continuously. \ No newline at end of file +The root note plays most often. Higher chord tones are rarer. Decay and harmonics vary continuously.