mirror of https://github.com/encounter/SDL.git
audio: More effort to improve and simplify audio resamplers.
This commit is contained in:
parent
52130bde40
commit
f12ab8f2b3
|
@ -50,9 +50,8 @@ 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_U16(SDL_AudioCVT *cvt, SDL_AudioFormat format);
|
||||||
void SDLCALL SDL_Convert_F32_to_S32(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_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_Arbitrary(SDL_AudioCVT *cvt, const int channels);
|
||||||
void SDL_Upsample_x2(SDL_AudioCVT *cvt, const int channels);
|
void SDL_Downsample_Multiple(SDL_AudioCVT *cvt, const int channels);
|
||||||
void SDL_Upsample_x4(SDL_AudioCVT *cvt, const int channels);
|
|
||||||
void SDL_Downsample_Multiple(SDL_AudioCVT *cvt, const int multiple, const int channels);
|
|
||||||
|
|
||||||
/* vi: set ts=4 sw=4 expandtab: */
|
/* vi: set ts=4 sw=4 expandtab: */
|
||||||
|
|
|
@ -331,14 +331,43 @@ SDL_BuildAudioTypeCVTFromFloat(SDL_AudioCVT *cvt, const SDL_AudioFormat dst_fmt)
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* !!! 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. */
|
||||||
|
#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); \
|
||||||
|
}
|
||||||
|
RESAMPLER_FUNCS(1)
|
||||||
|
RESAMPLER_FUNCS(2)
|
||||||
|
RESAMPLER_FUNCS(4)
|
||||||
|
RESAMPLER_FUNCS(6)
|
||||||
|
RESAMPLER_FUNCS(8)
|
||||||
|
#undef RESAMPLER_FUNCS
|
||||||
|
|
||||||
static int
|
static int
|
||||||
SDL_FindFrequencyMultiple(const int src_rate, const int dst_rate)
|
SDL_FindFrequencyMultiple(const int src_rate, const int dst_rate)
|
||||||
{
|
{
|
||||||
int retval = 0;
|
|
||||||
|
|
||||||
/* If we only built with the arbitrary resamplers, ignore multiples. */
|
|
||||||
int lo, hi;
|
int lo, hi;
|
||||||
int div;
|
|
||||||
|
|
||||||
SDL_assert(src_rate != 0);
|
SDL_assert(src_rate != 0);
|
||||||
SDL_assert(dst_rate != 0);
|
SDL_assert(dst_rate != 0);
|
||||||
|
@ -352,110 +381,73 @@ SDL_FindFrequencyMultiple(const int src_rate, const int dst_rate)
|
||||||
hi = src_rate;
|
hi = src_rate;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* zero means "not a supported multiple" ... we only do 2x and 4x. */
|
|
||||||
if ((hi % lo) != 0)
|
if ((hi % lo) != 0)
|
||||||
return 0; /* not a multiple. */
|
return 0; /* not a multiple. */
|
||||||
|
|
||||||
div = hi / lo;
|
return hi / lo;
|
||||||
retval = ((div == 2) || (div == 4)) ? div : 0;
|
|
||||||
|
|
||||||
return retval;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define RESAMPLER_FUNCS(chans) \
|
static SDL_AudioFilter
|
||||||
static void SDLCALL \
|
ChooseResampler(const int dst_channels, const int src_rate, const int dst_rate)
|
||||||
SDL_Upsample_Arbitrary_c##chans(SDL_AudioCVT *cvt, SDL_AudioFormat format) { \
|
{
|
||||||
SDL_assert(format == AUDIO_F32SYS); \
|
const int upsample = (src_rate < dst_rate) ? 1 : 0;
|
||||||
SDL_Upsample_Arbitrary(cvt, chans); \
|
const int multiple = SDL_FindFrequencyMultiple(src_rate, dst_rate);
|
||||||
}\
|
SDL_AudioFilter filter = NULL;
|
||||||
static void SDLCALL \
|
|
||||||
SDL_Downsample_Arbitrary_c##chans(SDL_AudioCVT *cvt, SDL_AudioFormat format) { \
|
#define PICK_CHANNEL_FILTER(upordown, resampler) switch (dst_channels) { \
|
||||||
SDL_assert(format == AUDIO_F32SYS); \
|
case 1: filter = SDL_##upordown##_##resampler##_c1; break; \
|
||||||
SDL_Downsample_Arbitrary(cvt, chans); \
|
case 2: filter = SDL_##upordown##_##resampler##_c2; break; \
|
||||||
} \
|
case 4: filter = SDL_##upordown##_##resampler##_c4; break; \
|
||||||
static void SDLCALL \
|
case 6: filter = SDL_##upordown##_##resampler##_c6; break; \
|
||||||
SDL_Upsample_x2_c##chans(SDL_AudioCVT *cvt, SDL_AudioFormat format) { \
|
case 8: filter = SDL_##upordown##_##resampler##_c8; break; \
|
||||||
SDL_assert(format == AUDIO_F32SYS); \
|
default: break; \
|
||||||
SDL_Upsample_x2(cvt, chans); \
|
|
||||||
} \
|
|
||||||
static void SDLCALL \
|
|
||||||
SDL_Downsample_x2_c##chans(SDL_AudioCVT *cvt, SDL_AudioFormat format) { \
|
|
||||||
SDL_assert(format == AUDIO_F32SYS); \
|
|
||||||
SDL_Downsample_Multiple(cvt, 2, chans); \
|
|
||||||
} \
|
|
||||||
static void SDLCALL \
|
|
||||||
SDL_Upsample_x4_c##chans(SDL_AudioCVT *cvt, SDL_AudioFormat format) { \
|
|
||||||
SDL_assert(format == AUDIO_F32SYS); \
|
|
||||||
SDL_Upsample_x4(cvt, chans); \
|
|
||||||
} \
|
|
||||||
static void SDLCALL \
|
|
||||||
SDL_Downsample_x4_c##chans(SDL_AudioCVT *cvt, SDL_AudioFormat format) { \
|
|
||||||
SDL_assert(format == AUDIO_F32SYS); \
|
|
||||||
SDL_Downsample_Multiple(cvt, 4, chans); \
|
|
||||||
}
|
}
|
||||||
RESAMPLER_FUNCS(1)
|
|
||||||
RESAMPLER_FUNCS(2)
|
if (upsample) {
|
||||||
RESAMPLER_FUNCS(4)
|
if (multiple) {
|
||||||
RESAMPLER_FUNCS(6)
|
PICK_CHANNEL_FILTER(Upsample, Multiple);
|
||||||
RESAMPLER_FUNCS(8)
|
} else {
|
||||||
#undef RESAMPLER_FUNCS
|
PICK_CHANNEL_FILTER(Upsample, Arbitrary);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (multiple) {
|
||||||
|
PICK_CHANNEL_FILTER(Downsample, Multiple);
|
||||||
|
} else {
|
||||||
|
PICK_CHANNEL_FILTER(Downsample, Arbitrary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef PICK_CHANNEL_FILTER
|
||||||
|
|
||||||
|
return filter;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
SDL_BuildAudioResampleCVT(SDL_AudioCVT * cvt, int dst_channels,
|
SDL_BuildAudioResampleCVT(SDL_AudioCVT * cvt, const int dst_channels,
|
||||||
int src_rate, int dst_rate)
|
const int src_rate, const int dst_rate)
|
||||||
{
|
{
|
||||||
if (src_rate != dst_rate) {
|
SDL_AudioFilter filter;
|
||||||
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) { \
|
if (src_rate == dst_rate) {
|
||||||
case 1: filter = SDL_##upordown##_##resampler##_c1; break; \
|
return 0; /* no conversion necessary. */
|
||||||
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 == 0) {
|
|
||||||
PICK_CHANNEL_FILTER(Upsample, Arbitrary);
|
|
||||||
} else if (multiple == 2) {
|
|
||||||
PICK_CHANNEL_FILTER(Upsample, x2);
|
|
||||||
} else if (multiple == 4) {
|
|
||||||
PICK_CHANNEL_FILTER(Upsample, x4);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (multiple == 0) {
|
|
||||||
PICK_CHANNEL_FILTER(Downsample, Arbitrary);
|
|
||||||
} else if (multiple == 2) {
|
|
||||||
PICK_CHANNEL_FILTER(Downsample, x2);
|
|
||||||
} else if (multiple == 4) {
|
|
||||||
PICK_CHANNEL_FILTER(Downsample, x4);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef PICK_CHANNEL_FILTER
|
|
||||||
|
|
||||||
if (filter == NULL) {
|
|
||||||
return SDL_SetError("No conversion available for these rates");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Update (cvt) with filter details... */
|
|
||||||
cvt->filters[cvt->filter_index++] = filter;
|
|
||||||
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; /* added a converter. */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0; /* no conversion necessary. */
|
filter = ChooseResampler(dst_channels, src_rate, dst_rate);
|
||||||
|
if (filter == NULL) {
|
||||||
|
return SDL_SetError("No conversion available for these rates");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Update (cvt) with filter details... */
|
||||||
|
cvt->filters[cvt->filter_index++] = filter;
|
||||||
|
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; /* added a converter. */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -514,7 +506,7 @@ SDL_BuildAudioCVT(SDL_AudioCVT * cvt,
|
||||||
|
|
||||||
The expectation is we can process data faster in float32
|
The expectation is we can process data faster in float32
|
||||||
(possibly with SIMD), and making several passes over the same
|
(possibly with SIMD), and making several passes over the same
|
||||||
buffer in is likely to be CPU cache-friendly, avoiding the
|
buffer is likely to be CPU cache-friendly, avoiding the
|
||||||
biggest performance hit in modern times. Previously we had
|
biggest performance hit in modern times. Previously we had
|
||||||
(script-generated) custom converters for every data type and
|
(script-generated) custom converters for every data type and
|
||||||
it was a bloat on SDL compile times and final library size. */
|
it was a bloat on SDL compile times and final library size. */
|
||||||
|
@ -585,11 +577,11 @@ SDL_BuildAudioCVT(SDL_AudioCVT * cvt,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Do rate conversion, if necessary. Updates (cvt). */
|
/* Do rate conversion, if necessary. Updates (cvt). */
|
||||||
if (SDL_BuildAudioResampleCVT(cvt, dst_channels, src_rate, dst_rate) ==
|
if (SDL_BuildAudioResampleCVT(cvt, dst_channels, src_rate, dst_rate) == -1) {
|
||||||
-1) {
|
|
||||||
return -1; /* shouldn't happen, but just in case... */
|
return -1; /* shouldn't happen, but just in case... */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Move to final data type. */
|
||||||
if (SDL_BuildAudioTypeCVTFromFloat(cvt, dst_fmt) == -1) {
|
if (SDL_BuildAudioTypeCVTFromFloat(cvt, dst_fmt) == -1) {
|
||||||
return -1; /* shouldn't happen, but just in case... */
|
return -1; /* shouldn't happen, but just in case... */
|
||||||
}
|
}
|
||||||
|
|
|
@ -220,14 +220,14 @@ void
|
||||||
SDL_Upsample_Arbitrary(SDL_AudioCVT *cvt, const int channels)
|
SDL_Upsample_Arbitrary(SDL_AudioCVT *cvt, const int channels)
|
||||||
{
|
{
|
||||||
const int srcsize = cvt->len_cvt - (64 * channels);
|
const int srcsize = cvt->len_cvt - (64 * channels);
|
||||||
const int dstsize = (int) (((double)(cvt->len_cvt/(channels*4))) * cvt->rate_incr) * (channels*4);
|
const int dstsize = (int) ((((double)(cvt->len_cvt/(channels*4))) * cvt->rate_incr)) * (channels*4);
|
||||||
register int eps = 0;
|
register int eps = 0;
|
||||||
float *dst = ((float *) (cvt->buf + dstsize)) - channels;
|
float *dst = ((float *) (cvt->buf + dstsize)) - channels;
|
||||||
const float *src = ((float *) (cvt->buf + cvt->len_cvt)) - channels;
|
const float *src = ((float *) (cvt->buf + cvt->len_cvt)) - channels;
|
||||||
const float *target = ((const float *) cvt->buf);
|
const float *target = ((const float *) cvt->buf);
|
||||||
const size_t cpy = sizeof (float) * channels;
|
const size_t cpy = sizeof (float) * channels;
|
||||||
float last_sample[8];
|
|
||||||
float sample[8];
|
float sample[8];
|
||||||
|
float last_sample[8];
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
#if DEBUG_CONVERT
|
#if DEBUG_CONVERT
|
||||||
|
@ -236,7 +236,9 @@ SDL_Upsample_Arbitrary(SDL_AudioCVT *cvt, const int channels)
|
||||||
|
|
||||||
SDL_assert(channels <= 8);
|
SDL_assert(channels <= 8);
|
||||||
|
|
||||||
SDL_memcpy(sample, src, cpy);
|
for (i = 0; i < channels; i++) {
|
||||||
|
sample[i] = (float) ((((double) src[i]) + ((double) src[i - channels])) * 0.5);
|
||||||
|
}
|
||||||
SDL_memcpy(last_sample, src, cpy);
|
SDL_memcpy(last_sample, src, cpy);
|
||||||
|
|
||||||
while (dst > target) {
|
while (dst > target) {
|
||||||
|
@ -244,11 +246,15 @@ SDL_Upsample_Arbitrary(SDL_AudioCVT *cvt, const int channels)
|
||||||
dst -= channels;
|
dst -= channels;
|
||||||
eps += srcsize;
|
eps += srcsize;
|
||||||
if ((eps << 1) >= dstsize) {
|
if ((eps << 1) >= dstsize) {
|
||||||
src -= channels;
|
if (src > target) {
|
||||||
for (i = 0; i < channels; i++) {
|
src -= channels;
|
||||||
sample[i] = (float) ((((double) src[i]) + ((double) last_sample[i])) * 0.5);
|
for (i = 0; i < channels; i++) {
|
||||||
|
sample[i] = (float) ((((double) src[i]) + ((double) last_sample[i])) * 0.5);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
|
||||||
}
|
}
|
||||||
SDL_memcpy(last_sample, sample, cpy);
|
SDL_memcpy(last_sample, src, cpy);
|
||||||
eps -= dstsize;
|
eps -= dstsize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -291,7 +297,7 @@ SDL_Downsample_Arbitrary(SDL_AudioCVT *cvt, const int channels)
|
||||||
for (i = 0; i < channels; i++) {
|
for (i = 0; i < channels; i++) {
|
||||||
sample[i] = (float) ((((double) src[i]) + ((double) last_sample[i])) * 0.5);
|
sample[i] = (float) ((((double) src[i]) + ((double) last_sample[i])) * 0.5);
|
||||||
}
|
}
|
||||||
SDL_memcpy(last_sample, sample, cpy);
|
SDL_memcpy(last_sample, src, cpy);
|
||||||
eps -= srcsize;
|
eps -= srcsize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -303,32 +309,43 @@ SDL_Downsample_Arbitrary(SDL_AudioCVT *cvt, const int channels)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
SDL_Upsample_x2(SDL_AudioCVT *cvt, const int channels)
|
SDL_Upsample_Multiple(SDL_AudioCVT *cvt, const int channels)
|
||||||
{
|
{
|
||||||
const int dstsize = cvt->len_cvt * 2;
|
const int multiple = (int) cvt->rate_incr;
|
||||||
float *dst = ((float *) (cvt->buf + dstsize)) - (channels * 2);
|
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 *src = ((float *) (cvt->buf + cvt->len_cvt)) - channels;
|
||||||
const float *target = ((const float *) cvt->buf);
|
const float *target = buf + channels;
|
||||||
const size_t cpy = sizeof (float) * channels;
|
const size_t cpy = sizeof (float) * channels;
|
||||||
float last_sample[8];
|
float last_sample[8];
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
#if DEBUG_CONVERT
|
#if DEBUG_CONVERT
|
||||||
fprintf(stderr, "Upsample (x2), %d channels.\n", channels);
|
fprintf(stderr, "Upsample (x%d), %d channels.\n", multiple, channels);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
SDL_assert(channels <= 8);
|
SDL_assert(channels <= 8);
|
||||||
|
|
||||||
SDL_memcpy(last_sample, src, cpy);
|
SDL_memcpy(last_sample, src, cpy);
|
||||||
|
|
||||||
while (dst > target) {
|
while (dst > target) {
|
||||||
|
SDL_assert(src >= buf);
|
||||||
|
|
||||||
for (i = 0; i < channels; i++) {
|
for (i = 0; i < channels; i++) {
|
||||||
dst[i] = (float) ((((double)src[i]) + ((double)last_sample[i])) * 0.5);
|
dst[i] = (float) ((((double)src[i]) + ((double)last_sample[i])) * 0.5);
|
||||||
}
|
}
|
||||||
dst -= channels;
|
dst -= channels;
|
||||||
SDL_memcpy(dst, src, cpy);
|
|
||||||
SDL_memcpy(last_sample, src, cpy);
|
for (i = 1; i < multiple; i++) {
|
||||||
|
SDL_memcpy(dst, dst + channels, cpy);
|
||||||
|
dst -= channels;
|
||||||
|
}
|
||||||
|
|
||||||
src -= channels;
|
src -= channels;
|
||||||
dst -= channels;
|
if (src > buf) {
|
||||||
|
SDL_memcpy(last_sample, src - channels, cpy);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cvt->len_cvt = dstsize;
|
cvt->len_cvt = dstsize;
|
||||||
|
@ -338,51 +355,9 @@ SDL_Upsample_x2(SDL_AudioCVT *cvt, const int channels)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
SDL_Upsample_x4(SDL_AudioCVT *cvt, const int channels)
|
SDL_Downsample_Multiple(SDL_AudioCVT *cvt, const int channels)
|
||||||
{
|
|
||||||
const int dstsize = cvt->len_cvt * 4;
|
|
||||||
float *dst = ((float *) (cvt->buf + dstsize)) - (channels * 4);
|
|
||||||
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 last_sample[8];
|
|
||||||
int i;
|
|
||||||
|
|
||||||
#if DEBUG_CONVERT
|
|
||||||
fprintf(stderr, "Upsample (x4), %d channels.\n", 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]) + (3.0 * ((double) last_sample[i]))) * 0.25);
|
|
||||||
}
|
|
||||||
dst -= channels;
|
|
||||||
for (i = 0; i < channels; i++) {
|
|
||||||
dst[i] = (float) ((((double) src[i]) + ((double) last_sample[i])) * 0.25);
|
|
||||||
}
|
|
||||||
dst -= channels;
|
|
||||||
for (i = 0; i < channels; i++) {
|
|
||||||
dst[i] = (float) (((3.0 * ((double) src[i])) + ((double) last_sample[i])) * 0.25);
|
|
||||||
}
|
|
||||||
dst -= channels;
|
|
||||||
SDL_memcpy(dst, src, cpy);
|
|
||||||
dst -= channels;
|
|
||||||
SDL_memcpy(last_sample, src, cpy);
|
|
||||||
src -= channels;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 multiple, const int channels)
|
|
||||||
{
|
{
|
||||||
|
const int multiple = (int) (1.0 / cvt->rate_incr);
|
||||||
const int dstsize = cvt->len_cvt / multiple;
|
const int dstsize = cvt->len_cvt / multiple;
|
||||||
float *dst = (float *) cvt->buf;
|
float *dst = (float *) cvt->buf;
|
||||||
const float *src = (float *) cvt->buf;
|
const float *src = (float *) cvt->buf;
|
||||||
|
|
Loading…
Reference in New Issue