Skip to content

Repository files navigation

KANON — Audio Analysis Suite

Greek κανών: the measuring rod, and the name of the Pythagorean monochord — the one-stringed instrument used to measure musical intervals.

A desktop app that measures an album's tracks against your own reference tracks and writes self-contained HTML reports. Runs on macOS and Windows.

Measurements only. The reports state what was measured and how it differs from your references. They never interpret a number, rank it, or suggest a move — that is the engineer's job. Every metric carries a one-line plain-English note explaining what it measures and why anyone looks at it.

One ruler. Every figure comes from this tool at the version stamped in the report footer. Readings from other analysers are measured differently and will not line up; comparing across tools is how you end up chasing a number that was never the same number.


Download a build (no Python needed)

Every push builds KANON for Windows and macOS on GitHub Actions — neither platform can cross-compile the other's bundle, so each is built on its own runner. Grab the one for your machine from the latest release, or from the Artifacts section of the most recent run under the Actions tab if no release is tagged yet.

Download For
KANON-windows-x64.zip Windows 10/11. Unzip and keep the whole folder together; run KANON.exe inside it.
KANON-macos-apple-silicon.zip Macs with M1/M2/M3/M4.
KANON-macos-intel.zip Older Intel Macs.

Not sure which Mac? Apple menu → About This Mac. "Apple M-something" is Apple silicon; anything saying Intel takes the Intel download.

First launch on macOS. These builds are unsigned, so Gatekeeper refuses a plain double-click. Right-click the app → Open → Open — once only; after that it launches normally. If macOS still blocks it:

xattr -cr /path/to/KANON.app

Setup (running from source)

macOS

KANON needs Tk, and how you get it depends on which Python you have.

# If you use Homebrew Python, Tk is a separate package:
brew install python-tk

# The python.org installer bundles Tcl/Tk already — nothing extra needed.

python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
python -m app.main

Check Tk is present before anything else — python3 -m tkinter should open a small test window. If it raises ModuleNotFoundError: No module named '_tkinter', that is the missing python-tk above.

MP3 reading comes from libsndfile, which ships inside the soundfile wheel; there is nothing to install with Homebrew for audio.

Windows

py -m venv .venv
.\.venv\Scripts\Activate.ps1
pip install -r requirements.txt
python -m app.main

Running it

The app

python -m app.main

Two panes: the album queue (ordered — the summary reports the change at each gap) and references (measured with the same ruler, never part of the sequence). Add files or a whole folder, reorder with the arrows, press Run analysis. Analysis runs on a worker thread, so the window stays live; each row shows its own status and grows a Report button when its page is ready.

Reports are written next to the source files unless you pick an output folder:

  • <track>__report.html — one per track
  • <folder>__album.html — the album summary

The command line

python cli.py "album/*.wav" --ref "refs/*.wav" --album --out-dir reports

Metrics as JSON, no reports

python -m core.analyze "track.wav"

What it measures

Loudness — integrated LUFS, max short-term (3 s), max momentary (400 ms), LRA, PLR, PSR, and a macro-dynamics curve of short-term loudness across the track.

Peaks and integrity — sample peak and 4x-oversampled true peak per channel, full-scale runs, DC offset, noise floor (the quietest 5 % of 400 ms windows) with its spectral shape, and mains-hum prominence at the 50 Hz and 60 Hz families measured on the quiet windows.

Spectral — seven mastering bands (sub, low, low-mid "mud", mid, presence "harshness", high, air), each with energy relative to total, crest factor, envelope depth, presence fraction, stereo width and L/R correlation; plus a 1/6-octave LTAS overlaid on the references, spectral tilt in dB/octave, and a sibilance reading for 5–10 kHz.

Stereo — full-band and sub-150 Hz correlation, width by band, and the mono-fold delta: the loudness that actually dies when the record is summed.

Album — every track against every headline metric, the change at each gap in the sequence, and each track's distance from the album median.


Two gates worth knowing about

Both exist because a percentile over a whole file otherwise measures the arrangement rather than the sound. Both are stated in the reports.

  1. Activity gate. Envelope statistics only count frames within 40 dB of the track's own p95 level, so leading silence and fade tails do not become "dynamics".
  2. Band presence gate. A band more than 40 dB below its own loud level counts as absent, not quiet — otherwise a breakdown with no bass in it turns into 60 dB of "sub dynamics". The share of time a band is present is reported separately, so absence is visible instead of hidden inside depth.

Band envelopes also use a window of roughly two cycles of the band's bottom edge (100 ms at the sub band, 10 ms up top). A 5 ms window is shorter than one cycle of a 25 Hz wave and would measure the waveform rather than its level.


Layout

core/      pure measurement: audio in, JSON-able dict out. No UI imports.
  audio.py       loading, folding, filters, envelopes, activity gate
  loudness.py    LUFS / LRA / PLR / PSR / macro curve (K-weighting + gating)
  peaks.py       true peak, clipping, DC, noise floor, hum
  spectral.py    bands, LTAS, tilt, width, correlation, sibilance
  analyze.py     orchestrator + `python -m core.analyze`
report/    metrics dicts in, self-contained HTML out
  teaching.py    the one-line note for every metric
  plots.py       matplotlib figures as base64 PNG data URIs
  render.py      per-track page
  album.py       album summary page
app/       customtkinter shell (worker thread, queue + references panes)
build/     build.ps1: PyInstaller + smoke test
tests/     selftest.py, test_reports.py, test_gui_smoke.py

The measurement core is ported from the recovery-analysis instrument in the lets-make-dnb studio — band-split envelopes, percentile depth, mono correlation, Welch band energies — with all the genre logic (tempo, onset epoching, duck/bloom, drop windows) removed. That project is a separate silo and is never written to.


Dependencies

numpy, scipy, soundfile, pyloudnorm, matplotlib, customtkinter. Verified on Python 3.14.

librosa is deliberately not a dependency — it drags in numba and llvmlite and would more than double the build. The build script fails if anything imports it.

matplotlib is pinned to the Agg backend and driven through the object API rather than pyplot, because figures are rendered on the worker thread and pyplot's global figure registry is not thread-safe.


Building the Windows .exe

The Mac delivery is run-from-source (above); this is for the Windows box.

.\build\build.ps1

Produces build\dist\KANON\ (--onedir; onefile would unpack a 160 MB scientific stack to a temp folder on every launch). The script then runs the built exe with --selftest, which measures a generated file and writes a report — a windowed build has no console, so that file is how a missing DLL announces itself instead of a window that never appears.

Ship the whole KANON folder, not just the .exe.

build.ps1 is Windows-only (PowerShell, .exe paths). A macOS .app bundle would need its own PyInstaller invocation — that is the planned GitHub Actions matrix build, not something this script does.


Tests

python tests/selftest.py "some track.wav"    # measurement ruler
python tests/test_reports.py                 # HTML structure + no-recommendations rule
python tests/test_gui_smoke.py               # drives the real window end to end

selftest.py checks synthetic signals with known answers and cross-checks our own BS.1770 gating against pyloudnorm. test_reports.py scans the rendered pages for advice-shaped language and fails on it — the no-recommendations rule is enforced, not just intended.

About

KANON - Audio Analysis Suite. Measures an album against your own reference tracks and writes self-contained HTML measurement reports. Measurements only, no recommendations.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages