
Listening lab · 8 October 2026 · 12 min
How to run a 432 vs 440 listening test you can trust
A fair 432 vs 440 test uses one approved master rendered two ways, level-matched within 0.1 LU, compared at the same musical position rather than the same clock time, with the labels hidden. Run a blind ABX round first to see if you can tell them apart, then a blind preference round. With 10 trials you need 9 correct before chance stops being a good explanation.
You know the scene. It's late, the session's been good, someone bounces a 432 version and hits play, and everybody in the room nods. "Yeah. Warmer." Maybe it is. But the file was also a touch louder, started on a better chord, and had a label on the screen that said 432. Every one of those things can make a version win before pitch gets a vote.
This essay is about removing those other votes. It's the same discipline you'd use to compare two limiters or two mix revisions, applied to a small pitch move. It costs about fifteen minutes and saves you from making an alternate master on a hunch.
What you're really comparing
Be clear about the variables first. A classic 440-to-432 conversion scales every frequency by 432/440, or 0.981818, which is about 31.77 cents lower. If it's done by resampling, it also runs about 1.85% longer, so a 120 BPM record lands near 117.8 BPM. What 432 Hz actually changes in a finished master covers the full picture, and Resampling, pitch shifting, and tempo change are three different jobs explains when you'd keep the runtime instead.
That means a "432 test" with a classic render is really a test of lower-and-slightly-slower. That's fine, it's what most people actually want to hear. Just know it, and don't credit pitch alone for something that might be tempo.
Then there are the variables that shouldn't be in the test at all: loudness, the chord you start on, the playback chain, the file format, and the label. Anyone who has done mix work knows the slightly louder version sounds clearer, wider, and more expensive for the first few seconds. That bias alone can decide a comparison.
Build both files from one source, then measure them
Use the same approved master for both sides, lossless, with identical processing except the retune. Don't compare a streaming rip against a fresh WAV, and don't compare a 432 file someone posted online against your own 440 bounce. Different masters, different encodes, different everything.
Then measure. Resampling barely changes perceived loudness, but "barely" isn't "zero," and sample peaks can move as the waveform is reconstructed. Turn the louder side down to match the quieter one. Never boost the version you're secretly rooting for.
Switch at the same note, not the same second
Here's the trap that catches most homemade tests. Because the classic 432 render is longer, the same syllable happens later in that file. If your player switches by clock time, you jump to a slightly different place in the music every time, and the error grows the further in you go. Your ear then compares two different moments and calls the difference "tone."
The fix is to map the position: the 432 time for a given note is the 440 time divided by 0.981818. A purpose-built synchronized player does that for you. If you're rigging it yourself in a DAW, put both files on separate tracks, time-stretch nothing, and align a downbeat near your test loop instead of the song start.
A runnable rehearsal
This script rehearses the whole method on synthetic audio: it renders a 30-second clip with a pad chord, a vibrato tone in the vocal range, an 808, and hats, makes a classic 432 version with ffmpeg's soxr resampler, measures both, gain-matches them, prints the clock-drift table, and then does the statistics for scoring a blind round.
#!/usr/bin/env python3
"""listening_test.py: build a fair 440 vs 432 listening test and score it.
Usage: python3 listening_test.py
Needs: numpy, scipy, ffmpeg (with soxr) on PATH.
1. Renders a 30 s SYNTHETIC clip (pad chord, vocal-like tone, 808, hats).
2. Makes a classic 432 version (asetrate + soxr resample), measures both.
3. Gain-matches the 432 side to the 440 side within 0.1 LU.
4. Shows why switching by clock time drifts, and the mapped position.
5. Scores a blind ABX run: how many correct you need, and how often a
guesser or a genuinely hearing listener passes."""
import re, subprocess
import numpy as np
from scipy import stats
SR, DUR, BPM = 48000, 30.0, 120
R = 432 / 440
def ffmpeg(*args):
subprocess.run(["ffmpeg", "-v", "error", "-y", *args], check=True)
def measure(path):
err = subprocess.run(["ffmpeg", "-nostats", "-hide_banner", "-i", path, "-af",
"ebur128=peak=true:framelog=quiet", "-f", "null", "-"],
capture_output=True, text=True).stderr
s = err[err.rfind("Summary:"):]
i = float(re.search(r"I:\s+(-?[\d.]+) LUFS", s).group(1))
tp = float(re.search(r"Peak:\s+(-?[\d.]+) dBFS", s).group(1))
dur = float(subprocess.run(["ffprobe", "-v", "error", "-show_entries", "format=duration",
"-of", "csv=p=0", path], capture_output=True, text=True).stdout)
return i, tp, dur
# 1. synthetic clip -------------------------------------------------------
t = np.arange(int(SR * DUR)) / SR
rng = np.random.default_rng(7)
def tone(f, amp, harmonics=6, decay=0.0):
ph = 2 * np.pi * (np.cumsum(f) / SR if np.ndim(f) else f * t) # integrate frequency -> phase
y = sum(amp / h * np.sin(h * ph) for h in range(1, harmonics + 1))
return y * (np.exp(-decay * (t % 2.0)) if decay else 1)
pad = tone(220.0, .10) + tone(277.18, .08) + tone(329.63, .08) # A3 C#4 E4
vox = tone(440.0 * (1 + 0.004 * np.sin(2 * np.pi * 5.5 * t)), .12, 10) # A4 with vibrato
beat = (t * BPM / 60) % 1.0
e808 = 0.45 * np.sin(2 * np.pi * 55.0 * t) * np.exp(-3.0 * beat) # A1 808 on every beat
hats = 0.05 * rng.standard_normal(t.size) * np.exp(-60 * ((t * BPM / 30) % 1.0))
mix = pad + vox + e808 + hats
mix = 0.7 * mix / np.max(np.abs(mix))
stereo = np.stack([mix, np.roll(mix, 24)], axis=1).astype(np.float32)
stereo.tofile("syn_raw.f32")
ffmpeg("-f", "f32le", "-ar", str(SR), "-ac", "2", "-i", "syn_raw.f32", "-c:a", "pcm_s24le", "synthetic_440.wav")
# 2. classic 432 render ----------------------------------------------------
ffmpeg("-i", "synthetic_440.wav", "-af",
f"asetrate={SR*R:.6f},aresample={SR}:resampler=soxr:precision=28",
"-c:a", "pcm_s24le", "synthetic_432.wav")
i440, tp440, d440 = measure("synthetic_440.wav")
i432, tp432, d432 = measure("synthetic_432.wav")
print("STEP 2 Same synthetic source, two renders")
print(f" 440: {i440:6.1f} LUFS {tp440:+5.1f} dBTP {d440:7.3f} s")
print(f" 432: {i432:6.1f} LUFS {tp432:+5.1f} dBTP {d432:7.3f} s (ratio {d432/d440:.5f}, expected {1/R:.5f})")
print(f" loudness gap before matching: {i432 - i440:+.2f} LU")
# 3. gain match -----------------------------------------------------------
g = i440 - i432
ffmpeg("-i", "synthetic_432.wav", "-af", f"volume={g:.3f}dB", "-c:a", "pcm_s24le", "synthetic_432_matched.wav")
im, tpm, _ = measure("synthetic_432_matched.wav")
print(f"\nSTEP 3 Apply {g:+.2f} dB to the 432 side")
print(f" 432 matched: {im:6.1f} LUFS {tpm:+5.1f} dBTP -> gap now {im - i440:+.2f} LU (target within 0.1)")
# 4. clock drift vs mapped position ----------------------------------------
print("\nSTEP 4 Switching by clock time vs by musical position (120 BPM)")
print(" 440 time 432 same-note time clock-switch error error in beats")
for s in (10, 30, 60, 120, 180):
m = s / R
print(f" {s:6.1f} s {m:10.3f} s {1000*(m - s):8.0f} ms {(m - s) * BPM / 60:6.2f}")
# 5. scoring a blind ABX run -----------------------------------------------
print("\nSTEP 5 Blind ABX scoring (one-sided binomial, chance = 50%)")
for n in (8, 10, 12, 16, 20):
k = next(k for k in range(n + 1) if stats.binom.sf(k - 1, n, 0.5) < 0.05)
print(f" {n:2d} trials: need {k:2d} correct for p<0.05 (P(guess 7/10 or better) = "
f"{stats.binom.sf(6, 10, 0.5):.3f})" if n == 10 else f" {n:2d} trials: need {k:2d} correct for p<0.05")
rng = np.random.default_rng(440432)
order = rng.choice(["X=A(440)", "X=B(432)"], size=12)
print(" example randomized 12-trial key:", " ".join(o[2] for o in order))
for p_true in (0.5, 0.65, 0.75, 0.9):
k12 = next(k for k in range(13) if stats.binom.sf(k - 1, 12, 0.5) < 0.05)
passes = np.mean(rng.binomial(12, p_true, size=100000) >= k12)
print(f" listener right {int(p_true*100)}% of the time: passes a 12-trial test in {100*passes:5.1f}% of sessions")
for f in ("syn_raw.f32", "synthetic_440.wav", "synthetic_432.wav", "synthetic_432_matched.wav"):
subprocess.run(["rm", "-f", f])
Real output from this machine. The clip is synthetic, generated by the script, not a commercial recording.
STEP 2 Same synthetic source, two renders
440: -14.5 LUFS -3.1 dBTP 30.000 s
432: -14.5 LUFS -3.1 dBTP 30.556 s (ratio 1.01852, expected 1.01852)
loudness gap before matching: +0.00 LU
STEP 3 Apply +0.00 dB to the 432 side
432 matched: -14.5 LUFS -3.1 dBTP -> gap now +0.00 LU (target within 0.1)
STEP 4 Switching by clock time vs by musical position (120 BPM)
440 time 432 same-note time clock-switch error error in beats
10.0 s 10.185 s 185 ms 0.37
30.0 s 30.556 s 556 ms 1.11
60.0 s 61.111 s 1111 ms 2.22
120.0 s 122.222 s 2222 ms 4.44
180.0 s 183.333 s 3333 ms 6.67
STEP 5 Blind ABX scoring (one-sided binomial, chance = 50%)
8 trials: need 7 correct for p<0.05
10 trials: need 9 correct for p<0.05 (P(guess 7/10 or better) = 0.172)
12 trials: need 10 correct for p<0.05
16 trials: need 12 correct for p<0.05
20 trials: need 15 correct for p<0.05
example randomized 12-trial key: A B B B B A B B A A B B
listener right 50% of the time: passes a 12-trial test in 2.0% of sessions
listener right 65% of the time: passes a 12-trial test in 15.1% of sessions
listener right 75% of the time: passes a 12-trial test in 39.0% of sessions
listener right 90% of the time: passes a 12-trial test in 89.1% of sessions
Three things to take from that. First, on this clip the loudness gap after resampling rounded to zero and true peak didn't move, so the gain-match step applied nothing. That won't always be true for a dense, limited master, and the only way to know for your track is to measure it. Second, look at the drift table: switching by clock time is 185 ms off at ten seconds, over a full second off at one minute, and more than six beats off at three minutes. That's not a subtle bias, it's a different part of the song. Third, the statistics are stricter than intuition. Getting 7 out of 10 right feels convincing, but a coin does that or better about 17% of the time.
No synced player? Cut matched loops instead
If you're working from files, the simplest fair setup is two short loops that contain exactly the same notes, level-matched, with neutral names. This little script does it with ffmpeg. You give it the 440 master, the 432 render, a start time, and a length in 440 time. It works out where those same notes live in the 432 file, cuts both, turns only the louder one down, then shuffles them into blind_1.wav and blind_2.wav with the answer in a key file you hand to your helper.
#!/usr/bin/env bash
# make_blind_pair.sh: cut the SAME musical passage from a 440 master and its
# classic 432 render, level-match them, and hide which is which.
# Usage: ./make_blind_pair.sh master_440.wav master_432.wav START_SEC LENGTH_SEC
set -euo pipefail
A="$1"; B="$2"; S="$3"; L="$4"
R=$(python3 -c "print(432/440)")
S432=$(python3 -c "print($S/$R)"); L432=$(python3 -c "print($L/$R)") # same notes, later and longer
lufs() { ffmpeg -nostats -hide_banner -i "$1" -af ebur128=framelog=quiet -f null - 2>&1 \
| awk '/Summary:/{f=1} f&&/ I:/{print $2; exit}'; }
ffmpeg -v error -y -ss "$S" -t "$L" -i "$A" -c:a pcm_s24le loop_440.wav
ffmpeg -v error -y -ss "$S432" -t "$L432" -i "$B" -c:a pcm_s24le loop_432.wav
IA=$(lufs loop_440.wav); IB=$(lufs loop_432.wav)
G=$(python3 -c "print(round(min(0.0, $IA-$IB),2))") # only ever turn the 432 side DOWN
H=$(python3 -c "print(round(min(0.0, $IB-$IA),2))") # ...or the 440 side down
ffmpeg -v error -y -i loop_440.wav -af "volume=${H}dB" -c:a pcm_s24le loop_440_m.wav
ffmpeg -v error -y -i loop_432.wav -af "volume=${G}dB" -c:a pcm_s24le loop_432_m.wav
if [ $((RANDOM % 2)) -eq 0 ]; then X=loop_440_m.wav; Y=loop_432_m.wav; K="1=440 2=432"
else X=loop_432_m.wav; Y=loop_440_m.wav; K="1=432 2=440"; fi
mv "$X" blind_1.wav; mv "$Y" blind_2.wav; echo "$K" > KEY_dont_peek.txt
rm -f loop_440.wav loop_432.wav loop_440_m.wav loop_432_m.wav
echo "440 loop: start ${S}s len ${L}s ${IA} LUFS"
echo "432 loop: start ${S432}s len ${L432}s ${IB} LUFS"
echo "blind_1: $(lufs blind_1.wav) LUFS blind_2: $(lufs blind_2.wav) LUFS key saved to KEY_dont_peek.txt"
Here's the real run, on a synthetic 90-second pair (a sustained chord, a vibrato tone, and an 808 pulse generated by ffmpeg, then resampled to 432):
$ ./make_blind_pair.sh synthetic_master_440.wav synthetic_master_432.wav 60 20
440 loop: start 60s len 20s -12.9 LUFS
432 loop: start 61.111111111111114s len 20.37037037037037s -13.0 LUFS
blind_1: -13.0 LUFS blind_2: -13.0 LUFS key saved to KEY_dont_peek.txt
durations: blind_1 20.370375s blind_2 20.000000s
Notice that the 432 loop starts at 61.1 seconds, not 60, and runs 20.37 seconds instead of 20. That's the same passage; it just takes longer to play. Hide the timeline while you listen, because the loop length is the one giveaway left once the levels are matched.
Pick a passage that can actually reveal it
Choose 15 to 30 seconds of a song you know well, ideally one you made or have the rights to. Exposed vocals, sustained chords, piano tails, strings, pads, and long sub notes show pitch movement clearly. A dense, distorted chorus full of percussion can hide a third of a semitone almost completely. Which songs reveal a 432 Hz retune, and which hide it goes deep on choosing material, including why your own catalog beats famous examples.
Loop that passage. Short loops beat full-song playthroughs because auditory memory for fine pitch and tone fades in seconds.
Round one: can you tell them apart at all?
Before asking which is better, find out whether you can reliably hear a difference under blind conditions. That's what an ABX test does. You hear A (440) and B (432) labeled, then an unlabeled X that is secretly one of them, and you say which. Repeat at least ten times with the key randomized.
- Get a friend to drive the switch, or use a tool that hides the label. If you can see which is which, it isn't blind.
- Keep the monitor volume fixed for the whole session.
- Use a randomized key like the one the script prints, written down before you start.
- Score honestly: 9 of 10, 10 of 12, 12 of 16, or 15 of 20 clears p<0.05.
The last block of the output is worth a second look, because it cuts both ways. A listener who really hears the difference 75% of the time only passes a 12-trial test in about 39% of sessions. So one failed run doesn't prove you can't hear it. Run another session another day. If you pass repeatedly, the difference is real for you on that material.
Round two: which do you prefer?
Now the question you actually care about. Keep it blind. Have your helper play the two in random order and ask you only which you prefer and how confident you are, on a simple 1 to 5 scale. Record preference and confidence separately. A string of low-confidence "B, I guess" answers tells you something very different from a string of confident ones.
Describe what you hear in concrete words before you name a winner: vocal chest weight, cymbal edge, bass sustain, piano brightness, perceived pace, tension. Avoid "better," "natural," or "healing" in your notes. Those words decide the answer before the listening does.
Then reverse the order, take five minutes of silence, and come back. Repeated switching creates fatigue and false certainty fast. A preference that only exists after twenty minutes of flipping is usually exhaustion talking. Test again the next day at a moderate level, on headphones and on speakers.
The biases and their controls
| Bias | How it fools you | Control |
|---|---|---|
| Loudness | The louder side sounds clearer and wider | Measure both, match within 0.1 LU, lower the louder side |
| Labels | "432" or "healing" primes the answer | Hidden labels, helper drives the switch |
| Position drift | Clock-time switching compares different notes | Map position, or align a downbeat near the loop |
| Source mismatch | Different masters or encodes differ in many ways | Both sides rendered from one lossless master |
| Order and fatigue | Whatever plays second, or last, can win | Reverse order, short sessions, silence between rounds |
| Small samples | A lucky streak feels like proof | At least 10 trials, score against chance, repeat another day |
The fifteen-minute protocol
- Render 440 and 432 from the same lossless master. Measure both and match within 0.1 LU.
- Pick one revealing 15 to 30 second loop from a song you know.
- Write a randomized key for 10 to 12 ABX trials. Have someone else run it.
- Score it against chance. If you can't pass, stop here and keep the original.
- If you can, run 10 blind preference trials, logging preference and confidence separately.
- Break for five minutes. Reverse the order. Repeat on a second playback system tomorrow.
- Save the loop location, system, date, and source file with your notes.
What to do with the answer
No reliable difference, or no consistent preference? That's a good result. It means the record is fine as it is, and you just saved yourself from managing a second master. If the 432 version keeps winning blind, across days and systems, it has earned a full render. At that point it becomes a delivery job, and 432 Hz mastering: LUFS and true peak after a retune covers getting it out the door without clipping or cheating the comparison.
The same habits pay off everywhere else in your work. Level-matched, position-aligned comparison is the backbone of Reference matching without guesswork, and it's also why streaming platforms turn loud masters down: they remove the loudness vote for listeners, so you might as well remove it for yourself first.
- Can you actually hear the difference between 432 and 440 Hz?
- Often, yes, on a sustained vocal or chord when you switch quickly at the same musical position. The change is about 31.77 cents, a third of a semitone. Whether you prefer it is a separate question, and a blind test is the only fair way to answer either.
- How many trials does a blind ABX test need?
- Ten is a practical minimum. With 10 trials you need 9 correct for p<0.05 against guessing; 7 out of 10 happens by pure chance about 17% of the time. Sixteen trials need 12 correct.
- How closely should the two versions be level-matched?
- Within 0.1 LU of integrated loudness. Measure both renders and turn the louder one down to match. Never boost the side you want to win, and never touch the monitor knob between switches.
- Why does the 432 version drift out of sync?
- A classic resampled 432 version is about 1.85% longer, so the same note arrives later. At one minute in, switching by clock time lands about 1.1 seconds off. A good player maps the musical position instead.
- What if I don't hear a reliable difference?
- That's a valid result. Keep the original master. A preference that doesn't survive blind switching, reversed order, and a break isn't a strong enough reason to make an alternate.