Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

UTS Format (Sound Object Blueprint)

A .uts file is a sound emitter: one or more .wav clips, the distance they carry, and how the engine varies them each time they play. They cover environmental hums, crowd chatter and localized looping effects.

At a Glance

PropertyValue
Extension(s).uts
Magic SignatureUTS / V3.2
TypeSound Object Blueprint
Rust ReferenceView rakata_generics::Uts in Rustdocs

Field Schema

The format’s field families, as an orientation before the full list.

CategoryCoversRepresentative fields
Audio EmittersThe .wav clips the engine sequences or shuffles throughSounds
Spatial GeometryThe distance boundaries that decide where the sound is audibleMinDistance, MaxDistance
Playback AutomationHow the sound loops and strings togetherContinuous, Random, Active, Looping
Algorithmic VariationRuntime distortion of pitch and volumePitchVariation, FixedVariance, VolumeVrtn
Procedural GeneratorsMarks the sound as engine-generated ambiance such as crowd chatter or combat noiseGeneratedType

Engine Audits & Decompilation

Read from CSWSSoundObject::Load at 0x005c9040 in swkotor.exe. Provenance: derived, not attested. The rows below have not been separately re-derived, so they sit on the reverse-engineering queue.

A sound object has no script hooks. Everything it does comes from playback scalars and the randomised placement the Positional and Random* fields drive.

The load path

FunctionSizeBehaviour
Load1345 BThe main parser. It reads the emitter’s placement, its distance bounds, and the volume, pitch and looping scalars.
Sounds Listn/aWalks the list of clips, loading each Sound resref in turn.

Rules the engine enforces

Engine RuleRuntime Behaviour
Generated Type TruncationGeneratedType is read as a 32-bit integer and stored as its low byte alone. A value above 255 therefore arrives as a different generator type than the one written.
Spatial Loading ContextLoaded through the area’s static map (CSWSArea::LoadSounds), the engine skips the .uts coordinates and takes XPosition/YPosition/ZPosition from the .git. A sound carries no orientation; placement comes from the Positional/RandomPosition flags plus RandomRangeX/RandomRangeY.
Silent Sound ListsAn entry is pushed into playable memory only where the file supplied a Sound resref. Missing entries are ignored rather than erroring.

Almost every scalar carries over rather than defaulting to a literal

An absent field falls back to whatever the object already holds, so the constructor supplies the value rather than the read site:

FieldConstructedFieldConstructed
Active1Interval0
Positional1IntervalVrtn0
Looping0MinDistance10.0
Volume127MaxDistance20.0
VolumeVrtn0Continuous0
Times3Random0
PitchVariation0.0FixedVariance1.0
Hours0RandomPosition0
GeneratedType0RandomRangeX0.0
RandomRangeY0.0

Tag works the same way, starting empty, and its result is re-applied through SetTag either way.

Position is the exception. XPosition, YPosition and ZPosition fall back to a fixed literal 0.0 rather than the carried-over value, applied through SetPosition unconditionally. For a sound placed through a .git the instance’s own values win, so that 0.0 surfaces only for a sound opened outside the placement path.

The return value is whichever field was read last

Load returns the found-flag of its last read: the final Sound resref in the Sounds list, or ZPosition where the list was absent or empty. The area-level save loader deletes the sound object outright when that flag comes back false.

A vanilla sound always carries a ZPosition, so this never bites real saves. A hand-authored .git sound entry with neither a populated Sounds list nor a ZPosition is silently dropped on load.

Fields the engine never reads

What a writer should do with each is a separate question, and it has four possible answers: see the engine ignores this is not you may leave it out.

Finding TypeExplanation
Legacy Engine ArtifactsTemplateResRef, LocName, Comment, Elevation, Priority and PaletteID are inherited from Aurora, the BioWare engine Odyssey descends from. CSWSSoundObject::Load reads none of them.

Implemented Linter Rules (Rakata-Lint)

Phase 1 (intra-resource, no context)

Implemented under rakata_lint::rules::uts.

  1. UTS-001 (Volume Ceiling): Warns when Volume > 127; values outside the engine’s byte threshold cause distortion or clipping.
  2. UTS-002 (Audio Integrity): Warns when the Sounds list contains blank entries; the engine skips them silently.
  3. UTS-003 (Emitter Verification): Errors when the Sounds list is empty; the object loads as a dead audio node.
  4. UTS-004 (GeneratedType Truncation): Errors when GeneratedType > 255; the engine keeps the low byte alone, so the stored type is not the one written.
  5. UTS-005 (Legacy Engine Artifacts): Informs when TemplateResRef, Elevation, Priority, or PaletteID are populated; CSWSSoundObject::Load reads none of them.

Phase 2 (resource existence, requires LintContext)

Implemented under rakata_lint::rules::uts_range.

  1. UTS-006 (Sound Resref Existence): Warns when any non-blank Sounds[i].Sound does not resolve to a .wav resource in the configured sources. Blank entries are skipped (UTS-002 already covers them).

Every label the schema declares

Generated from the schema, so no label can be quietly left out. How to read these tables.

Fields nobody has examined

Whether the engine reads these has not been established, which is not the same as establishing that it does not. Where When absent carries an answer, that half is settled.

FieldTypeWhen absent
TemplateResRefCResRefNOT EXAMINED; we substitute ""
TagCExoStringNOT EXAMINED; we substitute ""
LocNameCExoLocStringNOT EXAMINED; we substitute empty
CommentCExoStringNOT EXAMINED; we substitute ""
ActiveBYTEkeeps 1
ContinuousBYTEkeeps 0
LoopingBYTEkeeps 0
PositionalBYTEkeeps 1
RandomPositionBYTEkeeps 0
RandomBYTEkeeps 0
ElevationFLOATNOT EXAMINED; we substitute 0.0
MaxDistanceFLOATkeeps 20.0
MinDistanceFLOATkeeps 10.0
RandomRangeXFLOATkeeps 0.0
RandomRangeYFLOATkeeps 0.0
IntervalDWORDkeeps 0
IntervalVrtnDWORDkeeps 0
PitchVariationFLOATkeeps 0.0
PriorityBYTENOT EXAMINED; we substitute 0
VolumeBYTEkeeps 127
VolumeVrtnBYTEkeeps 0
HoursDWORDkeeps 0
TimesBYTEkeeps 3
PaletteIDBYTENOT EXAMINED; we substitute 0
FixedVarianceFLOATkeeps 1.0
GeneratedTypeDWORDkeeps 0
SoundsListNOT EXAMINED; we substitute container
Sounds[].SoundCResRefNOT EXAMINED; we substitute ""
XPositionFLOATstamps 0.0
YPositionFLOATstamps 0.0
ZPositionFLOATstamps 0.0