Implemented circular interpolation buffer to fix interpolation, thanks to kode54 for the code.
Implemented circular interpolation buffer to fix interpolation, thanks to kode54 for the code.

--- 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-12
+ * Last modification on 2013-04-18
  *
  * Adapted from source code of FeOS Sound System
  * By fincs
@@ -47,6 +47,7 @@
 	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();
 }
 
 void Channel::UpdateVol(const Track &trk)
@@ -122,6 +123,7 @@
 	this->reg.ClearControlRegister();
 	this->vol = 0;
 	this->noteLength = -1;
+	this->clearHistory();
 }
 
 static inline int getModFlag(int type)
@@ -585,38 +587,17 @@
 	double ratio = this->reg.samplePosition;
 	ratio -= static_cast<int32_t>(ratio);
 
-	uint32_t loc = static_cast<uint32_t>(this->reg.samplePosition);
-	const auto &data = &this->reg.source->dataptr[loc];
-	int32_t a = data[0], b;
-	if (loc + 1 < this->reg.totalLength)
-		b = data[1];
-	else
-		b = a;
+	const auto &data = &this->sampleHistory[this->sampleHistoryPtr + 5];
+	int32_t a = data[0], b = data[1];
 
 	double c0, c1, c2, c3, c4, c5;
 	if (this->ply->interpolation > INTERPOLATION_COSINE)
 	{
-		int32_t c, z;
-		if (loc + 2 < this->reg.totalLength)
-			c = data[2];
-		else
-			c = b;
-		if (loc)
-			z = data[-1];
-		else
-			z = a;
+		int32_t c = data[2], z = data[-1];
 
 		if (this->ply->interpolation > INTERPOLATION_4POINTBSPLINE)
 		{
-			int32_t d, y;
-			if (loc + 3 < this->reg.totalLength)
-				d = data[3];
-			else
-				d = c;
-			if (loc > 1)
-				y = data[-2];
-			else
-				y = z;
+			int32_t d = data[3], y = data[-2];
 
 			if (this->ply->interpolation == INTERPOLATION_6POINTBSPLINE)
 			{
@@ -631,7 +612,7 @@
 				c5 = 1 / 120.0 * (d - y) + 1 / 24.0 * (z - c) + 1 / 12.0 * (b - a);
 				return static_cast<int32_t>(((((c5 * ratio + c4) * ratio + c3) * ratio + c2) * ratio + c1) * ratio + c0);
 			}
-			else
+			else // INTERPOLATION_6POINTOSCULATING
 			{
 				ratio -= 0.5;
 				double even1 = y + d, odd1 = y - d;
@@ -646,7 +627,7 @@
 				return static_cast<int32_t>(((((c5 * ratio + c4) * ratio + c3) * ratio + c2) * ratio + c1) * ratio + c0);
 			}
 		}
-		else
+		else // INTERPOLATION_4POINTBSPLINE
 		{
 			double ym1py1 = z + b;
 			c0 = 1 / 6.0 * ym1py1 + 2 / 3.0 * a;
@@ -661,7 +642,7 @@
 		double ratio2 = (1.0 - std::cos(ratio * M_PI)) * 0.5;
 		return static_cast<int32_t>(a + ratio2 * (b - a));
 	}
-	else
+	else // INTERPOLATION_LINEAR
 		return static_cast<int32_t>(a + ratio * (b - a));
 }
 
@@ -712,7 +693,29 @@
 
 void Channel::IncrementSample()
 {
-	this->reg.samplePosition += this->reg.sampleIncrease;
+	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 + 8] = this->reg.source->dataptr[loc++];
+
+			this->sampleHistoryPtr = (this->sampleHistoryPtr + 1) & 7;
+
+			if (loc >= this->reg.totalLength)
+				loc -= this->reg.length;
+		}
+	}
+
+	this->reg.samplePosition = samplePosition;
+
 	if (this->reg.format != 3 && this->reg.samplePosition >= this->reg.totalLength)
 	{
 		if (this->reg.repeatMode == 1)
@@ -725,3 +728,9 @@
 	}
 }
 
+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-02
+ * Last modification on 2013-04-18
  *
  * Adapted from source code of FeOS Sound System
  * By fincs
@@ -127,6 +127,14 @@
 	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[16];
+
 	Channel();
 
 	void UpdateVol(const Track &trk);
@@ -141,6 +149,7 @@
 	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-01
+ * Last modification on 2013-04-18
  *
  * Adapted from source code of FeOS Sound System
  * By fincs
@@ -120,6 +120,7 @@
 	this->channels[curChnNo].ply = this;
 	this->channels[curChnNo].noteLength = -1;
 	this->channels[curChnNo].vol = 0;
+	this->channels[curChnNo].clearHistory();
 	return curChnNo;
 }