local pulse = require("pulse")
local title = "mini-symphony"
local bpm = 92.0
local beat = 60.0 / bpm
local export_options = {
sample_rate = 44100,
normalize = "rms",
target_db = -18.0,
true_peak_db = -1.0,
midi_velocity_gain = 2.0,
midi_min_velocity = 0.62,
}
local function rep(value, count)
local values = {}
for index = 1, count do
values[index] = value
end
return values
end
local function degree(scale, value)
local unique = #scale - 1
local zero = value - 1
local octave = math.floor(zero / unique)
local position = (zero % unique) + 1
return pulse.transpose(scale[position], octave * 12)
end
local function line(scale, degrees)
local notes = {}
for index, value in ipairs(degrees) do
notes[index] = degree(scale, value)
end
return notes
end
local function voicing(root, kind, shifts)
local source = pulse.chord(root, kind)
local chord = {}
for index, shift in ipairs(shifts) do
chord[index] = pulse.transpose(source[((index - 1) % #source) + 1], shift)
end
return chord
end
local d_minor = pulse.scale("D4", "minor")
local f_major = pulse.scale("F4", "ionian")
local a_phrygian = pulse.scale("A3", "phrygian")
local d_bass = pulse.scale("D2", "minor")
local exposition = pulse.phrase()
:add(
pulse.sequence()
:chords({
voicing("D3", "min7", {0, 12, 0, 12}),
voicing("Bb2", "maj7", {0, 12, 0, 12}),
voicing("F3", "maj7", {0, 0, 12, 12}),
voicing("A2", "dominant7", {0, 12, 0, 12}),
})
:durations(rep(beat * 2.0, 4))
:instrument("strings")
:volume(0.58)
:pan(-0.16)
:velocity(0.5)
:effect("chorus", "wide")
)
:add(
pulse.sequence()
:notes(line(d_minor, {1, 3, 5, 6, 8, 10, 8, 6, 5, 4, 3, 5, 6, 8, 10, 12}))
:durations(rep(beat / 2.0, 16))
:instrument("flute")
:volume(0.36)
:pan(0.24)
:velocity(0.48)
:at(beat)
:effect("reverb", "hall")
)
:add(
pulse.sequence()
:notes(line(d_bass, {1, 5, 1, 5, 6, 3, 5, 1}))
:durations(rep(beat, 8))
:instrument("double_bass")
:volume(0.64)
:pan(-0.28)
:velocity(0.62)
)
:repeat_times(2)
local development = pulse.phrase()
:add(
pulse.sequence()
:chords({
voicing("A2", "minor", {0, 12, 0}),
voicing("G2", "minor", {0, 12, 0}),
voicing("F2", "maj7", {0, 12, 0, 12}),
voicing("E2", "dim", {0, 12, 0}),
})
:durations(rep(beat * 2.0, 4))
:instrument("slow_strings")
:volume(0.62)
:pan(0.0)
:velocity(0.56)
:effect("reverb", "chamber")
)
:add(
pulse.sequence()
:notes(line(a_phrygian, {1, 2, 4, 5, 7, 8, 10, 8, 7, 5, 4, 2, 1, 2, 4, 5}))
:durations(rep(beat / 2.0, 16))
:instrument("oboe")
:volume(0.38)
:pan(-0.24)
:velocity(0.48)
:at(beat / 2.0)
:effect("delay", { time = beat, feedback = 0.18, mix = 0.14 })
)
:add(
pulse.sequence()
:notes(line(d_bass, {5, 5, 4, 4, 3, 3, 2, 2}))
:durations(rep(beat, 8))
:instrument("cello")
:volume(0.58)
:pan(0.18)
:velocity(0.58)
)
:repeat_times(2)
local fanfare = pulse.phrase()
:add(
pulse.sequence()
:chords({
voicing("F3", "maj7", {0, 0, 12, 12}),
voicing("C3", "dominant7", {0, 0, 12, 12}),
voicing("D3", "min7", {0, 0, 12, 12}),
voicing("A2", "dominant7", {0, 12, 0, 12}),
})
:durations(rep(beat * 2.0, 4))
:instrument("brass_section")
:volume(0.66)
:pan(0.08)
:velocity(0.7)
:effect("compressor", "gentle")
)
:add(
pulse.sequence()
:notes(line(f_major, {8, 10, 12, 13, 12, 10, 8, 6, 5, 6, 8, 10, 12, 10, 8, 5}))
:durations(rep(beat / 2.0, 16))
:instrument("violin")
:volume(0.46)
:pan(-0.16)
:velocity(0.56)
:effect("reverb", "plate")
)
:add(
pulse.sequence()
:notes(line(d_bass, {1, 1, 5, 5}))
:durations(rep(beat * 2.0, 4))
:instrument("timpani")
:volume(0.52)
:pan(0.0)
:velocity(0.76)
)
:repeat_times(2)
local coda = pulse.phrase()
:add(
pulse.sequence()
:chords({
voicing("D3", "min7", {0, 12, 0, 12}),
voicing("G2", "minor", {0, 12, 0}),
voicing("A2", "dominant7", {0, 12, 0, 12}),
voicing("D3", "minor", {0, 0, 12}),
})
:durations(rep(beat * 2.0, 4))
:instrument("strings")
:volume(0.54)
:velocity(0.5)
)
:add(
pulse.sequence()
:notes(line(d_minor, {8, 7, 6, 5, 4, 3, 2, 1}))
:durations(rep(beat, 8))
:instrument("flute")
:volume(0.32)
:pan(0.22)
:velocity(0.42)
)
local song = pulse.song()
:tempo(bpm)
:add_phrase(exposition)
:add_phrase(development)
:add_phrase(fanfare)
:add_phrase(coda)
:master_effect("reverb", "cathedral")
:master_effect("eq", "bright")
:master_effect("limiter", "standard")
assert(title == "mini-symphony")
song:export_wav("output/mini-symphony.wav", export_options)
song:export_midi("output/mini-symphony.mid", export_options)