Added Sinc resampler to SNSF plugin, as well as fixed issue with there being garbage at the start of an SNSF when played after one has finished.
Added Sinc resampler to SNSF plugin, as well as fixed issue with there being garbage at the start of an SNSF when played after one has finished.

--- a/src/in_snsf/XSFConfig_SNSF.cpp
+++ b/src/in_snsf/XSFConfig_SNSF.cpp
@@ -1,7 +1,7 @@
 /*
  * xSF - SNSF configuration
  * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
- * Last modification on 2013-04-12
+ * Last modification on 2013-05-08
  *
  * Partially based on the vio*sf framework
  *
@@ -98,6 +98,7 @@
 			SendMessageW(GetDlgItem(hwndDlg, idResampler), CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(L"Hermite Resampler"));
 			SendMessageW(GetDlgItem(hwndDlg, idResampler), CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(L"Bspline Resampler"));
 			SendMessageW(GetDlgItem(hwndDlg, idResampler), CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(L"Osculating Resampler"));
+			SendMessageW(GetDlgItem(hwndDlg, idResampler), CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(L"Sinc Resampler"));
 			SendMessageW(GetDlgItem(hwndDlg, idResampler), CB_SETCURSEL, this->resampler, 0);
 			// Mutes
 			for (int x = 0, numMutes = this->mutes.size(); x < numMutes; ++x)

--- a/src/in_snsf/XSFPlayer_SNSF.cpp
+++ b/src/in_snsf/XSFPlayer_SNSF.cpp
@@ -1,7 +1,7 @@
 /*
  * xSF - SNSF Player
  * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
- * Last modification on 2013-04-23
+ * Last modification on 2013-05-08
  *
  * Based on a modified in_snsf by Caitsith2
  * http://snsf.caitsith2.net/
@@ -26,6 +26,7 @@
 #include "snes9x/apu/hermite_resampler.h"
 #include "snes9x/apu/bspline_resampler.h"
 #include "snes9x/apu/osculating_resampler.h"
+#include "snes9x/apu/sinc_resampler.h"
 #include "snes9x/memmap.h"
 
 class XSFPlayer_SNSF : public XSFPlayer
@@ -71,8 +72,11 @@
 	BUFFER() : buf(), fil(0), cur(0), len(0) { }
 	bool Init()
 	{
+		if (!this->buf.empty())
+			this->buf.clear();
 		this->len = 2 * 2 * 48000 / 5;
-		buf.resize(len);
+		this->buf.resize(len, 0);
+		this->fil = this->cur = 0;
 		return true;
 	}
 	void Fill()
@@ -230,9 +234,11 @@
 
 	S9xInitAPU();
 	XSFConfig_SNSF *xSFConfig_SNSF = dynamic_cast<XSFConfig_SNSF *>(xSFConfig);
-	if (xSFConfig_SNSF->resampler == 3)
+	if (xSFConfig_SNSF->resampler == 4)
+		S9xInitSound<SincResampler>(10, 0);
+	else if (xSFConfig_SNSF->resampler == 3)
 		S9xInitSound<OsculatingResampler>(10, 0);
-	if (xSFConfig_SNSF->resampler == 2)
+	else if (xSFConfig_SNSF->resampler == 2)
 		S9xInitSound<BsplineResampler>(10, 0);
 	else if (xSFConfig_SNSF->resampler == 1)
 		S9xInitSound<HermiteResampler>(10, 0);

--- a/src/in_snsf/snes9x/apu/apu.cpp
+++ b/src/in_snsf/snes9x/apu/apu.cpp
@@ -184,6 +184,10 @@
 #include "hermite_resampler.h"
 #include "bspline_resampler.h"
 #include "osculating_resampler.h"
+#include "sinc_resampler.h"
+
+bool SincResampler::initializedLUTs = false;
+double SincResampler::sinc_lut[SincResampler::SINC_SAMPLES + 1];
 
 #define APU_DEFAULT_INPUT_RATE		32000
 #define APU_MINIMUM_SAMPLE_COUNT	512
@@ -479,6 +483,7 @@
 template bool S9xInitSound<HermiteResampler>(int, int);
 template bool S9xInitSound<BsplineResampler>(int, int);
 template bool S9xInitSound<OsculatingResampler>(int, int);
+template bool S9xInitSound<SincResampler>(int, int);
 
 void S9xSetSoundControl (uint8_t voice_switch)
 {

--- a/src/in_snsf/snes9x/apu/bspline_resampler.h
+++ b/src/in_snsf/snes9x/apu/bspline_resampler.h
@@ -8,8 +8,6 @@
 
 #undef CLAMP
 #undef SHORT_CLAMP
-template<typename T1, typename T2> static inline T1 CLAMP(T1 x, T2 low, T2 high) { return x > high ? high : (x < low ? low : x); }
-template<typename T> static inline short SHORT_CLAMP(T n) { return static_cast<short>(CLAMP(n, -32768, 32767)); }
 
 class BsplineResampler : public Resampler
 {
@@ -17,6 +15,9 @@
 	double r_step;
 	double r_frac;
 	int r_left[6], r_right[6];
+
+	template<typename T1, typename T2> static T1 CLAMP(T1 x, T2 low, T2 high) { return x > high ? high : (x < low ? low : x); }
+	template<typename T> static short SHORT_CLAMP(T n) { return static_cast<short>(CLAMP(n, -32768, 32767)); }
 
 	double bspline(double x, double a, double b, double c, double d, double e, double f)
 	{

--- a/src/in_snsf/snes9x/apu/osculating_resampler.h
+++ b/src/in_snsf/snes9x/apu/osculating_resampler.h
@@ -8,8 +8,6 @@
 
 #undef CLAMP
 #undef SHORT_CLAMP
-//template<typename T1, typename T2> static inline T1 CLAMP(T1 x, T2 low, T2 high) { return x > high ? high : (x < low ? low : x); }
-//template<typename T> static inline short SHORT_CLAMP(T n) { return static_cast<short>(CLAMP(n, -32768, 32767)); }
 
 class OsculatingResampler : public Resampler
 {
@@ -17,6 +15,9 @@
 	double r_step;
 	double r_frac;
 	int r_left[6], r_right[6];
+
+	template<typename T1, typename T2> static T1 CLAMP(T1 x, T2 low, T2 high) { return x > high ? high : (x < low ? low : x); }
+	template<typename T> static short SHORT_CLAMP(T n) { return static_cast<short>(CLAMP(n, -32768, 32767)); }
 
 	double osculating(double x, double a, double b, double c, double d, double e, double f)
 	{

--- /dev/null
+++ b/src/in_snsf/snes9x/apu/sinc_resampler.h
@@ -1,1 +1,159 @@
+/* Simple resampler based on bsnes's ruby audio library */
 
