فهرست منبع

audio: Replaced older resamplers in SDL_AudioCVT with the new ones.

Ryan C. Gordon 8 سال پیش
والد
کامیت
063c9d40d7
3فایلهای تغییر یافته به همراه118 افزوده شده و 288 حذف شده
  1. 0 4
      src/audio/SDL_audio_c.h
  2. 118 111
      src/audio/SDL_audiocvt.c
  3. 0 173
      src/audio/SDL_audiotypecvt.c

+ 0 - 4
src/audio/SDL_audio_c.h

@@ -63,10 +63,6 @@ void SDLCALL SDL_Convert_F32_to_U8(SDL_AudioCVT *cvt, SDL_AudioFormat format);
 void SDLCALL SDL_Convert_F32_to_S16(SDL_AudioCVT *cvt, SDL_AudioFormat format);
 void SDLCALL SDL_Convert_F32_to_U16(SDL_AudioCVT *cvt, SDL_AudioFormat format);
 void SDLCALL SDL_Convert_F32_to_S32(SDL_AudioCVT *cvt, SDL_AudioFormat format);
-void SDL_Upsample_Arbitrary(SDL_AudioCVT *cvt, const int channels);
-void SDL_Upsample_Multiple(SDL_AudioCVT *cvt, const int channels);
-void SDL_Downsample_Arbitrary(SDL_AudioCVT *cvt, const int channels);
-void SDL_Downsample_Multiple(SDL_AudioCVT *cvt, const int channels);
 
 
 /* SDL_AudioStream is a new audio conversion interface. It

+ 118 - 111
src/audio/SDL_audiocvt.c

@@ -191,6 +191,38 @@ SDL_ConvertStereoToQuad(SDL_AudioCVT * cvt, SDL_AudioFormat format)
     }
 }
 
+static int
+SDL_ResampleAudioSimple(const int chans, const double rate_incr,
+                        float *last_sample, const float *inbuf,
+                        const int inbuflen, float *outbuf, const int outbuflen)
+{
+    const int framelen = chans * sizeof(float);
+    const int total = (inbuflen / framelen);
+    const int finalpos = total - chans;
+    const double src_incr = 1.0 / rate_incr;
+    double idx = 0.0;
+    float *dst = outbuf;
+    int consumed = 0;
+    int i;
+
+    SDL_assert((inbuflen % framelen) == 0);
+
+    while (consumed < total) {
+        const int pos = ((int)idx) * chans;
+        const float *src = &inbuf[(pos >= finalpos) ? finalpos : pos];
+        SDL_assert(dst < (outbuf + (outbuflen / framelen)));
+        for (i = 0; i < chans; i++) {
+            const float val = *(src++);
+            *(dst++) = (val + last_sample[i]) * 0.5f;
+            last_sample[i] = val;
+        }
+        consumed = pos + chans;
+        idx += src_incr;
+    }
+
+    return (int)((dst - outbuf) * sizeof(float));
+}
+
 
 int
 SDL_ConvertAudio(SDL_AudioCVT * cvt)
@@ -338,31 +370,75 @@ SDL_BuildAudioTypeCVTFromFloat(SDL_AudioCVT *cvt, const SDL_AudioFormat dst_fmt)
     return retval;
 }
 
+static void
+SDL_ResampleCVT(SDL_AudioCVT *cvt, const int chans, const SDL_AudioFormat format)
+{
+    const float *src = (const float *) cvt->buf;
+    const int srclen = cvt->len_cvt;
+    float *dst = (float *) (cvt->buf + srclen);
+    const int dstlen = (cvt->len * cvt->len_mult) - srclen;
+    SDL_bool do_simple = SDL_TRUE;
+
+    SDL_assert(format == AUDIO_F32SYS);
+
+#ifdef HAVE_LIBSAMPLERATE_H
+    if (SRC_available) {
+        int result = 0;
+        SRC_STATE *state = SRC_src_new(SRC_SINC_FASTEST, chans, &result);
+        if (state) {
+            const int framelen = sizeof(float) * chans;
+            SRC_DATA data;
+
+            data.data_in = (float *)src; /* Older versions of libsamplerate had a non-const pointer, but didn't write to it */
+            data.input_frames = srclen / framelen;
+            data.input_frames_used = 0;
+
+            data.data_out = dst;
+            data.output_frames = dstlen / framelen;
+
+            data.end_of_input = 0;
+            data.src_ratio = cvt->rate_incr;
+
+            result = SRC_src_process(state, &data);
+            SDL_assert(result == 0);  /* what to do if this fails? Can it fail? */
 
