resampling now works

However, no fallback for when libsamplerate is missing.
This commit is contained in:
Bill Currie 2010-08-11 23:47:03 +00:00 committed by Jeff Teunissen
parent 1c985bc925
commit 22e8698827
8 changed files with 216 additions and 129 deletions

View file

@ -134,31 +134,33 @@ struct sfxstream_s {
void *file; //!< handle for "file" representing the stream
wavinfo_t wavinfo; //!< description of sound data
unsigned pos; //!< position of next frame full stream
/** resampler state information */
void *state;
/** Resample raw data into internal format.
\param sc buffer to write resampled sound (sfxstream_s::buffer)
\param data raw sample data
\param length number of frames to resample
\param prev pointer to end of last resample for smoothing
*/
int (*resample)(sfxbuffer_t *, float *, int);
void *state; //!< resampler state information
/** Read data from the stream.
\param file handle for "file" representing the stream
(sfxstream_s::file)
This is a low-level function used by sfxstream_t::read. The read
samples will be at the sample rate of the underlying stream.
\param cb_data stream relevant infomation (actually ::sfxstream_t
("this"), but this signature is used for compatibility
with libsamplerate
\param data address of pointer to be set to point to the buffer
holding the samples
*/
long (*ll_read)(void *cb_data, float **data);
/** Read data from the stream.
This is a high-level function for use in the mixer. The read samples
will always at be the correct sample rate for the mixer, reguardless
of the sample rate in the underlying stream.
\param stream "this"
\param data destination of read data
\param frames number of frames to read from stream
\param info description of sound data (sfxstream_s::wavinfo)
\param frames maximum number of frames to read from stream
\return number of frames read from stream
*/
int (*read)(void *file, float *data, int frames, wavinfo_t *info);
int (*read)(sfxstream_t *stream, float *data, int frames);
/** Seek to an absolute position within the stream.
\param file handle for "file" representing the stream
(sfxstream_s::file)
\param stream "this"
\param pos frame position with the stream
\param info description of sound data (sfxstream_s::wavinfo)
*/
int (*seek)(void *file, int pos, wavinfo_t *info);
int (*seek)(sfxstream_t *stream, int pos);
sfxbuffer_t buffer; //<! stream's ring buffer
};
@ -250,10 +252,15 @@ void SND_SFX_Stream (sfx_t *sfx, char *realname, wavinfo_t info,
\param close
*/
sfx_t *SND_SFX_StreamOpen (sfx_t *sfx, void *file,
int (*read)(void *, float *, int, wavinfo_t *),
int (*seek)(void *, int, wavinfo_t *),
long (*read)(void *, float **),
int (*seek)(sfxstream_t *, int),
void (*close) (sfx_t *));
/** Close a stream.
\param sfx
*/
void SND_SFX_StreamClose (sfx_t *sfx);
/** Pre-load a sound into the cache.
\param sample name of sound to precache
*/
@ -403,6 +410,11 @@ void SND_SetPaint (sfxbuffer_t *sc);
*/
void SND_SetupResampler (sfxbuffer_t *sc, int streamed);
/** Free memory allocated for the resampler.
\param stream stream to pulldown
*/
void SND_PulldownResampler (sfxstream_t *stream);
/** Copy/resample data into buffer, resampling as necessary.
\param sc buffer to write resampled sound
\param data raw sample data
@ -543,7 +555,6 @@ void SND_StreamSetPos (sfxbuffer_t *buffer, unsigned int pos);
/** Allocate a sound buffer from cache for cached sounds.
\param samples size in samples
\param rate sample rate
\param inwidth bits per sample of input data
\param channels number of channels in input data
\param block cached sound descriptor to initialize
\param allocator cache allocator function

View file

@ -335,16 +335,20 @@ flac_cache (sfx_t *sfx, char *realname, flacfile_t *ff, wavinfo_t info)
SND_SFX_Cache (sfx, realname, info, flac_callback_load);
}
static int
flac_stream_read (void *file, float *buf, int count, wavinfo_t *info)
static long
flac_stream_read (void *file, float **buf)
{
return flac_read (file, buf, count);
sfxstream_t *stream = (sfxstream_t *) file;
flacfile_t *ff = (flacfile_t *) stream->file;
FLAC__stream_decoder_process_single (ff->decoder);
*buf = ff->buffer;
return ff->size;
}
static int
flac_stream_seek (void *file, int pos, wavinfo_t *info)
flac_stream_seek (sfxstream_t *stream, int pos)
{
flacfile_t *ff = file;
flacfile_t *ff = stream->file;
ff->pos = ff->size = 0;
return FLAC__stream_decoder_seek_absolute (ff->decoder, pos);
@ -356,8 +360,7 @@ flac_stream_close (sfx_t *sfx)
sfxstream_t *stream = sfx->data.stream;
flac_close (stream->file);
free (stream);
free (sfx);
SND_SFX_StreamClose (sfx);
}
static sfx_t *

View file

@ -47,6 +47,15 @@ static __attribute__ ((used)) const char rcsid[] =
#include "snd_render.h"
#define FRAMES 1024
#define CHANNELS 2
#define WIDTH 2
typedef struct {
float data[FRAMES * CHANNELS];
midi *handle;
} midi_file_t;
static int midi_intiialized = 0;
static cvar_t *wildmidi_volume;
@ -88,48 +97,46 @@ midi_get_info (void * handle) {
return info;
}
static int
midi_stream_read (void *file, float *buf, int count, wavinfo_t *info)
static long
midi_stream_read (void *file, float **buf)
{
int size = count * info->channels * info->width;
sfxstream_t *stream = (sfxstream_t *) file;
midi_file_t *mf = (midi_file_t *) stream->file;
int size = FRAMES * CHANNELS * WIDTH;
int res;
byte *data = alloca (size);
res = WildMidi_GetOutput (file, (char *)data, size);
if (res > 0) {
res /= info->channels * info->width;
SND_Convert (data, buf, res, info->channels, info->width);
}
res = WildMidi_GetOutput (mf->handle, (char *)data, size);
if (res < 0)
return res;
res /= CHANNELS * WIDTH;
SND_Convert (data, mf->data, res, CHANNELS, WIDTH);
*buf = mf->data;
return res;
}
static int
midi_stream_seek (void *file, int pos, wavinfo_t *info)
midi_stream_seek (sfxstream_t *stream, int pos)
{
unsigned long int new_pos;
pos *= info->width * info->channels;
pos += info->dataofs;
pos *= stream->wavinfo.width * stream->wavinfo.channels;
pos += stream->wavinfo.dataofs;
new_pos = pos;
return WildMidi_SampledSeek(file, &new_pos);
return WildMidi_SampledSeek(stream->file, &new_pos);
}
static void
midi_stream_close (sfx_t *sfx)
{
sfxstream_t *stream = sfx->data.stream;
midi_file_t *mf = (midi_file_t *) stream->file;
WildMidi_Close (stream->file);
free (stream);
free (sfx);
WildMidi_Close (mf->handle);
free (mf);
SND_SFX_StreamClose (sfx);
}
/*
* Note: we set up only the QF stream here.
* The WildMidi stream was setup when SND_OpenMidi was called
* so stream->file contains the WildMidi handle for the midi
*/
static sfx_t *
midi_stream_open (sfx_t *sfx)
{
@ -138,6 +145,7 @@ midi_stream_open (sfx_t *sfx)
midi *handle;
unsigned char *local_buffer;
unsigned long int local_buffer_size;
midi_file_t *mf;
QFS_FOpenFile (stream->file, &file);
@ -152,7 +160,10 @@ midi_stream_open (sfx_t *sfx)
if (handle == NULL)
return NULL;
return SND_SFX_StreamOpen (sfx, handle, midi_stream_read, midi_stream_seek,
mf = calloc (sizeof (midi_file_t), 1);
mf->handle = handle;
return SND_SFX_StreamOpen (sfx, mf, midi_stream_read, midi_stream_seek,
midi_stream_close);
}

View file

@ -165,36 +165,15 @@ read_samples (sfxbuffer_t *buffer, int count)
read_samples (buffer, buffer->length - buffer->head);
read_samples (buffer, count);
} else {
float stepscale;
int frames, size;
sfx_t *sfx = buffer->sfx;
sfxstream_t *stream = sfx->data.stream;
wavinfo_t *info = &stream->wavinfo;
float *data = buffer->data + buffer->head * info->channels;
int c;
stepscale = (float) info->rate / snd_shm->speed;
if ((c = stream->read (stream, data, count)) != count)
Sys_Printf ("%s nr %d %d\n", sfx->name, count, c);
frames = count * stepscale;
size = frames * info->channels * sizeof (float);
if (stream->resample) {
float *data = alloca (size);
int c;
if (stream->read (stream->file, data, frames, info) != frames)
Sys_Printf ("%s r\n", sfx->name);
c = stream->resample (buffer, data, frames);
if (c < count) {
data = buffer->data + (buffer->head + c - 1) * info->channels;
while (c++ < count) {
memcpy (data + info->channels, data,
info->channels * sizeof (float));
}
}
} else {
float *data = buffer->data + buffer->head * info->channels;
if (stream->read (stream->file, data, frames, info) != frames)
Sys_Printf ("%s nr\n", sfx->name);
}
buffer->head += count;
if (buffer->head >= buffer->length)
buffer->head -= buffer->length;
@ -224,7 +203,7 @@ fill_buffer (sfx_t *sfx, sfxstream_t *stream, sfxbuffer_t *buffer,
if (samples)
read_samples (buffer, samples);
if (loop_samples) {
stream->seek (stream->file, info->loopstart, info);
stream->seek (stream, info->loopstart);
read_samples (buffer, loop_samples);
}
}
@ -242,7 +221,7 @@ SND_StreamSetPos (sfxbuffer_t *buffer, unsigned int pos)
buffer->head = buffer->tail = 0;
buffer->pos = pos;
stream->pos = pos;
stream->seek (stream->file, buffer->pos * stepscale, info);
stream->seek (stream, buffer->pos * stepscale);
fill_buffer (sfx, stream, buffer, info, pos);
}
@ -291,7 +270,7 @@ SND_StreamAdvance (sfxbuffer_t *buffer, unsigned int count)
stream->pos = buffer->pos;
}
headpos = buffer->pos;
stream->seek (stream->file, buffer->pos * stepscale, info);
stream->seek (stream, buffer->pos * stepscale);
} else {
buffer->pos += count;
if (buffer->pos >= sfx->length) {
@ -300,7 +279,7 @@ SND_StreamAdvance (sfxbuffer_t *buffer, unsigned int count)
headpos = buffer->pos = 0;
buffer->head = buffer->tail = 0;
count = 0;
stream->seek (stream->file, buffer->pos * stepscale, info);
stream->seek (stream, buffer->pos * stepscale);
} else {
buffer->pos -= sfx->length - sfx->loopstart;
}

View file

@ -50,6 +50,12 @@ static __attribute__ ((used)) const char rcsid[] =
#include "compat.h"
#include "snd_render.h"
typedef struct {
float *data;
int size;
int pos;
} snd_null_state_t;
static void
check_buffer_integrity (sfxbuffer_t *sc, int width, const char *func)
{
@ -85,28 +91,40 @@ SND_Resample (sfxbuffer_t *sc, float *data, int length)
}
static int
SND_ResampleStream (sfxbuffer_t *sc, float *data, int length)
snd_read (sfxstream_t *stream, float *data, int frames)
{
SRC_DATA src_data;
SRC_STATE *state = (SRC_STATE *) sc->sfx->data.stream->state;
snd_null_state_t *state = (snd_null_state_t *) stream->state;
int channels = stream->buffer.channels;
int framesize = channels * sizeof (float);
int count;
int read = 0;
int outcount;
double stepscale;
wavinfo_t *info = sc->sfx->wavinfo (sc->sfx);
int inrate = info->rate;
while (frames) {
if (state->pos == state->size) {
state->size = stream->ll_read (stream, &state->data);
if (state->size <= 0)
return state->size;
state->pos = 0;
}
count = frames;
if (count > state->size - state->pos)
count = state->size - state->pos;
memcpy (data, state->data + state->pos * channels, count * framesize);
state->pos += count;
frames -= count;
read += count;
data += count * channels;
}
return read;
}
stepscale = (double) snd_shm->speed / inrate;
outcount = length * stepscale;
static int
snd_resample_read (sfxstream_t *stream, float *data, int frames)
{
int inrate = stream->wavinfo.rate;
double ratio = (double) snd_shm->speed / inrate;
src_data.data_in = data;
src_data.data_out = sc->data + sc->head * sc->channels;
src_data.input_frames = length;
src_data.output_frames = outcount;
src_data.src_ratio = stepscale;
src_data.end_of_input = 0; //XXX
src_process (state, &src_data);
return src_data.output_frames_gen;
return src_callback_read (stream->state, ratio, frames, data);
}
void
@ -131,15 +149,27 @@ SND_SetupResampler (sfxbuffer_t *sc, int streamed)
sfxstream_t *stream = sc->sfx->data.stream;
if (snd_shm->speed == inrate) {
stream->state = 0;
stream->resample = 0;
stream->state = calloc (sizeof (snd_null_state_t), 1);
stream->read = snd_read;
} else {
stream->state = src_new (SRC_LINEAR, info->channels, &err);
stream->resample = SND_ResampleStream;
stream->state = src_callback_new (stream->ll_read,
SRC_LINEAR, info->channels,
&err, stream);
stream->read = snd_resample_read;
}
}
}
void
SND_PulldownResampler (sfxstream_t *stream)
{
if (stream->read == snd_resample_read) {
src_delete (stream->state);
} else {
free (stream->state);
}
}
void
SND_Convert (byte *idata, float *fdata, int frames, int channels, int width)
{

View file

@ -111,8 +111,8 @@ SND_SFX_Stream (sfx_t *sfx, char *realname, wavinfo_t info,
sfx_t *
SND_SFX_StreamOpen (sfx_t *sfx, void *file,
int (*read)(void *, float *, int, wavinfo_t *),
int (*seek)(void *, int, wavinfo_t *),
long (*read)(void *, float **),
int (*seek)(sfxstream_t *, int),
void (*close) (sfx_t *))
{
sfxstream_t *stream = sfx->data.stream;
@ -139,7 +139,7 @@ SND_SFX_StreamOpen (sfx_t *sfx, void *file,
memcpy ((byte *) stream->buffer.data + size, "\xde\xad\xbe\xef", 4);
stream->file = file;
stream->sfx = new_sfx;
stream->read = read;
stream->ll_read = read;
stream->seek = seek;
stream->wavinfo = *sfx->wavinfo (sfx);
@ -156,6 +156,15 @@ SND_SFX_StreamOpen (sfx_t *sfx, void *file,
return new_sfx;
}
void
SND_SFX_StreamClose (sfx_t *sfx)
{
sfxstream_t *stream = sfx->data.stream;
SND_PulldownResampler (stream);
free (stream);
free (sfx);
}
sfx_t *
SND_LoadSound (const char *name)
{

View file

@ -51,6 +51,13 @@ static __attribute__ ((used)) const char rcsid[] =
#include "snd_render.h"
#define FRAMES 1024
typedef struct {
float *data;
OggVorbis_File *vf;
} vorbis_file_t;
static size_t
vorbis_read_func (void *ptr, size_t size, size_t nmemb, void *datasource)
{
@ -211,26 +218,40 @@ vorbis_cache (sfx_t *sfx, char *realname, OggVorbis_File *vf, wavinfo_t info)
SND_SFX_Cache (sfx, realname, info, vorbis_callback_load);
}
static int
vorbis_stream_read (void *file, float *buf, int count, wavinfo_t *info)
static long
vorbis_stream_read (void *file, float **buf)
{
return vorbis_read (file, buf, count, info);
sfxstream_t *stream = (sfxstream_t *) file;
vorbis_file_t *vf = (vorbis_file_t *) stream->file;
int res;
if (!vf->data)
vf->data = malloc (FRAMES * stream->wavinfo.channels * sizeof (float));
res = vorbis_read (vf->vf, vf->data, FRAMES, &stream->wavinfo);
if (res <= 0)
return res;
*buf = vf->data;
return res;
}
static int
vorbis_stream_seek (void *file, int pos, wavinfo_t *info)
vorbis_stream_seek (sfxstream_t *stream, int pos)
{
return ov_pcm_seek (file, pos);
vorbis_file_t *vf = (vorbis_file_t *) stream->file;
return ov_pcm_seek (vf->vf, pos);
}
static void
vorbis_stream_close (sfx_t *sfx)
{
sfxstream_t *stream = sfx->data.stream;
vorbis_file_t *vf = (vorbis_file_t *) stream->file;
ov_clear (stream->file);
free (stream);
free (sfx);
if (vf->data)
free (vf->data);
ov_clear (vf->vf);
free (vf);
SND_SFX_StreamClose (sfx);
}
static sfx_t *
@ -238,14 +259,15 @@ vorbis_stream_open (sfx_t *sfx)
{
sfxstream_t *stream = sfx->data.stream;
QFile *file;
void *f;
vorbis_file_t *f;
QFS_FOpenFile (stream->file, &file);
if (!file)
return 0;
f = malloc (sizeof (OggVorbis_File));
if (ov_open_callbacks (file, f, 0, 0, callbacks) < 0) {
f = calloc (sizeof (vorbis_file_t), 1);
f->vf = malloc (sizeof (OggVorbis_File));
if (ov_open_callbacks (file, f->vf, 0, 0, callbacks) < 0) {
Sys_Printf ("Input does not appear to be an Ogg bitstream.\n");
Qclose (file);
free (f);

View file

@ -48,6 +48,13 @@ static __attribute__ ((used)) const char rcsid[] =
#include "snd_render.h"
#define FRAMES 1024
typedef struct {
float *data;
QFile *file;
} wav_file_t;
static void
wav_callback_load (void *object, cache_allocator_t allocator)
{
@ -91,37 +98,49 @@ wav_cache (sfx_t *sfx, char *realname, void *file, wavinfo_t info)
SND_SFX_Cache (sfx, realname, info, wav_callback_load);
}
static int
wav_stream_read (void *file, float *buf, int count, wavinfo_t *info)
static long
wav_stream_read (void *file, float **buf)
{
sfxstream_t *stream = (sfxstream_t *) file;
wavinfo_t *info = &stream->wavinfo;
wav_file_t *wf = (wav_file_t *) stream->file;
int res;
int len = count * info->channels * info->width;
int len = FRAMES * info->channels * info->width;
byte *data = alloca (len);
res = Qread (file, data, len);
if (res > 0) {
res /= (info->channels * info->width);
SND_Convert (data, buf, res, info->channels, info->width);
}
if (!wf->data)
wf->data = malloc (FRAMES * info->channels * sizeof (float));
res = Qread (wf->file, data, len);
if (res <= 0)
return res;
res /= (info->channels * info->width);
SND_Convert (data, wf->data, res, info->channels, info->width);
*buf = wf->data;
return res;
}
static int
wav_stream_seek (void *file, int pos, wavinfo_t *info)
wav_stream_seek (sfxstream_t *stream, int pos)
{
wavinfo_t *info = &stream->wavinfo;
wav_file_t *wf = (wav_file_t *) stream->file;
pos *= info->width * info->channels;
pos += info->dataofs;
return Qseek (file, pos, SEEK_SET);
return Qseek (wf->file, pos, SEEK_SET);
}
static void
wav_stream_close (sfx_t *sfx)
{
sfxstream_t *stream = sfx->data.stream;
wav_file_t *wf = (wav_file_t *) stream->file;
Qclose (stream->file);
free (stream);
free (sfx);
Qclose (wf->file);
if (wf->data)
free (wf->data);
free (wf);
SND_SFX_StreamClose (sfx);
}
static sfx_t *
@ -129,12 +148,15 @@ wav_stream_open (sfx_t *sfx)
{
sfxstream_t *stream = sfx->data.stream;
QFile *file;
wav_file_t *wf;
QFS_FOpenFile (stream->file, &file);
if (!file)
return 0;
return SND_SFX_StreamOpen (sfx, file, wav_stream_read, wav_stream_seek,
wf = calloc (sizeof (wav_file_t), 1);
wf->file = file;
return SND_SFX_StreamOpen (sfx, wf, wav_stream_read, wav_stream_seek,
wav_stream_close);
}