From a969526d870191ec584ea66f5f5345b5acdcd5df Mon Sep 17 00:00:00 2001 From: Yamagi Date: Sun, 8 Sep 2024 09:57:38 +0200 Subject: [PATCH] Switch the SDL2 sound backend to transparent audio format conversion. Since the SDL 1.2 day the SDL sound backend relied on the sound driver supporting the requested audio format. That workes fine for drivers support transparent conversions into formats supported by the hardware. But it failes with drivers which are unable to do such conversions. As long as we hardcoded the sound driver this wasn't a problem, because all our chouces supported transparent conversions. When we removed the hardcoded choices and started to rely on SDLs choices especially the wsaapi driver - which is SDLs default choice under windows - failed. wsaapi only guarantees support for AUDIO_F32LSB (other formats may be supported, depending on the hardware), Quake II needs AUDIO_S16SYS or AUDIO_U8. Solve this by switching to transparent conversions through SDL. This way Quake II can send whatever it wants to SDL and SDL will make sure that it is in the right format before sending it to the driver. This isn't necessary for SDL3, SDL3 doesn't support explicit formats and always relies on transparent conversions. Remove hardcoded wsaapi on Windows, it's no longer necessary. Part of #1135. --- doc/040_cvarlist.md | 7 +++--- src/client/sound/sdl.c | 54 ++++++++++++++++-------------------------- 2 files changed, 24 insertions(+), 37 deletions(-) diff --git a/doc/040_cvarlist.md b/doc/040_cvarlist.md index 1eebcdc1..4200fd76 100644 --- a/doc/040_cvarlist.md +++ b/doc/040_cvarlist.md @@ -301,10 +301,9 @@ it's `+set busywait 0` (setting the `busywait` cvar) and `-portable` modern systems like Windows 10 or Linux with PulseAudio. * **s_sdldriver**: Can be set to the name of a SDL audio driver. If set - to `auto`, SDL chooses the driver. If set to anything else the given - driver is forced, regardless if supported by SDL or the platform or - not. By default set to `directsound` under Windows and `auto` on all - other platforms. + to `auto` (the defailt), SDL chooses the driver. If set to anything + else the given driver is forced, regardless if supported by SDL or the + platform or not. * **s_underwater**: Dampen sounds if submerged. Enabled by default. diff --git a/src/client/sound/sdl.c b/src/client/sound/sdl.c index 8e3ae6a0..626bc658 100644 --- a/src/client/sound/sdl.c +++ b/src/client/sound/sdl.c @@ -1350,12 +1350,7 @@ SDL_BackendInit(void) int sndbits = (Cvar_Get("sndbits", "16", CVAR_ARCHIVE))->value; int sndfreq = (Cvar_Get("s_khz", "44", CVAR_ARCHIVE))->value; int sndchans = (Cvar_Get("sndchannels", "2", CVAR_ARCHIVE))->value; - -#if _WIN32 - cvar_t *s_sdldriver = (Cvar_Get("s_sdldriver", "directsound", CVAR_ARCHIVE)); -#else cvar_t *s_sdldriver = (Cvar_Get("s_sdldriver", "auto", CVAR_ARCHIVE)); -#endif if (strcmp(s_sdldriver->string, "auto") != 0) { @@ -1502,8 +1497,7 @@ qboolean SDL_BackendInit(void) { char reqdriver[128]; - SDL_AudioSpec desired; - SDL_AudioSpec obtained; + SDL_AudioSpec spec; int tmp, val; /* This should never happen, @@ -1516,12 +1510,7 @@ SDL_BackendInit(void) int sndbits = (Cvar_Get("sndbits", "16", CVAR_ARCHIVE))->value; int sndfreq = (Cvar_Get("s_khz", "44", CVAR_ARCHIVE))->value; int sndchans = (Cvar_Get("sndchannels", "2", CVAR_ARCHIVE))->value; - -#if _WIN32 - cvar_t *s_sdldriver = (Cvar_Get("s_sdldriver", "directsound", CVAR_ARCHIVE)); -#else cvar_t *s_sdldriver = (Cvar_Get("s_sdldriver", "auto", CVAR_ARCHIVE)); -#endif if (strcmp(s_sdldriver->string, "auto") != 0) { @@ -1547,8 +1536,7 @@ SDL_BackendInit(void) Com_Printf("SDL audio driver is \"%s\".\n", drivername); - memset(&desired, '\0', sizeof(desired)); - memset(&obtained, '\0', sizeof(obtained)); + memset(&spec, '\0', sizeof(spec)); /* Users are stupid */ if ((sndbits != 16) && (sndbits != 8)) @@ -1558,45 +1546,45 @@ SDL_BackendInit(void) if (sndfreq == 48) { - desired.freq = 48000; + spec.freq = 48000; } else if (sndfreq == 44) { - desired.freq = 44100; + spec.freq = 44100; } else if (sndfreq == 22) { - desired.freq = 22050; + spec.freq = 22050; } else if (sndfreq == 11) { - desired.freq = 11025; + spec.freq = 11025; } - desired.format = ((sndbits == 16) ? AUDIO_S16SYS : AUDIO_U8); + spec.format = ((sndbits == 16) ? AUDIO_S16SYS : AUDIO_U8); - if (desired.freq <= 11025) + if (spec.freq <= 11025) { - desired.samples = 256; + spec.samples = 256; } - else if (desired.freq <= 22050) + else if (spec.freq <= 22050) { - desired.samples = 512; + spec.samples = 512; } - else if (desired.freq <= 44100) + else if (spec.freq <= 44100) { - desired.samples = 1024; + spec.samples = 1024; } else { - desired.samples = 2048; + spec.samples = 2048; } - desired.channels = sndchans; - desired.callback = SDL_Callback; + spec.channels = sndchans; + spec.callback = SDL_Callback; /* Okay, let's try our luck */ - if (SDL_OpenAudio(&desired, &obtained) == -1) + if (SDL_OpenAudio(&spec, NULL) == -1) { Com_Printf("SDL_OpenAudio() failed: %s\n", SDL_GetError()); SDL_QuitSubSystem(SDL_INIT_AUDIO); @@ -1607,10 +1595,10 @@ SDL_BackendInit(void) backend = &sound; playpos = 0; - backend->samplebits = obtained.format & 0xFF; - backend->channels = obtained.channels; + backend->samplebits = spec.format & 0xFF; + backend->channels = spec.channels; - tmp = (obtained.samples * obtained.channels) * 10; + tmp = (spec.samples * spec.channels) * 10; if (tmp & (tmp - 1)) { /* make it a power of two */ @@ -1624,7 +1612,7 @@ SDL_BackendInit(void) backend->samples = tmp; backend->submission_chunk = 1; - backend->speed = obtained.freq; + backend->speed = spec.freq; samplesize = (backend->samples * (backend->samplebits / 8)); backend->buffer = calloc(1, samplesize); s_numchannels = MAX_CHANNELS;