+#ifndef __SINC_RESAMPLER_H
+#define __SINC_RESAMPLER_H
+
+#include <algorithm>
+#define _USE_MATH_DEFINES
+#include <cmath>
+#include "resampler.h"
+
+#undef CLAMP
+#undef SHORT_CLAMP
+
+#ifndef M_PI
+const double M_PI = 3.14159265358979323846;
+#endif
+
+class SincResampler : public Resampler
+{
+protected:
+	static bool initializedLUTs;
+	static const unsigned SINC_RESOLUTION = 8192;
+	static const unsigned SINC_WIDTH = 8;
+	static const unsigned SINC_SAMPLES = SINC_RESOLUTION * SINC_WIDTH;
+	static double sinc_lut[SINC_SAMPLES + 1];
+
+	double r_step;
+	double r_frac;
+	int r_left[SINC_WIDTH * 2], r_right[SINC_WIDTH * 2];
+
+	template<typename T1, typename T2> static T1 CLAMP(T1 x, T2 low, T2 high) { return x > high ? high : (x < low ? low : x); }
+	template<typename T> static short SHORT_CLAMP(T n) { return static_cast<short>(CLAMP(n, -32768, 32767)); }
+
+	// Code from http://learningcppisfun.blogspot.com/2010/04/comparing-floating-point-numbers.html
+	template<typename T> static bool fEqual(T x, T y, int N = 1)
+	{
+		T diff = std::abs(x - y);
+		T tolerance = N * std::numeric_limits<T>::epsilon();
+		return diff <= tolerance * std::abs(x) && diff <= tolerance * std::abs(y);
+	}
+
+	static inline double sinc(double x)
+	{
+		return fEqual(x, 0.0) ? 1.0 : std::sin(x * M_PI) / (x * M_PI);
+	}
+
+	double sinc(const int *data)
+	{
+		double kernel[SINC_WIDTH * 2], kernel_sum = 0.0;
+		int i = SINC_WIDTH, shift = static_cast<int>(std::floor(this->r_frac * SINC_RESOLUTION));
+		int step = this->r_step > 1.0 ? static_cast<int>(SINC_RESOLUTION / this->r_step) : SINC_RESOLUTION;
+		int shift_adj = shift * step / SINC_RESOLUTION;
+		for (; i >= -static_cast<int>(SINC_WIDTH - 1); --i)
+		{
+			int pos = i * step;
+			kernel_sum += kernel[i + SINC_WIDTH - 1] = this->sinc_lut[std::abs(shift_adj - pos)];
+		}
+		double sum = 0.0;
+		for (i = 0; i < static_cast<int>(SINC_WIDTH * 2); ++i)
+			sum += data[i] * kernel[i];
+		return sum / kernel_sum;
+	}
+
+public:
+	SincResampler(int num_samples) : Resampler(num_samples)
+	{
+		if (!this->initializedLUTs)
+		{
+			double dx = static_cast<double>(SINC_WIDTH) / SINC_SAMPLES, x = 0.0;
+			for (unsigned i = 0; i <= SINC_SAMPLES; ++i, x += dx)
+				this->sinc_lut[i] = std::abs(x) < SINC_WIDTH ? sinc(x) * (0.5 * (1.0 + std::cos((M_PI * x) / SINC_WIDTH))) : 0.0;
+			this->initializedLUTs = true;
+		}
+		this->clear();
+	}
+
+	void time_ratio(double ratio)
+	{
+		this->r_step = ratio;
+		this->clear();
+	}
+
+	void clear()
+	{
+		ring_buffer::clear ();
+		this->r_frac = 1.0;
+		std::fill(&this->r_left[0], &this->r_left[SINC_WIDTH * 2], 0);
+		std::fill(&this->r_right[0], &this->r_right[SINC_WIDTH * 2], 0);
+	}
+
+	void read(short *data, int num_samples)
+	{
+		int i_position = this->start >> 1;
+		short *internal_buffer = reinterpret_cast<short *>(this->buffer);
+		int o_position = 0;
+		int consumed = 0;
+
+		while (o_position < num_samples && consumed < this->buffer_size)
+		{
+			int s_left = internal_buffer[i_position];
+			int s_right = internal_buffer[i_position + 1];
+			int max_samples = this->buffer_size >> 1;
+			const double margin_of_error = 1.0e-10;
+
+			if (std::abs(this->r_step - 1.0) < margin_of_error)
+			{
+				data[o_position] = static_cast<short>(s_left);
+				data[o_position + 1] = static_cast<short>(s_right);
+
+				o_position += 2;
+				i_position += 2;
+				if (i_position >= max_samples)
+					i_position -= max_samples;
+				consumed += 2;
+
+				continue;
+			}
+
+			while (this->r_frac <= 1.0 && o_position < num_samples)
+			{
+				data[o_position] = SHORT_CLAMP(sinc(this->r_left));
+				data[o_position + 1] = SHORT_CLAMP(sinc(this->r_right));
+
+				o_position += 2;
+
+				this->r_frac += this->r_step;
+			}
+
+			if (this->r_frac > 1.0)
+			{
+				std::copy(&this->r_left[1], &this->r_left[SINC_WIDTH * 2], &this->r_left[0]);
+				this->r_left[SINC_WIDTH * 2 - 1] = s_left;
+
+				std::copy(&this->r_right[1], &this->r_right[SINC_WIDTH * 2], &this->r_right[0]);
+				this->r_right[SINC_WIDTH * 2 - 1] = s_right;
+
+				this->r_frac -= 1.0;
+
+				i_position += 2;
+				if (i_position >= max_samples)
+					i_position -= max_samples;
+				consumed += 2;
+			}
+		}
+
+		this->size -= consumed << 1;
+		this->start += consumed << 1;
+		if (this->start >= this->buffer_size)
+			this->start -= this->buffer_size;
+	}
+
+	inline int avail()
+	{
+		return static_cast<int>(std::floor(((this->size >> 2) - this->r_frac) / this->r_step) * 2);
+	}
+};
+
+#endif /* __SINC_RESAMPLER_H */
+