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[] =
{
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)"};
}
+#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;
static snd_format_t prev_render_format = {0, 0, 0};
const char* env;
int i;
- unsigned int layout_id;
if (!snd_initialized.integer)
return;
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);
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;
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)
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);
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
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