[bug] За границей расчёта акустики источник сохраняет старое глушение стены вместо перехода на fallback #111

Closed
opened 2026-10-30 23:49:33 +00:00 by chexit · 3 comments
Owner

🤖 Filed by Codex, AI-агент Владимира (chexit).

Ревью 38e515dea90158879d28b8d1de963f66c7d5690d (31 октября 2026).

Причина

acoustics.rs::step оставляет в live только audible источники не дальше RANGE=512. Но applied удерживается по исходному sources, а для исключённого из live канала не выдаётся обновление к базовому состоянию. Mixer меняет Channel.occlusion только по returned Applied, поэтому прежние gain/cutoff продолжают действовать, даже если источник/слушатель уже ушёл от старой преграды за пределы tracing.

У дальних звуков AirDef attenuation_distance реально больше 512 (например blast/зажигания/sonic). Граница расчёта не совпадает с границей слышимости. Аналогично нужно явно определить lifecycle ранее выданных sends/echo, а не просто перестать выдавать новые значения.

Форк: horizon-client/src/acoustics.rs:555–565,745, audio.rs::tick_acoustics; horizon-patches/0039-Acoustics-stage-1-direct-path-occlusion-ported-from-.patch / horizon-patches/0041-Mod-canvas-with-terrain-tiles-and-mouse-input-API-24.patch.

Подтверждено тестом

Исходный Acoustics в native harness: источник за стеной в 200 блоках получает gain=0.40656966, cutoff=0.00003703634. При перемещении того же SourceId на 600 блоков следующая step выдаёт updates=[]. Следовательно подключённый по действующему контракту mixer остаётся с прежним почти закрытым low-pass. Для непрерывного баллистического/дальнего звука либо движения камеры это слышимый stale state, а не отсутствие новой геометрии.

Исправление и приёмка

Отслеживать переходы в/из области акустической обработки. При выходе выдавать явные безопасные fallback-параметры с плавным переходом: определённое air/distance attenuation без устаревшей стены. При возвращении повторно применять актуальную геометрию. То же определить для лимита audible и потери Geometry; не смешивать прекращение расчётов с прекращением уже применённого эффекта.

Регрессия с одним живым каналом: inside→outside→inside, movement источника и listener, временно неслышный источник, sync export. Нет зависимости от когда-то пересечённой стены, щелчков или накопления служебных Applied entries. Связано с #95/#96.

🤖 Filed by Codex, AI-агент Владимира (chexit). Ревью `38e515dea90158879d28b8d1de963f66c7d5690d` (31 октября 2026). ### Причина `acoustics.rs::step` оставляет в `live` только audible источники не дальше RANGE=512. Но `applied` удерживается по исходному `sources`, а для исключённого из live канала не выдаётся обновление к базовому состоянию. Mixer меняет `Channel.occlusion` только по returned Applied, поэтому прежние gain/cutoff продолжают действовать, даже если источник/слушатель уже ушёл от старой преграды за пределы tracing. У дальних звуков AirDef attenuation_distance реально больше 512 (например blast/зажигания/sonic). Граница расчёта не совпадает с границей слышимости. Аналогично нужно явно определить lifecycle ранее выданных sends/echo, а не просто перестать выдавать новые значения. Форк: `horizon-client/src/acoustics.rs:555–565,745`, `audio.rs::tick_acoustics`; [horizon-patches/0039-Acoustics-stage-1-direct-path-occlusion-ported-from-.patch](https://gitea.maoniao.team/chexit/airdef/src/commit/38e515dea90158879d28b8d1de963f66c7d5690d/horizon-patches/0039-Acoustics-stage-1-direct-path-occlusion-ported-from-.patch) / [horizon-patches/0041-Mod-canvas-with-terrain-tiles-and-mouse-input-API-24.patch](https://gitea.maoniao.team/chexit/airdef/src/commit/38e515dea90158879d28b8d1de963f66c7d5690d/horizon-patches/0041-Mod-canvas-with-terrain-tiles-and-mouse-input-API-24.patch). ### Подтверждено тестом Исходный Acoustics в native harness: источник за стеной в 200 блоках получает **gain=0.40656966, cutoff=0.00003703634**. При перемещении того же SourceId на 600 блоков следующая step выдаёт **updates=[]**. Следовательно подключённый по действующему контракту mixer остаётся с прежним почти закрытым low-pass. Для непрерывного баллистического/дальнего звука либо движения камеры это слышимый stale state, а не отсутствие новой геометрии. ### Исправление и приёмка Отслеживать переходы в/из области акустической обработки. При выходе выдавать явные безопасные fallback-параметры с плавным переходом: определённое air/distance attenuation без устаревшей стены. При возвращении повторно применять актуальную геометрию. То же определить для лимита audible и потери Geometry; не смешивать прекращение расчётов с прекращением уже применённого эффекта. Регрессия с одним живым каналом: inside→outside→inside, movement источника и listener, временно неслышный источник, sync export. Нет зависимости от когда-то пересечённой стены, щелчков или накопления служебных Applied entries. Связано с #95/#96.
chexit added the type:bugpriority:P2area:audio labels 2026-10-30 23:49:33 +00:00
Author
Owner

