* Replaced Lanczos window with Hann window for the windowed sinc function in the NCSF plugin.
* Replaced Lanczos window with Hann window for the windowed sinc function in the NCSF plugin.
* Added a ring buffer specifically designed for working with SWAVs to replace the one provided by kode54, still have to give him thanks for the original though.
* Fixed clipping issue caused by invalid clamping values.
* Minor fix to using the min()/max() functions of numeric_limits because Winamp's out.h includes windows.h without my specific wrapper to redefine things.

--- a/src/in_ncsf/SSEQPlayer/Channel.cpp
+++ b/src/in_ncsf/SSEQPlayer/Channel.cpp
@@ -1,7 +1,7 @@
 /*
  * SSEQ Player - Channel structures
  * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
- * Last modification on 2013-04-26
+ * Last modification on 2013-05-07
  *
  * Adapted from source code of FeOS Sound System
  * By fincs
@@ -44,7 +44,7 @@
 
 bool Channel::initializedLUTs = false;
 double Channel::cosine_lut[Channel::COSINE_RESOLUTION];
-double Channel::lanczos_lut[Channel::LANCZOS_SAMPLES + 1];
+double Channel::sinc_lut[Channel::SINC_SAMPLES + 1];
 
 #ifndef M_PI
 static const double M_PI = 3.14159265358979323846;
@@ -57,16 +57,16 @@
 
 Channel::Channel() : chnId(-1), tempReg(), state(CS_NONE), trackId(-1), prio(0), manualSweep(false), flags(), pan(0), extAmpl(0), velocity(0), extPan(0),
 	key(0), ampl(0), extTune(0), orgKey(0), modType(0), modSpeed(0), modDepth(0), modRange(0), modDelay(0), modDelayCnt(0), modCounter(0),
-	sweepLen(0), sweepCnt(0), sweepPitch(0), attackLvl(0), sustainLvl(0x7F), decayRate(0), releaseRate(0xFFFF), noteLength(-1), vol(0), ply(nullptr), reg()
-{
-	this->clearHistory();
+	sweepLen(0), sweepCnt(0), sweepPitch(0), attackLvl(0), sustainLvl(0x7F), decayRate(0), releaseRate(0xFFFF), noteLength(-1), vol(0), ply(nullptr), reg(),
+	ringBuffer()
+{
 	if (!this->initializedLUTs)
 	{
 		for (unsigned i = 0; i < COSINE_RESOLUTION; ++i)
 			this->cosine_lut[i] = (1.0 - std::cos((static_cast<double>(i) / COSINE_RESOLUTION) * M_PI)) * 0.5;
-		double dx = static_cast<double>(LANCZOS_WIDTH) / LANCZOS_SAMPLES, x = 0.0;
-		for (unsigned i = 0; i <= LANCZOS_SAMPLES; ++i, x += dx)
-			this->lanczos_lut[i] = std::abs(x) < LANCZOS_WIDTH ? sinc(x) * sinc(x / LANCZOS_WIDTH) : 0.0;
+		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;
 	}
 }
@@ -144,7 +144,6 @@
 	this->reg.ClearControlRegister();
 	this->vol = 0;
 	this->noteLength = -1;
-	this->clearHistory();
 }
 
 static inline int getModFlag(int type)
@@ -604,22 +603,22 @@
 	double ratio = this->reg.samplePosition;
 	ratio -= static_cast<int32_t>(ratio);
 
-	const auto &data = &this->sampleHistory[this->sampleHistoryPtr + 16];
-
-	if (this->ply->interpolation == INTERPOLATION_LANCZOS)
-	{
-		double kernel[LANCZOS_WIDTH * 2], kernel_sum = 0.0;
-		int i = LANCZOS_WIDTH, shift = static_cast<int>(std::floor(ratio * LANCZOS_RESOLUTION));
-		int step = this->reg.sampleIncrease > 1.0 ? static_cast<int>(LANCZOS_RESOLUTION / this->reg.sampleIncrease) : LANCZOS_RESOLUTION;
-		int shift_adj = shift * step / LANCZOS_RESOLUTION;
-		for (; i >= -static_cast<int>(LANCZOS_WIDTH - 1); --i)
+	const auto &data = this->ringBuffer.GetBuffer();
+
+	if (this->ply->interpolation == INTERPOLATION_SINC)
+	{
+		double kernel[SINC_WIDTH * 2], kernel_sum = 0.0;
+		int i = SINC_WIDTH, shift = static_cast<int>(std::floor(ratio * SINC_RESOLUTION));
+		int step = this->reg.sampleIncrease > 1.0 ? static_cast<int>(SINC_RESOLUTION / this->reg.sampleIncrease) : 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 + LANCZOS_WIDTH - 1] = this->lanczos_lut[std::abs(shift_adj - pos)];
+			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>(LANCZOS_WIDTH * 2); ++i)
-			sum += data[i - static_cast<int>(LANCZOS_WIDTH) + 1] * kernel[i];
+		for (i = 0; i < static_cast<int>(SINC_WIDTH * 2); ++i)
+			sum += data[i - static_cast<int>(SINC_WIDTH) + 1] * kernel[i];
 		return static_cast<int32_t>(sum / kernel_sum);
 	}
 	else if (this->ply->interpolation > INTERPOLATION_COSINE)
@@ -721,22 +720,59 @@
 {
 	double samplePosition = this->reg.samplePosition + this->reg.sampleIncrease;
 
-	if (this->reg.format != 3 && this->reg.samplePosition >= 0)
-	{
-		uint32_t loc = static_cast<uint32_t>(this->reg.samplePosition);
-		uint32_t newloc = static_cast<uint32_t>(samplePosition);
-
-		if (newloc >= this->reg.totalLength)
-			newloc -= this->reg.length;
-
-		while (loc != newloc)
-		{
-			this->sampleHistory[this->sampleHistoryPtr] = this->sampleHistory[this->sampleHistoryPtr + 32] = this->reg.source->dataptr[loc++];
-
-			this->sampleHistoryPtr = (this->sampleHistoryPtr + 1) & 31;
-
-			if (loc >= this->reg.totalLength)
-				loc -= this->reg.length;
+	if (this->reg.format != 3)
+	{
+		if (this->reg.samplePosition < 0 && samplePosition >= 0)
+		{
+			this->ringBuffer.Clear();
+			this->ringBuffer.bufferPos += SINC_WIDTH + 1;
+			auto preData = std::vector<int16_t>(SINC_WIDTH + 1, this->reg.source->dataptr[0]);
+			this->ringBuffer.PushSamples(&preData[0], SINC_WIDTH + 1);
+			if (this->reg.totalLength < SINC_WIDTH + 1)
+			{
+				this->ringBuffer.PushSamples(&this->reg.source->dataptr[0], this->reg.totalLength);
+				if (this->reg.repeatMode == 1)
+				{
+					size_t samplesLeft = SINC_WIDTH + 1 - this->reg.totalLength;
+					while (samplesLeft)
+					{
+						size_t samplesToPush = std::min(samplesLeft, this->reg.length);
+						this->ringBuffer.PushSamples(&this->reg.source->dataptr[this->reg.loopStart], samplesToPush);
+						samplesLeft -= samplesToPush;
+					}
+				}
+			}
+			else
+				this->ringBuffer.PushSamples(&this->reg.source->dataptr[0], SINC_WIDTH + 1);
+		}
+		if (this->reg.samplePosition >= 0)
+		{
+			uint32_t loc = static_cast<uint32_t>(this->reg.samplePosition) + SINC_WIDTH + 1;
+			uint32_t newloc = static_cast<uint32_t>(samplePosition) + SINC_WIDTH + 1;
+
+			if (this->reg.repeatMode == 1)
+			{
+				if (loc >= this->reg.totalLength)
+					loc -= this->reg.length;
+				if (newloc >= this->reg.totalLength)
+					newloc -= this->reg.length;
+			}
+
+			while (loc != newloc)
+			{
+				this->ringBuffer.NextSample();
+
+				if (loc < this->reg.totalLength)
+					this->ringBuffer.PushSample(this->reg.source->dataptr[loc++]);
+				else
+				{
+					++loc;
+					this->ringBuffer.PushSample(this->reg.source->dataptr[this->reg.totalLength - 1]);
+				}
+
+				if (this->reg.repeatMode == 1 && loc >= this->reg.totalLength)
+					loc -= this->reg.length;
+			}
 		}
 	}
 
@@ -754,9 +790,3 @@
 	}
 }
 
-void Channel::clearHistory()
-{
-	this->sampleHistoryPtr = 0;
-	memset(this->sampleHistory, 0, sizeof(this->sampleHistory));
-}
-

--- a/src/in_ncsf/SSEQPlayer/Channel.h
+++ b/src/in_ncsf/SSEQPlayer/Channel.h
@@ -1,7 +1,7 @@
 /*
  * SSEQ Player - Channel structures
  * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
- * Last modification on 2013-04-26
+ * Last modification on 2013-05-07
  *
  * Adapted from source code of FeOS Sound System
  * By fincs
@@ -83,6 +83,89 @@
 
 struct Player;
 
+/*
+ * This creates a ring buffer, which will store N samples of SWAV
+ * data, duplicated. The way it is duplicated is done as follows:
+ * the samples are stored in the center of the buffer, and on both
+ * sides is half of the data, the first half being after the data
+ * and the second half before before the data. This in essense
+ * mirrors the data while allowing a pointer to always be retrieved
+ * and no extra copies of the buffer are created. Part of the idea
+ * for this came from kode54's original buffer implementation, but
+ * this has been designed to make sure that there are no delays in
+ * accessing the SWAVs samples and also doesn't use 0s before the
+ * start of the SWAV or use 0s after the end of a non-looping SWAV.
+ */
+template<size_t N> struct RingBuffer
+{
+	int16_t buffer[N * 2];
+	size_t bufferPos, getPos;
+
+	RingBuffer() : bufferPos(N / 2), getPos(N / 2)
+	{
+		std::fill(&this->buffer[0], &this->buffer[N * 2], 0);
+	}
+	void Clear()
+	{
+		std::fill(&this->buffer[0], &this->buffer[N * 2], 0);
+		this->bufferPos = this->getPos = N / 2;
+	}
+	void PushSample(int16_t sample)
+	{
+		this->buffer[this->bufferPos] = sample;
+		if (this->bufferPos >= N)
+			this->buffer[this->bufferPos - N] = sample;
+		else
+			this->buffer[this->bufferPos + N] = sample;
+		++this->bufferPos;
+		if (this->bufferPos >= N * 3 / 2)
+			this->bufferPos -= N;
+	}
+	void PushSamples(const int16_t *samples, size_t size)
+	{
+		if (this->bufferPos + size > N * 3 / 2)
+		{
+			size_t free = N * 3 / 2 - this->bufferPos;
+			std::copy(&samples[0], &samples[free], &this->buffer[this->bufferPos]);
+			std::copy(&samples[free], &samples[size], &this->buffer[N / 2]);
+		}
+		else
+			std::copy(&samples[0], &samples[size], &this->buffer[this->bufferPos]);
+		size_t rightFree = this->bufferPos < N ? N - this->bufferPos : 0;
+		if (rightFree < size)
+		{
+			if (!rightFree)
+			{
+				size_t leftStart = this->bufferPos - N;
+				size_t leftSize = std::min(N / 2 - leftStart, size);
+				std::copy(&samples[0], &samples[leftSize], &this->buffer[leftStart]);
+				if (leftSize < size)
+					std::copy(&samples[leftSize], &samples[size], &this->buffer[N * 3 / 2]);
+			}
+			else
+			{
+				std::copy(&samples[0], &samples[rightFree], &this->buffer[this->bufferPos + N]);
+				std::copy(&samples[rightFree], &samples[size], &this->buffer[0]);
+			}
+		}
+		else
+			std::copy(&samples[0], &samples[size], &this->buffer[this->bufferPos + N]);
+		this->bufferPos += size;
+		if (this->bufferPos >= N * 3 / 2)
+			this->bufferPos -= N;
+	}
+	const int16_t *const GetBuffer() const
+	{
+		return &this->buffer[this->getPos];
+	}
+	void NextSample()
+	{
+		++this->getPos;
+		if (this->getPos >= N * 3 / 2)
+			this->getPos -= N;
+	}
+};
+
 struct Channel
 {
 	int8_t chnId;
@@ -125,14 +208,6 @@
 
 	const Player *ply;
 	NDSSoundRegister reg;
-
-	/*
-	 * Interpolation history buffer, which contains the maximum number of
-	 * samples required for any given interpolation mode. Doubled to
-	 * simplify the case of wrapping. Thanks to kode54 for providing this.
-	 */
-	uint32_t sampleHistoryPtr;
-	int16_t sampleHistory[64];
 
 	/*
 	 * Lookup tables for the cosine and Lanczos Sinc interpolations, to
@@ -142,11 +217,13 @@
 	 */
 	static bool initializedLUTs;
 	static const unsigned COSINE_RESOLUTION = 8192;
-	static const unsigned LANCZOS_RESOLUTION = 8192;
-	static const unsigned LANCZOS_WIDTH = 8;
-	static const unsigned LANCZOS_SAMPLES = LANCZOS_RESOLUTION * LANCZOS_WIDTH;
+	static const unsigned SINC_RESOLUTION = 8192;
+	static const unsigned SINC_WIDTH = 8;
+	static const unsigned SINC_SAMPLES = SINC_RESOLUTION * SINC_WIDTH;
 	static double cosine_lut[COSINE_RESOLUTION];
-	static double lanczos_lut[LANCZOS_SAMPLES + 1];
+	static double sinc_lut[SINC_SAMPLES + 1];
+
+	RingBuffer<SINC_WIDTH * 2> ringBuffer;
 
 	Channel();
 
@@ -162,7 +239,6 @@
 	int32_t Interpolate();
 	int32_t GenerateSample();
 	void IncrementSample();
-	void clearHistory();
 };
 
 #endif

--- a/src/in_ncsf/SSEQPlayer/Player.cpp
+++ b/src/in_ncsf/SSEQPlayer/Player.cpp
@@ -1,7 +1,7 @@
 /*
  * SSEQ Player - Player structure
  * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
- * Last modification on 2013-04-18
+ * Last modification on 2013-05-07
  *
  * Adapted from source code of FeOS Sound System
  * By fincs
@@ -120,7 +120,6 @@
 	this->channels[curChnNo].ply = this;
 	this->channels[curChnNo].noteLength = -1;
 	this->channels[curChnNo].vol = 0;
-	this->channels[curChnNo].clearHistory();
 	return curChnNo;
 }
 

--- a/src/in_ncsf/SSEQPlayer/consts.h
+++ b/src/in_ncsf/SSEQPlayer/consts.h
@@ -1,7 +1,7 @@
 /*
  * SSEQ Player - Constants/Macros
  * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
- * Last modification on 2013-04-26
+ * Last modification on 2013-05-07
  *
  * Adapted from source code of FeOS Sound System
  * By fincs
@@ -59,7 +59,7 @@
 	INTERPOLATION_4POINTBSPLINE,
 	INTERPOLATION_6POINTOSCULATING,
 	INTERPOLATION_6POINTBSPLINE,
-	INTERPOLATION_LANCZOS
+	INTERPOLATION_SINC
 };
 
 #endif

--- a/src/in_ncsf/XSFConfig_NCSF.cpp
+++ b/src/in_ncsf/XSFConfig_NCSF.cpp
@@ -1,7 +1,7 @@
 /*
  * xSF - NCSF configuration
  * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
- * Last modification on 2013-04-26
+ * Last modification on 2013-05-07
  *
  * Partially based on the vio*sf framework
  */
