ref: cab1803f1d6517754696b5c3d9b600e23ef9015e
dir: /src/helpers/resample.inc/
/* _______ ____ __ ___ ___ * \ _ \ \ / \ / \ \ / / ' ' ' * | | \ \ | | || | \/ | . . * | | | | | | || ||\ /| | * | | | | | | || || \/ | | ' ' ' * | | | | | | || || | | . . * | |_/ / \ \__// || | | * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque * / \ * / . \ * resample.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. */ void dumb_reset_resampler(DUMB_RESAMPLER *resampler, SRCTYPE *src, int src_channels, long pos, long start, long end, int quality) { int i; resampler->src = src; resampler->pos = pos; resampler->subpos = 0; resampler->start = start; resampler->end = end; resampler->dir = 1; resampler->pickup = NULL; resampler->pickup_data = NULL; if (quality < 0) { resampler->quality = 0; } else if (quality > DUMB_RQ_N_LEVELS - 1) { resampler->quality = DUMB_RQ_N_LEVELS - 1; } else { resampler->quality = quality; } for (i = 0; i < src_channels * 3; i++) resampler->X[i] = 0; resampler->overshot = -1; resampler->fir_resampler_ratio = 0; resampler_clear(resampler->fir_resampler[0]); resampler_clear(resampler->fir_resampler[1]); resampler_set_quality(resampler->fir_resampler[0], resampler->quality); resampler_set_quality(resampler->fir_resampler[1], resampler->quality); } DUMB_RESAMPLER *dumb_start_resampler(SRCTYPE *src, int src_channels, long pos, long start, long end, int quality) { DUMB_RESAMPLER *resampler = malloc(sizeof(*resampler)); if (!resampler) return NULL; dumb_reset_resampler(resampler, src, src_channels, pos, start, end, quality); return resampler; } #define UPDATE_VOLUME(pvol, vol) \ { \ if (pvol) { \ vol##r += vol##d; \ if ((vol##d < 0 && vol##r <= vol##t) || \ (vol##d > 0 && vol##r >= vol##t)) { \ pvol->volume = pvol->target; \ if (pvol->declick_stage == 0 || pvol->declick_stage >= 3) \ pvol->declick_stage++; \ pvol = NULL; \ vol = vol##t * vol##m; \ } else { \ vol = vol##r * vol##m; \ } \ } \ } /* Create mono source resampler. */ #define SUFFIX2 _1 #define SRC_CHANNELS 1 #define DIVIDE_BY_SRC_CHANNELS(x) (x) #define COPYSRC(dstarray, dstindex, srcarray, srcindex) \ (dstarray)[dstindex] = (srcarray)[srcindex] #define COPYSRC2(dstarray, dstindex, condition, srcarray, srcindex) \ (dstarray)[dstindex] = condition ? (srcarray)[srcindex] : 0 #define MONO_DEST_VOLUME_PARAMETERS DUMB_VOLUME_RAMP_INFO *volume #define MONO_DEST_VOLUME_VARIABLES vol, volr, vold, volt, volm #define MONO_DEST_VOLUME_ZEROS 0 #define SET_MONO_DEST_VOLUME_VARIABLES \ { \ if (volume) { \ volr = volume->volume; \ vold = volume->delta; \ volt = volume->target; \ volm = volume->mix; \ vol = volr * volm; \ if (volr == volt) \ volume = NULL; \ } else { \ vol = 0; \ volr = 0; \ vold = 0; \ volt = 0; \ volm = 0; \ } \ } #define RETURN_MONO_DEST_VOLUME_VARIABLES \ if (volume) \ volume->volume = volr #define MONO_DEST_VOLUMES_ARE_ZERO (vol == 0 && volt == 0) #define POKE_FIR(offset) \ { \ resampler_write_sample_float(resampler->fir_resampler[0], \ FIR(x[offset])); \ } #define MONO_DEST_PEEK_FIR \ *dst = resampler_get_sample_float(resampler->fir_resampler[0]) * vol * \ 16777216.0f #define MONO_DEST_MIX_FIR \ { \ *dst++ += resampler_get_sample_float(resampler->fir_resampler[0]) * \ vol * 16777216.0f; \ UPDATE_VOLUME(volume, vol); \ } #define ADVANCE_FIR resampler_remove_sample(resampler->fir_resampler[0], 1) #define STEREO_DEST_PEEK_FIR \ { \ float sample = \ resampler_get_sample_float(resampler->fir_resampler[0]); \ *dst++ = sample * lvol * 16777216.0f; \ *dst++ = sample * rvol * 16777216.0f; \ } #define STEREO_DEST_MIX_FIR \ { \ float sample = \ resampler_get_sample_float(resampler->fir_resampler[0]); \ *dst++ += sample * lvol * 16777216.0f; \ *dst++ += sample * rvol * 16777216.0f; \ UPDATE_VOLUME(volume_left, lvol); \ UPDATE_VOLUME(volume_right, rvol); \ } #include "resamp2.inc" /* Create stereo source resampler. */ #define SUFFIX2 _2 #define SRC_CHANNELS 2 #define DIVIDE_BY_SRC_CHANNELS(x) ((x) >> 1) #define COPYSRC(dstarray, dstindex, srcarray, srcindex) \ { \ (dstarray)[(dstindex)*2] = (srcarray)[(srcindex)*2]; \ (dstarray)[(dstindex)*2 + 1] = (srcarray)[(srcindex)*2 + 1]; \ } #define COPYSRC2(dstarray, dstindex, condition, srcarray, srcindex) \ { \ if (condition) { \ (dstarray)[(dstindex)*2] = (srcarray)[(srcindex)*2]; \ (dstarray)[(dstindex)*2 + 1] = (srcarray)[(srcindex)*2 + 1]; \ } else { \ (dstarray)[(dstindex)*2] = 0; \ (dstarray)[(dstindex)*2 + 1] = 0; \ } \ } #define MONO_DEST_VOLUME_PARAMETERS \ DUMB_VOLUME_RAMP_INFO *volume_left, DUMB_VOLUME_RAMP_INFO *volume_right #define MONO_DEST_VOLUME_VARIABLES \ lvol, lvolr, lvold, lvolt, lvolm, rvol, rvolr, rvold, rvolt, rvolm #define MONO_DEST_VOLUME_ZEROS 0, 0 #define SET_MONO_DEST_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; \ lvolr = 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; \ rvolr = 0; \ rvold = 0; \ rvolt = 0; \ rvolm = 0; \ } \ } #define RETURN_MONO_DEST_VOLUME_VARIABLES \ { \ if (volume_left) \ volume_left->volume = lvolr; \ if (volume_right) \ volume_right->volume = rvolr; \ } #define MONO_DEST_VOLUMES_ARE_ZERO \ (lvol == 0 && lvolt == 0 && rvol == 0 && rvolt == 0) #define POKE_FIR(offset) \ { \ resampler_write_sample_float(resampler->fir_resampler[0], \ FIR(x[(offset)*2 + 0])); \ resampler_write_sample_float(resampler->fir_resampler[1], \ FIR(x[(offset)*2 + 1])); \ } #define MONO_DEST_PEEK_FIR \ { \ *dst = \ (resampler_get_sample_float(resampler->fir_resampler[0]) * lvol + \ resampler_get_sample_float(resampler->fir_resampler[1]) * rvol) * \ 16777216.0f; \ } #define MONO_DEST_MIX_FIR \ { \ *dst++ += \ (resampler_get_sample_float(resampler->fir_resampler[0]) * lvol + \ resampler_get_sample_float(resampler->fir_resampler[1]) * rvol) * \ 16777216.0f; \ UPDATE_VOLUME(volume_left, lvol); \ UPDATE_VOLUME(volume_right, rvol); \ } #define ADVANCE_FIR \ { \ resampler_remove_sample(resampler->fir_resampler[0], 1); \ resampler_remove_sample(resampler->fir_resampler[1], 1); \ } #define STEREO_DEST_PEEK_FIR \ { \ *dst++ = resampler_get_sample_float(resampler->fir_resampler[0]) * \ lvol * 16777216.0f; \ *dst++ = resampler_get_sample_float(resampler->fir_resampler[1]) * \ rvol * 16777216.0f; \ } #define STEREO_DEST_MIX_FIR \ { \ *dst++ += resampler_get_sample_float(resampler->fir_resampler[0]) * \ lvol * 16777216.0f; \ *dst++ += resampler_get_sample_float(resampler->fir_resampler[1]) * \ rvol * 16777216.0f; \ UPDATE_VOLUME(volume_left, lvol); \ UPDATE_VOLUME(volume_right, rvol); \ } #include "resamp2.inc" void dumb_end_resampler(DUMB_RESAMPLER *resampler) { if (resampler) free(resampler); } #undef FIR #undef SRCBITS #undef SRCTYPE #undef SUFFIX