Build Masterchannel
KINDAreplaces $29/mosaves $348/yrback to the verdict
A command line pipeline that measures your mix and a reference master, matches the spectral balance and the dynamic range towards the reference, normalises to a chosen loudness target with true peak headroom, and exports platform-ready files with a report showing every figure before and after.
Before step 1
Everything below is assumed from the first step. Tick each one when you actually have it, not when you plan to.
- installfree
Why Measurement to the standard and encoding both run through it, and reimplementing the measurement is not worth it.
Get it brew install ffmpeg or your package manager. Confirm the loudness filter is present. open ↗
Verify
ffmpeg -filters lists loudnorm - installfree
Why Spectral analysis and matching are array arithmetic.
Get it python.org or your package manager, then a virtual environment with numpy and a spectral analysis package.
Verify
python3 --version prints 3.12 or higher and numpy imports - have readyfree
Why Matching and dynamics work are only judgeable against real material, and you need something you already trust as a comparison in the final phase.
Get it Your own work. Include one mix you know is too dynamic and one you suspect is too compressed, since those are the cases the tool must handle differently.
Verify
Three mixes plus a trusted master are available - have readyfree with music you own
Why Analysing a commercial track for your own reference is ordinary practice, and redistributing it is not. Keep references local and never ship them.
Get it Tracks you own in a lossless format where possible, since a heavily compressed source distorts the spectral profile you are matching to.
Verify
At least two references analyse into profiles - have readyfree if you already have monitoring
Why Every decision here is finally judged by ear, and unfamiliar speakers will lead you to correct for the room rather than the track.
Get it Whatever you have listened to enough to know. Familiarity matters more than price.
Verify
You can identify a familiar reference track's character on them
Data model
Create these before the first phase that stores anything. Changing a table later is the expensive kind of change.
- tracks(id, source_path, sample_rate, channels, duration_ms, content_hash) - references(id, path, name, added_at, profile_json) · analysed once and reused across tracks - measurements(id, subject_kind, subject_id, stage, integrated_lufs, true_peak_dbtp, lra, spectral_bands_json, crest_db) · stage is before or after - jobs(id, track_id, reference_id, target_lufs, true_peak_db, match_strength, output_path, settings_hash, at) - The settings hash on every output is what makes a master reproducible, which matters when a client asks for a small change six months later.
Environment variables
These go in a .env file the app reads at startup. The pack's .env.example is this table as a file · copy it, never commit the filled-in version.
| Variable | Needed | Example | Where the value comes from |
|---|---|---|---|
TARGET_LUFS | required | -14 | Integrated loudness target. Around -14 matches common streaming normalisation; state your choice rather than inheriting a default. |
TRUE_PEAK_DB | required | -1.0 | Ceiling in dBTP. Headroom below zero so lossy encoding does not clip. |
MATCH_STRENGTH | required | 0.6 | How far towards the reference to move. Full strength copies the reference's arrangement. |
MATCH_BAND_CAP_DB | required | 3.0 | Maximum correction per band. The cap that prevents an extreme match. |
MIN_LRA | required | 6 | Loudness range floor. Below it the tool refuses to compress further. |
OUTPUT_DIR | required | ./masters | Where masters and reports are written. Never the source directory. |
The build, in order
Measure before you touch anything
You can describe a mix and a reference in the same numbers.
Parse the structured output rather than the human readable text, which changes between versions.
Files
src/measure.pyterminalffmpeg -i mix.wav -af loudnorm=print_format=json -f null -
A handful of bands, averaged over the track. Fine resolution invites over-matching later.
Files
src/spectrum.pyThe comparison is what the whole tool is for. Make it the first thing it does.
Files
src/report.py
done when · tick each as it passeswatch out- Peak and true peak are different: a file peaking at zero on a sample meter can clip audibly once encoded to a lossy format, because reconstruction between samples goes higher. Read the true peak figure, and leave headroom below zero for exactly that reason.
Matching a reference, gently
Your mix moves towards the reference's balance without taking on its arrangement.
Your profile against the reference's, in a small number of bands.
Files
src/match.pyStrength scales the whole correction; caps limit any single band. Both are needed.
Files
src/match.pyEvery applied correction in the report, so the processing is inspectable rather than magic.
Files
src/report.py
done when · tick each as it passeswatch out- Matching a fine spectral curve copies the reference's specific arrangement: its vocal, its bass note choices, its room. The result sounds wrong because your track has different content. Use a small number of broad bands, cap the movement per band, and treat the reference as a direction rather than a destination.
Dynamics, treated as a budget
The loudness range moves towards the reference without being crushed to get there.
Yours against the reference. The gap, if any, is what justifies compression.
Files
src/dynamics.pyWith a floor. Below it the tool refuses rather than continuing.
Files
src/dynamics.pyThe number that tells you whether you crushed it.
Files
src/report.py
done when · tick each as it passeswatch out- Reaching a loudness target by compressing rather than by gain is what produced a decade of tiring masters, and on a normalising platform it buys nothing at all: the platform turns you down anyway and you are left with the flattened dynamics. Move loudness with gain, and use compression only to close a genuine gap in range.
Loudness and true peak, done last
The master lands on its target with headroom that survives encoding.
Two pass with linear correction, so a fixed gain is applied rather than dynamic processing.
Files
src/normalise.pyBelow zero, because lossy encoding introduces peaks above the original samples.
Files
src/normalise.pyEncode to a lossy format and measure again. This is the check that justifies the headroom.
Files
src/verify.py
done when · tick each as it passeswatch out- Single pass normalisation compresses dynamics to reach the target rather than applying a fixed gain, which undoes the care taken in the previous phase. Measure first, then apply the measured values with linear correction, and confirm the loudness range survived.
Deliverables and the report
One run produces every file you need and the evidence that it was done properly.
One processed master, several encodings from it. Never reprocess per format.
Files
src/export.pyBefore and after, reference, settings hash. This is what makes the master defensible.
Files
src/report.pySame input and settings, same bytes. Pin anything random.
Files
tests/test_determinism.py
done when · tick each as it passeswatch out- Producing the lossy version by re-processing rather than by encoding the finished master means the two differ in more than format, and the difference will be noticed by whoever compares them. Process once, encode from that.
Batch, references and the honest comparisonproduct builder
An album masters consistently, and you can tell whether the tool helped.
One gain across the set, preserving relative levels. Per-track normalisation is the common mistake.
Files
src/album.pyAnalysed once, reused. Reference analysis is the slow part and does not change.
Files
src/references.pyAgainst something you trust, listening rather than reading figures. Record what you heard.
Files
docs/comparison.md
done when · tick each as it passeswatch out- Normalising each track of an album independently destroys the intended relative loudness between them, so the quiet interlude arrives as loud as the single. Measure the album as a whole and apply one gain across it, preserving the relationships the mix engineer intended.
That is the whole plan for Masterchannel. What it deliberately does not cover is below · check the gaps before you call it a replacement.
- The judgement of a mastering engineer.
- Fixing problems that belong in the mix.
- Stem mastering and corrective work on individual parts.
- Distribution and platform delivery requirements.
- Reference-free mastering: the service guesses a target for you, your script needs you to pick one
- Genre-aware presets and the taste baked into a trained model
- Stem mastering, vocal-forward variants and other per-track intelligence
- A clean web UI with instant previews and revision history
- Anything resembling a second opinion when your mix is the actual problem
- Mid and side processing, which is where a small amount of width adjustment lives
- A null test against the source, which shows exactly what the processing changed
- Per-platform variants once you know the targets differ enough to matter
Need the files? The project pack on the verdict page hands your agent the whole brief · more ai audio.