Advertisement
UI & Interface Sounds

How to Build a Voice Blip Template System for Fast Character Presets

A voice blip template system fails not on synthesis speed but on distinguishability and consistency. This guide covers the parameter contract a template needs, the perceptual spacing floor between characters, why the formant map is the identity card and pitch is only the label, and how to keep one character sounding like the same person across ten lines.

The stated reason to build a voice blip template system is speed. A game with thirty speaking characters and forty lines each is 1,200 lines. If every line takes a minute of manual synthesis and auditioning, that is twenty hours of work before the first revision. A template system, in principle, replaces that with a registry of thirty parameter sets and a runtime that reads text and emits audio.

In practice, the speed is not what breaks. What breaks is distinguishability — the templates multiply until the player cannot tell the shopkeeper from the guard captain, and the system meant to save time now requires a perceptual audit that nobody scheduled. The second failure is consistency — the same character, in two different scenes, drifts just enough in pitch and formant balance that the player registers a different person. Both failures are structural, not synthetic, and both are cheap to prevent if they are designed into the template from the start.

A Template Is a Parameter Contract, Not a Sound

The first thing a template system has to decide is what actually lives in a template. If a template is a rendered WAV plus a character name, it is not a template — it is a sound file with metadata, and it cannot be scaled or modified. If a template is a bundle of oscillator waveforms, it is too engine-specific to survive a port.

A working contract, from experience with systems that need to survive across engines, is roughly six required parameters and two optional ones. The required set:

  • Base pitch (Hz) — the center frequency of the character's voice, in the range where their syllables will oscillate.
  • Pitch contour shape — the per-syllable movement, not just the center. A character whose pitch doesn't move is a machine; the contour is what makes them a person. The site's guide to shaping pitch envelopes for voice blips covers the contour shapes worth having in a template vocabulary.
  • Formant pair (F1/F2) — the two resonances that make the blip read as a particular vowel color. This is the most underrated field in the contract and the one that makes or breaks character distinction.
  • Per-character duration (ms) — how long each text character occupies before the next blip begins. This is the template's speaking rate and it should be a function of text speed, not a constant.
  • Envelope — attack, decay, and sustain amount, described in milliseconds. A harsh voice uses a shorter decay than a soft one; the envelope is where that distinction lands.
  • Seed — a single integer that drives the per-syllable randomisation. This is the most important field to get right and the one most likely to be overlooked.

The optional set is usually oscillator shape and a set of post-processing hints (bit-crush, low-pass cutoff), used to differentiate families of characters (robotic, ethereal, synthetic) without changing the base voice.

Distinguishability Has a Floor, and You Should Measure It Before You Add a Thirty-First Preset

The temptation with a template system is to author presets until the list covers the cast, then keep adding for DLC and side characters. This works until it doesn't — the player hears the new character and says “that's just the merchant with a different hat.”

The floor for a voice blip is not an absolute pitch difference. In sustained vowels, the just-noticeable difference in F0 is in the range of roughly 10–20 cents, with the exact value depending on the reference pitch, the duration of the comparison, and the listener's training. That range is much tighter than most designers assume, and it suggests two things that are worth making explicit in a template system.

First, two templates that differ only in pitch need to be separated by more than a single JND to be perceptually distinct in context — and context matters because the blip is competing with music, footsteps, and the previous line. A practical floor for a voice blip registry is about 1.5 to 2 semitones between adjacent templates in the same family. Two presets half a semitone apart will pass a spectral inspection and fail a playtest.

Second, pitch spacing cannot carry all the distinction by itself. If you map forty characters onto pitch alone, you either compress them into the JND floor or you push the extremes outside the range that reads as human speech. A usable registry distributes characters across at least three perceptual axes: pitch center, formant color, and speaking rate. This is why the parameter contract above insists on all three as required fields.

The Formant Pair Is the Identity Card; Pitch Is Only the Label

Most voice blip systems treat pitch as the primary identifying property. This produces a cast where every character sounds like the same person at a different octave, which is exactly the failure mode of too-thin preset systems.

The reason is that pitch is the most obvious axis and the easiest to author, so it absorbs all the design attention. But two characters with the same F1/F2 pair and different pitch centers still sound related — like siblings. Two characters with different formant pairs and the same pitch sound different. This is not a preference; it follows from how the auditory system parses vowels: the vowel identity is carried by the formants, and the pitch is carried by the fundamental. If the formant pair is identical, the identity is identical regardless of pitch.

The site's guide to adding vowel-like movement with formant modulation covers how to modulate formants within a blip, but the registry problem is simpler: assign each character a target formant pair, not a formant modulation. The modulation is the per-line variation; the target is the identity.

A useful starting set for a small cast:

  • Rounded, deep — low F1, low F2 (roughly 300 / 850 Hz). Reads as large, older, or physically imposing.
  • Open, direct — low F1, high F2 (roughly 350 / 1900 Hz). Reads as bright, youthful, or energetic.
  • Central — mid F1, mid F2 (roughly 500 / 1400 Hz). Reads as neutral or everyperson.
  • Tight, nasal — mid-low F1, low F2 with a narrow Q (roughly 400 / 1000 Hz). Reads as guarded, irritated, or thin.
  • Wide, airy — high F1, high F2 (roughly 650 / 1800 Hz). Reads as ethereal, unstable, or distant.

These five formant pairs are distinguishable even when the pitch centers are close, which is precisely the point. They give a registry a set of identity cards that are not dependent on the player noticing a semitone.

The Seed Belongs to the Character, Not the Line

