audio: reworked audio streams to have right-hand resampling padding available.
Fixes Bugzilla #3851.
parent
28149e11c8
commit
37d89aa10f
|
@ -31,6 +31,8 @@
|
||||||
#include "../SDL_dataqueue.h"
|
#include "../SDL_dataqueue.h"
|
||||||
#include "SDL_cpuinfo.h"
|
#include "SDL_cpuinfo.h"
|
||||||
|
|
||||||
|
#define DEBUG_AUDIOSTREAM 0
|
||||||
|
|
||||||
#ifdef __SSE3__
|
#ifdef __SSE3__
|
||||||
#define HAVE_SSE3_INTRINSICS 1
|
#define HAVE_SSE3_INTRINSICS 1
|
||||||
#endif
|
#endif
|
||||||
|
@ -467,14 +469,20 @@ SDL_FreeResampleFilter(void)
|
||||||
static int
|
static int
|
||||||
ResamplerPadding(const int inrate, const int outrate)
|
ResamplerPadding(const int inrate, const int outrate)
|
||||||
{
|
{
|
||||||
return (inrate > outrate) ? (int) SDL_ceil(((float) (RESAMPLER_SAMPLES_PER_ZERO_CROSSING * inrate) / ((float) outrate))) : RESAMPLER_SAMPLES_PER_ZERO_CROSSING;
|
if (inrate == outrate) {
|
||||||
|
return 0;
|
||||||
|
} else if (inrate > outrate) {
|
||||||
|
return (int) SDL_ceil(((float) (RESAMPLER_SAMPLES_PER_ZERO_CROSSING * inrate) / ((float) outrate)));
|
||||||
|
}
|
||||||
|
return RESAMPLER_SAMPLES_PER_ZERO_CROSSING;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* lpadding and rpadding are expected to be buffers of (ResamplePadding(inrate, outrate) * chans * sizeof (float)) bytes. */
|
/* lpadding and rpadding are expected to be buffers of (ResamplePadding(inrate, outrate) * chans * sizeof (float)) bytes. */
|
||||||
static int
|
static int
|
||||||
SDL_ResampleAudio(const int chans, const int inrate, const int outrate,
|
SDL_ResampleAudio(const int chans, const int inrate, const int outrate,
|
||||||
float *lpadding, float *rpadding, const float *inbuf,
|
const float *lpadding, const float *rpadding,
|
||||||
const int inbuflen, float *outbuf, const int outbuflen)
|
const float *inbuf, const int inbuflen,
|
||||||
|
float *outbuf, const int outbuflen)
|
||||||
{
|
{
|
||||||
const float outtimeincr = 1.0f / ((float) outrate);
|
const float outtimeincr = 1.0f / ((float) outrate);
|
||||||
const float ratio = ((float) outrate) / ((float) inrate);
|
const float ratio = ((float) outrate) / ((float) inrate);
|
||||||
|
@ -483,7 +491,7 @@ SDL_ResampleAudio(const int chans, const int inrate, const int outrate,
|
||||||
const int inframes = inbuflen / framelen;
|
const int inframes = inbuflen / framelen;
|
||||||
const int wantedoutframes = (int) ((inbuflen / framelen) * ratio); /* outbuflen isn't total to write, it's total available. */
|
const int wantedoutframes = (int) ((inbuflen / framelen) * ratio); /* outbuflen isn't total to write, it's total available. */
|
||||||
const int maxoutframes = outbuflen / framelen;
|
const int maxoutframes = outbuflen / framelen;
|
||||||
const int outframes = (wantedoutframes < maxoutframes) ? wantedoutframes : maxoutframes;
|
const int outframes = SDL_min(wantedoutframes, maxoutframes);
|
||||||
float *dst = outbuf;
|
float *dst = outbuf;
|
||||||
float outtime = 0.0f;
|
float outtime = 0.0f;
|
||||||
int i, j, chan;
|
int i, j, chan;
|
||||||
|
@ -1076,6 +1084,7 @@ struct SDL_AudioStream
|
||||||
SDL_AudioCVT cvt_before_resampling;
|
SDL_AudioCVT cvt_before_resampling;
|
||||||
SDL_AudioCVT cvt_after_resampling;
|
SDL_AudioCVT cvt_after_resampling;
|
||||||
SDL_DataQueue *queue;
|
SDL_DataQueue *queue;
|
||||||
|
SDL_bool first_run;
|
||||||
Uint8 *work_buffer_base; /* maybe unaligned pointer from SDL_realloc(). */
|
Uint8 *work_buffer_base; /* maybe unaligned pointer from SDL_realloc(). */
|
||||||
int work_buffer_len;
|
int work_buffer_len;
|
||||||
int src_sample_frame_size;
|
int src_sample_frame_size;
|
||||||
|
@ -1089,6 +1098,8 @@ struct SDL_AudioStream
|
||||||
double rate_incr;
|
double rate_incr;
|
||||||
Uint8 pre_resample_channels;
|
Uint8 pre_resample_channels;
|
||||||
int packetlen;
|
int packetlen;
|
||||||
|
int resampler_padding_samples;
|
||||||
|
float *resampler_padding;
|
||||||
void *resampler_state;
|
void *resampler_state;
|
||||||
SDL_ResampleAudioStreamFunc resampler_func;
|
SDL_ResampleAudioStreamFunc resampler_func;
|
||||||
SDL_ResetAudioStreamResamplerFunc reset_resampler_func;
|
SDL_ResetAudioStreamResamplerFunc reset_resampler_func;
|
||||||
|
@ -1129,16 +1140,7 @@ SDL_ResampleAudioStream_SRC(SDL_AudioStream *stream, const void *_inbuf, const i
|
||||||
SRC_DATA data;
|
SRC_DATA data;
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
if (inbuf == ((const float *) outbuf)) { /* libsamplerate can't work in-place. */
|
SDL_assert(inbuf != ((const float *) outbuf)); /* SDL_AudioStreamPut() shouldn't allow in-place resamples. */
|
||||||
Uint8 *ptr = EnsureStreamBufferSize(stream, inbuflen + outbuflen);
|
|
||||||
if (ptr == NULL) {
|
|
||||||
SDL_OutOfMemory();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
SDL_memcpy(ptr + outbuflen, ptr, inbuflen);
|
|
||||||
inbuf = (const float *) (ptr + outbuflen);
|
|
||||||
outbuf = (float *) ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
data.data_in = (float *)inbuf; /* Older versions of libsamplerate had a non-const pointer, but didn't write to it */
|
data.data_in = (float *)inbuf; /* Older versions of libsamplerate had a non-const pointer, but didn't write to it */
|
||||||
data.input_frames = inbuflen / framelen;
|
data.input_frames = inbuflen / framelen;
|
||||||
|
@ -1213,54 +1215,32 @@ SetupLibSampleRateResampling(SDL_AudioStream *stream)
|
||||||
static int
|
static int
|
||||||
SDL_ResampleAudioStream(SDL_AudioStream *stream, const void *_inbuf, const int inbuflen, void *_outbuf, const int outbuflen)
|
SDL_ResampleAudioStream(SDL_AudioStream *stream, const void *_inbuf, const int inbuflen, void *_outbuf, const int outbuflen)
|
||||||
{
|
{
|
||||||
|
const Uint8 *inbufend = ((const Uint8 *) _inbuf) + inbuflen;
|
||||||
const float *inbuf = (const float *) _inbuf;
|
const float *inbuf = (const float *) _inbuf;
|
||||||
float *outbuf = (float *) _outbuf;
|
float *outbuf = (float *) _outbuf;
|
||||||
const int chans = (int) stream->pre_resample_channels;
|
const int chans = (int) stream->pre_resample_channels;
|
||||||
const int inrate = stream->src_rate;
|
const int inrate = stream->src_rate;
|
||||||
const int outrate = stream->dst_rate;
|
const int outrate = stream->dst_rate;
|
||||||
const int paddingsamples = ResamplerPadding(inrate, outrate) * chans;
|
const int paddingsamples = stream->resampler_padding_samples;
|
||||||
const int paddingbytes = paddingsamples * sizeof (float);
|
const int paddingbytes = paddingsamples * sizeof (float);
|
||||||
float *lpadding = (float *) stream->resampler_state;
|
float *lpadding = (float *) stream->resampler_state;
|
||||||
float *rpadding;
|
const float *rpadding = (const float *) inbufend; /* we set this up so there are valid padding samples at the end of the input buffer. */
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
if (inbuf == ((const float *) outbuf)) { /* !!! FIXME can't work in-place (for now!). */
|
SDL_assert(inbuf != ((const float *) outbuf)); /* SDL_AudioStreamPut() shouldn't allow in-place resamples. */
|
||||||
Uint8 *ptr = EnsureStreamBufferSize(stream, inbuflen + outbuflen);
|
|
||||||
if (ptr == NULL) {
|
|
||||||
SDL_OutOfMemory();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
SDL_memcpy(ptr + outbuflen, ptr, inbuflen);
|
|
||||||
inbuf = (const float *) (ptr + outbuflen);
|
|
||||||
outbuf = (float *) ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* !!! FIXME: streaming current resamples on Put, because of probably good reasons I can't remember right now, but if we resample on Get, we'd be able to access legit right padding values. */
|
|
||||||
rpadding = SDL_stack_alloc(float, paddingsamples);
|
|
||||||
if (!rpadding) {
|
|
||||||
SDL_OutOfMemory();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
SDL_memset(rpadding, '\0', paddingbytes);
|
|
||||||
|
|
||||||
retval = SDL_ResampleAudio(chans, inrate, outrate, lpadding, rpadding, inbuf, inbuflen, outbuf, outbuflen);
|
retval = SDL_ResampleAudio(chans, inrate, outrate, lpadding, rpadding, inbuf, inbuflen, outbuf, outbuflen);
|
||||||
|
|
||||||
SDL_stack_free(rpadding);
|
|
||||||
|
|
||||||
/* update our left padding with end of current input, for next run. */
|
/* update our left padding with end of current input, for next run. */
|
||||||
SDL_memcpy(lpadding, ((const Uint8 *) inbuf) + (inbuflen - paddingbytes), paddingbytes);
|
SDL_memcpy(lpadding, inbufend - paddingbytes, paddingbytes);
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
SDL_ResetAudioStreamResampler(SDL_AudioStream *stream)
|
SDL_ResetAudioStreamResampler(SDL_AudioStream *stream)
|
||||||
{
|
{
|
||||||
/* set all the left padding to silence. */
|
/* set all the padding to silence. */
|
||||||
const int inrate = stream->src_rate;
|
const int len = stream->resampler_padding_samples;
|
||||||
const int outrate = stream->dst_rate;
|
|
||||||
const int chans = (int) stream->pre_resample_channels;
|
|
||||||
const int len = ResamplerPadding(inrate, outrate) * chans;
|
|
||||||
SDL_memset(stream->resampler_state, '\0', len * sizeof (float));
|
SDL_memset(stream->resampler_state, '\0', len * sizeof (float));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1293,6 +1273,7 @@ SDL_NewAudioStream(const SDL_AudioFormat src_format,
|
||||||
the resampled data (!!! FIXME: decide if that works in practice, though!). */
|
the resampled data (!!! FIXME: decide if that works in practice, though!). */
|
||||||
pre_resample_channels = SDL_min(src_channels, dst_channels);
|
pre_resample_channels = SDL_min(src_channels, dst_channels);
|
||||||
|
|
||||||
|
retval->first_run = SDL_TRUE;
|
||||||
retval->src_sample_frame_size = (SDL_AUDIO_BITSIZE(src_format) / 8) * src_channels;
|
retval->src_sample_frame_size = (SDL_AUDIO_BITSIZE(src_format) / 8) * src_channels;
|
||||||
retval->src_format = src_format;
|
retval->src_format = src_format;
|
||||||
retval->src_channels = src_channels;
|
retval->src_channels = src_channels;
|
||||||
|
@ -1304,6 +1285,14 @@ SDL_NewAudioStream(const SDL_AudioFormat src_format,
|
||||||
retval->pre_resample_channels = pre_resample_channels;
|
retval->pre_resample_channels = pre_resample_channels;
|
||||||
retval->packetlen = packetlen;
|
retval->packetlen = packetlen;
|
||||||
retval->rate_incr = ((double) dst_rate) / ((double) src_rate);
|
retval->rate_incr = ((double) dst_rate) / ((double) src_rate);
|
||||||
|
retval->resampler_padding_samples = ResamplerPadding(retval->src_rate, retval->dst_rate) * pre_resample_channels;
|
||||||
|
retval->resampler_padding = (float *) SDL_calloc(retval->resampler_padding_samples, sizeof (float));
|
||||||
|
|
||||||
|
if (retval->resampler_padding == NULL) {
|
||||||
|
SDL_FreeAudioStream(retval);
|
||||||
|
SDL_OutOfMemory();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/* Not resampling? It's an easy conversion (and maybe not even that!). */
|
/* Not resampling? It's an easy conversion (and maybe not even that!). */
|
||||||
if (src_rate == dst_rate) {
|
if (src_rate == dst_rate) {
|
||||||
|
@ -1325,9 +1314,7 @@ SDL_NewAudioStream(const SDL_AudioFormat src_format,
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!retval->resampler_func) {
|
if (!retval->resampler_func) {
|
||||||
const int chans = (int) pre_resample_channels;
|
retval->resampler_state = SDL_calloc(retval->resampler_padding_samples, sizeof (float));
|
||||||
const int len = ResamplerPadding(src_rate, dst_rate) * chans;
|
|
||||||
retval->resampler_state = SDL_calloc(len, sizeof (float));
|
|
||||||
if (!retval->resampler_state) {
|
if (!retval->resampler_state) {
|
||||||
SDL_FreeAudioStream(retval);
|
SDL_FreeAudioStream(retval);
|
||||||
SDL_OutOfMemory();
|
SDL_OutOfMemory();
|
||||||
|
@ -1366,7 +1353,12 @@ int
|
||||||
SDL_AudioStreamPut(SDL_AudioStream *stream, const void *buf, const Uint32 _buflen)
|
SDL_AudioStreamPut(SDL_AudioStream *stream, const void *buf, const Uint32 _buflen)
|
||||||
{
|
{
|
||||||
int buflen = (int) _buflen;
|
int buflen = (int) _buflen;
|
||||||
const void *origbuf = buf;
|
int workbuflen;
|
||||||
|
Uint8 *workbuf;
|
||||||
|
Uint8 *resamplebuf = NULL;
|
||||||
|
int resamplebuflen = 0;
|
||||||
|
const int neededpaddingbytes = stream ? stream->resampler_padding_samples * sizeof (float) : 0;
|
||||||
|
int paddingbytes;
|
||||||
|
|
||||||
/* !!! FIXME: several converters can take advantage of SIMD, but only
|
/* !!! FIXME: several converters can take advantage of SIMD, but only
|
||||||
!!! FIXME: if the data is aligned to 16 bytes. EnsureStreamBufferSize()
|
!!! FIXME: if the data is aligned to 16 bytes. EnsureStreamBufferSize()
|
||||||
|
@ -1376,6 +1368,10 @@ SDL_AudioStreamPut(SDL_AudioStream *stream, const void *buf, const Uint32 _bufle
|
||||||
!!! FIXME: isn't a multiple of 16. In these cases, we should chop off
|
!!! FIXME: isn't a multiple of 16. In these cases, we should chop off
|
||||||
!!! FIXME: a few samples at the end and convert them separately. */
|
!!! FIXME: a few samples at the end and convert them separately. */
|
||||||
|
|
||||||
|
#if DEBUG_AUDIOSTREAM
|
||||||
|
printf("AUDIOSTREAM: wants to put %d preconverted bytes\n", buflen);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (!stream) {
|
if (!stream) {
|
||||||
return SDL_InvalidParamError("stream");
|
return SDL_InvalidParamError("stream");
|
||||||
} else if (!buf) {
|
} else if (!buf) {
|
||||||
|
@ -1384,60 +1380,114 @@ SDL_AudioStreamPut(SDL_AudioStream *stream, const void *buf, const Uint32 _bufle
|
||||||
return 0; /* nothing to do. */
|
return 0; /* nothing to do. */
|
||||||
} else if ((buflen % stream->src_sample_frame_size) != 0) {
|
} else if ((buflen % stream->src_sample_frame_size) != 0) {
|
||||||
return SDL_SetError("Can't add partial sample frames");
|
return SDL_SetError("Can't add partial sample frames");
|
||||||
|
} else if (buflen < (neededpaddingbytes * 2)) {
|
||||||
|
return SDL_SetError("Need to put a larger buffer");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* no padding prepended on first run. */
|
||||||
|
paddingbytes = stream->first_run ? 0 : neededpaddingbytes;
|
||||||
|
stream->first_run = SDL_FALSE;
|
||||||
|
|
||||||
|
if (!stream->cvt_before_resampling.needed &&
|
||||||
|
(stream->dst_rate == stream->src_rate) &&
|
||||||
|
!stream->cvt_after_resampling.needed) {
|
||||||
|
#if DEBUG_AUDIOSTREAM
|
||||||
|
printf("AUDIOSTREAM: no conversion needed at all, queueing %d bytes.\n", buflen);
|
||||||
|
#endif
|
||||||
|
return SDL_WriteToDataQueue(stream->queue, buf, buflen);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make sure the work buffer can hold all the data we need at once... */
|
||||||
|
workbuflen = buflen;
|
||||||
if (stream->cvt_before_resampling.needed) {
|
if (stream->cvt_before_resampling.needed) {
|
||||||
const int workbuflen = buflen * stream->cvt_before_resampling.len_mult; /* will be "* 1" if not needed */
|
workbuflen *= stream->cvt_before_resampling.len_mult;
|
||||||
Uint8 *workbuf = EnsureStreamBufferSize(stream, workbuflen);
|
}
|
||||||
if (workbuf == NULL) {
|
|
||||||
|
if (stream->dst_rate != stream->src_rate) {
|
||||||
|
/* resamples can't happen in place, so make space for second buf. */
|
||||||
|
const int framesize = stream->pre_resample_channels * sizeof (float);
|
||||||
|
const int frames = workbuflen / framesize;
|
||||||
|
resamplebuflen = ((int) SDL_ceil(frames * stream->rate_incr)) * framesize;
|
||||||
|
#if DEBUG_AUDIOSTREAM
|
||||||
|
printf("AUDIOSTREAM: will resample %d bytes to %d (ratio=%.6f)\n", workbuflen, resamplebuflen, stream->rate_incr);
|
||||||
|
#endif
|
||||||
|
workbuflen += resamplebuflen;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stream->cvt_after_resampling.needed) {
|
||||||
|
/* !!! FIXME: buffer might be big enough already? */
|
||||||
|
workbuflen *= stream->cvt_after_resampling.len_mult;
|
||||||
|
}
|
||||||
|
|
||||||
|
workbuflen += neededpaddingbytes;
|
||||||
|
|
||||||
|
#if DEBUG_AUDIOSTREAM
|
||||||
|
printf("AUDIOSTREAM: Putting %d bytes of preconverted audio, need %d byte work buffer\n", buflen, workbuflen);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
workbuf = EnsureStreamBufferSize(stream, workbuflen);
|
||||||
|
if (!workbuf) {
|
||||||
return -1; /* probably out of memory. */
|
return -1; /* probably out of memory. */
|
||||||
}
|
}
|
||||||
SDL_assert(buf == origbuf);
|
|
||||||
SDL_memcpy(workbuf, buf, buflen);
|
resamplebuf = workbuf; /* default if not resampling. */
|
||||||
stream->cvt_before_resampling.buf = workbuf;
|
|
||||||
|
SDL_memcpy(workbuf + paddingbytes, buf, buflen);
|
||||||
|
|
||||||
|
if (stream->cvt_before_resampling.needed) {
|
||||||
|
stream->cvt_before_resampling.buf = workbuf + paddingbytes;
|
||||||
stream->cvt_before_resampling.len = buflen;
|
stream->cvt_before_resampling.len = buflen;
|
||||||
if (SDL_ConvertAudio(&stream->cvt_before_resampling) == -1) {
|
if (SDL_ConvertAudio(&stream->cvt_before_resampling) == -1) {
|
||||||
return -1; /* uhoh! */
|
return -1; /* uhoh! */
|
||||||
}
|
}
|
||||||
buf = workbuf;
|
|
||||||
buflen = stream->cvt_before_resampling.len_cvt;
|
buflen = stream->cvt_before_resampling.len_cvt;
|
||||||
|
|
||||||
|
#if DEBUG_AUDIOSTREAM
|
||||||
|
printf("AUDIOSTREAM: After initial conversion we have %d bytes\n", buflen);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stream->dst_rate != stream->src_rate) {
|
if (stream->dst_rate != stream->src_rate) {
|
||||||
const int workbuflen = buflen * ((int) SDL_ceil(stream->rate_incr));
|
/* save off some samples at the end; they are used for padding now so
|
||||||
Uint8 *workbuf = EnsureStreamBufferSize(stream, workbuflen);
|
the resampler is coherent and then used at the start of the next
|
||||||
if (workbuf == NULL) {
|
put operation. Prepend last put operation's padding, too. */
|
||||||
return -1; /* probably out of memory. */
|
|
||||||
|
/* prepend prior put's padding. :P */
|
||||||
|
if (paddingbytes) {
|
||||||
|
SDL_memcpy(workbuf, stream->resampler_padding, paddingbytes);
|
||||||
|
buflen += paddingbytes;
|
||||||
}
|
}
|
||||||
/* don't SDL_memcpy(workbuf, buf, buflen) here; our resampler can work inplace or not,
|
|
||||||
libsamplerate needs buffers to be separate; either way, avoid a copy here if possible. */
|
/* save off the data at the end for the next run. */
|
||||||
if (buf != origbuf) {
|
SDL_memcpy(stream->resampler_padding, workbuf + (buflen - neededpaddingbytes), neededpaddingbytes);
|
||||||
buf = workbuf; /* in case we realloc()'d the pointer. */
|
|
||||||
}
|
resamplebuf = workbuf + buflen; /* skip to second piece of workbuf. */
|
||||||
buflen = stream->resampler_func(stream, buf, buflen, workbuf, workbuflen);
|
buflen = stream->resampler_func(stream, workbuf, buflen - neededpaddingbytes, resamplebuf, resamplebuflen);
|
||||||
buf = EnsureStreamBufferSize(stream, workbuflen);
|
|
||||||
SDL_assert(buf != NULL); /* shouldn't be growing, just aligning. */
|
#if DEBUG_AUDIOSTREAM
|
||||||
|
printf("AUDIOSTREAM: After resampling we have %d bytes\n", buflen);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stream->cvt_after_resampling.needed) {
|
if (stream->cvt_after_resampling.needed) {
|
||||||
const int workbuflen = buflen * stream->cvt_after_resampling.len_mult; /* will be "* 1" if not needed */
|
stream->cvt_after_resampling.buf = resamplebuf;
|
||||||
Uint8 *workbuf = EnsureStreamBufferSize(stream, workbuflen);
|
|
||||||
if (workbuf == NULL) {
|
|
||||||
return -1; /* probably out of memory. */
|
|
||||||
}
|
|
||||||
if (buf == origbuf) { /* copy if we haven't before. */
|
|
||||||
SDL_memcpy(workbuf, origbuf, buflen);
|
|
||||||
}
|
|
||||||
stream->cvt_after_resampling.buf = workbuf;
|
|
||||||
stream->cvt_after_resampling.len = buflen;
|
stream->cvt_after_resampling.len = buflen;
|
||||||
if (SDL_ConvertAudio(&stream->cvt_after_resampling) == -1) {
|
if (SDL_ConvertAudio(&stream->cvt_after_resampling) == -1) {
|
||||||
return -1; /* uhoh! */
|
return -1; /* uhoh! */
|
||||||
}
|
}
|
||||||
buf = workbuf;
|
|
||||||
buflen = stream->cvt_after_resampling.len_cvt;
|
buflen = stream->cvt_after_resampling.len_cvt;
|
||||||
|
|
||||||
|
#if DEBUG_AUDIOSTREAM
|
||||||
|
printf("AUDIOSTREAM: After final conversion we have %d bytes\n", buflen);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
return SDL_WriteToDataQueue(stream->queue, buf, buflen);
|
#if DEBUG_AUDIOSTREAM
|
||||||
|
printf("AUDIOSTREAM: Final output is %d bytes\n", buflen);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* resamplebuf holds the final output, even if we didn't resample. */
|
||||||
|
return SDL_WriteToDataQueue(stream->queue, resamplebuf, buflen);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -1450,6 +1500,7 @@ SDL_AudioStreamClear(SDL_AudioStream *stream)
|
||||||
if (stream->reset_resampler_func) {
|
if (stream->reset_resampler_func) {
|
||||||
stream->reset_resampler_func(stream);
|
stream->reset_resampler_func(stream);
|
||||||
}
|
}
|
||||||
|
stream->first_run = SDL_TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1458,6 +1509,10 @@ SDL_AudioStreamClear(SDL_AudioStream *stream)
|
||||||
int
|
int
|
||||||
SDL_AudioStreamGet(SDL_AudioStream *stream, void *buf, const Uint32 len)
|
SDL_AudioStreamGet(SDL_AudioStream *stream, void *buf, const Uint32 len)
|
||||||
{
|
{
|
||||||
|
#if DEBUG_AUDIOSTREAM
|
||||||
|
printf("AUDIOSTREAM: want to get %u converted bytes\n", (unsigned int) len);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (!stream) {
|
if (!stream) {
|
||||||
return SDL_InvalidParamError("stream");
|
return SDL_InvalidParamError("stream");
|
||||||
} else if (!buf) {
|
} else if (!buf) {
|
||||||
|
@ -1488,6 +1543,7 @@ SDL_FreeAudioStream(SDL_AudioStream *stream)
|
||||||
}
|
}
|
||||||
SDL_FreeDataQueue(stream->queue);
|
SDL_FreeDataQueue(stream->queue);
|
||||||
SDL_free(stream->work_buffer_base);
|
SDL_free(stream->work_buffer_base);
|
||||||
|
SDL_free(stream->resampler_padding);
|
||||||
SDL_free(stream);
|
SDL_free(stream);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue