What every setting actually does
Every field in every dock, grouped the way they're grouped in the app, with the parts that aren't obvious from the label alone called out. Three things are worth reading before the rest: the Settings dock's fields mean something different depending on what's selected, Audio8 quietly ignores two of its own generation fields, and JIT streaming isn't a checkbox every engine gets.
Options menuEngine, device, theme
Options > Engine is the one setting that changes what every other setting on this page looks like: switching it rebuilds the Settings tab's fields from the new engine's schema and swaps what sits behind the Voices tab (Mixing for Kokoro, Voice Reference for Audio8, nothing for the Dummy engine). Everything below is written per-engine where the two differ.
Options > Device picks CPU / CUDA / Auto for the Kokoro pipeline (the CUDA entry is greyed out when torch reports no device) and re-initializes the engine. Options > Theme switches between the dark (default) and light palettes. The three checkable entries under them are the old Settings dialog: whether copying text carries its character/FX along, whether a paste splits off its own run, and JIT streaming for clip-free documents. The welcome dialog's "Show at startup" box is the one launch setting that isn't here; it lives on the dialog itself (File > Welcome…).
Transcript dockThe transcript
The Transcript dock is a syntax-highlighting editor over the document's canonical text, not a plain input field. Two combos sit above it: Character and FX, both reflecting the clip under the caret. Changing Character reassigns the selection (or the caret's whole clip, or its line for untagged text); changing FX sets a named FX override on the caret's clip, undoable like everything else. The left gutter names the speaker once per character/FX change (Narrator on one line, FX: Echo under it) and shows a small play button beside each out-of-date clip that regenerates just that clip. Out-of-date text is dash-underlined; thin rules mark clip boundaries and where Auto-split would cut.
Every run of text is colored by its assigned character and FX, so the boundaries between speakers and effects are visible at a glance, without reading the inline [Speaker:FX]: syntax.
Selecting a range and opening the Characters menu reassigns that range's character/FX directly. Placing the caret inside an existing run instead shows that run's currently active voice/FX in the Settings dock. Copying a range carries its character/FX metadata with it; pasting into a run belonging to a different character splits the paste into its own run rather than silently overwriting the destination's assignment, unless "character/FX paste splits" is turned off, in which case a paste inherits whatever it lands on.
Settings tabOne panel, three scopes
The schema-driven form, scoped to whatever self.app.selection currently points at:
| Selection | Values come from | Edits write to |
|---|---|---|
| Nothing selected | The app's whole-document defaults | App settings (config_qt.json) |
| A clip | Its character's preset, merged with its own overrides | clip.overrides, never the app defaults |
| A character | That character's saved preset | The character's preset directly, so every non-overridden clip using it updates live |
Only the fields below can vary per clip or character. Everything else (Language, Parallel threads, Enable segment cache, and any engine's own non-preset fields like Audio8's sampling knobs) is rendered disabled, not hidden, while a clip or character is selected, since those settings only make sense at the whole-document level.
Schema-driven: the fields below are what both real engines currently declare. Rows marked Audio8 only or Kokoro only don't exist on the other engine's dock at all.
| Setting | What it does |
|---|---|
| Language | For Kokoro, picks which phonemization pipeline runs; each language uses its own KPipeline and voice list. For Audio8 it's one of eleven labels from the model card. See the callout below: it currently isn't sent to the model at all. |
| Voice | Kokoro: a named base voice (af_heart, bm_daniel, ...) or a saved custom mix from the Mixing dock. Audio8: a saved Voice Reference (WAV + transcript pair) from the Voice Reference dock. |
| Speed | Kokoro: 0.5x-2.0x, passed straight to the pipeline as a native generation parameter. Audio8: shown in the same range, but see the callout below, it's currently not forwarded to the model either. |
| Split by | Natural (newlines), Paragraphs (double newline), or Sentences (splits on ./!/?, with a regex guard against splitting mid-abbreviation). Controls where a long input gets cut into chunks before generation. |
| Output format | wav, flac, mp3, or ogg. Same four choices on both engines. |
| Parallel threads | Kokoro: 1-32, each worker thread gets its own KPipeline, so raising this genuinely parallelizes generation. Audio8: capped at 1-4 in the schema, and since every segment is serialized through one shared, locked model, raising it doesn't parallelize the model calls themselves. |
| Enable segment cache | Caches each generated segment as a .wav under cache/, keyed by a hash of the settings that affect what gets generated. Re-running with unchanged settings skips regenerating that segment. |
| Cache reference encoding Audio8 only | A second, separate cache that stores the model's encoded reference audio, keyed by the reference file's contents. Repeated segments against the same voice reference skip re-running the audio encoder, independent of the segment cache above. |
| Max new tokens Audio8 only | Caps how many tokens the model can generate per segment. Default 1024, hard-capped at 2048 to match the model's real max_seq_len; anything higher gets silently clamped by the model anyway. |
| Temperature Audio8 only | Sampling temperature, default 0.8. Higher values add more variation between takes of the same text. |
| Top P / Top K Audio8 only | Nucleus and top-k sampling cutoffs, default 0.95 and 50. Standard token-sampling controls for the model's decoder. |
Language and Speed do nothing on Audio8, currently. The model's own processor doesn't accept a language or speed argument at all; passing either raises a hard error. So audio8_tts.py keeps both in its internal function signature only to match the shape shared with the other engines, and never forwards them to the model. Audio8 infers the spoken language from the reference clip and text, and always generates at its own pace. The two fields still show up in the dock because the schema doesn't currently distinguish "displayed" from "functional." Worth knowing before you spend time chasing a Speed slider that isn't moving anything.
Settings tabAudio control
Hand-coded, not schema-driven, so every engine gets the same fields here, still subject to the same three-scope rules above. These are the post-processing steps from the signal chain on the home page.
| Setting | What it does |
|---|---|
| Volume | 0.1x-2.0x. A plain multiply on the waveform, applied second in the chain, after Trim and before Pitch. |
| Pitch (st) | -12 to +12 semitones, shifted by resampling to a new length. This changes duration along with pitch, the classic "chipmunk" effect: raise the pitch and playback gets faster, lower it and playback gets slower. For pitch without a duration change, use the FX dock's separate Pitch Shift effect instead. |
| FX preset / Apply | Loads a saved FX preset into the FX dock's sliders. The Apply checkbox is the master switch for the whole FX chain below; unchecked, none of the FX dock's effects run even if individually enabled. |
| Normalize | Scales the segment so its loudest peak sits at 98% of full scale. A simple peak normalize, not a loudness (LUFS) normalize. Runs last in the chain, after FX. |
| Trim silence | Strips leading and trailing audio below a fixed amplitude threshold. Runs first in the chain, before Volume. |
Timeline dockTimeline
One track per character on a real seconds axis, bottom-left of the window. Clips sit end to end in text order across all tracks: at their real duration once generated (with a waveform), at an estimated one before (dashed outline, no waveform; the estimate learns from generation_stats.json). A ruler runs across the top, a fixed header column names the tracks, and Ctrl+wheel zooms between 20 and 400 pixels per second.
| Action | What it does |
|---|---|
| Right-click a clip > Generate | Renders just that clip's text/settings through the normal cache-aware generation path, populating its segments with real audio. |
| Right-click a clip > Play | Plays that clip's cached audio. |
| Per-clip FX button | Opens an FX override for that one clip, applied on top of the FX chain and winning over its character's own FX preset. Button opacity shows state at a glance: 50% means no FX override, 90% means one's active. |
| Drag a clip left or right | Pins it to that start time (snapping to other clips' edges and the playhead). Drop it at or before the start of the clip that precedes it in the text and its text moves there too, so the timeline and the transcript stay in the same order. Right-click > Unpin from timeline puts it back in the flow. |
| Drag a clip onto another track | Reassigns the clip to that track's character (with a confirmation prompt when the characters actually differ) or just moves it to that lane. |
| Shift+drag inside a clip | Carves out the selected sub-range and opens an editable transcript for it. Confirming replaces just that sub-range with fresh TTS, under any character, not necessarily the clip's own. |
| Click the ruler | Seeks the transport to that time. |
| Generate (Transport dock) | Once the document has clips, this regenerates every dirty clip in one pass instead of the whole document, with bounded concurrency and cancel-safe queuing. A document with no clips yet still falls back to the original whole-document pipeline. Its menu holds Auto-split then generate and the Split by paragraph toggle. |
Transport dockPlayback
Bottom-right. Play / pause / stop, the position readout, a Loop toggle, then Preview / Generate / Cancel, then one progress bar that carries the status text.
| Control | What it does |
|---|---|
| Play / Pause / Stop | Plays the whole arrangement through one sounddevice output stream that mixes every clip at its timeline position (overlaps are a plain sum, clipped to full scale). Position comes from the audio callback's frame counter, so the playhead is sample accurate. Space toggles playback anywhere except inside the text editor; Ctrl+Space toggles everywhere. |
| Playhead | A line across every lane plus a marker on the ruler. The transcript highlights the clip being played and scrolls to it without moving your caret. A clip that finishes generating mid-playback becomes audible without stopping. |
| Loop | Wraps to the start instead of stopping at the end of the arrangement. |
| Preview | Speaks the selected text (or the first 1000 characters of the document) with the project-scope settings, through the fire-and-forget preview player. |
Edit menuUndo & redo
Text edits ride the editor's native undo; character/FX reassignments, clip moves and FX overrides push onto a plain-Python undo stack tied to the document. Edit > Undo/Redo (or the OS shortcuts) pops whichever happened most recently. Edit > Characters... edits each character's name, color, voice and FX preset; a character still used by clips can't be removed.
File menuProjects
A project is a .tbaw bundle (text based audio workflow): one zip with the text and clips, every generated segment, and the voice mixes, voice references and FX presets it names, so it opens on another machine with the same engines installed. The layout is on the format page. Older .json projects open and are converted next to the original. Launch reopens the last project you had open, then shows the welcome dialog over it.
| Action | What it does |
|---|---|
| Welcome… | The dialog launch shows: recent projects with the open one first and Resume as the default button, New project, New from text file, Open other, right-click a row to drop it, Clear list, and a details pane (path, modified time, character and clip counts, audio length, engines) read from the .tbaw manifest without extracting it. "Show at startup" is show_welcome in config_qt.json; untick it for a silent resume. |
| New | An empty project that inherits the current project's characters (a copy, until the global character library exists). |
| Open / Recent | Opens a project file; Recent lists the last ten. |
| Save / Save As | Autosave writes the app's working copy of the project (under cache/projects/), never the .tbaw; Save writes the file in the background and Save As branches to a new file. The window title shows * while the working copy is ahead of the file. Closing with unsaved changes asks Save / Discard / Cancel; after a crash, opening the project offers to recover the unsaved session. |
| Import Text | Extracts a .txt, .pdf, or .epub and asks whether to add it at the caret or start a new project from it. The insert is one undo step. |
| Import Audio | Greyed out for now; arrives with ASR-anchored import. |
| Export | The mixdown dialog described next. |
File > ExportExport
Generate only fills the per-clip cache. Export is what produces a deliverable: every clip mixed down at its timeline position into one file, using the same summing rule the transport plays. It refuses with a count when clips are out of date and offers to generate first.
| Setting | What it does |
|---|---|
| Output folder / Base filename | Where the mixdown is written and what it's called. Remembered per project. |
| Project: bundle generated audio / Bundle audio format | Whether Save puts generated segments into the .tbaw (off gives a small file whose clips regenerate on open) and whether new segments are written as wav or flac. Remembered per project. |
| Format | wav, mp3, flac or ogg. |
| Also write .srt | Subtitles timed from each clip's timeline start and duration, one row per generated clip. |
| Keep per-clip files | Writes each clip next to the mixdown as <base>_001_<Character>.<ext>, numbered in timeline order. |
Workspace menuWorkspaces & theme
Every panel is a dock you can drag, close and re-tab. Workspace > Advanced is the default 2x2 grid; Simple hides the timeline and gives the transcript the full height, same document, same Generate behavior; Reset layout rebuilds the active one. Whatever you drag around is saved into the active workspace and comes back with it. Options > Theme switches dark (the default) and light; the gutter, timeline and ruler read the same palette as the widgets.
Audio FX tabFX
Five groups, each section gated behind its own enable checkbox except EQ, which is always live (a slider left at 0 dB is simply a no-op). All of it runs through one Pedalboard chain together as step 4 of the signal chain. The whole chain (and volume, pitch, normalize, trim) is applied on playback and export over the clip's raw generated audio: edit anything here and the timeline plays the change, with no regeneration and no clip marked out of date. The tab follows the selection: project defaults, a character's preset, or one clip's override, layered in that order.
| Setting | What it does |
|---|---|
| Compressor | Threshold (dB) and Ratio. Standard dynamic-range compression. |
| Limiter | Threshold (dB). A hard ceiling on peak level, separate from the Compressor. |
| Gain | A flat gain change in dB, applied within the FX chain, on top of the separate Volume control above. |
| Setting | What it does |
|---|---|
| Bass (low shelf) | ±20 dB shelf below 250 Hz. No separate enable toggle; 0 dB does nothing. |
| Treble (high shelf) | ±20 dB shelf above 4000 Hz. Same, no toggle needed. |
| High-pass filter | Cutoff frequency, 20-1000 Hz. Removes content below the cutoff. |
| Low-pass filter | Cutoff frequency, 1000-20000 Hz. Removes content above the cutoff. |
| Setting | What it does |
|---|---|
| Reverb | Room Size, Wet Level, Damping, Width. Standard algorithmic reverb. |
| Delay | Time (seconds), Feedback, Mix. Echo/repeat effect. |
| Setting | What it does |
|---|---|
| Chorus | Rate (Hz), Depth. Layers a detuned, delayed copy of the signal. |
| Distortion | Drive (dB). Harmonic distortion. |
| Phaser | Rate (Hz). Sweeping comb-filter effect. |
| Clipping | Threshold (dB). Hard-clips the waveform above the threshold. |
| Setting | What it does |
|---|---|
| Pitch Shift (High Quality) | ±12 semitones. The formant-aware shift mentioned above: changes pitch without the duration side effect the plain Pitch control has. |
| Bitcrush | Bit depth, 2-16. Reduces sample resolution for a lo-fi, digital-artifact sound. |
| GSM Compressor | A single checkbox, no slider. Runs the audio through a simulated GSM phone-call codec. |
Lexicon dockLexicon
| Setting | What it does |
|---|---|
| Original text / Replacement | A list of literal find-and-replace rules, applied case-insensitively to every segment's text before synthesis. Useful for acronyms, names, or jargon a voice mispronounces. |
Rules apply regardless of which preset or FX preset an inline script tag switches to; Lexicon is global, not per-speaker.
Mixing dockMixing supports_voice_mixing engines only
| Setting | What it does |
|---|---|
| Voice A / Voice B | Each has its own language and voice picker; the two voices being combined. |
| Operation | Mix, Add, Subtract, Multiply, or Divide, applied directly to the two voices' underlying tensors. |
| Mix slider | 0-100%. For Mix, a straight blend: 0% is all Voice A, 100% is all Voice B. For the other four operations it's an influence amount, not a blend ratio, and the app's own label warns that Divide is "unstable and VERY LOUD." |
| Preview language / Preview | Speaks a short preview line in the chosen language using the in-progress mix, before you commit to saving it. |
| New voice name / Create & Save | Saves the result as a custom voice, which then shows up in the normal Voice dropdown alongside the built-in voices. |
Voice Reference dockVoice reference supports_voice_cloning engines only
| Setting | What it does |
|---|---|
| Reference audio | Browse to a WAV file of the voice to clone. |
| Transcript | What's actually said in that WAV, word for word. The cloning model uses this alongside the audio itself. |
| Auto-transcribe | Runs the reference clip through the bundled ASR model to pre-fill the transcript, off the Qt main thread so the UI doesn't freeze. Always worth proofreading the result before saving. |
| Save as / Saved references | Saves the WAV and transcript as a named pair, which then shows up in the Voice dropdown like any other voice. |
PresetsPresets, characters, and how they relate to inline scripting
Two preset systems, both plain JSON on disk. presets/<name>.json files are whole-config snapshots (voice, speed, split pattern, and the rest); since 4.0 nothing in the GUI writes them any more, because Edit > Characters... is where a named voice/FX bundle is edited now, but existing files still load. "Save FX Preset..." in the Audio FX tab snapshots just the FX sliders, as presets/fx/<name>.json.
Every file in presets/ also becomes a Character on first load, one per file, with a highlight color assigned from a small fixed palette. If you had no presets saved yet, one "Default" character is seeded from your last-used settings instead, so a returning user's config isn't discarded. The preset files themselves are untouched either way, characters are read from them, not a replacement for them.
These aren't a separate feature from inline scripting, they're the same thing. A [Name]: tag in the transcript looks up a character by exactly that name, case-insensitively, and a character's name starts out as whatever the preset file it came from was called.
App settingsJIT streaming needs speed to spare
JIT mode plays audio back while it's still being generated: a generation thread fills a queue, a playback thread drains it. For that to work at all, generation has to outrun playback, producing more than one second of audio for every second of wall-clock time it spends generating, with enough margin that playback never catches up and stalls waiting on the next chunk. An engine that can only generate at, or slower than, real time simply can't stream: there'd be nothing queued up by the time playback needs it.
This is exactly what the supports_jit_streaming capability flag encodes, per engine, not measured live, just declared:
| Engine | supports_jit_streaming |
|---|---|
| Kokoro (local) | True |
| Audio8 TTS (voice cloning) | False |
Audio8 is a 0.6B-parameter model running through one shared, lock-serialized instance rather than a pipeline per thread, so there's no way to overlap generation the way Kokoro does. Rather than offer a JIT toggle that would just stall constantly, the app disables it outright: with Audio8 active the "JIT streaming" entry under Options is greyed out, its tooltip reading Audio8 TTS (voice cloning) doesn't support streaming - runs as Standard.. Every run on that engine falls back to Standard batch generation, automatically, no separate setting to change.