-/* !!! FIXME: We only have this macro salsa because SDL_AudioCVT doesn't store
-   !!! FIXME:  channel info or integer sample rates, so we have to have
-   !!! FIXME:  function entry points for each supported channel count and
-   !!! FIXME:  multiple vs arbitrary. When we rev the ABI, remove this. */
+            /* What to do if this fails...? */
+            SDL_assert(data.input_frames_used == data.input_frames);
+
+            SRC_src_delete(state);
+            cvt->len_cvt = data.output_frames_gen * (sizeof(float) * chans);
+            do_simple = SDL_FALSE;
+        }
+
+        /* failed to create state? Fall back to simple method. */
+    }
+#endif
+
+    if (do_simple) {
+        float state[8];
+        int i;
+
+        for (i = 0; i < chans; i++) {
+            state[i] = src[i];
+        }
+
+        cvt->len_cvt = SDL_ResampleAudioSimple(chans, cvt->rate_incr, state, src, srclen, dst, dstlen);
+    }
+
+    SDL_memcpy(cvt->buf, dst, cvt->len_cvt);
+    if (cvt->filters[++cvt->filter_index]) {
+        cvt->filters[cvt->filter_index](cvt, format);
+    }
+}
+
+/* !!! FIXME: We only have this macro salsa because SDL_AudioCVT doesn't
+   !!! FIXME:  store channel info, so we have to have function entry
+   !!! FIXME:  points for each supported channel count and multiple
+   !!! FIXME:  vs arbitrary. When we rev the ABI, clean this up. */
 #define RESAMPLER_FUNCS(chans) \
     static void SDLCALL \
-    SDL_Upsample_Multiple_c##chans(SDL_AudioCVT *cvt, SDL_AudioFormat format) { \
-        SDL_assert(format == AUDIO_F32SYS); \
-        SDL_Upsample_Multiple(cvt, chans); \
-    } \
-    static void SDLCALL \
-    SDL_Upsample_Arbitrary_c##chans(SDL_AudioCVT *cvt, SDL_AudioFormat format) { \
-        SDL_assert(format == AUDIO_F32SYS); \
-        SDL_Upsample_Arbitrary(cvt, chans); \
-    }\
-    static void SDLCALL \
-    SDL_Downsample_Multiple_c##chans(SDL_AudioCVT *cvt, SDL_AudioFormat format) { \
-        SDL_assert(format == AUDIO_F32SYS); \
-        SDL_Downsample_Multiple(cvt, chans); \
-    } \
-    static void SDLCALL \
-    SDL_Downsample_Arbitrary_c##chans(SDL_AudioCVT *cvt, SDL_AudioFormat format) { \
-        SDL_assert(format == AUDIO_F32SYS); \
-        SDL_Downsample_Arbitrary(cvt, chans); \
+    SDL_ResampleCVT_c##chans(SDL_AudioCVT *cvt, SDL_AudioFormat format) { \
+        SDL_ResampleCVT(cvt, chans, format); \
     }
 RESAMPLER_FUNCS(1)
 RESAMPLER_FUNCS(2)
@@ -371,62 +447,19 @@ RESAMPLER_FUNCS(6)
 RESAMPLER_FUNCS(8)
 #undef RESAMPLER_FUNCS
 
-static int
-SDL_FindFrequencyMultiple(const int src_rate, const int dst_rate)
-{
-    int lo, hi;
-
-    SDL_assert(src_rate != 0);
-    SDL_assert(dst_rate != 0);
-    SDL_assert(src_rate != dst_rate);
-
-    if (src_rate < dst_rate) {
-        lo = src_rate;
-        hi = dst_rate;
-    } else {
-        lo = dst_rate;
-        hi = src_rate;
-    }
-
-    if ((hi % lo) != 0)
-        return 0;               /* not a multiple. */
-
-    return hi / lo;
-}
-
 static SDL_AudioFilter
