qboolean SNDDMA_Init (void)
{
- int err, i;
- int bps = -1, stereo = -1;
- unsigned int rate = 0;
+ int err, i, j;
+ int width;
+ int channels;
+ unsigned int rate;
snd_pcm_hw_params_t *hw;
snd_pcm_sw_params_t *sw;
- snd_pcm_uframes_t frag_size;
+ snd_pcm_uframes_t frag_size;
snd_pcm_hw_params_alloca (&hw);
snd_pcm_sw_params_alloca (&sw);
-// COMMANDLINEOPTION: Linux ALSA Sound: -sndpcm <devicename> selects which pcm device to us, default is "default"
- if ((i=COM_CheckParm("-sndpcm"))!=0)
- pcmname=com_argv[i+1];
- if (!pcmname)
- pcmname = "default";
-
// COMMANDLINEOPTION: Linux ALSA Sound: -sndbits <number> sets sound precision to 8 or 16 bit (email me if you want others added)
+ width = 2;
if ((i=COM_CheckParm("-sndbits")) != 0)
{
- bps = atoi(com_argv[i+1]);
- if (bps != 16 && bps != 8)
- {
- Con_Printf("Error: invalid sample bits: %d\n", bps);
- return false;
- }
+ j = atoi(com_argv[i+1]);
+ if (j == 16 || j == 8)
+ width = j / 8;
+ else
+ Con_Printf("Error: invalid sample bits: %d\n", j);
}
// COMMANDLINEOPTION: Linux ALSA Sound: -sndspeed <hz> chooses 44100 hz, 22100 hz, or 11025 hz sound output rate
+ rate = 44100;
if ((i=COM_CheckParm("-sndspeed")) != 0)
{
- rate = atoi(com_argv[i+1]);
- if (rate!=44100 && rate!=22050 && rate!=11025)
- {
+ j = atoi(com_argv[i+1]);
+ if (j >= 1)
+ rate = j;
+ else
Con_Printf("Error: invalid sample rate: %d\n", rate);
- return false;
- }
}
+ for (channels = 8;channels >= 1;channels--)
+ {
+ if ((channels & 1) && channels != 1)
+ continue;
// COMMANDLINEOPTION: Linux ALSA Sound: -sndmono sets sound output to mono
- if ((i=COM_CheckParm("-sndmono")) != 0)
- stereo=0;
+ if ((i=COM_CheckParm("-sndmono")) != 0)
+ if (channels != 1)
+ continue;
// COMMANDLINEOPTION: Linux ALSA Sound: -sndstereo sets sound output to stereo
- if ((i=COM_CheckParm("-sndstereo")) != 0)
- stereo=1;
+ if ((i=COM_CheckParm("-sndstereo")) != 0)
+ if (channels != 2)
+ continue;
- err = snd_pcm_open (&pcm, pcmname, SND_PCM_STREAM_PLAYBACK,
- SND_PCM_NONBLOCK);
- if (0 > err) {
- Con_Printf ("Error: audio open error: %s\n", snd_strerror (err));
- return 0;
- }
- Con_Printf ("ALSA: Using PCM %s.\n", pcmname);
+// COMMANDLINEOPTION: Linux ALSA Sound: -sndpcm <devicename> selects which pcm device to us, default is "default"
+ if (channels == 8)
+ pcmname = "surround71";
+ else if (channels == 6)
+ pcmname = "surround51";
+ else if (channels == 4)
+ pcmname = "surround40";
+ else
+ pcmname = "default";
+ if ((i=COM_CheckParm("-sndpcm"))!=0)
+ pcmname = com_argv[i+1];
+
+ Con_Printf ("ALSA: Trying PCM %s.\n", pcmname);
+
+ err = snd_pcm_open (&pcm, pcmname, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
+ if (0 > err)
+ {
+ Con_Printf ("Error: audio open error: %s\n", snd_strerror (err));
+ continue;
+ }
- err = snd_pcm_hw_params_any (pcm, hw);
- if (0 > err) {
- Con_Printf ("ALSA: error setting hw_params_any. %s\n",
- snd_strerror (err));
- goto error;
- }
+ err = snd_pcm_hw_params_any (pcm, hw);
+ if (0 > err)
+ {
+ Con_Printf ("ALSA: error setting hw_params_any. %s\n", snd_strerror (err));
+ snd_pcm_close (pcm);
+ continue;
+ }
- err = snd_pcm_hw_params_set_access (pcm, hw,
- SND_PCM_ACCESS_MMAP_INTERLEAVED);
- if (0 > err) {
- Con_Printf ("ALSA: Failure to set noninterleaved PCM access. %s\n"
- "Note: Interleaved is not supported\n",
- snd_strerror (err));
- goto error;
- }
+ err = snd_pcm_hw_params_set_access (pcm, hw, SND_PCM_ACCESS_MMAP_INTERLEAVED);
+ if (0 > err)
+ {
+ Con_Printf ("ALSA: Failure to set interleaved mmap PCM access. %s\n", snd_strerror (err));
+ snd_pcm_close (pcm);
+ continue;
+ }
- switch (bps) {
- case -1:
- err = snd_pcm_hw_params_set_format (pcm, hw,
- SND_PCM_FORMAT_S16);
- if (0 <= err) {
- bps = 16;
- } else if (0 <= (err = snd_pcm_hw_params_set_format (pcm, hw,
- SND_PCM_FORMAT_U8))) {
- bps = 8;
- } else {
- Con_Printf ("ALSA: no useable formats. %s\n",
- snd_strerror (err));
- goto error;
- }
- break;
- case 8:
- case 16:
- err = snd_pcm_hw_params_set_format (pcm, hw, bps == 8 ?
- SND_PCM_FORMAT_U8 :
- SND_PCM_FORMAT_S16);
- if (0 > err) {
- Con_Printf ("ALSA: no usable formats. %s\n",
- snd_strerror (err));
- goto error;
- }
- break;
- default:
- Con_Printf ("ALSA: desired format not supported\n");
- goto error;
- }
+ err = snd_pcm_hw_params_set_format (pcm, hw, width == 1 ? SND_PCM_FORMAT_U8 : SND_PCM_FORMAT_S16);
+ if (0 > err)
+ {
+ Con_Printf ("ALSA: desired bits %i not supported by driver. %s\n", width * 8, snd_strerror (err));
+ snd_pcm_close (pcm);
+ continue;
+ }
- switch (stereo) {
- case -1:
- err = snd_pcm_hw_params_set_channels (pcm, hw, 2);
- if (0 <= err) {
- stereo = 1;
- } else if (0 <= (err = snd_pcm_hw_params_set_channels (pcm, hw,
- 1))) {
- stereo = 0;
- } else {
- Con_Printf ("ALSA: no usable channels. %s\n",
- snd_strerror (err));
- goto error;
- }
- break;
- case 0:
- case 1:
- err = snd_pcm_hw_params_set_channels (pcm, hw, stereo ? 2 : 1);
- if (0 > err) {
- Con_Printf ("ALSA: no usable channels. %s\n",
- snd_strerror (err));
- goto error;
- }
- break;
- default:
- Con_Printf ("ALSA: desired channels not supported\n");
- goto error;
- }
+ err = snd_pcm_hw_params_set_channels (pcm, hw, channels);
+ if (0 > err)
+ {
+ Con_Printf ("ALSA: no usable channels. %s\n", snd_strerror (err));
+ snd_pcm_close (pcm);
+ continue;
+ }
- switch (rate) {
- case 0:
- rate = 44100;
- err = snd_pcm_hw_params_set_rate_near (pcm, hw, &rate, 0);
- if (0 <= err) {
- frag_size = 32 * bps;
- } else {
- rate = 22050;
- err = snd_pcm_hw_params_set_rate_near (pcm, hw, &rate, 0);
- if (0 <= err) {
- frag_size = 16 * bps;
- } else {
- rate = 11025;
- err = snd_pcm_hw_params_set_rate_near (pcm, hw, &rate,
- 0);
- if (0 <= err) {
- frag_size = 8 * bps;
- } else {
- Con_Printf ("ALSA: no usable rates. %s\n",
- snd_strerror (err));
- goto error;
- }
- }
- }
- break;
- case 11025:
- case 22050:
- case 44100:
- err = snd_pcm_hw_params_set_rate_near (pcm, hw, &rate, 0);
- if (0 > err) {
- Con_Printf ("ALSA: desired rate %i not supported. %s\n", rate,
- snd_strerror (err));
- goto error;
- }
- frag_size = 8 * bps * rate / 11025;
- break;
- default:
- Con_Printf ("ALSA: desired rate %i not supported.\n", rate);
- goto error;
- }
+ err = snd_pcm_hw_params_set_rate_near (pcm, hw, &rate, 0);
+ if (0 > err)
+ {
+ Con_Printf ("ALSA: desired rate %i not supported by driver. %s\n", rate, snd_strerror (err));
+ snd_pcm_close (pcm);
+ continue;
+ }
- err = snd_pcm_hw_params_set_period_size_near (pcm, hw, &frag_size, 0);
- if (0 > err) {
- Con_Printf ("ALSA: unable to set period size near %i. %s\n",
- (int) frag_size, snd_strerror (err));
- goto error;
- }
- err = snd_pcm_hw_params (pcm, hw);
- if (0 > err) {
- Con_Printf ("ALSA: unable to install hw params: %s\n",
- snd_strerror (err));
- goto error;
- }
- err = snd_pcm_sw_params_current (pcm, sw);
- if (0 > err) {
- Con_Printf ("ALSA: unable to determine current sw params. %s\n",
- snd_strerror (err));
- goto error;
- }
- err = snd_pcm_sw_params_set_start_threshold (pcm, sw, ~0U);
- if (0 > err) {
- Con_Printf ("ALSA: unable to set playback threshold. %s\n",
- snd_strerror (err));
- goto error;
- }
- err = snd_pcm_sw_params_set_stop_threshold (pcm, sw, ~0U);
- if (0 > err) {
- Con_Printf ("ALSA: unable to set playback stop threshold. %s\n",
- snd_strerror (err));
- goto error;
- }
- err = snd_pcm_sw_params (pcm, sw);
- if (0 > err) {
- Con_Printf ("ALSA: unable to install sw params. %s\n",
- snd_strerror (err));
- goto error;
- }
+ frag_size = 64 * width * rate / 11025;
+ err = snd_pcm_hw_params_set_period_size_near (pcm, hw, &frag_size, 0);
+ if (0 > err)
+ {
+ Con_Printf ("ALSA: unable to set period size near %i. %s\n", (int) frag_size, snd_strerror (err));
+ snd_pcm_close (pcm);
+ continue;
+ }
+ err = snd_pcm_hw_params (pcm, hw);
+ if (0 > err)
+ {
+ Con_Printf ("ALSA: unable to install hw params: %s\n", snd_strerror (err));
+ snd_pcm_close (pcm);
+ continue;
+ }
+ err = snd_pcm_sw_params_current (pcm, sw);
+ if (0 > err)
+ {
+ Con_Printf ("ALSA: unable to determine current sw params. %s\n", snd_strerror (err));
+ snd_pcm_close (pcm);
+ continue;
+ }
+ err = snd_pcm_sw_params_set_start_threshold (pcm, sw, ~0U);
+ if (0 > err)
+ {
+ Con_Printf ("ALSA: unable to set playback threshold. %s\n", snd_strerror (err));
+ snd_pcm_close (pcm);
+ continue;
+ }
+ err = snd_pcm_sw_params_set_stop_threshold (pcm, sw, ~0U);
+ if (0 > err)
+ {
+ Con_Printf ("ALSA: unable to set playback stop threshold. %s\n", snd_strerror (err));
+ snd_pcm_close (pcm);
+ continue;
+ }
+ err = snd_pcm_sw_params (pcm, sw);
+ if (0 > err)
+ {
+ Con_Printf ("ALSA: unable to install sw params. %s\n", snd_strerror (err));
+ snd_pcm_close (pcm);
+ continue;
+ }
- shm->format.channels = stereo + 1;
- shm->samplepos = 0;
- shm->format.width = bps / 8;
+ err = snd_pcm_hw_params_get_buffer_size (hw, &buffer_size);
+ if (0 > err)
+ {
+ Con_Printf ("ALSA: unable to get buffer size. %s\n", snd_strerror (err));
+ snd_pcm_close (pcm);
+ continue;
+ }
- err = snd_pcm_hw_params_get_buffer_size (hw, &buffer_size);
- if (0 > err) {
- Con_Printf ("ALSA: unable to get buffer size. %s\n",
- snd_strerror (err));
- goto error;
+ memset( (void*) shm, 0, sizeof(*shm) );
+ shm->format.channels = channels;
+ shm->format.width = width;
+ shm->format.speed = rate;
+ shm->samplepos = 0;
+ shm->sampleframes = buffer_size;
+ shm->samples = shm->sampleframes * shm->format.channels;
+ SNDDMA_GetDMAPos (); // sets shm->buffer
+
+ snd_inited = 1;
+ return true;
}
-
- shm->samples = buffer_size * shm->format.channels; // mono samples in buffer
- shm->format.speed = rate;
- SNDDMA_GetDMAPos (); // sets shm->buffer
-
- snd_inited = 1;
- return true;
-
-error:
- snd_pcm_close (pcm);
return false;
}
{
const snd_pcm_channel_area_t *areas;
snd_pcm_uframes_t offset;
- snd_pcm_uframes_t nframes = shm->samples/shm->format.channels;
+ snd_pcm_uframes_t nframes = shm->sampleframes;
if (!snd_inited)
return 0;
(info.play.channels == 2) ? "stereo" : "mono",
info.play.sample_rate);
- shm->samples = sizeof (dma_buffer) / shm->format.width;
+ shm->sampleframes = sizeof (dma_buffer) / shm->format.width / shm->format.channels;
+ shm->samples = shm->sampleframes * shm->format.channels;
shm->samplepos = 0;
shm->buffer = dma_buffer;
#include "snd_main.h"
#include "snd_ogg.h"
+#if SND_LISTENERS != 8
+#error this data only supports up to 8 channel, update it!
+#endif
+typedef struct listener_s
+{
+ float yawangle;
+ float dotscale;
+ float dotbias;
+ float ambientvolume;
+}
+listener_t;
+typedef struct speakerlayout_s
+{
+ const char *name;
+ unsigned int channels;
+ qboolean headphones;
+ listener_t listeners[SND_LISTENERS];
+}
+speakerlayout_t;
+
+static speakerlayout_t snd_speakerlayout;
void S_Play(void);
void S_PlayVol(void);
int snd_blocked = 0;
cvar_t snd_initialized = { CVAR_READONLY, "snd_initialized", "0"};
cvar_t snd_streaming = { CVAR_SAVE, "snd_streaming", "1"};
+cvar_t snd_headphones = { CVAR_SAVE, "snd_headphones", "0"};
volatile dma_t *shm = 0;
volatile dma_t sn;
vec3_t listener_origin;
-matrix4x4_t listener_matrix;
+matrix4x4_t listener_matrix[SND_LISTENERS];
vec_t sound_nominal_clip_dist=1000.0;
mempool_t *snd_mempool;
return;
}
- Con_Printf("%5d stereo\n", shm->format.channels - 1);
+ Con_Printf("%5d speakers\n", shm->format.channels);
+ Con_Printf("%5d frames\n", shm->sampleframes);
Con_Printf("%5d samples\n", shm->samples);
Con_Printf("%5d samplepos\n", shm->samplepos);
Con_Printf("%5d samplebits\n", shm->format.width * 8);
shm->format.width = 2;
shm->format.speed = 22050;
shm->format.channels = 2;
- shm->samples = 32768;
+ shm->sampleframes = 16384;
+ shm->samples = shm->sampleframes * shm->format.channels;
shm->samplepos = 0;
- shm->buffer = (unsigned char *)Mem_Alloc(snd_mempool, shm->format.channels * shm->samples * shm->format.width);
+ shm->buffer = (unsigned char *)Mem_Alloc(snd_mempool, shm->samples * shm->format.width);
}
else
{
Cvar_RegisterVariable(&volume);
Cvar_RegisterVariable(&bgmvolume);
Cvar_RegisterVariable(&snd_staticvolume);
+ Cvar_RegisterVariable(&snd_headphones);
// COMMANDLINEOPTION: Sound: -nosound disables sound (including CD audio)
if (COM_CheckParm("-nosound") || COM_CheckParm("-safe"))
for (ch_idx=NUM_AMBIENTS ; ch_idx < NUM_AMBIENTS + MAX_DYNAMIC_CHANNELS ; ch_idx++)
{
ch = &channels[ch_idx];
- if (entchannel != 0 // channel 0 never overrides
- && ch->entnum == entnum
- && (ch->entchannel == entchannel || entchannel == -1) )
- { // always override sound from same entity
- first_to_die = ch_idx;
- break;
+ if (entchannel != 0)
+ {
+ // try to override an existing channel
+ if (ch->entnum == entnum && (ch->entchannel == entchannel || entchannel == -1) )
+ {
+ // always override sound from same entity
+ first_to_die = ch_idx;
+ break;
+ }
+ }
+ else
+ {
+ if (!ch->sfx)
+ {
+ // no sound on this channel
+ first_to_die = ch_idx;
+ break;
+ }
}
- // don't let monster sounds override player sounds
- if (ch->entnum == cl.viewentity && entnum != cl.viewentity && ch->sfx)
- continue;
+ if (ch->sfx)
+ {
+ // don't let monster sounds override player sounds
+ if (ch->entnum == cl.viewentity && entnum != cl.viewentity)
+ continue;
- // don't override looped sounds
- if ((ch->flags & CHANNELFLAG_FORCELOOP) != 0 ||
- (ch->sfx != NULL && ch->sfx->loopstart >= 0))
- continue;
+ // don't override looped sounds
+ if ((ch->flags & CHANNELFLAG_FORCELOOP) || ch->sfx->loopstart >= 0)
+ continue;
+ }
if (ch->end - paintedtime < life_left)
{
*/
void SND_Spatialize(channel_t *ch, qboolean isstatic)
{
- vec_t dist, scale, pan;
+ int i;
+ vec_t dist, mastervol, intensity, vol;
vec3_t source_vec;
+ // update sound origin if we know about the entity
+ if (ch->entnum > 0 && cls.state == ca_connected && cl_entities[ch->entnum].state_current.active)
+ {
+ //Con_Printf("-- entnum %i origin %f %f %f neworigin %f %f %f\n", ch->entnum, ch->origin[0], ch->origin[1], ch->origin[2], cl_entities[ch->entnum].state_current.origin[0], cl_entities[ch->entnum].state_current.origin[1], cl_entities[ch->entnum].state_current.origin[2]);
+ VectorCopy(cl_entities[ch->entnum].state_current.origin, ch->origin);
+ if (cl_entities[ch->entnum].state_current.modelindex && cl.model_precache[cl_entities[ch->entnum].state_current.modelindex] && cl.model_precache[cl_entities[ch->entnum].state_current.modelindex]->soundfromcenter)
+ VectorMAMAM(1.0f, ch->origin, 0.5f, cl.model_precache[cl_entities[ch->entnum].state_current.modelindex]->normalmins, 0.5f, cl.model_precache[cl_entities[ch->entnum].state_current.modelindex]->normalmaxs, ch->origin);
+ }
+
+ mastervol = ch->master_vol;
+ // Adjust volume of static sounds
+ if (isstatic)
+ mastervol *= snd_staticvolume.value;
+
// anything coming from the view entity will always be full volume
// LordHavoc: make sounds with ATTN_NONE have no spatialization
if (ch->entnum == cl.viewentity || ch->dist_mult == 0)
{
- ch->leftvol = ch->master_vol;
- ch->rightvol = ch->master_vol;
+ for (i = 0;i < SND_LISTENERS;i++)
+ {
+ vol = mastervol * snd_speakerlayout.listeners[i].ambientvolume;
+ ch->listener_volume[i] = bound(0, vol, 255);
+ }
}
else
{
- // update sound origin if we know about the entity
- if (ch->entnum > 0 && cls.state == ca_connected && cl_entities[ch->entnum].render.model)
+ // calculate stereo seperation and distance attenuation
+ VectorSubtract(listener_origin, ch->origin, source_vec);
+ dist = VectorLength(source_vec);
+ intensity = mastervol * (1.0 - dist * ch->dist_mult);
+ if (intensity > 0)
{
- //Con_Printf("-- entnum %i origin %f %f %f neworigin %f %f %f\n", ch->entnum, ch->origin[0], ch->origin[1], ch->origin[2], cl_entities[ch->entnum].persistent.trail_origin[0], cl_entities[ch->entnum].persistent.trail_origin[1], cl_entities[ch->entnum].persistent.trail_origin[2]);
- VectorCopy(cl_entities[ch->entnum].persistent.trail_origin, ch->origin);
+ for (i = 0;i < SND_LISTENERS;i++)
+ {
+ Matrix4x4_Transform(&listener_matrix[i], ch->origin, source_vec);
+ VectorNormalize(source_vec);
+ vol = intensity * max(0, source_vec[0] * snd_speakerlayout.listeners[i].dotscale + snd_speakerlayout.listeners[i].dotbias);
+ ch->listener_volume[i] = bound(0, vol, 255);
+ }
}
-
- // calculate stereo seperation and distance attenuation
- Matrix4x4_Transform(&listener_matrix, ch->origin, source_vec);
- dist = VectorNormalizeLength(source_vec);
- // distance
- scale = ch->master_vol * (1.0 - (dist * ch->dist_mult));
- // panning
- pan = scale * source_vec[1];
- // calculate the volumes
- ch->leftvol = (int) (scale + pan);
- ch->rightvol = (int) (scale - pan);
- //Con_Printf("%f %f %f:%f %f %f:%f %f:%d %d\n", ch->origin[0], ch->origin[1], ch->origin[2], source_vec[0], source_vec[1], source_vec[2], scale, pan, ch->leftvol, ch->rightvol);
- }
-
- // Adjust volume of static sounds
- if (isstatic)
- {
- ch->leftvol *= snd_staticvolume.value;
- ch->rightvol *= snd_staticvolume.value;
+ else
+ for (i = 0;i < SND_LISTENERS;i++)
+ ch->listener_volume[i] = 0;
}
-
- // clamp volumes
- ch->leftvol = bound(0, ch->leftvol, 255);
- ch->rightvol = bound(0, ch->rightvol, 255);
}
*/
void S_UpdateAmbientSounds (void)
{
+ int i;
float vol;
int ambient_channel;
channel_t *chan;
unsigned char ambientlevels[NUM_AMBIENTS];
- if (ambient_level.value <= 0 || !cl.worldmodel || !cl.worldmodel->brush.AmbientSoundLevelsForPoint)
- return;
-
- cl.worldmodel->brush.AmbientSoundLevelsForPoint(cl.worldmodel, listener_origin, ambientlevels, sizeof(ambientlevels));
+ memset(ambientlevels, 0, sizeof(ambientlevels));
+ if (cl.worldmodel && cl.worldmodel->brush.AmbientSoundLevelsForPoint)
+ cl.worldmodel->brush.AmbientSoundLevelsForPoint(cl.worldmodel, listener_origin, ambientlevels, sizeof(ambientlevels));
// Calc ambient sound levels
for (ambient_channel = 0 ; ambient_channel< NUM_AMBIENTS ; ambient_channel++)
if (chan->sfx == NULL || chan->sfx->fetcher == NULL)
continue;
- vol = ambient_level.value * ambientlevels[ambient_channel];
+ vol = ambientlevels[ambient_channel];
if (vol < 8)
vol = 0;
chan->master_vol = vol;
}
- chan->leftvol = chan->rightvol = chan->master_vol;
+ for (i = 0;i < SND_LISTENERS;i++)
+ chan->listener_volume[i] = (int)(chan->master_vol * ambient_level.value * snd_speakerlayout.listeners[i].ambientvolume);
}
}
+#define SND_SPEAKERLAYOUTS 5
+static speakerlayout_t snd_speakerlayouts[SND_SPEAKERLAYOUTS] =
+{
+ {
+ "surround71", 8, false,
+ {
+ {45, 0.2, 0.2, 0.5}, // front left
+ {315, 0.2, 0.2, 0.5}, // front right
+ {135, 0.2, 0.2, 0.5}, // rear left
+ {225, 0.2, 0.2, 0.5}, // rear right
+ {0, 0.2, 0.2, 0.5}, // front center
+ {0, 0, 0, 0}, // lfe (we don't have any good lfe sound sources and it would take some filtering work to generate them (and they'd probably still be wrong), so... no lfe)
+ {90, 0.2, 0.2, 0.5}, // side left
+ {180, 0.2, 0.2, 0.5}, // side right
+ }
+ },
+ {
+ "surround51", 6, false,
+ {
+ {45, 0.2, 0.2, 0.5}, // front left
+ {315, 0.2, 0.2, 0.5}, // front right
+ {135, 0.2, 0.2, 0.5}, // rear left
+ {225, 0.2, 0.2, 0.5}, // rear right
+ {0, 0.2, 0.2, 0.5}, // front center
+ {0, 0, 0, 0}, // lfe (we don't have any good lfe sound sources and it would take some filtering work to generate them (and they'd probably still be wrong), so... no lfe)
+ {0, 0, 0, 0},
+ {0, 0, 0, 0},
+ }
+ },
+ {
+ // these systems sometimes have a subwoofer as well, but it has no
+ // channel of its own
+ "surround40", 4, false,
+ {
+ {45, 0.3, 0.3, 0.8}, // front left
+ {315, 0.3, 0.3, 0.8}, // front right
+ {135, 0.3, 0.3, 0.8}, // rear left
+ {225, 0.3, 0.3, 0.8}, // rear right
+ {0, 0, 0, 0},
+ {0, 0, 0, 0},
+ {0, 0, 0, 0},
+ {0, 0, 0, 0},
+ }
+ },
+ {
+ "headphones", 2, true,
+ {
+ {90, 0.5, 0.5, 1}, // side left
+ {270, 0.5, 0.5, 1}, // side right
+ {0, 0, 0, 0},
+ {0, 0, 0, 0},
+ {0, 0, 0, 0},
+ {0, 0, 0, 0},
+ {0, 0, 0, 0},
+ {0, 0, 0, 0},
+ }
+ },
+ {
+ // these systems sometimes have a subwoofer as well, but it has no
+ // channel of its own
+ "stereo", 2, false,
+ {
+ {45, 0.5, 0.5, 1}, // front left
+ {315, 0.5, 0.5, 1}, // front right
+ {0, 0, 0, 0},
+ {0, 0, 0, 0},
+ {0, 0, 0, 0},
+ {0, 0, 0, 0},
+ {0, 0, 0, 0},
+ {0, 0, 0, 0},
+ }
+ }
+};
/*
============
{
unsigned int i, j, total;
channel_t *ch, *combine;
+ matrix4x4_t basematrix, rotatematrix;
if (!snd_initialized.integer || (snd_blocked > 0))
return;
- Matrix4x4_Invert_Simple(&listener_matrix, listenermatrix);
+ Matrix4x4_Invert_Simple(&basematrix, listenermatrix);
Matrix4x4_OriginFromMatrix(listenermatrix, listener_origin);
+ // select speaker layout
+ for (i = 0;i < SND_SPEAKERLAYOUTS - 1;i++)
+ if (snd_speakerlayouts[i].channels == shm->format.channels && (!snd_speakerlayouts[i].headphones || snd_headphones.integer))
+ break;
+ snd_speakerlayout = snd_speakerlayouts[i];
+
+ // calculate the current matrices
+ for (j = 0;j < SND_LISTENERS;j++)
+ {
+ Matrix4x4_CreateFromQuakeEntity(&rotatematrix, 0, 0, 0, 0, snd_speakerlayout.listeners[j].yawangle, 0, 1);
+ Matrix4x4_Concat(&listener_matrix[j], &basematrix, &rotatematrix);
+ }
+
// update general area ambient sound sources
S_UpdateAmbientSounds ();
{
if (!ch->sfx)
continue;
- SND_Spatialize(ch, i >= MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS); // respatialize channel
- if (!ch->leftvol && !ch->rightvol)
- continue;
+
+ // respatialize channel
+ SND_Spatialize(ch, i >= MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS);
// try to combine static sounds with a previous channel of the same
// sound effect so we don't mix five torches every frame
if (i > MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS)
{
- // see if it can just use the last one
- if (combine && combine->sfx == ch->sfx)
- {
- combine->leftvol += ch->leftvol;
- combine->rightvol += ch->rightvol;
- ch->leftvol = ch->rightvol = 0;
- continue;
- }
- // search for one
- combine = channels+MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS;
- for (j=MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS ; j<i; j++, combine++)
- if (combine->sfx == ch->sfx)
+ // no need to merge silent channels
+ for (j = 0;j < SND_LISTENERS;j++)
+ if (ch->listener_volume[j])
break;
-
- if (j == total_channels)
+ if (j == SND_LISTENERS)
+ continue;
+ // if the last combine chosen isn't suitable, find a new one
+ if (!(combine && combine != ch && combine->sfx == ch->sfx))
+ {
+ // search for one
combine = NULL;
- else
+ for (j = MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS;j < i;j++)
+ {
+ if (channels[j].sfx == ch->sfx)
+ {
+ combine = channels + j;
+ break;
+ }
+ }
+ }
+ if (combine && combine != ch && combine->sfx == ch->sfx)
{
- if (combine != ch)
+ for (j = 0;j < SND_LISTENERS;j++)
{
- combine->leftvol += ch->leftvol;
- combine->rightvol += ch->rightvol;
- ch->leftvol = ch->rightvol = 0;
+ combine->listener_volume[j] += ch->listener_volume[j];
+ ch->listener_volume[j] = 0;
}
- continue;
}
}
}
total = 0;
ch = channels;
for (i=0 ; i<total_channels; i++, ch++)
- if (ch->sfx && (ch->leftvol || ch->rightvol) )
- total++;
+ {
+ if (ch->sfx)
+ {
+ for (j = 0;j < SND_LISTENERS;j++)
+ if (ch->listener_volume[j])
+ break;
+ if (j < SND_LISTENERS)
+ total++;
+ }
+ }
Con_Printf("----(%u)----\n", total);
}
static int oldsamplepos;
int fullsamples;
- fullsamples = shm->samples / shm->format.channels;
+ fullsamples = shm->sampleframes;
// it is possible to miscount buffers if it has wrapped twice between
// calls to S_Update. Oh well.
void S_Update_(void)
{
unsigned endtime;
- int samps;
if (!sound_started || (snd_blocked > 0))
return;
// mix ahead of current position
endtime = soundtime + _snd_mixahead.value * shm->format.speed;
- samps = shm->samples >> (shm->format.channels - 1);
- if (endtime > (unsigned int)(soundtime + samps))
- endtime = soundtime + samps;
+ endtime = min(endtime, (unsigned int)(soundtime + shm->sampleframes));
S_PaintChannels (endtime);
static void S_Play_Common(float fvol, float attenuation)
{
int i, ch_ind;
- char name[256];
+ char name[MAX_QPATH];
sfx_t *sfx;
i = 1;
typedef struct dma_s
{
snd_format_t format;
+ int sampleframes; // frames in buffer (frame = samples for all speakers)
int samples; // mono samples in buffer
int samplepos; // in mono samples
unsigned char *buffer;
int bufferlength; // used only by certain drivers
} dma_t;
+// maximum supported speakers constant
+#define SND_LISTENERS 8
+
typedef struct channel_s
{
+ int pad[8];
sfx_t *sfx; // sfx number
+ int pad2[8];
unsigned int flags; // cf CHANNELFLAG_* defines
int master_vol; // 0-255 master volume
- int leftvol; // 0-255 volume
- int rightvol; // 0-255 volume
+ short listener_volume[SND_LISTENERS]; // 0-255 volume per speaker
int end; // end time in global paintsamples
int lastptime; // last time this channel was painted
int pos; // sample position in sfx
typedef struct portable_samplepair_s
{
- int left;
- int right;
-} portable_samplepair_t;
+ int sample[SND_LISTENERS];
+} portable_sampleframe_t;
// LordHavoc: was 512, expanded to 2048
#define PAINTBUFFER_SIZE 2048
-portable_samplepair_t paintbuffer[PAINTBUFFER_SIZE];
+portable_sampleframe_t paintbuffer[PAINTBUFFER_SIZE];
// FIXME: this desyncs with the video too easily
extern qboolean cl_capturevideo_active;
extern void SCR_CaptureVideo_SoundFrame(unsigned char *bufstereo16le, size_t length, int rate);
-void S_CaptureAVISound(portable_samplepair_t *buf, size_t length)
+void S_CaptureAVISound(portable_sampleframe_t *buf, size_t length)
{
int n;
size_t i;
// write the sound buffer as little endian 16bit interleaved stereo
for(i = 0;i < length;i++)
{
- n = buf[i].left;
+ n = buf[i].sample[0];
n = bound(-32768, n, 32767);
out[i*4+0] = n & 0xFF;
out[i*4+1] = (n >> 8) & 0xFF;
- n = buf[i].right;
+ n = buf[i].sample[1];
n = bound(-32768, n, 32767);
out[i*4+2] = n & 0xFF;
out[i*4+3] = (n >> 8) & 0xFF;
void S_TransferPaintBuffer(int endtime)
{
void *pbuf;
+ int i;
+ portable_sampleframe_t *snd_p;
+ int lpaintedtime;
+ int snd_frames;
+ int val;
if ((pbuf = S_LockBuffer()))
{
- int i;
- int *snd_p;
- int lpaintedtime;
- int snd_linear_count;
- int val;
- snd_p = (int *) paintbuffer;
+ snd_p = paintbuffer;
lpaintedtime = paintedtime;
- if (shm->format.width == 2)
+ for (lpaintedtime = paintedtime;lpaintedtime < endtime;lpaintedtime += snd_frames)
{
- // 16bit
- short *snd_out;
- if (shm->format.channels == 2)
+ // handle recirculating buffer issues
+ i = lpaintedtime & (shm->sampleframes - 1);
+ snd_frames = shm->sampleframes - i;
+ if (snd_frames > endtime - lpaintedtime)
+ snd_frames = endtime - lpaintedtime;
+ if (shm->format.width == 2)
{
- // 16bit 2 channels (stereo)
- while (lpaintedtime < endtime)
+ // 16bit
+ short *snd_out = (short *) pbuf + i * shm->format.channels;
+ if (shm->format.channels == 8)
{
- // handle recirculating buffer issues
- i = lpaintedtime & ((shm->samples >> 1) - 1);
- snd_out = (short *) pbuf + (i << 1);
- snd_linear_count = (shm->samples >> 1) - i;
- if (snd_linear_count > endtime - lpaintedtime)
- snd_linear_count = endtime - lpaintedtime;
- snd_linear_count <<= 1;
+ // 7.1 surround
if (snd_swapstereo.value)
{
- for (i = 0;i < snd_linear_count;i += 2)
+ for (i = 0;i < snd_frames;i++, snd_p++)
{
- snd_out[i ] = bound(-32768, snd_p[i + 1], 32767);
- snd_out[i + 1] = bound(-32768, snd_p[i ], 32767);
+ *snd_out++ = bound(-32768, snd_p->sample[1], 32767);
+ *snd_out++ = bound(-32768, snd_p->sample[0], 32767);
+ *snd_out++ = bound(-32768, snd_p->sample[3], 32767);
+ *snd_out++ = bound(-32768, snd_p->sample[2], 32767);
+ *snd_out++ = bound(-32768, snd_p->sample[4], 32767);
+ *snd_out++ = bound(-32768, snd_p->sample[5], 32767);
+ *snd_out++ = bound(-32768, snd_p->sample[6], 32767);
+ *snd_out++ = bound(-32768, snd_p->sample[7], 32767);
}
}
else
{
- for (i = 0;i < snd_linear_count;i += 2)
+ for (i = 0;i < snd_frames;i++, snd_p++)
{
- snd_out[i ] = bound(-32768, snd_p[i ], 32767);
- snd_out[i + 1] = bound(-32768, snd_p[i + 1], 32767);
+ *snd_out++ = bound(-32768, snd_p->sample[0], 32767);
+ *snd_out++ = bound(-32768, snd_p->sample[1], 32767);
+ *snd_out++ = bound(-32768, snd_p->sample[2], 32767);
+ *snd_out++ = bound(-32768, snd_p->sample[3], 32767);
+ *snd_out++ = bound(-32768, snd_p->sample[4], 32767);
+ *snd_out++ = bound(-32768, snd_p->sample[5], 32767);
+ *snd_out++ = bound(-32768, snd_p->sample[6], 32767);
+ *snd_out++ = bound(-32768, snd_p->sample[7], 32767);
}
}
- snd_p += snd_linear_count;
- lpaintedtime += (snd_linear_count >> 1);
}
- }
- else
- {
- // 16bit 1 channel (mono)
- while (lpaintedtime < endtime)
+ else if (shm->format.channels == 6)
{
- // handle recirculating buffer issues
- i = lpaintedtime & (shm->samples - 1);
- snd_out = (short *) pbuf + i;
- snd_linear_count = shm->samples - i;
- if (snd_linear_count > endtime - lpaintedtime)
- snd_linear_count = endtime - lpaintedtime;
- for (i = 0;i < snd_linear_count;i++)
+ // 5.1 surround
+ if (snd_swapstereo.value)
{
- val = (snd_p[i * 2 + 0] + snd_p[i * 2 + 1]) >> 1;
- snd_out[i] = bound(-32768, val, 32767);
+ for (i = 0;i < snd_frames;i++, snd_p++)
+ {
+ *snd_out++ = bound(-32768, snd_p->sample[1], 32767);
+ *snd_out++ = bound(-32768, snd_p->sample[0], 32767);
+ *snd_out++ = bound(-32768, snd_p->sample[3], 32767);
+ *snd_out++ = bound(-32768, snd_p->sample[2], 32767);
+ *snd_out++ = bound(-32768, snd_p->sample[4], 32767);
+ *snd_out++ = bound(-32768, snd_p->sample[5], 32767);
+ }
+ }
+ else
+ {
+ for (i = 0;i < snd_frames;i++, snd_p++)
+ {
+ *snd_out++ = bound(-32768, snd_p->sample[0], 32767);
+ *snd_out++ = bound(-32768, snd_p->sample[1], 32767);
+ *snd_out++ = bound(-32768, snd_p->sample[2], 32767);
+ *snd_out++ = bound(-32768, snd_p->sample[3], 32767);
+ *snd_out++ = bound(-32768, snd_p->sample[4], 32767);
+ *snd_out++ = bound(-32768, snd_p->sample[5], 32767);
+ }
}
- snd_p += snd_linear_count << 1;
- lpaintedtime += snd_linear_count;
}
- }
- }
- else
- {
- // 8bit
- unsigned char *snd_out;
- if (shm->format.channels == 2)
- {
- // 8bit 2 channels (stereo)
- while (lpaintedtime < endtime)
+ else if (shm->format.channels == 4)
+ {
+ // 4.0 surround
+ if (snd_swapstereo.value)
+ {
+ for (i = 0;i < snd_frames;i++, snd_p++)
+ {
+ *snd_out++ = bound(-32768, snd_p->sample[1], 32767);
+ *snd_out++ = bound(-32768, snd_p->sample[0], 32767);
+ *snd_out++ = bound(-32768, snd_p->sample[3], 32767);
+ *snd_out++ = bound(-32768, snd_p->sample[2], 32767);
+ }
+ }
+ else
+ {
+ for (i = 0;i < snd_frames;i++, snd_p++)
+ {
+ *snd_out++ = bound(-32768, snd_p->sample[0], 32767);
+ *snd_out++ = bound(-32768, snd_p->sample[1], 32767);
+ *snd_out++ = bound(-32768, snd_p->sample[2], 32767);
+ *snd_out++ = bound(-32768, snd_p->sample[3], 32767);
+ }
+ }
+ }
+ else if (shm->format.channels == 2)
{
- // handle recirculating buffer issues
- i = lpaintedtime & ((shm->samples >> 1) - 1);
- snd_out = (unsigned char *) pbuf + (i << 1);
- snd_linear_count = (shm->samples >> 1) - i;
- if (snd_linear_count > endtime - lpaintedtime)
- snd_linear_count = endtime - lpaintedtime;
- snd_linear_count <<= 1;
+ // 2.0 stereo
if (snd_swapstereo.value)
{
- for (i = 0;i < snd_linear_count;i += 2)
+ for (i = 0;i < snd_frames;i++, snd_p++)
{
- val = (snd_p[i + 1] >> 8) + 128;
- snd_out[i ] = bound(0, val, 255);
- val = (snd_p[i ] >> 8) + 128;
- snd_out[i + 1] = bound(0, val, 255);
+ *snd_out++ = bound(-32768, snd_p->sample[1], 32767);
+ *snd_out++ = bound(-32768, snd_p->sample[0], 32767);
}
}
else
{
- for (i = 0;i < snd_linear_count;i += 2)
+ for (i = 0;i < snd_frames;i++, snd_p++)
{
- val = (snd_p[i ] >> 8) + 128;
- snd_out[i ] = bound(0, val, 255);
- val = (snd_p[i + 1] >> 8) + 128;
- snd_out[i + 1] = bound(0, val, 255);
+ *snd_out++ = bound(-32768, snd_p->sample[0], 32767);
+ *snd_out++ = bound(-32768, snd_p->sample[1], 32767);
}
}
- snd_p += snd_linear_count;
- lpaintedtime += (snd_linear_count >> 1);
+ }
+ else if (shm->format.channels == 1)
+ {
+ // 1.0 mono
+ for (i = 0;i < snd_frames;i++, snd_p++)
+ *snd_out++ = bound(-32768, (snd_p->sample[0] + snd_p->sample[1]) >> 1, 32767);
}
}
else
{
- // 8bit 1 channel (mono)
- while (lpaintedtime < endtime)
+ // 8bit
+ unsigned char *snd_out = (unsigned char *) pbuf + i * shm->format.channels;
+ if (shm->format.channels == 8)
+ {
+ // 7.1 surround
+ if (snd_swapstereo.value)
+ {
+ for (i = 0;i < snd_frames;i++, snd_p++)
+ {
+ val = (snd_p->sample[1] >> 8) + 128;*snd_out++ = bound(0, val, 255);
+ val = (snd_p->sample[0] >> 8) + 128;*snd_out++ = bound(0, val, 255);
+ val = (snd_p->sample[3] >> 8) + 128;*snd_out++ = bound(0, val, 255);
+ val = (snd_p->sample[2] >> 8) + 128;*snd_out++ = bound(0, val, 255);
+ val = (snd_p->sample[4] >> 8) + 128;*snd_out++ = bound(0, val, 255);
+ val = (snd_p->sample[5] >> 8) + 128;*snd_out++ = bound(0, val, 255);
+ val = (snd_p->sample[6] >> 8) + 128;*snd_out++ = bound(0, val, 255);
+ val = (snd_p->sample[7] >> 8) + 128;*snd_out++ = bound(0, val, 255);
+ }
+ }
+ else
+ {
+ for (i = 0;i < snd_frames;i++, snd_p++)
+ {
+ val = (snd_p->sample[0] >> 8) + 128;*snd_out++ = bound(0, val, 255);
+ val = (snd_p->sample[1] >> 8) + 128;*snd_out++ = bound(0, val, 255);
+ val = (snd_p->sample[2] >> 8) + 128;*snd_out++ = bound(0, val, 255);
+ val = (snd_p->sample[3] >> 8) + 128;*snd_out++ = bound(0, val, 255);
+ val = (snd_p->sample[4] >> 8) + 128;*snd_out++ = bound(0, val, 255);
+ val = (snd_p->sample[5] >> 8) + 128;*snd_out++ = bound(0, val, 255);
+ val = (snd_p->sample[6] >> 8) + 128;*snd_out++ = bound(0, val, 255);
+ val = (snd_p->sample[7] >> 8) + 128;*snd_out++ = bound(0, val, 255);
+ }
+ }
+ }
+ else if (shm->format.channels == 6)
+ {
+ // 5.1 surround
+ if (snd_swapstereo.value)
+ {
+ for (i = 0;i < snd_frames;i++, snd_p++)
+ {
+ val = (snd_p->sample[1] >> 8) + 128;*snd_out++ = bound(0, val, 255);
+ val = (snd_p->sample[0] >> 8) + 128;*snd_out++ = bound(0, val, 255);
+ val = (snd_p->sample[3] >> 8) + 128;*snd_out++ = bound(0, val, 255);
+ val = (snd_p->sample[2] >> 8) + 128;*snd_out++ = bound(0, val, 255);
+ val = (snd_p->sample[4] >> 8) + 128;*snd_out++ = bound(0, val, 255);
+ val = (snd_p->sample[5] >> 8) + 128;*snd_out++ = bound(0, val, 255);
+ }
+ }
+ else
+ {
+ for (i = 0;i < snd_frames;i++, snd_p++)
+ {
+ val = (snd_p->sample[0] >> 8) + 128;*snd_out++ = bound(0, val, 255);
+ val = (snd_p->sample[1] >> 8) + 128;*snd_out++ = bound(0, val, 255);
+ val = (snd_p->sample[2] >> 8) + 128;*snd_out++ = bound(0, val, 255);
+ val = (snd_p->sample[3] >> 8) + 128;*snd_out++ = bound(0, val, 255);
+ val = (snd_p->sample[4] >> 8) + 128;*snd_out++ = bound(0, val, 255);
+ val = (snd_p->sample[5] >> 8) + 128;*snd_out++ = bound(0, val, 255);
+ }
+ }
+ }
+ else if (shm->format.channels == 4)
+ {
+ // 4.0 surround
+ if (snd_swapstereo.value)
+ {
+ for (i = 0;i < snd_frames;i++, snd_p++)
+ {
+ val = (snd_p->sample[1] >> 8) + 128;*snd_out++ = bound(0, val, 255);
+ val = (snd_p->sample[0] >> 8) + 128;*snd_out++ = bound(0, val, 255);
+ val = (snd_p->sample[3] >> 8) + 128;*snd_out++ = bound(0, val, 255);
+ val = (snd_p->sample[2] >> 8) + 128;*snd_out++ = bound(0, val, 255);
+ }
+ }
+ else
+ {
+ for (i = 0;i < snd_frames;i++, snd_p++)
+ {
+ val = (snd_p->sample[0] >> 8) + 128;*snd_out++ = bound(0, val, 255);
+ val = (snd_p->sample[1] >> 8) + 128;*snd_out++ = bound(0, val, 255);
+ val = (snd_p->sample[2] >> 8) + 128;*snd_out++ = bound(0, val, 255);
+ val = (snd_p->sample[3] >> 8) + 128;*snd_out++ = bound(0, val, 255);
+ }
+ }
+ }
+ else if (shm->format.channels == 2)
{
- // handle recirculating buffer issues
- i = lpaintedtime & (shm->samples - 1);
- snd_out = (unsigned char *) pbuf + i;
- snd_linear_count = shm->samples - i;
- if (snd_linear_count > endtime - lpaintedtime)
- snd_linear_count = endtime - lpaintedtime;
- for (i = 0;i < snd_linear_count;i++)
+ // 2.0 stereo
+ if (snd_swapstereo.value)
{
- val = ((snd_p[i * 2] + snd_p[i * 2 + 1]) >> 9) + 128;
- snd_out[i ] = bound(0, val, 255);
+ for (i = 0;i < snd_frames;i++, snd_p++)
+ {
+ val = (snd_p->sample[1] >> 8) + 128;*snd_out++ = bound(0, val, 255);
+ val = (snd_p->sample[0] >> 8) + 128;*snd_out++ = bound(0, val, 255);
+ }
}
- snd_p += snd_linear_count << 1;
- lpaintedtime += snd_linear_count;
+ else
+ {
+ for (i = 0;i < snd_frames;i++, snd_p++)
+ {
+ val = (snd_p->sample[0] >> 8) + 128;*snd_out++ = bound(0, val, 255);
+ val = (snd_p->sample[1] >> 8) + 128;*snd_out++ = bound(0, val, 255);
+ }
+ }
+ }
+ else if (shm->format.channels == 1)
+ {
+ // 1.0 mono
+ for (i = 0;i < snd_frames;i++, snd_p++)
+ val = ((snd_p->sample[0]+snd_p->sample[1]) >> 9) + 128;*snd_out++ = bound(0, val, 255);
}
}
}
-
S_UnlockBuffer();
}
}
===============================================================================
*/
-qboolean SND_PaintChannelFrom8 (channel_t *ch, int endtime);
-qboolean SND_PaintChannelFrom16 (channel_t *ch, int endtime);
+qboolean SND_PaintChannel (channel_t *ch, int endtime);
void S_PaintChannels(int endtime)
{
- unsigned int i;
+ unsigned int i, j;
int end;
channel_t *ch;
sfx_t *sfx;
sfx = ch->sfx;
if (!sfx)
continue;
- if (!ch->leftvol && !ch->rightvol)
+ if (sfx->fetcher)
+ j++;
+ for (j = 0;j < SND_LISTENERS;j++)
+ if (ch->listener_volume[j])
+ break;
+ if (j == SND_LISTENERS)
continue;
if (!S_LoadSound (sfx, true))
continue;
if (count > 0)
{
- if (ch->leftvol > 255)
- ch->leftvol = 255;
- if (ch->rightvol > 255)
- ch->rightvol = 255;
+ for (j = 0;j < SND_LISTENERS;j++)
+ ch->listener_volume[j] = bound(0, ch->listener_volume[j], 255);
- if (sfx->format.width == 1)
- stop_paint = !SND_PaintChannelFrom8 (ch, count);
- else
- stop_paint = !SND_PaintChannelFrom16 (ch, count);
+ stop_paint = !SND_PaintChannel (ch, count);
if (!stop_paint)
{
}
-// TODO: Try to merge SND_PaintChannelFrom8 and SND_PaintChannelFrom16
-qboolean SND_PaintChannelFrom8 (channel_t *ch, int count)
+qboolean SND_PaintChannel (channel_t *ch, int count)
{
- int snd_vol, leftvol, rightvol;
- const signed char *sfx;
+ int snd_vol, vol[SND_LISTENERS];
const sfxbuffer_t *sb;
int i;
else
snd_vol = volume.value * 256;
- leftvol = ch->leftvol * snd_vol;
- rightvol = ch->rightvol * snd_vol;
+ for (i = 0;i < SND_LISTENERS;i++)
+ vol[i] = ch->listener_volume[i] * snd_vol;
sb = ch->sfx->fetcher->getsb (ch, ch->pos, count);
if (sb == NULL)
return false;
- // Stereo sound support
- if (ch->sfx->format.channels == 2)
+#if SND_LISTENERS != 8
+#error this code only supports up to 8 channels, update it
+#endif
+
+ if (ch->sfx->format.width == 1)
{
- sfx = (signed char *)sb->data + (ch->pos - sb->offset) * 2;
- for (i = 0;i < count;i++)
+ const signed char *sfx = (signed char *)sb->data + (ch->pos - sb->offset) * ch->sfx->format.channels;
+ // Stereo sound support
+ if (ch->sfx->format.channels == 2)
{
- paintbuffer[i].left += (*sfx++ * leftvol) >> 8;
- paintbuffer[i].right += (*sfx++ * rightvol) >> 8;
+ if (vol[6] + vol[7] > 0)
+ {
+ for (i = 0;i < count;i++)
+ {
+ paintbuffer[i].sample[0] += (sfx[0] * vol[0]) >> 8;
+ paintbuffer[i].sample[1] += (sfx[1] * vol[1]) >> 8;
+ paintbuffer[i].sample[2] += (sfx[0] * vol[2]) >> 8;
+ paintbuffer[i].sample[3] += (sfx[1] * vol[3]) >> 8;
+ paintbuffer[i].sample[4] += ((sfx[0]+sfx[1]) * vol[4]) >> 9;
+ paintbuffer[i].sample[5] += ((sfx[0]+sfx[1]) * vol[5]) >> 9;
+ paintbuffer[i].sample[6] += (sfx[0] * vol[6]) >> 8;
+ paintbuffer[i].sample[7] += (sfx[1] * vol[7]) >> 8;
+ sfx += 2;
+ }
+ }
+ else if (vol[4] + vol[5] > 0)
+ {
+ for (i = 0;i < count;i++)
+ {
+ paintbuffer[i].sample[0] += (sfx[0] * vol[0]) >> 8;
+ paintbuffer[i].sample[1] += (sfx[1] * vol[1]) >> 8;
+ paintbuffer[i].sample[2] += (sfx[0] * vol[2]) >> 8;
+ paintbuffer[i].sample[3] += (sfx[1] * vol[3]) >> 8;
+ paintbuffer[i].sample[4] += ((sfx[0]+sfx[1]) * vol[4]) >> 9;
+ paintbuffer[i].sample[5] += ((sfx[0]+sfx[1]) * vol[5]) >> 9;
+ sfx += 2;
+ }
+ }
+ else if (vol[2] + vol[3] > 0)
+ {
+ for (i = 0;i < count;i++)
+ {
+ paintbuffer[i].sample[0] += (sfx[0] * vol[0]) >> 8;
+ paintbuffer[i].sample[1] += (sfx[1] * vol[1]) >> 8;
+ paintbuffer[i].sample[2] += (sfx[0] * vol[2]) >> 8;
+ paintbuffer[i].sample[3] += (sfx[1] * vol[3]) >> 8;
+ sfx += 2;
+ }
+ }
+ else if (vol[0] + vol[1] > 0)
+ {
+ for (i = 0;i < count;i++)
+ {
+ paintbuffer[i].sample[0] += (sfx[0] * vol[0]) >> 8;
+ paintbuffer[i].sample[1] += (sfx[1] * vol[1]) >> 8;
+ sfx += 2;
+ }
+ }
}
- }
- else
- {
- sfx = (signed char *)sb->data + ch->pos - sb->offset;
- for (i = 0;i < count;i++)
+ else if (ch->sfx->format.channels == 1)
{
- paintbuffer[i].left += (*sfx * leftvol) >> 8;
- paintbuffer[i].right += (*sfx++ * rightvol) >> 8;
+ if (vol[6] + vol[7] > 0)
+ {
+ for (i = 0;i < count;i++)
+ {
+ paintbuffer[i].sample[0] += (sfx[0] * vol[0]) >> 8;
+ paintbuffer[i].sample[1] += (sfx[0] * vol[1]) >> 8;
+ paintbuffer[i].sample[2] += (sfx[0] * vol[2]) >> 8;
+ paintbuffer[i].sample[3] += (sfx[0] * vol[3]) >> 8;
+ paintbuffer[i].sample[4] += (sfx[0] * vol[4]) >> 8;
+ paintbuffer[i].sample[5] += (sfx[0] * vol[5]) >> 8;
+ paintbuffer[i].sample[6] += (sfx[0] * vol[6]) >> 8;
+ paintbuffer[i].sample[7] += (sfx[0] * vol[7]) >> 8;
+ sfx += 1;
+ }
+ }
+ else if (vol[4] + vol[5] > 0)
+ {
+ for (i = 0;i < count;i++)
+ {
+ paintbuffer[i].sample[0] += (sfx[0] * vol[0]) >> 8;
+ paintbuffer[i].sample[1] += (sfx[0] * vol[1]) >> 8;
+ paintbuffer[i].sample[2] += (sfx[0] * vol[2]) >> 8;
+ paintbuffer[i].sample[3] += (sfx[0] * vol[3]) >> 8;
+ paintbuffer[i].sample[4] += (sfx[0] * vol[4]) >> 8;
+ paintbuffer[i].sample[5] += (sfx[0] * vol[5]) >> 8;
+ sfx += 1;
+ }
+ }
+ else if (vol[2] + vol[3] > 0)
+ {
+ for (i = 0;i < count;i++)
+ {
+ paintbuffer[i].sample[0] += (sfx[0] * vol[0]) >> 8;
+ paintbuffer[i].sample[1] += (sfx[0] * vol[1]) >> 8;
+ paintbuffer[i].sample[2] += (sfx[0] * vol[2]) >> 8;
+ paintbuffer[i].sample[3] += (sfx[0] * vol[3]) >> 8;
+ sfx += 1;
+ }
+ }
+ else if (vol[0] + vol[1] > 0)
+ {
+ for (i = 0;i < count;i++)
+ {
+ paintbuffer[i].sample[0] += (sfx[0] * vol[0]) >> 8;
+ paintbuffer[i].sample[1] += (sfx[0] * vol[1]) >> 8;
+ sfx += 1;
+ }
+ }
}
+ else
+ return true; // unsupported number of channels in sound
}
- ch->pos += count;
- return true;
-}
-
-qboolean SND_PaintChannelFrom16 (channel_t *ch, int count)
-{
- int snd_vol, leftvol, rightvol;
- signed short *sfx;
- const sfxbuffer_t *sb;
- int i;
-
- // If this channel manages its own volume
- if (ch->flags & CHANNELFLAG_FULLVOLUME)
- snd_vol = 256;
- else
- snd_vol = volume.value * 256;
-
- leftvol = ch->leftvol * snd_vol;
- rightvol = ch->rightvol * snd_vol;
-
- sb = ch->sfx->fetcher->getsb (ch, ch->pos, count);
- if (sb == NULL)
- return false;
-
- // Stereo sound support
- if (ch->sfx->format.channels == 2)
+ else if (ch->sfx->format.width == 2)
{
- sfx = (signed short *)sb->data + (ch->pos - sb->offset) * 2;
-
- for (i=0 ; i<count ; i++)
+ const signed short *sfx = (signed short *)sb->data + (ch->pos - sb->offset) * ch->sfx->format.channels;
+ // Stereo sound support
+ if (ch->sfx->format.channels == 2)
{
- paintbuffer[i].left += (*sfx++ * leftvol) >> 16;
- paintbuffer[i].right += (*sfx++ * rightvol) >> 16;
+ if (vol[6] + vol[7] > 0)
+ {
+ for (i = 0;i < count;i++)
+ {
+ paintbuffer[i].sample[0] += (sfx[0] * vol[0]) >> 16;
+ paintbuffer[i].sample[1] += (sfx[1] * vol[1]) >> 16;
+ paintbuffer[i].sample[2] += (sfx[0] * vol[2]) >> 16;
+ paintbuffer[i].sample[3] += (sfx[1] * vol[3]) >> 16;
+ paintbuffer[i].sample[4] += ((sfx[0]+sfx[1]) * vol[4]) >> 17;
+ paintbuffer[i].sample[5] += ((sfx[0]+sfx[1]) * vol[5]) >> 17;
+ paintbuffer[i].sample[6] += (sfx[0] * vol[6]) >> 16;
+ paintbuffer[i].sample[7] += (sfx[1] * vol[7]) >> 16;
+ sfx += 2;
+ }
+ }
+ else if (vol[4] + vol[5] > 0)
+ {
+ for (i = 0;i < count;i++)
+ {
+ paintbuffer[i].sample[0] += (sfx[0] * vol[0]) >> 16;
+ paintbuffer[i].sample[1] += (sfx[1] * vol[1]) >> 16;
+ paintbuffer[i].sample[2] += (sfx[0] * vol[2]) >> 16;
+ paintbuffer[i].sample[3] += (sfx[1] * vol[3]) >> 16;
+ paintbuffer[i].sample[4] += ((sfx[0]+sfx[1]) * vol[4]) >> 17;
+ paintbuffer[i].sample[5] += ((sfx[0]+sfx[1]) * vol[5]) >> 17;
+ sfx += 2;
+ }
+ }
+ else if (vol[2] + vol[3] > 0)
+ {
+ for (i = 0;i < count;i++)
+ {
+ paintbuffer[i].sample[0] += (sfx[0] * vol[0]) >> 16;
+ paintbuffer[i].sample[1] += (sfx[1] * vol[1]) >> 16;
+ paintbuffer[i].sample[2] += (sfx[0] * vol[2]) >> 16;
+ paintbuffer[i].sample[3] += (sfx[1] * vol[3]) >> 16;
+ sfx += 2;
+ }
+ }
+ else if (vol[0] + vol[1] > 0)
+ {
+ for (i = 0;i < count;i++)
+ {
+ paintbuffer[i].sample[0] += (sfx[0] * vol[0]) >> 16;
+ paintbuffer[i].sample[1] += (sfx[1] * vol[1]) >> 16;
+ sfx += 2;
+ }
+ }
}
- }
- else
- {
- sfx = (signed short *)sb->data + ch->pos - sb->offset;
-
- for (i=0 ; i<count ; i++)
+ else if (ch->sfx->format.channels == 1)
{
- paintbuffer[i].left += (*sfx * leftvol) >> 16;
- paintbuffer[i].right += (*sfx++ * rightvol) >> 16;
+ if (vol[6] + vol[7] > 0)
+ {
+ for (i = 0;i < count;i++)
+ {
+ paintbuffer[i].sample[0] += (sfx[0] * vol[0]) >> 16;
+ paintbuffer[i].sample[1] += (sfx[0] * vol[1]) >> 16;
+ paintbuffer[i].sample[2] += (sfx[0] * vol[2]) >> 16;
+ paintbuffer[i].sample[3] += (sfx[0] * vol[3]) >> 16;
+ paintbuffer[i].sample[4] += (sfx[0] * vol[4]) >> 16;
+ paintbuffer[i].sample[5] += (sfx[0] * vol[5]) >> 16;
+ paintbuffer[i].sample[6] += (sfx[0] * vol[6]) >> 16;
+ paintbuffer[i].sample[7] += (sfx[0] * vol[7]) >> 16;
+ sfx += 1;
+ }
+ }
+ else if (vol[4] + vol[5] > 0)
+ {
+ for (i = 0;i < count;i++)
+ {
+ paintbuffer[i].sample[0] += (sfx[0] * vol[0]) >> 16;
+ paintbuffer[i].sample[1] += (sfx[0] * vol[1]) >> 16;
+ paintbuffer[i].sample[2] += (sfx[0] * vol[2]) >> 16;
+ paintbuffer[i].sample[3] += (sfx[0] * vol[3]) >> 16;
+ paintbuffer[i].sample[4] += (sfx[0] * vol[4]) >> 16;
+ paintbuffer[i].sample[5] += (sfx[0] * vol[5]) >> 16;
+ sfx += 1;
+ }
+ }
+ else if (vol[2] + vol[3] > 0)
+ {
+ for (i = 0;i < count;i++)
+ {
+ paintbuffer[i].sample[0] += (sfx[0] * vol[0]) >> 16;
+ paintbuffer[i].sample[1] += (sfx[0] * vol[1]) >> 16;
+ paintbuffer[i].sample[2] += (sfx[0] * vol[2]) >> 16;
+ paintbuffer[i].sample[3] += (sfx[0] * vol[3]) >> 16;
+ sfx += 1;
+ }
+ }
+ else if (vol[0] + vol[1] > 0)
+ {
+ for (i = 0;i < count;i++)
+ {
+ paintbuffer[i].sample[0] += (sfx[0] * vol[0]) >> 16;
+ paintbuffer[i].sample[1] += (sfx[0] * vol[1]) >> 16;
+ sfx += 1;
+ }
+ }
}
+ else
+ return true; // unsupported number of channels in sound
}
-
ch->pos += count;
return true;
}
return 0;
}
- shm->samples = info.fragstotal * info.fragsize / shm->format.width;
+ shm->sampleframes = info.fragstotal * info.fragsize / shm->format.width / shm->format.channels;
+ shm->samples = shm->sampleframes * shm->format.channels;
// memory map the dma buffer
shm->bufferlength = info.fragstotal * info.fragsize;
/*
Info:
-One SDL sample consists of x channel samples
-The mixer supposes that the driver has one channel entry/sample though it has x channels/sample
-like the SDL
+SDL samples are really frames (full set of samples for all speakers)
*/
-#define AUDIO_SDL_SAMPLES 4096
+#define AUDIO_SDL_SAMPLEFRAMES 4096
#define AUDIO_LOCALFACTOR 4
typedef struct AudioState_s
qboolean SNDDMA_Init(void)
{
- SDL_AudioSpec spec;
+ SDL_AudioSpec wantspec;
int i;
+ int channels;
// Init the SDL Audio subsystem
if( SDL_InitSubSystem( SDL_INIT_AUDIO ) ) {
return false;
}
- // Init the shm structure
- memset( (void*) shm, 0, sizeof(*shm) );
-
- shm->format.channels = 2; //stereo
- shm->format.width = 2;
-
-// COMMANDLINEOPTION: SDL Sound: -sndspeed <hz> chooses 44100 hz, 22100 hz, or 11025 hz sound output rate
- i = COM_CheckParm( "-sndspeed" );
- if( i && i != ( com_argc - 1 ) )
- shm->format.speed = atoi( com_argv[ i+1 ] );
- else
- shm->format.speed = 44100;
-
- shm->samplepos = 0;
- shm->samples = AUDIO_SDL_SAMPLES * AUDIO_LOCALFACTOR;
- shm->bufferlength = shm->samples * shm->format.width;
- shm->buffer = (unsigned char *)Mem_Alloc( snd_mempool, shm->bufferlength );
-
- // Init the as structure
- as.buffer = shm->buffer;
- as.width = shm->format.width;
- as.pos = 0;
- as.size = shm->bufferlength;
-
- // Init the SDL Audio subsystem
- spec.callback = Buffer_Callback;
- spec.channels = shm->format.channels;
- spec.format = AUDIO_S16SYS;
- spec.freq = shm->format.speed;
- spec.userdata = NULL;
- spec.samples = AUDIO_SDL_SAMPLES;
-
- if( SDL_OpenAudio( &spec, NULL ) ) {
+ for (channels = 8;channels >= 2;channels -= 2)
+ {
+ // Init the SDL Audio subsystem
+ wantspec.callback = Buffer_Callback;
+ wantspec.userdata = NULL;
+ wantspec.freq = 44100;
+ // COMMANDLINEOPTION: SDL Sound: -sndspeed <hz> chooses sound output rate (try values such as 44100, 48000, 22050, 11025 (quake), 24000, 32000, 96000, 192000, etc)
+ i = COM_CheckParm( "-sndspeed" );
+ if( i && i != ( com_argc - 1 ) )
+ wantspec.freq = atoi( com_argv[ i+1 ] );
+ wantspec.format = AUDIO_S16SYS;
+ wantspec.channels = channels;
+ wantspec.samples = AUDIO_SDL_SAMPLEFRAMES;
+
+ if( SDL_OpenAudio( &wantspec, NULL ) )
+ {
+ Con_Printf("%s\n", SDL_GetError());
+ continue;
+ }
+
+ // Init the shm structure
+ memset( (void*) shm, 0, sizeof(*shm) );
+ shm->format.channels = wantspec.channels;
+ shm->format.width = 2;
+ shm->format.speed = wantspec.freq;
+
+ shm->samplepos = 0;
+ shm->sampleframes = wantspec.samples * AUDIO_LOCALFACTOR;
+ shm->samples = shm->sampleframes * shm->format.channels;
+ shm->bufferlength = shm->samples * shm->format.width;
+ shm->buffer = (unsigned char *)Mem_Alloc( snd_mempool, shm->bufferlength );
+
+ // Init the as structure
+ as.buffer = shm->buffer;
+ as.width = shm->format.width;
+ as.pos = 0;
+ as.size = shm->bufferlength;
+ break;
+ }
+ if (channels < 2)
+ {
Con_Print( "Failed to open the audio device!\n" );
Con_DPrintf(
"Audio Specification:\n"
"\tChannels : %i\n"
"\tFormat : %x\n"
"\tFrequency : %i\n"
- "\tBuffersize: %i Bytes(%i Samples)\n",
- spec.channels, spec.format, spec.freq, shm->bufferlength , spec.samples );
- Mem_Free( shm->buffer );
+ "\tSamples : %i\n",
+ wantspec.channels, wantspec.format, wantspec.freq, wantspec.samples );
return false;
}
pDSBuf->lpVtbl->Play(pDSBuf, 0, 0, DSBPLAY_LOOPING);
shm->samples = gSndBufSize / shm->format.width;
+ shm->sampleframes = shm->samples / shm->format.channels;
shm->samplepos = 0;
shm->buffer = (unsigned char *) lpData;
}
shm->samples = gSndBufSize / shm->format.width;
+ shm->sampleframes = shm->samples / shm->format.channels;
shm->samplepos = 0;
shm->buffer = (unsigned char *) lpData;