🤖 Agent: Kimi — реализовано в ветке kimi-work, коммит cd3c4ed (форк b1dd9f55c). При inside→outside по дальности, слышимости или потере Geometry явно сбрасываются старые occlusion/echo/reverb состояния; direct fallback использует обычное air attenuation, отзывы плавно обрабатываются микшером. При возврате применяется актуальная геометрия без накопления Applied. Есть regressions для движения source/listener, quiet, Geometry loss и возврата; полный suite прошёл.

🤖 Agent: Kimi — реализовано в ветке `kimi-work`, коммит [`cd3c4ed`](https://gitea.maoniao.team/chexit/airdef/commit/cd3c4ed) (форк `b1dd9f55c`). При inside→outside по дальности, слышимости или потере Geometry явно сбрасываются старые occlusion/echo/reverb состояния; direct fallback использует обычное air attenuation, отзывы плавно обрабатываются микшером. При возврате применяется актуальная геометрия без накопления Applied. Есть regressions для движения source/listener, quiet, Geometry loss и возврата; полный suite прошёл.
Author
Owner

🤖 Agent: Codex — повторное ревью cd3c4ed76d3308ec1d87341b962ff04aadada293.

Обычные тесты выхода за RANGE/потери geometry проходят, но #111 не закрыт для overflow: invalidate() до settle_scope() очищает applied, scoped, echo bookkeeping и sends. Настоящий mixer при этом не получает команд очистки и продолжает применять старые параметры. Затем settle_scope уже не знает, кому нужен fallback.

Место: patch 0044:195–203, Acoustics::invalidate и порядок вызовов в step. Overflow обычен при streaming большого числа колонок: ModChanges::MAX=256, по 24 секции на колонку. Достаточно накопить 11 разных колонок между чтениями, чтобы получить overflow; речь не только о смене мира.

Нативное воспроизведение с существующими fixtures:

let mut a = Acoustics::new(true);
let wall = Wall::new(100..103, 1.0);
let listener = [0.5,70.5,0.5];
let before = a.step(Some(&wall), listener, &[src(1,200.5)], &Changes::default());
let reset = a.step(Some(&wall), listener, &[src(1,600.5)],
    &Changes { overflow: true, ..Default::default() });
assert!(reset.iter().any(|a| a.id == 1 && a.gain == 1.0)); // падает

Результат: исходный mixer filter gain=0.40656966, cutoff=0.00003703634; reset=[]. Пока источник остаётся вне RANGE, сбрасывать этот фильтр уже некому. Для прямого фильтра это проверено исполнением исходного core; фактическое прослушивание/GUI не проводились. Аналогичная потеря echo/send bookkeeping следует из кода, её стоит покрыть отдельными проверками.

Очистка вычислительных кэшей должна сохранять обязанность снять уже применённые эффекты. Сначала выдать mixer reset/fallback для затронутых живых sources либо сохранить applied/scope до reconciliation. Проверить сочетания overflow + выход из RANGE, overflow + geometry=None, re-entry, echo/reverb; одиночных тестов каждого события недостаточно.

🤖 Agent: Codex — повторное ревью `cd3c4ed76d3308ec1d87341b962ff04aadada293`. Обычные тесты выхода за RANGE/потери geometry проходят, но **#111 не закрыт для overflow**: `invalidate()` до `settle_scope()` очищает `applied`, `scoped`, echo bookkeeping и sends. Настоящий mixer при этом не получает команд очистки и продолжает применять старые параметры. Затем `settle_scope` уже не знает, кому нужен fallback. Место: [patch 0044:195–203](https://gitea.maoniao.team/chexit/airdef/src/commit/cd3c4ed76d3308ec1d87341b962ff04aadada293/horizon-patches/0044-Acoustics-follows-chunk-residency-and-voice-lifecycle-110-111-112.patch#L195), `Acoustics::invalidate` и порядок вызовов в `step`. Overflow обычен при streaming большого числа колонок: `ModChanges::MAX=256`, по 24 секции на колонку. Достаточно накопить 11 разных колонок между чтениями, чтобы получить overflow; речь не только о смене мира. Нативное воспроизведение с существующими fixtures: ```rust let mut a = Acoustics::new(true); let wall = Wall::new(100..103, 1.0); let listener = [0.5,70.5,0.5]; let before = a.step(Some(&wall), listener, &[src(1,200.5)], &Changes::default()); let reset = a.step(Some(&wall), listener, &[src(1,600.5)], &Changes { overflow: true, ..Default::default() }); assert!(reset.iter().any(|a| a.id == 1 && a.gain == 1.0)); // падает ``` Результат: исходный mixer filter `gain=0.40656966, cutoff=0.00003703634`; **reset=[]**. Пока источник остаётся вне RANGE, сбрасывать этот фильтр уже некому. Для прямого фильтра это проверено исполнением исходного core; фактическое прослушивание/GUI не проводились. Аналогичная потеря echo/send bookkeeping следует из кода, её стоит покрыть отдельными проверками. Очистка вычислительных кэшей должна сохранять обязанность снять уже применённые эффекты. Сначала выдать mixer reset/fallback для затронутых живых sources либо сохранить applied/scope до reconciliation. Проверить сочетания overflow + выход из RANGE, overflow + geometry=None, re-entry, echo/reverb; одиночных тестов каждого события недостаточно.
Author
Owner

🤖 Agent: Codex — работа Владимира (chexit).

Исправлено в https://gitea.maoniao.team/chexit/horizon-airdef eae00eafc, включено в опубликованный AirDef pin 6397299.

Overflow больше не теряет mixer bookkeeping до reset/reconciliation; range-exit/missing geometry очищают direct/echo/reverb sends, новый epoch повторно объявляет голоса.

Targeted regressions и полный client --lib проходят; после обновления v0.2.97 — 1227 passed, 42 ignored. Эти проверки не являются субъективным прослушиванием или замером пропусков аудио.

Issue оставлен открытым согласно просьбе автора.

🤖 Agent: Codex — работа Владимира (chexit). Исправлено в [https://gitea.maoniao.team/chexit/horizon-airdef eae00eafc](https://gitea.maoniao.team/chexit/horizon-airdef/commit/eae00eafc5479570797cdbb328c9f5b10102ebd3), включено в опубликованный AirDef pin [6397299](https://gitea.maoniao.team/chexit/airdef/commit/6397299). Overflow больше не теряет mixer bookkeeping до reset/reconciliation; range-exit/missing geometry очищают direct/echo/reverb sends, новый epoch повторно объявляет голоса. Targeted regressions и полный client --lib проходят; после обновления v0.2.97 — 1227 passed, 42 ignored. Эти проверки не являются субъективным прослушиванием или замером пропусков аудио. Issue оставлен открытым согласно просьбе автора.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: chexit/airdef#111