
Mixing · 9 November 2026 · 6 min
Auto-Tune sounding robotic? Slow the retune speed and keep the vibrato
Pitch correction sounds robotic when it moves the note faster than a person can. At a 0 ms retune speed our test vocal lost all of its vibrato, and every slide between notes turned into a staircase of full-semitone jumps. Slow it to 50 ms and the held notes still land within about 3 cents while most of the vibrato survives. Or correct only the center of each note, and keep all of it.
You tune the vocal, it’s finally in key, and now it sounds like a ringtone. The long notes sit dead flat, the slides between words click from one note to the next, and the singer you recorded has turned into a plug-in preset.
Nothing is broken. The tuner is doing exactly what you asked, just faster than any throat moves.
What retune speed actually controls
Every automatic tuner does the same two things. It decides which note you meant, usually the nearest note in the key you set, and then it pulls the pitch toward that note. Retune speed is how quickly it pulls. At 0 ms it snaps: the moment you drift, you’re back on the grid. At 100 or 200 ms it eases you over, and anything faster than that, like vibrato or a scoop into a word, mostly gets through.
That’s the whole trade. Vibrato is a fast wobble, five or six times a second. A slide between notes is a fast move too. A fast tuner treats both as mistakes.
We wrote tune_check.py to see how big the trade is. It isn’t audio, it’s a pitch track: four held notes (A3, C4, D4, C4), each sung 15 cents flat with ±30 cents of vibrato, joined by 90 ms slides. It runs the usual tuner model at different speeds, plus a center-only mode that corrects each note’s average and leaves the wobble alone, the way you’d move a note’s center in a graphical editor.
#!/usr/bin/env python3
"""What does retune speed do to a sung line?
python3 tune_check.py
Model of a pitch track, not audio. A synthetic sung phrase of four held notes (A3 C4 D4 C4),
each sung 15 cents flat on average with 5.5 Hz vibrato of +/-30 cents, joined by 90 ms glides.
Pitch correction is modelled the usual way: find the nearest semitone and pull the pitch toward
it through a smoother whose time constant is the retune speed (0 ms = instant snap).
Mode "center only" corrects the note's average (a one-vibrato-period moving average, like moving a
note's center in a graphical editor) and leaves the vibrato alone.
Reports, on the held parts: how far the note's average sits from the written note (cents),
vibrato depth left (peak-to-peak, % of the sung vibrato), and how long each note change takes
(10-90 %, measured on the same phrase sung without vibrato so the wobble can't trip the marks),
plus the biggest pitch jump inside one millisecond of a glide (a hard step sounds robotic).
"""
import numpy as np
FS = 1000 # pitch-track rate, 1 sample = 1 ms
NOTES = [57, 60, 62, 60] # MIDI: A3 C4 D4 C4
HOLD, GLIDE, FLAT, VIB_C, VIB_HZ = 600, 90, -15.0, 30.0, 5.5
n_total = len(NOTES) * HOLD + (len(NOTES) - 1) * GLIDE
t = np.arange(n_total) / FS
# sung pitch in cents (MIDI*100)
base = np.zeros(n_total); held = np.zeros(n_total, bool); pos = 0; starts = []
for i, m in enumerate(NOTES):
base[pos:pos + HOLD] = m * 100 + FLAT; held[pos + 120:pos + HOLD - 40] = True
pos += HOLD
if i < len(NOTES) - 1:
a, b = m * 100 + FLAT, NOTES[i + 1] * 100 + FLAT
s = 0.5 - 0.5 * np.cos(np.linspace(0, np.pi, GLIDE))
base[pos:pos + GLIDE] = a + (b - a) * s; starts.append(pos); pos += GLIDE
vib_env = np.clip((t % ((HOLD + GLIDE) / FS)) / 0.25, 0, 1) # vibrato fades in over 250 ms
sung = base + VIB_C * np.sin(2 * np.pi * VIB_HZ * t) * vib_env
def smooth(x, ms):
if ms <= 0: return x.copy()
a = np.exp(-1.0 / ms); y = np.empty_like(x); y[0] = x[0]
for i in range(1, len(x)): y[i] = a * y[i - 1] + (1 - a) * x[i]
return y
def correct(x, speed_ms, center_only=False):
if center_only: # one vibrato period moving average kills the wobble
k = int(round(FS / VIB_HZ)); ref = np.convolve(np.pad(x, (k // 2, k - k // 2 - 1), mode="edge"), np.ones(k) / k, "valid")
else:
ref = x # what the tuner listens to
target = np.round(ref / 100.0) * 100.0
return x + smooth(target - ref, speed_ms)
intended = np.zeros(n_total); pos = 0
for m in NOTES: intended[pos:pos + HOLD + GLIDE] = m * 100; pos += HOLD + GLIDE
def segs(y):
out, pos = [], 0
for m in NOTES: out.append((y[pos + 250:pos + HOLD - 40], m * 100)); pos += HOLD + GLIDE
return out
SUNG_PP = np.mean([seg.max() - seg.min() for seg, _ in segs(sung)])
def stats(y, y_plain):
center = np.mean([abs(seg.mean() - m) for seg, m in segs(y)])
vib = 100.0 * np.mean([seg.max() - seg.min() for seg, _ in segs(y)]) / SUNG_PP
tr, jump = [], 0.0
for i, s0 in enumerate(starts):
a, b = NOTES[i] * 100 + FLAT, NOTES[i + 1] * 100 + FLAT
w = y_plain[s0 - 300:s0 + GLIDE + 400]
f = (w - a) / (b - a)
tr.append(np.argmax(f >= 0.9) - np.argmax(f >= 0.1)); jump = max(jump, np.abs(np.diff(w)).max())
return center, vib, np.mean(tr), jump
print("Sung phrase: A3 C4 D4 C4, 15 cents flat on average, vibrato +/-30 cents at 5.5 Hz, 90 ms glides")
print(f"{'version':34s} {'note center':>12s} {'vibrato left':>13s} {'note change':>12s} {'biggest 1 ms jump':>18s}")
c, v, tr, j = stats(sung, base)
print(f"{'as sung (no correction)':34s} {c:8.1f} c off {v:10.0f} % {tr:9.0f} ms {j:13.0f} c")
for sp in (0, 10, 25, 50, 100, 200):
c, v, tr, j = stats(correct(sung, sp), correct(base, sp))
print(f"{'retune ' + str(sp) + ' ms':34s} {c:8.1f} c off {v:10.0f} % {tr:9.0f} ms {j:13.0f} c")
for sp in (25, 50):
c, v, tr, j = stats(correct(sung, sp, True), correct(base, sp, True))
print(f"{'retune ' + str(sp) + ' ms, center only':34s} {c:8.1f} c off {v:10.0f} % {tr:9.0f} ms {j:13.0f} c")
$ python3 tune_check.py
Sung phrase: A3 C4 D4 C4, 15 cents flat on average, vibrato +/-30 cents at 5.5 Hz, 90 ms glides
version note center vibrato left note change biggest 1 ms jump
as sung (no correction) 14.5 c off 100 % 52 ms 5 c
retune 0 ms 0.0 c off 0 % 34 ms 100 c
retune 10 ms 0.8 c off 31 % 52 ms 11 c
retune 25 ms 2.0 c off 64 % 54 ms 7 c
retune 50 ms 3.0 c off 86 % 54 ms 6 c
retune 100 ms 3.3 c off 96 % 55 ms 6 c
retune 200 ms 3.4 c off 99 % 55 ms 5 c
retune 25 ms, center only 3.2 c off 100 % 56 ms 8 c
retune 50 ms, center only 3.2 c off 100 % 54 ms 6 c
Reading the numbers
0 ms is the effect, not a setting. The note center is perfect, 0.0 cents off, but the vibrato is gone, 0 % left, and the biggest jump inside one millisecond is 100 cents. That’s a whole semitone in an instant: the three-semitone slide from A3 up to C4 becomes three steps. If you want that sound, great, it’s a style. If you didn’t, that’s where the robot lives.
10 ms still flattens most of the life out. Only 31 % of the vibrato is left. It’s in tune, it just doesn’t sound sung.
Somewhere around 25 to 50 ms is the natural zone. At 25 ms the notes sit 2.0 cents off and 64 % of the vibrato is left. At 50 ms it’s 3.0 cents and 86 %. A singer who was 14.5 cents flat now lands within a few cents, and still sounds like a person.
Center-only keeps everything. Correcting each note’s average instead of every wiggle got the notes to 3.2 cents off with 100 % of the vibrato. That’s the idea behind Melodyne’s pitch center tool, and behind the humanize-style controls some automatic tuners have that go easy on held notes.
This is a model of a pitch track with a tidy tuner, not a recording, and every plug-in’s speed knob is scaled a little differently. Read it for the shape of the trade, not exact settings.
How to tune so it doesn’t sound tuned
- Set the key and scale first. A chromatic tuner will happily pull a flat note to the wrong semitone. Telling it the key removes the wrong targets.
- Start slow and speed up. Begin around 50 ms and lower it only until the sour notes stop bothering you. The first speed that sounds in tune is usually the right one.
- Use the humanize or held-note control if it has one. It lets the fast moves through and corrects the long notes, which is where pitch problems are most obvious anyway.
- Fix the bad notes by hand, leave the good ones. In a graphical editor, move the centers of the notes that are actually off and leave the vibrato and slides as sung.
- Tune before compression and saturation. They add harmonics that make pitch detection less sure of itself, which shows up as warble.
- Check it in the mix, not solo. A little drift you hear soloed often disappears under the beat. A robotic slide doesn’t.
Hear how much your references are tuned
Most of us guess at how hard the records we like are tuned. You don’t have to. Pull the vocal out of a reference with StemSplit and solo it. It won’t be studio clean, but you can hear whether the long notes sit flat and dead or wobble a little, and whether the slides step or glide. Then tune yours to match that, not a number.
- Why does my Auto-Tune sound robotic?
- Because the retune speed is fast enough to remove the vibrato and snap slides into steps. In our test 0 ms left 0 % of the vibrato and made one-semitone jumps inside a millisecond.
- What retune speed sounds natural?
- Usually somewhere around 25 to 50 ms, then adjust by ear. In our model 50 ms put held notes within 3.0 cents and kept 86 % of the vibrato.
- Does pitch correction remove vibrato?
- A fast one does. At 10 ms our test vocal kept only 31 % of its vibrato. Correcting each note’s center instead of every wobble kept 100 %.
- Should I tune vocals before or after compression?
- Before. Compression and saturation add harmonics and noise that make pitch detection less certain, which can show up as warble.