local pulse = require("pulse")
local bpm = 104.0
local beat = 60.0 / bpm
local export_options = {
sample_rate = 44100,
normalize = "rms",
target_db = -16.0,
true_peak_db = -1.0,
midi_velocity_gain = 1.8,
midi_min_velocity = 0.58,
}
local function rep(value, count)
local values = {}
for index = 1, count do
values[index] = value
end
return values
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 function sequence(notes, durations, instrument, volume, pan, velocity, at)
local part = pulse.sequence()
:notes(notes)
:durations(durations)
:instrument(instrument)
:volume(volume)
:pan(pan)
:velocity(velocity)
if at then
part = part:at(at)
end
return part
end
local function chord_sequence(chords, duration, instrument, volume, pan, velocity, at)
local part = pulse.sequence()
:chords(chords)
:durations(rep(duration, #chords))
:instrument(instrument)
:volume(volume)
:pan(pan)
:velocity(velocity)
if at then
part = part:at(at)
end
return part
end
local harmony = chord_sequence({
voicing("C3", "maj7", {0, 12, 0, 12}),
voicing("A2", "min7", {0, 12, 0, 12}),
voicing("F2", "maj7", {0, 12, 0, 12}),
voicing("G2", "dominant7", {0, 12, 0, 12}),
}, beat * 2.0, "electric_piano", 0.74, -0.18, 0.68)
:effect("chorus", "subtle")
:effect("reverb", "room")
local bass = sequence({
voicing("C2", "major", {0})[1],
voicing("C2", "major", {7})[1],
voicing("A1", "minor", {0})[1],
voicing("A1", "minor", {7})[1],
voicing("F1", "major", {0})[1],
voicing("F1", "major", {7})[1],
voicing("G1", "major", {0})[1],
voicing("G1", "major", {7})[1],
}, rep(beat, 8), "picked_bass", 0.86, -0.08, 0.78)
local motif = sequence(
{pulse.scale("C4", "ionian")[3], pulse.scale("C4", "ionian")[5], pulse.scale("C4", "ionian")[6], pulse.scale("C4", "ionian")[8],
pulse.scale("A3", "minor")[3], pulse.scale("A3", "minor")[5], pulse.scale("A3", "minor")[6], pulse.scale("A3", "minor")[8],
pulse.scale("F4", "lydian")[2], pulse.scale("F4", "lydian")[4], pulse.scale("F4", "lydian")[6], pulse.scale("F4", "lydian")[8],
pulse.scale("G3", "mixolydian")[5], pulse.scale("G3", "mixolydian")[7], pulse.scale("G3", "mixolydian")[8], pulse.scale("G3", "mixolydian")[7]},
rep(beat / 2.0, 16),
"synth_lead",
0.42,
0.22,
0.56,
beat / 2.0
):effect("delay", { time = beat * 0.75, feedback = 0.28, mix = 0.2 })
local beat_grid = pulse.drum_machine("808")
:steps(16)
:step_duration(beat / 4.0)
:kick("x---x-----x-x---")
:snare("----x-------x---")
:hihat("x-x-x-xxx-x-x-xx")
:clap("----x-------x---")
:grid()
:repeat_times(1)
:volume(0.74)
:pan(0.0)
:effect("compressor", "drum_bus")
pulse.song()
:tempo(bpm)
:add(harmony)
:add(bass)
:add(motif)
:add_drum_grid(beat_grid)
:master_effect("eq", "warm")
:master_effect("limiter", "transparent")
:export_wav("output/foundation-loop.wav", export_options)