@@ -42,7 +42,7 @@
 
 unsigned XSFConfig::initSampleRate = 44100;
 std::wstring XSFConfig::commonName = L"NCSF Decoder";
-std::wstring XSFConfig::versionNumber = L"1.7.1";
+std::wstring XSFConfig::versionNumber = L"1.8";
 unsigned XSFConfig_NCSF::initInterpolation = 5;
 std::wstring XSFConfig_NCSF::initMutes = L"0000000000000000";
 
@@ -101,7 +101,7 @@
 			SendMessageW(GetDlgItem(hwndDlg, idInterpolation), CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(L"4-point, 3rd-order B-spline"));
 			SendMessageW(GetDlgItem(hwndDlg, idInterpolation), CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(L"6-point, 5th-order Osculating"));
 			SendMessageW(GetDlgItem(hwndDlg, idInterpolation), CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(L"6-point, 5th-order B-spline"));
-			SendMessageW(GetDlgItem(hwndDlg, idInterpolation), CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(L"Lanczos (Sinc)"));
+			SendMessageW(GetDlgItem(hwndDlg, idInterpolation), CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(L"Sinc (Hann Window)"));
 			SendMessageW(GetDlgItem(hwndDlg, idInterpolation), CB_SETCURSEL, this->interpolation, 0);
 			// Mutes
 			for (int x = 0, numMutes = this->mutes.size(); x < numMutes; ++x)
@@ -142,6 +142,6 @@
 void XSFConfig_NCSF::About(HWND parent)
 {
 	MessageBox(parent, (XSFConfig::commonName + L" v" + XSFConfig::versionNumber + L", using xSF Winamp plugin framework (based on the vio*sf plugins) by Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]\n\n"
-		L"Utilizes code adapted from the FeOS Sound System library by fincs, git revision 9cb9820 on GitHub, for audio playback.").c_str(), (XSFConfig::commonName + L" v" + XSFConfig::versionNumber).c_str(), MB_OK);
+		L"Utilizes code adapted from the FeOS Sound System library by fincs, git revision 5204c55 on GitHub, for audio playback.").c_str(), (XSFConfig::commonName + L" v" + XSFConfig::versionNumber).c_str(), MB_OK);
 }
 

--- a/src/in_xsf_framework/XSFPlayer.cpp
+++ b/src/in_xsf_framework/XSFPlayer.cpp
@@ -1,7 +1,7 @@
 /*
  * xSF - Core Player
  * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
- * Last modification on 2013-04-26
+ * Last modification on 2013-05-07
  *
  * Partially based on the vio*sf framework
  */
@@ -169,8 +169,8 @@
 			double s1 = bufLong[2 * ofs] * scale, s2 = bufLong[2 * ofs + 1] * scale;
 			if (!this->uses32BitSamplesClampedTo16Bit)
 			{
-				clamp(s1, -0x7FFF, 0x8000);
-				clamp(s2, -0x7FFF, 0x8000);
+				clamp(s1, std::numeric_limits<int16_t>::min(), std::numeric_limits<int16_t>::max());
+				clamp(s2, std::numeric_limits<int16_t>::min(), std::numeric_limits<int16_t>::max());
 			}
 			bufLong[2 * ofs] = static_cast<int32_t>(s1);
 			bufLong[2 * ofs + 1] = static_cast<int32_t>(s2);