This is the design decision that separates a system that works from one that generates the same character as five different people. If every line is synthesised with a freshly randomised seed, the character's syllable-level variation (onset jitter, small pitch wobble, formant drift) changes from line to line, and the player hears a different voice each time.

The fix is to store a character-level seed in the template and derive per-line variation from it using a line identifier. When the same character says ten lines, the ten lines share a vocal personality; when two characters say the same line, the two renderings differ. The site's guide to creating randomized blip variations to avoid repetition discusses this distinction in the context of repetition fatigue, and the same principle resolves the registry problem.

Concretely: onset jitter is roughly ±5–10 ms, per-syllable pitch deviation is roughly ±2–4% of the contour target, and per-syllable amplitude variation is roughly ±1–2 dB. These values are small enough that the character's identity is stable and large enough that consecutive lines don't sound copy-pasted. The seed that produces them is stable at the character level; the line identifier perturbs it for each line.

The Registry Shape That Actually Survives Production

A registry that works in production has fields for the contract above, plus two more that are easy to forget and painful to add later: a version number and a family tag.

{
  "id": "captain",
  "family": "authority",
  "version": 3,
  "basePitchHz": 172,
  "pitchContour": "falling",
  "formants": { "f1": 400, "f2": 1000, "q": 4.2 },
  "charsPerSec": 22,
  "envelope": { "attackMs": 8, "decayMs": 45, "sustain": 0.0 },
  "seed": 42017,
  "jitter": { "onsetMs": 7, "pitchPct": 2.5, "ampDb": 1.5 },
  "post": { "bitCrush": 6, "lowPassHz": 4200 }
}

The version field is not bureaucratic. When a template is edited after dialogue has shipped, the editor needs to know which lines were generated against which version, or every scene that uses that character has to be re-rendered to keep the voice consistent. A single integer version per template, stamped onto each generated line's metadata, is enough to catch the drift.

The family tag is what lets the engine apply shared processing to a class of characters — all “authority” templates might share a slight low-pass, all “ethereal” templates a particular reverb tail — without duplicating that processing in every entry. It also gives the designer a coarse axis for placement: characters in the same family should be pitch-spaced apart; characters in different families should be primarily separated by their formant pair.

Ten Lines Must Sound Like One Person — Test This Before You Ship

The consistency test is not “does this line sound good.” It is “does this character sound like the same person across ten lines, three scenes, and two editing passes.”

  • Render ten lines from one template with different text lengths. The per-character duration must scale so the template's speaking rate is preserved; a ten-character line and a hundred-character line should feel like the same person speaking, not a slow person and a fast one. If the per-character duration was set to a fixed value rather than derived from text speed, this is where it shows.
  • Blind-test adjacent templates. Ask a listener who hasn't seen the registry to identify which character said which line from a set that includes two templates from the same family. If they cannot, the templates are too close or the same seed was reused.
  • Run the same line through every template. The same sentence spoken by six templates should produce six renderings that a listener can sort into the six intended characters without labels. If two templates collapse in this test, they will collapse in the game.
  • Change the text speed slider and check the template holds. A template whose identity depends on a specific per-character duration will lose that identity when the designer changes the game's text speed setting. The template should remain recognisable at half-speed and double-speed, because that is what the player will experience if the accessibility setting exists.

Deriving Variants Is Cheaper Than Authoring New Templates, and More Consistent

A well-built registry does not need a new template for every state a character passes through. It needs a small set of derivation rules from a base template to its variants — injured, tired, transformed, dying, possessed.

Each derivation rule modifies a subset of the contract while preserving the rest, so the derived voice reads as the same character in a different state. This is meaningfully different from authoring a fresh template, because the derived voice shares the base voice's seed and formant family, and only changes the parameters that track the state.

A working set of derivations:

  • Injured — reduce pitch contour amplitude by 30–40%, shorten decay by 20%, add a small per-syllable pitch wobble (a second seed derived from the base seed). Reads as the same person, weakened.
  • Tired — reduce per-character duration by 10–15%, soften the attack by 3–5 ms, reduce base pitch by about a semitone. Reads as the same person, slower.
  • Transformed — keep the formant pair, shift the base pitch by 3–4 semitones and replace the oscillator with a different waveform. Reads as the same identity, different body.
  • Dying — increase onset jitter to the upper bound (15–20 ms), increase the decay, drop the sustain to zero. Reads as the same person, failing.

The site's guide to building a voice blip system in Defold shows how this derivation pattern lands in a concrete engine, and the same structure — base template plus state-modifier table — survives the port to any engine that can accept a parameter dictionary at runtime.

What to Check Before the Registry Is Public

A template system is done when it can be handed to a writer without a sound designer in the room. The check is not whether the templates are beautiful; it is whether the registry can produce a line for a character who was not in the original brief, with only the parameters in the contract, and get a voice that reads as part of the same cast.

Run this test before the system leaves the prototype: ask the writer for a new character — no reference image, no voice direction, just a name and a line. Author a template for that character using only the registry fields. Render the line. If the listener can place the new character into the cast without being told which family it belongs to, the registry is doing its job. If the listener hears “a voice” but not “a specific person,” the contract is missing a field, or the seed is being randomised at the wrong level, or the distinguishability floor was set too low for the size of the cast.

The template system should reduce authoring time from hours to minutes. It should not reduce character identity to a slider. The difference between those two outcomes is not synthesis quality — it is whether the contract, the spacing floor, and the seed discipline were designed before the first preset was written.

Advertisement