Top Speed Track Creation Guide
Table of Contents
- 1. Introduction
- 2. How to Imagine a Track Shape as an Author
- 3. Folder Layout, File Discovery, and Loading Rules
- 4. TSM File Format Rules
- 5. Sections and How They Connect
- 6. Detailed Key Reference
- 6.1 Meta Section
- 6.2 Weather Profile Sections
- 6.3 Room Sections
- 6.4 Segment Sections
- 6.5 Sound Source Sections
- 6.6 Value Parsing and Token Rules
- 7. Room Reverb Model and Full Preset Catalog
- 7.1 Reverb Parameter Meanings
- 7.2 Full Built-In Room Presets
- 8. Full Example TSM Track File
- 9. Validation and Troubleshooting
- 10. Practical Authoring Workflow
1. Introduction
This guide documents the current custom track format used by Top Speed and is based on the current parser and runtime code paths. It is written as an authoring reference, not a marketing overview, so the goal is practical correctness.
A custom track file controls four things at once: the road shape and surface flow, the active weather model and its transition behavior, the acoustic room profile applied while driving through segments, and optional custom sound sources placed on the track. Each of those systems is linked through ids and validated before the track is accepted.
This means track authoring is not only about writing valid keys. You also need to understand which keys are actually consumed by runtime, which keys are only metadata, how clamping changes extreme values, and which references must exist up front.
2. How to Imagine a Track Shape as an Author
The most accurate mental model is a timeline of segments that is replayed in a loop. Segment order is the track order. Segment length is physical distance in meters. Turn type changes how fast the lane center drifts left or right as the player moves through that segment.
straight keeps lateral center drift at zero. Left and right curves apply continuous drift with different strengths. Because drift is evaluated across segment length, long segments create larger accumulated center movement than short segments with the same turn type.
Current curve-strength factors used by runtime are:
straight:0easy_left/easy_right:0.5left/right:0.6667hard_left/hard_right:1.0hairpin_left/hairpin_right:1.5
Segment width is separate from turn shape. If width > 0, that segment uses its own width. If width <= 0, runtime falls back to the default lane width. This matters for track feel because the exact same turn sequence can feel forgiving or punishing depending on width profile.
A practical workflow is to first author only segment sequence, length, and width, then drive and tune pacing. Add weather, rooms, and custom sounds after geometry feels right.
3. Folder Layout, File Discovery, and Loading Rules
Custom loading accepts either a folder path or a file path. If you pass a folder, loader scans that folder for *.tsm and picks the first filename in case-insensitive sort order. If you pass a file path, it must be a .tsm file that exists inside an existing folder.
Recommended layout:
Tracks/
MyTrack/
track.tsm
Audio/
ambience_loop.ogg
birds_1.ogg
Sound paths in sound sections are resolved relative to the folder containing the tsm file. They are not resolved from the game root and not resolved from the Sounds asset root. This keeps each custom track self-contained.
Display name resolution for custom tracks follows this order:
meta.nameif defined and non-empty.- Parent folder name.
- Filename without extension.
4. TSM File Format Rules
TSM is line-based and supports exactly two statement forms: section headers and key-value assignments.
Section header format:
[kind]
[kind:id]
Key-value format:
key = value
Inline comments start with # and are stripped before parsing. Empty lines are ignored.
Supported section kinds are meta, segment, weather, room, and sound. segment, weather, room, and sound require ids ([kind:id]). meta does not use an id ([meta]).
Unknown section kinds fail validation. Unknown keys in strict sections also fail validation, except extension-style keys that start with meta or metadata.
Section order is flexible. The parser reads top-to-bottom and finalizes each section object when a new section header starts. Repeating a key in the same section is allowed; the later value overrides the earlier value for that section object.
Key and section-kind parsing is normalized to lower-case, and spaces/hyphens become underscores. IDs are trimmed and matched case-insensitively. ID uniqueness is enforced per section family (segment, weather, room, sound), so duplicate ids in the same family are validation errors.
5. Sections and How They Connect
At least one segment section is required. Also, meta.weather is required and must point to an existing weather profile id. If either is missing, the track is rejected.
Segments are the backbone and can reference:
- weather profile ids
- room ids or built-in room preset names
- sound source ids
Sound sources can reference segment ids with start_area and end_area, so segment ids are used by both geometry and audio trigger logic.
Room behavior has two override layers:
- room section values override room preset baseline
- segment room override keys override the selected room only for that segment
Weather behavior also has two layers:
- track-level default profile from
meta.weather - optional segment-level weather id with optional blend time (
weather_transition_seconds)
6. Detailed Key Reference
6.1 Meta Section
Header syntax for this section is [meta].
name
This is the display name used for the custom track in menus and announcements.
Allowed values:
- Any non-empty text value.
version
This is optional author metadata for your own revisioning. It is stored with track data but does not change runtime driving/audio behavior by itself.
Allowed values:
- Any non-empty text value.
weather
This is the required default weather profile id for the track.
Allowed values:
- Any existing weather section id.
- Example: if the file contains
[weather:clear], thenweather = clearis valid. - If the id does not exist, loading fails.
ambience
This selects the legacy ambience loop family.
Allowed values:
noneDisables legacy ambience loop playback.desertUses the desert ambience loop behavior.airportUses the airport ambience loop behavior.
Alias values:
0:nonenoambience:none1:desert2:airport
pit_area
This controls whether the track has a pit area where cars can stop to refuel and change tires when fuel consumption or tire wear is enabled. It is optional and defaults to true, so every track has a pit area unless you turn it off here.
Allowed values:
- Omitted, or any value other than the false tokens below: the track has a pit area. If you do not define pit entry/exit segments (see section 6.4), the pit area falls back to the start/finish line.
false(also0,no,off): the track has no pit area. Any pit entry/exit segment markers are ignored, and a validation warning is reported. Players cannot pit on such a track, so do not pair it with fuel consumption or tire wear.
6.2 Weather Profile Sections
Header syntax is [weather:<id>], for example [weather:clear].
kind
This picks the base preset for the profile. When this key is set, runtime first loads the preset values, then applies any explicit numeric keys in the same weather section.
Allowed values:
sunnyClear weather baseline with neutral wind and long visibility.rainRain profile baseline with wet ambience emphasis.windWind profile baseline with stronger lateral wind.stormStorm profile baseline with strongest weather intensity.
Alias values:
0:sunny1:rainrainy:rain2:windwindy:wind3:stormstormy:storm
longitudinal_wind_mps
This is the wind component along the driving axis, in meters per second. Positive values act like headwind and increase relative air speed; negative values act like tailwind.
Allowed values:
- Any finite numeric value.
lateral_wind_mps
This is the crosswind component in meters per second. It contributes side-air-speed into aerodynamic drag magnitude.
Allowed values:
- Any finite numeric value.
air_density
This controls air density in kg/m³ used by aerodynamic force calculations.
Allowed values:
- Any numeric value greater than
0.
Runtime note: if an invalid non-positive value still reaches constructor-level code, it falls back to 1.225.
drafting_factor
This is a direct multiplier on aerodynamic drag in the resistance model.
1.0 is neutral. Values above 1.0 increase drag. Values below 1.0 reduce drag.
Allowed values:
- Any numeric value greater than
0.
Runtime note: constructor-level clamping enforces a floor of 0.1.
temperature_c
This stores weather temperature in Celsius for profile state. Current driving resistance logic does not directly depend on this key, but it remains part of the weather profile data.
Allowed values:
- Any finite numeric value.
humidity
This stores relative humidity as a normalized ratio.
Allowed values:
- Any numeric value from
0to1.
Runtime note: values are clamped to 0..1 in weather profile construction.
pressure_kpa
This stores atmospheric pressure in kPa for the profile.
Allowed values:
- Any numeric value greater than
0.
Runtime note: if invalid non-positive input reaches constructor-level code, it falls back to 101.325.
visibility_m
This stores visibility distance in meters for weather profile state.
Allowed values:
- Any numeric value greater than
0.
Runtime note: if invalid non-positive input reaches constructor-level code, it falls back to 20000.
rain_gain
This sets rain-loop weather intensity gain for the profile.
Allowed values:
- Any numeric value greater than or equal to
0.
Runtime note: profile stores 0..4 after clamping; playback path currently applies final 0..1 clamp before source volume.
wind_gain
This sets wind-loop weather intensity gain for the profile.
Allowed values:
- Any numeric value greater than or equal to
0.
Runtime note: profile stores 0..4 after clamping; playback path currently applies final 0..1 clamp before source volume.
storm_gain
This sets storm-loop weather intensity gain for the profile.
Allowed values:
- Any numeric value greater than or equal to
0.
Runtime note: profile stores 0..4 after clamping; playback path currently applies final 0..1 clamp before source volume.
Weather switching behavior:
When a segment sets weather = some_id, runtime blends toward that profile.
Blend speed is controlled by segment key weather_transition_seconds.
6.3 Room Sections
Header syntax is [room:<id>], for example [room:tunnel_a].
name
This is an optional readable label for the room profile.
Allowed values:
- Any non-empty text value.
room_preset
This selects the built-in preset baseline used to initialize room acoustics. Any numeric room keys in the same section override that baseline.
Allowed values:
- Any preset id listed in Section 7.2.
reverb_time
This controls total decay duration of the room tail in seconds.
Allowed values:
- Any numeric value.
- Runtime clamps to non-negative.
reverb_gain
This controls overall reverb return level for the room.
Allowed values:
- Any numeric value.
- Runtime clamps to
0..1.
hf_decay_ratio
This controls how fast high frequencies decay compared to low/mid frequencies in the reverb tail. Lower values darken quickly. Higher values preserve brightness longer.
Allowed values:
- Any numeric value.
- Runtime clamps to
0..1.
late_reverb_gain
This controls the gain of the late-tail component (late reflections).
Allowed values:
- Any numeric value.
- Runtime clamps to
0..1.
diffusion
This controls reflection density and smoothness. Lower values sound more discrete/grainy; higher values sound smoother and denser.
Allowed values:
- Any numeric value.
- Runtime clamps to
0..1.
air_absorption
This controls how much high-frequency content is lost as sound travels through air. Lower values keep sources brighter at distance. Higher values make distant sources duller faster.
Allowed values:
- Any numeric value.
- Runtime clamps to
0..1.
occlusion_scale
This controls how strongly obstacles reduce the direct sound path. Lower values make obstacles less blocking. Higher values make obstacles more blocking.
Allowed values:
- Any numeric value.
- Runtime clamps to
0..1.
transmission_scale
This controls how much sound leaks through boundaries such as walls or heavy structures. Lower values make through-wall sound weaker and more blocked. Higher values let more sound pass through.
Allowed values:
- Any numeric value.
- Runtime clamps to
0..1.
occlusion_override
This is an optional direct value for occlusion. When set, it overrides the derived occlusion amount for the room/profile path.
Allowed values:
- Any numeric value.
- Runtime clamps to
0..1when set.
transmission_override
This sets one transmission value and applies it to all three frequency bands (low, mid, high). Use this when you want one global transmission override instead of per-band tuning.
Allowed values:
- Any numeric value.
- Runtime clamps to
0..1when set.
transmission_override_low
This sets low-band transmission override.
Allowed values:
- Any numeric value.
- Runtime clamps to
0..1when set.
transmission_override_mid
This sets mid-band transmission override.
Allowed values:
- Any numeric value.
- Runtime clamps to
0..1when set.
transmission_override_high
This sets high-band transmission override.
Allowed values:
- Any numeric value.
- Runtime clamps to
0..1when set.
air_absorption_override
This sets one air-absorption override and applies it to low, mid, and high bands together.
Allowed values:
- Any numeric value.
- Runtime clamps to
0..1when set.
air_absorption_override_low
This sets low-band air-absorption override.
Allowed values:
- Any numeric value.
- Runtime clamps to
0..1when set.
air_absorption_override_mid
This sets mid-band air-absorption override.
Allowed values:
- Any numeric value.
- Runtime clamps to
0..1when set.
air_absorption_override_high
This sets high-band air-absorption override.
Allowed values:
- Any numeric value.
- Runtime clamps to
0..1when set.
Segment reference behavior: A segment can reference a room section id or preset id. If segment-level room overrides are present, those apply after the selected room baseline.
6.4 Segment Sections
Header syntax is [segment:<id>], for example [segment:s12].
type
This sets the curve class for the segment. The selected class affects how road center drifts across this segment as distance advances.
Allowed values:
straightNo lateral drift.easy_leftGentle left drift.leftMedium left drift.hard_leftStrong left drift.hairpin_leftVery strong left drift.easy_rightGentle right drift.rightMedium right drift.hard_rightStrong right drift.hairpin_rightVery strong right drift.
Alias values:
0:straight1:easy_left2:left3:hard_left4:hairpin_left5:easy_right6:right7:hard_right8:hairpin_right
surface
This sets segment surface category.
Allowed values:
asphaltStandard paved behavior.gravelLoose-surface behavior.waterWet/low-grip behavior.sandSoft-surface behavior.snowSnow-like low-grip behavior.
Alias values:
0:asphalt1:gravel2:water3:sand4:snow
noise
This sets legacy segment noise behavior.
Allowed values:
noneNo legacy segment noise.crowdCrowd ambience behavior.oceanOcean ambience behavior.runwayRunway/airplane behavior.clockClock ambience behavior.jetJet event behavior.thunderThunder event behavior.pilePile ambience behavior.constructionConstruction ambience behavior.riverRiver ambience behavior.helicopterHelicopter event behavior.owlOwl event behavior.
Alias values:
0:nonenonoise:noneoff:none1:crowd2:ocean3:runway4:clock5:jet6:thunder7:pile8:construction9:river10:helicopter11:owl
length
This sets segment length in meters. The parser enforces a minimum part length threshold.
Allowed values:
- Any numeric value.
Values below the current parser minimum are warned and clamped.
Default minimum is
50meters.
width
This sets segment width override in meters for this segment.
Allowed values:
- Any numeric value.
- Runtime clamps to
>= 0. - Non-positive values fall back to default lane width.
height
This stores segment height value.
Allowed values:
- Any numeric value.
- Parsed and stored, not currently applied by active road geometry behavior.
weather
This assigns weather profile id for this segment.
Allowed values:
- Existing weather profile ids only.
weather_transition_seconds
This sets blend duration when transitioning into this segment's weather profile.
Allowed values:
- Finite numeric values
>= 0.
room
This assigns room/acoustics source for this segment.
Allowed values:
- Existing room section id.
- Built-in room preset id.
Alias keys:
room_profile:roomroom_preset:room
room_profile
This is an alias key for room.
Allowed values:
- Same as
room.
room_preset
This is an alias key for room.
Allowed values:
- Same as
room.
sound_sources
This assigns sound source ids directly to this segment.
Allowed values:
- Comma-separated list of existing sound ids.
Alias keys:
sound_source_ids:sound_sources
sound_source_ids
This is an alias key for sound_sources.
Allowed values:
- Same as
sound_sources.
pit
This marks the segment as the pit entry, the pit exit, or both, defining where pit road connects to the track. It only matters when the track has a pit area (see pit_area in section 6.1). A single segment can carry both markers by using two pit lines in any order.
Allowed values:
pit_entry(also accepted aspitentry) Cars leave the track and enter pit road at the start of this segment.pit_exit(also accepted aspitexit) Cars rejoin the track at this segment, at the position described below.
If you do not mark any pit entry or exit segments, the pit area falls back to the start/finish line.
Pit entry and exit behavior: - Cars always enter pit road at the start of the pit-entry segment. - If the pit-exit segment is the same segment as the pit-entry segment, or comes later in the lap, cars rejoin at the end of the pit-exit segment on the same lap. - As a special case of the above, if the pit-exit segment is the last segment on the lap, cars rejoin at its end, which sits right at the start/finish line. They therefore cross it immediately and begin the next lap, so this layout effectively advances the lap on exit as well. - If the pit-exit segment comes earlier in the lap than the pit-entry segment, a car that pits drives all the way through the pit and rejoins at the start of the pit-exit segment on the next lap. The car's lap count advances as it comes out, which is expected. Use this layout deliberately when you want the pit lane to carry cars across the start/finish line.
Additional segment note: Room numeric keys and room override keys can appear directly in segment sections. When present, they override room acoustics only for that segment.
Simple shaping strategy:
- Build shape with
type+length. - Set consistent
widthband. - Add
surface. - Add weather/room transitions.
- Add sounds last.
6.5 Sound Source Sections
Header syntax supports two forms:
[sound:<id>][sound_<type>:<id>]In this form,<type>can be:ambientstaticmovingrandom
Example: [sound_random:wind_gusts] implicitly sets type = random.
type
This sets sound source behavior type.
Allowed values:
ambientEnvironment-style source behavior.staticFixed source behavior.movingPath/motion-driven source behavior.randomVariant-selecting source behavior.
Alias values:
0:ambient1:static2:moving3:random
path
Primary source file path.
Allowed values:
- Track-relative path only.
Alias keys:
file:path
file
This is an alias key for path.
Allowed values:
- Same as
path.
variant_paths
Additional file variants for selection.
Allowed values:
- Comma-separated track-relative file paths.
- Empty list is invalid.
variant_source_ids
Additional variants by referencing other sound source ids.
Allowed values:
- Comma-separated list of existing sound source ids.
- Empty list is invalid.
random_mode
Variant refresh mode.
Allowed values:
onstartChoose variant once when created/started, then keep it.perareaRefresh variant when area/segment context changes.
Alias values:
0:onstart1:perarea
loop
Loop playback flag.
Allowed values:
trueEnabled.falseDisabled.
Alias values:
1:true0:falseyes:trueno:falseon:trueoff:false
spatial
Enable spatialized source behavior.
Allowed values:
trueEnabled.falseDisabled.
Alias values:
1:true0:falseyes:trueno:falseon:trueoff:false
allow_hrtf
Allow HRTF in spatial path.
Allowed values:
trueEnabled.falseDisabled.
Alias values:
1:true0:falseyes:trueno:falseon:trueoff:false
global
Keep source globally active without area/segment gating.
Allowed values:
trueEnabled.falseDisabled.
Alias values:
1:true0:falseyes:trueno:falseon:trueoff:false
volume
Base source gain.
Allowed values:
- Any numeric value.
- Runtime clamps to
0..1.
fade_in
Fade-in time in seconds.
Allowed values:
- Any numeric value.
- Runtime clamps to non-negative.
fade_out
Fade-out time in seconds.
Allowed values:
- Any numeric value.
- Runtime clamps to non-negative.
crossfade_seconds
Crossfade time for variant transition.
Allowed values:
- Any numeric value.
- Runtime clamps to non-negative.
pitch
Playback pitch factor.
Allowed values:
- Any numeric value.
- Runtime replaces
<= 0with1.
pan
Stereo pan value.
Allowed values:
- Any numeric value.
- Runtime clamps to
-1..1.
min_distance
Spatial minimum distance setting.
Allowed values:
- Any numeric value.
max_distance
Spatial maximum distance setting.
Allowed values:
- Any numeric value.
rolloff
Spatial distance rolloff setting.
Allowed values:
- Any numeric value.
start_area
Segment id trigger for activation start.
Allowed values:
- Existing segment ids only.
end_area
Segment id trigger for activation end.
Allowed values:
- Existing segment ids only.
start_position
Activation start position.
Allowed values:
- Vector text
x,y,z.
end_position
Activation end position.
Allowed values:
- Vector text
x,y,z.
position
Static or anchor position.
Allowed values:
- Vector text
x,y,z.
start_radius
Radius for start position trigger.
Allowed values:
- Any numeric value.
Runtime note: missing or non-positive values fall back to 1 meter at trigger evaluation.
end_radius
Radius for end position trigger.
Allowed values:
- Any numeric value.
Runtime note: missing or non-positive values fall back to 1 meter at trigger evaluation.
speed
Moving-source speed value.
Allowed values:
- Any numeric value.
Alias keys:
speed_meters_per_second:speed
speed_meters_per_second
This is an alias key for speed.
Allowed values:
- Same as
speed.
Sound path validation note: Absolute paths, drive-letter paths, and traversal path segments are rejected.
Runtime activation summary:
If global = true, source is active without area/segment checks.
Otherwise activation depends on segment assignment, area spans, and start/end trigger conditions.
6.6 Value Parsing and Token Rules
Numeric parsing is invariant-culture, so decimals must use ..
Enum parsing is case-insensitive and tolerant of spaces/hyphens/underscores in token text.
Boolean parsing accepts 1/0, true/false, yes/no, and on/off.
Vector keys must be exactly three comma-separated float values (x,y,z).
Unknown keys are validation errors in strict sections unless key name starts with meta or metadata.
Sound path safety rules reject rooted paths, drive letters, and traversal segments (. and .. path components).
Cross-reference validation runs after parse and ensures referenced weather ids, room ids, segment ids, and sound ids all exist.
7. Room Reverb Model and Full Preset Catalog
7.1 Reverb Parameter Meanings
This section explains each room parameter in plain language.
| Parameter | What it controls | What happens when increased |
|---|---|---|
reverb_time_seconds |
How long the reverb tail lasts before fading out. | The space sounds longer and more lingering. |
reverb_gain |
Overall strength of the reverb return. | Reflections become louder compared to the dry signal. |
hf_decay_ratio |
How long high frequencies survive in the tail relative to the rest. | High-frequency content stays brighter for longer. |
late_reverb_gain |
Level of the late, dense tail component. | The late reverb body becomes stronger and more obvious. |
diffusion |
How dense/smooth early and late reflections feel. | Reflections sound less discrete and more blended/smooth. |
air_absorption |
High-frequency loss caused by distance through air. | Distant sound loses more brightness and clarity. |
occlusion_scale |
How strongly obstacles reduce direct sound. | Obstacle blocking effect becomes stronger. |
transmission_scale |
How much sound passes through walls/structures. | More through-boundary sound leakage is audible. |
7.2 Full Built-In Room Presets
This table uses separate columns for every reverb parameter so values are directly comparable without tuple shorthand.
| Category | Preset | Acoustic character | reverb_time_seconds | reverb_gain | hf_decay_ratio | late_reverb_gain | diffusion | air_absorption | occlusion_scale | transmission_scale |
|---|---|---|---|---|---|---|---|---|---|---|
| Outdoor environments | outdoor_open |
Very open plain with minimal tail. | 0.35 | 0.08 | 0.85 | 0.08 | 0.20 | 0.65 | 0.35 | 0.75 |
| Outdoor environments | outdoor_field |
Open field, slightly fuller than open plain. | 0.45 | 0.10 | 0.82 | 0.10 | 0.25 | 0.62 | 0.38 | 0.72 |
| Outdoor environments | outdoor_urban |
Dense urban reflections and stronger return energy. | 0.90 | 0.22 | 0.70 | 0.24 | 0.45 | 0.48 | 0.55 | 0.52 |
| Outdoor environments | outdoor_suburban |
Mixed suburban reflections with medium tail. | 0.75 | 0.18 | 0.74 | 0.20 | 0.38 | 0.50 | 0.48 | 0.58 |
| Outdoor environments | outdoor_forest |
Damped highs, foliage-heavy absorption feel. | 0.70 | 0.16 | 0.52 | 0.18 | 0.32 | 0.82 | 0.60 | 0.60 |
| Outdoor environments | outdoor_mountains |
Large reflected space with longer tail. | 1.80 | 0.34 | 0.52 | 0.36 | 0.42 | 0.42 | 0.55 | 0.52 |
| Outdoor environments | outdoor_desert |
Dry open terrain with modest reflection body. | 0.55 | 0.12 | 0.76 | 0.12 | 0.26 | 0.58 | 0.42 | 0.66 |
| Outdoor environments | outdoor_snowfield |
Open but softened highs, snowy damping. | 0.90 | 0.20 | 0.62 | 0.24 | 0.34 | 0.70 | 0.45 | 0.62 |
| Outdoor environments | outdoor_coast |
Shoreline openness with moderate reflections. | 0.85 | 0.20 | 0.68 | 0.22 | 0.36 | 0.52 | 0.46 | 0.60 |
| Outdoor environments | outdoor_valley |
Broad valley bloom with extended return. | 1.60 | 0.30 | 0.56 | 0.34 | 0.46 | 0.46 | 0.58 | 0.52 |
| Tunnels | tunnel_short |
Short tunnel with clear reflections. | 1.10 | 0.48 | 0.62 | 0.52 | 0.72 | 0.22 | 0.80 | 0.32 |
| Tunnels | tunnel_medium |
Medium tunnel with fuller tail. | 1.80 | 0.60 | 0.56 | 0.62 | 0.78 | 0.20 | 0.86 | 0.26 |
| Tunnels | tunnel_long |
Long tunnel with sustained late field. | 2.70 | 0.72 | 0.50 | 0.76 | 0.82 | 0.18 | 0.90 | 0.22 |
| Tunnels | tunnel_concrete |
Hard concrete tunnel signature. | 2.10 | 0.66 | 0.54 | 0.70 | 0.80 | 0.20 | 0.88 | 0.24 |
| Tunnels | tunnel_brick |
Brick tunnel, warmer and slightly shorter. | 1.70 | 0.58 | 0.58 | 0.62 | 0.76 | 0.22 | 0.84 | 0.30 |
| Tunnels | tunnel_metal |
Metallic tunnel with bright return energy. | 2.00 | 0.70 | 0.46 | 0.74 | 0.84 | 0.16 | 0.88 | 0.22 |
| Tunnels | tunnel_stone |
Stone tunnel with heavy late response. | 2.40 | 0.68 | 0.50 | 0.72 | 0.80 | 0.18 | 0.90 | 0.24 |
| Underpasses and bridge structures | underpass_small |
Tight underpass with quick dense return. | 0.95 | 0.38 | 0.62 | 0.42 | 0.62 | 0.26 | 0.78 | 0.34 |
| Underpasses and bridge structures | underpass_large |
Larger underpass with longer reflection train. | 1.35 | 0.46 | 0.56 | 0.52 | 0.68 | 0.24 | 0.82 | 0.30 |
| Underpasses and bridge structures | overhang |
Partial cover, moderate reflection spread. | 0.75 | 0.30 | 0.66 | 0.34 | 0.56 | 0.28 | 0.72 | 0.38 |
| Underpasses and bridge structures | bridge_truss |
Bridge truss cavity response. | 0.65 | 0.24 | 0.64 | 0.26 | 0.44 | 0.34 | 0.60 | 0.46 |
| Garages and parking spaces | garage_small |
Small garage with compact reflections. | 0.95 | 0.40 | 0.64 | 0.44 | 0.62 | 0.30 | 0.72 | 0.34 |
| Garages and parking spaces | garage_medium |
Medium garage with broader tail. | 1.30 | 0.48 | 0.60 | 0.52 | 0.68 | 0.28 | 0.74 | 0.30 |
| Garages and parking spaces | garage_large |
Large garage with stronger late field. | 1.80 | 0.56 | 0.58 | 0.60 | 0.72 | 0.26 | 0.76 | 0.28 |
| Garages and parking spaces | parking_open |
Mostly open parking structure. | 0.70 | 0.20 | 0.70 | 0.22 | 0.38 | 0.40 | 0.48 | 0.58 |
| Garages and parking spaces | parking_covered |
Covered parking with stronger reflections. | 1.20 | 0.44 | 0.60 | 0.48 | 0.64 | 0.28 | 0.72 | 0.34 |
| Garages and parking spaces | parking_underground |
Underground parking, enclosed and persistent. | 1.90 | 0.62 | 0.54 | 0.66 | 0.76 | 0.22 | 0.84 | 0.24 |
| Warehouses and industrial halls | warehouse_small |
Small warehouse with clear room response. | 1.10 | 0.38 | 0.62 | 0.42 | 0.66 | 0.30 | 0.70 | 0.34 |
| Warehouses and industrial halls | warehouse_medium |
Medium warehouse with fuller tail. | 1.70 | 0.50 | 0.56 | 0.56 | 0.74 | 0.28 | 0.74 | 0.30 |
| Warehouses and industrial halls | warehouse_large |
Large warehouse with long decay. | 2.40 | 0.62 | 0.50 | 0.68 | 0.80 | 0.24 | 0.78 | 0.26 |
| Warehouses and industrial halls | factory_hall |
Industrial hall with dense reflections. | 2.20 | 0.60 | 0.48 | 0.66 | 0.78 | 0.24 | 0.80 | 0.26 |
| Warehouses and industrial halls | machine_shop |
Machine room, tighter than warehouse halls. | 1.30 | 0.44 | 0.54 | 0.50 | 0.70 | 0.26 | 0.76 | 0.30 |
| Hangars and transit stations | hangar_small |
Small hangar with broad reflections. | 2.00 | 0.56 | 0.54 | 0.60 | 0.76 | 0.24 | 0.72 | 0.30 |
| Hangars and transit stations | hangar_large |
Very large hangar with long reverb field. | 3.10 | 0.68 | 0.48 | 0.74 | 0.82 | 0.22 | 0.76 | 0.26 |
| Hangars and transit stations | airport_terminal |
Terminal concourse reflection style. | 1.80 | 0.52 | 0.58 | 0.58 | 0.74 | 0.28 | 0.66 | 0.36 |
| Hangars and transit stations | subway_station |
Deep station with strong enclosed tail. | 2.30 | 0.64 | 0.50 | 0.70 | 0.80 | 0.22 | 0.84 | 0.24 |
| Hangars and transit stations | rail_station |
Large station, less enclosed than subway. | 1.90 | 0.54 | 0.56 | 0.60 | 0.74 | 0.26 | 0.72 | 0.32 |
| Corridors, basements, and secure spaces | corridor_short |
Short corridor with quick feedback. | 0.85 | 0.36 | 0.62 | 0.40 | 0.58 | 0.30 | 0.72 | 0.34 |
| Corridors, basements, and secure spaces | corridor_long |
Long corridor with stretched reflections. | 1.40 | 0.50 | 0.56 | 0.56 | 0.68 | 0.26 | 0.80 | 0.28 |
| Corridors, basements, and secure spaces | stairwell_concrete |
Concrete stairwell with firm late return. | 1.60 | 0.54 | 0.54 | 0.58 | 0.70 | 0.26 | 0.78 | 0.28 |
| Corridors, basements, and secure spaces | basement_low |
Low basement, medium enclosed tail. | 1.10 | 0.44 | 0.58 | 0.48 | 0.66 | 0.28 | 0.76 | 0.30 |
| Corridors, basements, and secure spaces | basement_large |
Large basement with heavier late energy. | 1.90 | 0.58 | 0.52 | 0.64 | 0.76 | 0.24 | 0.82 | 0.26 |
| Corridors, basements, and secure spaces | bunker |
Heavy enclosed bunker response. | 2.10 | 0.64 | 0.46 | 0.70 | 0.80 | 0.20 | 0.90 | 0.20 |
| Corridors, basements, and secure spaces | vault |
Highly enclosed vault signature. | 2.60 | 0.72 | 0.42 | 0.78 | 0.84 | 0.18 | 0.92 | 0.18 |
| Halls, arenas, and stadiums | hall_small |
Small hall with coherent reflections. | 1.10 | 0.40 | 0.64 | 0.44 | 0.70 | 0.30 | 0.68 | 0.34 |
| Halls, arenas, and stadiums | hall_medium |
Medium hall with fuller density. | 1.70 | 0.52 | 0.58 | 0.56 | 0.78 | 0.28 | 0.72 | 0.30 |
| Halls, arenas, and stadiums | hall_large |
Large hall with long spacious tail. | 2.70 | 0.62 | 0.50 | 0.66 | 0.82 | 0.24 | 0.78 | 0.26 |
| Halls, arenas, and stadiums | arena_indoor |
Big indoor arena with high diffusion. | 3.00 | 0.66 | 0.48 | 0.72 | 0.84 | 0.24 | 0.70 | 0.32 |
| Halls, arenas, and stadiums | stadium_open |
Open stadium, lighter enclosure. | 1.50 | 0.45 | 0.60 | 0.50 | 0.70 | 0.40 | 0.40 | 0.60 |
| Halls, arenas, and stadiums | stadium_closed |
Closed stadium with extended late field. | 2.80 | 0.64 | 0.50 | 0.70 | 0.82 | 0.28 | 0.68 | 0.34 |
| Rooms and studios | room_small |
Small room with short focused response. | 0.70 | 0.30 | 0.70 | 0.32 | 0.62 | 0.36 | 0.60 | 0.40 |
| Rooms and studios | room_medium |
Medium room with balanced body and tail. | 1.10 | 0.40 | 0.62 | 0.42 | 0.70 | 0.30 | 0.62 | 0.34 |
| Rooms and studios | room_large |
Large room with longer lingering reflections. | 1.80 | 0.50 | 0.54 | 0.54 | 0.76 | 0.26 | 0.68 | 0.30 |
| Rooms and studios | studio_dry |
Dry studio response with short tail. | 0.35 | 0.12 | 0.78 | 0.14 | 0.40 | 0.50 | 0.40 | 0.70 |
| Rooms and studios | studio_live |
Live room studio with more bloom. | 0.90 | 0.34 | 0.66 | 0.38 | 0.66 | 0.34 | 0.58 | 0.44 |
| Rooms and studios | broadcast_booth |
Very dry booth with tight control. | 0.28 | 0.08 | 0.82 | 0.10 | 0.30 | 0.58 | 0.45 | 0.70 |
| Sacred, cavern, canyon, and sewer spaces | church_small |
Small church with pronounced tail. | 2.40 | 0.56 | 0.46 | 0.60 | 0.82 | 0.26 | 0.72 | 0.30 |
| Sacred, cavern, canyon, and sewer spaces | church_large |
Large church with long reverberant bloom. | 3.80 | 0.70 | 0.40 | 0.76 | 0.86 | 0.22 | 0.78 | 0.24 |
| Sacred, cavern, canyon, and sewer spaces | cathedral |
Very large sacred hall, very long decay. | 5.40 | 0.78 | 0.34 | 0.84 | 0.90 | 0.20 | 0.82 | 0.20 |
| Sacred, cavern, canyon, and sewer spaces | cave_small |
Small cave with dense enclosed reflections. | 2.60 | 0.62 | 0.46 | 0.66 | 0.74 | 0.20 | 0.86 | 0.24 |
| Sacred, cavern, canyon, and sewer spaces | cave_large |
Large cave with long dark tail. | 4.50 | 0.78 | 0.34 | 0.84 | 0.84 | 0.16 | 0.92 | 0.16 |
| Sacred, cavern, canyon, and sewer spaces | cave_ice |
Ice cave style with bright lingering return. | 3.80 | 0.72 | 0.40 | 0.80 | 0.80 | 0.24 | 0.86 | 0.22 |
| Sacred, cavern, canyon, and sewer spaces | canyon_narrow |
Narrow canyon with directional returns. | 2.10 | 0.54 | 0.46 | 0.58 | 0.52 | 0.34 | 0.64 | 0.42 |
| Sacred, cavern, canyon, and sewer spaces | canyon_wide |
Wide canyon with broader spread and less enclosure. | 2.90 | 0.60 | 0.44 | 0.64 | 0.48 | 0.36 | 0.56 | 0.48 |
| Sacred, cavern, canyon, and sewer spaces | sewer_brick |
Brick sewer channel with wet enclosed tail. | 2.10 | 0.62 | 0.50 | 0.68 | 0.78 | 0.22 | 0.86 | 0.22 |
| Sacred, cavern, canyon, and sewer spaces | sewer_concrete |
Concrete sewer with hard reflective body. | 2.40 | 0.68 | 0.46 | 0.74 | 0.82 | 0.20 | 0.88 | 0.20 |
8. Full Example TSM Track File
[meta]
name = Demo Accessible Track
version = 1
weather = clear
ambience = noambience
[weather:clear]
kind = sunny
longitudinal_wind_mps = 0
lateral_wind_mps = 0
air_density = 1.225
drafting_factor = 1
temperature_c = 22
humidity = 0.45
pressure_kpa = 101.325
visibility_m = 20000
rain_gain = 0
wind_gain = 0
storm_gain = 0
[weather:storm_edge]
kind = storm
longitudinal_wind_mps = 4
lateral_wind_mps = 8
air_density = 1.24
drafting_factor = 1
temperature_c = 17
humidity = 1
pressure_kpa = 99.8
visibility_m = 3500
rain_gain = 0.2
wind_gain = 0.4
storm_gain = 1.0
[room:open_day]
room_preset = outdoor_open
[room:tunnel_a]
room_preset = tunnel_medium
reverb_gain = 0.62
late_reverb_gain = 0.65
[sound_ambient:birds]
path = Audio/birds_loop.ogg
loop = true
volume = 0.5
spatial = false
[sound_random:wind_gusts]
variant_paths = Audio/wind_gust_1.ogg, Audio/wind_gust_2.ogg, Audio/wind_gust_3.ogg
random_mode = perarea
loop = true
volume = 0.4
spatial = true
allow_hrtf = true
fade_in = 0.15
fade_out = 0.15
crossfade_seconds = 0.5
start_area = s2
end_area = s5
[segment:s1]
type = straight
surface = asphalt
noise = none
length = 300
width = 10
room = open_day
sound_sources = birds
[segment:s2]
type = easy_right
surface = asphalt
noise = crowd
length = 220
room = open_day
sound_source_ids = wind_gusts
[segment:s3]
type = hard_right
surface = asphalt
noise = none
length = 180
room = tunnel_a
weather = storm_edge
weather_transition_seconds = 2.5
[segment:s4]
type = straight
surface = asphalt
noise = jet
length = 260
room = tunnel_a
[segment:s5]
type = left
surface = asphalt
noise = none
length = 240
room = open_day
weather = clear
weather_transition_seconds = 1.5
9. Validation and Troubleshooting
Track loading has a strict validation phase before runtime objects are built. Errors stop loading. Warnings allow loading but values may be adjusted by clamp rules.
Common hard failures and direct fixes:
| Failure | Why it happens | Fix |
|---|---|---|
| Missing default weather profile | meta.weather is empty or points to unknown id |
Define weather = some_id in meta and add [weather:some_id] section |
| Duplicate section ids | Two sections in same family reuse same id | Rename ids so each segment, weather, room, and sound id is unique |
| Unknown enum token | Value text does not map to a supported enum token/int | Use valid token or numeric enum value from this guide |
| Unknown key in strict section | Misspelled key or unsupported key name | Correct spelling; keep custom tags under meta* / metadata* prefix |
| Unknown reference id | Segment or sound references id that does not exist | Add missing target section or fix reference id text |
| Invalid sound path | Absolute path, drive-letter path, or traversal path | Use track-relative path only, for example Audio/wind.ogg |
| Invalid vector | Position value is not exactly x,y,z floats |
Write exactly three float values separated by commas |
Important non-fatal behavior:
- Segment lengths below 50 are warned and clamped up to 50.
- Many room and weather gain fields are clamped in runtime constructors.
pitch <= 0for sound sources becomes1.0.width <= 0does not fail; runtime falls back to default lane width.
10. Practical Authoring Workflow
A stable workflow is to build in four passes and test after each pass instead of writing all systems at once.
Pass 1 is geometry only: meta, one weather profile, and segments with type, length, surface, width. Confirm pacing, curve flow, and lap feel.
Pass 2 is weather transitions: add extra weather profiles, then add segment-level weather and weather_transition_seconds only where transitions are intentional. Confirm transitions are smooth and occur at expected segment boundaries.
Pass 3 is acoustics: add room presets or room sections for specific areas like tunnels and enclosed structures. If needed, use segment room overrides for local tuning instead of duplicating many room sections.
Pass 4 is sound sources: start with one simple source with known good file path, then add spatial behavior, area triggers, and random variants. Validate each sound id reference from segments and area ids from sound triggers.
Keep a companion plain-text sequence that describes segment order, distance, and intent. When behavior is wrong, compare the sequence against runtime behavior to isolate whether the problem is geometry, weather ids, room selection, or sound trigger references.