MongoosePeople. Places. Questionable inventions.

Changelog

All public mailing lists

Spatial audio: acoustic origin, scene consistency, object-attached ambience

2026-07-17 04:39 UTC · claude (#13505)

Added $gpo:sound_origin() -- canonical acoustic origin, the centre of an object's box. $player overrides it to head height (93% of stature). coordinates() is unchanged and remains the min-corner for collision/pathing/bounds.

Cause: coordinates() (the AABB min-corner) was sent raw as the panner position, so every sound played from its object's west/south/floor corner, and a player's min-corner has z=0, putting the listener's ears on the floor.

Four send sites now use sound_origin(): #10136:_entity_payload, #10136:_scene_payload, #10136:send_position_update (was recomputing its own min-corner and disagreeing with the scene snapshot), and $sound #3010::coordinates (fallback used location:coordinates()).

#10137::is_active: an emitter whose source_entity is valid but whose sound cannot be resolved is an orphan and now reports inactive. It previously fell through to this.active (set 1 at initialize, never cleared), so orphans reported playing forever. #8608 held 167 such ghosts in every Scene snapshot; now 1 active. Nothing deleted. The this.active fallback still applies to direct-media emitters, which have no source_entity.

#10137::serialize_start: entity-bound emitters no longer let world_position override the source's real position. world_position defaults to {0,0,0} and a 3-element list is truthy, so it fired for every emitter that never called move_world, pinning the Scene packet to the room origin while the Media packet carried the truth. World/fixed emitters still use it.

Added $gpo:set_ambience(file, ?volume): idempotent object-attached ambience. Handle is owner-derived ("ambience"+tostr(this)), so ensure_emitter_for_sound reuses the emitter and the previous sound under the key is stopped first. Same key pattern as $sh:social_sound. Three calls produce one sound and one emitter.

Orientation was checked and is CORRECT -- no change. #6:orientation returns {sin(yaw), -cos(yaw), 0}; mongooseToWebAudioVector is a determinant +1 rotation mapping MOO south onto the Web Audio default forward.

react-client/docs/GMCP/packages/client-spatial.md rewrote: it documented Web-Audio-frame vectors as the wire format. Wire is MOO frame (+x east, +y north, +z up).

New tests: #2200 test_sound_origin, test_set_ambience; #6 test_sound_origin_head; #10136 test_entity_payload_uses_sound_origin, test_scene_payload_listener_at_ear_height; #3010 test_serialize_3d_uses_source_acoustic_origin; #10137 test_orphan_emitter_is_inactive, test_serialize_position_is_not_clobbered_by_unset_world_position.

Not fixed, flagged: #3010 test_threeD_is_boolean_flag fails pre-existing (class default :threeD is 1, test asserts falsy). #2700 13/18, 5 atmosphere failures unrelated (after_coalesce is called in #13873 and defined nowhere).

Back to Changelog