Research and implement environmental audio in PRK.Client
Outcome Research AO’s authored environmental-sound behavior and implement faithful environmental audio in PRK.Client using idiomatic C# and the existing shared audio runtime. This is the placed/district/timed ambience follow-up deferred by tsk_n87n48dj3s and tsk_vjf59g4jc2; it complements gameplay music from tsk_jsv48x84cf without copying original client internals or creating a parallel audio stack. Repository evidence and intended scope - District metadata carries a dedicated slot-zero sound ID separately from day/weather music; RdbArea also preserves five currently unnamed sound settings and cell-to-area mapping. - RdbPlayfieldStatels and PRK.Client’s Playfield/PlayfieldChunk framing identify global and per-chunk 18-byte sound-emitter records, but the client currently skips them. Indoor transforms/room visibility and outdoor chunk bounds already exist and should be reused. - AudioCatalog/ClientAudio already provide validated SBF graph resolution, asset decoding/caching, OpenAL ownership, positional voices, authored gain/distance/loop/duration/fades, preferences, bounded queues and generation-safe teardown. TimedChildren currently fail explicitly and are the likely authored ambience scheduler input. - Reuse AudioAssetIndex, decoder/backend, effects volume, listener publication, world lifecycle and existing playfield loading. Keep music’s streaming/director path separate while sharing device/context and lifecycle. Constraints - First establish the semantics of district/area settings, 18-byte emitter fields, SBF timed children/intervals and activation/visibility rules using original binaries plus installed-data census. Record binary hashes/addresses and distinguish evidence from unresolved behavior. - Model the verified behavior with typed C# data and explicit state/scheduling rather than translating native layouts/control flow into a line-by-line port. - No game assets committed. Parsing and scheduling must be bounded and reject malformed, cyclic, unresolved, unsafe or excessive data without crashing or blocking frame/audio-owner threads. - Environmental audio uses existing master/effects/global mute behavior unless research proves another shipped preference route. World/session reset must cancel stale emitters and pending decode work; missing assets/devices degrade safely. Acceptance criteria - An evidence-backed behavior map and installed corpus census establish emitter field meanings, district/area selection, timed/random/sequential/all-child scheduling, intervals, spatialization, room/chunk activation, retrigger/stop/fade and teardown semantics; unsupported cases are explicit. - Playfield loading exposes validated environmental-sound definitions for outdoor/global and indoor/room sources with correct transforms and no duplicate parser/runtime ownership. - A bounded environmental-audio director activates, updates and retires district and placed ambience from authoritative player/room/world state, using existing ClientAudio/OpenAL services and authored SBF parameters without restarting unchanged loops or leaking voices. - Timed ambience graphs are supported according to verified semantics; malformed graphs and unavailable assets are isolated and reported without disabling unrelated audio. - Deterministic synthetic tests cover parsing, scheduling, visibility/distance transitions, loop/timed behavior, stale generation cancellation and lifecycle. Installed-data census, representative in-client audible comparison with AO, focused regressions, client build and available NativeAOT/native checks pass; unavailable platform/device gates are stated explicitly. - Frame publication remains nonblocking and warmed update paths are bounded; quantify voice/memory/allocation/performance impact rather than asserting no impact without measurement. Research and implementation milestone - Original binaries examined together: Gamecode.dll SHA256 654969a6b65946cb161f0e60aed8589260fc5eca1795488f66bb56f8fff73726 and SandyInterface.dll SHA256 8827f94909b31d1173edc0cc331e2b65b60b0b3138ab8a8976f17695311648ce. Sandy PlayEnvSound 0x100076da routes authored IDs/positions/gain/material/radius into PlaySample 0x10002d98; FrameProcessSound 0x10003b70 owns interval countdown/retrigger and fades. Gamecode wrappers are 0x100112a6/0x1001130d. The environment sphere processor at 0x100ad148/0x100ad1f8 uses inner/outer distance attenuation and starts/stops its sound as the listener crosses the sphere. - ParseSourceFile 0x10003520 plus sound construction 0x100011b0 disproved the existing composite-bit labels: bit 2 is all-children, bit 3 sequential and bit 6 random. Bit 7 selects an alternate timed-child mode absent from the shipped bank. Normal timed ambience instead uses each child’s min/max interval. The shared SoundBank model is corrected accordingly. - Installed census: game SBF v11 has 6,810 records and 1,606 records with nonzero authored intervals. All 1,362 placed emitters across 600 statel records resolve exactly to 55 game-bank IDs; no missing IDs or parse failures. Placed records are world position + uint sound ID + ushort radius override. The radius override preserves the bank inner/outer ratio, matching PlaySample. All 9,990 RdbArea sound-setting values in this installation are 0xffffffff, so that path is retained as currently unused rather than guessed into playback. - Implemented typed global/indoor-room emitter parsing with transforms, bounded persistent environmental voices, authored radius override, 100 ms proximity/room updates with hysteresis, generation-safe stop/reset, a 64-emitter cap, timed one-shot accents and malformed-graph isolation. It reuses ClientAudio’s queues, decoding/cache, OpenAL owner, effects volume and lifecycle; no parallel backend or asset resolver. - Verified: focused environmental/audio tests 25 passed with two conditional native/install checks skipped; full non-install client regression 2,732 passed and 26 fixture/native-conditional tests skipped; installed emitter/catalog census passed against the supplied RDB and AO installation. Warmed director updates allocate zero bytes on the frame thread in the regression probe. Existing NU1903 SQLite warning remains unrelated. - Linux NativeAOT publish passes. Host OpenAL null-driver --audio-check passes all four installed codec families, 128 effect sources plus reserved music, source reuse/rebinding, stream reset/underrun recovery, installed GUI playback and world reset. This validates packaging/API lifecycle, not audible environmental playback. - User’s ICC run exposed missing district ambience despite correctly silent district music. Follow-up trace found Gamecode background definitions at 0x100bd930 and name-table construction at 0x100ba8d7: four nonpositional sounds named `SM_Sandy_Env_Background{Dawn|Day|Dusk|Night}_{districtSoundId}`. ICC district sound ID 6 resolves exactly to the installed plains dawn/day/dusk/night assets (including the reported wind/bird ambience). Implemented district lookup from slot zero and stable day-period background playback through the same persistent runtime, with explicit `[audio.environment]` start/unavailable diagnostics. Synthetic transition/no-restart tests and installed ICC four-period resolution tests pass. - User’s first district-background run repeatedly logged the unchanged Day_6 start while stationary. Root cause: UpdateDistrict tied unchanged-request suppression to the asynchronous persistent handle still being reported active; any early retirement made the frame loop publish and log the same request continuously. Fixed the ownership boundary: district/period identity is authoritative and unchanged requests never restart, matching the original client’s stable environment selection. Regression explicitly retires the underlying logical handle and verifies no retry spin; changing period still starts the successor. - Second user run produced the decisive refusal: `Sound 72db42a2 refused: Unsupported SBF composite policy`. Installed Day_6 is a valid environment graph with a persistent `plains_bg_day.wav` base path plus five interval-driven bird/drum children and deliberately no immediate composite policy. District playback incorrectly used ordinary one-shot selection. Fixed it to use environment-base selection and schedule district child accents as nonpositional one-shots (15–72 second authored ranges for ICC Day_6). Synthetic base-loop/accent tests and installed dawn/day/dusk/night base+timed-graph checks pass. - User correctly noted the first audible correction was too basic. Original Gamecode background construction at 0x100bd930 creates four simultaneous district layers; processing at 0x100ba779 evaluates trapezoidal gains and overlaps adjacent periods over 300-second transitions. Replaced hard period switching with four independently owned Dawn/Day/Dusk/Night loops, per-handle gains and cyclic night handling. Timed accents remain attached to each active layer, so crossfades stack both beds and their authored accents. Boundary tests verify 50/50 Dawn↔Day, Dusk↔Night and Night↔Dawn mixes with unity total gain; full non-install regression passes 2,735 tests with 26 conditional skips. - The original additionally layers `SM_Sandy_Env_Wind`, sand/fallout wind and weather loops through the environment/weather simulation (not district metadata). PRK.Client does not yet expose equivalent live weather/wind state; do not fake constant weather gains. Remaining: user confirmation of the period stack, research/implementation of authoritative weather inputs, broader allocation/voice-pressure measurement, and confirmation of room-boundary behavior versus visible adjacent rooms. Pull request - #2600 — feature: Add environmental audio to PRK.Client - https://git.project-rk.com/prk/engines/pulls/2600 - `feature/client-environmental-audio` -> `develop`
Checklist
3 of 5 complete- Verify environmental-sound semantics in original binaries and installed data: district/area fields, emitter records, SBF timed graphs, activation, spatialization and teardown; document unknowns.
- Expose validated typed global/chunk/room environmental-sound definitions through existing playfield parsing and transforms, with corpus and malformed-data tests.
- Extend shared audio graph/runtime support for bounded authored timed ambience without duplicating decoding, asset indexing, backend ownership or volume/lifecycle logic.
- Integrate a C# environmental-audio director with authoritative player zone/room/world state, visibility and generation-safe reset; verify stable activation and retirement.
- Pass deterministic, installed-corpus, audible AO comparison, lifecycle/performance, regression, build and available native/AOT validation; record remaining platform/device gaps.
- Area
- Project Rubi-Ka
- Project
- engines
- Kind
- Feature
- Task ID
tsk_dtpk9a2xmd- Updated