Runtime Engine¶
The runtime binding is the main embedding surface of LunaVox. GUIs,
scripts, and notebooks call into lunavox.runtime.Engine directly via
ctypes — no subprocess, no stdout parsing. The C handle is managed with
RAII semantics so a with Engine(...) as eng: block is safe from leaks.
Since v2.2.0 the public API is a single synthesize(text, voice, params)
entry point. Every voice mode is a Voice.<factory>() call; adding a
new mode is a one-line extension instead of a new method.
Example¶
from pathlib import Path
from lunavox.runtime import Engine, SynthesisParams, Voice
with Engine(Path("models/base_small")) as eng:
params = SynthesisParams(temperature=0.6, top_p=1.0, top_k=50)
# Default speaker
result = eng.synthesize("Hello from LunaVox.", voice=Voice.base(), params=params)
# Clone from a reference file (.wav or pre-computed .json)
cloned = eng.synthesize(
"Hello from a cloned voice.",
voice=Voice.clone_file("ref/ref_0.6B.json"),
params=params,
)
# Catalog speaker with an optional style instruction
custom = eng.synthesize(
"Use angry tone.",
voice=Voice.custom("Vivian", instruct="Use angry tone."),
params=params,
)
# Design a new voice from a text description
designed = eng.synthesize(
"It's in the top drawer… wait, it's empty?",
voice=Voice.design(instruct="Speak in an incredulous tone."),
params=params,
)
print(f"RTF: {result.stats.rtf:.3f}")
print(f"Peak RSS delta: {result.stats.mem.rss_peak_delta_bytes / 1024**2:.1f} MB")
if result.stats.mem.vram_measured:
print(f"Peak VRAM delta: {result.stats.mem.vram_peak_delta_bytes / 1024**2:.1f} MB")
# result.audio is a numpy.float32 array in [-1, 1], mono @ sample_rate
Engine¶
Engine
¶
RAII wrapper around LunavoxEngine*.
Construction loads models synchronously (blocking on GPU warmup).
Call :meth:close or use a with block to release the
underlying C++ engine. Methods raise :class:LunavoxSynthesisError
on failure with the message pulled from lunavox_get_error.
Source code in src/lunavox/runtime/engine.py
__exit__
¶
close
¶
Source code in src/lunavox/runtime/engine.py
is_loaded
¶
synthesize
¶
synthesize(
text: str, voice: Optional[Voice] = None, params: Optional[SynthesisParams] = None
) -> SynthesisResult
Synthesise text into audio using voice.
voice defaults to :func:Voice.base (the model's built-in
speaker). params defaults to :func:SynthesisParams
defaults, which match lunavox_default_params in the C API.
The dispatch table below is the only place that knows which C
symbol each mode maps to — voice-side changes never ripple out.
Source code in src/lunavox/runtime/engine.py
on_log
¶
Install a Python-side log sink that receives every C++ log line.
cb is invoked as cb(level: int, message: str) where
level is the raw LunavoxLogLevel (0=DEBUG, 1=INFO,
2=WARN, 3=ERROR, 4=USER). Passing None removes the current
callback. The Engine holds the ctypes trampoline so the C
engine never dereferences a freed Python object.
Source code in src/lunavox/runtime/engine.py
Voice¶
Voice
dataclass
¶
Voice(
mode: SynthesisMode,
reference_path: Optional[Path] = None,
speaker: Optional[str] = None,
instruct: Optional[str] = None,
)
A description of how to voice a synthesis request.
Do not construct directly — use the classmethod factories:
Voice.base()— default speaker baked into the modelVoice.clone_file(path)— reference WAV or pre-computed JSON featuresVoice.custom(speaker, instruct=...)— catalog speaker id with optional styleVoice.design(instruct=...)— text-described synthetic voice
clone_file
classmethod
¶
clone_file(path: Union[str, Path]) -> Voice
Clone a voice from a reference .wav or pre-computed .json
feature file. The C engine auto-detects the format from the extension.
Source code in src/lunavox/runtime/voice.py
custom
classmethod
¶
custom(speaker: str, instruct: str = '') -> Voice
Use a catalog speaker id (e.g. "Vivian") with an optional
free-form style instruction.
Source code in src/lunavox/runtime/voice.py
design
classmethod
¶
design(instruct: str) -> Voice
Synthesise a speaker from a text description. The instruct
field is required — an empty string is rejected at the Engine
level too, but catching it here gives a clearer error.
Source code in src/lunavox/runtime/voice.py
Synthesis params¶
SynthesisParams
dataclass
¶
SynthesisParams(
max_audio_tokens: int = 0,
temperature: float = 0.6,
top_p: float = 1.0,
top_k: int = 50,
n_threads: int = 4,
repetition_penalty: float = 1.05,
language_id: int = -1,
ref_text: Optional[str] = None,
)
Python-side mirror of LunavoxSynthesisParams.
Defaults match lunavox_default_params in the C API; overriding
any field produces a fresh struct passed to the next synthesize
call. The ref_text field is an optional prompt hint used by
voice-clone and voice-design flows.
This dataclass is the single source of truth for sampler
defaults across CLI / HTTP / WS / GUI. All entries override fields
via :meth:from_overrides rather than re-declaring defaults.
from_overrides
classmethod
¶
from_overrides(**overrides: Any) -> SynthesisParams
Build a fresh instance, applying only the non-None overrides.
Unknown keys raise TypeError so typos surface at the call
site instead of silently ignoring an option. None values
are dropped — they mean "no override, use the default" — so
callers can pass through optional CLI / API fields directly
without per-field if guards.
Source code in src/lunavox/runtime/params.py
default_params
¶
default_params() -> SynthesisParams
Synthesis result¶
SynthesisResult
dataclass
¶
SynthesisResult(audio: Any, sample_rate: int, stats: SynthesisStats, mode: SynthesisMode)
Structured output of a single synthesize call.
audio is a numpy.float32 ndarray in [-1, 1] (mono). Typed as
Any here so importing this module does not pay the numpy import
cost — the actual array is only materialised by
:class:~lunavox.runtime.engine.Engine when it calls into the C API.
SynthesisStats
dataclass
¶
SynthesisStats(
t_tokenize_ms: int = 0,
t_encode_ms: int = 0,
t_generate_ms: int = 0,
t_decode_ms: int = 0,
t_total_ms: int = 0,
audio_duration_ms: int = 0,
rtf: float = 0.0,
mem: MemStats = MemStats(),
)
Per-run timing + memory stats echoed from the C engine.
SynthesisMode
¶
Bases: Enum
Which voice path produced a :class:SynthesisResult.
Only the four modes the Python API actually exposes are listed.
The C ABI also accepts raw sample/embedding clone calls, but those
are not currently reachable from Python — adding them means adding
a :class:~lunavox.runtime.voice.Voice classmethod, not mutating
this enum independently.
Error hierarchy¶
LunavoxLibraryError
¶
Bases: RuntimeError
Raised when liblunavox cannot be located or loaded.
LunavoxSynthesisError
¶
Bases: RuntimeError
Raised when a C-side synthesize call returns NULL or the engine
reports an error via lunavox_get_error.