audio: Resampler now special-cases stereo and mono processing.
authorRyan C. Gordon <icculus@icculus.org>
Mon, 23 Jan 2017 16:45:50 -0500
changeset 108403c3708a0b217
parent 10839 64f7fccca56e
child 10841 b9d6a3d65394
audio: Resampler now special-cases stereo and mono processing.

Turns out that iterating from 0 to channels-1 was a serious performance hit!

These cases now tend to match or beat the original audio resampler's speed!
src/audio/SDL_audiocvt.c
     1.1 --- a/src/audio/SDL_audiocvt.c	Mon Jan 23 16:42:47 2017 -0500
     1.2 +++ b/src/audio/SDL_audiocvt.c	Mon Jan 23 16:45:50 2017 -0500
     1.3 @@ -249,49 +249,115 @@
     1.4      SDL_assert((dest_samples * framelen) <= outbuflen);
     1.5      SDL_assert((inbuflen % framelen) == 0);
     1.6  
     1.7 -    if (rate_incr > 1.0) {
     1.8 +    if (rate_incr > 1.0) {  /* upsample */
     1.9          float *target = (outbuf + chans);
    1.10 -        const float *earlier_sample = &inbuf[finalpos];
    1.11 -        float final_sample[8];
    1.12          dst = outbuf + (dest_samples * chans);
    1.13          idx = (double) total;
    1.14  
    1.15 -        /* save this off so we can correctly maintain state between runs. */
    1.16 -        SDL_memcpy(final_sample, &inbuf[finalpos], framelen);
    1.17 -
    1.18 -        while (dst > target) {
    1.19 -            const int pos = ((int) idx) * chans;
    1.20 -            const float *src = &inbuf[pos];
    1.21 -            SDL_assert(pos >= 0.0);
    1.22 +        if (chans == 1) {
    1.23 +            const float final_sample = inbuf[finalpos];
    1.24 +            float earlier_sample = inbuf[finalpos];
    1.25 +            while (dst > target) {
    1.26 +                const int pos = ((int) idx) * chans;
    1.27 +                const float *src = &inbuf[pos];
    1.28 +                const float val = *(--src);
    1.29 +                SDL_assert(pos >= 0.0);
    1.30 +                *(--dst) = (val + earlier_sample) * 0.5f;
    1.31 +                earlier_sample = val;
    1.32 +                idx -= src_incr;
    1.33 +            }
    1.34 +            /* do last sample, interpolated against previous run's state. */
    1.35 +            *(--dst) = (inbuf[0] + last_sample[0]) * 0.5f;
    1.36 +            *last_sample = final_sample;
    1.37 +        } else if (chans == 2) {
    1.38 +            const float final_sample2 = inbuf[finalpos+1];
    1.39 +            const float final_sample1 = inbuf[finalpos];
    1.40 +            float earlier_sample2 = inbuf[finalpos];
    1.41 +            float earlier_sample1 = inbuf[finalpos-1];
    1.42 +            while (dst > target) {
    1.43 +                const int pos = ((int) idx) * chans;
    1.44 +                const float *src = &inbuf[pos];
    1.45 +                const float val2 = *(--src);
    1.46 +                const float val1 = *(--src);
    1.47 +                SDL_assert(pos >= 0.0);
    1.48 +                *(--dst) = (val2 + earlier_sample2) * 0.5f;
    1.49 +                *(--dst) = (val1 + earlier_sample1) * 0.5f;
    1.50 +                earlier_sample2 = val2;
    1.51 +                earlier_sample1 = val1;
    1.52 +                idx -= src_incr;
    1.53 +            }
    1.54 +            /* do last sample, interpolated against previous run's state. */
    1.55 +            *(--dst) = (inbuf[1] + last_sample[1]) * 0.5f;
    1.56 +            *(--dst) = (inbuf[0] + last_sample[0]) * 0.5f;
    1.57 +            last_sample[1] = final_sample2;
    1.58 +            last_sample[0] = final_sample1;
    1.59 +        } else {
    1.60 +            const float *earlier_sample = &inbuf[finalpos];
    1.61 +            float final_sample[8];
    1.62 +            SDL_memcpy(final_sample, &inbuf[finalpos], framelen);
    1.63 +            while (dst > target) {
    1.64 +                const int pos = ((int) idx) * chans;
    1.65 +                const float *src = &inbuf[pos];
    1.66 +                SDL_assert(pos >= 0.0);
    1.67 +                for (i = chans - 1; i >= 0; i--) {
    1.68 +                    const float val = *(--src);
    1.69 +                    *(--dst) = (val + earlier_sample[i]) * 0.5f;
    1.70 +                }
    1.71 +                earlier_sample = src;
    1.72 +                idx -= src_incr;
    1.73 +            }
    1.74 +            /* do last sample, interpolated against previous run's state. */
    1.75              for (i = chans - 1; i >= 0; i--) {
    1.76 -                const float val = *(--src);
    1.77 -                *(--dst) = (val + earlier_sample[i]) * 0.5f;
    1.78 +                const float val = inbuf[i];
    1.79 +                *(--dst) = (val + last_sample[i]) * 0.5f;
    1.80              }
    1.81 -            earlier_sample = src;
    1.82 -            idx -= src_incr;
    1.83 +            SDL_memcpy(last_sample, final_sample, framelen);
    1.84          }
    1.85  
    1.86 -        /* do last sample, interpolated against previous run's state. */
    1.87 -        for (i = chans - 1; i >= 0; i--) {
    1.88 -            const float val = inbuf[i];
    1.89 -            *(--dst) = (val + last_sample[i]) * 0.5f;
    1.90 -        }
    1.91 -        SDL_memcpy(last_sample, final_sample, framelen);
    1.92          dst = (outbuf + (dest_samples * chans)) - 1;
    1.93 -    } else {
    1.94 +    } else {  /* downsample */
    1.95          float *target = (outbuf + (dest_samples * chans));
    1.96          dst = outbuf;
    1.97          idx = 0.0;
    1.98 -        while (dst < target) {
    1.99 -            const int pos = ((int) idx) * chans;
   1.100 -            const float *src = &inbuf[pos];
   1.101 -            SDL_assert(pos <= finalpos);
   1.102 -            for (i = 0; i < chans; i++) {
   1.103 -                const float val = *(src++);
   1.104 -                *(dst++) = (val + last_sample[i]) * 0.5f;
   1.105 -                last_sample[i] = val;
   1.106 +        if (chans == 1) {
   1.107 +            float last = *last_sample;
   1.108 +            while (dst < target) {
   1.109 +                const int pos = ((int) idx) * chans;
   1.110 +                const float val = inbuf[pos];
   1.111 +                SDL_assert(pos <= finalpos);
   1.112 +                *(dst++) = (val + last) * 0.5f;
   1.113 +                last = val;
   1.114 +                idx += src_incr;
   1.115              }
   1.116 -            idx += src_incr;
   1.117 +            *last_sample = last;
   1.118 +        } else if (chans == 2) {
   1.119 +            float last1 = last_sample[0];
   1.120 +            float last2 = last_sample[1];
   1.121 +            while (dst < target) {
   1.122 +                const int pos = ((int) idx) * chans;
   1.123 +                const float val1 = inbuf[pos];
   1.124 +                const float val2 = inbuf[pos+1];
   1.125 +                SDL_assert(pos <= finalpos);
   1.126 +                *(dst++) = (val1 + last1) * 0.5f;
   1.127 +                *(dst++) = (val2 + last2) * 0.5f;
   1.128 +                last1 = val1;
   1.129 +                last2 = val2;
   1.130 +                idx += src_incr;
   1.131 +            }
   1.132 +            last_sample[0] = last1;
   1.133 +            last_sample[1] = last2;
   1.134 +        } else {
   1.135 +            while (dst < target) {
   1.136 +                const int pos = ((int) idx) * chans;
   1.137 +                const float *src = &inbuf[pos];
   1.138 +                SDL_assert(pos <= finalpos);
   1.139 +                for (i = 0; i < chans; i++) {
   1.140 +                    const float val = *(src++);
   1.141 +                    *(dst++) = (val + last_sample[i]) * 0.5f;
   1.142 +                    last_sample[i] = val;
   1.143 +                }
   1.144 +                idx += src_incr;
   1.145 +            }
   1.146          }
   1.147      }
   1.148