From 5a62228b228e2a329d2ba7fef9dacd12de4d9033 Mon Sep 17 00:00:00 2001 From: molivier Date: Tue, 6 Jun 2006 06:21:47 +0000 Subject: [PATCH] Attempt to fix speaker layout for 5.1 and 7.1 sound, on Windows and Mac OS X; the sound engine now builds its speaker layout based on the OS and the snd_swapstereo cvar. Plus a minor fix for the OSS sound module (was incorrectly reporting "audio can't keep up") git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@6421 d7cf8633-e32d-0410-b094-e92efae38249 --- snd_alsa.c | 1 + snd_main.c | 86 ++++++++++++++++++---- snd_main.h | 2 + snd_mix.c | 208 +++++++++++++---------------------------------------- snd_oss.c | 17 ++++- snd_sdl.c | 6 ++ 6 files changed, 145 insertions(+), 175 deletions(-) diff --git a/snd_alsa.c b/snd_alsa.c index 2e6b8f37..c9065bd8 100644 --- a/snd_alsa.c +++ b/snd_alsa.c @@ -201,6 +201,7 @@ qboolean SndSys_Init (const snd_format_t* requested, snd_format_t* suggested) snd_renderbuffer = Snd_CreateRingBuffer(requested, 0, NULL); expected_delay = 0; alsasoundtime = 0; + alsaspeakerlayout = true; return true; diff --git a/snd_main.c b/snd_main.c index 38ff9d1a..06dc218b 100644 --- a/snd_main.c +++ b/snd_main.c @@ -53,6 +53,9 @@ speakerlayout_t; static speakerlayout_t snd_speakerlayout; +// Our speaker layouts are based on ALSA. They differ from those +// Win32 APIs and Mac OS X use when there's more than 4 channels. +// (rear left + rear right, and front center + LFE are swapped). #define SND_SPEAKERLAYOUTS (sizeof(snd_speakerlayouts) / sizeof(snd_speakerlayouts[0])) static const speakerlayout_t snd_speakerlayouts[] = { @@ -152,8 +155,10 @@ static sfx_t *known_sfx = NULL; static qboolean sound_spatialized = false; qboolean simsound = false; +qboolean alsaspeakerlayout = false; int snd_blocked = 0; +static int current_swapstereo = 0; // Cvars declared in sound.h (part of the sound API) cvar_t bgmvolume = {CVAR_SAVE, "bgmvolume", "1", "volume of background music (such as CD music or replacement files such as sound/cdtracks/track002.ogg)"}; @@ -343,6 +348,60 @@ static qboolean S_ChooseCheaperFormat (snd_format_t* format, qboolean fixed_spee } +#define SWAP_LISTENERS(l1, l2, tmpl) { tmpl = (l1); (l1) = (l2); (l2) = tmpl; } + +void S_SetSpeakerLayout (void) +{ + unsigned int i; + listener_t swaplistener; + listener_t *listeners; + + for (i = 0; i < SND_SPEAKERLAYOUTS; i++) + if (snd_speakerlayouts[i].channels == snd_renderbuffer->format.channels) + break; + if (i >= SND_SPEAKERLAYOUTS) + { + Con_Printf("S_SetSpeakerLayout: Can't find the speaker layout for %hu channels. Defaulting to mono output\n", + snd_renderbuffer->format.channels); + i = SND_SPEAKERLAYOUTS - 1; + } + + snd_speakerlayout = snd_speakerlayouts[i]; + listeners = snd_speakerlayout.listeners; + + // Swap the left and right channels if snd_swapstereo is set + if (snd_swapstereo.integer) + { + switch (snd_speakerlayout.channels) + { + case 8: + SWAP_LISTENERS(listeners[6], listeners[7], swaplistener); + // no break + case 4: + case 6: + SWAP_LISTENERS(listeners[2], listeners[3], swaplistener); + // no break + case 2: + SWAP_LISTENERS(listeners[0], listeners[1], swaplistener); + break; + + default: + case 1: + // Nothing to do + break; + } + } + + // Convert our layout (= ALSA) to Win32/CoreAudio layout if necessary + if (!alsaspeakerlayout && + (snd_speakerlayout.channels == 6 || snd_speakerlayout.channels == 8)) + { + SWAP_LISTENERS(listeners[2], listeners[4], swaplistener); + SWAP_LISTENERS(listeners[3], listeners[5], swaplistener); + } +} + + void S_Startup (void) { qboolean fixed_speed, fixed_width, fixed_channels; @@ -350,7 +409,6 @@ void S_Startup (void) static snd_format_t prev_render_format = {0, 0, 0}; const char* env; int i; - unsigned int layout_id; if (!snd_initialized.integer) return; @@ -477,6 +535,7 @@ void S_Startup (void) chosen_fmt.speed, chosen_fmt.width * 8, chosen_fmt.channels); + alsaspeakerlayout = false; memset(&suggest_fmt, 0, sizeof(suggest_fmt)); accepted = SndSys_Init(&chosen_fmt, &suggest_fmt); @@ -516,6 +575,10 @@ void S_Startup (void) Con_Printf("Sound format: %dHz, %d channels, %d bits per sample\n", chosen_fmt.speed, chosen_fmt.channels, chosen_fmt.width * 8); + if (chosen_fmt.channels > 4) + Con_Printf("Using %s speaker layout for 3D sound\n", + alsaspeakerlayout ? "ALSA" : "standard"); + // Update the cvars snd_speed.integer = chosen_fmt.speed; snd_width.integer = chosen_fmt.width; @@ -541,18 +604,8 @@ void S_Startup (void) snd_renderbuffer->startframe = soundtime; snd_renderbuffer->endframe = soundtime; - // select speaker layout - for (layout_id = 0; layout_id < SND_SPEAKERLAYOUTS; layout_id++) - if (snd_speakerlayouts[layout_id].channels == snd_renderbuffer->format.channels) - break; - if (layout_id >= SND_SPEAKERLAYOUTS) - { - Con_Printf("S_Startup: invalid number of channels (%hu). Can't find the corresponding speaker layout.\n" - "Defaulting to mono output\n", - snd_renderbuffer->format.channels); - layout_id = SND_SPEAKERLAYOUTS - 1; - } - snd_speakerlayout = snd_speakerlayouts[layout_id]; + S_SetSpeakerLayout(); + current_swapstereo = snd_swapstereo.integer; } void S_Shutdown(void) @@ -1331,6 +1384,13 @@ void S_Update(const matrix4x4_t *listenermatrix) if (snd_renderbuffer == NULL || snd_blocked > 0 || nosound.integer) return; + // If snd_swapstereo has changed, recompute the speaker layout + if (current_swapstereo != snd_swapstereo.integer) + { + current_swapstereo = snd_swapstereo.integer; + S_SetSpeakerLayout(); + } + Matrix4x4_Invert_Simple(&basematrix, listenermatrix); Matrix4x4_OriginFromMatrix(listenermatrix, listener_origin); diff --git a/snd_main.h b/snd_main.h index 47b622d0..82c34727 100644 --- a/snd_main.h +++ b/snd_main.h @@ -135,6 +135,8 @@ extern mempool_t *snd_mempool; // Used for isolating performance in the renderer. extern qboolean simsound; +extern qboolean alsaspeakerlayout; + // ==================================================================== // Architecture-independent functions diff --git a/snd_mix.c b/snd_mix.c index 0e4dada0..af6ba2b8 100644 --- a/snd_mix.c +++ b/snd_mix.c @@ -91,102 +91,46 @@ static unsigned int S_TransferPaintBuffer(snd_ringbuffer_t* rb, unsigned int sta short *snd_out = (short*)rb_ptr; if (rb->format.channels == 8) // 7.1 surround { - if (snd_swapstereo.value) - { - for (i = 0; i < nbframes; i++, painted_ptr++) - { - *snd_out++ = bound(-32768, painted_ptr->sample[1], 32767); - *snd_out++ = bound(-32768, painted_ptr->sample[0], 32767); - *snd_out++ = bound(-32768, painted_ptr->sample[3], 32767); - *snd_out++ = bound(-32768, painted_ptr->sample[2], 32767); - *snd_out++ = bound(-32768, painted_ptr->sample[4], 32767); - *snd_out++ = bound(-32768, painted_ptr->sample[5], 32767); - *snd_out++ = bound(-32768, painted_ptr->sample[6], 32767); - *snd_out++ = bound(-32768, painted_ptr->sample[7], 32767); - } - } - else + for (i = 0;i < nbframes;i++, painted_ptr++) { - for (i = 0;i < nbframes;i++, painted_ptr++) - { - *snd_out++ = bound(-32768, painted_ptr->sample[0], 32767); - *snd_out++ = bound(-32768, painted_ptr->sample[1], 32767); - *snd_out++ = bound(-32768, painted_ptr->sample[2], 32767); - *snd_out++ = bound(-32768, painted_ptr->sample[3], 32767); - *snd_out++ = bound(-32768, painted_ptr->sample[4], 32767); - *snd_out++ = bound(-32768, painted_ptr->sample[5], 32767); - *snd_out++ = bound(-32768, painted_ptr->sample[6], 32767); - *snd_out++ = bound(-32768, painted_ptr->sample[7], 32767); - } + *snd_out++ = bound(-32768, painted_ptr->sample[0], 32767); + *snd_out++ = bound(-32768, painted_ptr->sample[1], 32767); + *snd_out++ = bound(-32768, painted_ptr->sample[2], 32767); + *snd_out++ = bound(-32768, painted_ptr->sample[3], 32767); + *snd_out++ = bound(-32768, painted_ptr->sample[4], 32767); + *snd_out++ = bound(-32768, painted_ptr->sample[5], 32767); + *snd_out++ = bound(-32768, painted_ptr->sample[6], 32767); + *snd_out++ = bound(-32768, painted_ptr->sample[7], 32767); } } else if (rb->format.channels == 6) // 5.1 surround { - if (snd_swapstereo.value) - { - for (i = 0; i < nbframes; i++, painted_ptr++) - { - *snd_out++ = bound(-32768, painted_ptr->sample[1], 32767); - *snd_out++ = bound(-32768, painted_ptr->sample[0], 32767); - *snd_out++ = bound(-32768, painted_ptr->sample[3], 32767); - *snd_out++ = bound(-32768, painted_ptr->sample[2], 32767); - *snd_out++ = bound(-32768, painted_ptr->sample[4], 32767); - *snd_out++ = bound(-32768, painted_ptr->sample[5], 32767); - } - } - else + for (i = 0; i < nbframes; i++, painted_ptr++) { - for (i = 0; i < nbframes; i++, painted_ptr++) - { - *snd_out++ = bound(-32768, painted_ptr->sample[0], 32767); - *snd_out++ = bound(-32768, painted_ptr->sample[1], 32767); - *snd_out++ = bound(-32768, painted_ptr->sample[2], 32767); - *snd_out++ = bound(-32768, painted_ptr->sample[3], 32767); - *snd_out++ = bound(-32768, painted_ptr->sample[4], 32767); - *snd_out++ = bound(-32768, painted_ptr->sample[5], 32767); - } + *snd_out++ = bound(-32768, painted_ptr->sample[0], 32767); + *snd_out++ = bound(-32768, painted_ptr->sample[1], 32767); + *snd_out++ = bound(-32768, painted_ptr->sample[2], 32767); + *snd_out++ = bound(-32768, painted_ptr->sample[3], 32767); + *snd_out++ = bound(-32768, painted_ptr->sample[4], 32767); + *snd_out++ = bound(-32768, painted_ptr->sample[5], 32767); } } else if (rb->format.channels == 4) // 4.0 surround { - if (snd_swapstereo.value) - { - for (i = 0; i < nbframes; i++, painted_ptr++) - { - *snd_out++ = bound(-32768, painted_ptr->sample[1], 32767); - *snd_out++ = bound(-32768, painted_ptr->sample[0], 32767); - *snd_out++ = bound(-32768, painted_ptr->sample[3], 32767); - *snd_out++ = bound(-32768, painted_ptr->sample[2], 32767); - } - } - else + for (i = 0; i < nbframes; i++, painted_ptr++) { - for (i = 0; i < nbframes; i++, painted_ptr++) - { - *snd_out++ = bound(-32768, painted_ptr->sample[0], 32767); - *snd_out++ = bound(-32768, painted_ptr->sample[1], 32767); - *snd_out++ = bound(-32768, painted_ptr->sample[2], 32767); - *snd_out++ = bound(-32768, painted_ptr->sample[3], 32767); - } + *snd_out++ = bound(-32768, painted_ptr->sample[0], 32767); + *snd_out++ = bound(-32768, painted_ptr->sample[1], 32767); + *snd_out++ = bound(-32768, painted_ptr->sample[2], 32767); + *snd_out++ = bound(-32768, painted_ptr->sample[3], 32767); } } else if (rb->format.channels == 2) // 2.0 stereo { - if (snd_swapstereo.value) - { - for (i = 0; i < nbframes; i++, painted_ptr++) - { - *snd_out++ = bound(-32768, painted_ptr->sample[1], 32767); - *snd_out++ = bound(-32768, painted_ptr->sample[0], 32767); - } - } - else + for (i = 0; i < nbframes; i++, painted_ptr++) { - for (i = 0; i < nbframes; i++, painted_ptr++) - { - *snd_out++ = bound(-32768, painted_ptr->sample[0], 32767); - *snd_out++ = bound(-32768, painted_ptr->sample[1], 32767); - } + *snd_out++ = bound(-32768, painted_ptr->sample[0], 32767); + *snd_out++ = bound(-32768, painted_ptr->sample[1], 32767); } } else if (rb->format.channels == 1) // 1.0 mono @@ -203,102 +147,46 @@ static unsigned int S_TransferPaintBuffer(snd_ringbuffer_t* rb, unsigned int sta unsigned char *snd_out = (unsigned char*)rb_ptr; if (rb->format.channels == 8) // 7.1 surround { - if (snd_swapstereo.value) - { - for (i = 0; i < nbframes; i++, painted_ptr++) - { - val = (painted_ptr->sample[1] >> 8) + 128; *snd_out++ = bound(0, val, 255); - val = (painted_ptr->sample[0] >> 8) + 128; *snd_out++ = bound(0, val, 255); - val = (painted_ptr->sample[3] >> 8) + 128; *snd_out++ = bound(0, val, 255); - val = (painted_ptr->sample[2] >> 8) + 128; *snd_out++ = bound(0, val, 255); - val = (painted_ptr->sample[4] >> 8) + 128; *snd_out++ = bound(0, val, 255); - val = (painted_ptr->sample[5] >> 8) + 128; *snd_out++ = bound(0, val, 255); - val = (painted_ptr->sample[6] >> 8) + 128; *snd_out++ = bound(0, val, 255); - val = (painted_ptr->sample[7] >> 8) + 128; *snd_out++ = bound(0, val, 255); - } - } - else + for (i = 0; i < nbframes; i++, painted_ptr++) { - for (i = 0; i < nbframes; i++, painted_ptr++) - { - val = (painted_ptr->sample[0] >> 8) + 128; *snd_out++ = bound(0, val, 255); - val = (painted_ptr->sample[1] >> 8) + 128; *snd_out++ = bound(0, val, 255); - val = (painted_ptr->sample[2] >> 8) + 128; *snd_out++ = bound(0, val, 255); - val = (painted_ptr->sample[3] >> 8) + 128; *snd_out++ = bound(0, val, 255); - val = (painted_ptr->sample[4] >> 8) + 128; *snd_out++ = bound(0, val, 255); - val = (painted_ptr->sample[5] >> 8) + 128; *snd_out++ = bound(0, val, 255); - val = (painted_ptr->sample[6] >> 8) + 128; *snd_out++ = bound(0, val, 255); - val = (painted_ptr->sample[7] >> 8) + 128; *snd_out++ = bound(0, val, 255); - } + val = (painted_ptr->sample[0] >> 8) + 128; *snd_out++ = bound(0, val, 255); + val = (painted_ptr->sample[1] >> 8) + 128; *snd_out++ = bound(0, val, 255); + val = (painted_ptr->sample[2] >> 8) + 128; *snd_out++ = bound(0, val, 255); + val = (painted_ptr->sample[3] >> 8) + 128; *snd_out++ = bound(0, val, 255); + val = (painted_ptr->sample[4] >> 8) + 128; *snd_out++ = bound(0, val, 255); + val = (painted_ptr->sample[5] >> 8) + 128; *snd_out++ = bound(0, val, 255); + val = (painted_ptr->sample[6] >> 8) + 128; *snd_out++ = bound(0, val, 255); + val = (painted_ptr->sample[7] >> 8) + 128; *snd_out++ = bound(0, val, 255); } } else if (rb->format.channels == 6) // 5.1 surround { - if (snd_swapstereo.value) - { - for (i = 0; i < nbframes; i++, painted_ptr++) - { - val = (painted_ptr->sample[1] >> 8) + 128; *snd_out++ = bound(0, val, 255); - val = (painted_ptr->sample[0] >> 8) + 128; *snd_out++ = bound(0, val, 255); - val = (painted_ptr->sample[3] >> 8) + 128; *snd_out++ = bound(0, val, 255); - val = (painted_ptr->sample[2] >> 8) + 128; *snd_out++ = bound(0, val, 255); - val = (painted_ptr->sample[4] >> 8) + 128; *snd_out++ = bound(0, val, 255); - val = (painted_ptr->sample[5] >> 8) + 128; *snd_out++ = bound(0, val, 255); - } - } - else + for (i = 0; i < nbframes; i++, painted_ptr++) { - for (i = 0; i < nbframes; i++, painted_ptr++) - { - val = (painted_ptr->sample[0] >> 8) + 128; *snd_out++ = bound(0, val, 255); - val = (painted_ptr->sample[1] >> 8) + 128; *snd_out++ = bound(0, val, 255); - val = (painted_ptr->sample[2] >> 8) + 128; *snd_out++ = bound(0, val, 255); - val = (painted_ptr->sample[3] >> 8) + 128; *snd_out++ = bound(0, val, 255); - val = (painted_ptr->sample[4] >> 8) + 128; *snd_out++ = bound(0, val, 255); - val = (painted_ptr->sample[5] >> 8) + 128; *snd_out++ = bound(0, val, 255); - } + val = (painted_ptr->sample[0] >> 8) + 128; *snd_out++ = bound(0, val, 255); + val = (painted_ptr->sample[1] >> 8) + 128; *snd_out++ = bound(0, val, 255); + val = (painted_ptr->sample[2] >> 8) + 128; *snd_out++ = bound(0, val, 255); + val = (painted_ptr->sample[3] >> 8) + 128; *snd_out++ = bound(0, val, 255); + val = (painted_ptr->sample[4] >> 8) + 128; *snd_out++ = bound(0, val, 255); + val = (painted_ptr->sample[5] >> 8) + 128; *snd_out++ = bound(0, val, 255); } } else if (rb->format.channels == 4) // 4.0 surround { - if (snd_swapstereo.value) - { - for (i = 0; i < nbframes; i++, painted_ptr++) - { - val = (painted_ptr->sample[1] >> 8) + 128; *snd_out++ = bound(0, val, 255); - val = (painted_ptr->sample[0] >> 8) + 128; *snd_out++ = bound(0, val, 255); - val = (painted_ptr->sample[3] >> 8) + 128; *snd_out++ = bound(0, val, 255); - val = (painted_ptr->sample[2] >> 8) + 128; *snd_out++ = bound(0, val, 255); - } - } - else + for (i = 0; i < nbframes; i++, painted_ptr++) { - for (i = 0; i < nbframes; i++, painted_ptr++) - { - val = (painted_ptr->sample[0] >> 8) + 128; *snd_out++ = bound(0, val, 255); - val = (painted_ptr->sample[1] >> 8) + 128; *snd_out++ = bound(0, val, 255); - val = (painted_ptr->sample[2] >> 8) + 128; *snd_out++ = bound(0, val, 255); - val = (painted_ptr->sample[3] >> 8) + 128; *snd_out++ = bound(0, val, 255); - } + val = (painted_ptr->sample[0] >> 8) + 128; *snd_out++ = bound(0, val, 255); + val = (painted_ptr->sample[1] >> 8) + 128; *snd_out++ = bound(0, val, 255); + val = (painted_ptr->sample[2] >> 8) + 128; *snd_out++ = bound(0, val, 255); + val = (painted_ptr->sample[3] >> 8) + 128; *snd_out++ = bound(0, val, 255); } } else if (rb->format.channels == 2) // 2.0 stereo { - if (snd_swapstereo.value) - { - for (i = 0; i < nbframes; i++, painted_ptr++) - { - val = (painted_ptr->sample[1] >> 8) + 128; *snd_out++ = bound(0, val, 255); - val = (painted_ptr->sample[0] >> 8) + 128; *snd_out++ = bound(0, val, 255); - } - } - else + for (i = 0; i < nbframes; i++, painted_ptr++) { - for (i = 0; i < nbframes; i++, painted_ptr++) - { - val = (painted_ptr->sample[0] >> 8) + 128; *snd_out++ = bound(0, val, 255); - val = (painted_ptr->sample[1] >> 8) + 128; *snd_out++ = bound(0, val, 255); - } + val = (painted_ptr->sample[0] >> 8) + 128; *snd_out++ = bound(0, val, 255); + val = (painted_ptr->sample[1] >> 8) + 128; *snd_out++ = bound(0, val, 255); } } else if (rb->format.channels == 1) // 1.0 mono diff --git a/snd_oss.c b/snd_oss.c index 89800691..ca17c051 100644 --- a/snd_oss.c +++ b/snd_oss.c @@ -161,6 +161,12 @@ qboolean SndSys_Init (const snd_format_t* requested, snd_format_t* suggested) return false; } +#ifdef __linux__ + alsaspeakerlayout = true; +#else + alsaspeakerlayout = false; +#endif + old_osstime = 0; osssoundtime = 0; snd_renderbuffer = Snd_CreateRingBuffer(requested, 0, NULL); @@ -228,9 +234,9 @@ void SndSys_Submit (void) snd_renderbuffer->startframe += written / factor; - if ((unsigned int)written < nbframes * factor) + if ((unsigned int)written < limit * factor) { - Con_Printf("SndSys_Submit: audio can't keep up! (%d < %u)\n", written, nbframes * factor); + Con_Printf("SndSys_Submit: audio can't keep up! (%u < %u)\n", written, limit * factor); return; } @@ -244,7 +250,14 @@ void SndSys_Submit (void) Con_Printf("SndSys_Submit: audio write returned %d!\n", written); return; } + + if (written % factor != 0) + Sys_Error("SndSys_Submit: nb of bytes written (%d) isn't aligned to a frame sample!\n", written); + snd_renderbuffer->startframe += written / factor; + + if ((unsigned int)written < nbframes * factor) + Con_Printf("SndSys_Submit: audio can't keep up! (%u < %u)\n", written, nbframes * factor); } diff --git a/snd_sdl.c b/snd_sdl.c index 6dccba73..90b53129 100644 --- a/snd_sdl.c +++ b/snd_sdl.c @@ -142,6 +142,12 @@ qboolean SndSys_Init (const snd_format_t* requested, snd_format_t* suggested) snd_renderbuffer = Snd_CreateRingBuffer(requested, 0, NULL); +#ifdef __linux__ + alsaspeakerlayout = true; +#else + alsaspeakerlayout = false; +#endif + sdlaudiotime = 0; SDL_PauseAudio( false ); -- 2.39.2