mlua-pulse 0.1.0

Lua-friendly music composition and audio export bindings built on tunes and mlua
Documentation
local pulse = require("pulse")

local available_effects = pulse.effects()
assert(#available_effects >= 8)

local bpm = 120.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.6,
}

local function rep(value, count)
  local values = {}
  for index = 1, count do
    values[index] = value
  end
  return values
end

local chords = pulse.sequence()
  :chords({
    pulse.chord("C3", "min7"),
    pulse.chord("Ab2", "maj7"),
    pulse.chord("Eb3", "maj7"),
    pulse.chord("Bb2", "dominant7"),
  })
  :durations(rep(beat * 2.0, 4))
  :instrument("supersaw")
  :volume(0.5)
  :pan(-0.08)
  :velocity(0.52)
  :effect("filter", { type = "low_pass", cutoff = 1800.0, resonance = 0.4 })
  :effect("chorus", "wide")
  :effect("delay", { time = beat * 0.75, feedback = 0.35, mix = 0.3 })

local lead = pulse.sequence()
  :notes({
    pulse.scale("C4", "minor")[5], pulse.scale("C4", "minor")[6], pulse.scale("C4", "minor")[8], pulse.transpose(pulse.scale("C4", "minor")[3], 12),
    pulse.scale("C4", "minor")[8], pulse.scale("C4", "minor")[6], pulse.scale("C4", "minor")[5], pulse.scale("C4", "minor")[3],
  })
  :durations(rep(beat / 2.0, 8))
  :instrument("saw_lead")
  :volume(0.42)
  :pan(0.24)
  :velocity(0.6)
  :at(beat)
  :effect("phaser", "subtle")
  :effect("reverb", "plate")

local bass = pulse.sequence()
  :notes({pulse.chord("C2", "minor")[1], pulse.chord("C2", "minor")[3], pulse.chord("Ab1", "major")[1], pulse.chord("Ab1", "major")[3],
          pulse.chord("Eb2", "major")[1], pulse.chord("Eb2", "major")[3], pulse.chord("Bb1", "major")[1], pulse.chord("Bb1", "major")[3]})
  :durations(rep(beat, 8))
  :instrument("sub_bass")
  :volume(0.8)
  :pan(0.0)
  :velocity(0.82)
  :effect("compressor", "bass")

local beat_grid = pulse.drum_machine("808")
  :steps(16)
  :step_duration(beat / 4.0)
  :kick("x---x---x-xxx---")
  :snare("----x-------x---")
  :hihat("x-x-xxx-x-x-xxxx")
  :open_hihat("--x---x---x---x-")
  :clap("----x-------x---")
  :grid()
  :repeat_times(1)
  :volume(0.74)
  :effect("compressor", {
    threshold = 0.6,
    ratio = 4.0,
    attack = 0.01,
    release = 0.08,
    makeup_gain = 1.0,
  })

local song = pulse.song()
  :tempo(bpm)
  :add(chords)
  :add(lead)
  :add(bass)
  :add_drum_grid(beat_grid)
  :master_effect("reverb", "hall")
  :master_effect("eq", { low_gain = 1.04, mid_gain = 0.95, high_gain = 1.12 })
  :master_effect("limiter", "standard")

song:export_wav("output/effects-chain.wav", export_options)
song:export_flac("output/effects-chain.flac", export_options)