shithub: dumb

Download patch

ref: 9db1273c6431216946c2c30e71e2c90859635744
parent: b844f7ce65c15ee70426640de1802ba97d409dec
author: Chris Moeller <kode54@gmail.com>
date: Mon Jan 11 03:58:43 EST 2010

{10/13/2005 2:19:30 AM~10/13/2005 2:22:22 AM}

git-tfs-id: [http://localhost:8080/tfs/DefaultCollection/]$/foobar2000/files/plugins.root;C22

--- /dev/null
+++ b/dumb/src/helpers/resample.inc
@@ -1,0 +1,559 @@
+/*  _______         ____    __         ___    ___
+ * \    _  \       \    /  \  /       \   \  /   /       '   '  '
+ *  |  | \  \       |  |    ||         |   \/   |         .      .
+ *  |  |  |  |      |  |    ||         ||\  /|  |
+ *  |  |  |  |      |  |    ||         || \/ |  |         '  '  '
+ *  |  |  |  |      |  |    ||         ||    |  |         .      .
+ *  |  |_/  /        \  \__//          ||    |  |
+ * /_______/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.
+ */
+
+#include <math.h>
+#include "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
+
+
+
+//#define MULSC(a, b) ((int)((LONG_LONG)(a) * (b) >> 16))
+//#define MULSC(a, b) ((a) * ((b) >> 2) >> 14)
+#define MULSC(a, b) ((int)((LONG_LONG)((a) << 4) * ((b) << 12) >> 32))
+
+
+
+void dumb_reset_resampler(DUMB_RESAMPLER *resampler, SRCTYPE *src, long pos, long start, long end, int quality)
+{
+	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;
+	}
+	resampler->X[2] = resampler->X[1] = resampler->X[0] = 0;
+	resampler->overshot = -1;
+}
+
+
+
+DUMB_RESAMPLER *dumb_start_resampler(SRCTYPE *src, long pos, long start, long end, int quality)
+{
+	DUMB_RESAMPLER *resampler = malloc(sizeof(*resampler));
+	if (!resampler) return NULL;
+	dumb_reset_resampler(resampler, src, pos, start, end, quality);
+	return resampler;
+}
+
+
+
+/* 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, 0, 0, 0, 0, 1.0f);
+		resampler->X[0] = resampler->X[1];
+	}
+
+	for (;;) {
+		SRCTYPE *src = resampler->src;
+
+		if (resampler->dir < 0) {
+			if (resampler->overshot >= 3 && resampler->pos+3 >= resampler->start) resampler->X[0] = src[resampler->pos+3];
+			if (resampler->overshot >= 2 && resampler->pos+2 >= resampler->start) resampler->X[1] = src[resampler->pos+2];
+			if (resampler->overshot >= 1 && resampler->pos+1 >= resampler->start) resampler->X[2] = src[resampler->pos+1];
+			resampler->overshot = resampler->start - resampler->pos - 1;
+		} else {
+			if (resampler->overshot >= 3 && resampler->pos-3 < resampler->end) resampler->X[0] = src[resampler->pos-3];
+			if (resampler->overshot >= 2 && resampler->pos-2 < resampler->end) resampler->X[1] = src[resampler->pos-2];
+			if (resampler->overshot >= 1 && resampler->pos-1 < resampler->end) resampler->X[2] = src[resampler->pos-1];
+			resampler->overshot = 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);
+	}
+}
+
+
+
+/* Executes the content 'iterator' times.
+ * Clobbers the 'iterator' variable.
+ * The loop is unrolled by four.
+ */
+#define LOOP4(iterator, CONTENT) \
+{ \
+	if ((iterator) & 2) { \
+		CONTENT; \
+		CONTENT; \
+	} \
+	if ((iterator) & 1) { \
+		CONTENT; \
+	} \
+	(iterator) >>= 2; \
+	while (iterator) { \
+		CONTENT; \
+		CONTENT; \
+		CONTENT; \
+		CONTENT; \
+		(iterator)--; \
+	} \
+}
+
+#define UPDATE_VOLUME                                              \
+	if (volume) {                                                  \
+		if (volume_delta < 0) {                                    \
+			if (volume_target - *volume > volume_delta) {          \
+				*volume = volume_target;                           \
+				volume = NULL;                                     \
+				vol = (int)(volume_target * volume_mix * 65536.0 + 0.5);        \
+			} else {                                               \
+				*volume += volume_delta;                           \
+				vol = (int)(*volume * volume_mix * 65536.0 + 0.5);              \
+			}                                                      \
+		} else {                                                   \
+			if (volume_target - *volume < volume_delta) {          \
+				*volume = volume_target;                           \
+				volume = NULL;                                     \
+				vol = (int)(volume_target * volume_mix * 65536.0 + 0.5);        \
+			} else {                                               \
+				*volume += volume_delta;                           \
+				vol = (int)(*volume * volume_mix * 65536.0 + 0.5);              \
+			}                                                      \
+		}                                                          \
+	}
+
+long dumb_resample(DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, float * volume, float volume_delta, float volume_target, float volume_mix, float delta)
+{
+	int dt;
+	int vol;
+	long done;
+	long todo;
+	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 (volume) {
+		vol = (int)(*volume * volume_mix * 65536.0 + 0.5);
+		if (*volume == volume_target) volume = NULL;
+	}
+	else vol = 0;
+
+	if (vol == 0 && volume_target == 0) dst = NULL;
+
+	init_cubic();
+
+	quality = resampler->quality;
+
+	while (done < dst_size) {
+		if (process_pickup(resampler)) return done;
+
+		if ((resampler->dir ^ dt) < 0)
+			dt = -dt;
+
+		if (!dt)
+			todo = 0;
+		else if (resampler->dir < 0)
+			todo = (long)((((LONG_LONG)(resampler->pos - resampler->start) << 16) + resampler->subpos - dt) / -dt);
+		else
+			todo = (long)((((LONG_LONG)(resampler->end - resampler->pos) << 16) - resampler->subpos - 1 + dt) / dt);
+
+		if ((todo <= 0) ||
+			(todo > dst_size - done))
+			todo = dst_size - done;
+
+		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];
+					SRCTYPE *x = &xbuf[0];
+					SRCTYPE *xstart;
+					xbuf[0] = resampler->X[1];
+					xbuf[1] = resampler->X[2];
+					while (todo && x < &xbuf[2]) {
+						HEAVYASSERT(pos >= resampler->start);
+						*dst++ += ALIAS(x[0]);
+						subpos += dt;
+						pos += subpos >> 16;
+						x -= subpos >> 16;
+						subpos &= 65535;
+						todo--;
+						UPDATE_VOLUME;
+					}
+					x = xstart = &src[pos];
+					LOOP4(todo,
+						*dst++ += ALIAS(x[2]);
+						subpos += dt;
+						x += subpos >> 16;
+						subpos &= 65535;
+						UPDATE_VOLUME;
+					);
+					pos += x - xstart;
+				} else if (quality <= DUMB_RQ_LINEAR) {
+					/* Linear interpolation, backwards */
+					SRCTYPE xbuf[3];
+					SRCTYPE *x = &xbuf[1];
+					xbuf[0] = resampler->X[1];
+					xbuf[1] = resampler->X[2];
+					xbuf[2] = src[pos];
+					while (todo && x < &xbuf[3]) {
+						HEAVYASSERT(pos >= resampler->start);
+						*dst++ += LINEAR(x[0], x[-1]);
+						subpos += dt;
+						pos += subpos >> 16;
+						x -= subpos >> 16;
+						subpos &= 65535;
+						todo--;
+						UPDATE_VOLUME;
+					}
+					x = &src[pos];
+					LOOP4(todo,
+						HEAVYASSERT(pos >= resampler->start);
+						*dst++ += LINEAR(x[1], x[2]);
+						subpos += dt;
+						pos += subpos >> 16;
+						x += subpos >> 16;
+						subpos &= 65535;
+						UPDATE_VOLUME;
+					);
+				} else {
+					/* Cubic interpolation, backwards */
+					SRCTYPE xbuf[6];
+					SRCTYPE *x = &xbuf[3];
+					//SRCTYPE *lastx = NULL;
+					//int a = 0, b = 0, c = 0;
+					xbuf[0] = resampler->X[0];
+					xbuf[1] = resampler->X[1];
+					xbuf[2] = resampler->X[2];
+					xbuf[3] = src[pos];
+					if (pos-1 >= resampler->start) xbuf[4] = src[pos-1];
+					if (pos-2 >= resampler->start) xbuf[5] = src[pos-2];
+					while (todo && x < &xbuf[6]) {
+						HEAVYASSERT(pos >= resampler->start);
+						//if (lastx != x) {
+						//	lastx = x;
+						//	SET_CUBIC_COEFFICIENTS(x[0], x[-1], x[-2], x[-3]);
+						//}
+						*dst++ += CUBIC(x[0], x[-1], x[-2], x[-3]);
+						subpos += dt;
+						pos += subpos >> 16;
+						x -= subpos >> 16;
+						subpos &= 65535;
+						todo--;
+						UPDATE_VOLUME;
+					}
+					x = &src[pos];
+					//lastx = NULL;
+					LOOP4(todo,
+						HEAVYASSERT(pos >= resampler->start);
+						//if (lastx != x) {
+						//	lastx = x;
+						//	SET_CUBIC_COEFFICIENTS(x[0], x[1], x[2], x[3]);
+						//}
+						*dst++ += CUBIC(x[0], x[1], x[2], x[3]);
+						subpos += dt;
+						pos += subpos >> 16;
+						x += subpos >> 16;
+						subpos &= 65535;
+						UPDATE_VOLUME;
+					);
+				}
+				diff = diff - pos;
+				overshot = resampler->start - pos - 1;
+				if (diff >= 3) {
+					resampler->X[0] = overshot >= 3 ? 0 : src[pos+3];
+					resampler->X[1] = overshot >= 2 ? 0 : src[pos+2];
+					resampler->X[2] = overshot >= 1 ? 0 : src[pos+1];
+				} else if (diff >= 2) {
+					resampler->X[0] = resampler->X[2];
+					resampler->X[1] = overshot >= 2 ? 0 : src[pos+2];
+					resampler->X[2] = overshot >= 1 ? 0 : src[pos+1];
+				} else if (diff >= 1) {
+					resampler->X[0] = resampler->X[1];
+					resampler->X[1] = resampler->X[2];
+					resampler->X[2] = overshot >= 1 ? 0 : 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];
+					SRCTYPE *x = &xbuf[0];
+					SRCTYPE *xstart;
+					xbuf[0] = resampler->X[1];
+					xbuf[1] = resampler->X[2];
+					while (todo && x < &xbuf[2]) {
+						HEAVYASSERT(pos < resampler->end);
+						*dst++ += ALIAS(x[0]);
+						subpos += dt;
+						pos += subpos >> 16;
+						x += subpos >> 16;
+						subpos &= 65535;
+						todo--;
+						UPDATE_VOLUME;
+					}
+					x = xstart = &src[pos];
+					LOOP4(todo,
+						*dst++ += ALIAS(x[-2]);
+						subpos += dt;
+						x += subpos >> 16;
+						subpos &= 65535;
+						UPDATE_VOLUME;
+					);
+					pos += x - xstart;
+				} else if (quality <= DUMB_RQ_LINEAR) {
+					/* Linear interpolation, forwards */
+					SRCTYPE xbuf[3];
+					SRCTYPE *x = &xbuf[1];
+					xbuf[0] = resampler->X[1];
+					xbuf[1] = resampler->X[2];
+					xbuf[2] = src[pos];
+					while (todo && x < &xbuf[3]) {
+						HEAVYASSERT(pos < resampler->end);
+						*dst++ += LINEAR(x[-1], x[0]);
+						subpos += dt;
+						pos += subpos >> 16;
+						x += subpos >> 16;
+						subpos &= 65535;
+						todo--;
+						UPDATE_VOLUME;
+					}
+					x = &src[pos];
+					LOOP4(todo,
+						HEAVYASSERT(pos < resampler->end);
+						*dst++ += LINEAR(x[-2], x[-1]);
+						subpos += dt;
+						pos += subpos >> 16;
+						x += subpos >> 16;
+						subpos &= 65535;
+						UPDATE_VOLUME;
+					);
+				} else {
+					/* Cubic interpolation, forwards */
+					SRCTYPE xbuf[6];
+					SRCTYPE *x = &xbuf[3];
+					//SRCTYPE *lastx = NULL;
+					//int a = 0, b = 0, c = 0;
+					xbuf[0] = resampler->X[0];
+					xbuf[1] = resampler->X[1];
+					xbuf[2] = resampler->X[2];
+					xbuf[3] = src[pos];
+					if (pos+1 < resampler->end) xbuf[4] = src[pos+1];
+					if (pos+2 < resampler->end) xbuf[5] = src[pos+2];
+					while (todo && x < &xbuf[6]) {
+						HEAVYASSERT(pos < resampler->end);
+						//if (lastx != x) {
+						//	lastx = x;
+						//	SET_CUBIC_COEFFICIENTS(x[-3], x[-2], x[-1], x[0]);
+						//}
+						*dst++ += CUBIC(x[-3], x[-2], x[-1], x[0]);
+						subpos += dt;
+						pos += subpos >> 16;
+						x += subpos >> 16;
+						subpos &= 65535;
+						todo--;
+						UPDATE_VOLUME;
+					}
+					x = &src[pos];
+					//lastx = NULL;
+					LOOP4(todo,
+						HEAVYASSERT(pos < resampler->end);
+						//if (lastx != x) {
+						//	lastx = x;
+						//	SET_CUBIC_COEFFICIENTS(x[-3], x[-2], x[-1], x[0]);
+						//}
+						*dst++ += CUBIC(x[-3], x[-2], x[-1], x[0]);
+						subpos += dt;
+						pos += subpos >> 16;
+						x += subpos >> 16;
+						subpos &= 65535;
+						UPDATE_VOLUME;
+					);
+				}
+				diff = pos - diff;
+				overshot = pos - resampler->end;
+				if (diff >= 3) {
+					resampler->X[0] = overshot >= 3 ? 0 : src[pos-3];
+					resampler->X[1] = overshot >= 2 ? 0 : src[pos-2];
+					resampler->X[2] = overshot >= 1 ? 0 : src[pos-1];
+				} else if (diff >= 2) {
+					resampler->X[0] = resampler->X[2];
+					resampler->X[1] = overshot >= 2 ? 0 : src[pos-2];
+					resampler->X[2] = overshot >= 1 ? 0 : src[pos-1];
+				} else if (diff >= 1) {
+					resampler->X[0] = resampler->X[1];
+					resampler->X[1] = resampler->X[2];
+					resampler->X[2] = overshot >= 1 ? 0 : src[pos-1];
+				}
+			}
+			resampler->pos = pos;
+			resampler->subpos = subpos;
+		}
+	}
+
+	return done;
+}
+
+
+
+sample_t dumb_resample_get_current_sample(DUMB_RESAMPLER *resampler, float volume)
+{
+	int vol;
+	SRCTYPE *src;
+	long pos;
+	int subpos;
+	int quality;
+
+	if (!resampler || resampler->dir == 0) return 0;
+	ASSERT(resampler->dir == -1 || resampler->dir == 1);
+
+	if (process_pickup(resampler)) return 0;
+
+	vol = (int)floor(volume * 65536.0 + 0.5);
+	if (vol == 0) return 0;
+
+	init_cubic();
+
+	quality = resampler->quality;
+
+	src = resampler->src;
+	pos = resampler->pos;
+	subpos = resampler->subpos;
+
+	if (resampler->dir < 0) {
+		HEAVYASSERT(pos >= resampler->start);
+		if (quality <= DUMB_RQ_ALIASING) {
+			/* Aliasing, backwards */
+			return ALIAS(src[pos]);
+		} else if (quality <= DUMB_RQ_LINEAR) {
+			/* Linear interpolation, backwards */
+			return LINEAR(resampler->X[2], resampler->X[1]);
+		} else {
+			/* Cubic interpolation, backwards */
+			SRCTYPE *x = resampler->X;
+			//int a, b, c;
+			//SET_CUBIC_COEFFICIENTS(src[pos], x[2], x[1], x[0]);
+			return CUBIC(src[pos], x[2], x[1], x[0]);
+		}
+	} else {
+		HEAVYASSERT(pos < resampler->end);
+		if (quality <= DUMB_RQ_ALIASING) {
+			/* Aliasing */
+			return ALIAS(src[pos]);
+		} else if (quality <= DUMB_RQ_LINEAR) {
+			/* Linear interpolation, forwards */
+			return LINEAR(resampler->X[1], resampler->X[2]);
+		} else {
+			/* Cubic interpolation, forwards */
+			SRCTYPE *x = resampler->X;
+			//int a, b, c;
+			//SET_CUBIC_COEFFICIENTS(x[0], x[1], x[2], src[pos]);
+			return CUBIC(x[0], x[1], x[2], src[pos]);
+		}
+	}
+}
+
+
+
+void dumb_end_resampler(DUMB_RESAMPLER *resampler)
+{
+	if (resampler)
+		free(resampler);
+}
+
+
+
+#undef CUBIC
+//#undef SET_CUBIC_COEFFICIENTS
+#undef LINEAR
+#undef ALIAS
+#undef SRCBITS
+#undef SRCTYPE
+#undef SUFFIX
--- a/dumb/vc6/dumb/dumb.vcproj
+++ b/dumb/vc6/dumb/dumb.vcproj
@@ -814,6 +814,34 @@
 					</FileConfiguration>
 				</File>
 				<File
+					RelativePath="..\..\src\helpers\resample.inc"
+					>
+					<FileConfiguration
+						Name="Release|Win32"
+						ExcludedFromBuild="true"
+						>
+						<Tool
+							Name="VCCustomBuildTool"
+						/>
+					</FileConfiguration>
+					<FileConfiguration
+						Name="Debug|Win32"
+						ExcludedFromBuild="true"
+						>
+						<Tool
+							Name="VCCustomBuildTool"
+						/>
+					</FileConfiguration>
+					<FileConfiguration
+						Name="Release staticlink|Win32"
+						ExcludedFromBuild="true"
+						>
+						<Tool
+							Name="VCCustomBuildTool"
+						/>
+					</FileConfiguration>
+				</File>
+				<File
 					RelativePath="..\..\src\helpers\sampbuf.c"
 					>
 					<FileConfiguration