Config Reference¶
Every table and key in the config — the base Data\SKSE\Plugins\AudioUtil\AudioUtil.toml and any AudioUtil\config\*.toml overlays, which are merged into one effective config. Defaults shown are the DLL's internal defaults, applied when a key is absent from every file. All keys/names are normalized (case- and space-insensitive).
Paths written 'Sound\...' are Data-relative. Single-quoted TOML literal strings are used throughout so backslashes need no escaping.
[general]¶
Base-only section
[general] (along with [ppa], the [lipsync] scalar tuning, and the [gag] enable/default_category toggles) is a global section, read only from the base AudioUtil.toml. If a config\*.toml overlay sets any of these, it is ignored with a warning in AudioUtil.log. The two additive exceptions inside those tables — [lipsync] block_categories and [gag] keywords — do merge from every file. See the merge rules.
[general]
log_level = "info" # trace | debug | info | warn | error
sound_flags = 0x1A # BuildSoundDataFromFile flags
sound_priority = 128
default_female_slot = "F1"
default_male_slot = "M1"
pc_female_slot = "" # reserved player slot; empty = no reservation
pc_male_slot = ""
voice_3d = true # 3D-position voices at the speaker; false = flat/2D
voice_no_interrupt = false # skip a new line while its channel is still playing
| Key | Type | Default | Meaning |
|---|---|---|---|
log_level |
string | "info" |
Verbosity of AudioUtil.log. |
sound_flags |
int | 0x1A |
BuildSoundDataFromFile flags. Sweep with DebugPlayFile if audio is silent or not 3D. |
sound_priority |
int | 128 |
Sound priority passed to the engine. |
sfx_slot |
slot id | "SFX0" |
The [[slot]] whose categories PlaySFX resolves before the flat [sfx] table (see SFX). "" = table only. |
default_female_slot |
slot id | "F1" |
Slot for unrouted female actors. |
default_male_slot |
slot id | "M1" |
Slot for unrouted male actors (and creatures). |
pc_female_slot |
slot id | "" |
Reserved for the player; no NPC ever resolves to it. |
pc_male_slot |
slot id | "" |
Same, for a male PC. |
voice_3d |
bool | true |
true = 3D-position each voice at the speaker (distance attenuation). false = play flat/2D at full volume so every speaker is equally audible. Lipsync is unaffected either way. |
voice_no_interrupt |
bool | false |
true = when a PlayVoice names a channel still playing a line, skip the new line instead of cutting the old one off (per channel — different speakers still overlap). SFX and PlayFile/PlayFolder are unaffected. |
[ppa]¶
| Key | Type | Default | Meaning |
|---|---|---|---|
enable |
bool | true (internal) |
Gate the Accurate Penetration bridge. The shipped neutral TOML sets false; the bridge also needs the PPA plugin present. |
event_rate_ms |
int | 2000 |
Min interval per receiver for AudioUtilPPA_Update mod events. Floored at 1000 ms (values below are clamped up). Context-bit changes still fire immediately. |
[lipsync]¶
Scalars base-only; block_categories is additive
The scalar tuning below (enable, gain, attack_ms, release_ms, min_level, block_in_dialogue) is base-only — an overlay that sets it is ignored with a warning. block_categories is the exception: it merges from every file (base + overlays, union), so an add-on can mark its own category pools mouth-still without owning the base config.
[lipsync]
enable = true
gain = 1.0 # 0.0-2.0 mouth-open strength
attack_ms = 30 # how fast the mouth opens toward a louder level
release_ms = 90 # how fast it closes on quiet / clip end
min_level = 0.04 # envelope levels below this keep the mouth closed
block_in_dialogue = true # never lipsync an actor while they talk to the player
block_categories = ["Slurp"] # never drive the mouth (additive — merges across overlays)
| Key | Type | Default | Meaning |
|---|---|---|---|
enable |
bool | true |
Amplitude-envelope lipsync master switch. |
gain |
float | 1.0 |
Mouth-open strength, 0.0–2.0 (1.0 = envelope as-is). |
attack_ms |
int | 30 |
Opening speed toward a louder level. |
release_ms |
int | 90 |
Closing speed on quiet / clip end. |
min_level |
float | 0.04 |
Envelope levels below this keep the mouth closed. |
block_in_dialogue |
bool | true |
Suppress lipsync for an actor while they're in a dialogue with the player — the game's own dialogue/voice system drives that mouth from the real voice file, so AudioUtil stays off it to avoid fighting. Checked when the line starts and re-checked on a 500 ms throttle, so a conversation started mid-line hands the mouth back. |
block_categories |
string list | (none) | Additive (merges from the base + every overlay). Requested categories that never drive lipsync — the line plays mouth-still. Matched on the requested name (normalized), before aliasing, across every slot. For pools that aren't vocalization (oral SFX / slurping) or where another system owns the mouth (a climax/ahegao face). Same effect as passing blockLipSync=true to PlayVoice, but declared once in config. |
Runtime overrides: SetLipSyncEnabled / SetLipSyncGain. ReloadConfig restores these TOML values.
Lipsync is suppressed automatically for a gagged actor — when the speaker wears a device configured in [gag], the device owns the mouth and the DLL won't drive it (checked when the line starts and re-checked on a 500 ms throttle, so a gag equipped mid-line hands the mouth over). No mouth-open threshold to tune.
[gag]¶
Gag / deepthroat / mouth-owning devices. When a speaking actor wears any configured keyword, AudioUtil (1) routes their voice through the slot's gag_slot so a muffled clip plays instead of the clear line, and (2) suppresses lipsync (see above). Detection is native — the DLL reads the actor's worn items, no Papyrus wiring.
Dormant unless keywords is set, so the SFW-neutral default is unaffected.
[gag]
enable = true
default_category = "GagMoan" # muffled catch-all for categories the gag slot lacks
keywords = [ # 'Plugin.esp|FormID' (hex), like [npc_overrides] keys
'Devious Devices - Assets.esm|7EB8',
'ZaZAnimationPack.esm|8A4D',
'Toys.esm|8C2',
]
| Key | Type | Default | Meaning |
|---|---|---|---|
enable |
bool | true |
Master switch. Feature is also inert while keywords is empty. |
default_category |
category | "" |
Played from the gag slot when the requested category has no audio there — a muffled catch-all so a gagged actor never leaks a clear line (and never falls silent). Empty = no catch-all. |
keywords |
list of 'Plugin.esp\|FormID' |
(none) | Worn keywords that mark an actor as gagged. Hex form id, 0x optional; same format as [npc_overrides] keys. A keyword whose plugin isn't in the load order is skipped (one debug line), so listing optional mods is harmless. |
See Resolution → gag redirect for how the redirect interacts with the category chain.
[[slot]]¶
An array of tables — one per voice pack. See Overview → three ways and Resolution.
[[slot]]
id = "M4"
sex = "male" # "male" | "female" | "all"
path = 'Sound\fx\MyMod\M4' # scanned for <Category>\*.wav subfolders
fallback = "M1" # optional: backfill empty categories from this slot
gag_slot = "M4gag" # optional: muffled parallel slot used when gagged
| Key | Type | Meaning |
|---|---|---|
id |
string | Slot id ("F1", "M4", "C2", …). |
sex |
string | "male", "female", or "all". "all" is sex-neutral: it matches either sex on explicit routes ([race_map]/[voicetype_map]/[npc_overrides]) but is skipped by the blind default-by-sex fallback. For the category layer it shares the male aliases/[category_fallbacks.male] (where creature/neutral fallbacks are authored) and skips [male_only_remap]. Use it for creature slots (a creature's reported sex is unreliable) and the sfx slot. Plain "male"/"female" otherwise; creatures otherwise read as male. |
path |
path | Folder scanned for <Category>\*.wav subfolders. Optional if the slot is defined purely by explicit categories. Loose files only. |
fallback |
slot id | Optional. Per-category backfill slot when a category resolves to nothing here. Chains capped at 4 hops. |
gag_slot |
slot id | Optional. A parallel slot (another [[slot]], same category names, muffled audio) used instead of this one when the speaking actor is gagged. See [gag]. |
[slot.categories] |
table | Optional explicit categories (below). Win over same-named scanned folders. |
[slot.categories] — explicit categories¶
A category value may be an array (a file list) or a string (one folder):
[[slot]]
id = "C1"
sex = "male"
[slot.categories]
# array: explicit file list — needs no loose files, may point into a BSA
BattleCry = [
'Sound\FX\NPC\Giant\AttackVocal\NPC_Giant_AttackVocal_01.wav',
'Sound\FX\NPC\Giant\AttackVocal\NPC_Giant_AttackVocal_02.wav',
]
# string: one folder scanned for this category ('Sound\...' = full Data path,
# otherwise relative to the slot's path). Loose files only.
WarCry = 'Sound\fx\SomeOtherMod\shouts'
Rally = 'Sound\fx\SomeOtherMod\shouts'
- Array (file list) — bypasses the filesystem scan, so it can reference BSA-packed audio (loose files still win over archives at play time). List a file more than once to weight it — a clip listed twice is drawn about twice as often, and the shuffle bag's no-back-to-back guard still keeps it from playing twice in a row.
- String (folder) — scanned like a slot folder; lets several categories share one pool of files without copies. Loose files only.
Slot resolution tables¶
Full behavior in Voice & Category Resolution.
[voicetype_remap] # rename a voicetype (one hop) before slot lookup
enable = true
MaleGuard = "MaleNord" # values are voicetype names, not slot ids
[voicetype_map] # voicetype -> slot id, or a list of candidates
MaleEvenToned = "M1"
MaleBandit = ["M3", "M4"]
[race_map] # race-editor-id substring -> slot id(s); longest hint wins
Nord = "M4"
Troll = "C1"
[npc_overrides] # 'Plugin.esp|FormID' -> slot; ESL: last 3 hex digits
'MyFollower.esp|000D62' = "F2"
| Table | Key | Value |
|---|---|---|
[voicetype_remap] |
enable (bool) + voicetype name |
Target voicetype name (must be a [voicetype_map] key). |
[voicetype_map] |
voicetype name | Slot id or list of slot ids (spread deterministically per actor). |
[race_map] |
race-id substring | Slot id or list. Longest matching hint wins. |
[npc_overrides] |
'Plugin.esp\|FormID' |
Slot id. Checked before voicetype/race. |
Category layer tables¶
Full behavior in Category resolution.
[category_aliases.female] # script name -> on-disk folder
BattleCry = "War Shout"
[category_aliases.male]
# ...
[male_only_remap] # male slots only: female-engine category -> male category
ComfortLines = "Calm Lines"
[category_fallbacks.female] # substitute when a category has no folder (one hop)
Whisper = "Murmur"
[category_fallbacks.male]
# ...
| Table | Applies to | Meaning |
|---|---|---|
[category_aliases.female] / .male |
that sex's slots | Rename a requested category to the actual folder name. |
[male_only_remap] |
male slots only | Substitute a male category for a female-engine category name. |
[category_fallbacks.female] / .male |
that sex's slots | Substitute (one hop) when a category resolves to no folder. |
[groups]¶
Startup volumes, 0.0–1.0. Startup state only — MCM sliders override at runtime via SetGroupVolume. Groups are created on first use; these are just the conventional ones.
SFX — the sfx slot + [sfx] table¶
PlaySFX(name, ...) plays a named shuffle-bag pool, and a voice category with no folder falls through to an sfx pool of the same name (last resort). A name resolves in two places, in order:
- A category of the sfx slot — id
SFX0by default, setsfx_slotin[general]to rename (""disables it). Since it's a normal[[slot]], each sfx pool can use any category form — a scanned folder, an explicit file list (BSA-capable), or a folder ref. Preferred, and the only way to give an sfx pool BSA-packed audio. - The
[sfx]table — flatname = folder, loose files only. The value is a fullSound\...Data-relative path, same as a slot path.
Names are matched directly (no category_aliases/fallbacks). The slot's sex is irrelevant to sfx lookup.
[[slot]]
id = "SFX0" # PlaySFX resolves categories here first
sex = "all" # sex-neutral (irrelevant to sfx lookup)
[slot.categories]
Clap = 'Sound\fx\MyMod\SFX\Clap' # scanned folder
Slap = ['Sound\fx\MyMod\SFX\slap01.wav'] # explicit list — may point into a BSA
[sfx] # legacy flat table, still supported
Thud = 'Sound\fx\MyMod\thuds' # full Data path (loose files only)
Clap = 'Sound\fx\MyMod\SFX\Clap' # full Data path