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;