implemented 7.1 audio, only works with SDL (attempted ALSA support but ALSA doesn...
authorhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Wed, 23 Nov 2005 03:00:34 +0000 (03:00 +0000)
committerhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Wed, 23 Nov 2005 03:00:34 +0000 (03:00 +0000)
git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@5818 d7cf8633-e32d-0410-b094-e92efae38249

snd_alsa.c
snd_bsd.c
snd_main.c
snd_main.h
snd_mix.c
snd_oss.c
snd_sdl.c
snd_win.c

index 95310d8..4328a60 100644 (file)
@@ -39,232 +39,177 @@ static snd_pcm_t   *pcm;
 
 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;
 }
 
@@ -272,7 +217,7 @@ int SNDDMA_GetDMAPos (void)
 {
        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;
index caa7ee0..ef22f5b 100644 (file)
--- a/snd_bsd.c
+++ b/snd_bsd.c
@@ -111,7 +111,8 @@ qboolean SNDDMA_Init (void)
                                (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;
 
index 7a39a48..0708a15 100644 (file)
@@ -24,6 +24,27 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 #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);
@@ -42,12 +63,13 @@ unsigned int total_channels;
 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;
 
@@ -98,7 +120,8 @@ void S_SoundInfo_f(void)
                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);
@@ -122,9 +145,10 @@ void S_Startup(void)
                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
        {
@@ -177,6 +201,7 @@ void S_Init(void)
        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"))
@@ -459,22 +484,36 @@ channel_t *SND_PickChannel(int entnum, int entchannel)
        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)
                {
@@ -500,48 +539,54 @@ Spatializes a channel
 */
 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);
 }
 
 
@@ -777,15 +822,15 @@ S_UpdateAmbientSounds
 */
 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++)
@@ -794,7 +839,7 @@ void S_UpdateAmbientSounds (void)
                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;
 
@@ -812,10 +857,84 @@ void S_UpdateAmbientSounds (void)
                                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},
+               }
+       }
+};
 
 /*
 ============
@@ -828,13 +947,27 @@ void S_Update(const matrix4x4_t *listenermatrix)
 {
        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 ();
 
@@ -846,39 +979,41 @@ void S_Update(const matrix4x4_t *listenermatrix)
        {
                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;
                        }
                }
        }
@@ -891,8 +1026,16 @@ void S_Update(const matrix4x4_t *listenermatrix)
                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);
        }
@@ -907,7 +1050,7 @@ void GetSoundtime(void)
        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.
@@ -940,7 +1083,6 @@ void S_ExtraUpdate (void)
 void S_Update_(void)
 {
        unsigned        endtime;
-       int                             samps;
 
        if (!sound_started || (snd_blocked > 0))
                return;
@@ -954,9 +1096,7 @@ void S_Update_(void)
 
        // 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);
 
@@ -974,7 +1114,7 @@ console functions
 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;
index fbf2f3e..ec097d2 100644 (file)
@@ -67,19 +67,24 @@ struct sfx_s
 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
index d2329f4..f4a857d 100644 (file)
--- a/snd_mix.c
+++ b/snd_mix.c
@@ -24,18 +24,17 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
 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;
@@ -45,11 +44,11 @@ void S_CaptureAVISound(portable_samplepair_t *buf, size_t length)
        // 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;
@@ -61,134 +60,253 @@ void S_CaptureAVISound(portable_samplepair_t *buf, size_t length)
 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();
        }
 }
@@ -202,12 +320,11 @@ CHANNEL MIXING
 ===============================================================================
 */
 
-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;
@@ -230,7 +347,12 @@ void S_PaintChannels(int endtime)
                        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;
@@ -283,15 +405,10 @@ void S_PaintChannels(int endtime)
 
                                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)
                                        {
@@ -331,11 +448,9 @@ void S_PaintChannels(int endtime)
 }
 
 
-// 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;
 
@@ -345,78 +460,235 @@ qboolean SND_PaintChannelFrom8 (channel_t *ch, int count)
        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;
 }
index eef8e62..b150320 100644 (file)
--- a/snd_oss.c
+++ b/snd_oss.c
@@ -189,7 +189,8 @@ qboolean SNDDMA_Init(void)
                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;
index dbeb3ce..1b9ef7d 100644 (file)
--- a/snd_sdl.c
+++ b/snd_sdl.c
@@ -22,12 +22,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
 /*
 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
@@ -81,8 +79,9 @@ Returns false if nothing is found.
 
 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 ) ) {
@@ -90,48 +89,55 @@ qboolean SNDDMA_Init(void)
                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;
        }
 
index 2752446..0f62112 100644 (file)
--- a/snd_win.c
+++ b/snd_win.c
@@ -397,6 +397,7 @@ sndinitstat SNDDMA_InitDirect (void)
        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;
 
@@ -527,6 +528,7 @@ qboolean SNDDMA_InitWav (void)
        }
 
        shm->samples = gSndBufSize / shm->format.width;
+       shm->sampleframes = shm->samples / shm->format.channels;
        shm->samplepos = 0;
        shm->buffer = (unsigned char *) lpData;