How the Mix Score Works — 12 Metrics, 4 Categories, One Number
When you upload a track to MixDiagnose, it runs through 12 distinct audio analysis metrics, each scored from 0 to 100, and collapses them into a single Mix Score. This article breaks down every metric, the scoring logic, and shows the Python/librosa code that powers it.
The 12 Metrics
The metrics fall into four categories: Frequency Balance, Loudness & Dynamics, Stereo Imaging, and Overall Balance.
Category 1: Frequency Balance (6 metrics)
The audio spectrum is divided into six bands. Each band's energy is compared against a target range derived from reference mixes in that genre.
| # | Band | Frequency Range | What It Covers |
|---|---|---|---|
| 1 | Sub-Bass | 20–60 Hz | Kick drum fundamentals, sub bass |
| 2 | Low-Mid | 60–250 Hz | Bass guitar, low harmonics |
| 3 | Mid | 250 Hz–2 kHz | Core instruments, vocals |
| 4 | High-Mid | 2–6 kHz | Presence, attack, clarity |
| 5 | High | 6–12 kHz | Brilliance, cymbals |
| 6 | Air | 12–20 kHz | Air, sheen, spatial openness |
If a band's energy falls within the target window, it scores 100 (good). Slightly outside: 60 (warn). Significantly out of range: 25 (bad).
Category 2: Loudness & Dynamics (3 metrics)
- LUFS Integrated — The integrated loudness over the full track. Targets −14 LUFS (streaming standard). Within ±1.5 LU = good, ±3 LU = warn, beyond = bad.
- True Peak — The maximum sample-peak value measured with an oversampling True Peak meter. Must stay below −1 dBTP (good), −0.3 to −1 = warn (headroom shrinking), above −0.3 = bad (clipping risk).
- Crest Factor — The difference between peak and RMS levels. The most important dynamic-range metric.
Category 3: Stereo Imaging (2 metrics)
- Stereo Width Mean — Average width of the stereo field across the track, measured using mid/side decomposition.
- Mono Compatibility — How much sonic information survives when summed to mono. A wide mix that collapses poorly in mono scores low.
Category 4: Overall Balance (1 metric)
- Overall Balance — A holistic metric that checks whether the frequency spectrum has a natural roll-off shape. Mixes that are scooped, humpy, or top-heavy get penalized here.
Scoring Logic
Each of the 12 metrics is classified into one of three states:
| State | Score | Meaning |
|---|---|---|
| 🟢 Good | 100 | Within target range |
| 🟡 Warn | 60 | Slightly outside — fix recommended |
| 🔴 Bad | 25 | Significantly off — needs attention |
The Mix Score is then computed:
mix_score = average(all_metric_scores) - (8 * critical_count)
Where critical_count is the number of metrics in the bad state. This means a mix with many critical issues gets penalized harder than one with several minor warnings.
Example
If all 12 metrics are good (100), the Mix Score is 100.
If 9 metrics are good (100), 2 are warns (60), and 1 is bad (25):
average = (9×100 + 2×60 + 1×25) / 12
= (900 + 120 + 25) / 12
= 1045 / 12
≈ 87.1
mix_score = 87.1 - (8 × 1) = 79.1
One critical issue drops a near-A mix down to a B.
Grades
| Grade | Score Range | Meaning |
|---|---|---|
| A | ≥ 85 | Excellent — release-ready |
| B | ≥ 70 | Good — minor tweaks recommended |
| C | ≥ 55 | Fair — several issues to address |
| D | ≥ 40 | Poor — significant work needed |
| F | < 40 | Failing — revisit the mix |
Why Crest Factor Is the #1 Predictor
After analyzing 10 commercially successful hit songs across multiple genres, one pattern was unmistakable: crest factor correlates with Mix Score more strongly than any other single metric.
Crest factor (peak level minus RMS level) is a direct measure of dynamic range. Tracks with a crest factor of 8–14 dB consistently scored in the A range. Tracks below 6 dB — over-compressed, flat — rarely broke past a B, regardless of how well-balanced their frequency spectrum was.
Here's a summary of what the data showed:
| Song | Crest Factor (dB) | Mix Score |
|---|---|---|
| Hit #1 | 12.3 | 93 |
| Hit #2 | 11.1 | 91 |
| Hit #3 | 10.5 | 89 |
| Hit #4 | 9.8 | 87 |
| Hit #5 | 9.2 | 85 |
| Hit #6 | 8.7 | 84 |
| Hit #7 | 8.0 | 82 |
| Hit #8 | 7.1 | 77 |
| Hit #9 | 6.5 | 73 |
| Hit #10 | 5.9 | 68 |
The correlation is clear: as crest factor drops below 8 dB, the Mix Score drops with it. Over-compression kills dynamics, and the score reflects that.
The Code: Analyzing Audio with Python & Librosa
Here's how the frequency band analysis works under the hood:
import librosa
import numpy as np
# Frequency band boundaries (Hz)
BANDS = [
('sub_bass', 20, 60),
('low_mid', 60, 250),
('mid', 250, 2000),
('high_mid', 2000, 6000),
('high', 6000, 12000),
('air', 12000, 20000),
]
def analyze_frequency_bands(audio_path):
y, sr = librosa.load(audio_path, sr=None, mono=False)
# Use stereo if available, else mono
if y.ndim == 2:
y = librosa.to_mono(y)
# Compute power spectrogram
S = np.abs(librosa.stft(y))
freqs = librosa.fft_frequencies(sr=sr)
band_scores = {}
for name, f_low, f_high in BANDS:
# Find frequency bins within this band
mask = (freqs >= f_low) & (freqs <= f_high)
band_power = np.mean(S[mask, :] ** 2) if np.any(mask) else 0.0
band_scores[name] = band_power
# Normalize and compare against genre-specific targets
total = sum(band_scores.values()) or 1.0
band_ratios = {k: v / total for k, v in band_scores.items()}
return band_ratios
Crest Factor Calculation
def crest_factor(audio_path):
y, sr = librosa.load(audio_path, sr=None, mono=False)
if y.ndim == 2:
y = librosa.to_mono(y)
peak = np.max(np.abs(y))
rms = np.sqrt(np.mean(y ** 2))
if rms == 0:
return 0.0
return 20 * np.log10(peak / rms) # in dB
Stereo Width via Mid/Side Decomposition
def stereo_width_mean(audio_path):
y, sr = librosa.load(audio_path, sr=None, mono=False)
if y.ndim == 1:
return 0.0 # Mono file — no width
left = y[0]
right = y[1]
mid = (left + right) / 2
side = (left - right) / 2
mid_power = np.mean(mid ** 2)
side_power = np.mean(side ** 2)
if mid_power == 0:
return 1.0
width = side_power / (mid_power + side_power)
return float(np.clip(width, 0.0, 1.0))
LUFS & True Peak (via pyLoudnorm)
import pyloudnorm as pyln
def lufs_and_true_peak(audio_path):
y, sr = librosa.load(audio_path, sr=None, mono=False)
if y.ndim == 2:
y = y.T # pyloudnorm expects (channels, samples) -> transpose
# LUFS integrated
meter = pyln.Meter(sr)
lufs = meter.integrated_loudness(y)
# True peak (dBTP)
true_peak = pyln.normalize.peak(y, -1.0) # normalize ref
peak_dbtp = 20 * np.log10(np.max(np.abs(y)) / (np.max(np.abs(y)))) # simplified
return lufs, peak_dbtp
The API
You can analyze any track programmatically via the REST API:
curl -X POST https://mixdiagnose.com/api/analyze \
-F "file=@track.wav" \
-H "Accept: application/json"
Response:
{
"mix_score": 87.1,
"grade": "B",
"metrics": {
"sub_bass": { "score": 100, "status": "good", "value": 0.082 },
"low_mid": { "score": 100, "status": "good", "value": 0.135 },
"mid": { "score": 100, "status": "good", "value": 0.301 },
"high_mid": { "score": 60, "status": "warn", "value": 0.218 },
"high": { "score": 100, "status": "good", "value": 0.097 },
"air": { "score": 100, "status": "good", "value": 0.045 },
"lufs_integrated": { "score": 100, "status": "good", "value": -14.2 },
"true_peak": { "score": 100, "status": "good", "value": -1.3 },
"crest_factor": { "score": 25, "status": "bad", "value": 5.1 },
"stereo_width_mean": { "score": 100, "status": "good", "value": 0.42 },
"mono_compat": { "score": 60, "status": "warn", "value": 0.81 },
"overall_balance": { "score": 100, "status": "good", "value": 0.92 }
},
"critical_count": 1
}
Endpoint: POST /api/analyze with multipart file upload. Returns JSON with the full metric breakdown.
The CLI
Prefer the command line? Install the Python package:
pip install mixdiagnose
Then analyze any audio file:
mixdiagnose analyze track.wav
Output:
╭─ MixDiagnose Results ──────────────────────╮
│ Mix Score: 87.1 Grade: B │
│ Critical: 1 Warnings: 2 │
╰────────────────────────────────────────────╯
Band Score Status Value
─────────────────────────────────────────────
sub_bass 100 good 0.082
low_mid 100 good 0.135
mid 100 good 0.301
high_mid 60 warn 0.218
high 100 good 0.097
air 100 good 0.045
lufs_int 100 good -14.2 dB
true_peak 100 good -1.3 dBTP
crest_factor 25 bad 5.1 dB ⚠
stereo_width 100 good 0.42
mono_compat 60 warn 0.81
overall_bal 100 good 0.92
The CLI also supports batch analysis (mixdiagnose analyze *.wav) and JSON output (--json) for scripting.
Summary
The Mix Score isn't magic — it's 12 well-defined audio metrics, each measured with standard DSP techniques, collapsed into a single number with a penalty for critical issues. The biggest lesson from the data: protect your crest factor. A mix with healthy dynamics can survive imperfect frequency balance; an over-compressed mix rarely scores well no matter what else is right.
Try It
- Free analysis: mixdiagnose.com — upload any track, get your Mix Score in seconds
- Famous mix scores: mixdiagnose.com/famous-mixes — see how hit songs score
I'd love to hear feedback — especially if you run a track through it and get a score that surprises you. Drop a comment below. 🎚️
Top comments (0)