From aab4dcf931f63829664d430d15ce2d24ad6a846a Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 14 Apr 2003 06:11:53 +0000 Subject: [PATCH] getting there with streams. just need to get the painters working, I think. (streaming currently disabled for anything < 30s :) --- include/snd_render.h | 3 + libs/audio/renderer/snd_mem.c | 109 ++++++++++++++++++++++++++++ libs/audio/renderer/vorbis.c | 131 +++++++--------------------------- libs/audio/renderer/wav.c | 92 +++++++++++++++++++----- 4 files changed, 211 insertions(+), 124 deletions(-) diff --git a/include/snd_render.h b/include/snd_render.h index ea3df7c39..163306f97 100644 --- a/include/snd_render.h +++ b/include/snd_render.h @@ -68,6 +68,8 @@ typedef struct sfxstream_s { void *file; wavinfo_t wavinfo; void (*resample)(sfxbuffer_t *, byte *, int); + int (*read)(void *file, byte *data, int bytes, wavinfo_t *info); + int (*seek)(void *file, int pos, wavinfo_t *info); sfxbuffer_t buffer; } sfxstream_t; @@ -142,6 +144,7 @@ sfxbuffer_t *SND_CacheRetain (sfx_t *sfx); void SND_CacheRelease (sfx_t *sfx); sfxbuffer_t *SND_StreamRetain (sfx_t *sfx); void SND_StreamRelease (sfx_t *sfx); +void SND_StreamAdvance (sfxbuffer_t *buffer, int count); void SND_WriteLinearBlastStereo16 (void); void SND_PaintChannelFrom8 (channel_t *ch, sfxbuffer_t *sc, int count); diff --git a/libs/audio/renderer/snd_mem.c b/libs/audio/renderer/snd_mem.c index 14dfe6069..84330ad56 100644 --- a/libs/audio/renderer/snd_mem.c +++ b/libs/audio/renderer/snd_mem.c @@ -110,6 +110,114 @@ SND_StreamWavinfo (sfx_t *sfx) return &((sfxstream_t *) sfx->data)->wavinfo; } +static void +read_samples (sfxbuffer_t *buffer, int count) +{ + if (buffer->head + count > buffer->length) { + count -= buffer->length - buffer->head; + read_samples (buffer, buffer->length - buffer->head); + } else { + byte *data; + float stepscale; + int samples, size; + sfx_t *sfx = buffer->sfx; + sfxstream_t *stream = (sfxstream_t *) sfx->data; + wavinfo_t *info = &stream->wavinfo; + + stepscale = (float) info->rate / shm->speed; // usually 0.5, 1, or 2 + + samples = count * stepscale; + size = samples * info->width * info->channels; + data = alloca (size); + + stream->read (stream->file, data, size, info); + stream->resample (buffer, data, samples); + buffer->head += count; + if (buffer->head >= buffer->length) + buffer->head -= buffer->length; + } +} + +void +SND_StreamAdvance (sfxbuffer_t *buffer, int count) +{ + float stepscale; + int headpos, samples; + int loop_samples = 0; + sfx_t *sfx = buffer->sfx; + sfxstream_t *stream = (sfxstream_t *) sfx->data; + wavinfo_t *info = &stream->wavinfo; + + stepscale = (float) info->rate / shm->speed; // usually 0.5, 1, or 2 + + // find out how many samples the buffer currently holds + samples = buffer->head - buffer->tail; + if (samples < 0) + samples += buffer->length; + + // find out where head points to in the stream + headpos = buffer->pos + samples; + if (headpos >= sfx->length) { + if (sfx->loopstart == -1) + headpos = sfx->length; + else + headpos -= sfx->length - sfx->loopstart; + } + + if (samples < count) { + buffer->head = buffer->tail = 0; + buffer->pos += count; + if (buffer->pos > sfx->length) { + if (sfx->loopstart == -1) { + // reset the buffer and fill it incase it's needed again + headpos = buffer->pos = 0; + } else { + buffer->pos -= sfx->loopstart; + buffer->pos %= sfx->length - sfx->loopstart; + buffer->pos += sfx->loopstart; + } + } + stream->seek (stream->file, buffer->pos * stepscale, info); + } else { + buffer->pos += count; + if (buffer->pos >= sfx->length) { + if (sfx->loopstart == -1) { + // reset the buffer and fill it incase it's needed again + buffer->pos = 0; + buffer->head = buffer->tail = 0; + count = 0; + } else { + buffer->pos -= sfx->length - sfx->loopstart; + } + } + + buffer->tail += count; + if (buffer->tail >= buffer->length) + buffer->tail -= buffer->length; + } + + // find out how many samples can be read into the buffer + samples = buffer->tail - buffer->head - 1; + if (samples < 0) + samples += buffer->length; + + if (headpos + samples > sfx->length) { + if (sfx->loopstart == -1) { + samples = sfx->length - headpos; + } else { + loop_samples = headpos + samples - sfx->length; + samples -= loop_samples; + } + } + if (samples) { + read_samples (buffer, samples); + } + if (loop_samples) { + stream->seek (stream->file, info->loopstart, info); + read_samples (buffer, loop_samples); + } +} + void SND_Load (sfx_t *sfx) { @@ -174,6 +282,7 @@ SND_GetCache (long samples, int rate, int inwidth, int channels, sc = allocator (&block->cache, sizeof (sfxbuffer_t) + size, sfx->name); if (!sc) return 0; + memset (sc, 0, sizeof (sfxbuffer_t) + size); sc->length = len; memcpy (sc->data + size, "\xde\xad\xbe\xef", 4); return sc; diff --git a/libs/audio/renderer/vorbis.c b/libs/audio/renderer/vorbis.c index a12a06637..e498a7f0f 100644 --- a/libs/audio/renderer/vorbis.c +++ b/libs/audio/renderer/vorbis.c @@ -1,7 +1,7 @@ /* vorbis.c - ogg/vorbis support + Ogg Vorbis support Copyright (C) 2001 Bill Currie @@ -127,7 +127,7 @@ get_info (OggVorbis_File *vf) } static int -read_ogg (OggVorbis_File *vf, byte *buf, int len) +vorbis_read (OggVorbis_File *vf, byte *buf, int len) { int count = 0; int current_section; @@ -150,7 +150,7 @@ read_ogg (OggVorbis_File *vf, byte *buf, int len) } static sfxbuffer_t * -load_ogg (OggVorbis_File *vf, sfxblock_t *block, cache_allocator_t allocator) +vorbis_load (OggVorbis_File *vf, sfxblock_t *block, cache_allocator_t allocator) { byte *data; sfxbuffer_t *sc = 0; @@ -179,7 +179,7 @@ load_ogg (OggVorbis_File *vf, sfxblock_t *block, cache_allocator_t allocator) if (!sc) goto bail; sc->sfx = sfx; - if (read_ogg (vf, data, info->datalen) < 0) + if (vorbis_read (vf, data, info->datalen) < 0) goto bail; resample (sc, data, info->samples); sc->head = sc->length; @@ -191,7 +191,7 @@ load_ogg (OggVorbis_File *vf, sfxblock_t *block, cache_allocator_t allocator) } static void -ogg_callback_load (void *object, cache_allocator_t allocator) +vorbis_callback_load (void *object, cache_allocator_t allocator) { QFile *file; OggVorbis_File vf; @@ -207,11 +207,11 @@ ogg_callback_load (void *object, cache_allocator_t allocator) Qclose (file); return; //FIXME Sys_Error? } - load_ogg (&vf, block, allocator); + vorbis_load (&vf, block, allocator); } static void -cache_ogg (sfx_t *sfx, char *realname, OggVorbis_File *vf, wavinfo_t info) +vorbis_cache (sfx_t *sfx, char *realname, OggVorbis_File *vf, wavinfo_t info) { sfxblock_t *block = calloc (1, sizeof (sfxblock_t)); ov_clear (vf); @@ -225,111 +225,27 @@ cache_ogg (sfx_t *sfx, char *realname, OggVorbis_File *vf, wavinfo_t info) block->file = realname; block->wavinfo = info; - Cache_Add (&block->cache, block, ogg_callback_load); + Cache_Add (&block->cache, block, vorbis_callback_load); } -static void -fill_buffer (sfxbuffer_t *buffer, int count) +static int +vorbis_stream_read (void *file, byte *buf, int count, wavinfo_t *info) { - byte data[65536]; - float stepscale; - int bps, bytes, insamples, outsamples; - sfx_t *sfx = buffer->sfx; - sfxstream_t *stream = (sfxstream_t *) sfx->data; - wavinfo_t *info = &stream->wavinfo; - - stepscale = (float) info->rate / shm->speed; - bps = info->width * info->channels; - insamples = sizeof (data) / bps; - outsamples = insamples / stepscale; - - bytes = count * bps * stepscale; - - while (bytes > sizeof (data)) { - read_ogg (stream->file, data, sizeof (data)); - stream->resample (buffer, data, insamples); - buffer->head += outsamples; - count -= outsamples; - bytes -= sizeof (data); - } - - if (bytes) { - int n = bytes / bps; - read_ogg (stream->file, data, bytes); - stream->resample (buffer, data, n); - buffer->head += count; - } + return vorbis_read (file, buf, count); } -static void -ogg_advance (sfxbuffer_t *buffer, int count) +static int +vorbis_stream_seek (void *file, int pos, wavinfo_t *info) { - int headpos, samples; - int post_count = 0; - sfx_t *sfx = buffer->sfx; - sfxstream_t *stream = (sfxstream_t *) sfx->data; - wavinfo_t *info = &stream->wavinfo; - - // find out how many samples the buffer currently holds - samples = buffer->head - buffer->tail; - if (samples < 0) - samples += buffer->length; - - headpos = buffer->pos + samples; - - if (info->loopstart == -1) { - // unlooped sound - if (headpos == sfx->length) - return; // at end of sample, nothing to do - if (headpos + count > sfx->length) - count = sfx->length - headpos; // only advance to end of sample - } else { - // looped sound - if (headpos > sfx->length) { - // already handled the loop, nothing to worry about - } else { - if (headpos + count > sfx->length) { - post_count = headpos + count - sfx->length; - } - } - } - - buffer->pos += count; - if (samples < count) { - buffer->tail = buffer->head = 0; - ov_pcm_seek (stream->file, buffer->pos); - } else { - buffer->tail += count; - if (buffer->tail >= buffer->length) - buffer->tail -= buffer->length; - } - - count -= post_count; - - // find out how many new samples we can fit into the buffer - samples = buffer->tail - buffer->head - 1; - if (samples < 0) - samples += buffer->length; - - while (samples) { - count = buffer->length - buffer->head; - if (count > samples) - count = samples; - samples -= count; - - fill_buffer (buffer, count); - - if (buffer->head >= buffer->length) - buffer->head = buffer->length; - } + return ov_pcm_seek (file, pos); } static void -stream_ogg (sfx_t *sfx, char *realname, OggVorbis_File *vf, wavinfo_t info) +vorbis_stream (sfx_t *sfx, char *realname, OggVorbis_File *vf, wavinfo_t info) { sfxstream_t *stream; - int samples; - int size; + int samples; + int size; samples = size = shm->speed * 0.3; if (!snd_loadas8bit->int_val) @@ -350,10 +266,15 @@ stream_ogg (sfx_t *sfx, char *realname, OggVorbis_File *vf, wavinfo_t info) stream->file = vf; stream->resample = info.channels == 2 ? SND_ResampleStereo : SND_ResampleMono; + stream->read = vorbis_stream_read; + stream->seek = vorbis_stream_seek; stream->wavinfo = info; stream->buffer.length = samples; - stream->buffer.advance = ogg_advance; + stream->buffer.advance = SND_StreamAdvance; + stream->buffer.sfx = sfx; + + stream->buffer.advance (&stream->buffer, 0); } void @@ -373,12 +294,12 @@ SND_LoadOgg (QFile *file, sfx_t *sfx, char *realname) Sys_Printf ("unsupported number of channels"); return; } - if (info.samples / info.rate < 3) { + if (info.samples / info.rate < 30) { printf ("cache %s\n", realname); - cache_ogg (sfx, realname, &vf, info); + vorbis_cache (sfx, realname, &vf, info); } else { printf ("stream %s\n", realname); - stream_ogg (sfx, realname, &vf, info); + vorbis_stream (sfx, realname, &vf, info); } } diff --git a/libs/audio/renderer/wav.c b/libs/audio/renderer/wav.c index 22b3869c1..cb58f3d90 100644 --- a/libs/audio/renderer/wav.c +++ b/libs/audio/renderer/wav.c @@ -80,8 +80,72 @@ wav_callback_load (void *object, cache_allocator_t allocator) } static void -stream_wav (sfx_t *sfx, wavinfo_t info) +wav_cache (sfx_t *sfx, char *realname, void *file, wavinfo_t info) { + sfxblock_t *block = calloc (1, sizeof (sfxblock_t)); + Qclose (file); + sfx->data = block; + sfx->wavinfo = SND_CacheWavinfo; + sfx->touch = SND_CacheTouch; + sfx->retain = SND_CacheRetain; + sfx->release = SND_CacheRelease; + + block->sfx = sfx; + block->file = realname; + block->wavinfo = info; + + Cache_Add (&block->cache, block, wav_callback_load); +} + +static int +wav_stream_read (void *file, byte *buf, int count, wavinfo_t *info) +{ + return Qread (file, buf, count); +} + +static int +wav_stream_seek (void *file, int pos, wavinfo_t *info) +{ + pos *= info->width * info->channels; + pos += info->dataofs; + return Qseek (file, pos, SEEK_SET); +} + +static void +wav_stream (sfx_t *sfx, char *realname, void *file, wavinfo_t info) +{ + sfxstream_t *stream; + int samples; + int size; + + samples = size = shm->speed * 0.3; + if (!snd_loadas8bit->int_val) + size *= 2; + if (info.channels == 2) + size *= 2; + stream = calloc (1, sizeof (sfxstream_t) + size); + memcpy (stream->buffer.data + size, "\xde\xad\xbe\xef", 4); + + free (realname); + + sfx->data = stream; + sfx->wavinfo = SND_CacheWavinfo; + sfx->touch = sfx->retain = SND_StreamRetain; + sfx->release = SND_StreamRelease; + + stream->sfx = sfx; + stream->file = file; + stream->resample = info.channels == 2 ? SND_ResampleStereo + : SND_ResampleMono; + stream->read = wav_stream_read; + stream->seek = wav_stream_seek; + stream->wavinfo = info; + + stream->buffer.length = samples; + stream->buffer.advance = SND_StreamAdvance; + stream->buffer.sfx = sfx; + + stream->buffer.advance (&stream->buffer, 0); } static wavinfo_t @@ -181,7 +245,6 @@ get_info (QFile *file) info.datalen = data->ck.len; bail: - Qclose (file); riff_free (riff); return info; } @@ -192,25 +255,16 @@ SND_LoadWav (QFile *file, sfx_t *sfx, char *realname) wavinfo_t info; info = get_info (file); - if (!info.rate) + if (!info.rate) { + Qclose (file); return; + } - if (sfx->length < 8 * shm->speed) { - sfxblock_t *block = calloc (1, sizeof (sfxblock_t)); - sfx->data = block; - sfx->wavinfo = SND_CacheWavinfo; - sfx->touch = SND_CacheTouch; - sfx->retain = SND_CacheRetain; - sfx->release = SND_CacheRelease; - sfx->data = block; - block->sfx = sfx; - block->file = realname; - block->wavinfo = info; - Cache_Add (&block->cache, block, wav_callback_load); + if (info.samples / info.rate < 30) { + printf ("cache %s\n", realname); + wav_cache (sfx, realname, file, info); } else { - sfx->touch = sfx->retain = SND_StreamRetain; - sfx->release = SND_StreamRelease; - free (realname); - stream_wav (sfx, info); + printf ("stream %s\n", realname); + wav_stream (sfx, realname, file, info); } }