src/audio/SDL_audiocvt.c
changeset 10799 234f71894a52
parent 10793 7e657de3758d
child 10804 1502bb751ca4
     1.1 --- a/src/audio/SDL_audiocvt.c	Mon Jan 09 05:59:30 2017 -0500
     1.2 +++ b/src/audio/SDL_audiocvt.c	Mon Jan 09 06:00:58 2017 -0500
     1.3 @@ -191,6 +191,38 @@
     1.4      }
     1.5  }
     1.6  
     1.7 +static int
     1.8 +SDL_ResampleAudioSimple(const int chans, const double rate_incr,
     1.9 +                        float *last_sample, const float *inbuf,
    1.10 +                        const int inbuflen, float *outbuf, const int outbuflen)
    1.11 +{
    1.12 +    const int framelen = chans * sizeof(float);
    1.13 +    const int total = (inbuflen / framelen);
    1.14 +    const int finalpos = total - chans;
    1.15 +    const double src_incr = 1.0 / rate_incr;
    1.16 +    double idx = 0.0;
    1.17 +    float *dst = outbuf;
    1.18 +    int consumed = 0;
    1.19 +    int i;
    1.20 +
    1.21 +    SDL_assert((inbuflen % framelen) == 0);
    1.22 +
    1.23 +    while (consumed < total) {
    1.24 +        const int pos = ((int)idx) * chans;
    1.25 +        const float *src = &inbuf[(pos >= finalpos) ? finalpos : pos];
    1.26 +        SDL_assert(dst < (outbuf + (outbuflen / framelen)));
    1.27 +        for (i = 0; i < chans; i++) {
    1.28 +            const float val = *(src++);
    1.29 +            *(dst++) = (val + last_sample[i]) * 0.5f;
    1.30 +            last_sample[i] = val;
    1.31 +        }
    1.32 +        consumed = pos + chans;
    1.33 +        idx += src_incr;
    1.34 +    }
    1.35 +
    1.36 +    return (int)((dst - outbuf) * sizeof(float));
    1.37 +}
    1.38 +
    1.39  
    1.40  int
    1.41  SDL_ConvertAudio(SDL_AudioCVT * cvt)
    1.42 @@ -338,31 +370,75 @@
    1.43      return retval;
    1.44  }
    1.45  
    1.46 +static void
    1.47 +SDL_ResampleCVT(SDL_AudioCVT *cvt, const int chans, const SDL_AudioFormat format)
    1.48 +{
    1.49 +    const float *src = (const float *) cvt->buf;
    1.50 +    const int srclen = cvt->len_cvt;
    1.51 +    float *dst = (float *) (cvt->buf + srclen);
    1.52 +    const int dstlen = (cvt->len * cvt->len_mult) - srclen;
    1.53 +    SDL_bool do_simple = SDL_TRUE;
    1.54  
    1.55 -/* !!! FIXME: We only have this macro salsa because SDL_AudioCVT doesn't store
    1.56 -   !!! FIXME:  channel info or integer sample rates, so we have to have
    1.57 -   !!! FIXME:  function entry points for each supported channel count and
    1.58 -   !!! FIXME:  multiple vs arbitrary. When we rev the ABI, remove this. */
    1.59 +    SDL_assert(format == AUDIO_F32SYS);
    1.60 +
    1.61 +#ifdef HAVE_LIBSAMPLERATE_H
    1.62 +    if (SRC_available) {
    1.63 +        int result = 0;
    1.64 +        SRC_STATE *state = SRC_src_new(SRC_SINC_FASTEST, chans, &result);
    1.65 +        if (state) {
    1.66 +            const int framelen = sizeof(float) * chans;
    1.67 +            SRC_DATA data;
    1.68 +
    1.69 +            data.data_in = (float *)src; /* Older versions of libsamplerate had a non-const pointer, but didn't write to it */
    1.70 +            data.input_frames = srclen / framelen;
    1.71 +            data.input_frames_used = 0;
    1.72 +
    1.73 +            data.data_out = dst;
    1.74 +            data.output_frames = dstlen / framelen;
    1.75 +
    1.76 +            data.end_of_input = 0;
    1.77 +            data.src_ratio = cvt->rate_incr;
    1.78 +
    1.79 +            result = SRC_src_process(state, &data);
    1.80 +            SDL_assert(result == 0);  /* what to do if this fails? Can it fail? */
    1.81 +
    1.82 +            /* What to do if this fails...? */
    1.83 +            SDL_assert(data.input_frames_used == data.input_frames);
    1.84 +
    1.85 +            SRC_src_delete(state);
    1.86 +            cvt->len_cvt = data.output_frames_gen * (sizeof(float) * chans);
    1.87 +            do_simple = SDL_FALSE;
    1.88 +        }
    1.89 +
    1.90 +        /* failed to create state? Fall back to simple method. */
    1.91 +    }
    1.92 +#endif
    1.93 +
    1.94 +    if (do_simple) {
    1.95 +        float state[8];
    1.96 +        int i;
    1.97 +
    1.98 +        for (i = 0; i < chans; i++) {
    1.99 +            state[i] = src[i];
   1.100 +        }
   1.101 +
   1.102 +        cvt->len_cvt = SDL_ResampleAudioSimple(chans, cvt->rate_incr, state, src, srclen, dst, dstlen);
   1.103 +    }
   1.104 +
   1.105 +    SDL_memcpy(cvt->buf, dst, cvt->len_cvt);
   1.106 +    if (cvt->filters[++cvt->filter_index]) {
   1.107 +        cvt->filters[cvt->filter_index](cvt, format);
   1.108 +    }
   1.109 +}
   1.110 +
   1.111 +/* !!! FIXME: We only have this macro salsa because SDL_AudioCVT doesn't
   1.112 +   !!! FIXME:  store channel info, so we have to have function entry
   1.113 +   !!! FIXME:  points for each supported channel count and multiple
   1.114 +   !!! FIXME:  vs arbitrary. When we rev the ABI, clean this up. */
   1.115  #define RESAMPLER_FUNCS(chans) \
   1.116      static void SDLCALL \
   1.117 -    SDL_Upsample_Multiple_c##chans(SDL_AudioCVT *cvt, SDL_AudioFormat format) { \
   1.118 -        SDL_assert(format == AUDIO_F32SYS); \
   1.119 -        SDL_Upsample_Multiple(cvt, chans); \
   1.120 -    } \
   1.121 -    static void SDLCALL \
   1.122 -    SDL_Upsample_Arbitrary_c##chans(SDL_AudioCVT *cvt, SDL_AudioFormat format) { \
   1.123 -        SDL_assert(format == AUDIO_F32SYS); \
   1.124 -        SDL_Upsample_Arbitrary(cvt, chans); \
   1.125 -    }\
   1.126 -    static void SDLCALL \
   1.127 -    SDL_Downsample_Multiple_c##chans(SDL_AudioCVT *cvt, SDL_AudioFormat format) { \
   1.128 -        SDL_assert(format == AUDIO_F32SYS); \
   1.129 -        SDL_Downsample_Multiple(cvt, chans); \
   1.130 -    } \
   1.131 -    static void SDLCALL \
   1.132 -    SDL_Downsample_Arbitrary_c##chans(SDL_AudioCVT *cvt, SDL_AudioFormat format) { \
   1.133 -        SDL_assert(format == AUDIO_F32SYS); \
   1.134 -        SDL_Downsample_Arbitrary(cvt, chans); \
   1.135 +    SDL_ResampleCVT_c##chans(SDL_AudioCVT *cvt, SDL_AudioFormat format) { \
   1.136 +        SDL_ResampleCVT(cvt, chans, format); \
   1.137      }
   1.138  RESAMPLER_FUNCS(1)
   1.139  RESAMPLER_FUNCS(2)
   1.140 @@ -371,62 +447,19 @@
   1.141  RESAMPLER_FUNCS(8)
   1.142  #undef RESAMPLER_FUNCS
   1.143  
   1.144 -static int
   1.145 -SDL_FindFrequencyMultiple(const int src_rate, const int dst_rate)
   1.146 +static SDL_AudioFilter
   1.147 +ChooseCVTResampler(const int dst_channels)
   1.148  {
   1.149 -    int lo, hi;
   1.150 -
   1.151 -    SDL_assert(src_rate != 0);
   1.152 -    SDL_assert(dst_rate != 0);
   1.153 -    SDL_assert(src_rate != dst_rate);
   1.154 -
   1.155 -    if (src_rate < dst_rate) {
   1.156 -        lo = src_rate;
   1.157 -        hi = dst_rate;
   1.158 -    } else {
   1.159 -        lo = dst_rate;
   1.160 -        hi = src_rate;
   1.161 +    switch (dst_channels) {
   1.162 +        case 1: return SDL_ResampleCVT_c1;
   1.163 +        case 2: return SDL_ResampleCVT_c2;
   1.164 +        case 4: return SDL_ResampleCVT_c4;
   1.165 +        case 6: return SDL_ResampleCVT_c6;
   1.166 +        case 8: return SDL_ResampleCVT_c8;
   1.167 +        default: break;
   1.168      }
   1.169  
   1.170 -    if ((hi % lo) != 0)
   1.171 -        return 0;               /* not a multiple. */
   1.172 -
   1.173 -    return hi / lo;
   1.174 -}
   1.175 -
   1.176 -static SDL_AudioFilter
   1.177 -ChooseResampler(const int dst_channels, const int src_rate, const int dst_rate)
   1.178 -{
   1.179 -    const int upsample = (src_rate < dst_rate) ? 1 : 0;
   1.180 -    const int multiple = SDL_FindFrequencyMultiple(src_rate, dst_rate);
   1.181 -    SDL_AudioFilter filter = NULL;
   1.182 -
   1.183 -    #define PICK_CHANNEL_FILTER(upordown, resampler) switch (dst_channels) { \
   1.184 -        case 1: filter = SDL_##upordown##_##resampler##_c1; break; \
   1.185 -        case 2: filter = SDL_##upordown##_##resampler##_c2; break; \
   1.186 -        case 4: filter = SDL_##upordown##_##resampler##_c4; break; \
   1.187 -        case 6: filter = SDL_##upordown##_##resampler##_c6; break; \
   1.188 -        case 8: filter = SDL_##upordown##_##resampler##_c8; break; \
   1.189 -        default: break; \
   1.190 -    }
   1.191 -
   1.192 -    if (upsample) {
   1.193 -        if (multiple) {
   1.194 -            PICK_CHANNEL_FILTER(Upsample, Multiple);
   1.195 -        } else {
   1.196 -            PICK_CHANNEL_FILTER(Upsample, Arbitrary);
   1.197 -        }
   1.198 -    } else {
   1.199 -        if (multiple) {
   1.200 -            PICK_CHANNEL_FILTER(Downsample, Multiple);
   1.201 -        } else {
   1.202 -            PICK_CHANNEL_FILTER(Downsample, Arbitrary);
   1.203 -        }
   1.204 -    }
   1.205 -
   1.206 -    #undef PICK_CHANNEL_FILTER
   1.207 -
   1.208 -    return filter;
   1.209 +    return NULL;
   1.210  }
   1.211  
   1.212  static int
   1.213 @@ -439,7 +472,7 @@
   1.214          return 0;  /* no conversion necessary. */
   1.215      }
   1.216  
   1.217 -    filter = ChooseResampler(dst_channels, src_rate, dst_rate);
   1.218 +    filter = ChooseCVTResampler(dst_channels);
   1.219      if (filter == NULL) {
   1.220          return SDL_SetError("No conversion available for these rates");
   1.221      }
   1.222 @@ -454,6 +487,10 @@
   1.223          cvt->len_ratio /= ((double) src_rate) / ((double) dst_rate);
   1.224      }
   1.225  
   1.226 +    /* the buffer is big enough to hold the destination now, but
   1.227 +       we need it large enough to hold a separate scratch buffer. */
   1.228 +    cvt->len_mult *= 2;
   1.229 +
   1.230      return 1;               /* added a converter. */
   1.231  }
   1.232  
   1.233 @@ -638,16 +675,17 @@
   1.234  static int
   1.235  SDL_ResampleAudioStream_SRC(SDL_AudioStream *stream, const float *inbuf, const int inbuflen, float *outbuf, const int outbuflen)
   1.236  {
   1.237 +    const int framelen = sizeof(float) * stream->pre_resample_channels;
   1.238      SRC_STATE *state = (SRC_STATE *)stream->resampler_state;
   1.239      SRC_DATA data;
   1.240      int result;
   1.241  
   1.242      data.data_in = (float *)inbuf; /* Older versions of libsamplerate had a non-const pointer, but didn't write to it */
   1.243 -    data.input_frames = inbuflen / ( sizeof(float) * stream->pre_resample_channels );
   1.244 +    data.input_frames = inbuflen / framelen;
   1.245      data.input_frames_used = 0;
   1.246  
   1.247      data.data_out = outbuf;
   1.248 -    data.output_frames = outbuflen / (sizeof(float) * stream->pre_resample_channels);
   1.249 +    data.output_frames = outbuflen / framelen;
   1.250  
   1.251      data.end_of_input = 0;
   1.252      data.src_ratio = stream->rate_incr;
   1.253 @@ -721,51 +759,20 @@
   1.254  static int
   1.255  SDL_ResampleAudioStream(SDL_AudioStream *stream, const float *inbuf, const int inbuflen, float *outbuf, const int outbuflen)
   1.256  {
   1.257 -    /* !!! FIXME: this resampler sucks, but not much worse than our usual resampler.  :)  */  /* ... :( */
   1.258      SDL_AudioStreamResamplerState *state = (SDL_AudioStreamResamplerState*)stream->resampler_state;
   1.259      const int chans = (int)stream->pre_resample_channels;
   1.260 -    const int framelen = chans * sizeof(float);
   1.261 -    const int total = (inbuflen / framelen);
   1.262 -    const int finalpos = total - chans;
   1.263 -    const double src_incr = 1.0 / stream->rate_incr;
   1.264 -    double idx = 0.0;
   1.265 -    float *dst = outbuf;
   1.266 -    float last_sample[SDL_arraysize(state->resampler_state)];
   1.267 -    int consumed = 0;
   1.268 -    int i;
   1.269  
   1.270 -    SDL_assert(chans <= SDL_arraysize(last_sample));
   1.271 -    SDL_assert((inbuflen % framelen) == 0);
   1.272 +    SDL_assert(chans <= SDL_arraysize(state->resampler_state));
   1.273  
   1.274      if (!state->resampler_seeded) {
   1.275 +        int i;
   1.276          for (i = 0; i < chans; i++) {
   1.277              state->resampler_state[i] = inbuf[i];
   1.278          }
   1.279          state->resampler_seeded = SDL_TRUE;
   1.280      }
   1.281  
   1.282 -    for (i = 0; i < chans; i++) {
   1.283 -        last_sample[i] = state->resampler_state[i];
   1.284 -    }
   1.285 -
   1.286 -    while (consumed < total) {
   1.287 -        const int pos = ((int)idx) * chans;
   1.288 -        const float *src = &inbuf[(pos >= finalpos) ? finalpos : pos];
   1.289 -        SDL_assert(dst < (outbuf + (outbuflen / framelen)));
   1.290 -        for (i = 0; i < chans; i++) {
   1.291 -            const float val = *(src++);
   1.292 -            *(dst++) = (val + last_sample[i]) * 0.5f;
   1.293 -            last_sample[i] = val;
   1.294 -        }
   1.295 -        consumed = pos + chans;
   1.296 -        idx += src_incr;
   1.297 -    }
   1.298 -
   1.299 -    for (i = 0; i < chans; i++) {
   1.300 -        state->resampler_state[i] = last_sample[i];
   1.301 -    }
   1.302 -
   1.303 -    return (int)((dst - outbuf) * sizeof(float));
   1.304 +    return SDL_ResampleAudioSimple(chans, stream->rate_incr, state->resampler_state, inbuf, inbuflen, outbuf, outbuflen);
   1.305  }
   1.306  
   1.307  static void