mlua-pulse 0.1.0

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

local bpm = 118.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.9,
  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 verse = pulse.phrase()
  :add(
    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("electric_piano")
      :volume(0.62)
      :pan(-0.16)
      :velocity(0.58)
      :effect("chorus", "subtle")
  )
  :add(
    pulse.sequence()
      :notes({pulse.scale("C4", "minor")[1], pulse.scale("C4", "minor")[3], pulse.scale("C4", "minor")[5], pulse.scale("C4", "minor")[6],
              pulse.scale("Eb4", "ionian")[5], pulse.scale("Eb4", "ionian")[6], pulse.scale("Eb4", "ionian")[8], pulse.scale("Bb3", "mixolydian")[7]})
      :durations(rep(beat, 8))
      :instrument("mallet")
      :volume(0.42)
      :pan(0.22)
      :velocity(0.5)
      :at(beat)
  )
  :add_drum_grid(
    pulse.drum_machine("808")
      :steps(16)
      :step_duration(beat / 4.0)
      :kick("x---x-----x-x---")
      :snare("----x-------x---")
      :hihat("x-x-x-x-x-x-x-x-")
      :grid()
      :repeat_times(1)
      :volume(0.62)
  )
  :repeat_times(2)

local chorus = pulse.phrase()
  :add(
    pulse.sequence()
      :chords({
        pulse.chord("Ab2", "maj7"),
        pulse.chord("Bb2", "dominant7"),
        pulse.chord("C3", "min7"),
        pulse.chord("Eb3", "maj7"),
      })
      :durations(rep(beat * 2.0, 4))
      :instrument("supersaw")
      :volume(0.52)
      :pan(0.08)
      :velocity(0.56)
      :effect("filter", { type = "low_pass", cutoff = 3400.0, resonance = 0.2 })
      :effect("chorus", "wide")
  )
  :add(
    pulse.sequence()
      :notes({pulse.chord("Ab1", "major")[1], pulse.chord("Ab1", "major")[3], pulse.chord("Bb1", "major")[1], pulse.chord("Bb1", "major")[3],
              pulse.chord("C2", "minor")[1], pulse.chord("C2", "minor")[3], pulse.chord("Eb2", "major")[1], pulse.chord("Eb2", "major")[3]})
      :durations(rep(beat, 8))
      :instrument("bass_808")
      :volume(0.78)
      :velocity(0.84)
      :effect("compressor", "bass")
  )

local song = pulse.song()
  :tempo(bpm)
  :add_phrase(verse)
  :add_phrase(chorus)
  :master_effect("reverb", "room")
  :master_effect("limiter", "standard")

song:export_wav("output/phrase-arrangement.wav", export_options)
song:export_midi("output/phrase-arrangement.mid", export_options)