audio: WASAPI Force Shared Mode option (#745)

## Link to GitHub Issue or related Pull Request, if one exists
n/a

## Description of change
This new option, `-wasapishared`, detects when the game opens WASAPI
Exclusive stream and forcibly opens a shared mode stream instead on the
real device.

#### Benefits of this:

1. No need for `force wasapi shared` patches
2. No need to change sample rate of audio devices before starting up
games
3. Adds ability to boot in shared mode even for games that do not have
shared wasapi changes (old GITADORA, popn HC)

As a result, this option is strictly better than `shared wasapi` patches
available for many games.

#### Downsides:
1. OS resampling will add a small latency, but not big enough to be
noticeable.
2. Using shared mode instead of exclusive mode adds latency, of course.

(If you cared about latency, you would use the low latency option, or
use exclusive or asio)

Basically it's the "make things work" button for audio that should work
for almost all games that we support.

The option has no effect if the game opens in shared mode.

## Testing
SDVX7 - ok
GITADORA GW - ok
popn HC - ok
IIDX - ok
This commit is contained in:
bicarus
2026-06-10 00:20:59 -07:00
committed by GitHub
parent ccb3bac48c
commit 6bcadccf09
11 changed files with 234 additions and 65 deletions
@@ -0,0 +1,31 @@
#pragma once
#include <cstdint>
#include <windows.h>
#include <audioclient.h>
namespace hooks::audio {
// The -wasapishared option redirects an exclusive WASAPI stream to shared mode. lets other apps
// play sound and works on devices that can't open the exclusive format, at the cost of some
// latency. Only PCM / float is converted; bitstream (AC-3 / DTS) is left alone.
struct SharedRedirect {
// true once apply() has redirected an exclusive request. gates the buffer clamp; stays false
// for a natively-shared stream (it paces itself, so must not be clamped).
bool redirected_from_exclusive = false;
// whether an exclusive-mode request should be redirected, given the -wasapishared option.
// only PCM / float is eligible; bitstream (AC-3 / DTS) is left in exclusive mode.
static bool wants(AUDCLNT_SHAREMODE share_mode, const WAVEFORMATEX *format);
// redirect an exclusive request to shared mode. caller must have checked wants() first.
void apply(AUDCLNT_SHAREMODE *share_mode, DWORD *stream_flags, REFERENCE_TIME *periodicity);
// clamp a reported buffer size to one device period. some games write the whole buffer per
// event, which overflows shared-mode buffering (AUDCLNT_E_BUFFER_TOO_LARGE -> stutter); one
// period always fits. a no-op unless an exclusive request was redirected.
UINT32 clamp_buffer_size(IAudioClient *real, uint32_t sample_rate, UINT32 device_frames) const;
};
}