mixing.dubbing.tts

ElevenLabs text-to-speech (TTS) HTTP client.

Stdlib-only — no requests or elevenlabs SDK dependency, mirroring mixing.transcript.scribe. Synthesizes speech from text and lists the voices available on the account.

The default model is eleven_multilingual_v2 — ElevenLabs’ high-quality, multilingual model (handles English, French, and ~30 other languages with the same voice), which is the right default for dubbing into multiple languages.

An optional on-disk cache (enabled by default here, since the same line is often re-synthesized across runs) skips the network call when the same text + voice + model + settings have been synthesized before.

Quick start:

>>> from mixing.dubbing import list_voices, synthesize_to_file
>>> voices = list_voices()
>>> synthesize_to_file("Hello world", voices[0]["voice_id"], "hello.mp3")

Module Attributes

DFLT_MODEL_ID

High-quality, multilingual default model (one voice speaks many languages).

DFLT_OUTPUT_FORMAT

Highest standard MP3 quality that does not require a paid tier.

DFLT_VOICE_SETTINGS

Voice settings for dubbing fidelity — see DFLT_MODEL_ID on why this is not tuned for expressiveness.

Functions

add_shared_voice(public_owner_id, voice_id, ...)

Add a shared-library voice to the account so it can be synthesized.

default_cache_dir()

Default on-disk cache for synthesized audio.

find_voice(query, *[, api_key, voices])

Return the first voice whose name or labels contain query (case-insensitive).

list_voices(*[, api_key, timeout])

List the voices available on the account.

search_shared_voices(*[, language, ...])

Search ElevenLabs' public shared voice library (not just the account).

synthesize_to_file(text, voice_id, path, ...)

Synthesize text and write the audio to path.

text_to_speech(text, voice_id, *[, api_key, ...])

Synthesize text to speech with ElevenLabs and return audio bytes.

mixing.dubbing.tts.DFLT_MODEL_ID = 'eleven_multilingual_v2'

High-quality, multilingual default model (one voice speaks many languages).

This is a DUBBING default, and deliberately not an expressive one. A dub has to track a performance that already exists: the timing is fixed by the source, the delivery belongs to the original actor, and per-take variance is a defect rather than life. eleven_multilingual_v2 is steady and speaks many languages in one voice, which is what that job wants.

If you are writing NARRATION or COMMENTARY, this is the wrong tool. Use braidio, which owns expressive delivery and defaults to eleven_v3 so inline [audio tags] fire — the single biggest lever on whether a read sounds alive (measured: plain text 70.8 Hz of pitch range, densely tagged 124.4 Hz). v2 cannot render those tags at all, so a narration built on this default is capped at the flat end before a word is written.

mixing.dubbing.tts.DFLT_OUTPUT_FORMAT = 'mp3_44100_128'

Highest standard MP3 quality that does not require a paid tier.

mixing.dubbing.tts.DFLT_VOICE_SETTINGS: dict[str, Any] = {'similarity_boost': 0.8, 'stability': 0.5, 'style': 0.0, 'use_speaker_boost': True}

Voice settings for dubbing fidelity — see DFLT_MODEL_ID on why this is not tuned for expressiveness. stability ~0.5 keeps the read steady; similarity_boost ~0.8 keeps timbre faithful to the chosen voice.

mixing.dubbing.tts.add_shared_voice(public_owner_id, voice_id, name, *, api_key=None, timeout=60.0)[source]

Add a shared-library voice to the account so it can be synthesized.

Idempotent-ish: if the voice (by name) is already on the account, returns its existing id instead of erroring on a duplicate add.

Parameters:
  • public_owner_id (str) – public_owner_id from search_shared_voices().

  • voice_id (str) – The shared voice’s voice_id.

  • name (str) – Name to give the added voice on the account.

  • api_key (str | None) – API key. Falls back to env var ELEVENLABS_API_KEY.

Return type:

str

Returns:

The account-local voice_id to pass to text_to_speech().

mixing.dubbing.tts.default_cache_dir()[source]

Default on-disk cache for synthesized audio.

Honors $MIXING_TTS_CACHE_DIR, then $XDG_CACHE_HOME, then ~/.cache/. Final segment is always mixing/tts.

Return type:

Path

mixing.dubbing.tts.find_voice(query, *, api_key=None, voices=None)[source]

Return the first voice whose name or labels contain query (case-insensitive).

Convenience for picking a voice by a human name (e.g. "Brian") or a label keyword (e.g. "french") without memorizing voice ids.

Return type:

dict[str, Any] | None

mixing.dubbing.tts.list_voices(*, api_key=None, timeout=60.0)[source]

List the voices available on the account.

Parameters:
  • api_key (str | None) – API key. Falls back to env var ELEVENLABS_API_KEY.

  • timeout (float) – Request timeout in seconds.

Return type:

list[dict[str, Any]]

Returns:

A list of voice dicts. Each has at least voice_id, name, category, and a labels dict (accent, description, age, gender, use_case) describing the voice.

Raises:

RuntimeError – No API key supplied and ELEVENLABS_API_KEY unset.

mixing.dubbing.tts.search_shared_voices(*, language=None, use_cases=None, gender=None, category=None, sort=None, page_size=40, api_key=None, timeout=60.0, **extra_params)[source]

Search ElevenLabs’ public shared voice library (not just the account).

Useful for finding a native voice in a target language (e.g. a French advertising voice) that is not yet on the account. Add the chosen voice with add_shared_voice(), then synthesize with the returned id.

Parameters:
  • language (str | None) – ISO-639-1 language filter, e.g. "fr".

  • use_cases (str | None) – e.g. "advertisement", "narrative_story".

  • gender (str | None) – "male" / "female" / "neutral".

  • category (str | None) – e.g. "professional", "high_quality".

  • sort (str | None) – e.g. "trending".

  • page_size (int) – Max results.

  • extra_params – Any other query params the endpoint accepts.

Return type:

list[dict[str, Any]]

Returns:

A list of shared-voice dicts. Each has voice_id and public_owner_id (both needed by add_shared_voice()), plus name, language, accent, gender, use_case, description.

mixing.dubbing.tts.synthesize_to_file(text, voice_id, path, **kwargs)[source]

Synthesize text and write the audio to path.

Thin convenience wrapper over text_to_speech(). Extra keyword arguments are forwarded unchanged.

Return type:

Path

Returns:

The path written.

mixing.dubbing.tts.text_to_speech(text, voice_id, *, api_key=None, model_id='eleven_multilingual_v2', output_format='mp3_44100_128', voice_settings=None, language_code=None, timeout=600.0, cache=True, refresh=False, return_cache_status=False)[source]

Synthesize text to speech with ElevenLabs and return audio bytes.

Parameters:
  • text (str) – The text to speak.

  • voice_id (str) – ElevenLabs voice id (see list_voices()).

  • api_key (str | None) – API key. Falls back to env var ELEVENLABS_API_KEY.

  • model_id (str) – TTS model id. Defaults to eleven_multilingual_v2.

  • output_format (str) – ElevenLabs output_format query value, e.g. mp3_44100_128 (default), mp3_44100_192 (needs a paid tier), or pcm_44100.

  • voice_settings (Optional[Mapping[str, Any]]) – Override the default voice settings (stability, similarity_boost, style, use_speaker_boost). Merged over DFLT_VOICE_SETTINGS.

  • language_code (str | None) – Optional ISO-639-1 hint (e.g. "fr"). Only some models honor it; ignored by others.

  • timeout (float) – Total request timeout in seconds.

  • cache (Union[bool, str, Path]) – True (default) → use default_cache_dir(). False → no cache. A path → use that directory. The cache key is a SHA-256 of the text plus every parameter that affects the audio.

  • refresh (bool) – When True and cache is enabled, force a re-call and overwrite the cached entry.

  • return_cache_status (bool) – When True, return (audio, was_cached) instead of just audio. was_cached is True iff the bytes came from the on-disk cache (no ElevenLabs call = no spend), so a caller can attribute real cost. Default False keeps the bytes return.

Return type:

bytes | tuple[bytes, bool]

Returns:

Raw audio bytes in output_format (MP3 by default) — or, when return_cache_status is True, a (audio, was_cached) tuple.

Raises:
  • RuntimeError – No API key supplied and ELEVENLABS_API_KEY unset.

  • HTTPError – Request failed (4xx/5xx).