Voice acting is one of the last things indie devs ship and the first thing players notice is missing.
A professional voice actor costs $200–$400 per hour. A full voiced RPG might need 50+ hours. For a solo dev or small team, that's a $10,000+ line item that kills the budget before the game ships.
With a TTS API, you can voice every character in your game for under $5 — and change any line instantly during development.
The workflow
Here's the basic loop most indie devs use:
- Write dialogue in your game's script/dialogue system
- Export dialogue lines as JSON or CSV
- Run a generation script — each line gets an audio file
- Import audio files into Unity/Godot
- Hook up to your dialogue trigger system
Once it's set up, changing a line takes 5 seconds and costs fractions of a cent.
Pick voices for your characters
LeanVox has a curated library of 238+ voices organized by character archetype. For games, the most useful categories:
- Narrator — world exposition, item descriptions, loading screen tips
- Gaming — hero voices, villain voices, NPC archetypes
- Meditation/Calm — ambient dialogue, sage characters, ancient beings
- Kids — young player characters, sidekicks, young NPCs
Or use the Max tier to describe any voice in plain English:
result = client.generate(
text="The ancient prophecy speaks of one who will...",
model="max",
instructions="Elderly male wizard, deep gravelly voice, slow deliberate speech, hint of otherworldly echo"
)
Batch generate all dialogue
Export your dialogue as JSON and run this script once to generate all audio files. We submit async jobs in parallel — much faster than waiting for each line sequentially:
import json
import os
import requests
from leanvox import Leanvox
client = Leanvox(api_key="lv_live_...")
# dialogue.json format:
# [{"id": "guard_01_greeting", "character": "town_guard", "text": "Halt! Who goes there?"}]
with open("dialogue.json") as f:
dialogue = json.load(f)
VOICES = {
"town_guard": "gaming_gruff_male",
"village_elder": "narrator_wise_elder",
"young_hero": "podcast_casual_male",
"mysterious_stranger": "narrator_dramatic_male",
"merchant": "podcast_conversational_female",
}
os.makedirs("audio/dialogue", exist_ok=True)
# Submit all jobs in parallel
jobs = {}
for line in dialogue:
output_path = f"audio/dialogue/{line['id']}.mp3"
if os.path.exists(output_path):
continue # already generated
voice = VOICES.get(line["character"], "podcast_casual_male")
job = client.generate_async(text=line["text"], model="pro", voice=voice)
jobs[job.job_id] = (line["id"], output_path)
print(f"Submitted {len(jobs)} jobs, waiting for results...")
# Collect results
for job_id, (line_id, output_path) in jobs.items():
result = client.jobs.wait(job_id)
audio = requests.get(result.audio_url).content
with open(output_path, "wb") as f:
f.write(audio)
print(f"✅ {line_id}")
print(f"\nGenerated {len(jobs)} dialogue files")
Run this whenever you update dialogue. It's idempotent — skips files that already exist. Async jobs mean all lines process in parallel rather than one at a time.
Prefer the CLI? Generate a single line directly from a text file:
lvox generate --model pro --voice gaming_gruff_male --file guard_line.txt --output guard_01.mp3
Unity integration
Drop the generated audio files into Assets/Audio/Dialogue/ and load them programmatically:
using UnityEngine;
using System.Collections;
public class DialogueTrigger : MonoBehaviour
{
[SerializeField] private AudioSource audioSource;
public void PlayLine(string lineId)
{
StartCoroutine(LoadAndPlay(lineId));
}
private IEnumerator LoadAndPlay(string lineId)
{
var clip = Resources.Load<AudioClip>($"Audio/Dialogue/{lineId}");
if (clip != null)
{
audioSource.clip = clip;
audioSource.Play();
}
yield return null;
}
}
Or generate lines at runtime for procedurally generated content:
// Call your backend to generate audio dynamically
IEnumerator GenerateVoiceLine(string text, string voice, System.Action<AudioClip> callback)
{
var payload = JsonUtility.ToJson(new { text, model = "pro", voice });
using var req = new UnityWebRequest("https://your-backend.com/api/tts", "POST");
req.uploadHandler = new UploadHandlerRaw(System.Text.Encoding.UTF8.GetBytes(payload));
req.downloadHandler = new DownloadHandlerBuffer();
req.SetRequestHeader("Content-Type", "application/json");
yield return req.SendWebRequest();
// Parse the audio_url from the response and load it
}
Godot (GDScript)
extends Node
var http_request = HTTPRequest.new()
func generate_voice_line(text: String, voice: String) -> void:
add_child(http_request)
http_request.request_completed.connect(_on_request_completed)
var headers = [
"Authorization: Bearer " + OS.get_environment("LEANVOX_API_KEY"),
"Content-Type: application/json"
]
var body = JSON.stringify({
"text": text,
"model": "pro",
"voice": voice
})
http_request.request(
"https://api.leanvox.com/v1/tts/generate",
headers,
HTTPClient.METHOD_POST,
body
)
func _on_request_completed(result, response_code, headers, body):
var response = JSON.parse_string(body.get_string_from_utf8())
var audio_url = response["audio_url"]
# Download audio_url and play it
Designing unique character voices
For main characters with distinct personalities, the Max tier's instruction-based voice design gives you more control:
CHARACTER_VOICES = {
"main_villain": {
"model": "max",
"instructions": "Smooth, sophisticated male villain. Calm and measured even when threatening. Slight European accent. Never raises voice."
},
"comic_relief_sidekick": {
"model": "max",
"instructions": "Young male voice, excitable and slightly nervous. Talks fast. Occasional awkward laugh."
},
"ancient_dragon": {
"model": "max",
"instructions": "Ancient, powerful dragon. Very deep, resonant. Speaks slowly with authority. Hints of fire and age in the voice."
}
}
def generate_character_line(character: str, text: str) -> str:
config = CHARACTER_VOICES[character]
result = client.generate(
text=text,
**config
)
return result.audio_url
What does it cost for a full game?
| Game type | Est. dialogue | Pro tier cost |
|---|---|---|
| Small game (20 NPCs, 200 lines) | ~50K chars | $0.50 |
| Mid-size RPG (100 NPCs, 2,000 lines) | ~500K chars | $5.00 |
| Large story-driven game (5,000 lines) | ~1.5M chars | $15.00 |
Your $1.00 signup credit voices a small game completely. A fully-voiced RPG costs less than a single hour of professional voice acting.
When to use a real voice actor
AI voice is excellent for: all NPCs, ambient dialogue, narrator, tutorial prompts, procedural content.
Real voice actors still win for: main protagonist, iconic villain, cutscene moments where the delivery needs to be perfect and the character is central to the marketing.
Use both. AI voices everything, then replace key lines with professional recordings if your game gets traction.
Try it
Browse the voice library — preview character archetypes before committing. Your $1.00 signup credit lets you generate hundreds of test lines.