-
Notifications
You must be signed in to change notification settings - Fork 0
Song Structure
Flow provides section declarations and Song expressions to organize music into named parts with an arrangement order.
A section is a named block of musical code containing one or more sequences:
section intro {
Sequence melody = | C4 E4 G4 C5 |
}
Sections can contain multiple sequences (e.g., a lead melody and a bass line):
section verse {
Sequence lead = | E4 E4 F4 G4 |
Sequence bass = | C3 C3 G3 G3 |
}
Sections can be empty (useful for rests or structural placeholders):
section bridge {
}
Sections inherit the musical context they're declared in:
key Cmajor {
section outro {
Sequence melody = | I IV V I |
}
}
A Song arranges sections in order using bracket syntax:
section intro { Sequence mel = | C4 E4 G4 C5 | }
section verse { Sequence mel = | E4 E4 F4 G4 | }
section chorus { Sequence mel = | G4 A4 G4 E4 | }
Song mySong = [intro verse chorus]
(print (str mySong))
Use *N to repeat a section:
Song mySong = [intro verse*2 chorus verse chorus*2]
This plays: intro, verse, verse, chorus, verse, chorus, chorus.
Get the section names from a song:
use "@std"
Strings sections = (getSections mySong)
(print (str sections)) Note: ["intro", "verse", "chorus"]
Get the sequence names within a section:
use "@std"
section mySection {
Sequence lead = | C4 D4 E4 F4 |
Sequence bass = | C3 G3 C3 G3 |
}
Strings seqs = (sectionSequences mySection)
(print (str seqs))
Convert a song or section to its string representation:
use "@std"
(print (str mySong))
Use renderSong to convert a Song to an audio Buffer:
use "@std"
use "@audio"
tempo 120 {
timesig 4/4 {
key Cmajor {
section intro {
Sequence melody = | C4 E4 G4 C5 |
}
section chorus {
Sequence melody = | I IV V I |
}
Song song = [intro chorus]
Buffer buf = (renderSong song "piano")
(exportWav buf "song.wav")
}
}
}
The second argument to renderSong selects the synthesizer:
| Name | Aliases | Character |
|---|---|---|
| Piano | "piano" |
Percussive attack with warm decay |
| Brass |
"brass", "horn"
|
Bold, sustained tone |
| Saxophone |
"sax", "saxophone"
|
Reed-like character |
| Flute | "flute" |
Pure, breathy tone |
| Organ | "organ" |
Sustained, multi-partial timbre |
| Strings | "strings" |
Smooth bowed-instrument-like timbre |
| Bell | "bell" |
Inharmonic bell / chime character |
| Drums |
"drums", "drum"
|
Percussive, pitched drums |
| Sine | "sine" |
Clean sine wave |
Custom wavetables registered via oscillator(name, ...) also work here. You can also pass a Flow Function as a custom instrument — see Audio and Synthesis.
use "@std"
use "@audio"
tempo 120 {
timesig 4/4 {
key Cmajor {
section intro {
Sequence melody = | C4 E4 G4 C5 |
}
section verse {
Sequence lead = | E4 E4 F4 G4 |
Sequence bass = | C3 C3 G3 G3 |
}
section chorus {
Sequence lead = | G4 A4 G4 E4 |
}
section bridge {
Sequence mel = | A4 G4 F4 E4 |
}
section outro {
Sequence melody = | I IV V I |
}
Song fullSong = [intro verse*2 chorus bridge outro]
Buffer rendered = (renderSong fullSong "piano")
Buffer final = rendered -> fadeIn 0.3 -> fadeOut 0.5
(exportWav final "full_song.wav")
(print "Song exported!")
}
}
}
- Organizing composition: Break music into logical parts (intro, verse, chorus, bridge, outro)
-
Reuse: Reference the same section multiple times with
*Nrepeats - Clarity: Named sections make the arrangement readable at a glance
A Song can also be exported to a Standard MIDI File, preserving tempo, time signature, and key:
(writeMidi "my_song.mid" fullSong)
See Playback and Export.
- Note Streams - Writing sequences within sections
- Musical Context - Context blocks around sections
- Audio and Synthesis - Rendering and synthesizers
- Voices and Tracks - Lower-level multi-track rendering
- Chord Progressions - Voice-led chord sequences
- Playback and Export - Playing and exporting songs