-ChooseResampler(const int dst_channels, const int src_rate, const int dst_rate)
+ChooseCVTResampler(const int dst_channels)
 {
-    const int upsample = (src_rate < dst_rate) ? 1 : 0;
-    const int multiple = SDL_FindFrequencyMultiple(src_rate, dst_rate);
-    SDL_AudioFilter filter = NULL;
-
-    #define PICK_CHANNEL_FILTER(upordown, resampler) switch (dst_channels) { \
-        case 1: filter = SDL_##upordown##_##resampler##_c1; break; \
-        case 2: filter = SDL_##upordown##_##resampler##_c2; break; \
-        case 4: filter = SDL_##upordown##_##resampler##_c4; break; \
-        case 6: filter = SDL_##upordown##_##resampler##_c6; break; \
-        case 8: filter = SDL_##upordown##_##resampler##_c8; break; \
-        default: break; \
-    }
-
-    if (upsample) {
-        if (multiple) {
-            PICK_CHANNEL_FILTER(Upsample, Multiple);
-        } else {
-            PICK_CHANNEL_FILTER(Upsample, Arbitrary);
-        }
-    } else {
-        if (multiple) {
-            PICK_CHANNEL_FILTER(Downsample, Multiple);
-        } else {
-            PICK_CHANNEL_FILTER(Downsample, Arbitrary);
-        }
+    switch (dst_channels) {
+        case 1: return SDL_ResampleCVT_c1;
+        case 2: return SDL_ResampleCVT_c2;
+        case 4: return SDL_ResampleCVT_c4;
+        case 6: return SDL_ResampleCVT_c6;
+        case 8: return SDL_ResampleCVT_c8;
+        default: break;
     }
 
-    #undef PICK_CHANNEL_FILTER
-
-    return filter;
+    return NULL;
 }
 
 static int
@@ -439,7 +472,7 @@ SDL_BuildAudioResampleCVT(SDL_AudioCVT * cvt, const int dst_channels,
         return 0;  /* no conversion necessary. */
     }
 
-    filter = ChooseResampler(dst_channels, src_rate, dst_rate);
+    filter = ChooseCVTResampler(dst_channels);
     if (filter == NULL) {
         return SDL_SetError("No conversion available for these rates");
     }
@@ -454,6 +487,10 @@ SDL_BuildAudioResampleCVT(SDL_AudioCVT * cvt, const int dst_channels,
         cvt->len_ratio /= ((double) src_rate) / ((double) dst_rate);
     }
 
+    /* the buffer is big enough to hold the destination now, but
+       we need it large enough to hold a separate scratch buffer. */
+    cvt->len_mult *= 2;
+
     return 1;               /* added a converter. */
 }
 
