ode, the song format
ode, the language a Songcode track is written in. The first line, the plan at the top, stems, the arrange table, blocks that change a stem for part of the track, the mix table and how it changes through a track, lyrics and score blocks.
A track is a short text file written in ode, Songcode’s language for a song. The current version is ode 0.3.0. Anyone who writes ode is an odist, and Songcode, which wrote the language, is the greatest odist of all. This page is its reference: what each part of a track is for and the rules the app holds it to. Rows and settings covers what goes inside a stem.
#The shape of a track
A track has three parts, and no fact is written twice.
- Stems say what each instrument plays.
- The arrange table says where in the track each stem plays.
- The mix table says how loud each stem is, where it sits from left to right, and where in the track either one changes.
Above them sits the plan: the tempo, the key, the sections and the chords.
#A whole loop
This is one of the worked examples the model is shown, complete.
ode
title "night bus"
tempo 124
key a minor
swing 56%
form loop 8
chords [Am9 % Fmaj7 Em7]
stem kick: analog {
kick [x... x... x... x...]
}
stem hats: analog {
hat [xxxx xxxx xxxx xxxx]
openhat [..x. ..x. ..x. ..x.]
velocity [100 38 62 44]
chance 88%
highpass 420hz
bar 8 of 8 {
hat [xxxx xxxx xx22 2222]
}
}
stem clap: analog {
clap [.... x... .... x...]
behind 8ms
highpass 260hz
reverb 30%
}
stem bass: pulsebass {
rhythm [x.xx .x.x x.xx .x..]
tones [root]
octave 1
velocity [112 70 84 70]
lowpass sweep(320hz, 1.5khz, every: 8bars), resonance: 35%
}
stem stab: dubchord {
rhythm [.... x... .... ..x.]
tones [all]
octave 3
highpass 330hz
reverb 45%, tone: 4.2khz
delay 30%, time: 3/16
}
stem perc: clave {
rhythm [..x. .x.. x... .x..]
take [0 2 1 3]
chance 60%
highpass 700hz
}
mix {
kick 0db
hats -10db, pan: 15R
clap -7db
bass -4db
stab -8db, pan: 10L
perc -14db, pan: 30R
duck bass, stab under kick, depth: 75%, recover: 110ms
}
#How it is written
ode has one grammar, and anything outside it is an error.
| piece | rule | example | |
|---|---|---|---|
| first line | Exactly ode. | ode | |
| statement | Starts with a word and ends at the end of the line. | tempo 126 | |
| block | A statement that opens { and holds statements until }. | stem bass: fmbass { } | |
| row | Music, between [ and ]. `\ | ` ends a bar. A row may run over several lines. | [x... x... x... x...] |
| quantity | A number with its unit attached, no space. | 400hz 8ms -6db 30% 16bars | |
| detail | Follows a setting after a comma, as name: value. | reverb 40%, decay: 6s | |
| name | Lowercase letters, digits and _. You name stems, sections, phrases and groups. | bass verse_2 | |
| text | In double quotes. Only titles and lyrics. | "glass elevator" | |
| comment | // to the end of the line. | // drop |
A track declares music and runs nothing. There are no loops, no conditions and no functions of your own, so opening someone’s track never runs their code.
#The first line
ode
The first line says the track is written in ode. Every track Songcode writes starts with it, and a track that starts with anything else does not open.
The line can also name a version of ode, as in ode 0.3.0. That is optional: ode alone reads as the newest version the engine knows, and it is what Songcode writes. Name a version when a track has to say which ode it needs, so an older engine says plainly that it cannot read it instead of tripping over a word it does not know. Tracks saved before ode was versioned start with ode 1, and they still open and play as they always have. See versions.
#The plan
title "glass elevator"
tempo 126
key f minor
swing 54%
form intro 8, build 8, main 16, break 8, peak 16, outro 8
chords [Fm9 % Dbmaj7 Eb6]
The top of a track is its plan. Everything below is checked against it.
| statement | what it sets |
|---|---|
title "glass elevator" | The track’s name. |
tempo 126 | The speed, in beats a minute. A beat is a quarter note, or a dotted quarter in 6/8, 9/8 and 12/8. |
meter 3/4 | The time signature, for the whole track. Left out, it is 4/4. |
key f minor | The tonic and the scale. Scale steps and chord tones are worked out from it. |
tuning e -50cents, b -50cents | Moves those notes, in every octave and on every pitched stem, away from equal temperament, by up to 100 cents either way. Quarter tones, pure thirds and tunings from outside the piano are written this way. Left out, the track is in equal temperament. |
swing 54% | The track’s swing. See swing. |
loose 8ms | How far each note may land from where it is written, for every stem. Left out, the track is on the grid. See swing and feel. |
seed 7 | The number that chance, humanize and loose draw from. The same seed gives the same track every time. |
allow range | Lets every stem break a rule of what a person can play: range, reach, hands, breath, speed, or all. A stem can say it for itself instead. |
form … | The sections in order, with their lengths in bars. |
chords […] | The chord chart. |
The scales are major, minor, dorian, phrygian, lydian, mixolydian, locrian, harmonic minor, melodic minor, major pentatonic, minor pentatonic, blues, whole tone and chromatic.
A wider set covers jazz and scales from outside the western seven: harmonic major, major blues, diminished, half whole diminished, altered, lydian dominant, bebop, phrygian dominant, double harmonic major, hungarian minor, neapolitan minor, persian, hirajoshi, in sen, iwato, kumoi, pelog, egyptian, prometheus, augmented and enigmatic.
An odd meter names how its beats group, and rhythm rows are grouped the same way:
meter 7/8, beats: 2+2+3
#The form
form intro 8, verse 16, chorus 8, verse 16, chorus 8, outro 8
form lists the track’s sections in order, each as a name and a length in bars. The total is the length of the track. Section names are free: whatever fits the music.
- A loop has one section,
form loop 8, and repeats at exactly that length. - A full track has several. The app shows their names along the timeline.
- A name used twice is the same section played again, so a chorus is written once.
in chorus 2 { }then changes only the second one: in a stem, in the mix, or at the top of the track for its chords and key.
Bar numbers inside a section count from the start of that section. Moving a section never renumbers its music.
#The chords
chords [Fm9 % Dbmaj7 Eb6]
The chord chart is written the way a lead sheet writes it.
|ends a bar.%repeats the bar before.- Chords that share a bar split it evenly, and
-holds the chord before it. - The chart starts again when it runs out, for as long as its section lasts.
Chord names are the ones on a lead sheet: Fm9, Dbmaj7, C7, Gsus4, Bdim, Ab/C.
The chart is what keeps a track in one key. A bass written as tones [root] and a pad written as tones [all] both read it, so changing one chord here changes every stem that follows it.
A section can have its own chords or its own key:
in break {
chords [Dbmaj7 % Bbm9 C7]
}
in chorus 2 {
key g minor
}
in chorus 2 is the second time the chorus comes.
#Stems
stem bass: fmbass {
rhythm [x.x. ..x. x... ..xx]
tones [root]
octave 1
lowpass 700hz, resonance: 20%
}
A stem is one instrument: the word stem, a name, a sound from the catalog, and a block. Inside the block come the rows that say what it plays, then its settings, then any blocks that change it for part of the track.
Because each stem stands alone, the app can mute, redraw or regenerate one without touching the rest.
A stem carries its music in one of three ways:
- Lanes, on a drum kit: one row per drum.
- A rhythm and a pitch row, for parts that repeat: basslines, stabs, pads, arpeggios.
- A line, for melodies and anything written note by note.
Rows and settings covers all three.
Rules for names:
- Lowercase letters, digits and underscores.
- Name a stem for what it is. The app recognises 15 roles from the name: kick, snare, clap, hats, perc, bass, sub, chords, stab, lead, arp, pad, vocal, texture, fx. See roles.
- Each name is used once.
#The arrange table
form intro 8, verse 16, chorus 8, verse 16, chorus 8, outro 8
arrange {
sections [intro verse chorus verse chorus outro]
kick [. x x x x .]
bass [. x x x x x]
keys [x . x x x x]
lead [. . x . x .]
lift [. 4 . 4 . .]
}
Where each stem plays is one table: a row per stem and a column per section, in the order the form lists them. A section that comes twice has two columns, so the second verse can carry more than the first.
| mark | what it means |
|---|---|
x | The stem plays in that section. |
. | The stem rests. |
| a number | The stem plays only the last that many bars. This is for risers, rolls and pickups. |
A stem with no row plays through the whole track. A loop needs no arrange table.
#Blocks
A block inside a stem changes it for part of the track. A row in the block replaces the stem’s row of the same name there, and a setting replaces that setting. A line in a block takes the whole part over from the stem’s rhythm and pitch rows, and a rhythm takes it over from a line, so one stem can loop a figure in the verse and play a written melody in the break.
stem hats: club {
hat [xx.x xx.x xx.x xx.x]
highpass 400hz
in intro, outro {
chance 55%
lowpass 4khz
}
last 1bar into main, peak {
hat [xx.x xx.x xx.x 2222]
}
}
| block | what it covers |
|---|---|
in intro, outro { } | Those sections. in verse 2 { } is only the second verse. |
last 1bar into main, peak { } | The last bar before those sections begin. This is how fills, drops and a bar of silence are written. |
last 2bars into end { } | The last bars of the track. end is the end of the song: an ending, a last hit, a fade. A loop has no end, so it takes bar … of. |
bar 8 of 8 { } | The 8th bar of every 8. bars 7..8 of 8 covers the last two, and bars 9..16 of 16 gives the second half of a section its own rows. A line in there may open with its bar number, 9:. |
A block may also hold one of a few moves:
| move | what it does |
|---|---|
silent | The stem plays nothing. One bar of it before a drop is the most used. |
ratchet 2 | Every hit is doubled. |
halftime doubletime | The row plays at half or twice its speed. |
reverse | The row plays backwards. |
shift 2 | The row plays two steps later. |
transpose 12st octave 5 | The stem moves up or down. |
When several blocks touch the same bar, the most specific wins: last … into beats bar … of, which beats in, which beats the stem’s own lines.
#A whole full track
The second worked example the model is shown.
ode
title "glass elevator"
tempo 126
key f minor
swing 54%
form intro 8, build 8, main 16, break 8, peak 16, outro 8
chords [Fm9 % Dbmaj7 Eb6 Fm9 % Bbm7 C7]
in break {
chords [Dbmaj7 % Bbm9 % Gm7b5 % C7sus4 C7]
}
in peak {
chords [Fm9 Abmaj7 Dbmaj7 Eb6 Fm9 Abmaj7 Bbm7 C7]
}
in outro {
chords [Fm9 % Dbmaj7 % Fm9 % % %]
}
// the theme and its answer: hinted in the build, stated in main, slowed down in the break, developed at the peak
let theme = line [c5/8 r ab4 c5/4 bb4/8 ab4/4 g4/4. ab4/8 f4/2]
let answer = line [ab4/8 r ab4 bb4/4 c5/8 bb4/4 g4/4. bb4/8 g4/2]
let turn = line [db5/4 f5/8 db5 bb4/4 db5 c5/2 e4/4 g4]
arrange {
sections [intro build main break peak outro]
kick [x x x . x x]
clap [. x x . x .]
hats [x x x . x x]
bass [. x x . x x]
keys [. x x x x x]
motif [. x x . . x]
pad [. . . x x x]
lead [. . . . x .]
lift [. 4 . 4 . .]
}
stem kick: club {
kick [x... x... x... x...]
bar 8 of 8 {
kick [x... x... x... x.x.]
}
last 1bar into main { silent }
last 2bars into end { silent }
}
stem clap: club {
clap [.... x... .... x...]
behind 8ms
reverb 25%
last 1bar into peak {
clap [.... x... ..x. x.xx]
}
}
stem hats: club {
hat [xx.x xx.x xx.x xx.x xx.x xx.x xx.x xxxx]
openhat [..x. ..x. ..x. ..x. ..x. ..x. ..x. ....]
velocity [100 40 65 45]
chance 90%
highpass 400hz
in intro, outro {
chance 55%
lowpass 4khz
}
in peak {
hat [xxxx xxxx xxxx xxxx xxxx xxxx xxxx xx.x]
}
last 1bar into main, peak {
hat [xx.x xx.x xx.x 2222]
}
last 2bars into end { silent }
}
stem bass: fmbass {
rhythm [xxxx xxxx xxxx xxxx]
tones [root]
octave 1
velocity [110 60 85 60]
lowpass sweep(300hz, 1.2khz, every: 16bars), resonance: 30%
in build {
lowpass 500hz
}
in peak {
rhythm [x.xx x.xx x.xx x.xx]
tones [1 1 1' 1 1 1' 1 1 1' 1 1 1']
}
bar 8 of 8 {
rhythm [xxxx xxxx x.x. x.x.]
tones [1 1 1 1 1 1 1 1 3 2 1' 3]
}
last 2bars into end {
rhythm [x -]
tones [root]
}
}
stem keys: reedpiano {
rhythm [x... ..x. .... ..x.]
tones [all]
octave 3
voicing smooth
highpass 320hz
phaser 0.4hz, depth: 40%
reverb 40%
delay 25%, time: 3/16, feedback: 40%
in break {
line [mp theme(slower) bb4/2 g4/4 bb4 db5/2. bb4/4 < c5/1 r/2 mf e4/4 g4]
reverb 70%
}
in outro {
rhythm [x]
}
}
stem motif: synthpluck {
line [theme answer theme turn]
delay 30%, time: 3/16, feedback: 35%
reverb 30%
in build {
line [theme(first 4) r/8 r/4 r/1 r/1 r/1]
lowpass 1.4khz
}
in main {
bars 13..16 of 16 {
line [13: theme(up 2) turn]
}
}
in outro {
line [theme(first 4) r/8 r/4 r/1 theme(first 4, down 2) r/8 r/4 r/1]
}
}
stem pad: ensemble {
rhythm [x]
tones [all]
voicing smooth
attack 400ms
release 1.5s
highpass 240hz
chorus 35%
bell 400hz, gain: -3db, width: 1oct
reverb 60%, decay: 6s
in break {
lowpass ramp(500hz, 6khz)
}
}
stem lead: sawlead {
line [theme answer(up 2) theme(up 2) turn]
delay 30%, time: 3/16
bars 9..16 of 16 {
line [9: theme(up 1oct) answer(up 1oct) theme(first 1bar, up 1oct) theme(first 1bar, up 2) f5/4:bend db5/8 f5 bb5/4 f5 g5/2 e5/4 c5:fall]
}
}
stem lift: riser {
rhythm [x - - -]
highpass ramp(300hz, 9khz)
fade in
}
mix {
kick 0db
clap -7db
hats -10db, pan: 15R
bass -4db
keys -8db, pan: 10L
motif -9db, pan: 12R
pad -11db
lead -9db
lift -12db
duck bass, keys, pad under kick, depth: 75%, recover: 110ms
reverb decay: 1.8s, tone: 5khz
master ceiling: -1db
in break {
pad ramp(-17db, -11db)
keys -6db
}
in outro {
hats ramp(-10db, -16db)
motif ramp(-9db, -15db)
}
}
#The mix table
group drums: kick, clap, hats
mix {
kick 0db
clap -7db
hats -10db, pan: 15R
bass -4db
pad -11db, mute
drums -1db
duck bass, pad under kick, depth: 75%, recover: 110ms
reverb decay: 1.8s, tone: 5khz
}
The mix is one table at the end of the track.
| row | what it means |
|---|---|
hats -10db, pan: 15R | A stem’s level and pan. 0db is the sound at its catalog level. Pan runs from 50L to 50R, and C is the centre. |
pad -11db, mute | A muted stem keeps its level. |
drums -1db | A group’s level, on top of its stems’ own levels. A group is declared with group. |
duck bass, pad under kick | Those stems dip each time the kick plays. depth is how far and recover is how long they take to come back. |
reverb decay: 1.8s, tone: 5khz | The one reverb that every stem’s reverb amount feeds. |
The table and the stems view are the same thing. Dragging the bass fader rewrites bass -4db, and typing -6db moves the fader. Level and pan live only here. A stem that sets either is an error that says where they go.
Solo is not in the code. It is a way of listening, so it stays in the app.
#A mix that changes
The rows above are the track’s resting mix. Blocks under them change it for part of the track. They are the same three blocks a stem takes, and each holds rows.
group drums: kick, clap, hats
mix {
kick 0db
clap -7db
hats -10db, pan: 15R
bass -4db
pad -11db
voice -6db
in verse {
voice -8db
pad pan: ramp(30L, 30R)
}
in break {
pad ramp(-18db, -11db)
drums -3db
}
bar 8 of 8 {
hats mute
}
last 4bars into end {
master fade out
}
}
| row in a block | what it does |
|---|---|
voice -8db | The stem’s level for as long as the block lasts. It is the level itself, taking the place of the stem’s row there, so -8db against a row of -6db is 2 dB down. |
pad ramp(-18db, -11db) | A level that climbs or falls across the block. sweep(-14db, -9db, every: 2bars) goes there and back. |
pad pan: ramp(30L, 30R) | A pan that travels across the block. pan: 25L holds the stem there, and pan: sweep(40L, 40R, every: 4bars) goes from side to side. |
pad fade in pad fade out | Up from silence across the block, or down to it. |
hats mute | Silent for the block. |
drums -3db | A group’s row moves every stem in it together, on top of their own rows. |
master fade out | master is the whole mix. It takes a level, a ramp or a fade. |
A row names its stem, then the level if it has one, then pan:, fade in, fade out and mute, with commas between. Pan is set stem by stem, so a group and master take none. duck, reverb and master ceiling are set once for the track, above the blocks.
Where two blocks cover the same bar and name the same stem, the later one in the table wins, setting by setting: one can set the level while the other sets the pan.
These moves run through a note while it sounds. A pad held for eight bars fades and travels smoothly, where a filter ramp on a stem is read once at the start of each note.
A fader in the stems view writes the stem’s row above the blocks and leaves the blocks as they are.
#Lyrics
stem voice: alto {
line [r/4 g4/8 g4 a4/4 b4 c5/2 b4/4 r/4 r/4 a4/8 a4 b4/4 g4 e4/2. r/4]
lyrics 2bars {
"the river keeps its name"
"long after the rain"
}
reverb 30%
}
A vocal is a stem like any other: a singer as its sound, a melody as a line, and the words in a lyrics block.
- One syllable per note, in order.
- The length is how long each quoted line takes.
lyrics 2barssings the first line over two bars and the next line over the next two. - Sections get their own words with a block:
in chorus { lyrics 2bars { … } }. - A harmony is a second singer stem with its own line.
Inside the quotes, a few marks place the words:
| mark | what it does |
|---|---|
- | Splits a word into syllables: riv-er takes two notes. |
_ | Holds the syllable before for one more note. |
/k.ae.t/ | Spells a word in phonemes, for when a singer says it wrong. |
"~" | A line that is only ~ is a silent line. |
Lyrics are English. To hear a vocal in a generated track, ask for one in the prompt: “with a sung chorus about the last train home”. A track is instrumental unless the prompt asks for singing or lyrics.
#Score blocks
Music that never repeats is written a few bars at a time, with every part together.
ode
title "small minuet"
tempo 112
meter 3/4
key g major
form a 8
stem violin: violin {
reverb 30%
}
stem cello: cello {
reverb 25%
}
score a bars 1..4 {
violin [1: mf b4/4 d5/8 c5 b4 a4 g4/4 b4 d5 c5/4 e5/8 d5 c5 b4 a4/2 r/4]
cello [1: mp g2/2. b2/2 d3/4 c3/2. d3/2 d2/4]
}
score a bars 5..8 {
violin [5: b4/4 d5/8 c5 b4 a4 g4/4 e5 d5 c5/8 b4 a4/4 f#4 g4/2.]
cello [5: g2/2. e3/2 b2/4 c3/4 d3 d2 g2/2.]
}
- Each row is a stem’s name and a line. The stems are declared above the blocks with their sound and settings.
- Every row in a block holds the same number of bars, so bar 3 of the violin sits above bar 3 of the cello.
bars 5..8is checked against the bars written. Bar numbers start at 1 in each section.- A section’s blocks must cover the whole section between them. A stem with no row in a block rests for those bars, the way an instrument does in a printed score.
- A stem may have two rows in one block, which sound together: a piano’s right hand, then its left.
- A row can quote a theme, as it is or changed:
violin [1: theme | theme(up 2)]. This is how a written piece develops an idea without writing every note again.
The two ways of writing mix freely. A track can keep its drums as grids and write its melody as a line.
#Names for things you reuse
let clave = rhythm [x..x ..x. ..x. x...]
phrase hook {
line [g4/8 a4 c5/4 a4/8 g4 e4/4 d4/2 r/2]
}
stem rim: wood { rim clave }
stem lead: sawlead { play hook }
stem brass: synthbrass {
play hook
octave 3
}
| word | what it gives |
|---|---|
let | A named row that any stem can use. Change it once and every stem that uses it follows. A named line is a theme: other lines quote it, moved, cut, slowed or turned upside down. |
phrase and play | A named musical idea, played by more than one instrument. |
group | Stems under one level in the mix table. |
#What the app checks
A track is checked before you hear it, and every problem names its line.
- Unknown is an error. A word, a sound, a unit or a name the track does not define stops the track. Nothing is skipped in silence.
- Every count is checked. Steps in a bar, pitches in a bar, note lengths in a bar, bars in a section and marks in an arrange row all have to add up.
- Every sound is in the catalog.
See errors for what the messages look like.
#Tracks from earlier versions
A track made before ode does not start with ode and does not open. A file saved from an earlier version stays as it is on your disk.