Cog/Frameworks/Dumb/dumb/src/helpers/resample.inc

257 lines
9.8 KiB
PHP
Raw Normal View History

2013-09-28 00:24:23 -03:00
/* _______ ____ __ ___ ___
* \ _ \ \ / \ / \ \ / / ' ' '
* | | \ \ | | || | \/ | . .
* | | | | | | || ||\ /| |
* | | | | | | || || \/ | | ' ' '
* | | | | | | || || | | . .
* | |_/ / \ \__// || | |
* /_______/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;
2014-03-04 22:21:07 -03:00
resampler->fir_resampler_ratio = 0;
2014-03-23 17:29:14 -03:00
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);
2013-09-28 00:24:23 -03:00
}
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++; \
2013-09-28 00:24:23 -03:00
pvol = NULL; \
2017-09-17 01:37:49 -03:00
vol = vol##t * vol##m; \
2013-09-28 00:24:23 -03:00
} else { \
2017-09-17 01:37:49 -03:00
vol = vol##r * vol##m; \
2013-09-28 00:24:23 -03:00
} \
} \
}
/* 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 ) { \
2017-09-17 01:37:49 -03:00
volr = volume->volume; \
vold = volume->delta; \
volt = volume->target; \
volm = volume->mix; \
vol = volr * volm; \
2013-09-28 00:24:23 -03:00
if ( volr == volt ) volume = NULL; \
} else { \
vol = 0; \
vold = 0; \
volt = 0; \
volm = 0; \
} \
}
2017-09-17 01:37:49 -03:00
#define RETURN_MONO_DEST_VOLUME_VARIABLES if ( volume ) volume->volume = volr
2013-09-28 00:24:23 -03:00
#define MONO_DEST_VOLUMES_ARE_ZERO (vol == 0 && volt == 0)
#define POKE_FIR(offset) { \
2017-09-17 01:37:49 -03:00
resampler_write_sample_float( resampler->fir_resampler[0], FIR(x[offset]) ); \
2013-09-28 00:24:23 -03:00
}
2017-09-17 01:37:49 -03:00
#define MONO_DEST_PEEK_FIR *dst = resampler_get_sample_float( resampler->fir_resampler[0] ) * vol * 16777216.0f
2013-09-28 00:24:23 -03:00
#define MONO_DEST_MIX_FIR { \
2017-09-17 01:37:49 -03:00
*dst++ += resampler_get_sample_float( resampler->fir_resampler[0] ) * vol * 16777216.0f; \
2013-09-28 00:24:23 -03:00
UPDATE_VOLUME( volume, vol ); \
}
#define ADVANCE_FIR resampler_remove_sample( resampler->fir_resampler[0], 1 )
2013-09-28 00:24:23 -03:00
#define STEREO_DEST_PEEK_FIR { \
2017-09-17 01:37:49 -03:00
float sample = resampler_get_sample_float( resampler->fir_resampler[0] ); \
*dst++ = sample * lvol * 16777216.0f; \
*dst++ = sample * rvol * 16777216.0f; \
2013-09-28 00:24:23 -03:00
}
#define STEREO_DEST_MIX_FIR { \
2017-09-17 01:37:49 -03:00
float sample = resampler_get_sample_float( resampler->fir_resampler[0] ); \
*dst++ += sample * lvol * 16777216.0f; \
*dst++ += sample * rvol * 16777216.0f; \
2013-09-28 00:24:23 -03:00
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 ) { \
2017-09-17 01:37:49 -03:00
lvolr = volume_left->volume; \
lvold = volume_left->delta; \
lvolt = volume_left->target; \
lvolm = volume_left->mix; \
lvol = lvolr * lvolm; \
2013-09-28 00:24:23 -03:00
if ( lvolr == lvolt ) volume_left = NULL; \
} else { \
lvol = 0; \
lvold = 0; \
lvolt = 0; \
lvolm = 0; \
} \
if ( volume_right ) { \
2017-09-17 01:37:49 -03:00
rvolr = volume_right->volume; \
rvold = volume_right->delta; \
rvolt = volume_right->target; \
rvolm = volume_right->mix; \
rvol = rvolr * rvolm; \
2013-09-28 00:24:23 -03:00
if ( rvolr == rvolt ) volume_right = NULL; \
} else { \
rvol = 0; \
rvold = 0; \
rvolt = 0; \
rvolm = 0; \
} \
}
#define RETURN_MONO_DEST_VOLUME_VARIABLES { \
2017-09-17 01:37:49 -03:00
if ( volume_left ) volume_left->volume = lvolr; \
if ( volume_right ) volume_right->volume = rvolr; \
2013-09-28 00:24:23 -03:00
}
#define MONO_DEST_VOLUMES_ARE_ZERO (lvol == 0 && lvolt == 0 && rvol == 0 && rvolt == 0)
#define POKE_FIR(offset) { \
2017-09-17 01:37:49 -03:00
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]) ); \
2013-09-28 00:24:23 -03:00
}
#define MONO_DEST_PEEK_FIR { \
2017-09-17 01:37:49 -03:00
*dst = (resampler_get_sample_float( resampler->fir_resampler[0] ) * lvol + \
resampler_get_sample_float( resampler->fir_resampler[1] ) * rvol) * 16777216.0f; \
2013-09-28 00:24:23 -03:00
}
#define MONO_DEST_MIX_FIR { \
2017-09-17 01:37:49 -03:00
*dst++ += (resampler_get_sample_float( resampler->fir_resampler[0] ) * lvol + \
resampler_get_sample_float( resampler->fir_resampler[1] ) * rvol) * 16777216.0f; \
2013-09-28 00:24:23 -03:00
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 ); \
2013-09-28 00:24:23 -03:00
}
#define STEREO_DEST_PEEK_FIR { \
2017-09-17 01:37:49 -03:00
*dst++ = resampler_get_sample_float( resampler->fir_resampler[0] ) * lvol * 16777216.0f; \
*dst++ = resampler_get_sample_float( resampler->fir_resampler[1] ) * rvol * 16777216.0f; \
2013-09-28 00:24:23 -03:00
}
#define STEREO_DEST_MIX_FIR { \
2017-09-17 01:37:49 -03:00
*dst++ += resampler_get_sample_float( resampler->fir_resampler[0] ) * lvol * 16777216.0f; \
*dst++ += resampler_get_sample_float( resampler->fir_resampler[1] ) * rvol * 16777216.0f; \
2013-09-28 00:24:23 -03:00
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