Skip to content

Fix XAudio2 2.7→2.9 effect chain compatibility and GetState flags (tryname) - #1

Open
passed111 wants to merge 2 commits into
masterfrom
passed111-patch-1
Open

Fix XAudio2 2.7→2.9 effect chain compatibility and GetState flags (tryname)#1
passed111 wants to merge 2 commits into
masterfrom
passed111-patch-1

Conversation

@passed111

Copy link
Copy Markdown
Owner

Fix: XAudio2 2.7→2.9 effect chain compatibility and GetState flags

This PR fixes three audio bugs in the Audio Proxy module when redirecting the game's XAudio2 2.7 engine to the system 2.9 engine:

1. GetState flags not cleared (crash/visual bug) The game (built against 2.7) calls IXAudio2SourceVoice::GetState with the 2.7 single-argument signature. The 2.9 engine added a Flags argument that the 2.7 caller never initialises, so the 2.9 engine reads a garbage Flags value. When bit 1 (XAUDIO2_VOICE_NOSAMPLESPLAYED) is set, SamplesPlayed is zeroed out, causing:

  • Lip-sync twitches on OG (1.10.163)
  • Audio state-machine collapse on AE (no voice / music reset / sirens)

Fix: pass Flags=0 explicitly when forwarding to the 2.9 engine.

2. Effect chain dropped (dry radio / power-armor audio) The AD_USE_AUDIOFX_XAPO=0 branch replaced pEffectChain with nullptr in all Create*Voice / SetEffectChain calls, silently stripping every effect (radio EQ, power-armor processing, etc.).

Fix: forward pEffectChain verbatim.

3. 2.7 APO rejected by 2.9 engine (E_NOINTERFACE) The game's built-in APO classes (BSStateVariableFilter, BSOverdrive, BSDelayEffect, BSCXAPOWrapper, MonitorAPO) are compiled against the 2.7 DXSDK and only recognise IID_IXAPO27. The 2.9 engine queries for IID_IXAPO_29 and rejects them, so even with the effect chain forwarded the effects are never attached.

Fix: EnsureEffectChainCompat patches each 2.7 APO vtable's QueryInterface slot on first use to also accept IID_IXAPO_29.


Credit: the GetState and QI compatibility approach is adapted from the AudioDeviceFollowFix plugin by tryname (Nexus Mods).

## Fix: XAudio2 2.7→2.9 effect chain compatibility and GetState flags

This PR fixes three audio bugs in the Audio Proxy module when redirecting
the game's XAudio2 2.7 engine to the system 2.9 engine:

### 1. GetState flags not cleared (crash/visual bug)
The game (built against 2.7) calls `IXAudio2SourceVoice::GetState` with
the 2.7 single-argument signature. The 2.9 engine added a `Flags`
argument that the 2.7 caller never initialises, so the 2.9 engine reads
a garbage `Flags` value. When bit 1 (`XAUDIO2_VOICE_NOSAMPLESPLAYED`) is
set, `SamplesPlayed` is zeroed out, causing:
- Lip-sync twitches on OG (1.10.163)
- Audio state-machine collapse on AE (no voice / music reset / sirens)

Fix: pass `Flags=0` explicitly when forwarding to the 2.9 engine.

### 2. Effect chain dropped (dry radio / power-armor audio)
The `AD_USE_AUDIOFX_XAPO=0` branch replaced `pEffectChain` with `nullptr`
in all `Create*Voice` / `SetEffectChain` calls, silently stripping every
effect (radio EQ, power-armor processing, etc.).

Fix: forward `pEffectChain` verbatim.

### 3. 2.7 APO rejected by 2.9 engine (E_NOINTERFACE)
The game's built-in APO classes (BSStateVariableFilter, BSOverdrive,
BSDelayEffect, BSCXAPOWrapper, MonitorAPO) are compiled against the 2.7
DXSDK and only recognise `IID_IXAPO27`. The 2.9 engine queries for
`IID_IXAPO_29` and rejects them, so even with the effect chain forwarded
the effects are never attached.

Fix: `EnsureEffectChainCompat` patches each 2.7 APO vtable's
`QueryInterface` slot on first use to also accept `IID_IXAPO_29`.

---

Credit: the GetState and QI compatibility approach is adapted from the
**AudioDeviceFollowFix** plugin by **tryname** (Nexus Mods).
@passed111 passed111 closed this Jul 22, 2026
… tryname)

## Fix: XAudio2 2.7→2.9 effect chain compatibility and GetState flags

This PR fixes three audio bugs in the Audio Proxy module when redirecting
the game's XAudio2 2.7 engine to the system 2.9 engine:

### 1. GetState flags not cleared (crash/visual bug)
The game (built against 2.7) calls `IXAudio2SourceVoice::GetState` with
the 2.7 single-argument signature. The 2.9 engine added a `Flags`
argument that the 2.7 caller never initialises, so the 2.9 engine reads
a garbage `Flags` value. When bit 1 (`XAUDIO2_VOICE_NOSAMPLESPLAYED`) is
set, `SamplesPlayed` is zeroed out, causing:
- Lip-sync twitches on OG (1.10.163)
- Audio state-machine collapse on AE (no voice / music reset / sirens)

Fix: pass `Flags=0` explicitly when forwarding to the 2.9 engine.

### 2. Effect chain dropped (dry radio / power-armor audio)
The `AD_USE_AUDIOFX_XAPO=0` branch replaced `pEffectChain` with `nullptr`
in all `Create*Voice` / `SetEffectChain` calls, silently stripping every
effect (radio EQ, power-armor processing, etc.).

Fix: forward `pEffectChain` verbatim.

### 3. 2.7 APO rejected by 2.9 engine (E_NOINTERFACE)
The game's built-in APO classes (BSStateVariableFilter, BSOverdrive,
BSDelayEffect, BSCXAPOWrapper, MonitorAPO) are compiled against the 2.7
DXSDK and only recognise `IID_IXAPO27`. The 2.9 engine queries for
`IID_IXAPO_29` and rejects them, so even with the effect chain forwarded
the effects are never attached.

Fix: `EnsureEffectChainCompat` patches each 2.7 APO vtable's
`QueryInterface` slot on first use to also accept `IID_IXAPO_29`.
@passed111 passed111 reopened this Jul 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant