ref: ceb1f19afffc8a17eb132a5ee2f8ff58dd5803b1
dir: /src/helpers/resamp2.inc/
/* _______ ____ __ ___ ___ * \ _ \ \ / \ / \ \ / / ' ' ' * | | \ \ | | || | \/ | . . * | | | | | | || ||\ /| | * | | | | | | || || \/ | | ' ' ' * | | | | | | || || | | . . * | |_/ / \ \__// || | | * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque * / \ * / . \ * resamp2.inc - Resampling helper template. / / \ \ * | < / \_ * 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. */ #define SUFFIX3 _1 /* For convenience, returns nonzero on stop. */ static int process_pickup(DUMB_RESAMPLER *resampler) { if (resampler->overshot < 0) { resampler->overshot = 0; dumb_resample(resampler, NULL, 2, MONO_DEST_VOLUME_ZEROS, 1.0f); /* Doesn't matter which SUFFIX3. */ COPYSRC(resampler->X, 0, resampler->X, 1); } for (;;) { SRCTYPE *src = resampler->src; if (resampler->dir < 0) { if (resampler->overshot >= 3 && resampler->pos + 3 >= resampler->start) COPYSRC(resampler->X, 0, src, resampler->pos + 3); if (resampler->overshot >= 2 && resampler->pos + 2 >= resampler->start) COPYSRC(resampler->X, 1, src, resampler->pos + 2); if (resampler->overshot >= 1 && resampler->pos + 1 >= resampler->start) COPYSRC(resampler->X, 2, src, resampler->pos + 1); resampler->overshot = (int)(resampler->start - resampler->pos - 1); } else { if (resampler->overshot >= 3 && resampler->pos - 3 < resampler->end) COPYSRC(resampler->X, 0, src, resampler->pos - 3); if (resampler->overshot >= 2 && resampler->pos - 2 < resampler->end) COPYSRC(resampler->X, 1, src, resampler->pos - 2); if (resampler->overshot >= 1 && resampler->pos - 1 < resampler->end) COPYSRC(resampler->X, 2, src, resampler->pos - 1); resampler->overshot = (int)(resampler->pos - resampler->end); } if (resampler->overshot < 0) { resampler->overshot = 0; return 0; } if (!resampler->pickup) { resampler->dir = 0; return 1; } (*resampler->pickup)(resampler, resampler->pickup_data); if (resampler->dir == 0) return 1; ASSERT(resampler->dir == -1 || resampler->dir == 1); } } /* Create mono destination resampler. */ /* SUFFIX3 was set above. */ #define VOLUME_PARAMETERS MONO_DEST_VOLUME_PARAMETERS #define VOLUME_VARIABLES MONO_DEST_VOLUME_VARIABLES #define SET_VOLUME_VARIABLES SET_MONO_DEST_VOLUME_VARIABLES #define RETURN_VOLUME_VARIABLES RETURN_MONO_DEST_VOLUME_VARIABLES #define VOLUMES_ARE_ZERO MONO_DEST_VOLUMES_ARE_ZERO #define PEEK_FIR MONO_DEST_PEEK_FIR #define MIX_FIR MONO_DEST_MIX_FIR #define MIX_ZEROS(op) *dst++ op 0 #include "resamp3.inc" /* Create stereo destination resampler. */ #define SUFFIX3 _2 #define VOLUME_PARAMETERS \ DUMB_VOLUME_RAMP_INFO *volume_left, DUMB_VOLUME_RAMP_INFO *volume_right #define VOLUME_VARIABLES \ lvol, lvolr, lvold, lvolt, lvolm, rvol, rvolr, rvold, rvolt, rvolm #define SET_VOLUME_VARIABLES \ { \ if (volume_left) { \ lvolr = volume_left->volume; \ lvold = volume_left->delta; \ lvolt = volume_left->target; \ lvolm = volume_left->mix; \ lvol = lvolr * lvolm; \ if (lvolr == lvolt) \ volume_left = NULL; \ } else { \ lvol = 0; \ lvold = 0; \ lvolt = 0; \ lvolm = 0; \ } \ if (volume_right) { \ rvolr = volume_right->volume; \ rvold = volume_right->delta; \ rvolt = volume_right->target; \ rvolm = volume_right->mix; \ rvol = rvolr * rvolm; \ if (rvolr == rvolt) \ volume_right = NULL; \ } else { \ rvol = 0; \ rvold = 0; \ rvolt = 0; \ rvolm = 0; \ } \ } #define RETURN_VOLUME_VARIABLES \ { \ if (volume_left) \ volume_left->volume = lvolr; \ if (volume_right) \ volume_right->volume = rvolr; \ } #define VOLUMES_ARE_ZERO (lvol == 0 && lvolt == 0 && rvol == 0 && rvolt == 0) #define PEEK_FIR STEREO_DEST_PEEK_FIR #define MIX_FIR STEREO_DEST_MIX_FIR #define MIX_ZEROS(op) \ { \ *dst++ op 0; \ *dst++ op 0; \ } #include "resamp3.inc" #undef MONO_DEST_VOLUMES_ARE_ZERO #undef SET_MONO_DEST_VOLUME_VARIABLES #undef RETURN_MONO_DEST_VOLUME_VARIABLES #undef MONO_DEST_VOLUME_ZEROS #undef MONO_DEST_VOLUME_VARIABLES #undef MONO_DEST_VOLUME_PARAMETERS #undef MONO_DEST_PEEK_FIR #undef STEREO_DEST_PEEK_FIR #undef MONO_DEST_MIX_FIR #undef STEREO_DEST_MIX_FIR #undef ADVANCE_FIR #undef POKE_FIR #undef COPYSRC2 #undef COPYSRC #undef DIVIDE_BY_SRC_CHANNELS #undef SRC_CHANNELS #undef SUFFIX2