mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-01-17 22:50:51 +00:00
streams getting closer, not working yet, though
This commit is contained in:
parent
105ef11e0e
commit
1b2d7b79a6
3 changed files with 171 additions and 30 deletions
|
@ -67,6 +67,7 @@ typedef struct sfxstream_s {
|
||||||
sfx_t *sfx;
|
sfx_t *sfx;
|
||||||
void *file;
|
void *file;
|
||||||
wavinfo_t wavinfo;
|
wavinfo_t wavinfo;
|
||||||
|
void (*resample)(sfxbuffer_t *, byte *, int);
|
||||||
sfxbuffer_t buffer;
|
sfxbuffer_t buffer;
|
||||||
} sfxstream_t;
|
} sfxstream_t;
|
||||||
|
|
||||||
|
|
|
@ -195,12 +195,15 @@ SND_ResampleMono (sfxbuffer_t *sc, byte *data, int length)
|
||||||
ib = data;
|
ib = data;
|
||||||
ob = sc->data;
|
ob = sc->data;
|
||||||
|
|
||||||
|
os += sc->head;
|
||||||
|
ob += sc->head;
|
||||||
|
|
||||||
stepscale = (float) inrate / shm->speed; // usually 0.5, 1, or 2
|
stepscale = (float) inrate / shm->speed; // usually 0.5, 1, or 2
|
||||||
|
|
||||||
outcount = length / stepscale;
|
outcount = length / stepscale;
|
||||||
//printf ("%d %d\n", length, outcount);
|
//printf ("%d %d\n", length, outcount);
|
||||||
|
|
||||||
sc->sfx->length = outcount;
|
sc->sfx->length = info->samples / stepscale;
|
||||||
if (info->loopstart != -1)
|
if (info->loopstart != -1)
|
||||||
sc->sfx->loopstart = info->loopstart / stepscale;
|
sc->sfx->loopstart = info->loopstart / stepscale;
|
||||||
else
|
else
|
||||||
|
@ -285,7 +288,7 @@ SND_ResampleMono (sfxbuffer_t *sc, byte *data, int length)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
byte *x = sc->data + outcount * outwidth;
|
byte *x = sc->data + sc->length * outwidth;
|
||||||
if (memcmp (x, "\xde\xad\xbe\xef", 4))
|
if (memcmp (x, "\xde\xad\xbe\xef", 4))
|
||||||
Sys_Error ("SND_ResampleMono screwed the pooch %02x%02x%02x%02x",
|
Sys_Error ("SND_ResampleMono screwed the pooch %02x%02x%02x%02x",
|
||||||
x[0], x[1], x[2], x[3]);
|
x[0], x[1], x[2], x[3]);
|
||||||
|
@ -309,11 +312,14 @@ SND_ResampleStereo (sfxbuffer_t *sc, byte *data, int length)
|
||||||
ib = (stereo8_t *) data;
|
ib = (stereo8_t *) data;
|
||||||
ob = (stereo8_t *) sc->data;
|
ob = (stereo8_t *) sc->data;
|
||||||
|
|
||||||
|
os += sc->head;
|
||||||
|
ob += sc->head;
|
||||||
|
|
||||||
stepscale = (float) inrate / shm->speed; // usually 0.5, 1, or 2
|
stepscale = (float) inrate / shm->speed; // usually 0.5, 1, or 2
|
||||||
|
|
||||||
outcount = length / stepscale;
|
outcount = length / stepscale;
|
||||||
|
|
||||||
sc->sfx->length = outcount;
|
sc->sfx->length = info->samples / stepscale;
|
||||||
if (info->loopstart != -1)
|
if (info->loopstart != -1)
|
||||||
sc->sfx->loopstart = info->loopstart / stepscale;
|
sc->sfx->loopstart = info->loopstart / stepscale;
|
||||||
else
|
else
|
||||||
|
|
|
@ -88,11 +88,11 @@ static ov_callbacks callbacks = {
|
||||||
static wavinfo_t
|
static wavinfo_t
|
||||||
get_info (OggVorbis_File *vf)
|
get_info (OggVorbis_File *vf)
|
||||||
{
|
{
|
||||||
wavinfo_t info;
|
|
||||||
vorbis_info *vi;
|
vorbis_info *vi;
|
||||||
int sample_start = -1, sample_count = 0;
|
int sample_start = -1, sample_count = 0;
|
||||||
int samples;
|
int samples;
|
||||||
char **ptr;
|
char **ptr;
|
||||||
|
wavinfo_t info;
|
||||||
|
|
||||||
vi = ov_info (vf, -1);
|
vi = ov_info (vf, -1);
|
||||||
samples = ov_pcm_total (vf, -1);
|
samples = ov_pcm_total (vf, -1);
|
||||||
|
@ -156,11 +156,9 @@ load_ogg (OggVorbis_File *vf, sfxblock_t *block, cache_allocator_t allocator)
|
||||||
sfxbuffer_t *sc = 0;
|
sfxbuffer_t *sc = 0;
|
||||||
sfx_t *sfx = block->sfx;
|
sfx_t *sfx = block->sfx;
|
||||||
void (*resample)(sfxbuffer_t *, byte *, int);
|
void (*resample)(sfxbuffer_t *, byte *, int);
|
||||||
wavinfo_t info;
|
wavinfo_t *info = &block->wavinfo;
|
||||||
|
|
||||||
info = get_info (vf);
|
switch (info->channels) {
|
||||||
|
|
||||||
switch (info.channels) {
|
|
||||||
case 1:
|
case 1:
|
||||||
resample = SND_ResampleMono;
|
resample = SND_ResampleMono;
|
||||||
break;
|
break;
|
||||||
|
@ -169,22 +167,21 @@ load_ogg (OggVorbis_File *vf, sfxblock_t *block, cache_allocator_t allocator)
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
Sys_Printf ("%s: unsupported channel count: %d\n",
|
Sys_Printf ("%s: unsupported channel count: %d\n",
|
||||||
sfx->name, info.channels);
|
sfx->name, info->channels);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
data = malloc (info.datalen);
|
data = malloc (info->datalen);
|
||||||
if (!data)
|
if (!data)
|
||||||
goto bail;
|
goto bail;
|
||||||
sc = SND_GetCache (info.samples, info.rate, info.width, info.channels,
|
sc = SND_GetCache (info->samples, info->rate, info->width, info->channels,
|
||||||
block, allocator);
|
block, allocator);
|
||||||
if (!sc)
|
if (!sc)
|
||||||
goto bail;
|
goto bail;
|
||||||
sc->sfx = sfx;
|
sc->sfx = sfx;
|
||||||
if (read_ogg (vf, data, info.datalen) < 0)
|
if (read_ogg (vf, data, info->datalen) < 0)
|
||||||
goto bail;
|
goto bail;
|
||||||
block->wavinfo = info;
|
resample (sc, data, info->samples);
|
||||||
resample (sc, data, info.samples);
|
|
||||||
sc->length = sc->head = sfx->length;
|
sc->length = sc->head = sfx->length;
|
||||||
bail:
|
bail:
|
||||||
if (data)
|
if (data)
|
||||||
|
@ -214,14 +211,156 @@ ogg_callback_load (void *object, cache_allocator_t allocator)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
stream_ogg (sfx_t *sfx, OggVorbis_File *vf)
|
cache_ogg (sfx_t *sfx, char *realname, OggVorbis_File *vf, wavinfo_t info)
|
||||||
{
|
{
|
||||||
|
sfxblock_t *block = calloc (1, sizeof (sfxblock_t));
|
||||||
|
ov_clear (vf);
|
||||||
|
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, ogg_callback_load);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fill_buffer (sfxbuffer_t *buffer, int count)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ogg_advance (sfxbuffer_t *buffer, int count)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
stream_ogg (sfx_t *sfx, char *realname, OggVorbis_File *vf, 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 = vf;
|
||||||
|
stream->resample = info.channels == 2 ? SND_ResampleStereo
|
||||||
|
: SND_ResampleMono;
|
||||||
|
stream->wavinfo = info;
|
||||||
|
|
||||||
|
stream->buffer.length = samples;
|
||||||
|
stream->buffer.advance = ogg_advance;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
SND_LoadOgg (QFile *file, sfx_t *sfx, char *realname)
|
SND_LoadOgg (QFile *file, sfx_t *sfx, char *realname)
|
||||||
{
|
{
|
||||||
OggVorbis_File vf;
|
OggVorbis_File vf;
|
||||||
|
wavinfo_t info;
|
||||||
|
|
||||||
if (ov_open_callbacks (file, &vf, 0, 0, callbacks) < 0) {
|
if (ov_open_callbacks (file, &vf, 0, 0, callbacks) < 0) {
|
||||||
Sys_Printf ("Input does not appear to be an Ogg bitstream.\n");
|
Sys_Printf ("Input does not appear to be an Ogg bitstream.\n");
|
||||||
|
@ -229,22 +368,17 @@ SND_LoadOgg (QFile *file, sfx_t *sfx, char *realname)
|
||||||
free (realname);
|
free (realname);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (ov_pcm_total (&vf, -1) < 8 * shm->speed) {
|
info = get_info (&vf);
|
||||||
sfxblock_t *block = calloc (1, sizeof (sfxblock_t));
|
if (info.channels < 1 || info.channels > 2) {
|
||||||
ov_clear (&vf);
|
Sys_Printf ("unsupported number of channels");
|
||||||
sfx->data = block;
|
return;
|
||||||
sfx->wavinfo = SND_CacheWavinfo;
|
}
|
||||||
sfx->touch = SND_CacheTouch;
|
if (info.samples / info.rate < 3) {
|
||||||
sfx->retain = SND_CacheRetain;
|
printf ("cache %s\n", realname);
|
||||||
sfx->release = SND_CacheRelease;
|
cache_ogg (sfx, realname, &vf, info);
|
||||||
block->sfx = sfx;
|
|
||||||
block->file = realname;
|
|
||||||
Cache_Add (&block->cache, block, ogg_callback_load);
|
|
||||||
} else {
|
} else {
|
||||||
sfx->touch = sfx->retain = SND_StreamRetain;
|
printf ("stream %s\n", realname);
|
||||||
sfx->release = SND_StreamRelease;
|
stream_ogg (sfx, realname, &vf, info);
|
||||||
free (realname);
|
|
||||||
stream_ogg (sfx, &vf);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue