← Blog

Speechify's pitch tag swaps the speaker

simba-3.2 is a clean, steady Speechify voice — until you touch <prosody pitch>. Raise it 15% and speaker similarity halves. At ±40% it's a different person. The clip is one second long, so nothing drifted. rate and volume leave the voice alone. Pitch doesn't.


A real, expressive line from Speechify’s simba-3.2, voice harper_32: “Oh my goodness, you remembered my birthday. I really wasn’t expecting this. Thank you so much!” Read it plain first:

Now the same line, same voice ID, with the SSML you’d write for it — a pause after “goodness,” emphasis on “remembered,” a slowed middle, and <prosody pitch="+15%" volume="+3dB">Thank you so much!</prosody> on the closing:

Listen to the last three words. The break, the emphasis, and the slow-down all keep harper’s voice. Then the pitch lifts on “Thank you so much,” and halfway through you’re hearing someone else. Same voice ID, same generation, different person by the end.

To isolate the cause, we cut the line to the closing — “Thank you so much!” — and moved only the pitch. Plain:

<prosody pitch="+15%">:

And +40%:

Same one-second line, different speaker. It isn’t longer, it didn’t “wander,” nothing accumulated over time. The pitch transform lands and the person changes.

This is not drift

We published a piece on Cartesia drift — a voice that decays away from itself over a two-minute take. That’s a temporal failure: the longer the generation runs, the further the autoregressive state slides from its anchor. Length causes it; a shorter take or a steadier voice fixes it.

This is a different problem. The audio is one second long and the identity is already gone. Nothing drifted. The <prosody pitch> transform replaced the speaker outright. Two different axes:

Cartesia driftThe pitch trap
Triggerelapsed time in one long takea single SSML attribute
Audio length~2 minutes~1 second
Causeautoregressive state decaythe pitch transform
Fixshorter takes / stabler voicedon’t pitch a branded voice

Drift is about duration. This is about the transform you applied.

The number

We generated one fixed utterance under six conditions, changing only the SSML wrapper. Each was embedded with ECAPA-TDNN — the same speaker-verification model our drift probe uses — and compared by cosine similarity to the plain, un-tagged voice. Duration is identical across conditions, so length can’t be the variable. Only the tag changes.

Bar chart of ECAPA speaker cosine to the plain voice across five SSML conditions. rate x-slow (0.60) and volume +6dB (0.69) sit at the same-voice baseline of 0.63. pitch +15% collapses to 0.28, pitch +40% to 0.02, pitch -40% to -0.04.

SSML appliedECAPA cosine to plain voiceReading
(second plain take — baseline)0.63same voice, different generation
rate="x-slow"0.60same speaker
volume="+6dB"0.69same speaker
pitch="+15%"0.28halfway to a stranger
pitch="+40%"0.02a different speaker
pitch="-40%"−0.04a different speaker

Two plain takes of the same line land at 0.63 — the “same voice, different roll of the dice” baseline (short clips embed noisier than long ones, which is why we compare within the same length rather than against an absolute threshold). rate and volume sit right on it, at 0.60 and 0.69. They change delivery without changing who’s talking.

pitch doesn’t. A modest +15% drops similarity to 0.28, less than half the baseline and already an audibly different person. At ±40% the cosine falls to ~0 — in embedding space, orthogonal to the original speaker. The pitch conditions don’t degrade the voice; they replace it. And it scales cleanly: more pitch, more distance. A mechanism, not noise.

Hear the control

The controls make the case. Same line at volume="+6dB" — louder, still the same person:

And at rate="x-slow" — slower, same person:

Play those next to the pitch clips above. Volume and rate are knobs on one voice. Pitch changes the voice.

The mechanism, briefly

A pitch shift can be done two ways. The correct way for TTS is formant-preserving — move the fundamental frequency (F0) but hold the vocal-tract resonances (the formants) that carry a speaker’s identity. The cheap way is a naive resample of the whole signal, which drags the formants along with F0 and makes the speaker sound smaller or larger, younger or older: a different person.

Speechify’s behaviour is the signature of the cheap path. We tried to confirm it by tracking formants directly, but on a one-second exclamation the estimates were too noisy to trust, so we lead with the ECAPA result instead — unambiguous about the outcome even where the mechanism measurement isn’t. Either way the practical point holds: on simba-3.2, <prosody pitch> is a different-voice dial, not a louder-voice dial.

Caveats

  • One voice, one model, one line. Measured on simba-3.2 / harper_32, English, “Thank you so much!”. A clean scope, not a survey.
  • Short-clip embeddings are noisy — so we compare within length against a same-length baseline and controls, not an absolute cosine threshold. The pitch conditions fall far below both. That’s the load-bearing fact.
  • Measured through the Speko gateway, on the audio the gateway actually returns.
  • This is a Speechify result. Other providers may implement <prosody pitch> with proper formant preservation — we haven’t run the same probe on them yet. That’s the obvious next piece.

What it means for production

The takeaway is practical, and it runs against the usual SSML advice:

  • Don’t use <prosody pitch> on a branded or consistent agent voice. It doesn’t nudge the pitch up a little. It changes who the customer thinks they’re talking to, on the first sentence, with no drift required.
  • rate, volume, and break are safe. They control pace, level, and pauses without touching identity. That’s your toolkit for expressive control on a fixed voice.
  • If you want a different-sounding voice, pitch is a fine lever — just know that’s what it’s doing.

There’s a benchmark gap here too. Leaderboards score clarity and naturalness; our drift probe scores steadiness over time. Nobody scores identity-preservation under prosody — whether a provider’s own control tags keep the speaker intact. Speechify’s pitch tag fails that test; its rate and volume tags pass. Worth measuring across the field.

One API for every voice provider — with the traps already mapped.

Speko routes each call to the best STT → LLM → TTS stack and flags failure modes like this one before they hit production. You build the agent; we handle the provider maze.

Start building on Speko → Explore the TTS benchmark →