summaryrefslogtreecommitdiff
path: root/plugins/dumb/dumb-kode54/src/helpers/resamp3.inc
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/dumb/dumb-kode54/src/helpers/resamp3.inc')
-rw-r--r--plugins/dumb/dumb-kode54/src/helpers/resamp3.inc376
1 files changed, 376 insertions, 0 deletions
diff --git a/plugins/dumb/dumb-kode54/src/helpers/resamp3.inc b/plugins/dumb/dumb-kode54/src/helpers/resamp3.inc
new file mode 100644
index 00000000..0c13f201
--- /dev/null
+++ b/plugins/dumb/dumb-kode54/src/helpers/resamp3.inc
@@ -0,0 +1,376 @@
+/* _______ ____ __ ___ ___
+ * \ _ \ \ / \ / \ \ / / ' ' '
+ * | | \ \ | | || | \/ | . .
+ * | | | | | | || ||\ /| |
+ * | | | | | | || || \/ | | ' ' '
+ * | | | | | | || || | | . .
+ * | |_/ / \ \__// || | |
+ * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
+ * / \
+ * / . \
+ * resamp3.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.
+ */
+
+
+
+long dumb_resample(DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, VOLUME_PARAMETERS, float delta)
+{
+ int dt;
+ int VOLUME_VARIABLES;
+ long done;
+ long todo;
+ LONG_LONG todo64;
+ int quality;
+
+ if (!resampler || resampler->dir == 0) return 0;
+ ASSERT(resampler->dir == -1 || resampler->dir == 1);
+
+ done = 0;
+ dt = (int)(delta * 65536.0 + 0.5);
+ if (dt == 0) return 0;
+ SET_VOLUME_VARIABLES;
+
+ if (VOLUMES_ARE_ZERO) dst = NULL;
+
+ init_cubic();
+
+ quality = resampler->quality;
+
+ while (done < dst_size) {
+ if (process_pickup(resampler)) {
+ RETURN_VOLUME_VARIABLES;
+ return done;
+ }
+
+ if ((resampler->dir ^ dt) < 0)
+ dt = -dt;
+
+ if (resampler->dir < 0)
+ todo64 = ((((LONG_LONG)(resampler->pos - resampler->start) << 16) + resampler->subpos - dt) / -dt);
+ else
+ todo64 = ((((LONG_LONG)(resampler->end - resampler->pos) << 16) - resampler->subpos - 1 + dt) / dt);
+
+ if (todo64 < 0)
+ todo = 0;
+ else if (todo64 > dst_size - done)
+ todo = dst_size - done;
+ else
+ todo = (long) todo64;
+
+ done += todo;
+
+ {
+ SRCTYPE *src = resampler->src;
+ long pos = resampler->pos;
+ int subpos = resampler->subpos;
+ long diff = pos;
+ long overshot;
+ if (resampler->dir < 0) {
+ if (!dst) {
+ /* Silence or simulation */
+ LONG_LONG new_subpos = subpos + (LONG_LONG)dt * todo;
+ pos += (long)(new_subpos >> 16);
+ subpos = (long)new_subpos & 65535;
+ } else if (quality <= DUMB_RQ_ALIASING) {
+ /* Aliasing, backwards */
+ SRCTYPE xbuf[2*SRC_CHANNELS];
+ SRCTYPE *x = &xbuf[0];
+ SRCTYPE *xstart;
+ COPYSRC(xbuf, 0, resampler->X, 1);
+ COPYSRC(xbuf, 1, resampler->X, 2);
+ while (todo && x < &xbuf[2*SRC_CHANNELS]) {
+ // TODO: check what happens when multiple tempo slides occur per row
+ HEAVYASSERT(pos >= resampler->start);
+ MIX_ALIAS(+=, 1, 0);
+ subpos += dt;
+ pos += subpos >> 16;
+ x -= (subpos >> 16) * SRC_CHANNELS;
+ subpos &= 65535;
+ todo--;
+ }
+ x = xstart = &src[pos*SRC_CHANNELS];
+ LOOP4(todo,
+ MIX_ALIAS(+=, 1, 2);
+ subpos += dt;
+ x += (subpos >> 16) * SRC_CHANNELS;
+ subpos &= 65535;
+ );
+ pos += DIVIDE_BY_SRC_CHANNELS(x - xstart);
+ } else if (quality <= DUMB_RQ_LINEAR) {
+ /* Linear interpolation, backwards */
+ SRCTYPE xbuf[3*SRC_CHANNELS];
+ SRCTYPE *x = &xbuf[1*SRC_CHANNELS];
+ COPYSRC(xbuf, 0, resampler->X, 1);
+ COPYSRC(xbuf, 1, resampler->X, 2);
+ COPYSRC(xbuf, 2, src, pos);
+ while (todo && x < &xbuf[3*SRC_CHANNELS]) {
+ HEAVYASSERT(pos >= resampler->start);
+ MIX_LINEAR(+=, 1, 0, -1);
+ subpos += dt;
+ pos += subpos >> 16;
+ x -= (subpos >> 16) * SRC_CHANNELS;
+ subpos &= 65535;
+ todo--;
+ }
+ // TODO: use xstart for others too
+ x = &src[pos*SRC_CHANNELS];
+ LOOP4(todo,
+ HEAVYASSERT(pos >= resampler->start);
+ MIX_LINEAR(+=, 1, 1, 2);
+ subpos += dt;
+ pos += subpos >> 16;
+ x += (subpos >> 16) * SRC_CHANNELS;
+ subpos &= 65535;
+ );
+ } else {
+ /* Cubic interpolation, backwards */
+ SRCTYPE xbuf[6*SRC_CHANNELS];
+ SRCTYPE *x = &xbuf[3*SRC_CHANNELS];
+ COPYSRC(xbuf, 0, resampler->X, 0);
+ COPYSRC(xbuf, 1, resampler->X, 1);
+ COPYSRC(xbuf, 2, resampler->X, 2);
+ COPYSRC(xbuf, 3, src, pos);
+ if (pos-1 >= resampler->start) COPYSRC(xbuf, 4, src, pos-1);
+ if (pos-2 >= resampler->start) COPYSRC(xbuf, 5, src, pos-2);
+ while (todo && x < &xbuf[6*SRC_CHANNELS]) {
+ HEAVYASSERT(pos >= resampler->start);
+ MIX_CUBIC(+=, 1, x, x, 0, -1, -2, -3);
+ subpos += dt;
+ pos += subpos >> 16;
+ x -= (subpos >> 16) * SRC_CHANNELS;
+ subpos &= 65535;
+ todo--;
+ }
+ x = &src[pos*SRC_CHANNELS];
+ LOOP4(todo,
+ HEAVYASSERT(pos >= resampler->start);
+ MIX_CUBIC(+=, 1, x, x, 0, 1, 2, 3);
+ subpos += dt;
+ pos += subpos >> 16;
+ x += (subpos >> 16) * SRC_CHANNELS;
+ subpos &= 65535;
+ );
+ }
+ diff = diff - pos;
+ overshot = resampler->start - pos - 1;
+ if (diff >= 3) {
+ COPYSRC2(resampler->X, 0, overshot < 3, src, pos+3);
+ COPYSRC2(resampler->X, 1, overshot < 2, src, pos+2);
+ COPYSRC2(resampler->X, 2, overshot < 1, src, pos+1);
+ } else if (diff >= 2) {
+ COPYSRC(resampler->X, 0, resampler->X, 2);
+ COPYSRC2(resampler->X, 1, overshot < 2, src, pos+2);
+ COPYSRC2(resampler->X, 2, overshot < 1, src, pos+1);
+ } else if (diff >= 1) {
+ COPYSRC(resampler->X, 0, resampler->X, 1);
+ COPYSRC(resampler->X, 1, resampler->X, 2);
+ COPYSRC2(resampler->X, 2, overshot < 1, src, pos+1);
+ }
+ } else {
+ if (!dst) {
+ /* Silence or simulation */
+ LONG_LONG new_subpos = subpos + (LONG_LONG)dt * todo;
+ pos += (long)(new_subpos >> 16);
+ subpos = (long)new_subpos & 65535;
+ } else if (quality <= DUMB_RQ_ALIASING) {
+ /* Aliasing, forwards */
+ SRCTYPE xbuf[2*SRC_CHANNELS];
+ SRCTYPE *x = &xbuf[0];
+ SRCTYPE *xstart;
+ COPYSRC(xbuf, 0, resampler->X, 1);
+ COPYSRC(xbuf, 1, resampler->X, 2);
+ while (todo && x < &xbuf[2*SRC_CHANNELS]) {
+ HEAVYASSERT(pos < resampler->end);
+ MIX_ALIAS(+=, 1, 0);
+ subpos += dt;
+ pos += subpos >> 16;
+ x += (subpos >> 16) * SRC_CHANNELS;
+ subpos &= 65535;
+ todo--;
+ }
+ x = xstart = &src[pos*SRC_CHANNELS];
+ LOOP4(todo,
+ MIX_ALIAS(+=, 1, -2);
+ subpos += dt;
+ x += (subpos >> 16) * SRC_CHANNELS;
+ subpos &= 65535;
+ );
+ pos += DIVIDE_BY_SRC_CHANNELS(x - xstart);
+ } else if (quality <= DUMB_RQ_LINEAR) {
+ /* Linear interpolation, forwards */
+ SRCTYPE xbuf[3*SRC_CHANNELS];
+ SRCTYPE *x = &xbuf[1*SRC_CHANNELS];
+ COPYSRC(xbuf, 0, resampler->X, 1);
+ COPYSRC(xbuf, 1, resampler->X, 2);
+ COPYSRC(xbuf, 2, src, pos);
+ while (todo && x < &xbuf[3*SRC_CHANNELS]) {
+ HEAVYASSERT(pos < resampler->end);
+ MIX_LINEAR(+=, 1, -1, 0);
+ subpos += dt;
+ pos += subpos >> 16;
+ x += (subpos >> 16) * SRC_CHANNELS;
+ subpos &= 65535;
+ todo--;
+ }
+ x = &src[pos*SRC_CHANNELS];
+ LOOP4(todo,
+ HEAVYASSERT(pos < resampler->end);
+ MIX_LINEAR(+=, 1, -2, -1);
+ subpos += dt;
+ pos += subpos >> 16;
+ x += (subpos >> 16) * SRC_CHANNELS;
+ subpos &= 65535;
+ );
+ } else {
+ /* Cubic interpolation, forwards */
+ SRCTYPE xbuf[6*SRC_CHANNELS];
+ SRCTYPE *x = &xbuf[3*SRC_CHANNELS];
+ COPYSRC(xbuf, 0, resampler->X, 0);
+ COPYSRC(xbuf, 1, resampler->X, 1);
+ COPYSRC(xbuf, 2, resampler->X, 2);
+ COPYSRC(xbuf, 3, src, pos);
+ if (pos+1 < resampler->end) COPYSRC(xbuf, 4, src, pos+1);
+ if (pos+2 < resampler->end) COPYSRC(xbuf, 5, src, pos+2);
+ while (todo && x < &xbuf[6*SRC_CHANNELS]) {
+ HEAVYASSERT(pos < resampler->end);
+ MIX_CUBIC(+=, 1, x, x, -3, -2, -1, 0);
+ subpos += dt;
+ pos += subpos >> 16;
+ x += (subpos >> 16) * SRC_CHANNELS;
+ subpos &= 65535;
+ todo--;
+ }
+ x = &src[pos*SRC_CHANNELS];
+ LOOP4(todo,
+ HEAVYASSERT(pos < resampler->end);
+ MIX_CUBIC(+=, 1, x, x, -3, -2, -1, 0);
+ subpos += dt;
+ pos += subpos >> 16;
+ x += (subpos >> 16) * SRC_CHANNELS;
+ subpos &= 65535;
+ );
+ }
+ diff = pos - diff;
+ overshot = pos - resampler->end;
+ if (diff >= 3) {
+ COPYSRC2(resampler->X, 0, overshot < 3, src, pos-3);
+ COPYSRC2(resampler->X, 1, overshot < 2, src, pos-2);
+ COPYSRC2(resampler->X, 2, overshot < 1, src, pos-1);
+ } else if (diff >= 2) {
+ COPYSRC(resampler->X, 0, resampler->X, 2);
+ COPYSRC2(resampler->X, 1, overshot < 2, src, pos-2);
+ COPYSRC2(resampler->X, 2, overshot < 1, src, pos-1);
+ } else if (diff >= 1) {
+ COPYSRC(resampler->X, 0, resampler->X, 1);
+ COPYSRC(resampler->X, 1, resampler->X, 2);
+ COPYSRC2(resampler->X, 2, overshot < 1, src, pos-1);
+ }
+ }
+ resampler->pos = pos;
+ resampler->subpos = subpos;
+ }
+ }
+
+ RETURN_VOLUME_VARIABLES;
+ return done;
+}
+
+
+
+void dumb_resample_get_current_sample(DUMB_RESAMPLER *resampler, VOLUME_PARAMETERS, sample_t *dst)
+{
+ int VOLUME_VARIABLES;
+ SRCTYPE *src;
+ long pos;
+ int subpos;
+ int quality;
+ SRCTYPE *x;
+
+ if (!resampler || resampler->dir == 0) { MIX_ZEROS(=); return; }
+ ASSERT(resampler->dir == -1 || resampler->dir == 1);
+
+ if (process_pickup(resampler)) { MIX_ZEROS(=); return; }
+
+ SET_VOLUME_VARIABLES;
+
+ if (VOLUMES_ARE_ZERO) { MIX_ZEROS(=); return; }
+
+ init_cubic();
+
+ quality = resampler->quality;
+
+ src = resampler->src;
+ pos = resampler->pos;
+ subpos = resampler->subpos;
+ x = resampler->X;
+
+ if (resampler->dir < 0) {
+ HEAVYASSERT(pos >= resampler->start);
+ if (dumb_resampling_quality <= DUMB_RQ_ALIASING) {
+ /* Aliasing, backwards */
+ MIX_ALIAS(=, 0, 1);
+ } else if (quality <= DUMB_RQ_LINEAR) {
+ /* Linear interpolation, backwards */
+ MIX_LINEAR(=, 0, 2, 1);
+ } else {
+ /* Cubic interpolation, backwards */
+ MIX_CUBIC(=, 0, src, x, pos, 2, 1, 0);
+ }
+ } else {
+ HEAVYASSERT(pos < resampler->end);
+ if (dumb_resampling_quality <= DUMB_RQ_ALIASING) {
+ /* Aliasing */
+ MIX_ALIAS(=, 0, 1);
+ } else if (dumb_resampling_quality <= DUMB_RQ_LINEAR) {
+ /* Linear interpolation, forwards */
+ MIX_LINEAR(=, 0, 1, 2);
+ } else {
+ /* Cubic interpolation, forwards */
+ MIX_CUBIC(=, 0, x, src, 0, 1, 2, pos);
+ }
+ }
+}
+
+
+
+#undef MIX_ZEROS
+#undef MIX_CUBIC
+#undef MIX_LINEAR
+#undef MIX_ALIAS
+#undef VOLUMES_ARE_ZERO
+#undef SET_VOLUME_VARIABLES
+#undef RETURN_VOLUME_VARIABLES
+#undef VOLUME_VARIABLES
+#undef VOLUME_PARAMETERS
+#undef SUFFIX3