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
+51 -39
View File
@@ -28,6 +28,7 @@ static const std::vector<std::string> CATEGORY_ORDER_BASIC = {
"Graphics (Full Screen)",
"Graphics (Windowed)",
"Audio",
"Audio (Conversion)",
};
static const std::vector<std::string> CATEGORY_ORDER_ADVANCED = {
@@ -1933,6 +1934,30 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
.type = OptionType::Bool,
.category = "Audio (Hacks)",
},
{
// AudioShared
.title = "WASAPI Force Shared Mode",
.name = "wasapishared",
.desc = "This option converts all WASAPI exclusive mode requests to shared mode.\n\n"
"Many games have patches that turn on shared mode, but this option is better! "
"This will automatically perform sample rate conversion - "
"you do not need to manually set the sample rate of your audio device before launching the game.",
.type = OptionType::Bool,
.category = "Audio",
},
{
// spice2x_LowLatencySharedAudio
.title = "Low Latency Shared Audio",
.name = "sp2x-lowlatencysharedaudio",
.display_name = "lowlatencysharedaudio",
.aliases= "lowlatencysharedaudio",
.desc = "Force the usage of smallest buffer size supported by the device when shared mode audio is used. "
"Works for games using DirectSound or shared WASAPI; no effect for exclusive WASAPI and ASIO. "
"For best results (under 10ms), use the default Windows inbox audio driver instead of manufacturer supplied driver. "
"Requires Windows 10 and above.",
.type = OptionType::Bool,
.category = "Audio",
},
{
// AudioBackend
.title = "Spice Audio Hook Backend (DEPRECATED - use -asioconvert instead)",
@@ -1941,7 +1966,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
"Does nothing for games that do not output to exclusive WASAPI.",
.type = OptionType::Enum,
.hidden = true,
.category = "Audio",
.category = "Audio (Conversion)",
.elements = {
{"asio", "ASIO"},
{"waveout", "broken, do not use"}
@@ -1954,7 +1979,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
.desc = "Selects the ASIO driver id to use when Spice Audio Backend is set to ASIO.",
.type = OptionType::Integer,
.hidden = true,
.category = "Audio",
.category = "Audio (Conversion)",
},
{
// AsioDriverName
@@ -1965,7 +1990,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
"This should only be used as last resort if your audio device does not support WASAPI Exclusive.\n\n"
"Does nothing for games that do not output to exclusive WASAPI.",
.type = OptionType::Text,
.category = "Audio",
.category = "Audio (Conversion)",
.picker = OptionPickerType::AsioDriver,
},
{
@@ -1990,7 +2015,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
"rear: rear channels only.\n\n"
"side: side channels only.",
.type = OptionType::Enum,
.category = "Audio",
.category = "Audio (Conversion)",
.elements = {
{"ac4", "AC-4 downmix"},
{"normalize", "All channels"},
@@ -1999,26 +2024,6 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
{"side", "Side channels only"},
},
},
{
// AsioDownmixToStereo
.title = "ASIO 7.1 to Stereo Downmix",
.name = "asiodownmix",
.desc = "Extracts a single stereo channel pair from a multi-channel ASIO output, "
"mapping the selected pair to the device's first two channels.\n\n"
"Channel pairs assume a standard 7.1 ASIO layout (0-indexed):\n\n"
"front: channels 0/1 (front left/right).\n\n"
"center: channel 2 (front center, duplicated to both outputs).\n\n"
"rear: channels 4/5 (rear left/right).\n\n"
"side: channels 6/7 (side left/right).",
.type = OptionType::Enum,
.category = "Audio",
.elements = {
{"front", "Front channels (0/1)"},
{"center", "Center channel (2)"},
{"rear", "Rear channels (4/5)"},
{"side", "Side channels (6/7)"},
},
},
{
// VolumeBoost
.title = "WASAPI/ASIO Boost Audio Volume",
@@ -2050,7 +2055,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
"Select the TARGET sample rate (one that your audio card supports).\n\n"
"Will result in couple milliseconds of latency and increased CPU usage when active.",
.type = OptionType::Enum,
.category = "Audio",
.category = "Audio (Conversion)",
.elements = {
{"44100", "44.1 kHz"},
{"48000", "48 kHz"},
@@ -2069,7 +2074,27 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
"(at the cost of slightly increased latency).",
.type = OptionType::Integer,
.setting_name = "16",
.category = "Audio",
.category = "Audio (Conversion)",
},
{
// AsioDownmixToStereo
.title = "ASIO 7.1 to Stereo Downmix",
.name = "asiodownmix",
.desc = "Extracts a single stereo channel pair from a multi-channel ASIO output, "
"mapping the selected pair to the device's first two channels.\n\n"
"Channel pairs assume a standard 7.1 ASIO layout (0-indexed):\n\n"
"front: channels 0/1 (front left/right).\n\n"
"center: channel 2 (front center, duplicated to both outputs).\n\n"
"rear: channels 4/5 (rear left/right).\n\n"
"side: channels 6/7 (side left/right).",
.type = OptionType::Enum,
.category = "Audio (Conversion)",
.elements = {
{"front", "Front (ch 0/1)"},
{"center", "Center (ch 2)"},
{"rear", "Rear (ch 4/5)"},
{"side", "Side (ch 6/7)"},
},
},
{
// DelayBy5Seconds
@@ -2740,19 +2765,6 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
{"both", ""},
},
},
{
// spice2x_LowLatencySharedAudio
.title = "Low Latency Shared Audio",
.name = "sp2x-lowlatencysharedaudio",
.display_name = "lowlatencysharedaudio",
.aliases= "lowlatencysharedaudio",
.desc = "Force the usage of smallest buffer size supported by the device when shared mode audio is used. "
"Works for games using DirectSound or shared WASAPI; no effect for exclusive WASAPI and ASIO. "
"For best results (under 10ms), use the default Windows inbox audio driver instead of manufacturer supplied driver. "
"Requires Windows 10 and above.",
.type = OptionType::Bool,
.category = "Audio",
},
{
// spice2x_TapeLedAlgorithm
.title = "Tape LED Avg Algorithm",