src/audio/SDL_audiocvt.c
 changeset 11508 a8382e3d0b54 parent 11406 f40c2dedaded child 11517 beb96c015b30
```     1.1 --- a/src/audio/SDL_audiocvt.c	Thu Sep 21 14:01:12 2017 +0900
1.2 +++ b/src/audio/SDL_audiocvt.c	Thu Sep 21 02:51:14 2017 -0400
1.3 @@ -369,228 +369,157 @@
1.4      }
1.5  }
1.6
1.7 +/* SDL's resampler uses a "bandlimited interpolation" algorithm:
1.8 +     https://ccrma.stanford.edu/~jos/resample/ */
1.9 +
1.10 +#define RESAMPLER_ZERO_CROSSINGS 5
1.11 +#define RESAMPLER_BITS_PER_SAMPLE 16
1.12 +#define RESAMPLER_SAMPLES_PER_ZERO_CROSSING  (1 << ((RESAMPLER_BITS_PER_SAMPLE / 2) + 1))
1.13 +#define RESAMPLER_FILTER_SIZE ((RESAMPLER_SAMPLES_PER_ZERO_CROSSING * RESAMPLER_ZERO_CROSSINGS) + 1)
1.14 +
1.15 +/* This is a "modified" bessel function, so you can't use POSIX j0() */
1.16 +static double
1.17 +bessel(const double x)
1.18 +{
1.19 +    const double xdiv2 = x / 2.0;
1.20 +    double i0 = 1.0f;
1.21 +    double f = 1.0f;
1.22 +    int i = 1;
1.23 +
1.24 +    while (SDL_TRUE) {
1.25 +        const double diff = SDL_pow(xdiv2, i * 2) / SDL_pow(f, 2);
1.26 +        if (diff < 1.0e-21f) {
1.27 +            break;
1.28 +        }
1.29 +        i0 += diff;
1.30 +        i++;
1.31 +        f *= (double) i;
1.32 +    }
1.33 +
1.34 +    return i0;
1.35 +}
1.36 +
1.37 +/* build kaiser table with cardinal sine applied to it, and array of differences between elements. */
1.38 +static void
1.39 +kaiser_and_sinc(float *table, float *diffs, const int tablelen, const double beta)
1.40 +{
1.41 +    const int lenm1 = tablelen - 1;
1.42 +    const int lenm1div2 = lenm1 / 2;
1.43 +    int i;
1.44 +
1.45 +    table[0] = 1.0f;
1.46 +    for (i = 1; i < tablelen; i++) {
1.47 +        const double kaiser = bessel(beta * SDL_sqrt(1.0 - SDL_pow(((i - lenm1) / 2.0) / lenm1div2, 2.0))) / bessel(beta);
1.48 +        table[tablelen - i] = (float) kaiser;
1.49 +    }
1.50 +
1.51 +    for (i = 1; i < tablelen; i++) {
1.52 +        const float x = (((float) i) / ((float) RESAMPLER_SAMPLES_PER_ZERO_CROSSING)) * ((float) M_PI);
1.53 +        table[i] *= SDL_sinf(x) / x;
1.54 +        diffs[i - 1] = table[i] - table[i - 1];
1.55 +    }
1.56 +    diffs[lenm1] = 0.0f;
1.57 +}
1.58 +
1.59 +
1.60 +static SDL_SpinLock ResampleFilterSpinlock = 0;
1.61 +static float *ResamplerFilter = NULL;
1.62 +static float *ResamplerFilterDifference = NULL;
1.63 +
1.64 +int
1.65 +SDL_PrepareResampleFilter(void)
1.66 +{
1.67 +    SDL_AtomicLock(&ResampleFilterSpinlock);
1.68 +    if (!ResamplerFilter) {
1.69 +        /* if dB > 50, beta=(0.1102 * (dB - 8.7)), according to Matlab. */
1.70 +        const double dB = 80.0;
1.71 +        const double beta = 0.1102 * (dB - 8.7);
1.72 +        const size_t alloclen = RESAMPLER_FILTER_SIZE * sizeof (float);
1.73 +
1.74 +        ResamplerFilter = (float *) SDL_malloc(alloclen);
1.75 +        if (!ResamplerFilter) {
1.76 +            SDL_AtomicUnlock(&ResampleFilterSpinlock);
1.77 +            return SDL_OutOfMemory();
1.78 +        }
1.79 +
1.80 +        ResamplerFilterDifference = (float *) SDL_malloc(alloclen);
1.81 +        if (!ResamplerFilterDifference) {
1.82 +            SDL_free(ResamplerFilter);
1.83 +            ResamplerFilter = NULL;
1.84 +            SDL_AtomicUnlock(&ResampleFilterSpinlock);
1.85 +            return SDL_OutOfMemory();
1.86 +        }
1.87 +        kaiser_and_sinc(ResamplerFilter, ResamplerFilterDifference, RESAMPLER_FILTER_SIZE, beta);
1.88 +    }
1.89 +    SDL_AtomicUnlock(&ResampleFilterSpinlock);
1.90 +    return 0;
1.91 +}
1.92 +
1.93 +void
1.94 +SDL_FreeResampleFilter(void)
1.95 +{
1.96 +    SDL_free(ResamplerFilter);
1.97 +    SDL_free(ResamplerFilterDifference);
1.98 +    ResamplerFilter = NULL;
1.99 +    ResamplerFilterDifference = NULL;
1.100 +}
1.101 +
1.102
1.103  static int
1.104 -SDL_ResampleAudioSimple(const int chans, const double rate_incr,
1.105 +SDL_ResampleAudio(const int chans, const int inrate, const int outrate,
1.106                          float *last_sample, const float *inbuf,
1.107                          const int inbuflen, float *outbuf, const int outbuflen)
1.108  {
1.109 +    const float outtimeincr = 1.0f / ((float) outrate);
1.110 +    const float ratio = ((float) outrate) / ((float) inrate);
1.111 +    /*const int padding_len = (ratio < 1.0f) ? (int) SDL_ceilf(((float) (RESAMPLER_SAMPLES_PER_ZERO_CROSSING * inrate) / ((float) outrate))) : RESAMPLER_SAMPLES_PER_ZERO_CROSSING;*/
1.112      const int framelen = chans * (int)sizeof (float);
1.113 -    const int total = (inbuflen / framelen);
1.114 -    const int finalpos = (total * chans) - chans;
1.115 -    const int dest_samples = (int)(((double)total) * rate_incr);
1.116 -    const double src_incr = 1.0 / rate_incr;
1.117 -    float *dst;
1.118 -    double idx;
1.119 -    int i;
1.120 +    const int inframes = inbuflen / framelen;
1.121 +    const int wantedoutframes = (int) ((inbuflen / framelen) * ratio);  /* outbuflen isn't total to write, it's total available. */
1.122 +    const int maxoutframes = outbuflen / framelen;
1.123 +    const int outframes = (wantedoutframes < maxoutframes) ? wantedoutframes : maxoutframes;
1.124 +    float *dst = outbuf;
1.125 +    float outtime = 0.0f;
1.126 +    int i, j, chan;
1.127
1.128 -    SDL_assert((dest_samples * framelen) <= outbuflen);
1.129 -    SDL_assert((inbuflen % framelen) == 0);
1.130 +    for (i = 0; i < outframes; i++) {
1.131 +        const int srcindex = (int) (outtime * inrate);
1.132 +        const float finrate = (float) inrate;
1.133 +        const float intime = ((float) srcindex) / finrate;
1.134 +        const float innexttime = ((float) (srcindex + 1)) / finrate;
1.135
1.136 -    if (rate_incr > 1.0) {  /* upsample */
1.137 -        float *target = (outbuf + chans);
1.138 -        dst = outbuf + (dest_samples * chans);
1.139 -        idx = (double) total;
1.140 +        const float interpolation1 = 1.0f - (innexttime - outtime) / (innexttime - intime);
1.141 +        const int filterindex1 = (int) (interpolation1 * RESAMPLER_SAMPLES_PER_ZERO_CROSSING);
1.142 +        const float interpolation2 = 1.0f - interpolation1;
1.143 +        const int filterindex2 = interpolation2 * RESAMPLER_SAMPLES_PER_ZERO_CROSSING;
1.144
1.145 -        if (chans == 1) {
1.146 -            const float final_sample = inbuf[finalpos];
1.147 -            float earlier_sample = inbuf[finalpos];
1.148 -            while (dst > target) {
1.149 -                const int pos = ((int) idx) * chans;
1.150 -                const float *src = &inbuf[pos];
1.151 -                const float val = *(--src);
1.152 -                SDL_assert(pos >= 0.0);
1.153 -                *(--dst) = (val + earlier_sample) * 0.5f;
1.154 -                earlier_sample = val;
1.155 -                idx -= src_incr;
1.156 +        for (chan = 0; chan < chans; chan++) {
1.157 +            float outsample = 0.0f;
1.158 +
1.159 +            /* do this twice to calculate the sample, once for the "left wing" and then same for the right. */
1.160 +            /* !!! FIXME: do both wings in one loop */
1.161 +            for (j = 0; (filterindex1 + (j * RESAMPLER_SAMPLES_PER_ZERO_CROSSING)) < RESAMPLER_FILTER_SIZE; j++) {
1.162 +                /* !!! FIXME: insample uses zero for padding samples, but it should use prior state from last_sample. */
1.163 +                const int srcframe = srcindex - j;
1.164 +                const float insample = (srcframe < 0) ? 0.0f : inbuf[(srcframe * chans) + chan];  /* !!! FIXME: we can bubble this conditional out of here by doing a pre loop. */
1.165 +                outsample += (insample * (ResamplerFilter[filterindex1 + (j * RESAMPLER_SAMPLES_PER_ZERO_CROSSING)] + (interpolation1 * ResamplerFilterDifference[filterindex1 + (j * RESAMPLER_SAMPLES_PER_ZERO_CROSSING)])));
1.166              }
1.167 -            /* do last sample, interpolated against previous run's state. */
1.168 -            *(--dst) = (inbuf[0] + last_sample[0]) * 0.5f;
1.169 -            *last_sample = final_sample;
1.170 -        } else if (chans == 2) {
1.171 -            const float final_sample2 = inbuf[finalpos+1];
1.172 -            const float final_sample1 = inbuf[finalpos];
1.173 -            float earlier_sample2 = inbuf[finalpos];
1.174 -            float earlier_sample1 = inbuf[finalpos-1];
1.175 -            while (dst > target) {
1.176 -                const int pos = ((int) idx) * chans;
1.177 -                const float *src = &inbuf[pos];
1.178 -                const float val2 = *(--src);
1.179 -                const float val1 = *(--src);
1.180 -                SDL_assert(pos >= 0.0);
1.181 -                *(--dst) = (val2 + earlier_sample2) * 0.5f;
1.182 -                *(--dst) = (val1 + earlier_sample1) * 0.5f;
1.183 -                earlier_sample2 = val2;
1.184 -                earlier_sample1 = val1;
1.185 -                idx -= src_incr;
1.186 +
1.187 +            for (j = 0; (filterindex2 + (j * RESAMPLER_SAMPLES_PER_ZERO_CROSSING)) < RESAMPLER_FILTER_SIZE; j++) {
1.188 +                const int srcframe = srcindex + 1 + j;
1.189 +                /* !!! FIXME: insample uses zero for padding samples, but it should use prior state from last_sample. */
1.190 +                const float insample = (srcframe >= inframes) ? 0.0f : inbuf[(srcframe * chans) + chan];  /* !!! FIXME: we can bubble this conditional out of here by doing a post loop. */
1.191 +                outsample += (insample * (ResamplerFilter[filterindex2 + (j * RESAMPLER_SAMPLES_PER_ZERO_CROSSING)] + (interpolation2 * ResamplerFilterDifference[filterindex2 + (j * RESAMPLER_SAMPLES_PER_ZERO_CROSSING)])));
1.192              }
1.193 -            /* do last sample, interpolated against previous run's state. */
1.194 -            *(--dst) = (inbuf[1] + last_sample[1]) * 0.5f;
1.195 -            *(--dst) = (inbuf[0] + last_sample[0]) * 0.5f;
1.196 -            last_sample[1] = final_sample2;
1.197 -            last_sample[0] = final_sample1;
1.198 -        } else {
1.199 -            const float *earlier_sample = &inbuf[finalpos];
1.200 -            float final_sample[8];
1.201 -            SDL_memcpy(final_sample, &inbuf[finalpos], framelen);
1.202 -            while (dst > target) {
1.203 -                const int pos = ((int) idx) * chans;
1.204 -                const float *src = &inbuf[pos];
1.205 -                SDL_assert(pos >= 0.0);
1.206 -                for (i = chans - 1; i >= 0; i--) {
1.207 -                    const float val = *(--src);
1.208 -                    *(--dst) = (val + earlier_sample[i]) * 0.5f;
1.209 -                }
1.210 -                earlier_sample = src;
1.211 -                idx -= src_incr;
1.212 -            }
1.213 -            /* do last sample, interpolated against previous run's state. */
1.214 -            for (i = chans - 1; i >= 0; i--) {
1.215 -                const float val = inbuf[i];
1.216 -                *(--dst) = (val + last_sample[i]) * 0.5f;
1.217 -            }
1.218 -            SDL_memcpy(last_sample, final_sample, framelen);
1.219 +            *(dst++) = outsample;
1.220          }
1.221
1.222 -        dst = (outbuf + (dest_samples * chans));
1.223 -    } else {  /* downsample */
1.224 -        float *target = (outbuf + (dest_samples * chans));
1.225 -        dst = outbuf;
1.226 -        idx = 0.0;
1.227 -        if (chans == 1) {
1.228 -            float last = *last_sample;
1.229 -            while (dst < target) {
1.230 -                const int pos = ((int) idx) * chans;
1.231 -                const float val = inbuf[pos];
1.232 -                SDL_assert(pos <= finalpos);
1.233 -                *(dst++) = (val + last) * 0.5f;
1.234 -                last = val;
1.235 -                idx += src_incr;
1.236 -            }
1.237 -            *last_sample = last;
1.238 -        } else if (chans == 2) {
1.239 -            float last1 = last_sample[0];
1.240 -            float last2 = last_sample[1];
1.241 -            while (dst < target) {
1.242 -                const int pos = ((int) idx) * chans;
1.243 -                const float val1 = inbuf[pos];
1.244 -                const float val2 = inbuf[pos+1];
1.245 -                SDL_assert(pos <= finalpos);
1.246 -                *(dst++) = (val1 + last1) * 0.5f;
1.247 -                *(dst++) = (val2 + last2) * 0.5f;
1.248 -                last1 = val1;
1.249 -                last2 = val2;
1.250 -                idx += src_incr;
1.251 -            }
1.252 -            last_sample[0] = last1;
1.253 -            last_sample[1] = last2;
1.254 -        } else {
1.255 -            while (dst < target) {
1.256 -                const int pos = ((int) idx) * chans;
1.257 -                const float *src = &inbuf[pos];
1.258 -                SDL_assert(pos <= finalpos);
1.259 -                for (i = 0; i < chans; i++) {
1.260 -                    const float val = *(src++);
1.261 -                    *(dst++) = (val + last_sample[i]) * 0.5f;
1.262 -                    last_sample[i] = val;
1.263 -                }
1.264 -                idx += src_incr;
1.265 -            }
1.266 -        }
1.267 +        outtime += outtimeincr;
1.268      }
1.269
1.270 -    return (int) ((dst - outbuf) * ((int) sizeof (float)));
1.271 +    return outframes * chans * sizeof (float);
1.272  }
1.273
1.274 -/* We keep one special-case fast path around for an extremely common audio format. */
1.275 -static int
1.276 -SDL_ResampleAudioSimple_si16_c2(const double rate_incr,
1.277 -                        Sint16 *last_sample, const Sint16 *inbuf,
1.278 -                        const int inbuflen, Sint16 *outbuf, const int outbuflen)
1.279 -{
1.280 -    const int chans = 2;
1.281 -    const int framelen = 4;  /* stereo 16 bit */
1.282 -    const int total = (inbuflen / framelen);
1.283 -    const int finalpos = (total * chans) - chans;
1.284 -    const int dest_samples = (int)(((double)total) * rate_incr);
1.285 -    const double src_incr = 1.0 / rate_incr;
1.286 -    Sint16 *dst;
1.287 -    double idx;
1.288 -
1.289 -    SDL_assert((dest_samples * framelen) <= outbuflen);
1.290 -    SDL_assert((inbuflen % framelen) == 0);
1.291 -
1.292 -    if (rate_incr > 1.0) {
1.293 -        Sint16 *target = (outbuf + chans);
1.294 -        const Sint16 final_right = inbuf[finalpos+1];
1.295 -        const Sint16 final_left = inbuf[finalpos];
1.296 -        Sint16 earlier_right = inbuf[finalpos-1];
1.297 -        Sint16 earlier_left = inbuf[finalpos-2];
1.298 -        dst = outbuf + (dest_samples * chans);
1.299 -        idx = (double) total;
1.300 -
1.301 -        while (dst > target) {
1.302 -            const int pos = ((int) idx) * chans;
1.303 -            const Sint16 *src = &inbuf[pos];
1.304 -            const Sint16 right = *(--src);
1.305 -            const Sint16 left = *(--src);
1.306 -            SDL_assert(pos >= 0.0);
1.307 -            *(--dst) = (((Sint32) right) + ((Sint32) earlier_right)) >> 1;
1.308 -            *(--dst) = (((Sint32) left) + ((Sint32) earlier_left)) >> 1;
1.309 -            earlier_right = right;
1.310 -            earlier_left = left;
1.311 -            idx -= src_incr;
1.312 -        }
1.313 -
1.314 -        /* do last sample, interpolated against previous run's state. */
1.315 -        *(--dst) = (((Sint32) inbuf[1]) + ((Sint32) last_sample[1])) >> 1;
1.316 -        *(--dst) = (((Sint32) inbuf[0]) + ((Sint32) last_sample[0])) >> 1;
1.317 -        last_sample[1] = final_right;
1.318 -        last_sample[0] = final_left;
1.319 -
1.320 -        dst = (outbuf + (dest_samples * chans));
1.321 -    } else {
1.322 -        Sint16 *target = (outbuf + (dest_samples * chans));
1.323 -        dst = outbuf;
1.324 -        idx = 0.0;
1.325 -        while (dst < target) {
1.326 -            const int pos = ((int) idx) * chans;
1.327 -            const Sint16 *src = &inbuf[pos];
1.328 -            const Sint16 left = *(src++);
1.329 -            const Sint16 right = *(src++);
1.330 -            SDL_assert(pos <= finalpos);
1.331 -            *(dst++) = (((Sint32) left) + ((Sint32) last_sample[0])) >> 1;
1.332 -            *(dst++) = (((Sint32) right) + ((Sint32) last_sample[1])) >> 1;
1.333 -            last_sample[0] = left;
1.334 -            last_sample[1] = right;
1.335 -            idx += src_incr;
1.336 -        }
1.337 -    }
1.338 -
1.339 -    return (int) ((dst - outbuf) * ((int) sizeof (Sint16)));
1.340 -}
1.341 -
1.342 -static void SDLCALL
1.343 -SDL_ResampleCVT_si16_c2(SDL_AudioCVT *cvt, SDL_AudioFormat format)
1.344 -{
1.345 -    const Sint16 *src = (const Sint16 *) cvt->buf;
1.346 -    const int srclen = cvt->len_cvt;
1.347 -    Sint16 *dst = (Sint16 *) cvt->buf;
1.348 -    const int dstlen = (cvt->len * cvt->len_mult);
1.349 -    Sint16 state[2];
1.350 -
1.351 -    state[0] = src[0];
1.352 -    state[1] = src[1];
1.353 -
1.354 -    SDL_assert(format == AUDIO_S16SYS);
1.355 -
1.356 -    cvt->len_cvt = SDL_ResampleAudioSimple_si16_c2(cvt->rate_incr, state, src, srclen, dst, dstlen);
1.357 -    if (cvt->filters[++cvt->filter_index]) {
1.358 -        cvt->filters[cvt->filter_index](cvt, format);
1.359 -    }
1.360 -}
1.361 -
1.362 -
1.363  int
1.364  SDL_ConvertAudio(SDL_AudioCVT * cvt)
1.365  {
1.366 @@ -761,17 +690,28 @@
1.367  static void
1.368  SDL_ResampleCVT(SDL_AudioCVT *cvt, const int chans, const SDL_AudioFormat format)
1.369  {
1.370 +    /* !!! FIXME in 2.1: there are ten slots in the filter list, and the theoretical maximum we use is six (seven with NULL terminator).
1.371 +       !!! FIXME in 2.1:   We need to store data for this resampler, because the cvt structure doesn't store the original sample rates,
1.372 +       !!! FIXME in 2.1:   so we steal the ninth and tenth slot.  :( */
1.373 +    const int srcrate = (int) (size_t) cvt->filters[SDL_AUDIOCVT_MAX_FILTERS-1];
1.374 +    const int dstrate = (int) (size_t) cvt->filters[SDL_AUDIOCVT_MAX_FILTERS];
1.375      const float *src = (const float *) cvt->buf;
1.376      const int srclen = cvt->len_cvt;
1.377 -    float *dst = (float *) cvt->buf;
1.378 -    const int dstlen = (cvt->len * cvt->len_mult);
1.379 +    /*float *dst = (float *) cvt->buf;
1.380 +    const int dstlen = (cvt->len * cvt->len_mult);*/
1.381 +    /* !!! FIXME: remove this if we can get the resampler to work in-place again. */
1.382 +    float *dst = (float *) (cvt->buf + srclen);
1.383 +    const int dstlen = (cvt->len * cvt->len_mult) - srclen;
1.384      float state[8];
1.385
1.386      SDL_assert(format == AUDIO_F32SYS);
1.387
1.388 -    SDL_memcpy(state, src, chans*sizeof(*src));
1.389 +    SDL_zero(state);
1.390
1.391 -    cvt->len_cvt = SDL_ResampleAudioSimple(chans, cvt->rate_incr, state, src, srclen, dst, dstlen);
1.392 +    cvt->len_cvt = SDL_ResampleAudio(chans, srcrate, dstrate, state, src, srclen, dst, dstlen);
1.393 +
1.394 +    SDL_memcpy(cvt->buf, dst, cvt->len_cvt);  /* !!! FIXME: remove this if we can get the resampler to work in-place again. */
1.395 +
1.396      if (cvt->filters[++cvt->filter_index]) {
1.397          cvt->filters[cvt->filter_index](cvt, format);
1.398      }
1.399 @@ -823,10 +763,24 @@
1.400          return SDL_SetError("No conversion available for these rates");
1.401      }
1.402
1.403 +    if (SDL_PrepareResampleFilter() < 0) {
1.404 +        return -1;
1.405 +    }
1.406 +
1.407      /* Update (cvt) with filter details... */
1.408      if (SDL_AddAudioCVTFilter(cvt, filter) < 0) {
1.409          return -1;
1.410      }
1.411 +
1.412 +    /* !!! FIXME in 2.1: there are ten slots in the filter list, and the theoretical maximum we use is six (seven with NULL terminator).
1.413 +       !!! FIXME in 2.1:   We need to store data for this resampler, because the cvt structure doesn't store the original sample rates,
1.414 +       !!! FIXME in 2.1:   so we steal the ninth and tenth slot.  :( */
1.415 +    if (cvt->filter_index >= (SDL_AUDIOCVT_MAX_FILTERS-2)) {
1.416 +        return SDL_SetError("Too many filters needed for conversion, exceeded maximum of %d", SDL_AUDIOCVT_MAX_FILTERS-2);
1.417 +    }
1.418 +    cvt->filters[SDL_AUDIOCVT_MAX_FILTERS-1] = (SDL_AudioFilter) (size_t) src_rate;
1.419 +    cvt->filters[SDL_AUDIOCVT_MAX_FILTERS] = (SDL_AudioFilter) (size_t) dst_rate;
1.420 +
1.421      if (src_rate < dst_rate) {
1.422          const double mult = ((double) dst_rate) / ((double) src_rate);
1.423          cvt->len_mult *= (int) SDL_ceil(mult);
1.424 @@ -835,6 +789,11 @@
1.425          cvt->len_ratio /= ((double) src_rate) / ((double) dst_rate);
1.426      }
1.427
1.428 +    /* !!! FIXME: remove this if we can get the resampler to work in-place again. */
1.429 +    /* the buffer is big enough to hold the destination now, but
1.430 +       we need it large enough to hold a separate scratch buffer. */
1.431 +    cvt->len_mult *= 2;
1.432 +
1.433      return 1;               /* added a converter. */
1.434  }
1.435
1.436 @@ -922,7 +881,7 @@
1.437      cvt->dst_format = dst_fmt;
1.438      cvt->needed = 0;
1.439      cvt->filter_index = 0;
1.440 -    cvt->filters[0] = NULL;
1.441 +    SDL_zero(cvt->filters);
1.442      cvt->len_mult = 1;
1.443      cvt->len_ratio = 1.0;
1.444      cvt->rate_incr = ((double) dst_rate) / ((double) src_rate);
1.445 @@ -930,32 +889,6 @@
1.446      /* Make sure we've chosen audio conversion functions (MMX, scalar, etc.) */
1.447      SDL_ChooseAudioConverters();
1.448
1.449 -    /* SDL now favors float32 as its preferred internal format, and considers
1.450 -       everything else to be a degenerate case that we might have to make
1.451 -       multiple passes over the data to convert to and from float32 as
1.452 -       necessary. That being said, we keep one special case around for
1.453 -       efficiency: stereo data in Sint16 format, in the native byte order,
1.454 -       that only needs resampling. This is likely to be the most popular
1.455 -       legacy format, that apps, hardware and the OS are likely to be able
1.456 -       to process directly, so we handle this one case directly without
1.457 -       unnecessary conversions. This means that apps on embedded devices
1.458 -       without floating point hardware should consider aiming for this
1.459 -       format as well. */
1.460 -    if ((src_channels == 2) && (dst_channels == 2) && (src_fmt == AUDIO_S16SYS) && (dst_fmt == AUDIO_S16SYS) && (src_rate != dst_rate)) {
1.461 -        cvt->needed = 1;
1.462 -        if (SDL_AddAudioCVTFilter(cvt, SDL_ResampleCVT_si16_c2) < 0) {
1.463 -            return -1;
1.464 -        }
1.465 -        if (src_rate < dst_rate) {
1.466 -            const double mult = ((double) dst_rate) / ((double) src_rate);
1.467 -            cvt->len_mult *= (int) SDL_ceil(mult);
1.468 -            cvt->len_ratio *= mult;
1.469 -        } else {
1.470 -            cvt->len_ratio /= ((double) src_rate) / ((double) dst_rate);
1.471 -        }
1.472 -        return 1;
1.473 -    }
1.474 -
1.475      /* Type conversion goes like this now:
1.476          - byteswap to CPU native format first if necessary.
1.477          - convert to native Float32 if necessary.
1.478 @@ -1282,30 +1215,23 @@
1.479
1.480      SDL_assert(chans <= SDL_arraysize(state->resampler_state.f));
1.481
1.482 +    if (inbuf == ((const float *) outbuf)) {  /* !!! FIXME can't work in-place (for now!). */
1.483 +        Uint8 *ptr = EnsureStreamBufferSize(stream, inbuflen + outbuflen);
1.484 +        if (ptr == NULL) {
1.485 +            SDL_OutOfMemory();
1.486 +            return 0;
1.487 +        }
1.488 +        SDL_memcpy(ptr + outbuflen, ptr, inbuflen);
1.489 +        inbuf = (const float *) (ptr + outbuflen);
1.490 +        outbuf = (float *) ptr;
1.491 +    }
1.492 +
1.493      if (!state->resampler_seeded) {
1.494 -        SDL_memcpy(state->resampler_state.f, inbuf, chans * sizeof (float));
1.495 +        SDL_zero(state->resampler_state.f);
1.496          state->resampler_seeded = SDL_TRUE;
1.497      }
1.498
1.499 -    return SDL_ResampleAudioSimple(chans, stream->rate_incr, state->resampler_state.f, inbuf, inbuflen, outbuf, outbuflen);
1.500 -}
1.501 -
1.502 -static int
1.503 -SDL_ResampleAudioStream_si16_c2(SDL_AudioStream *stream, const void *_inbuf, const int inbuflen, void *_outbuf, const int outbuflen)
1.504 -{
1.505 -    const Sint16 *inbuf = (const Sint16 *) _inbuf;
1.506 -    Sint16 *outbuf = (Sint16 *) _outbuf;
1.507 -    SDL_AudioStreamResamplerState *state = (SDL_AudioStreamResamplerState*)stream->resampler_state;
1.508 -
1.509 -    SDL_assert(((int)stream->pre_resample_channels) <= SDL_arraysize(state->resampler_state.si16));
1.510 -
1.511 -    if (!state->resampler_seeded) {
1.512 -        state->resampler_state.si16[0] = inbuf[0];
1.513 -        state->resampler_state.si16[1] = inbuf[1];
1.514 -        state->resampler_seeded = SDL_TRUE;
1.515 -    }
1.516 -
1.517 -    return SDL_ResampleAudioSimple_si16_c2(stream->rate_incr, state->resampler_state.si16, inbuf, inbuflen, outbuf, outbuflen);
1.518 +    return SDL_ResampleAudio(chans, stream->src_rate, stream->dst_rate, state->resampler_state.f, inbuf, inbuflen, outbuf, outbuflen);
1.519  }
1.520
1.521  static void
1.522 @@ -1332,9 +1258,6 @@
1.523      const int packetlen = 4096;  /* !!! FIXME: good enough for now. */
1.524      Uint8 pre_resample_channels;
1.525      SDL_AudioStream *retval;
1.526 -#ifndef HAVE_LIBSAMPLERATE_H
1.527 -    const SDL_bool SRC_available = SDL_FALSE;
1.528 -#endif
1.529
1.530      retval = (SDL_AudioStream *) SDL_calloc(1, sizeof (SDL_AudioStream));
1.531      if (!retval) {
1.532 @@ -1366,18 +1289,6 @@
1.533              SDL_FreeAudioStream(retval);
1.534              return NULL;  /* SDL_BuildAudioCVT should have called SDL_SetError. */
1.535          }
1.536 -    /* fast path special case for stereo Sint16 data that just needs resampling. */
1.537 -    } else if ((!SRC_available) && (src_channels == 2) && (dst_channels == 2) && (src_format == AUDIO_S16SYS) && (dst_format == AUDIO_S16SYS)) {
1.538 -        SDL_assert(src_rate != dst_rate);
1.539 -        retval->resampler_state = SDL_calloc(1, sizeof(SDL_AudioStreamResamplerState));
1.540 -        if (!retval->resampler_state) {
1.541 -            SDL_FreeAudioStream(retval);
1.542 -            SDL_OutOfMemory();
1.543 -            return NULL;
1.544 -        }
1.545 -        retval->resampler_func = SDL_ResampleAudioStream_si16_c2;
1.546 -        retval->reset_resampler_func = SDL_ResetAudioStreamResampler;
1.547 -        retval->cleanup_resampler_func = SDL_CleanupAudioStreamResampler;
1.548      } else {
1.549          /* Don't resample at first. Just get us to Float32 format. */
1.550          /* !!! FIXME: convert to int32 on devices without hardware float. */
1.551 @@ -1397,6 +1308,14 @@
1.552                  SDL_OutOfMemory();
1.553                  return NULL;
1.554              }
1.555 +
1.556 +            if (SDL_PrepareResampleFilter() < 0) {
1.557 +                SDL_free(retval->resampler_state);
1.558 +                retval->resampler_state = NULL;
1.559 +                SDL_FreeAudioStream(retval);
1.560 +                return NULL;
1.561 +            }
1.562 +
1.563              retval->resampler_func = SDL_ResampleAudioStream;
1.564              retval->reset_resampler_func = SDL_ResetAudioStreamResampler;
1.565              retval->cleanup_resampler_func = SDL_CleanupAudioStreamResampler;
```