@@ -638,16 +675,17 @@ struct SDL_AudioStream
 static int
 SDL_ResampleAudioStream_SRC(SDL_AudioStream *stream, const float *inbuf, const int inbuflen, float *outbuf, const int outbuflen)
 {
+    const int framelen = sizeof(float) * stream->pre_resample_channels;
     SRC_STATE *state = (SRC_STATE *)stream->resampler_state;
     SRC_DATA data;
     int result;
 
     data.data_in = (float *)inbuf; /* Older versions of libsamplerate had a non-const pointer, but didn't write to it */
-    data.input_frames = inbuflen / ( sizeof(float) * stream->pre_resample_channels );
+    data.input_frames = inbuflen / framelen;
     data.input_frames_used = 0;
 
     data.data_out = outbuf;
-    data.output_frames = outbuflen / (sizeof(float) * stream->pre_resample_channels);
+    data.output_frames = outbuflen / framelen;
 
     data.end_of_input = 0;
     data.src_ratio = stream->rate_incr;
@@ -721,51 +759,20 @@ typedef struct
 static int
 SDL_ResampleAudioStream(SDL_AudioStream *stream, const float *inbuf, const int inbuflen, float *outbuf, const int outbuflen)
 {
-    /* !!! FIXME: this resampler sucks, but not much worse than our usual resampler.  :)  */  /* ... :( */
     SDL_AudioStreamResamplerState *state = (SDL_AudioStreamResamplerState*)stream->resampler_state;
     const int chans = (int)stream->pre_resample_channels;
-    const int framelen = chans * sizeof(float);
-    const int total = (inbuflen / framelen);
-    const int finalpos = total - chans;
-    const double src_incr = 1.0 / stream->rate_incr;
-    double idx = 0.0;
-    float *dst = outbuf;
-    float last_sample[SDL_arraysize(state->resampler_state)];
-    int consumed = 0;
-    int i;
 
-    SDL_assert(chans <= SDL_arraysize(last_sample));
-    SDL_assert((inbuflen % framelen) == 0);
+    SDL_assert(chans <= SDL_arraysize(state->resampler_state));
 
     if (!state->resampler_seeded) {
+        int i;
         for (i = 0; i < chans; i++) {
             state->resampler_state[i] = inbuf[i];
         }
         state->resampler_seeded = SDL_TRUE;
     }
 
-    for (i = 0; i < chans; i++) {
-        last_sample[i] = state->resampler_state[i];
-    }
-
-    while (consumed < total) {
-        const int pos = ((int)idx) * chans;
-        const float *src = &inbuf[(pos >= finalpos) ? finalpos : pos];
-        SDL_assert(dst < (outbuf + (outbuflen / framelen)));
-        for (i = 0; i < chans; i++) {
-            const float val = *(src++);
-            *(dst++) = (val + last_sample[i]) * 0.5f;
-            last_sample[i] = val;
-        }
-        consumed = pos + chans;
-        idx += src_incr;
-    }
-
-    for (i = 0; i < chans; i++) {
-        state->resampler_state[i] = last_sample[i];
-    }
-
-    return (int)((dst - outbuf) * sizeof(float));
+    return SDL_ResampleAudioSimple(chans, stream->rate_incr, state->resampler_state, inbuf, inbuflen, outbuf, outbuflen);
 }
 
 static void

+ 0 - 173
src/audio/SDL_audiotypecvt.c

@@ -216,177 +216,4 @@ SDL_Convert_F32_to_S32(SDL_AudioCVT *cvt, SDL_AudioFormat format)
     }
 }
 
