diff --git a/src/audio/SDL_audiocvt.c b/src/audio/SDL_audiocvt.c index 82367f71b..28e715639 100644 --- a/src/audio/SDL_audiocvt.c +++ b/src/audio/SDL_audiocvt.c @@ -858,7 +858,7 @@ SDL_BuildAudioCVT(SDL_AudioCVT * cvt, return (cvt->needed); } -typedef int (*SDL_ResampleAudioStreamFunc)(SDL_AudioStream *stream, const float *inbuf, const int inbuflen, float *outbuf, const int outbuflen); +typedef int (*SDL_ResampleAudioStreamFunc)(SDL_AudioStream *stream, const void *inbuf, const int inbuflen, void *outbuf, const int outbuflen); typedef void (*SDL_ResetAudioStreamResamplerFunc)(SDL_AudioStream *stream); typedef void (*SDL_CleanupAudioStreamResamplerFunc)(SDL_AudioStream *stream); @@ -890,8 +890,10 @@ struct SDL_AudioStream #ifdef HAVE_LIBSAMPLERATE_H static int -SDL_ResampleAudioStream_SRC(SDL_AudioStream *stream, const float *inbuf, const int inbuflen, float *outbuf, const int outbuflen) +SDL_ResampleAudioStream_SRC(SDL_AudioStream *stream, const void *_inbuf, const int inbuflen, void *_outbuf, const int outbuflen) { + const float *inbuf = (const float *) _inbuf; + float *outbuf = (float *) _outbuf; const int framelen = sizeof(float) * stream->pre_resample_channels; SRC_STATE *state = (SRC_STATE *)stream->resampler_state; SRC_DATA data; @@ -970,26 +972,48 @@ SetupLibSampleRateResampling(SDL_AudioStream *stream) typedef struct { SDL_bool resampler_seeded; - float resampler_state[8]; + union + { + float f[8]; + Sint16 si16[2]; + } resampler_state; } SDL_AudioStreamResamplerState; static int -SDL_ResampleAudioStream(SDL_AudioStream *stream, const float *inbuf, const int inbuflen, float *outbuf, const int outbuflen) +SDL_ResampleAudioStream(SDL_AudioStream *stream, const void *_inbuf, const int inbuflen, void *_outbuf, const int outbuflen) { + const float *inbuf = (const float *) _inbuf; + float *outbuf = (float *) _outbuf; SDL_AudioStreamResamplerState *state = (SDL_AudioStreamResamplerState*)stream->resampler_state; const int chans = (int)stream->pre_resample_channels; - SDL_assert(chans <= SDL_arraysize(state->resampler_state)); + SDL_assert(chans <= SDL_arraysize(state->resampler_state.f)); if (!state->resampler_seeded) { - int i; - for (i = 0; i < chans; i++) { - state->resampler_state[i] = inbuf[i]; - } + SDL_memcpy(state->resampler_state.f, inbuf, chans * sizeof (float)); state->resampler_seeded = SDL_TRUE; } - return SDL_ResampleAudioSimple(chans, stream->rate_incr, state->resampler_state, inbuf, inbuflen, outbuf, outbuflen); + return SDL_ResampleAudioSimple(chans, stream->rate_incr, state->resampler_state.f, inbuf, inbuflen, outbuf, outbuflen); +} + +static int +SDL_ResampleAudioStream_si16_c2(SDL_AudioStream *stream, const void *_inbuf, const int inbuflen, void *_outbuf, const int outbuflen) +{ + const Sint16 *inbuf = (const Sint16 *) _inbuf; + Sint16 *outbuf = (Sint16 *) _outbuf; + SDL_AudioStreamResamplerState *state = (SDL_AudioStreamResamplerState*)stream->resampler_state; + const int chans = (int)stream->pre_resample_channels; + + SDL_assert(chans <= SDL_arraysize(state->resampler_state.si16)); + + if (!state->resampler_seeded) { + state->resampler_state.si16[0] = inbuf[0]; + state->resampler_state.si16[1] = inbuf[1]; + state->resampler_seeded = SDL_TRUE; + } + + return SDL_ResampleAudioSimple_si16_c2(stream->rate_incr, state->resampler_state.si16, inbuf, inbuflen, outbuf, outbuflen); } static void @@ -1016,6 +1040,9 @@ SDL_NewAudioStream(const SDL_AudioFormat src_format, const int packetlen = 4096; /* !!! FIXME: good enough for now. */ Uint8 pre_resample_channels; SDL_AudioStream *retval; +#ifndef HAVE_LIBSAMPLERATE_H + const SDL_bool SRC_available = SDL_FALSE; +#endif retval = (SDL_AudioStream *) SDL_calloc(1, sizeof (SDL_AudioStream)); if (!retval) { @@ -1043,11 +1070,22 @@ SDL_NewAudioStream(const SDL_AudioFormat src_format, /* Not resampling? It's an easy conversion (and maybe not even that!). */ if (src_rate == dst_rate) { retval->cvt_before_resampling.needed = SDL_FALSE; - retval->cvt_before_resampling.len_mult = 1; if (SDL_BuildAudioCVT(&retval->cvt_after_resampling, src_format, src_channels, dst_rate, dst_format, dst_channels, dst_rate) < 0) { SDL_FreeAudioStream(retval); return NULL; /* SDL_BuildAudioCVT should have called SDL_SetError. */ } + /* fast path special case for stereo Sint16 data that just needs resampling. */ + } else if ((!SRC_available) && (src_channels == 2) && (dst_channels == 2) && (src_format == AUDIO_S16SYS) && (dst_format == AUDIO_S16SYS)) { + SDL_assert(src_rate != dst_rate); + retval->resampler_state = SDL_calloc(1, sizeof(SDL_AudioStreamResamplerState)); + if (!retval->resampler_state) { + SDL_FreeAudioStream(retval); + SDL_OutOfMemory(); + return NULL; + } + retval->resampler_func = SDL_ResampleAudioStream_si16_c2; + retval->reset_resampler_func = SDL_ResetAudioStreamResampler; + retval->cleanup_resampler_func = SDL_CleanupAudioStreamResampler; } else { /* Don't resample at first. Just get us to Float32 format. */ /* !!! FIXME: convert to int32 on devices without hardware float. */ @@ -1136,16 +1174,16 @@ SDL_AudioStreamPut(SDL_AudioStream *stream, const void *buf, const Uint32 _bufle if (stream->dst_rate != stream->src_rate) { const int workbuflen = buflen * ((int) SDL_ceil(stream->rate_incr)); - float *workbuf = (float *) EnsureBufferSize(&stream->resample_buffer, &stream->resample_buffer_len, workbuflen); + void *workbuf = EnsureBufferSize(&stream->resample_buffer, &stream->resample_buffer_len, workbuflen); if (workbuf == NULL) { return -1; /* probably out of memory. */ } - buflen = stream->resampler_func(stream, (float *) buf, buflen, workbuf, workbuflen); + buflen = stream->resampler_func(stream, buf, buflen, workbuf, workbuflen); buf = workbuf; } if (stream->cvt_after_resampling.needed) { - const int workbuflen = buflen * stream->cvt_before_resampling.len_mult; /* will be "* 1" if not needed */ + const int workbuflen = buflen * stream->cvt_after_resampling.len_mult; /* will be "* 1" if not needed */ Uint8 *workbuf; if (buf == stream->resample_buffer) {