@@ -183,8 +183,8 @@
 		for (unsigned ofs = 0; ofs < bufsize; ++ofs)
 		{
 			int32_t s1 = bufLong[2 * ofs], s2 = bufLong[2 * ofs + 1];
-			clamp(s1, -0x7FFF, 0x8000);
-			clamp(s2, -0x7FFF, 0x8000);
+			clamp(s1, std::numeric_limits<int16_t>::min(), std::numeric_limits<int16_t>::max());
+			clamp(s2, std::numeric_limits<int16_t>::min(), std::numeric_limits<int16_t>::max());
 			bufShort[2 * ofs] = static_cast<int16_t>(s1);
 			bufShort[2 * ofs + 1] = static_cast<int16_t>(s2);
 		}

--- a/src/in_xsf_framework/XSFPlayer.h
+++ b/src/in_xsf_framework/XSFPlayer.h
@@ -1,7 +1,7 @@
 /*
  * xSF - Core Player
  * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
- * Last modification on 2013-04-26
+ * Last modification on 2013-05-07
  *
  * Partially based on the vio*sf framework
  */
@@ -12,6 +12,7 @@
 #include "XSFFile.h"
 
 #ifdef WINAMP_PLUGIN
+# include "windowsh_wrapper.h"
 # include <winamp/out.h>
 #endif