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 in all contexts — including inside note streams. Use Gdom7 for the dominant 7th 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: ["C4", "E4", "G4", "B4"]
(print $"root: {root}, quality: {quality}, count: {notes -> len}")
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. A chord with a letter-bearing quality (maj7, m7, dim7, sus4, m, …) fuses directly with the duration letter — Cmaj7q — just like a note literal. The space-separated form also works and is required for chords whose quality is a bare digit (Gdom7, C6):

timesig 4/4 {
    Note: fused — letter-quality chord + duration
    Sequence fused = | Cmaj7q Am7q Dm7h Fsmaj7h |

    Note: space-separated — works for any chord, required for bare-digit qualities
    Sequence spaced = | Cmaj7 q Am7 q Gdom7 h Dsus4 h |
}
Open in playground

Bare-digit chords don’t fuse. G7, Bb7, and C6 parse as a note + octave (so Bb7q is the note Bb7 as a quarter, not the Bb dominant 7th — see the warning at the top of this page). When you mean the chord, use a letter-quality spelling (Gdom7, Bfdom7) so it fuses, or write the dominant explicitly.

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. Rate is a NoteValue constant from @notation (QUARTER, EIGHTH, SIXTEENTH, etc.) — bare q/e/s are only valid as duration suffixes inside note streams:

use "@std"
use "@notation"

Note: direction is up/down/updown/downup/random; pattern is linear/chord-tone/scale-tone
Sequence triplets = (arpeggio Cmaj7 QUARTER "updown" "linear")
Sequence rolling  = (arpeggio Cmaj7 SIXTEENTH "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:

Note: snippet - not standalone; mel must be defined first, e.g.: Sequence mel = | C4 D4 E4 F4 G4 |
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"]

Note: sectionSequences(Song, String) returns the sequence names of one named section.
String[] introSeqs = (sectionSequences mySong "intro")
(print (str introSeqs))              Note: ["mel"]
Open in playground

See Also