diff --git a/src/audio/SDL_audio_c.h b/src/audio/SDL_audio_c.h index 2b94d723c..62fd6bcc8 100644 --- a/src/audio/SDL_audio_c.h +++ b/src/audio/SDL_audio_c.h @@ -63,10 +63,6 @@ void SDLCALL SDL_Convert_F32_to_U8(SDL_AudioCVT *cvt, SDL_AudioFormat format); void SDLCALL SDL_Convert_F32_to_S16(SDL_AudioCVT *cvt, SDL_AudioFormat format); void SDLCALL SDL_Convert_F32_to_U16(SDL_AudioCVT *cvt, SDL_AudioFormat format); void SDLCALL SDL_Convert_F32_to_S32(SDL_AudioCVT *cvt, SDL_AudioFormat format); -void SDL_Upsample_Arbitrary(SDL_AudioCVT *cvt, const int channels); -void SDL_Upsample_Multiple(SDL_AudioCVT *cvt, const int channels); -void SDL_Downsample_Arbitrary(SDL_AudioCVT *cvt, const int channels); -void SDL_Downsample_Multiple(SDL_AudioCVT *cvt, const int channels); /* SDL_AudioStream is a new audio conversion interface. It diff --git a/src/audio/SDL_audiocvt.c b/src/audio/SDL_audiocvt.c index a9eecda05..e690b1d17 100644 --- a/src/audio/SDL_audiocvt.c +++ b/src/audio/SDL_audiocvt.c @@ -191,6 +191,38 @@ SDL_ConvertStereoToQuad(SDL_AudioCVT * cvt, SDL_AudioFormat format) } } +static int +SDL_ResampleAudioSimple(const int chans, const double rate_incr, + float *last_sample, const float *inbuf, + const int inbuflen, float *outbuf, const int outbuflen) +{ + const int framelen = chans * sizeof(float); + const int total = (inbuflen / framelen); + const int finalpos = total - chans; + const double src_incr = 1.0 / rate_incr; + double idx = 0.0; + float *dst = outbuf; + int consumed = 0; + int i; + + SDL_assert((inbuflen % framelen) == 0); + + while (consumed < total) { + const int pos = ((int)idx) * chans; + const float *src = &inbuf[(pos >= finalpos) ? finalpos : pos]; + SDL_assert(dst < (outbuf + (outbuflen / framelen))); + for (i = 0; i < chans; i++) { + const float val = *(src++); + *(dst++) = (val + last_sample[i]) * 0.5f; + last_sample[i] = val; + } + consumed = pos + chans; + idx += src_incr; + } + + return (int)((dst - outbuf) * sizeof(float)); +} + int SDL_ConvertAudio(SDL_AudioCVT * cvt) @@ -338,31 +370,75 @@ SDL_BuildAudioTypeCVTFromFloat(SDL_AudioCVT *cvt, const SDL_AudioFormat dst_fmt) return retval; } +static void +SDL_ResampleCVT(SDL_AudioCVT *cvt, const int chans, const SDL_AudioFormat format) +{ + const float *src = (const float *) cvt->buf; + const int srclen = cvt->len_cvt; + float *dst = (float *) (cvt->buf + srclen); + const int dstlen = (cvt->len * cvt->len_mult) - srclen; + SDL_bool do_simple = SDL_TRUE; -/* !!! FIXME: We only have this macro salsa because SDL_AudioCVT doesn't store - !!! FIXME: channel info or integer sample rates, so we have to have - !!! FIXME: function entry points for each supported channel count and - !!! FIXME: multiple vs arbitrary. When we rev the ABI, remove this. */ + SDL_assert(format == AUDIO_F32SYS); + +#ifdef HAVE_LIBSAMPLERATE_H + if (SRC_available) { + int result = 0; + SRC_STATE *state = SRC_src_new(SRC_SINC_FASTEST, chans, &result); + if (state) { + const int framelen = sizeof(float) * chans; + SRC_DATA data; + + data.data_in = (float *)src; /* Older versions of libsamplerate had a non-const pointer, but didn't write to it */ + data.input_frames = srclen / framelen; + data.input_frames_used = 0; + + data.data_out = dst; + data.output_frames = dstlen / framelen; + + data.end_of_input = 0; + data.src_ratio = cvt->rate_incr; + + result = SRC_src_process(state, &data); + SDL_assert(result == 0); /* what to do if this fails? Can it fail? */ + + /* What to do if this fails...? */ + SDL_assert(data.input_frames_used == data.input_frames); + + SRC_src_delete(state); + cvt->len_cvt = data.output_frames_gen * (sizeof(float) * chans); + do_simple = SDL_FALSE; + } + + /* failed to create state? Fall back to simple method. */ + } +#endif + + if (do_simple) { + float state[8]; + int i; + + for (i = 0; i < chans; i++) { + state[i] = src[i]; + } + + cvt->len_cvt = SDL_ResampleAudioSimple(chans, cvt->rate_incr, state, src, srclen, dst, dstlen); + } + + SDL_memcpy(cvt->buf, dst, cvt->len_cvt); + if (cvt->filters[++cvt->filter_index]) { + cvt->filters[cvt->filter_index](cvt, format); + } +} + +/* !!! FIXME: We only have this macro salsa because SDL_AudioCVT doesn't + !!! FIXME: store channel info, so we have to have function entry + !!! FIXME: points for each supported channel count and multiple + !!! FIXME: vs arbitrary. When we rev the ABI, clean this up. */ #define RESAMPLER_FUNCS(chans) \ static void SDLCALL \ - SDL_Upsample_Multiple_c##chans(SDL_AudioCVT *cvt, SDL_AudioFormat format) { \ - SDL_assert(format == AUDIO_F32SYS); \ - SDL_Upsample_Multiple(cvt, chans); \ - } \ - static void SDLCALL \ - SDL_Upsample_Arbitrary_c##chans(SDL_AudioCVT *cvt, SDL_AudioFormat format) { \ - SDL_assert(format == AUDIO_F32SYS); \ - SDL_Upsample_Arbitrary(cvt, chans); \ - }\ - static void SDLCALL \ - SDL_Downsample_Multiple_c##chans(SDL_AudioCVT *cvt, SDL_AudioFormat format) { \ - SDL_assert(format == AUDIO_F32SYS); \ - SDL_Downsample_Multiple(cvt, chans); \ - } \ - static void SDLCALL \ - SDL_Downsample_Arbitrary_c##chans(SDL_AudioCVT *cvt, SDL_AudioFormat format) { \ - SDL_assert(format == AUDIO_F32SYS); \ - SDL_Downsample_Arbitrary(cvt, chans); \ + SDL_ResampleCVT_c##chans(SDL_AudioCVT *cvt, SDL_AudioFormat format) { \ + SDL_ResampleCVT(cvt, chans, format); \ } RESAMPLER_FUNCS(1) RESAMPLER_FUNCS(2) @@ -371,62 +447,19 @@ RESAMPLER_FUNCS(6) RESAMPLER_FUNCS(8) #undef RESAMPLER_FUNCS -static int -SDL_FindFrequencyMultiple(const int src_rate, const int dst_rate) -{ - int lo, hi; - - SDL_assert(src_rate != 0); - SDL_assert(dst_rate != 0); - SDL_assert(src_rate != dst_rate); - - if (src_rate < dst_rate) { - lo = src_rate; - hi = dst_rate; - } else { - lo = dst_rate; - hi = src_rate; - } - - if ((hi % lo) != 0) - return 0; /* not a multiple. */ - - return hi / lo; -} - static SDL_AudioFilter -ChooseResampler(const int dst_channels, const int src_rate, const int dst_rate) +ChooseCVTResampler(const int dst_channels) { - const int upsample = (src_rate < dst_rate) ? 1 : 0; - const int multiple = SDL_FindFrequencyMultiple(src_rate, dst_rate); - SDL_AudioFilter filter = NULL; - - #define PICK_CHANNEL_FILTER(upordown, resampler) switch (dst_channels) { \ - case 1: filter = SDL_##upordown##_##resampler##_c1; break; \ - case 2: filter = SDL_##upordown##_##resampler##_c2; break; \ - case 4: filter = SDL_##upordown##_##resampler##_c4; break; \ - case 6: filter = SDL_##upordown##_##resampler##_c6; break; \ - case 8: filter = SDL_##upordown##_##resampler##_c8; break; \ - default: break; \ + switch (dst_channels) { + case 1: return SDL_ResampleCVT_c1; + case 2: return SDL_ResampleCVT_c2; + case 4: return SDL_ResampleCVT_c4; + case 6: return SDL_ResampleCVT_c6; + case 8: return SDL_ResampleCVT_c8; + default: break; } - if (upsample) { - if (multiple) { - PICK_CHANNEL_FILTER(Upsample, Multiple); - } else { - PICK_CHANNEL_FILTER(Upsample, Arbitrary); - } - } else { - if (multiple) { - PICK_CHANNEL_FILTER(Downsample, Multiple); - } else { - PICK_CHANNEL_FILTER(Downsample, Arbitrary); - } - } - - #undef PICK_CHANNEL_FILTER - - return filter; + return NULL; } static int @@ -439,7 +472,7 @@ SDL_BuildAudioResampleCVT(SDL_AudioCVT * cvt, const int dst_channels, return 0; /* no conversion necessary. */ } - filter = ChooseResampler(dst_channels, src_rate, dst_rate); + filter = ChooseCVTResampler(dst_channels); if (filter == NULL) { return SDL_SetError("No conversion available for these rates"); } @@ -454,6 +487,10 @@ SDL_BuildAudioResampleCVT(SDL_AudioCVT * cvt, const int dst_channels, cvt->len_ratio /= ((double) src_rate) / ((double) dst_rate); } + /* the buffer is big enough to hold the destination now, but + we need it large enough to hold a separate scratch buffer. */ + cvt->len_mult *= 2; + return 1; /* added a converter. */ } @@ -638,16 +675,17 @@ struct SDL_AudioStream static int SDL_ResampleAudioStream_SRC(SDL_AudioStream *stream, const float *inbuf, const int inbuflen, float *outbuf, const int outbuflen) { + const int framelen = sizeof(float) * stream->pre_resample_channels; SRC_STATE *state = (SRC_STATE *)stream->resampler_state; SRC_DATA data; int result; data.data_in = (float *)inbuf; /* Older versions of libsamplerate had a non-const pointer, but didn't write to it */ - data.input_frames = inbuflen / ( sizeof(float) * stream->pre_resample_channels ); + data.input_frames = inbuflen / framelen; data.input_frames_used = 0; data.data_out = outbuf; - data.output_frames = outbuflen / (sizeof(float) * stream->pre_resample_channels); + data.output_frames = outbuflen / framelen; data.end_of_input = 0; data.src_ratio = stream->rate_incr; @@ -721,51 +759,20 @@ typedef struct static int SDL_ResampleAudioStream(SDL_AudioStream *stream, const float *inbuf, const int inbuflen, float *outbuf, const int outbuflen) { - /* !!! FIXME: this resampler sucks, but not much worse than our usual resampler. :) */ /* ... :( */ SDL_AudioStreamResamplerState *state = (SDL_AudioStreamResamplerState*)stream->resampler_state; const int chans = (int)stream->pre_resample_channels; - const int framelen = chans * sizeof(float); - const int total = (inbuflen / framelen); - const int finalpos = total - chans; - const double src_incr = 1.0 / stream->rate_incr; - double idx = 0.0; - float *dst = outbuf; - float last_sample[SDL_arraysize(state->resampler_state)]; - int consumed = 0; - int i; - SDL_assert(chans <= SDL_arraysize(last_sample)); - SDL_assert((inbuflen % framelen) == 0); + SDL_assert(chans <= SDL_arraysize(state->resampler_state)); if (!state->resampler_seeded) { + int i; for (i = 0; i < chans; i++) { state->resampler_state[i] = inbuf[i]; } state->resampler_seeded = SDL_TRUE; } - for (i = 0; i < chans; i++) { - last_sample[i] = state->resampler_state[i]; - } - - while (consumed < total) { - const int pos = ((int)idx) * chans; - const float *src = &inbuf[(pos >= finalpos) ? finalpos : pos]; - SDL_assert(dst < (outbuf + (outbuflen / framelen))); - for (i = 0; i < chans; i++) { - const float val = *(src++); - *(dst++) = (val + last_sample[i]) * 0.5f; - last_sample[i] = val; - } - consumed = pos + chans; - idx += src_incr; - } - - for (i = 0; i < chans; i++) { - state->resampler_state[i] = last_sample[i]; - } - - return (int)((dst - outbuf) * sizeof(float)); + return SDL_ResampleAudioSimple(chans, stream->rate_incr, state->resampler_state, inbuf, inbuflen, outbuf, outbuflen); } static void diff --git a/src/audio/SDL_audiotypecvt.c b/src/audio/SDL_audiotypecvt.c index 0364e4a78..12b34fe99 100644 --- a/src/audio/SDL_audiotypecvt.c +++ b/src/audio/SDL_audiotypecvt.c @@ -216,177 +216,4 @@ SDL_Convert_F32_to_S32(SDL_AudioCVT *cvt, SDL_AudioFormat format) } } -void -SDL_Upsample_Arbitrary(SDL_AudioCVT *cvt, const int channels) -{ - const int srcsize = cvt->len_cvt - (64 * channels); - const int dstsize = (int) ((((double)(cvt->len_cvt/(channels*4))) * cvt->rate_incr)) * (channels*4); - register int eps = 0; - float *dst = ((float *) (cvt->buf + dstsize)) - channels; - const float *src = ((float *) (cvt->buf + cvt->len_cvt)) - channels; - const float *target = ((const float *) cvt->buf); - const size_t cpy = sizeof (float) * channels; - float sample[8]; - float last_sample[8]; - int i; - -#if DEBUG_CONVERT - fprintf(stderr, "Upsample arbitrary (x%f), %d channels.\n", cvt->rate_incr, channels); -#endif - - SDL_assert(channels <= 8); - - for (i = 0; i < channels; i++) { - sample[i] = (float) ((((double) src[i]) + ((double) src[i - channels])) * 0.5); - } - SDL_memcpy(last_sample, src, cpy); - - while (dst > target) { - SDL_memcpy(dst, sample, cpy); - dst -= channels; - eps += srcsize; - if ((eps << 1) >= dstsize) { - if (src > target) { - src -= channels; - for (i = 0; i < channels; i++) { - sample[i] = (float) ((((double) src[i]) + ((double) last_sample[i])) * 0.5); - } - } else { - - } - SDL_memcpy(last_sample, src, cpy); - eps -= dstsize; - } - } - - cvt->len_cvt = dstsize; - if (cvt->filters[++cvt->filter_index]) { - cvt->filters[cvt->filter_index](cvt, AUDIO_F32SYS); - } -} - -void -SDL_Downsample_Arbitrary(SDL_AudioCVT *cvt, const int channels) -{ - const int srcsize = cvt->len_cvt - (64 * channels); - const int dstsize = (int) (((double)(cvt->len_cvt/(channels*4))) * cvt->rate_incr) * (channels*4); - register int eps = 0; - float *dst = (float *) cvt->buf; - const float *src = (float *) cvt->buf; - const float *target = (const float *) (cvt->buf + dstsize); - const size_t cpy = sizeof (float) * channels; - float last_sample[8]; - float sample[8]; - int i; - -#if DEBUG_CONVERT - fprintf(stderr, "Downsample arbitrary (x%f), %d channels.\n", cvt->rate_incr, channels); -#endif - - SDL_assert(channels <= 8); - - SDL_memcpy(sample, src, cpy); - SDL_memcpy(last_sample, src, cpy); - - while (dst < target) { - src += channels; - eps += dstsize; - if ((eps << 1) >= srcsize) { - SDL_memcpy(dst, sample, cpy); - dst += channels; - for (i = 0; i < channels; i++) { - sample[i] = (float) ((((double) src[i]) + ((double) last_sample[i])) * 0.5); - } - SDL_memcpy(last_sample, src, cpy); - eps -= srcsize; - } - } - - cvt->len_cvt = dstsize; - if (cvt->filters[++cvt->filter_index]) { - cvt->filters[cvt->filter_index](cvt, AUDIO_F32SYS); - } -} - -void -SDL_Upsample_Multiple(SDL_AudioCVT *cvt, const int channels) -{ - const int multiple = (int) cvt->rate_incr; - const int dstsize = cvt->len_cvt * multiple; - float *buf = (float *) cvt->buf; - float *dst = ((float *) (cvt->buf + dstsize)) - channels; - const float *src = ((float *) (cvt->buf + cvt->len_cvt)) - channels; - const float *target = buf + channels; - const size_t cpy = sizeof (float) * channels; - float last_sample[8]; - int i; - -#if DEBUG_CONVERT - fprintf(stderr, "Upsample (x%d), %d channels.\n", multiple, channels); -#endif - - SDL_assert(channels <= 8); - - SDL_memcpy(last_sample, src, cpy); - - while (dst > target) { - SDL_assert(src >= buf); - - for (i = 0; i < channels; i++) { - dst[i] = (float) ((((double)src[i]) + ((double)last_sample[i])) * 0.5); - } - dst -= channels; - - for (i = 1; i < multiple; i++) { - SDL_memcpy(dst, dst + channels, cpy); - dst -= channels; - } - - src -= channels; - if (src > buf) { - SDL_memcpy(last_sample, src - channels, cpy); - } - } - - cvt->len_cvt = dstsize; - if (cvt->filters[++cvt->filter_index]) { - cvt->filters[cvt->filter_index](cvt, AUDIO_F32SYS); - } -} - -void -SDL_Downsample_Multiple(SDL_AudioCVT *cvt, const int channels) -{ - const int multiple = (int) (1.0 / cvt->rate_incr); - const int dstsize = cvt->len_cvt / multiple; - float *dst = (float *) cvt->buf; - const float *src = (float *) cvt->buf; - const float *target = (const float *) (cvt->buf + dstsize); - const size_t cpy = sizeof (float) * channels; - float last_sample[8]; - int i; - -#if DEBUG_CONVERT - fprintf(stderr, "Downsample (x%d), %d channels.\n", multiple, channels); -#endif - - SDL_assert(channels <= 8); - SDL_memcpy(last_sample, src, cpy); - - while (dst < target) { - for (i = 0; i < channels; i++) { - dst[i] = (float) ((((double)src[i]) + ((double)last_sample[i])) * 0.5); - } - dst += channels; - - SDL_memcpy(last_sample, src, cpy); - src += (channels * multiple); - } - - cvt->len_cvt = dstsize; - if (cvt->filters[++cvt->filter_index]) { - cvt->filters[cvt->filter_index](cvt, AUDIO_F32SYS); - } -} - /* vi: set ts=4 sw=4 expandtab: */