-void
-SDL_Upsample_Arbitrary(SDL_AudioCVT *cvt, const int channels)
-{
-    const int srcsize = cvt->len_cvt - (64 * channels);
-    const int dstsize = (int) ((((double)(cvt->len_cvt/(channels*4))) * cvt->rate_incr)) * (channels*4);
-    register int eps = 0;
-    float *dst = ((float *) (cvt->buf + dstsize)) - channels;
-    const float *src = ((float *) (cvt->buf + cvt->len_cvt)) - channels;
-    const float *target = ((const float *) cvt->buf);
-    const size_t cpy = sizeof (float) * channels;
-    float sample[8];
-    float last_sample[8];
-    int i;
-
-#if DEBUG_CONVERT
-    fprintf(stderr, "Upsample arbitrary (x%f), %d channels.\n", cvt->rate_incr, channels);
-#endif
-
-    SDL_assert(channels <= 8);
-
-    for (i = 0; i < channels; i++) {
-        sample[i] = (float) ((((double) src[i]) + ((double) src[i - channels])) * 0.5);
-    }
-    SDL_memcpy(last_sample, src, cpy);
-
-    while (dst > target) {
-        SDL_memcpy(dst, sample, cpy);
-        dst -= channels;
-        eps += srcsize;
-        if ((eps << 1) >= dstsize) {
-            if (src > target) {
-                src -= channels;
-                for (i = 0; i < channels; i++) {
-                    sample[i] = (float) ((((double) src[i]) + ((double) last_sample[i])) * 0.5);
-                }
-            } else {
-
-            }
-            SDL_memcpy(last_sample, src, cpy);
-            eps -= dstsize;
-        }
-    }
-
-    cvt->len_cvt = dstsize;
-    if (cvt->filters[++cvt->filter_index]) {
-        cvt->filters[cvt->filter_index](cvt, AUDIO_F32SYS);
-    }
-}
-
-void
-SDL_Downsample_Arbitrary(SDL_AudioCVT *cvt, const int channels)
-{
-    const int srcsize = cvt->len_cvt - (64 * channels);
-    const int dstsize = (int) (((double)(cvt->len_cvt/(channels*4))) * cvt->rate_incr) * (channels*4);
-    register int eps = 0;
-    float *dst = (float *) cvt->buf;
-    const float *src = (float *) cvt->buf;
-    const float *target = (const float *) (cvt->buf + dstsize);
-    const size_t cpy = sizeof (float) * channels;
-    float last_sample[8];
-    float sample[8];
-    int i;
-
-#if DEBUG_CONVERT
-    fprintf(stderr, "Downsample arbitrary (x%f), %d channels.\n", cvt->rate_incr, channels);
-#endif
-
-    SDL_assert(channels <= 8);
-
-    SDL_memcpy(sample, src, cpy);
-    SDL_memcpy(last_sample, src, cpy);
-
-    while (dst < target) {
-        src += channels;
-        eps += dstsize;
-        if ((eps << 1) >= srcsize) {
-            SDL_memcpy(dst, sample, cpy);
-            dst += channels;
-            for (i = 0; i < channels; i++) {
-                sample[i] = (float) ((((double) src[i]) + ((double) last_sample[i])) * 0.5);
-            }
-            SDL_memcpy(last_sample, src, cpy);
-            eps -= srcsize;
-        }
-    }
-
-    cvt->len_cvt = dstsize;
-    if (cvt->filters[++cvt->filter_index]) {
-        cvt->filters[cvt->filter_index](cvt, AUDIO_F32SYS);
-    }
-}
-
-void
-SDL_Upsample_Multiple(SDL_AudioCVT *cvt, const int channels)
-{
-    const int multiple = (int) cvt->rate_incr;
-    const int dstsize = cvt->len_cvt * multiple;
-    float *buf = (float *) cvt->buf;
-    float *dst = ((float *) (cvt->buf + dstsize)) - channels;
-    const float *src = ((float *) (cvt->buf + cvt->len_cvt)) - channels;
-    const float *target = buf + channels;
-    const size_t cpy = sizeof (float) * channels;
-    float last_sample[8];
-    int i;
-
-#if DEBUG_CONVERT
-    fprintf(stderr, "Upsample (x%d), %d channels.\n", multiple, channels);
-#endif
-
-    SDL_assert(channels <= 8);
-
-    SDL_memcpy(last_sample, src, cpy);
-
-    while (dst > target) {
-        SDL_assert(src >= buf);
-
-        for (i = 0; i < channels; i++) {
-            dst[i] = (float) ((((double)src[i]) + ((double)last_sample[i])) * 0.5);
-        }
-        dst -= channels;
-
-        for (i = 1; i < multiple; i++) {
-            SDL_memcpy(dst, dst + channels, cpy);
-            dst -= channels;
-        }
-
-        src -= channels;
-        if (src > buf) {
-            SDL_memcpy(last_sample, src - channels, cpy);
-        }
-    }
-
-    cvt->len_cvt = dstsize;
-    if (cvt->filters[++cvt->filter_index]) {
-        cvt->filters[cvt->filter_index](cvt, AUDIO_F32SYS);
-    }
-}
-
-void
-SDL_Downsample_Multiple(SDL_AudioCVT *cvt, const int channels)
-{
-    const int multiple = (int) (1.0 / cvt->rate_incr);
-    const int dstsize = cvt->len_cvt / multiple;
-    float *dst = (float *) cvt->buf;
-    const float *src = (float *) cvt->buf;
-    const float *target = (const float *) (cvt->buf + dstsize);
-    const size_t cpy = sizeof (float) * channels;
-    float last_sample[8];
-    int i;
-
-#if DEBUG_CONVERT
-    fprintf(stderr, "Downsample (x%d), %d channels.\n", multiple, channels);
-#endif
-
-    SDL_assert(channels <= 8);
-    SDL_memcpy(last_sample, src, cpy);
-
-    while (dst < target) {
-        for (i = 0; i < channels; i++) {
-            dst[i] = (float) ((((double)src[i]) + ((double)last_sample[i])) * 0.5);
-        }
-        dst += channels;
-
-        SDL_memcpy(last_sample, src, cpy);
-        src += (channels * multiple);
-    }
-
-    cvt->len_cvt = dstsize;
-    if (cvt->filters[++cvt->filter_index]) {
-        cvt->filters[cvt->filter_index](cvt, AUDIO_F32SYS);
-    }
-}
-
 /* vi: set ts=4 sw=4 expandtab: */