src/audio/SDL_audiocvt.c
changeset 10834 336efe4fc373
parent 10833 86f6353f1aae
child 10835 0e9e7a128391
     1.1 --- a/src/audio/SDL_audiocvt.c	Sun Jan 22 23:48:15 2017 -0500
     1.2 +++ b/src/audio/SDL_audiocvt.c	Sun Jan 22 20:27:48 2017 -0500
     1.3 @@ -301,6 +301,91 @@
     1.4      return (int) ((dst - outbuf) * ((int) sizeof (float)));
     1.5  }
     1.6  
     1.7 +/* We keep one special-case fast path around for an extremely common audio format. */
     1.8 +static int
     1.9 +SDL_ResampleAudioSimple_si16_c2(const double rate_incr,
    1.10 +                        Sint16 *last_sample, const Sint16 *inbuf,
    1.11 +                        const int inbuflen, Sint16 *outbuf, const int outbuflen)
    1.12 +{
    1.13 +    const int chans = 2;
    1.14 +    const int framelen = 4;  /* stereo 16 bit */
    1.15 +    const int total = (inbuflen / framelen);
    1.16 +    const int finalpos = (total * chans) - chans;
    1.17 +    const int dest_samples = (int)(((double)total) * rate_incr);
    1.18 +    const double src_incr = 1.0 / rate_incr;
    1.19 +    Sint16 *dst;
    1.20 +    double idx;
    1.21 +
    1.22 +    SDL_assert((dest_samples * framelen) <= outbuflen);
    1.23 +    SDL_assert((inbuflen % framelen) == 0);
    1.24 +
    1.25 +    if (rate_incr > 1.0) {
    1.26 +        Sint16 *target = (outbuf + chans);
    1.27 +        const Sint16 final_right = inbuf[finalpos+1];
    1.28 +        const Sint16 final_left = inbuf[finalpos];
    1.29 +        Sint16 earlier_right = inbuf[finalpos-1];
    1.30 +        Sint16 earlier_left = inbuf[finalpos-2];
    1.31 +        dst = outbuf + (dest_samples * chans);
    1.32 +        idx = (double) total;
    1.33 +
    1.34 +        while (dst > target) {
    1.35 +            const int pos = ((int) idx) * chans;
    1.36 +            const Sint16 *src = &inbuf[pos];
    1.37 +            const Sint16 right = *(--src);
    1.38 +            const Sint16 left = *(--src);
    1.39 +            SDL_assert(pos >= 0.0);
    1.40 +            *(--dst) = (((Sint32) right) + ((Sint32) earlier_right)) >> 1;
    1.41 +            *(--dst) = (((Sint32) left) + ((Sint32) earlier_left)) >> 1;
    1.42 +            earlier_right = right;
    1.43 +            earlier_left = left;
    1.44 +            idx -= src_incr;
    1.45 +        }
    1.46 +
    1.47 +        /* do last sample, interpolated against previous run's state. */
    1.48 +        *(--dst) = (((Sint32) inbuf[1]) + ((Sint32) last_sample[1])) >> 1;
    1.49 +        *(--dst) = (((Sint32) inbuf[0]) + ((Sint32) last_sample[0])) >> 1;
    1.50 +        last_sample[1] = final_right;
    1.51 +        last_sample[0] = final_left;
    1.52 +
    1.53 +        dst = (outbuf + (dest_samples * chans)) - 1;
    1.54 +    } else {
    1.55 +        Sint16 *target = (outbuf + (dest_samples * chans));
    1.56 +        dst = outbuf;
    1.57 +        idx = 0.0;
    1.58 +        while (dst < target) {
    1.59 +            const int pos = ((int) idx) * chans;
    1.60 +            const Sint16 *src = &inbuf[pos];
    1.61 +            const Sint16 left = *(src++);
    1.62 +            const Sint16 right = *(src++);
    1.63 +            SDL_assert(pos <= finalpos);
    1.64 +            *(dst++) = (((Sint32) left) + ((Sint32) last_sample[0])) >> 1;
    1.65 +            *(dst++) = (((Sint32) right) + ((Sint32) last_sample[1])) >> 1;
    1.66 +            last_sample[0] = left;
    1.67 +            last_sample[1] = right;
    1.68 +            idx += src_incr;
    1.69 +        }
    1.70 +    }
    1.71 +
    1.72 +    return (int) ((dst - outbuf) * ((int) sizeof (Sint16)));
    1.73 +}
    1.74 +
    1.75 +static void SDLCALL
    1.76 +SDL_ResampleCVT_si16_c2(SDL_AudioCVT *cvt, SDL_AudioFormat format)
    1.77 +{
    1.78 +    const Sint16 *src = (const Sint16 *) cvt->buf;
    1.79 +    const int srclen = cvt->len_cvt;
    1.80 +    Sint16 *dst = (Sint16 *) (cvt->buf + srclen);
    1.81 +    const int dstlen = (cvt->len * cvt->len_mult) - srclen;
    1.82 +    Sint16 state[2] = { src[0], src[1] };
    1.83 +
    1.84 +    SDL_assert(format == AUDIO_S16SYS);
    1.85 +
    1.86 +    cvt->len_cvt = SDL_ResampleAudioSimple_si16_c2(cvt->rate_incr, state, src, srclen, dst, dstlen);
    1.87 +    if (cvt->filters[++cvt->filter_index]) {
    1.88 +        cvt->filters[cvt->filter_index](cvt, format);
    1.89 +    }
    1.90 +}
    1.91 +
    1.92  
    1.93  int
    1.94  SDL_ConvertAudio(SDL_AudioCVT * cvt)
    1.95 @@ -575,6 +660,30 @@
    1.96      cvt->len_ratio = 1.0;
    1.97      cvt->rate_incr = ((double) dst_rate) / ((double) src_rate);
    1.98  
    1.99 +    /* SDL now favors float32 as its preferred internal format, and considers
   1.100 +       everything else to be a degenerate case that we might have to make
   1.101 +       multiple passes over the data to convert to and from float32 as
   1.102 +       necessary. That being said, we keep one special case around for
   1.103 +       efficiency: stereo data in Sint16 format, in the native byte order,
   1.104 +       that only needs resampling. This is likely to be the most popular
   1.105 +       legacy format, that apps, hardware and the OS are likely to be able
   1.106 +       to process directly, so we handle this one case directly without
   1.107 +       unnecessary conversions. This means that apps on embedded devices
   1.108 +       without floating point hardware should consider aiming for this
   1.109 +       format as well. */
   1.110 +    if ((src_channels == 2) && (dst_channels == 2) && (src_fmt == AUDIO_S16SYS) && (dst_fmt == AUDIO_S16SYS) && (src_rate != dst_rate)) {
   1.111 +        cvt->needed = 1;
   1.112 +        cvt->filters[cvt->filter_index++] = SDL_ResampleCVT_si16_c2;
   1.113 +        if (src_rate < dst_rate) {
   1.114 +            const double mult = ((double) dst_rate) / ((double) src_rate);
   1.115 +            cvt->len_mult *= (int) SDL_ceil(mult);
   1.116 +            cvt->len_ratio *= mult;
   1.117 +        } else {
   1.118 +            cvt->len_ratio /= ((double) src_rate) / ((double) dst_rate);
   1.119 +        }
   1.120 +        return 1;
   1.121 +    }
   1.122 +
   1.123      /* Type conversion goes like this now:
   1.124          - byteswap to CPU native format first if necessary.
   1.125          - convert to native Float32 if necessary.