Skip to content

Audio analysis

nari.analyze measures a song, for smart playlists, mixes or your own visuals:

nari.analyze(song, { bpm = true, key = true }, function(result, problem)
if result then
nari.log(song.title, result.bpm, result.key, result.camelot)
end
end)

song is a song table (Nari finds its file or stream the same way the player does), or a path, URL or scheme:id. Leave the options out to get everything.

Option Result
bpm = true bpm (tempo, 60 to 200) and confidence (0 to 1).
key = true key, like "A minor", and camelot, like "8A", for harmonic mixing.
loudness = true loudness = { integrated, range, peak }: EBU R128 loudness in LUFS, loudness range in LU and sample peak in dBFS.
waveform = 200 waveform: that many peaks between 0 and 1 (true gives 200).

The work runs in the background and only reads the first 10 minutes. Results are cached per file, so asking again is instant.

In background threads, nari.analyze(path, options) blocks and returns result, problem directly. Pass it a path or URL:

-- a playlist of songs between 120 and 130 BPM
local picks = {}
for _, path in ipairs(paths) do
local result = nari.analyze(path, { bpm = true })
if result and result.bpm >= 120 and result.bpm <= 130 then
table.insert(picks, path)
end
end