Build Masterchannel

KINDAreplaces $29/mosaves $348/yrback to the verdict

0%0 of 20 items done

Saved on this device only. Tick prerequisites first, then work the phases in order · do not start one until the checks above it pass.

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.

estimated effort weekendthe files for this build are in the project pack

Processingffmpeg for measurement and rendering, plus a small DSP layer for matchingRuntimePython 3.12 with numpy and a spectral analysis libraryMeasurementIntegrated loudness, true peak, loudness range and a spectral profileMatchingBroad multiband tilt towards the reference, not a hundred narrow bandsOutputOriginal untouched, masters plus a JSON report alongside

Before step 1

Everything below is assumed from the first step. Tick each one when you actually have it, not when you plan to.

  1. 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

  2. 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

  3. 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

  4. 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

  5. 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.

VariableNeededExampleWhere the value comes from
TARGET_LUFSrequired-14Integrated loudness target. Around -14 matches common streaming normalisation; state your choice rather than inheriting a default.
TRUE_PEAK_DBrequired-1.0Ceiling in dBTP. Headroom below zero so lossy encoding does not clip.
MATCH_STRENGTHrequired0.6How far towards the reference to move. Full strength copies the reference's arrangement.
MATCH_BAND_CAP_DBrequired3.0Maximum correction per band. The cap that prevents an extreme match.
MIN_LRArequired6Loudness range floor. Below it the tool refuses to compress further.
OUTPUT_DIRrequired./mastersWhere masters and reports are written. Never the source directory.

The build, in order

  1. Measure before you touch anything

    You can describe a mix and a reference in the same numbers.

    1. Parse the structured output rather than the human readable text, which changes between versions.

      Files src/measure.py

      terminal
      ffmpeg -i mix.wav -af loudnorm=print_format=json -f null -
    2. A handful of bands, averaged over the track. Fine resolution invites over-matching later.

      Files src/spectrum.py

    3. The 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 passes
    watch 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.
  2. Matching a reference, gently

    Your mix moves towards the reference's balance without taking on its arrangement.

    1. Your profile against the reference's, in a small number of bands.

      Files src/match.py

    2. Strength scales the whole correction; caps limit any single band. Both are needed.

      Files src/match.py

    3. Every applied correction in the report, so the processing is inspectable rather than magic.

      Files src/report.py

    done when · tick each as it passes
    watch 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.
  3. Dynamics, treated as a budget

    The loudness range moves towards the reference without being crushed to get there.

    1. Yours against the reference. The gap, if any, is what justifies compression.

      Files src/dynamics.py

    2. With a floor. Below it the tool refuses rather than continuing.

      Files src/dynamics.py

    3. The number that tells you whether you crushed it.

      Files src/report.py

    done when · tick each as it passes
    watch 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.
  4. Loudness and true peak, done last

    The master lands on its target with headroom that survives encoding.

    1. Two pass with linear correction, so a fixed gain is applied rather than dynamic processing.

      Files src/normalise.py

    2. Below zero, because lossy encoding introduces peaks above the original samples.

      Files src/normalise.py

    3. Encode 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 passes
    watch 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.
  5. Deliverables and the report

    One run produces every file you need and the evidence that it was done properly.

    1. One processed master, several encodings from it. Never reprocess per format.

      Files src/export.py

    2. Before and after, reference, settings hash. This is what makes the master defensible.

      Files src/report.py

    3. Same input and settings, same bytes. Pin anything random.

      Files tests/test_determinism.py

    done when · tick each as it passes
    watch 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.
what this build does not replace
after v1, if you want it

Need the files? The project pack on the verdict page hands your agent the whole brief · more ai audio.