Ogg vorbis streaming support; the code decides whether it will cache or stream the...
authormolivier <molivier@d7cf8633-e32d-0410-b094-e92efae38249>
Tue, 23 Mar 2004 08:28:28 +0000 (08:28 +0000)
committermolivier <molivier@d7cf8633-e32d-0410-b094-e92efae38249>
Tue, 23 Mar 2004 08:28:28 +0000 (08:28 +0000)
git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@4052 d7cf8633-e32d-0410-b094-e92efae38249

snd_bsd.c
snd_dma.c
snd_mem.c
snd_mix.c
snd_ogg.c
snd_ogg.h
snd_oss.c
snd_win.c
sound.h

index 1c39404..5735013 100644 (file)
--- a/snd_bsd.c
+++ b/snd_bsd.c
@@ -30,7 +30,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 #include "quakedef.h"
 
 
-static const int tryrates[] = {44100, 22051, 11025, 8000};
+static const int tryrates[] = {44100, 22050, 11025, 8000};
 
 static int audio_fd = -1;
 static qboolean snd_inited = false;
@@ -61,16 +61,16 @@ qboolean SNDDMA_Init (void)
        // Look for an appropriate sound format
        // TODO: we should also test mono/stereo and bits
        // TODO: support "-sndspeed", "-sndbits", "-sndmono" and "-sndstereo"
-       shm->channels = 2;
-       shm->samplebits = 16;
+       shm->format.channels = 2;
+       shm->format.width = 2;
        for (i = 0; i < sizeof (tryrates) / sizeof (tryrates[0]); i++)
        {
-               shm->speed = tryrates[i];
+               shm->format.speed = tryrates[i];
 
                AUDIO_INITINFO (&info);
-               info.play.sample_rate = shm->speed;
-               info.play.channels = shm->channels;
-               info.play.precision = shm->samplebits;
+               info.play.sample_rate = shm->format.speed;
+               info.play.channels = shm->format.channels;
+               info.play.precision = shm->format.width * 8;
 // We only handle sound cards of the same endianess than the CPU
 #if BYTE_ORDER == BIG_ENDIAN
                info.play.encoding = AUDIO_ENCODING_SLINEAR_BE;
@@ -93,7 +93,7 @@ qboolean SNDDMA_Init (void)
                                (info.play.channels == 2) ? "stereo" : "mono",
                                info.play.sample_rate);
 
-       shm->samples = sizeof (dma_buffer) / (shm->samplebits / 8);
+       shm->samples = sizeof (dma_buffer) / shm->format.width;
        shm->samplepos = 0;
        shm->buffer = dma_buffer;
 
@@ -115,7 +115,7 @@ int SNDDMA_GetDMAPos (void)
                return 0;
        }
 
-       return ((info.play.samples * shm->channels) % shm->samples);
+       return ((info.play.samples * shm->format.channels) % shm->samples);
 }
 
 void SNDDMA_Shutdown (void)
@@ -150,7 +150,7 @@ void SNDDMA_Submit (void)
        if (paintedtime < wbufp)
                wbufp = 0; // reset
 
-       bsize = shm->channels * (shm->samplebits / 8);
+       bsize = shm->format.channels * shm->format.width;
        bytes = (paintedtime - wbufp) * bsize;
 
        if (!bytes)
index b55c553..48bbaf9 100644 (file)
--- a/snd_dma.c
+++ b/snd_dma.c
@@ -45,11 +45,12 @@ void S_StopAllSoundsC(void);
 // =======================================================================
 
 channel_t channels[MAX_CHANNELS];
-int total_channels;
+unsigned int total_channels;
 
 int snd_blocked = 0;
 static qboolean snd_ambient = 1;
 cvar_t snd_initialized = { CVAR_READONLY, "snd_initialized", "0"};
+cvar_t snd_streaming = { CVAR_SAVE, "snd_streaming", "1"};
 
 // pointer should go away
 volatile dma_t *shm = 0;
@@ -126,13 +127,13 @@ void S_SoundInfo_f(void)
                return;
        }
 
-       Con_Printf("%5d stereo\n", shm->channels - 1);
+       Con_Printf("%5d stereo\n", shm->format.channels - 1);
        Con_Printf("%5d samples\n", shm->samples);
        Con_Printf("%5d samplepos\n", shm->samplepos);
-       Con_Printf("%5d samplebits\n", shm->samplebits);
-       Con_Printf("%5d speed\n", shm->speed);
+       Con_Printf("%5d samplebits\n", shm->format.width * 8);
+       Con_Printf("%5d speed\n", shm->format.speed);
        Con_Printf("0x%x dma buffer\n", shm->buffer);
-       Con_Printf("%5d total_channels\n", total_channels);
+       Con_Printf("%5u total_channels\n", total_channels);
 }
 
 void S_UnloadSounds(void)
