Flow

Chords and Harmony

Flow has built-in support for chord literals, chord analysis functions, roman numeral resolution, arpeggios, scale operations, and voice-led chord progressions.

Chord Literals

Chords are created using standard chord symbol notation:

Chord c1 = Cmaj      Note: C major
Chord c2 = Dm        Note: D minor
Chord c3 = Gdom7     Note: G dominant 7th
Chord c4 = Cmaj7     Note: C major 7th
Chord c5 = Am7       Note: A minor 7th
Chord c6 = Bdim      Note: B diminished
Chord c7 = Caug      Note: C augmented
Chord c8 = Dsus2     Note: D sus2
Chord c9 = Asus4     Note: A sus4
Open in playground

Chord Qualities

SuffixQualityIntervals
majMajor1-3-5
m / minMinor1-b3-5
dimDiminished1-b3-b5
augAugmented1-3-#5
7 / dom7Dominant 7th1-3-5-b7
maj7Major 7th1-3-5-7
m7 / min7Minor 7th1-b3-5-b7
dim7Diminished 7th1-b3-b5-bb7
m7f5Half-diminished (m7♭5)1-b3-b5-b7
sus2Suspended 2nd1-2-5
sus4Suspended 4th1-4-5
add9Add 9th1-3-5-9
9Dominant 9th1-3-5-b7-9
6Major 6th1-3-5-6
m6Minor 6th1-b3-5-6

Sharp and Flat Notation in Chord Symbols

Chord roots use s for sharp and f for flat:

Chord cs = Csmaj     Note: C# major
Chord bf = Bfm       Note: Bb minor
Chord fs = Fsmaj7    Note: F# major 7th
Open in playground

This is different from note literal accidentals, which use + and - (e.g., C4+ = C# at octave 4). See Note Streams.

G7 is parsed as the note G at octave 7, not a G dominant 7th chord. Use Gdom7 (or G7 in a context where a chord is explicit, like inside a note stream) for the chord.

Chord Functions

use "@std"

Chord c = Cmaj7

String root = (chordRoot c)                 Note: "C"
String quality = (chordQuality c)           Note: "maj7"
String[] notes = (chordNotes c)             Note: ["C", "E", "G", "B"]
(print $"root: {root}, quality: {quality}, count: {notes -> length}")
Open in playground

Chords in Note Streams

Chord symbols can be used directly in note streams. Each chord expands to its component notes played simultaneously, with auto-fit duration:

timesig 4/4 {
    Sequence prog = | Cmaj7 Am7 Dm7 G7 |
    (print (str prog))
}
Open in playground

Append duration suffixes (and dots) to a named chord element to control its rhythm:

timesig 4/4 {
    Sequence rhythmic = | Cmaj7q Am7q Dm7h | G7h. Cmaj7q |
}
Open in playground

Roman Numerals

Within a key context, roman numerals represent scale-degree chords:

key Cmajor {
    timesig 4/4 {
        Note: in C major: I=C, IV=F, V=G
        Sequence mjr = | I IV V I |

        Note: lowercase = minor: ii=Dm, vi=Am
        Sequence mix = | ii V7 I |
    }
}
Open in playground

Roman Numeral Reference

NumeralDegreeDefault Quality
I / i1st (tonic)Major / minor
II / ii2nd (supertonic)Major / minor
III / iii3rd (mediant)Major / minor
IV / iv4th (subdominant)Major / minor
V / v5th (dominant)Major / minor
VI / vi6th (submediant)Major / minor
VII / vii7th (leading)Major / minor

Uppercase = major, lowercase = minor. Extensions like V7 add a dominant 7th.

Resolving Numerals Programmatically

use "@std"

Chord v = (resolveNumeral "V" "Cmajor")
(print (str v))      Note: G major

Chord v7 = (resolveNumeral "V7" "Cmajor")
(print (str v7))     Note: G dominant 7th
Open in playground

Chord Progressions with Voice Leading

For smoother voice leading between chords, use the dedicated progression expression:

use "@std"

key Cmajor {
    Sequence chords = progression | I IV V I |
    Sequence thick  = progression voices 4 | I:2 IV vi V:2 |
}
Open in playground

See Chord Progressions for the full reference, including bar-count suffixes, voice counts, and voice-leading behavior.

Arpeggios

Generate arpeggiated sequences from chords. The 2-arg form takes a direction string and emits eighth notes:

use "@std"

Sequence up     = (arpeggio Cmaj "up")
Sequence down   = (arpeggio Cmaj "down")
Sequence updown = (arpeggio Cmaj "updown")
Open in playground

The 4-arg form gives full control over rate, direction, and pattern:

use "@std"

Note: rate is a NoteValue (q, e, s, etc. as keywords), direction is up/down/updown/downup/random,
Note: pattern is linear/chord-tone/scale-tone
Sequence triplets = (arpeggio Cmaj7 q "updown" "linear")
Sequence rolling  = (arpeggio Cmaj7 s "down" "linear")
Open in playground

downup and random are accepted today; chord-tone and scale-tone currently behave the same as linear (placeholders for future expansion).

Chord Inversions and Voicings

Invert a chord by rotating its lowest N notes up an octave each:

use "@std"

Chord triad = Cmaj                          Note: C4 E4 G4
Chord first = (inversion triad 1)           Note: E4 G4 C5
Chord second = (inversion triad 2)          Note: G4 C5 E5
Open in playground

Apply a named voicing for richer textures (jazz comping, open spacing, etc.):

use "@std"

Chord shell = Cmaj7

Chord drop2  = (voicing shell "drop2")      Note: lower the 2nd-from-top note an octave
Chord drop3  = (voicing shell "drop3")      Note: lower the 3rd-from-top note an octave
Chord open   = (voicing shell "open")       Note: raise the middle note an octave (wider)
Chord close  = (voicing shell "close")      Note: collapse to within one octave of root
Chord spread = (voicing shell "spread")     Note: raise the highest note another octave
Open in playground

Voicings whose minimum-note requirement isn’t met (drop2/drop3 need ≥4 notes; spread/open/close need ≥3) return the input unchanged — no error, no warning. Same for out-of-range inversion indices.

Scale Operations

Get the note names of any scale:

use "@std"

String[] cMajor = (scaleNotes "Cmajor")      Note: 7 notes
String[] aMinor = (scaleNotes "Aminor")      Note: 7 notes
(print (str cMajor))
Open in playground

Scales are useful for constraining diatonic mutation with vary:

Sequence varied = (vary mel 0.3 "pitch" "Cmajor")
Open in playground

See Generative Music.

Chord Bracket Notation (Custom Voicings)

For custom voicings not limited to standard shapes, use bracket notation in a note stream:

timesig 4/4 {
    Sequence custom = | [C4 E4 G4]q [D4 F4 A4]q [E4 G4 B4]q [C4 E4 G4]q |
}
Open in playground

Section Query Functions

use "@std"

section intro { Sequence mel = | C4 E4 G4 C5 | }
section verse { Sequence mel = | E4 F4 G4 A4 | }

Song mySong = [intro verse]

String[] sections = (getSections mySong)
(print (str sections))               Note: ["intro", "verse"]

String[] seqs = (sectionSequences intro)
(print (str seqs))                   Note: ["mel"]
Open in playground

See Also