diff --git a/include/snd_render.h b/include/snd_render.h index 0054e8be8..aa7f312e0 100644 --- a/include/snd_render.h +++ b/include/snd_render.h @@ -120,7 +120,13 @@ struct sfxbuffer_s { */ void (*setpos) (sfxbuffer_t *buffer, unsigned int pos); sfx_t *sfx; //!< owning sfx_t instance - byte data[4]; //!< sample data + /** Points to the beginning of the sample data within sample_data. + */ + byte *data; + /** Sample data. The block at the beginning of the buffer (size depends on + sample size) holds the state information for resampling. + */ + byte sample_data[4]; }; /** Representation of sound loaded that is streamed in as needed. @@ -136,7 +142,7 @@ struct sfxstream_s { \param length number of raw samples to resample \param prev pointer to end of last resample for smoothing */ - void (*resample)(sfxbuffer_t *, byte *, int, void *); + void (*resample)(sfxbuffer_t *, byte *, int); /** Read data from the stream. \param file handle for "file" representing the stream (sfxstream_s::file) @@ -395,17 +401,15 @@ void SND_SetPaint (sfxbuffer_t *sc); \param sc buffer to write resampled sound \param data raw sample data \param length number of raw samples to resample - \param prev pointer to end of last resample for smoothing */ -void SND_ResampleMono (sfxbuffer_t *sc, byte *data, int length, void *prev); +void SND_ResampleMono (sfxbuffer_t *sc, byte *data, int length); /** Copy/resample stereo data into sample buffer, resampling as necessary. \param sc buffer to write resampled sound \param data raw sample data \param length number of raw samples to resample - \param prev pointer to end of last resample for smoothing */ -void SND_ResampleStereo (sfxbuffer_t *sc, byte *data, int length, void *prev); +void SND_ResampleStereo (sfxbuffer_t *sc, byte *data, int length); //@} diff --git a/libs/audio/renderer/flac.c b/libs/audio/renderer/flac.c index 803faa06e..f5964e147 100644 --- a/libs/audio/renderer/flac.c +++ b/libs/audio/renderer/flac.c @@ -345,7 +345,7 @@ flac_load (flacfile_t *ff, sfxblock_t *block, cache_allocator_t allocator) byte *data; sfxbuffer_t *sc = 0; sfx_t *sfx = block->sfx; - void (*resample)(sfxbuffer_t *, byte *, int, void *); + void (*resample)(sfxbuffer_t *, byte *, int); wavinfo_t *info = &block->wavinfo; switch (ff->info.channels) { @@ -372,7 +372,7 @@ flac_load (flacfile_t *ff, sfxblock_t *block, cache_allocator_t allocator) if (flac_read (ff, data, info->datalen) < 0) goto bail; SND_SetPaint (sc); - resample (sc, data, info->samples, 0); + resample (sc, data, info->samples); sc->head = sc->length; bail: if (data) diff --git a/libs/audio/renderer/snd_mem.c b/libs/audio/renderer/snd_mem.c index 9bdbba8be..d4d9e28f1 100644 --- a/libs/audio/renderer/snd_mem.c +++ b/libs/audio/renderer/snd_mem.c @@ -157,16 +157,13 @@ SND_StreamWavinfo (sfx_t *sfx) } static void -read_samples (sfxbuffer_t *buffer, int count, void *prev) +read_samples (sfxbuffer_t *buffer, int count) { if (buffer->head + count > buffer->length) { - int s = (buffer->length - 1); - count -= buffer->length - buffer->head; - read_samples (buffer, buffer->length - buffer->head, prev); - prev = buffer->data + s * buffer->bps; - read_samples (buffer, count, prev); + read_samples (buffer, buffer->length - buffer->head); + read_samples (buffer, count); } else { float stepscale; int samples, size; @@ -183,7 +180,7 @@ read_samples (sfxbuffer_t *buffer, int count, void *prev) byte *data = alloca (size); if (stream->read (stream->file, data, size, info) != size) Sys_Printf ("%s r\n", sfx->name); - stream->resample (buffer, data, samples, prev); + stream->resample (buffer, data, samples); } else { if (stream->read (stream->file, buffer->data, size, info) != size) Sys_Printf ("%s nr\n", sfx->name); @@ -198,7 +195,6 @@ static void fill_buffer (sfx_t *sfx, sfxstream_t *stream, sfxbuffer_t *buffer, wavinfo_t *info, unsigned int headpos) { - void *prev; unsigned int samples; unsigned int loop_samples = 0; @@ -220,23 +216,17 @@ fill_buffer (sfx_t *sfx, sfxstream_t *stream, sfxbuffer_t *buffer, int s = buffer->head - 1; if (!buffer->head) s += buffer->length; - prev = buffer->data + s * buffer->bps; - } else { - prev = 0; } - read_samples (buffer, samples, prev); + read_samples (buffer, samples); } if (loop_samples) { if (buffer->head != buffer->tail) { int s = buffer->head - 1; if (!buffer->head) s += buffer->length; - prev = buffer->data + s * buffer->bps; - } else { - prev = 0; } stream->seek (stream->file, info->loopstart, info); - read_samples (buffer, loop_samples, prev); + read_samples (buffer, loop_samples); } } @@ -403,6 +393,7 @@ SND_GetCache (long samples, int rate, int inwidth, int channels, return 0; memset (sc, 0, sizeof (sfxbuffer_t) + size); sc->length = len; + sc->data = sc->sample_data; memcpy (sc->data + size, "\xde\xad\xbe\xef", 4); return sc; } diff --git a/libs/audio/renderer/snd_resample.c b/libs/audio/renderer/snd_resample.c index 98a75dccc..542bc3d03 100644 --- a/libs/audio/renderer/snd_resample.c +++ b/libs/audio/renderer/snd_resample.c @@ -61,6 +61,39 @@ typedef struct { cvar_t *snd_loadas8bit; cvar_t *snd_interp; +static inline int +snd_convert_8_to_8 (byte data) +{ + return data - 128; +} + +static inline int +snd_convert_8_to_16 (byte data) +{ + return snd_convert_8_to_8 (data) << 8; +} + +static inline int +snd_convert_16_to_16 (short data) +{ + return LittleShort (data); +} + +static inline int +snd_convert_16_to_8 (short data) +{ + return snd_convert_16_to_16 (data) >> 8; +} + +#define FAST_RESAMPLE(in,out,count,convert) \ + do { \ + int i; \ + \ + for (i = 0; i < count; i++) { \ + *out++ = convert (*in++); \ + } \ + } while (0) + static void check_buffer_integrity (sfxbuffer_t *sc, int width, const char *func) { @@ -71,8 +104,9 @@ check_buffer_integrity (sfxbuffer_t *sc, int width, const char *func) } void -SND_ResampleMono (sfxbuffer_t *sc, byte *data, int length, void *prev) +SND_ResampleMono (sfxbuffer_t *sc, byte *data, int length) { + void *prev = 0; byte *ib, *ob, *pb; int fracstep, outcount, sample, samplefrac, srcsample, i; float stepscale; @@ -84,6 +118,9 @@ SND_ResampleMono (sfxbuffer_t *sc, byte *data, int length, void *prev) short zero_s[1]; byte zero_b[1]; + if (sc->data != sc->sample_data) + prev = sc->data; + is = (short *) data; os = (short *) sc->data; ib = data; @@ -111,18 +148,16 @@ SND_ResampleMono (sfxbuffer_t *sc, byte *data, int length, void *prev) else sc->sfx->loopstart = (unsigned int)-1; - if (snd_loadas8bit->int_val) { + if (snd_loadas8bit->int_val) sc->bps = outwidth = 1; - if (prev) { - zero_s[0] = ((char *)prev)[0]; - zero_b[0] = ((char *)prev)[0] + 128; - } - } else { + else sc->bps = outwidth = 2; - if (prev) { + + if (prev) { + if (inwidth == 1) + zero_b[0] = ((char *)prev)[0]; + else zero_s[0] = ((short *)prev)[0]; - zero_b[0] = (((short *)prev)[0] >> 8) + 128; - } } if (!length) @@ -131,29 +166,19 @@ SND_ResampleMono (sfxbuffer_t *sc, byte *data, int length, void *prev) // resample / decimate to the current source rate if (stepscale == 1) { if (inwidth == 1) { - if (outwidth == 1) { - for (i = 0; i < outcount; i++) { - *ob++ = *ib++ - 128; - } - } else if (outwidth == 2) { - for (i = 0; i < outcount; i++) { - *os++ = (*ib++ - 128) << 8; - } - } else { + if (outwidth == 1) + FAST_RESAMPLE (ib, ob, outcount, snd_convert_8_to_8); + else if (outwidth == 2) + FAST_RESAMPLE (ib, os, outcount, snd_convert_8_to_16); + else goto general_Mono; - } } else if (inwidth == 2) { - if (outwidth == 1) { - for (i = 0; i < outcount; i++) { - *ob++ = LittleShort (*is++) >> 8; - } - } else if (outwidth == 2) { - for (i = 0; i < outcount; i++) { - *os++ = LittleShort (*is++); - } - } else { + if (outwidth == 1) + FAST_RESAMPLE (is, ob, outcount, snd_convert_16_to_8); + else if (outwidth == 2) + FAST_RESAMPLE (is, os, outcount, snd_convert_16_to_16); + else goto general_Mono; - } } } else { // general case general_Mono: @@ -165,12 +190,12 @@ general_Mono: int s1, s2; if (inwidth == 2) { - s1 = LittleShort (*ps); - s2 = LittleShort (*is); + s1 = snd_convert_16_to_16 (*ps); + s2 = snd_convert_16_to_16 (*is); ps = is++; } else { - s1 = (*pb - 128) << 8; - s2 = (*ib - 128) << 8; + s1 = snd_convert_8_to_16 (*pb); + s2 = snd_convert_8_to_16 (*ib); pb = ib++; } for (j = 0; j < points; j++) { @@ -187,6 +212,12 @@ general_Mono: ob += points; } } + if (prev) { + if (inwidth == 1) + ((char *)prev)[0] = *pb; + else + ((short *)prev)[0] = *ps; + } } else { samplefrac = 0; fracstep = stepscale * 256; @@ -194,9 +225,9 @@ general_Mono: srcsample = samplefrac >> 8; samplefrac += fracstep; if (inwidth == 2) - sample = LittleShort (is[srcsample]); + sample = snd_convert_16_to_16 (is[srcsample]); else - sample = (ib[srcsample] - 128) << 8; + sample = snd_convert_8_to_16 (ib[srcsample]); if (outwidth == 2) os[i] = sample; else @@ -208,8 +239,9 @@ general_Mono: } void -SND_ResampleStereo (sfxbuffer_t *sc, byte *data, int length, void *prev) +SND_ResampleStereo (sfxbuffer_t *sc, byte *data, int length) { + void *prev = 0; int fracstep, outcount, outwidth, samplefrac, srcsample, sl, sr, i; float stepscale; stereo8_t *ib, *ob, *pb; @@ -220,6 +252,9 @@ SND_ResampleStereo (sfxbuffer_t *sc, byte *data, int length, void *prev) stereo16_t zero_s; stereo8_t zero_b; + if (sc->data != sc->sample_data) + prev = sc->data; + is = (stereo16_t *) data; os = (stereo16_t *) sc->data; ib = (stereo8_t *) data; @@ -249,20 +284,18 @@ SND_ResampleStereo (sfxbuffer_t *sc, byte *data, int length, void *prev) if (snd_loadas8bit->int_val) { outwidth = 1; sc->bps = 2; - if (prev) { - zero_s.left = ((char *)prev)[0]; - zero_s.right = ((char *)prev)[1]; - zero_b.left = ((char *)prev)[0] + 128; - zero_b.right = ((char *)prev)[1] + 128; - } } else { outwidth = 2; sc->bps = 4; - if (prev) { + } + + if (prev) { + if (inwidth == 1) { + zero_b.left = ((char *)prev)[0]; + zero_b.right = ((char *)prev)[1]; + } else { zero_s.left = ((short *)prev)[0]; zero_s.right = ((short *)prev)[1]; - zero_b.left = (((short *)prev)[0] >> 8) + 128; - zero_b.right = (((short *)prev)[1] >> 8) + 128; } } @@ -340,6 +373,15 @@ general_Stereo: ob += points; } } + if (prev) { + if (inwidth == 1) { + ((char *)prev)[0] = pb->left; + ((char *)prev)[1] = pb->right; + } else { + ((short *)prev)[0] = ps->left; + ((short *)prev)[1] = ps->right; + } + } } else { samplefrac = 0; fracstep = stepscale * 256; diff --git a/libs/audio/renderer/snd_sfx.c b/libs/audio/renderer/snd_sfx.c index a806b7906..416ed235d 100644 --- a/libs/audio/renderer/snd_sfx.c +++ b/libs/audio/renderer/snd_sfx.c @@ -119,6 +119,7 @@ SND_SFX_StreamOpen (sfx_t *sfx, void *file, wavinfo_t *info = &stream->wavinfo; int samples; int size; + int width; sfx_t *new_sfx = calloc (1, sizeof (sfx_t)); @@ -131,15 +132,18 @@ SND_SFX_StreamOpen (sfx_t *sfx, void *file, new_sfx->close = close; samples = snd_shm->speed * 0.3; - size = samples = (samples + 255) & ~255; + samples = (samples + 255) & ~255; + size = samples + 1; // one extra sample for the resampler + width = 1; if (!snd_loadas8bit->int_val) - size *= 2; + width *= 2; if (info->channels == 2) - size *= 2; + width *= 2; + size *= width; stream = calloc (1, sizeof (sfxstream_t) + size); new_sfx->data.stream = stream; - memcpy (stream->buffer.data + size, "\xde\xad\xbe\xef", 4); + memcpy (stream->buffer.sample_data + size, "\xde\xad\xbe\xef", 4); stream->file = file; stream->sfx = new_sfx; stream->resample = info->channels == 2 ? SND_ResampleStereo @@ -153,9 +157,15 @@ SND_SFX_StreamOpen (sfx_t *sfx, void *file, stream->buffer.advance = SND_StreamAdvance; stream->buffer.setpos = SND_StreamSetPos; stream->buffer.sfx = new_sfx; + stream->buffer.data = &stream->buffer.sample_data[width]; + if (info->width == 1) { + stream->buffer.sample_data[0] = 128; + if (info->channels == 2) + stream->buffer.sample_data[1] = 128; + } SND_SetPaint (&stream->buffer); - stream->resample (&stream->buffer, 0, 0, 0); // get sfx setup properly + stream->resample (&stream->buffer, 0, 0); // get sfx setup properly stream->seek (stream->file, 0, &stream->wavinfo); stream->buffer.advance (&stream->buffer, 0); diff --git a/libs/audio/renderer/vorbis.c b/libs/audio/renderer/vorbis.c index eea810e84..bb34f5521 100644 --- a/libs/audio/renderer/vorbis.c +++ b/libs/audio/renderer/vorbis.c @@ -156,7 +156,7 @@ vorbis_load (OggVorbis_File *vf, sfxblock_t *block, cache_allocator_t allocator) byte *data; sfxbuffer_t *sc = 0; sfx_t *sfx = block->sfx; - void (*resample)(sfxbuffer_t *, byte *, int, void *); + void (*resample)(sfxbuffer_t *, byte *, int); wavinfo_t *info = &block->wavinfo; switch (info->channels) { @@ -183,7 +183,7 @@ vorbis_load (OggVorbis_File *vf, sfxblock_t *block, cache_allocator_t allocator) if (vorbis_read (vf, data, info->datalen) < 0) goto bail; SND_SetPaint (sc); - resample (sc, data, info->samples, 0); + resample (sc, data, info->samples); sc->head = sc->length; bail: if (data) diff --git a/libs/audio/renderer/wav.c b/libs/audio/renderer/wav.c index be166650c..542e381a5 100644 --- a/libs/audio/renderer/wav.c +++ b/libs/audio/renderer/wav.c @@ -73,9 +73,9 @@ wav_callback_load (void *object, cache_allocator_t allocator) buffer->sfx = sfx; SND_SetPaint (buffer); if (info->channels == 2) - SND_ResampleStereo (buffer, data, info->samples, 0); + SND_ResampleStereo (buffer, data, info->samples); else - SND_ResampleMono (buffer, data, info->samples, 0); + SND_ResampleMono (buffer, data, info->samples); buffer->head = buffer->length; free (data); }