@@ -161,12 +162,12 @@ void S_Startup(void)
 
        if (fakedma)
        {
-               shm->samplebits = 16;
-               shm->speed = 22050;
-               shm->channels = 2;
+               shm->format.width = 2;
+               shm->format.speed = 22050;
+               shm->format.channels = 2;
                shm->samples = 32768;
                shm->samplepos = 0;
-               shm->buffer = Mem_Alloc(snd_mempool, shm->channels * shm->samples * (shm->samplebits / 8));
+               shm->buffer = Mem_Alloc(snd_mempool, shm->format.channels * shm->samples * shm->format.width);
        }
        else
        {
@@ -181,7 +182,7 @@ void S_Startup(void)
 
        sound_started = 1;
 
-       Con_DPrintf("Sound sampling rate: %i\n", shm->speed);
+       Con_DPrintf("Sound sampling rate: %i\n", shm->format.speed);
 
        //S_LoadSounds();
 
@@ -244,6 +245,7 @@ void S_Init(void)
        Cvar_RegisterVariable(&nosound);
        Cvar_RegisterVariable(&snd_precache);
        Cvar_RegisterVariable(&snd_initialized);
+       Cvar_RegisterVariable(&snd_streaming);
        Cvar_RegisterVariable(&bgmbuffer);
        Cvar_RegisterVariable(&ambient_level);
        Cvar_RegisterVariable(&ambient_fade);
@@ -517,12 +519,11 @@ void SND_Spatialize(channel_t *ch, int isstatic)
 void S_StartSound(int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float fvol, float attenuation)
 {
        channel_t *target_chan, *check;
-       sfxcache_t      *sc;
        int             vol;
        int             ch_idx;
-       int             skip;
+       size_t  skip;
 
-       if (!sound_started || !sfx || !sfx->sfxcache || nosound.integer)
+       if (!sound_started || !sfx || !sfx->fetcher || nosound.integer)
                return;
 
        vol = fvol*255;
@@ -545,9 +546,8 @@ void S_StartSound(int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float f
        //if (!target_chan->leftvol && !target_chan->rightvol)
        //      return;         // not audible at all
 
-// new channel
-       sc = S_LoadSound (sfx, true);
-       if (!sc)
+       // new channel
+       if (!S_LoadSound (sfx, true))
        {
                target_chan->sfx = NULL;
                return;         // couldn't load the sound's data
@@ -555,7 +555,7 @@ void S_StartSound(int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float f
 
        target_chan->sfx = sfx;
        target_chan->pos = 0.0;
-       target_chan->end = paintedtime + sc->length;
+       target_chan->end = paintedtime + sfx->total_length;
 
 // if an identical sound has also been started this frame, offset the pos
 // a bit to keep it from just making the first one louder
@@ -567,9 +567,9 @@ void S_StartSound(int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float f
                if (check->sfx == sfx && !check->pos)
                {
                        // LordHavoc: fixed skip calculations
-                       skip = 0.1 * sc->speed;
-                       if (skip > sc->length)
-                               skip = sc->length;
+                       skip = 0.1 * sfx->format.speed;
+                       if (skip > sfx->total_length)
+                               skip = sfx->total_length;
                        if (skip > 0)
                                skip = rand() % skip;
                        target_chan->pos += skip;
@@ -616,7 +616,7 @@ void S_ClearBuffer(void)
        if (!sound_started || !shm)
                return;
 
-       if (shm->samplebits == 8)
+       if (shm->format.width == 1)
                clear = 0x80;
        else
                clear = 0;
@@ -648,7 +648,7 @@ void S_ClearBuffer(void)
                        }
                }
 
-               memset(pData, clear, shm->samples * shm->samplebits/8);
+               memset(pData, clear, shm->samples * shm->format.width);
 
                pDSBuf->lpVtbl->Unlock(pDSBuf, pData, dwSize, NULL, 0);
 
@@ -657,7 +657,7 @@ void S_ClearBuffer(void)
 #endif
        if (shm->buffer)
        {
-               int             setsize = shm->samples * shm->samplebits / 8;
+               int             setsize = shm->samples * shm->format.width;
                char    *buf = shm->buffer;
 
                while (setsize--)
@@ -679,7 +679,6 @@ S_StaticSound
 void S_StaticSound (sfx_t *sfx, vec3_t origin, float vol, float attenuation)
 {
        channel_t       *ss;
-       sfxcache_t              *sc;
 
        if (!sfx)
                return;
@@ -690,11 +689,10 @@ void S_StaticSound (sfx_t *sfx, vec3_t origin, float vol, float attenuation)
                return;
        }
 
-       sc = S_LoadSound (sfx, true);
-       if (!sc)
+       if (!S_LoadSound (sfx, true))
                return;
 
-       if (sc->loopstart == -1)
+       if (sfx->loopstart == -1)
                Con_DPrintf("Quake compatibility warning: Static sound \"%s\" is not looped\n", sfx->name);
 
        ss = &channels[total_channels++];
@@ -704,7 +702,7 @@ void S_StaticSound (sfx_t *sfx, vec3_t origin, float vol, float attenuation)
        VectorCopy (origin, ss->origin);
        ss->master_vol = vol;
        ss->dist_mult = (attenuation/64) / sound_nominal_clip_dist;
-       ss->end = paintedtime + sc->length;
+       ss->end = paintedtime + sfx->total_length;
 
        SND_Spatialize (ss, true);
 }
@@ -775,10 +773,8 @@ Called once each time through the main loop
 */
 void S_Update(vec3_t origin, vec3_t forward, vec3_t left, vec3_t up)
 {
-       int                     i, j;
-       int                     total;
-       channel_t       *ch;
-       channel_t       *combine;
+       unsigned int i, j, total;
+       channel_t *ch, *combine;
 
        if (!snd_initialized.integer || (snd_blocked > 0))
                return;
@@ -848,7 +844,7 @@ void S_Update(vec3_t origin, vec3_t forward, vec3_t left, vec3_t up)
                        if (ch->sfx && (ch->leftvol || ch->rightvol) )
                                total++;
 
-               Con_Printf("----(%i)----\n", total);
+               Con_Printf("----(%u)----\n", total);
        }
 
 // mix some sound
@@ -862,7 +858,7 @@ void GetSoundtime(void)
        static  int             oldsamplepos;
        int             fullsamples;
 
-       fullsamples = shm->samples / shm->channels;
+       fullsamples = shm->samples / shm->format.channels;
 
 // it is possible to miscount buffers if it has wrapped twice between
 // calls to S_Update.  Oh well.
@@ -881,7 +877,7 @@ void GetSoundtime(void)
        }
        oldsamplepos = samplepos;
 
-       soundtime = buffers*fullsamples + samplepos/shm->channels;
+       soundtime = buffers * fullsamples + samplepos / shm->format.channels;
 }
 
 void IN_Accumulate (void);
@@ -914,8 +910,8 @@ void S_Update_(void)
                paintedtime = soundtime;
 
 // mix ahead of current position
-       endtime = soundtime + _snd_mixahead.value * shm->speed;
-       samps = shm->samples >> (shm->channels-1);
+       endtime = soundtime + _snd_mixahead.value * shm->format.speed;
+       samps = shm->samples >> (shm->format.channels - 1);
        if (endtime > (unsigned int)(soundtime + samps))
                endtime = soundtime + samps;
 
@@ -998,18 +994,16 @@ void S_SoundList(void)
 {
        int             i;
        sfx_t   *sfx;
-       sfxcache_t      *sc;
        int             size, total;
 
        total = 0;
        for (sfx=known_sfx, i=0 ; i<num_sfx ; i++, sfx++)
        {
-               sc = sfx->sfxcache;
-               if (sc)
+               if (sfx->fetcher != NULL)
                {
-                       size = sc->length*sc->width*(sc->stereo+1);
+                       size = sfx->mempool->totalsize;
                        total += size;
-                       Con_Printf("%c(%2db) %6i : %s\n", sc->loopstart >= 0 ? 'L' : ' ',sc->width*8,  size, sfx->name);
+                       Con_Printf("%c(%2db) %7i : %s\n", sfx->loopstart >= 0 ? 'L' : ' ', sfx->format.width * 8, size, sfx->name);
                }
        }
        Con_Printf("Total resident: %i\n", total);
@@ -1036,7 +1030,7 @@ void S_LocalSound (char *sound)
 #define RAWSAMPLESBUFFER 32768
 short s_rawsamplesbuffer[RAWSAMPLESBUFFER * 2];
 int s_rawsamplesbuffer_start;
-int s_rawsamplesbuffer_count;
+size_t s_rawsamplesbuffer_count;
 
 void S_RawSamples_Enqueue(short *samples, unsigned int length)
 {
@@ -1058,7 +1052,8 @@ void S_RawSamples_Enqueue(short *samples, unsigned int length)
 
 void S_RawSamples_Dequeue(int *samples, unsigned int length)
 {
-       int b1, b2, l;
+       int b1, b2;
+       size_t l;
        int i;
        short *in;
        int *out;
@@ -1102,7 +1097,7 @@ void S_RawSamples_ClearQueue(void)
 
 int S_RawSamples_QueueWantsMore(void)
 {
-       if (shm != NULL && s_rawsamplesbuffer_count < min(shm->speed >> 1, RAWSAMPLESBUFFER >> 1))
+       if (shm != NULL && s_rawsamplesbuffer_count < min(shm->format.speed >> 1, RAWSAMPLESBUFFER >> 1))
                return RAWSAMPLESBUFFER - s_rawsamplesbuffer_count;
        else
                return 0;
@@ -1140,6 +1135,6 @@ void S_ResampleBuffer16Stereo(short *input, int inputlength, short *output, int
 
 int S_RawSamples_SampleRate(void)
 {
-       return shm != NULL ? shm->speed : 0;
+       return shm != NULL ? shm->format.speed : 0;
 }
 
index d0671eb..d924d66 100644 (file)
--- a/snd_mem.c
+++ b/snd_mem.c
@@ -29,34 +29,31 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 ResampleSfx
 ================
 */
-void ResampleSfx (sfxcache_t *sc, qbyte *data, char *name)
+size_t ResampleSfx (const qbyte *in_data, size_t in_length, const snd_format_t* in_format, qbyte *out_data, const char* sfxname)
 {
-       int i, outcount, srcsample, srclength, samplefrac, fracstep;
+       int samplefrac, fracstep;
+       size_t i, srcsample, srclength, outcount;
 
        // this is usually 0.5 (128), 1 (256), or 2 (512)
-       fracstep = ((double) sc->speed / (double) shm->speed) * 256.0;
+       fracstep = ((double) in_format->speed / (double) shm->format.speed) * 256.0;
 
-       srclength = sc->length << sc->stereo;
+       srclength = in_length * in_format->channels;
 
-       outcount = (double) sc->length * (double) shm->speed / (double) sc->speed;
-       Con_DPrintf("ResampleSfx: resampling sound %s from %dhz to %dhz (%d samples to %d samples)\n", name, sc->speed, shm->speed, sc->length, outcount);
-       sc->length = outcount;
-       if (sc->loopstart != -1)
-               sc->loopstart = (double) sc->loopstart * (double) shm->speed / (double) sc->speed;
-
-       sc->speed = shm->speed;
+       outcount = (double) in_length * (double) shm->format.speed / (double) in_format->speed;
+       Con_DPrintf("ResampleSfx: resampling sound \"%s\" from %dHz to %dHz (%d samples to %d samples)\n",
+                               sfxname, in_format->speed, shm->format.speed, in_length, outcount);
 
 // resample / decimate to the current source rate
 
        if (fracstep == 256)
        {
                // fast case for direct transfer
-               if (sc->width == 1) // 8bit
+               if (in_format->width == 1) // 8bit
                        for (i = 0;i < srclength;i++)
-                               ((signed char *)sc->data)[i] = ((unsigned char *)data)[i] - 128;
-               else //if (sc->width == 2) // 16bit
+                               ((signed char *)out_data)[i] = ((unsigned char *)in_data)[i] - 128;
+               else //if (sb->width == 2) // 16bit
                        for (i = 0;i < srclength;i++)
-                               ((short *)sc->data)[i] = ((short *)data)[i];
+                               ((short *)out_data)[i] = ((short *)in_data)[i];
        }
        else
        {
@@ -66,10 +63,11 @@ void ResampleSfx (sfxcache_t *sc, qbyte *data, char *name)
                {
                        srcsample = 0;
                        fracstep >>= 8;
-                       if (sc->width == 2)
+                       if (in_format->width == 2)
                        {
-                               short *out = (void *)sc->data, *in = (void *)data;
-                               if (sc->stereo) // LordHavoc: stereo sound support
+                               short *out = (short*)out_data;
+                               const short *in = (const short*)in_data;
+                               if (in_format->channels == 2) // LordHavoc: stereo sound support
                                {
                                        fracstep <<= 1;
                                        for (i=0 ; i<outcount ; i++)
@@ -90,9 +88,9 @@ void ResampleSfx (sfxcache_t *sc, qbyte *data, char *name)
                        }
                        else
                        {
-                               signed char *out = (void *)sc->data;
-                               unsigned char *in = (void *)data;
-                               if (sc->stereo) // LordHavoc: stereo sound support
+                               signed char *out = out_data;
+                               const unsigned char *in = in_data;
+                               if (in_format->channels == 2)
                                {
                                        fracstep <<= 1;
                                        for (i=0 ; i<outcount ; i++)
@@ -116,10 +114,11 @@ void ResampleSfx (sfxcache_t *sc, qbyte *data, char *name)
                {
                        int sample;
                        int a, b;
-                       if (sc->width == 2)
+                       if (in_format->width == 2)
                        {
-                               short *out = (void *)sc->data, *in = (void *)data;
-                               if (sc->stereo) // LordHavoc: stereo sound support
+                               short *out = (short*)out_data;
+                               const short *in = (const short*)in_data;
+                               if (in_format->channels == 2)
                                {
                                        for (i=0 ; i<outcount ; i++)
                                        {
@@ -159,9 +158,9 @@ void ResampleSfx (sfxcache_t *sc, qbyte *data, char *name)
                        }
                        else
                        {
-                               signed char *out = (void *)sc->data;
-                               unsigned char *in = (void *)data;
-                               if (sc->stereo) // LordHavoc: stereo sound support
+                               signed char *out = out_data;
+                               const unsigned char *in = in_data;
+                               if (in_format->channels == 2)
                                {
                                        for (i=0 ; i<outcount ; i++)
                                        {
@@ -202,62 +201,89 @@ void ResampleSfx (sfxcache_t *sc, qbyte *data, char *name)
                }
        }
 
-       // LordHavoc: use this for testing if it ever becomes useful again
-       //COM_WriteFile (va("sound/%s.pcm", name), sc->data, (sc->length << sc->stereo) * sc->width);
+       return outcount;
 }
 
 //=============================================================================
 
+wavinfo_t GetWavinfo (char *name, qbyte *wav, int wavlength);
+
+/*
+====================
+WAV_FetchSound
+====================
+*/
+static const sfxbuffer_t* WAV_FetchSound (channel_t* ch, unsigned int start, unsigned int nbsamples)
+{
+       return ch->sfx->fetcher_data;
+}
+
+
+snd_fetcher_t wav_fetcher = { WAV_FetchSound, NULL };
+
+
 /*
 ==============
 S_LoadWavFile
 ==============
 */
-sfxcache_t *S_LoadWavFile (const char *filename, sfx_t *s)
+qboolean S_LoadWavFile (const char *filename, sfx_t *s)
 {
        qbyte *data;
        wavinfo_t info;
        int len;
-       sfxcache_t *sc;
+       sfxbuffer_t* sb;
+
+       Mem_FreePool (&s->mempool);
+       s->mempool = Mem_AllocPool(s->name);
 
        // Load the file
-       data = FS_LoadFile(filename, tempmempool, false);
+       data = FS_LoadFile(filename, s->mempool, false);
        if (!data)
-               return NULL;
+       {
+               Mem_FreePool (&s->mempool);
+               return false;
+       }
 
        // Don't try to load it if it's not a WAV file
        if (memcmp (data, "RIFF", 4) || memcmp (data + 8, "WAVE", 4))
-               return NULL;
+       {
+               Mem_FreePool (&s->mempool);
+               return false;
+       }
+
+       Con_DPrintf ("Loading WAV file \"%s\"\n", filename);
 
        info = GetWavinfo (s->name, data, fs_filesize);
        // Stereo sounds are allowed (intended for music)
        if (info.channels < 1 || info.channels > 2)
        {
                Con_Printf("%s has an unsupported number of channels (%i)\n",s->name, info.channels);
-               Mem_Free(data);
-               return NULL;
+               Mem_FreePool (&s->mempool);
+               return false;
        }
 
        // calculate resampled length
-       len = (int) ((double) info.samples * (double) shm->speed / (double) info.rate);
+       len = (int) ((double) info.samples * (double) shm->format.speed / (double) info.rate);
        len = len * info.width * info.channels;
 
-       Mem_FreePool(&s->mempool);
-       s->mempool = Mem_AllocPool(s->name);
-       sc = s->sfxcache = Mem_Alloc(s->mempool, len + sizeof(sfxcache_t));
-       if (!sc)
+       sb = Mem_Alloc (s->mempool, len + sizeof (*sb) - sizeof (sb->data));
+       if (sb == NULL)
        {
                Con_Printf("failed to allocate memory for sound \"%s\"\n", s->name);
                Mem_FreePool(&s->mempool);
-               Mem_Free(data);
-               return NULL;
+               return false;
        }
 
-       sc->length = info.samples;
-       sc->loopstart = info.loopstart;
-       sc->speed = info.rate;
-       sc->width = info.width;
-       sc->stereo = info.channels == 2;
+       s->fetcher = &wav_fetcher;
+       s->fetcher_data = sb;
+       s->format.speed = info.rate;
+       s->format.width = info.width;
+       s->format.channels = info.channels;
+       if (info.loopstart < 0)
+               s->loopstart = -1;
+       else
+               s->loopstart = (double) s->loopstart * (double) shm->format.speed / (double) s->format.speed;
 
 #if BYTE_ORDER != LITTLE_ENDIAN
        // We must convert the WAV data from little endian
@@ -274,10 +300,13 @@ sfxcache_t *S_LoadWavFile (const char *filename, sfx_t *s)
        }
 #endif
 
-       ResampleSfx(sc, data + info.dataofs, s->name);
+       sb->length = ResampleSfx (data + info.dataofs, info.samples, &s->format, sb->data, s->name);
+       s->format.speed = shm->format.speed;
+       s->total_length = sb->length;
+       sb->offset = 0;
 
-       Mem_Free(data);
-       return sc;
+       Mem_Free (data);
+       return true;
 }
 
 
@@ -286,27 +315,29 @@ sfxcache_t *S_LoadWavFile (const char *filename, sfx_t *s)
 S_LoadSound
 ==============
 */
-sfxcache_t *S_LoadSound (sfx_t *s, int complain)
+qboolean S_LoadSound (sfx_t *s, int complain)
 {
        char namebuffer[MAX_QPATH];
        size_t len;
-       sfxcache_t *sc;
        qboolean modified_name = false;
 
        // see if still in memory
-       if (!shm || !shm->speed)
-               return NULL;
-       if (s->sfxcache && (s->sfxcache->speed == shm->speed))
-               return s->sfxcache;
+       if (!shm || !shm->format.speed)
+               return false;
+       if (s->fetcher != NULL)
+       {
+               if (s->format.speed != shm->format.speed)
+                       Sys_Error ("S_LoadSound: sound %s hasn't been resampled (%uHz instead of %uHz)", s->name);
+               return true;
+       }
 
        len = snprintf (namebuffer, sizeof (namebuffer), "sound/%s", s->name);
        if (len >= sizeof (namebuffer))
-               return NULL;
+               return false;
 
        // Try to load it as a WAV file
-       sc = S_LoadWavFile (namebuffer, s);
-       if (sc != NULL)
-               return sc;
+       if (S_LoadWavFile (namebuffer, s))
+               return true;
 
        // Else, try to load it as an Ogg Vorbis file
        if (!strcasecmp (namebuffer + len - 4, ".wav"))
@@ -314,9 +345,8 @@ sfxcache_t *S_LoadSound (sfx_t *s, int complain)
                strcpy (namebuffer + len - 3, "ogg");
                modified_name = true;
        }
-       sc = OGG_LoadVorbisFile (namebuffer, s);
-       if (sc != NULL)
-               return sc;
+       if (OGG_LoadVorbisFile (namebuffer, s))
+               return true;
 
        // Can't load the sound!
        if (!complain)
@@ -329,15 +359,24 @@ sfxcache_t *S_LoadSound (sfx_t *s, int complain)
                        strcpy (namebuffer + len - 3, "wav");
                Con_Printf("Couldn't load %s\n", namebuffer);
        }
-       return NULL;
+       return false;
 }
 
 void S_UnloadSound(sfx_t *s)
 {
-       if (s->sfxcache)
+       if (s->fetcher != NULL)
        {
-               s->sfxcache = NULL;
+               unsigned int i;
+
+               s->fetcher = NULL;
+               s->fetcher_data = NULL;
                Mem_FreePool(&s->mempool);
+
+               // At this point, some per-channel data pointers may point to freed zones.
+               // Practically, it shouldn't be a problem; but it's wrong, so we fix that
+               for (i = 0; i < total_channels ; i++)
+                       if (channels[i].sfx == s)
+                               channels[i].fetcher_data = NULL;
        }
 }
 
index e27b97d..6bb0658 100644 (file)
--- a/snd_mix.c
+++ b/snd_mix.c
@@ -121,11 +121,11 @@ void S_TransferPaintBuffer(int endtime)
                snd_p = (int *) paintbuffer;
                snd_vol = volume.value*256;
                lpaintedtime = paintedtime;
-               if (shm->samplebits == 16)
+               if (shm->format.width == 2)
                {
                        // 16bit
                        short *snd_out;
-                       if (shm->channels == 2)
+                       if (shm->format.channels == 2)
                        {
                                // 16bit 2 channels (stereo)
                                while (lpaintedtime < endtime)
@@ -186,7 +186,7 @@ void S_TransferPaintBuffer(int endtime)
                {
                        // 8bit
                        unsigned char *snd_out;
-                       if (shm->channels == 2)
+                       if (shm->format.channels == 2)
                        {
                                // 8bit 2 channels (stereo)
                                while (lpaintedtime < endtime)
@@ -257,15 +257,15 @@ CHANNEL MIXING
 ===============================================================================
 */
 
-void SND_PaintChannelFrom8 (channel_t *ch, sfxcache_t *sc, int endtime);
-void SND_PaintChannelFrom16 (channel_t *ch, sfxcache_t *sc, int endtime);
+qboolean SND_PaintChannelFrom8 (channel_t *ch, int endtime);
+qboolean SND_PaintChannelFrom16 (channel_t *ch, int endtime);
 
 void S_PaintChannels(int endtime)
 {
-       int i;
+       unsigned int i;
        int end;
        channel_t *ch;
-       sfxcache_t *sc;
+       sfx_t *sfx;
        int ltime, count;
 
        while (paintedtime < endtime)
@@ -282,18 +282,20 @@ void S_PaintChannels(int endtime)
                ch = channels;
                for (i=0; i<total_channels ; i++, ch++)
                {
-                       if (!ch->sfx)
+                       sfx = ch->sfx;
+                       if (!sfx)
                                continue;
                        if (!ch->leftvol && !ch->rightvol)
                                continue;
-                       sc = S_LoadSound (ch->sfx, true);
-                       if (!sc)
+                       if (!S_LoadSound (sfx, true))
                                continue;
 
                        ltime = paintedtime;
 
                        while (ltime < end)
                        {
+                               qboolean stop_paint;
+
                                // paint up to end
                                if (ch->end < end)
                                        count = ch->end - ltime;
@@ -302,28 +304,35 @@ void S_PaintChannels(int endtime)
 
                                if (count > 0)
                                {
-                                       if (sc->width == 1)
-                                               SND_PaintChannelFrom8(ch, sc, count);
+                                       if (sfx->format.width == 1)
+                                               stop_paint = !SND_PaintChannelFrom8(ch, count);
                                        else
-                                               SND_PaintChannelFrom16(ch, sc, count);
+                                               stop_paint = !SND_PaintChannelFrom16(ch, count);
 
                                        ltime += count;
                                }
+                               else
+                                       stop_paint = false;
 
-                               // if at end of loop, restart
                                if (ltime >= ch->end)
                                {
-                                       if (sc->loopstart >= 0 || ch->forceloop)
+                                       // if at end of loop, restart
+                                       if ((sfx->loopstart >= 0 || ch->forceloop) && !stop_paint)
                                        {
-                                               ch->pos = bound(0, sc->loopstart, sc->length - 1);
-                                               ch->end = ltime + sc->length - ch->pos;
+                                               ch->pos = bound(0, sfx->loopstart, (int)sfx->total_length - 1);
+                                               ch->end = ltime + sfx->total_length - ch->pos;
                                        }
+                                       // channel just stopped
                                        else
-                                       {
-                                               // channel just stopped
-                                               ch->sfx = NULL;
-                                               break;
-                                       }
+                                               stop_paint = true;
+                               }
+
+                               if (stop_paint)
+                               {
+                                       if (ch->sfx->fetcher->end != NULL)
+                                               ch->sfx->fetcher->end (ch);
+                                       ch->sfx = NULL;
+                                       break;
                                }
                        }
                }
@@ -345,10 +354,11 @@ void SND_InitScaletable (void)
 }
 
 
-void SND_PaintChannelFrom8 (channel_t *ch, sfxcache_t *sc, int count)
+qboolean SND_PaintChannelFrom8 (channel_t *ch, int count)
 {
        int *lscale, *rscale;
        unsigned char *sfx;
+       const sfxbuffer_t *sb;
        int i, n;
 
        if (ch->leftvol > 255)
@@ -358,10 +368,15 @@ void SND_PaintChannelFrom8 (channel_t *ch, sfxcache_t *sc, int count)
 
        lscale = snd_scaletable[ch->leftvol >> 3];
        rscale = snd_scaletable[ch->rightvol >> 3];
-       if (sc->stereo)
+
+       sb = ch->sfx->fetcher->getsb (ch, ch->pos, count);
+       if (sb == NULL)
+               return false;
+
+       if (ch->sfx->format.channels == 2)
        {
                // LordHavoc: stereo sound support, and optimizations
-               sfx = (unsigned char *)sc->data + ch->pos * 2;
+               sfx = (unsigned char *)sb->data + (ch->pos - sb->offset) * 2;
                for (i = 0;i < count;i++)
                {
                        paintbuffer[i].left += lscale[*sfx++];
@@ -370,7 +385,7 @@ void SND_PaintChannelFrom8 (channel_t *ch, sfxcache_t *sc, int count)
        }
        else
        {
-               sfx = (unsigned char *)sc->data + ch->pos;
+               sfx = (unsigned char *)sb->data + ch->pos - sb->offset;
                for (i = 0;i < count;i++)
                {
                        n = *sfx++;
@@ -380,20 +395,27 @@ void SND_PaintChannelFrom8 (channel_t *ch, sfxcache_t *sc, int count)
 
        }
        ch->pos += count;
+       return true;
 }
 
-void SND_PaintChannelFrom16 (channel_t *ch, sfxcache_t *sc, int count)
+qboolean SND_PaintChannelFrom16 (channel_t *ch, int count)
 {
        int leftvol, rightvol;
        signed short *sfx;
+       const sfxbuffer_t *sb;
        int i;
 
        leftvol = ch->leftvol;
        rightvol = ch->rightvol;
-       if (sc->stereo)
+
+       sb = ch->sfx->fetcher->getsb (ch, ch->pos, count);
+       if (sb == NULL)
+               return false;
+
+       if (ch->sfx->format.channels == 2)
        {
                // LordHavoc: stereo sound support, and optimizations
-               sfx = (signed short *)sc->data + ch->pos * 2;
+               sfx = (signed short *)sb->data + (ch->pos - sb->offset) * 2;
 
                for (i=0 ; i<count ; i++)
                {
@@ -403,7 +425,7 @@ void SND_PaintChannelFrom16 (channel_t *ch, sfxcache_t *sc, int count)
        }
        else
        {
-               sfx = (signed short *)sc->data + ch->pos;
+               sfx = (signed short *)sb->data + ch->pos - sb->offset;
 
                for (i=0 ; i<count ; i++)
                {
@@ -413,5 +435,6 @@ void SND_PaintChannelFrom16 (channel_t *ch, sfxcache_t *sc, int count)
        }
 
        ch->pos += count;
+       return true;
 }
 
index bf7bd2a..d1a44f2 100644 (file)
--- a/snd_ogg.c
+++ b/snd_ogg.c
@@ -1,5 +1,5 @@
 /*
-       Copyright (C) 2003  Mathieu Olivier
+       Copyright (C) 2003-2004  Mathieu Olivier
 
        This program is free software; you can redistribute it and/or
        modify it under the terms of the GNU General Public License
@@ -26,9 +26,6 @@
 #include "snd_ogg.h"
 
 
-extern void ResampleSfx (sfxcache_t *sc, qbyte *data, char *name);
-
-
 /*
 =================================================================
 
@@ -200,6 +197,7 @@ static vorbis_info* (*qov_info) (OggVorbis_File *vf,int link);
 static int (*qov_open_callbacks) (void *datasource, OggVorbis_File *vf,
                                                                  char *initial, long ibytes,
                                                                  ov_callbacks callbacks);
+static int (*qov_pcm_seek) (OggVorbis_File *vf,ogg_int64_t pos);
 static ogg_int64_t (*qov_pcm_total) (OggVorbis_File *vf,int i);
 static long (*qov_read) (OggVorbis_File *vf,char *buffer,int length,
                                                 int bigendianp,int word,int sgned,int *bitstream);
@@ -209,6 +207,7 @@ static dllfunction_t oggvorbisfuncs[] =
        {"ov_clear",                    (void **) &qov_clear},
        {"ov_info",                             (void **) &qov_info},
        {"ov_open_callbacks",   (void **) &qov_open_callbacks},
+       {"ov_pcm_seek",                 (void **) &qov_pcm_seek},
        {"ov_pcm_total",                (void **) &qov_pcm_total},
        {"ov_read",                             (void **) &qov_read},
        {NULL, NULL}
@@ -355,34 +354,185 @@ void OGG_CloseLibrary (void)
 =================================================================
 */
 
+#define STREAM_BUFFER_SIZE (128 * 1024)
+
+// Note: it must be able to contain enough samples at 48 KHz (max speed)
+//       to fill STREAM_BUFFER_SIZE bytes of samples at 8 KHz (min speed)
+// TODO: dynamically allocate this buffer depending on the shm and min sound speeds
+static qbyte resampling_buffer [STREAM_BUFFER_SIZE * (48000 / 8000)];
+
+
+// Per-sfx data structure
+typedef struct
+{
+       qbyte   *file;
+       size_t  filesize;
+} ogg_stream_persfx_t;
+
+// Per-channel data structure
+typedef struct
+{
+       OggVorbis_File  vf;
+       ov_decode_t             ov_decode;
+       int                             bs;
+       snd_format_t    format;
+       sfxbuffer_t             sb;             // must be at the end due to its dynamically allocated size
+} ogg_stream_perchannel_t;
+
+
+static const ov_callbacks callbacks = {ovcb_read, ovcb_seek, ovcb_close, ovcb_tell};
+
+/*
+====================
+OGG_FetchSound
+====================
+*/
+static const sfxbuffer_t* OGG_FetchSound (channel_t* ch, unsigned int start, unsigned int nbsamples)
+{
+       ogg_stream_perchannel_t* per_ch;
+       sfxbuffer_t* sb;
+       int newlength, done, ret, bigendian;
+       unsigned int factor;
+
+       per_ch = ch->fetcher_data;
+
+       // If there's no fetcher structure attached to the channel yet
+       if (per_ch == NULL)
+       {
+               sfx_t* sfx;
+               vorbis_info *vi;
+               ogg_stream_persfx_t* per_sfx;
+
+               sfx = ch->sfx;
+               per_ch = Mem_Alloc (sfx->mempool, sizeof (*per_ch) - sizeof (per_ch->sb.data) + STREAM_BUFFER_SIZE);
+               per_sfx = sfx->fetcher_data;
+
+               // Open it with the VorbisFile API
+               per_ch->ov_decode.buffer = per_sfx->file;
+               per_ch->ov_decode.ind = 0;
+               per_ch->ov_decode.buffsize = per_sfx->filesize;
+               if (qov_open_callbacks (&per_ch->ov_decode, &per_ch->vf, NULL, 0, callbacks) < 0)
+               {
+                       Con_Printf("error while reading Ogg Vorbis stream \"%s\"\n", sfx->name);
+                       Mem_Free (per_ch);
+                       return NULL;
+               }
+
+               // Get the stream information
+               vi = qov_info (&per_ch->vf, -1);
+               per_ch->format.speed = vi->rate;
+               per_ch->format.width = sfx->format.width;
+               per_ch->format.channels = sfx->format.channels;
+               
+               per_ch->sb.offset = 0;
+               per_ch->sb.length = 0;
+               per_ch->bs = 0;
+
+               ch->fetcher_data = per_ch;
+       }
+
+       sb = &per_ch->sb;
+
+       // If the data we need has already been decompressed in the sfxbuffer, just return it
+       if (sb->offset <= start && sb->offset + sb->length >= start + nbsamples)
+               return sb;
+
+       newlength = sb->offset + sb->length - start;
+       factor = per_ch->format.width * per_ch->format.channels;
+
+       // If we need to skip some data before decompressing the rest, or if the stream has looped
+       if (newlength < 0 || sb->offset > start)
+       {
+               if (qov_pcm_seek (&per_ch->vf, (ogg_int64_t)start) != 0)
+                       return NULL;
+
+               sb->offset = start;
+               sb->length = 0;
+               newlength = 0;
+       }
+       // Else, move forward the samples we need to keep in the sfxbuffer
+       else
+       {
+               memmove (sb->data, sb->data + (start - sb->offset) * factor, newlength * factor);
+               sb->offset = start;
+               sb->length = newlength;
+       }
+
+       // How many free bytes do we have in the sfxbuffer now?
+       newlength = STREAM_BUFFER_SIZE - (newlength * factor);
+
+       // Decompress in the resampling_buffer to get STREAM_BUFFER_SIZE samples after resampling
+#if BYTE_ORDER == LITTLE_ENDIAN
+       bigendian = 0;
+#else
+       bigendian = 1;
+#endif
+       done = 0;
+       while ((ret = qov_read (&per_ch->vf, &resampling_buffer[done], (int)(newlength - done), bigendian, 2, 1, &per_ch->bs)) > 0)
+               done += ret;
+
+       // Resample in the sfxbuffer
+       newlength = ResampleSfx (resampling_buffer, (size_t)done / factor, &per_ch->format, sb->data + sb->length * factor, ch->sfx->name);
+       sb->length += newlength;
+
+       return sb;
+}
+
+
+/*
+====================
+OGG_FetchEnd
+====================
+*/
+static void OGG_FetchEnd (channel_t* ch)
+{
+       ogg_stream_perchannel_t* per_ch;
+
+       per_ch = ch->fetcher_data;
+       if (per_ch != NULL)
+       {
+               // Free the ogg vorbis decoder
+               qov_clear (&per_ch->vf);
+
+               Mem_Free (per_ch);
+               ch->fetcher_data = NULL;
+       }
+}
+
+static const snd_fetcher_t ogg_fetcher = { OGG_FetchSound, OGG_FetchEnd };
+extern snd_fetcher_t wav_fetcher;
+
+
 /*
 ====================
 OGG_LoadVorbisFile
 
-Load an Ogg Vorbis file into a sfxcache_t
+Load an Ogg Vorbis file into memory
 ====================
 */
-sfxcache_t *OGG_LoadVorbisFile (const char *filename, sfx_t *s)
+qboolean OGG_LoadVorbisFile (const char *filename, sfx_t *s)
 {
        qbyte *data;
        ov_decode_t ov_decode;
        OggVorbis_File vf;
-       ov_callbacks callbacks = {ovcb_read, ovcb_seek, ovcb_close, ovcb_tell};
        vorbis_info *vi;
        ogg_int64_t len;
-       char *buff;
-       ogg_int64_t done;
-       int bs, bigendian;
-       long ret;
-       sfxcache_t *sc;
 
        if (!vf_dll)
-               return NULL;
+               return false;
+
+       Mem_FreePool (&s->mempool);
+       s->mempool = Mem_AllocPool (s->name);
 
        // Load the file
-       data = FS_LoadFile (filename, tempmempool, false);
+       data = FS_LoadFile (filename, s->mempool, false);
        if (data == NULL)
-               return NULL;
+       {
+               Mem_FreePool (&s->mempool);
+               return false;
+       }
+
+       Con_DPrintf ("Loading Ogg Vorbis file \"%s\"\n", filename);
 
        // Open it with the VorbisFile API
        ov_decode.buffer = data;
@@ -390,9 +540,9 @@ sfxcache_t *OGG_LoadVorbisFile (const char *filename, sfx_t *s)
        ov_decode.buffsize = fs_filesize;
        if (qov_open_callbacks (&ov_decode, &vf, NULL, 0, callbacks) < 0)
        {
-               Con_Printf("error while opening Ogg Vorbis file \"%s\"\n", filename);
-               Mem_Free (data);
-               return NULL;
+               Con_Printf ("error while opening Ogg Vorbis file \"%s\"\n", filename);
+               Mem_FreePool (&s->mempool);
+               return false;
        }
 
        // Get the stream information
@@ -402,49 +552,72 @@ sfxcache_t *OGG_LoadVorbisFile (const char *filename, sfx_t *s)
                Con_Printf("%s has an unsupported number of channels (%i)\n",
                                        s->name, vi->channels);
                qov_clear (&vf);
-               Mem_Free (data);
-               return NULL;
+               Mem_FreePool (&s->mempool);
+               return false;
        }
 
-       // Decode it
        len = qov_pcm_total (&vf, -1) * vi->channels * 2;  // 16 bits => "* 2"
-       buff = Mem_Alloc (tempmempool, (int)len);
-       done = 0;
-       bs = 0;
-#if BYTE_ORDER == LITTLE_ENDIAN
-       bigendian = 0;
-#else
-       bigendian = 1;
-#endif
-       while ((ret = qov_read (&vf, &buff[done], (int)(len - done), bigendian, 2, 1, &bs)) > 0)
-               done += ret;
-
-       // Calculate resampled length
-       len = (double)done * (double)shm->speed / (double)vi->rate;
 
-       // Resample it
-       Mem_FreePool (&s->mempool);
-       s->mempool = Mem_AllocPool (s->name);
-       sc = s->sfxcache = Mem_Alloc (s->mempool, (int)len + sizeof (sfxcache_t));
-       if (sc != NULL)
+       // Decide if we go for a stream or a simple PCM cache
+       if (snd_streaming.integer && len > fs_filesize + 3 * STREAM_BUFFER_SIZE)
        {
-               sc->length = (int)done / (vi->channels * 2);
-               sc->loopstart = -1;
-               sc->speed = vi->rate;
-               sc->width = 2;  // We always work with 16 bits samples
-               sc->stereo = (vi->channels == 2);
-
-               ResampleSfx (sc, buff, s->name);
+               ogg_stream_persfx_t* per_sfx;
+
+               Con_DPrintf ("\"%s\" will be streamed\n", filename);
+               per_sfx = Mem_Alloc (s->mempool, sizeof (*per_sfx));
+               per_sfx->file = data;
+               per_sfx->filesize = fs_filesize;
+               s->fetcher_data = per_sfx;
+               s->fetcher = &ogg_fetcher;
+               s->format.speed = shm->format.speed;
+               s->format.width = 2;  // We always work with 16 bits samples
+               s->format.channels = vi->channels;
+               s->loopstart = -1;
+               s->total_length = (size_t)len / (vi->channels * 2) * (float)(shm->format.speed / vi->rate);
        }
        else
        {
-               Con_Printf("failed to allocate memory for sound \"%s\"\n", s->name);
-               Mem_FreePool (&s->mempool);
-       }
+               char *buff;
+               ogg_int64_t done;
+               int bs, bigendian;
+               long ret;
+               sfxbuffer_t *sb;
+
+               Con_DPrintf ("\"%s\" will be streamed\n", filename);
+
+               // Decode it
+               buff = Mem_Alloc (s->mempool, (int)len);
+               done = 0;
+               bs = 0;
+#if BYTE_ORDER == LITTLE_ENDIAN
+               bigendian = 0;
+#else
+               bigendian = 1;
+#endif
+               while ((ret = qov_read (&vf, &buff[done], (int)(len - done), bigendian, 2, 1, &bs)) > 0)
+                       done += ret;
+
+               // Calculate resampled length
+               len = (double)done * (double)shm->format.speed / (double)vi->rate;
+
+               // Resample it
+               sb = Mem_Alloc (s->mempool, (size_t)len + sizeof (*sb) - sizeof (sb->data));
+               s->fetcher_data = sb;
+               s->fetcher = &wav_fetcher;
+               s->format.speed = vi->rate;
+               s->format.width = 2;  // We always work with 16 bits samples
+               s->format.channels = vi->channels;
+               s->loopstart = -1;
+
+               sb->length = ResampleSfx (buff, (size_t)done / (vi->channels * 2), &s->format, sb->data, s->name);
+               s->format.speed = shm->format.speed;
+               s->total_length = sb->length;
+               sb->offset = 0;
 
-       qov_clear (&vf);
-       Mem_Free (buff);
-       Mem_Free (data);
+               qov_clear (&vf);
+               Mem_Free (data);
+               Mem_Free (buff);
+       }
 
-       return sc;
+       return true;
 }
index c25e32a..4d200b7 100644 (file)
--- a/snd_ogg.h
+++ b/snd_ogg.h
@@ -27,7 +27,7 @@
 
 qboolean OGG_OpenLibrary (void);
 void OGG_CloseLibrary (void);
-sfxcache_t *OGG_LoadVorbisFile (const char *filename, sfx_t *s);
+qboolean OGG_LoadVorbisFile (const char *filename, sfx_t *s);
 
 
 #endif
index e5fddc2..d06e478 100644 (file)
--- a/snd_oss.c
+++ b/snd_oss.c
@@ -32,7 +32,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 int audio_fd;
 int snd_inited;
 
-static int tryrates[] = {44100, 22051, 11025, 8000};
+static int tryrates[] = {44100, 22050, 11025, 8000};
 
 qboolean SNDDMA_Init(void)
 {
@@ -95,44 +95,44 @@ qboolean SNDDMA_Init(void)
        // set sample bits & speed
        s = getenv("QUAKE_SOUND_SAMPLEBITS");
        if (s)
-               shm->samplebits = atoi(s);
+               shm->format.width = atoi(s) / 8;
        else if ((i = COM_CheckParm("-sndbits")) != 0)
-               shm->samplebits = atoi(com_argv[i+1]);
+               shm->format.width = atoi(com_argv[i+1]) / 8;
 
-       if (shm->samplebits != 16 && shm->samplebits != 8)
+       if (shm->format.width != 2 && shm->format.width != 1)
        {
                ioctl(audio_fd, SNDCTL_DSP_GETFMTS, &fmt);
                if (fmt & format16bit)
-                       shm->samplebits = 16;
+                       shm->format.width = 2;
                else if (fmt & AFMT_U8)
-                       shm->samplebits = 8;
+                       shm->format.width = 1;
     }
 
        s = getenv("QUAKE_SOUND_SPEED");
        if (s)
-               shm->speed = atoi(s);
+               shm->format.speed = atoi(s);
        else if ((i = COM_CheckParm("-sndspeed")) != 0)
-               shm->speed = atoi(com_argv[i+1]);
+               shm->format.speed = atoi(com_argv[i+1]);
        else
        {
                for (i = 0;i < (int) sizeof(tryrates) / 4;i++)
                        if (!ioctl(audio_fd, SNDCTL_DSP_SPEED, &tryrates[i]))
                                break;
 
-               shm->speed = tryrates[i];
+               shm->format.speed = tryrates[i];
     }
 
        s = getenv("QUAKE_SOUND_CHANNELS");
        if (s)
-               shm->channels = atoi(s);
+               shm->format.channels = atoi(s);
        else if ((i = COM_CheckParm("-sndmono")) != 0)
-               shm->channels = 1;
+               shm->format.channels = 1;
        else if ((i = COM_CheckParm("-sndstereo")) != 0)
-               shm->channels = 2;
+               shm->format.channels = 2;
        else
-               shm->channels = 2;
+               shm->format.channels = 2;
 
-       shm->samples = info.fragstotal * info.fragsize / (shm->samplebits/8);
+       shm->samples = info.fragstotal * info.fragsize / shm->format.width;
 
        // memory map the dma buffer
        shm->bufferlength = info.fragstotal * info.fragsize;
@@ -146,32 +146,32 @@ qboolean SNDDMA_Init(void)
        }
 
        tmp = 0;
-       if (shm->channels == 2)
+       if (shm->format.channels == 2)
                tmp = 1;
 
        rc = ioctl(audio_fd, SNDCTL_DSP_STEREO, &tmp);
        if (rc < 0)
        {
                perror("/dev/dsp");
-               Con_Printf("Could not set /dev/dsp to stereo=%d\n", shm->channels);
+               Con_Printf("Could not set /dev/dsp to stereo=%d\n", shm->format.channels);
                close(audio_fd);
                return 0;
        }
        if (tmp)
-               shm->channels = 2;
+               shm->format.channels = 2;
        else
-               shm->channels = 1;
+               shm->format.channels = 1;
 
-       rc = ioctl(audio_fd, SNDCTL_DSP_SPEED, &shm->speed);
+       rc = ioctl(audio_fd, SNDCTL_DSP_SPEED, &shm->format.speed);
        if (rc < 0)
        {
                perror("/dev/dsp");
-               Con_Printf("Could not set /dev/dsp speed to %d\n", shm->speed);
+               Con_Printf("Could not set /dev/dsp speed to %d\n", shm->format.speed);
                close(audio_fd);
                return 0;
        }
 
-       if (shm->samplebits == 16)
+       if (shm->format.width == 2)
        {
                rc = format16bit;
                rc = ioctl(audio_fd, SNDCTL_DSP_SETFMT, &rc);
@@ -183,7 +183,7 @@ qboolean SNDDMA_Init(void)
                        return 0;
                }
        }
-       else if (shm->samplebits == 8)
+       else if (shm->format.width == 1)
        {
                rc = AFMT_U8;
                rc = ioctl(audio_fd, SNDCTL_DSP_SETFMT, &rc);
@@ -198,7 +198,7 @@ qboolean SNDDMA_Init(void)
        else
        {
                perror("/dev/dsp");
-               Con_Printf("%d-bit sound not supported.\n", shm->samplebits);
+               Con_Printf("%d-bit sound not supported.\n", shm->format.width * 8);
                close(audio_fd);
                return 0;
        }
@@ -244,7 +244,7 @@ int SNDDMA_GetDMAPos(void)
                snd_inited = 0;
                return 0;
        }
-       shm->samplepos = count.ptr / (shm->samplebits / 8);
+       shm->samplepos = count.ptr / shm->format.width;
 
        return shm->samplepos;
 }
index 9806ada..bea76b5 100644 (file)
--- a/snd_win.c
+++ b/snd_win.c
@@ -194,19 +194,19 @@ sndinitstat SNDDMA_InitDirect (void)
        int i;
 
        memset((void *)shm, 0, sizeof(*shm));
-       shm->channels = 2;
-       shm->samplebits = 16;
+       shm->format.channels = 2;
+       shm->format.width = 2;
        i = COM_CheckParm ("-sndspeed"); // LordHavoc: -sndspeed option
        if (i && i != (com_argc - 1))
-               shm->speed = atoi(com_argv[i+1]);
+               shm->format.speed = atoi(com_argv[i+1]);
        else
-               shm->speed = 44100;
+               shm->format.speed = 44100;
 
        memset (&format, 0, sizeof(format));
        format.wFormatTag = WAVE_FORMAT_PCM;
-    format.nChannels = shm->channels;
-    format.wBitsPerSample = shm->samplebits;
-    format.nSamplesPerSec = shm->speed;
+    format.nChannels = shm->format.channels;
+    format.wBitsPerSample = shm->format.width * 8;
+    format.nSamplesPerSec = shm->format.speed;
     format.nBlockAlign = format.nChannels * format.wBitsPerSample / 8;
     format.cbSize = 0;
     format.nAvgBytesPerSec = format.nSamplesPerSec * format.nBlockAlign;
@@ -322,9 +322,9 @@ sndinitstat SNDDMA_InitDirect (void)
                        return SIS_FAILURE;
                }
 
-               shm->channels = format.nChannels;
-               shm->samplebits = format.wBitsPerSample;
-               shm->speed = format.nSamplesPerSec;
+               shm->format.channels = format.nChannels;
+               shm->format.width = format.wBitsPerSample / 8;
+               shm->format.speed = format.nSamplesPerSec;
 
                if (DS_OK != pDSBuf->lpVtbl->GetCaps (pDSBuf, &dsbcaps))
                {
@@ -362,7 +362,7 @@ sndinitstat SNDDMA_InitDirect (void)
                Con_SafePrintf("   %d channel(s)\n"
                               "   %d bits/sample\n"
                                           "   %d samples/sec\n",
-                                          shm->channels, shm->samplebits, shm->speed);
+                                          shm->format.channels, shm->format.width * 8, shm->format.speed);
 
        gSndBufSize = dsbcaps.dwBufferBytes;
 
@@ -398,10 +398,10 @@ sndinitstat SNDDMA_InitDirect (void)
        pDSBuf->lpVtbl->GetCurrentPosition(pDSBuf, &mmstarttime.u.sample, &dwWrite);
        pDSBuf->lpVtbl->Play(pDSBuf, 0, 0, DSBPLAY_LOOPING);
 
-       shm->samples = gSndBufSize/(shm->samplebits/8);
+       shm->samples = gSndBufSize / shm->format.width;
        shm->samplepos = 0;
        shm->buffer = (unsigned char *) lpData;
-       sample16 = (shm->samplebits/8) - 1;
+       sample16 = shm->format.width - 1;
 
        dsound_init = true;
 
@@ -426,19 +426,19 @@ qboolean SNDDMA_InitWav (void)
        snd_completed = 0;
 
        memset((void *)shm, 0, sizeof(*shm));
-       shm->channels = 2;
-       shm->samplebits = 16;
+       shm->format.channels = 2;
+       shm->format.width = 2;
        i = COM_CheckParm ("-sndspeed"); // LordHavoc: -sndspeed option
        if (i && i != (com_argc - 1))
-               shm->speed = atoi(com_argv[i+1]);
+               shm->format.speed = atoi(com_argv[i+1]);
        else
-               shm->speed = 44100;
+               shm->format.speed = 44100;
 
        memset (&format, 0, sizeof(format));
        format.wFormatTag = WAVE_FORMAT_PCM;
-       format.nChannels = shm->channels;
-       format.wBitsPerSample = shm->samplebits;
-       format.nSamplesPerSec = shm->speed;
+       format.nChannels = shm->format.channels;
+       format.wBitsPerSample = shm->format.width * 8;
+       format.nSamplesPerSec = shm->format.speed;
        format.nBlockAlign = format.nChannels
                *format.wBitsPerSample / 8;
        format.cbSize = 0;
@@ -531,10 +531,10 @@ qboolean SNDDMA_InitWav (void)
                }
        }
 
-       shm->samples = gSndBufSize/(shm->samplebits/8);
+       shm->samples = gSndBufSize / shm->format.width;
        shm->samplepos = 0;
        shm->buffer = (unsigned char *) lpData;
-       sample16 = (shm->samplebits/8) - 1;
+       sample16 = shm->format.width - 1;
 
        wav_init = true;
 
diff --git a/sound.h b/sound.h
index 075719a..ffefe94 100644 (file)
--- a/sound.h
+++ b/sound.h
@@ -19,8 +19,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */
 // sound.h -- client sound i/o functions
 
-#ifndef __SOUND__
-#define __SOUND__
+#ifndef SOUND_H
+#define SOUND_H
 
 #define DEFAULT_SOUND_PACKET_VOLUME 255
 #define DEFAULT_SOUND_PACKET_ATTENUATION 1.0
@@ -33,35 +33,42 @@ typedef struct
 
 typedef struct
 {
-       int     length;
-       int     loopstart;
-       int     speed;
-       int     width;
-       int     stereo;
-       qbyte   data[1];                // variable sized
-} sfxcache_t;
+       size_t  length;
+       size_t  offset;
+       qbyte   data[4];        // variable sized
+} sfxbuffer_t;
+
+typedef struct
+{
+       unsigned int    speed;
+       unsigned int    width;
+       unsigned int    channels;
+} snd_format_t;
 
 // sfx_t flags
 #define SFXFLAG_SILENTLYMISSING        (1 << 0) // if the sfx is missing and loaded with complain = false
 #define SFXFLAG_USED                   (1 << 1)
 
+typedef struct snd_fetcher_s snd_fetcher_t;
 typedef struct sfx_s
 {
-       char    name[MAX_QPATH];
-       mempool_t       *mempool;
-       sfxcache_t      *sfxcache;
-       unsigned int flags;  // cf SFXFLAG_* defines
+       char                            name[MAX_QPATH];
+       mempool_t                       *mempool;
+       unsigned int            flags;                  // cf SFXFLAG_* defines
+       snd_format_t            format;
+       int                                     loopstart;
+       size_t                          total_length;
+       const snd_fetcher_t     *fetcher;
+       void                            *fetcher_data;  // Per-sfx data for the sound fetching functions
 } sfx_t;
 
 typedef struct
 {
-       int                             channels;
-       int                             samples;                                // mono samples in buffer
-       int                             samplepos;                              // in mono samples
-       int                             samplebits;
-       int                             speed;
+       snd_format_t    format;
+       int                             samples;                // mono samples in buffer
+       int                             samplepos;              // in mono samples
        unsigned char   *buffer;
-       int                             bufferlength; // used only by certain drivers
+       int                             bufferlength;   // used only by certain drivers
 } dma_t;
 
 typedef struct
@@ -74,12 +81,21 @@ typedef struct
        int     pos;                    // sample position in sfx
        int             looping;                // where to loop, -1 = no looping
        int             entnum;                 // to allow overriding a specific sound
-       int             entchannel;             //
+       int             entchannel;
        vec3_t  origin;                 // origin of sound effect
        vec_t   dist_mult;              // distance multiplier (attenuation/clipK)
        int             master_vol;             // 0-255 master volume
+       void    *fetcher_data;  // Per-channel data for the sound fetching function
 } channel_t;
 
+typedef const sfxbuffer_t* (*snd_fetcher_getsb_t) (channel_t* ch, unsigned int start, unsigned int nbsamples);
+typedef void (*snd_fetcher_end_t) (channel_t* ch);
+struct snd_fetcher_s
+{
+       snd_fetcher_getsb_t     getsb;
+       snd_fetcher_end_t       end;
+};
+
 typedef struct
 {
        int             rate;
@@ -124,6 +140,8 @@ int SNDDMA_GetDMAPos(void);
 // shutdown the DMA xfer.
 void SNDDMA_Shutdown(void);
 
+extern size_t ResampleSfx (const qbyte *in_data, size_t in_length, const snd_format_t* in_format, qbyte *out_data, const char* sfxname);
+
 // ====================================================================
 // User-setable variables
 // ====================================================================
@@ -139,7 +157,7 @@ extern channel_t channels[MAX_CHANNELS];
 // MAX_DYNAMIC_CHANNELS to MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS -1 = water, etc
 // MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS to total_channels = static sounds
 
-extern int total_channels;
+extern unsigned int total_channels;
 
 //
 // Fake dma is a synchronous faking of the DMA progress used for
@@ -165,16 +183,15 @@ extern cvar_t volume;
 extern cvar_t snd_swapstereo;
 
 extern cvar_t cdaudioinitialized;
-extern cvar_t  snd_initialized;
+extern cvar_t snd_initialized;
+extern cvar_t snd_streaming;
 
 extern int snd_blocked;
 
 void S_LocalSound (char *s);
-sfxcache_t *S_LoadSound (sfx_t *s, int complain);
+qboolean S_LoadSound (sfx_t *s, int complain);
 void S_UnloadSound(sfx_t *s);
 
-wavinfo_t GetWavinfo (char *name, qbyte *wav, int wavlength);
-
 void SND_InitScaletable (void);
 void SNDDMA_Submit(void);