/* _______ ____ __ ___ ___ * \ _ \ \ / \ / \ \ / / ' ' ' * | | \ \ | | || | \/ | . . * | | | | | | || ||\ /| | * | | | | | | || || \/ | | ' ' ' * | | | | | | || || | | . . * | |_/ / \ \__// || | | * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque * / \ * / . \ * resample.c - Resampling helpers. / / \ \ * | < / \_ * By Bob and entheh. | \/ /\ / * \_ / > / * In order to find a good trade-off between | \ / / * speed and accuracy in this code, some tests | ' / * were carried out regarding the behaviour of \__/ * long long ints with gcc. The following code * was tested: * * int a, b, c; * c = ((long long)a * b) >> 16; * * DJGPP GCC Version 3.0.3 generated the following assembly language code for * the multiplication and scaling, leaving the 32-bit result in EAX. * * movl -8(%ebp), %eax ; read one int into EAX * imull -4(%ebp) ; multiply by the other; result goes in EDX:EAX * shrdl $16, %edx, %eax ; shift EAX right 16, shifting bits in from EDX * * Note that a 32*32->64 multiplication is performed, allowing for high * accuracy. On the Pentium 2 and above, shrdl takes two cycles (generally), * so it is a minor concern when four multiplications are being performed * (the cubic resampler). On the Pentium MMX and earlier, it takes four or * more cycles, so this method is unsuitable for use in the low-quality * resamplers. * * Since "long long" is a gcc-specific extension, we use LONG_LONG instead, * defined in dumb.h. We may investigate later what code MSVC generates, but * if it seems too slow then we suggest you use a good compiler. * * FIXME: these comments are somewhat out of date now. */ #include <math.h>#include "internal/resampler.h"#include "internal/dumb.h" /* Compile with -DHEAVYDEBUG if you want to make sure the pick-up function is * called when it should be. There will be a considerable performance hit, * since at least one condition has to be tested for every sample generated. */#ifdef HEAVYDEBUG#define HEAVYASSERT(cond) ASSERT(cond)#else#define HEAVYASSERT(cond)#endif /* Make MSVC shut the hell up about if ( upd ) UPDATE_VOLUME() conditions being * constant */#ifdef _MSC_VER#pragma warning(disable : 4127 4701)#endif /* A global variable for controlling resampling quality wherever a local * specification doesn't override it. The following values are valid: * * 0 - DUMB_RQ_ALIASING - fastest * 1 - DUMB_RQ_BLEP - nicer than aliasing, but slower * 2 - DUMB_RQ_LINEAR * 3 - DUMB_RQ_BLAM - band-limited linear interpolation, nice but slower * 4 - DUMB_RQ_CUBIC * 5 - DUMB_RQ_FIR - nicest * * Values outside the range 0-4 will behave the same as the nearest * value within the range. */int dumb_resampling_quality = DUMB_RQ_CUBIC; //#define MULSC(a, b) ((int)((LONG_LONG)(a) * (b) >> 16))//#define MULSC(a, b) ((a) * ((b) >> 2) >> 14)#define MULSCV(a, b) ((int)((LONG_LONG)(a) * (b) >> 32))#define MULSC(a, b) ((int)((LONG_LONG)((a) << 4) * ((b) << 12) >> 32))#define MULSC16(a, b) ((int)((LONG_LONG)((a) << 12) * ((b) << 12) >> 32)) /* Executes the content 'iterator' times. * Clobbers the 'iterator' variable. * The loop is unrolled by four. */#if 0#define LOOP4(iterator, CONTENT) \ { \ if ((iterator)&2) { \ CONTENT; \ CONTENT; \ } \ if ((iterator)&1) { \ CONTENT; \ } \ (iterator) >>= 2; \ while (iterator) { \ CONTENT; \ CONTENT; \ CONTENT; \ CONTENT; \ (iterator)--; \ } \ }#else#define LOOP4(iterator, CONTENT) \ { \ while ((iterator)--) { \ CONTENT; \ } \ }#endif #define PASTERAW(a, b) a##b /* This does not expand macros in b ... */#define PASTE(a, b) \ PASTERAW(a, b) /* ... but b is expanded during this substitution. */ #define X PASTE(x.x, SRCBITS) void _dumb_init_cubic(void) { static int done = 0; if (done) return; resampler_init(); done = 1;} /* Create resamplers for 24-in-32-bit source samples. */ /* #define SUFFIX * MSVC warns if we try to paste a null SUFFIX, so instead we define * special macros for the function names that don't bother doing the * corresponding paste. The more generic definitions are further down. */#define process_pickup PASTE(process_pickup, SUFFIX2)#define dumb_resample PASTE(PASTE(dumb_resample, SUFFIX2), SUFFIX3)#define dumb_resample_get_current_sample \ PASTE(PASTE(dumb_resample_get_current_sample, SUFFIX2), SUFFIX3) #define SRCTYPE sample_t#define SRCBITS 24#define FIR(x) (x >> 8)#include "resample.inc" /* Undefine the simplified macros. */#undef dumb_resample_get_current_sample#undef dumb_resample#undef process_pickup /* Now define the proper ones that use SUFFIX. */#define dumb_reset_resampler PASTE(dumb_reset_resampler, SUFFIX)#define dumb_start_resampler PASTE(dumb_start_resampler, SUFFIX)#define process_pickup PASTE(PASTE(process_pickup, SUFFIX), SUFFIX2)#define dumb_resample \ PASTE(PASTE(PASTE(dumb_resample, SUFFIX), SUFFIX2), SUFFIX3)#define dumb_resample_get_current_sample \ PASTE(PASTE(PASTE(dumb_resample_get_current_sample, SUFFIX), SUFFIX2), \ SUFFIX3)#define dumb_end_resampler PASTE(dumb_end_resampler, SUFFIX) /* Create resamplers for 16-bit source samples. */#define SUFFIX _16#define SRCTYPE short#define SRCBITS 16#define FIR(x) (x * (1.0f / 32768.0f))#include "resample.inc" /* Create resamplers for 8-bit source samples. */#define SUFFIX _8#define SRCTYPE signed char#define SRCBITS 8#define FIR(x) (x * (1.0f / 256.0f))#include "resample.inc" #undef dumb_reset_resampler#undef dumb_start_resampler#undef process_pickup#undef dumb_resample#undef dumb_resample_get_current_sample#undef dumb_end_resampler void dumb_reset_resampler_n(int n, DUMB_RESAMPLER *resampler, void *src, int src_channels, long pos, long start, long end, int quality) { if (n == 8) dumb_reset_resampler_8(resampler, src, src_channels, pos, start, end, quality); else if (n == 16) dumb_reset_resampler_16(resampler, src, src_channels, pos, start, end, quality); else dumb_reset_resampler(resampler, src, src_channels, pos, start, end, quality);} DUMB_RESAMPLER *dumb_start_resampler_n(int n, void *src, int src_channels, long pos, long start, long end, int quality) { if (n == 8) return dumb_start_resampler_8(src, src_channels, pos, start, end, quality); else if (n == 16) return dumb_start_resampler_16(src, src_channels, pos, start, end, quality); else return dumb_start_resampler(src, src_channels, pos, start, end, quality);} long dumb_resample_n_1_1(int n, DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, DUMB_VOLUME_RAMP_INFO *volume, float delta) { if (n == 8) return dumb_resample_8_1_1(resampler, dst, dst_size, volume, delta); else if (n == 16) return dumb_resample_16_1_1(resampler, dst, dst_size, volume, delta); else return dumb_resample_1_1(resampler, dst, dst_size, volume, delta);} long dumb_resample_n_1_2(int n, DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, DUMB_VOLUME_RAMP_INFO *volume_left, DUMB_VOLUME_RAMP_INFO *volume_right, float delta) { if (n == 8) return dumb_resample_8_1_2(resampler, dst, dst_size, volume_left, volume_right, delta); else if (n == 16) return dumb_resample_16_1_2(resampler, dst, dst_size, volume_left, volume_right, delta); else return dumb_resample_1_2(resampler, dst, dst_size, volume_left, volume_right, delta);} long dumb_resample_n_2_1(int n, DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, DUMB_VOLUME_RAMP_INFO *volume_left, DUMB_VOLUME_RAMP_INFO *volume_right, float delta) { if (n == 8) return dumb_resample_8_2_1(resampler, dst, dst_size, volume_left, volume_right, delta); else if (n == 16) return dumb_resample_16_2_1(resampler, dst, dst_size, volume_left, volume_right, delta); else return dumb_resample_2_1(resampler, dst, dst_size, volume_left, volume_right, delta);} long dumb_resample_n_2_2(int n, DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, DUMB_VOLUME_RAMP_INFO *volume_left, DUMB_VOLUME_RAMP_INFO *volume_right, float delta) { if (n == 8) return dumb_resample_8_2_2(resampler, dst, dst_size, volume_left, volume_right, delta); else if (n == 16) return dumb_resample_16_2_2(resampler, dst, dst_size, volume_left, volume_right, delta); else return dumb_resample_2_2(resampler, dst, dst_size, volume_left, volume_right, delta);} void dumb_resample_get_current_sample_n_1_1(int n, DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO *volume, sample_t *dst) { if (n == 8) dumb_resample_get_current_sample_8_1_1(resampler, volume, dst); else if (n == 16) dumb_resample_get_current_sample_16_1_1(resampler, volume, dst); else dumb_resample_get_current_sample_1_1(resampler, volume, dst);} void dumb_resample_get_current_sample_n_1_2(int n, DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO *volume_left, DUMB_VOLUME_RAMP_INFO *volume_right, sample_t *dst) { if (n == 8) dumb_resample_get_current_sample_8_1_2(resampler, volume_left, volume_right, dst); else if (n == 16) dumb_resample_get_current_sample_16_1_2(resampler, volume_left, volume_right, dst); else dumb_resample_get_current_sample_1_2(resampler, volume_left, volume_right, dst);} void dumb_resample_get_current_sample_n_2_1(int n, DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO *volume_left, DUMB_VOLUME_RAMP_INFO *volume_right, sample_t *dst) { if (n == 8) dumb_resample_get_current_sample_8_2_1(resampler, volume_left, volume_right, dst); else if (n == 16) dumb_resample_get_current_sample_16_2_1(resampler, volume_left, volume_right, dst); else dumb_resample_get_current_sample_2_1(resampler, volume_left, volume_right, dst);} void dumb_resample_get_current_sample_n_2_2(int n, DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO *volume_left, DUMB_VOLUME_RAMP_INFO *volume_right, sample_t *dst) { if (n == 8) dumb_resample_get_current_sample_8_2_2(resampler, volume_left, volume_right, dst); else if (n == 16) dumb_resample_get_current_sample_16_2_2(resampler, volume_left, volume_right, dst); else dumb_resample_get_current_sample_2_2(resampler, volume_left, volume_right, dst);} void dumb_end_resampler_n(int n, DUMB_RESAMPLER *resampler) { if (n == 8) dumb_end_resampler_8(resampler); else if (n == 16) dumb_end_resampler_16(resampler); else dumb_end_resampler(resampler);}
/* _______ ____ __ ___ ___
* \ _ \ \ / \ / \ \ / / ' ' '
* | | \ \ | | || | \/ | . .
* | | | | | | || ||\ /| |
* | | | | | | || || \/ | | ' ' '
* | | | | | | || || | | . .
* | |_/ / \ \__// || | |
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
* / \
* / . \
* resample.c - Resampling helpers. / / \ \
* | < / \_
* By Bob and entheh. | \/ /\ /
* \_ / > /
* In order to find a good trade-off between | \ / /
* speed and accuracy in this code, some tests | ' /
* were carried out regarding the behaviour of \__/
* long long ints with gcc. The following code
* was tested:
*
* int a, b, c;
* c = ((long long)a * b) >> 16;
*
* DJGPP GCC Version 3.0.3 generated the following assembly language code for
* the multiplication and scaling, leaving the 32-bit result in EAX.
*
* movl -8(%ebp), %eax ; read one int into EAX
* imull -4(%ebp) ; multiply by the other; result goes in EDX:EAX
* shrdl $16, %edx, %eax ; shift EAX right 16, shifting bits in from EDX
*
* Note that a 32*32->64 multiplication is performed, allowing for high
* accuracy. On the Pentium 2 and above, shrdl takes two cycles (generally),
* so it is a minor concern when four multiplications are being performed
* (the cubic resampler). On the Pentium MMX and earlier, it takes four or
* more cycles, so this method is unsuitable for use in the low-quality
* resamplers.
*
* Since "long long" is a gcc-specific extension, we use LONG_LONG instead,
* defined in dumb.h. We may investigate later what code MSVC generates, but
* if it seems too slow then we suggest you use a good compiler.
*
* FIXME: these comments are somewhat out of date now.
*/
#include <math.h>
#include "internal/resampler.h"
#include "internal/dumb.h"
/* Compile with -DHEAVYDEBUG if you want to make sure the pick-up function is
* called when it should be. There will be a considerable performance hit,
* since at least one condition has to be tested for every sample generated.
*/
#ifdef HEAVYDEBUG
#define HEAVYASSERT(cond) ASSERT(cond)
#else
#define HEAVYASSERT(cond)
#endif
/* Make MSVC shut the hell up about if ( upd ) UPDATE_VOLUME() conditions being
* constant */
#ifdef _MSC_VER
#pragma warning(disable : 4127 4701)
#endif
/* A global variable for controlling resampling quality wherever a local
* specification doesn't override it. The following values are valid:
*
* 0 - DUMB_RQ_ALIASING - fastest
* 1 - DUMB_RQ_BLEP - nicer than aliasing, but slower
* 2 - DUMB_RQ_LINEAR
* 3 - DUMB_RQ_BLAM - band-limited linear interpolation, nice but slower
* 4 - DUMB_RQ_CUBIC
* 5 - DUMB_RQ_FIR - nicest
*
* Values outside the range 0-4 will behave the same as the nearest
* value within the range.
*/
int dumb_resampling_quality = DUMB_RQ_CUBIC;
//#define MULSC(a, b) ((int)((LONG_LONG)(a) * (b) >> 16))
//#define MULSC(a, b) ((a) * ((b) >> 2) >> 14)
#define MULSCV(a, b) ((int)((LONG_LONG)(a) * (b) >> 32))
#define MULSC(a, b) ((int)((LONG_LONG)((a) << 4) * ((b) << 12) >> 32))
#define MULSC16(a, b) ((int)((LONG_LONG)((a) << 12) * ((b) << 12) >> 32))
/* Executes the content 'iterator' times.
* Clobbers the 'iterator' variable.
* The loop is unrolled by four.
*/
#if 0
#define LOOP4(iterator, CONTENT) \
{ \
if ((iterator)&2) { \
CONTENT; \
CONTENT; \
} \
if ((iterator)&1) { \
CONTENT; \
} \
(iterator) >>= 2; \
while (iterator) { \
CONTENT; \
CONTENT; \
CONTENT; \
CONTENT; \
(iterator)--; \
} \
}
#else
#define LOOP4(iterator, CONTENT) \
{ \
while ((iterator)--) { \
CONTENT; \
} \
}
#endif
#define PASTERAW(a, b) a##b /* This does not expand macros in b ... */
#define PASTE(a, b) \
PASTERAW(a, b) /* ... but b is expanded during this substitution. */
#define X PASTE(x.x, SRCBITS)
void _dumb_init_cubic(void) {
static int done = 0;
if (done)
return;
resampler_init();
done = 1;
}
/* Create resamplers for 24-in-32-bit source samples. */
/* #define SUFFIX
* MSVC warns if we try to paste a null SUFFIX, so instead we define
* special macros for the function names that don't bother doing the
* corresponding paste. The more generic definitions are further down.
*/
#define process_pickup PASTE(process_pickup, SUFFIX2)
#define dumb_resample PASTE(PASTE(dumb_resample, SUFFIX2), SUFFIX3)
#define dumb_resample_get_current_sample \
PASTE(PASTE(dumb_resample_get_current_sample, SUFFIX2), SUFFIX3)
#define SRCTYPE sample_t
#define SRCBITS 24
#define FIR(x) (x >> 8)
#include "resample.inc"
/* Undefine the simplified macros. */
#undef dumb_resample_get_current_sample
#undef dumb_resample
#undef process_pickup
/* Now define the proper ones that use SUFFIX. */
#define dumb_reset_resampler PASTE(dumb_reset_resampler, SUFFIX)
#define dumb_start_resampler PASTE(dumb_start_resampler, SUFFIX)
#define process_pickup PASTE(PASTE(process_pickup, SUFFIX), SUFFIX2)
#define dumb_resample \
PASTE(PASTE(PASTE(dumb_resample, SUFFIX), SUFFIX2), SUFFIX3)
#define dumb_resample_get_current_sample \
PASTE(PASTE(PASTE(dumb_resample_get_current_sample, SUFFIX), SUFFIX2), \
SUFFIX3)
#define dumb_end_resampler PASTE(dumb_end_resampler, SUFFIX)
/* Create resamplers for 16-bit source samples. */
#define SUFFIX _16
#define SRCTYPE short
#define SRCBITS 16
#define FIR(x) (x * (1.0f / 32768.0f))
#include "resample.inc"
/* Create resamplers for 8-bit source samples. */
#define SUFFIX _8
#define SRCTYPE signed char
#define SRCBITS 8
#define FIR(x) (x * (1.0f / 256.0f))
#include "resample.inc"
#undef dumb_reset_resampler
#undef dumb_start_resampler
#undef process_pickup
#undef dumb_resample
#undef dumb_resample_get_current_sample
#undef dumb_end_resampler
void dumb_reset_resampler_n(int n, DUMB_RESAMPLER *resampler, void *src,
int src_channels, long pos, long start, long end,
int quality) {
if (n == 8)
dumb_reset_resampler_8(resampler, src, src_channels, pos, start, end,
quality);
else if (n == 16)
dumb_reset_resampler_16(resampler, src, src_channels, pos, start, end,
quality);
else
dumb_reset_resampler(resampler, src, src_channels, pos, start, end,
quality);
}
DUMB_RESAMPLER *dumb_start_resampler_n(int n, void *src, int src_channels,
long pos, long start, long end,
int quality) {
if (n == 8)
return dumb_start_resampler_8(src, src_channels, pos, start, end,
quality);
else if (n == 16)
return dumb_start_resampler_16(src, src_channels, pos, start, end,
quality);
else
return dumb_start_resampler(src, src_channels, pos, start, end,
quality);
}
long dumb_resample_n_1_1(int n, DUMB_RESAMPLER *resampler, sample_t *dst,
long dst_size, DUMB_VOLUME_RAMP_INFO *volume,
float delta) {
if (n == 8)
return dumb_resample_8_1_1(resampler, dst, dst_size, volume, delta);
else if (n == 16)
return dumb_resample_16_1_1(resampler, dst, dst_size, volume, delta);
else
return dumb_resample_1_1(resampler, dst, dst_size, volume, delta);
}
long dumb_resample_n_1_2(int n, DUMB_RESAMPLER *resampler, sample_t *dst,
long dst_size, DUMB_VOLUME_RAMP_INFO *volume_left,
DUMB_VOLUME_RAMP_INFO *volume_right, float delta) {
if (n == 8)
return dumb_resample_8_1_2(resampler, dst, dst_size, volume_left,
volume_right, delta);
else if (n == 16)
return dumb_resample_16_1_2(resampler, dst, dst_size, volume_left,
volume_right, delta);
else
return dumb_resample_1_2(resampler, dst, dst_size, volume_left,
volume_right, delta);
}
long dumb_resample_n_2_1(int n, DUMB_RESAMPLER *resampler, sample_t *dst,
long dst_size, DUMB_VOLUME_RAMP_INFO *volume_left,
DUMB_VOLUME_RAMP_INFO *volume_right, float delta) {
if (n == 8)
return dumb_resample_8_2_1(resampler, dst, dst_size, volume_left,
volume_right, delta);
else if (n == 16)
return dumb_resample_16_2_1(resampler, dst, dst_size, volume_left,
volume_right, delta);
else
return dumb_resample_2_1(resampler, dst, dst_size, volume_left,
volume_right, delta);
}
long dumb_resample_n_2_2(int n, DUMB_RESAMPLER *resampler, sample_t *dst,
long dst_size, DUMB_VOLUME_RAMP_INFO *volume_left,
DUMB_VOLUME_RAMP_INFO *volume_right, float delta) {
if (n == 8)
return dumb_resample_8_2_2(resampler, dst, dst_size, volume_left,
volume_right, delta);
else if (n == 16)
return dumb_resample_16_2_2(resampler, dst, dst_size, volume_left,
volume_right, delta);
else
return dumb_resample_2_2(resampler, dst, dst_size, volume_left,
volume_right, delta);
}
void dumb_resample_get_current_sample_n_1_1(int n, DUMB_RESAMPLER *resampler,
DUMB_VOLUME_RAMP_INFO *volume,
sample_t *dst) {
if (n == 8)
dumb_resample_get_current_sample_8_1_1(resampler, volume, dst);
else if (n == 16)
dumb_resample_get_current_sample_16_1_1(resampler, volume, dst);
else
dumb_resample_get_current_sample_1_1(resampler, volume, dst);
}
void dumb_resample_get_current_sample_n_1_2(int n, DUMB_RESAMPLER *resampler,
DUMB_VOLUME_RAMP_INFO *volume_left,
DUMB_VOLUME_RAMP_INFO *volume_right,
sample_t *dst) {
if (n == 8)
dumb_resample_get_current_sample_8_1_2(resampler, volume_left,
volume_right, dst);
else if (n == 16)
dumb_resample_get_current_sample_16_1_2(resampler, volume_left,
volume_right, dst);
else
dumb_resample_get_current_sample_1_2(resampler, volume_left,
volume_right, dst);
}
void dumb_resample_get_current_sample_n_2_1(int n, DUMB_RESAMPLER *resampler,
DUMB_VOLUME_RAMP_INFO *volume_left,
DUMB_VOLUME_RAMP_INFO *volume_right,
sample_t *dst) {
if (n == 8)
dumb_resample_get_current_sample_8_2_1(resampler, volume_left,
volume_right, dst);
else if (n == 16)
dumb_resample_get_current_sample_16_2_1(resampler, volume_left,
volume_right, dst);
else
dumb_resample_get_current_sample_2_1(resampler, volume_left,
volume_right, dst);
}
void dumb_resample_get_current_sample_n_2_2(int n, DUMB_RESAMPLER *resampler,
DUMB_VOLUME_RAMP_INFO *volume_left,
DUMB_VOLUME_RAMP_INFO *volume_right,
sample_t *dst) {
if (n == 8)
dumb_resample_get_current_sample_8_2_2(resampler, volume_left,
volume_right, dst);
else if (n == 16)
dumb_resample_get_current_sample_16_2_2(resampler, volume_left,
volume_right, dst);
else
dumb_resample_get_current_sample_2_2(resampler, volume_left,
volume_right, dst);
}
void dumb_end_resampler_n(int n, DUMB_RESAMPLER *resampler) {
if (n == 8)
dumb_end_resampler_8(resampler);
else if (n == 16)
dumb_end_resampler_16(resampler);
else
dumb_end_resampler(resampler);
}