Forráskód Böngészése

audio: Special case for resampling stereo AUDIO_S16SYS audio data.

This is a fairly common case, so we avoid the conversion to/from float here.
Ryan C. Gordon 8 éve
szülő
commit
202ab30c16
1 módosított fájl, 109 hozzáadás és 0 törlés
  1. 109 0
      src/audio/SDL_audiocvt.c

+ 109 - 0
src/audio/SDL_audiocvt.c

@@ -301,6 +301,91 @@ SDL_ResampleAudioSimple(const int chans, const double rate_incr,
     return (int) ((dst - outbuf) * ((int) sizeof (float)));
 }
 
+/* We keep one special-case fast path around for an extremely common audio format. */
+static int
+SDL_ResampleAudioSimple_si16_c2(const double rate_incr,
+                        Sint16 *last_sample, const Sint16 *inbuf,
+                        const int inbuflen, Sint16 *outbuf, const int outbuflen)
+{
+    const int chans = 2;
+    const int framelen = 4;  /* stereo 16 bit */
+    const int total = (inbuflen / framelen);
+    const int finalpos = (total * chans) - chans;
+    const int dest_samples = (int)(((double)total) * rate_incr);
+    const double src_incr = 1.0 / rate_incr;
+    Sint16 *dst;
+    double idx;
+
+    SDL_assert((dest_samples * framelen) <= outbuflen);
+    SDL_assert((inbuflen % framelen) == 0);
+
+    if (rate_incr > 1.0) {
+        Sint16 *target = (outbuf + chans);
+        const Sint16 final_right = inbuf[finalpos+1];
+        const Sint16 final_left = inbuf[finalpos];
+        Sint16 earlier_right = inbuf[finalpos-1];
+        Sint16 earlier_left = inbuf[finalpos-2];
+        dst = outbuf + (dest_samples * chans);
+        idx = (double) total;
+
+        while (dst > target) {
+            const int pos = ((int) idx) * chans;
+            const Sint16 *src = &inbuf[pos];
+            const Sint16 right = *(--src);
+            const Sint16 left = *(--src);
+            SDL_assert(pos >= 0.0);
+            *(--dst) = (((Sint32) right) + ((Sint32) earlier_right)) >> 1;
+            *(--dst) = (((Sint32) left) + ((Sint32) earlier_left)) >> 1;
+            earlier_right = right;
+            earlier_left = left;
+            idx -= src_incr;
+        }
+
+        /* do last sample, interpolated against previous run's state. */
+        *(--dst) = (((Sint32) inbuf[1]) + ((Sint32) last_sample[1])) >> 1;
+        *(--dst) = (((Sint32) inbuf[0]) + ((Sint32) last_sample[0])) >> 1;
+        last_sample[1] = final_right;
+        last_sample[0] = final_left;
+
+        dst = (outbuf + (dest_samples * chans)) - 1;
+    } else {
+        Sint16 *target = (outbuf + (dest_samples * chans));
+        dst = outbuf;
+        idx = 0.0;
+        while (dst < target) {
+            const int pos = ((int) idx) * chans;
+            const Sint16 *src = &inbuf[pos];
+            const Sint16 left = *(src++);
+            const Sint16 right = *(src++);
+            SDL_assert(pos <= finalpos);
+            *(dst++) = (((Sint32) left) + ((Sint32) last_sample[0])) >> 1;
+            *(dst++) = (((Sint32) right) + ((Sint32) last_sample[1])) >> 1;
+            last_sample[0] = left;
+            last_sample[1] = right;
+            idx += src_incr;
+        }
+    }
+
+    return (int) ((dst - outbuf) * ((int) sizeof (Sint16)));
+}
+
+static void SDLCALL
+SDL_ResampleCVT_si16_c2(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+{
+    const Sint16 *src = (const Sint16 *) cvt->buf;
+    const int srclen = cvt->len_cvt;
+    Sint16 *dst = (Sint16 *) (cvt->buf + srclen);
+    const int dstlen = (cvt->len * cvt->len_mult) - srclen;
+    Sint16 state[2] = { src[0], src[1] };
+
+    SDL_assert(format == AUDIO_S16SYS);
+
+    cvt->len_cvt = SDL_ResampleAudioSimple_si16_c2(cvt->rate_incr, state, src, srclen, dst, dstlen);
+    if (cvt->filters[++cvt->filter_index]) {
+        cvt->filters[cvt->filter_index](cvt, format);
+    }
+}
+
 
 int
 SDL_ConvertAudio(SDL_AudioCVT * cvt)
@@ -575,6 +660,30 @@ SDL_BuildAudioCVT(SDL_AudioCVT * cvt,
     cvt->len_ratio = 1.0;
     cvt->rate_incr = ((double) dst_rate) / ((double) src_rate);
 
+    /* SDL now favors float32 as its preferred internal format, and considers
+       everything else to be a degenerate case that we might have to make
+       multiple passes over the data to convert to and from float32 as
+       necessary. That being said, we keep one special case around for
+       efficiency: stereo data in Sint16 format, in the native byte order,
+       that only needs resampling. This is likely to be the most popular
+       legacy format, that apps, hardware and the OS are likely to be able
+       to process directly, so we handle this one case directly without
+       unnecessary conversions. This means that apps on embedded devices
+       without floating point hardware should consider aiming for this
+       format as well. */
+    if ((src_channels == 2) && (dst_channels == 2) && (src_fmt == AUDIO_S16SYS) && (dst_fmt == AUDIO_S16SYS) && (src_rate != dst_rate)) {
+        cvt->needed = 1;
+        cvt->filters[cvt->filter_index++] = SDL_ResampleCVT_si16_c2;
+        if (src_rate < dst_rate) {
+            const double mult = ((double) dst_rate) / ((double) src_rate);
+            cvt->len_mult *= (int) SDL_ceil(mult);
+            cvt->len_ratio *= mult;
+        } else {
+            cvt->len_ratio /= ((double) src_rate) / ((double) dst_rate);
+        }
+        return 1;
+    }
+
     /* Type conversion goes like this now:
         - byteswap to CPU native format first if necessary.
         - convert to native Float32 if necessary.