Added new interpolation methods, added version number in plugin description.
Added new interpolation methods, added version number in plugin description.

--- 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-03-30
+ * Last modification on 2013-04-02
  *
  * Adapted from source code of FeOS Sound System
  * By fincs
@@ -576,17 +576,97 @@
 static const double M_PI = 3.14159265358979323846;
 #endif
 
-int32_t Channel::Interpolate(int32_t a, int32_t b, double ratio)
-{
-	float ratiof = static_cast<float>(ratio);
-	ratiof -= static_cast<int32_t>(ratiof);
-	if (this->ply->interpolation == INTERPOLATION_COSINE)
-	{
-		double ratio2 = (1.0 - std::cos(ratiof * M_PI)) * 0.5;
-		return static_cast<int32_t>((1 - ratio2) * a + ratio2 * b);
-	}
+// Linear and Cosine interpolation code originally from DeSmuME
+// B-spline, Hermite, and Optimal come from Olli Niemitalo:
+// http://www.student.oulu.fi/~oniemita/dsp/deip.pdf
+int32_t Channel::Interpolate()
+{
+	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->data[loc];
+	int32_t a = data[0], b;
+	if (loc + 1 < this->reg.loopStart + this->reg.length)
+		b = data[1];
 	else
-		return static_cast<int32_t>((1 - ratiof) * a + ratiof * b);
+	{
+		if (loc)
+		{
+			int32_t am1 = data[-1];
+			b = 2 * a - am1;
+		}
+		else
+			b = a;
+	}
+
+	if (this->ply->interpolation == INTERPOLATION_BSPLINE || this->ply->interpolation == INTERPOLATION_HERMITE || this->ply->interpolation == INTERPOLATION_OPTIMAL)
+	{
+		int32_t c, z;
+		if (loc + 2 < this->reg.loopStart + this->reg.length)
+			c = data[2];
+		else
+		{
+			if (loc)
+			{
+				int32_t am1 = data[-1];
+				c = 3 * a - 2 * am1;
+			}
+			else
+				c = a;
+		}
+		if (loc)
+			z = data[-1];
+		else
+		{
+			if (loc + 1 < this->reg.loopStart + this->reg.length)
+			{
+				int32_t ap1 = data[1];
+				z = 2 * a - ap1;
+			}
+			else
+				z = a;
+		}
+
+		double c0, c1, c2, c3;
+
+		if (this->ply->interpolation == INTERPOLATION_BSPLINE)
+		{
+			double zpb = z + b;
+			c0 = 1 / 6.0 * zpb + 2 / 3.0 * a;
+			c1 = 0.5 * (b - z);
+			c2 = 0.5 * zpb - a;
+			c3 = 0.5 * (a - b) + 1 / 6.0 * (c - z);
+			return static_cast<int32_t>(((c3 * ratio + c2) * ratio + c1) * ratio + c0);
+		}
+		if (this->ply->interpolation == INTERPOLATION_HERMITE)
+		{
+			c0 = a;
+			c1 = 0.5 * (b - z);
+			c2 = z - 2.5 * a + 2 * b - 0.5 * c;
+			c3 = 0.5 * (c - z) + 1.5 * (a - b);
+			return static_cast<int32_t>(((c3 * ratio + c2) * ratio + c1) * ratio + c0);
+		}
+		else
+		{
+			ratio -= 0.5;
+			double even1 = b + a, odd1 = b - a;
+			double even2 = c + z, odd2 = c - z;
+			c0 = even1 * 0.46835497211269561 + even2 * 0.03164502784253309;
+			c1 = odd1 * 0.56001293337091440 + odd2 * 0.14666238593949288;
+			c2 = even1 * -0.250038759826233691 + even2 * 0.25003876124297131;
+			c3 = odd1 * -0.49949850957839148 + odd2 * 0.16649935475113800;
+			double c4 = even1 * 0.00016095224137360 + even2 * -0.00016095810460478;
+			return static_cast<int32_t>((((c4 * ratio + c3) * ratio + c2) * ratio + c1) * ratio + c0);
+		}
+	}
+	else if (this->ply->interpolation == INTERPOLATION_COSINE)
+	{
+		double ratio2 = (1.0 - std::cos(ratio * M_PI)) * 0.5;
+		return static_cast<int32_t>(a + ratio2 * (b - a));
+	}
+	else
+		return static_cast<int32_t>(a + ratio * (b - a));
 }
 
 int32_t Channel::GenerateSample()
@@ -599,16 +679,7 @@
 		if (this->ply->interpolation == INTERPOLATION_NONE)
 			return this->reg.source->data[static_cast<uint32_t>(this->reg.samplePosition)];
 		else
-		{
-			uint32_t loc = static_cast<uint32_t>(this->reg.samplePosition);
-			int32_t a = this->reg.source->data[loc], b;
-			if (loc < static_cast<uint32_t>(this->reg.loopStart + this->reg.length - 1))
-			{
-				b = this->reg.source->data[loc + 1];
-				a = this->Interpolate(a, b, this->reg.samplePosition);
-			}
-			return a;
-		}
+			return this->Interpolate();
 	}
 	else
 	{

--- 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-03-21
+ * Last modification on 2013-04-02
  *
  * Adapted from source code of FeOS Sound System
  * By fincs
@@ -15,6 +15,7 @@
 #define SSEQPLAYER_CHANNEL_H
 
 #include <bitset>
+#include <tuple>
 #include "SWAV.h"
 #include "Track.h"
 #include "pstdint.h"
@@ -135,7 +136,7 @@
 	void Kill();
 	void UpdateTrack();
 	void Update();
-	int32_t Interpolate(int32_t a, int32_t b, double ratio);
+	int32_t Interpolate();
 	int32_t GenerateSample();
 	void IncrementSample();
 };

--- 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-03-21
+ * Last modification on 2013-04-02
  *
  * Adapted from source code of FeOS Sound System
  * By fincs
@@ -51,7 +51,7 @@
 inline uint32_t SOUND_FORMAT(int n) { return n << 29; }
 const uint32_t SCHANNEL_ENABLE = BIT(31);
 
-enum Interpolation { INTERPOLATION_NONE, INTERPOLATION_LINEAR, INTERPOLATION_COSINE };
+enum Interpolation { INTERPOLATION_NONE, INTERPOLATION_LINEAR, INTERPOLATION_COSINE, INTERPOLATION_BSPLINE, INTERPOLATION_HERMITE, INTERPOLATION_OPTIMAL };
 
 #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-03-25
+ * Last modification on 2013-04-02
  *
  * Partially based on the vio*sf framework
  */
@@ -42,8 +42,8 @@
 
 unsigned XSFConfig::initSampleRate = 44100;
 std::wstring XSFConfig::commonName = L"NCSF Decoder";
-std::wstring XSFConfig::versionNumber = L"1.0";
-unsigned XSFConfig_NCSF::initInterpolation = 2;
+std::wstring XSFConfig::versionNumber = L"1.1";
+unsigned XSFConfig_NCSF::initInterpolation = 5;
 std::wstring XSFConfig_NCSF::initMutes = L"0000000000000000";
 
 XSFConfig *XSFConfig::Create()
@@ -82,7 +82,7 @@
 void XSFConfig_NCSF::GenerateSpecificDialogs()
 {
 	this->configDialog.AddLabelControl(DialogLabelBuilder(L"Interpolation").WithSize(50, 8).InGroup(L"Output").WithRelativePositionToSibling(RelativePosition::FROM_BOTTOMLEFT, Point<short>(0, 10), 2).IsLeftJustified());
-	this->configDialog.AddComboBoxControl(DialogComboBoxBuilder().WithSize(78, 14).InGroup(L"Output").WithRelativePositionToSibling(RelativePosition::FROM_TOPRIGHT, Point<short>(5, -3)).WithID(idInterpolation).
+	this->configDialog.AddComboBoxControl(DialogComboBoxBuilder().WithSize(90, 14).InGroup(L"Output").WithRelativePositionToSibling(RelativePosition::FROM_TOPRIGHT, Point<short>(5, -3)).WithID(idInterpolation).
 		IsDropDownList().WithTabStop());
 	this->configDialog.AddLabelControl(DialogLabelBuilder(L"Mute").WithSize(50, 8).InGroup(L"Output").WithRelativePositionToSibling(RelativePosition::FROM_BOTTOMLEFT, Point<short>(0, 10), 2).IsLeftJustified());
 	this->configDialog.AddListBoxControl(DialogListBoxBuilder().WithSize(78, 45).WithExactHeight().InGroup(L"Output").WithRelativePositionToSibling(RelativePosition::FROM_TOPRIGHT, Point<short>(5, -3)).WithID(idMutes).
@@ -98,6 +98,9 @@
 			SendMessageW(GetDlgItem(hwndDlg, idInterpolation), CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(L"No Interpolation"));
 			SendMessageW(GetDlgItem(hwndDlg, idInterpolation), CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(L"Linear Interpolation"));
 			SendMessageW(GetDlgItem(hwndDlg, idInterpolation), CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(L"Cosine Interpolation"));
+			SendMessageW(GetDlgItem(hwndDlg, idInterpolation), CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(L"B-spline Interpolation"));
+			SendMessageW(GetDlgItem(hwndDlg, idInterpolation), CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(L"Hermite Interpolation"));
+			SendMessageW(GetDlgItem(hwndDlg, idInterpolation), CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(L"Optimal Interpolation"));
 			SendMessageW(GetDlgItem(hwndDlg, idInterpolation), CB_SETCURSEL, this->interpolation, 0);
 			// Mutes
 			for (int x = 0, numMutes = this->mutes.size(); x < numMutes; ++x)

--- a/src/in_xsf_framework/XSFConfig.cpp
+++ b/src/in_xsf_framework/XSFConfig.cpp
@@ -1,7 +1,7 @@
 /*
  * xSF - Core configuration handler
  * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
- * Last modification on 2013-03-30
+ * Last modification on 2013-04-02
  *
  * Partially based on the vio*sf framework
  */
@@ -46,6 +46,12 @@
 XSFConfig::XSFConfig() : playInfinitely(false), skipSilenceOnStartSec(0), detectSilenceSec(0), defaultLength(0), defaultFade(0), volume(0.0), volumeType(VOLUMETYPE_NONE), peakType(PEAKTYPE_NONE),
 	sampleRate(0), titleFormat(L""), configDialog(), configDialogProperty(), infoDialog(), supportedSampleRates(), configIO(XSFConfigIO::Create())
 {
+}
+
+const String &XSFConfig::CommonNameWithVersion()
+{
+	static const auto commonNameWithVersion = String(XSFConfig::commonName + L" v" + XSFConfig::versionNumber);
+	return commonNameWithVersion;
 }
 
 std::wstring XSFConfig::GetTextFromWindow(HWND hwnd)

--- a/src/in_xsf_framework/XSFConfig.h
+++ b/src/in_xsf_framework/XSFConfig.h
@@ -1,7 +1,7 @@
 /*
  * xSF - Core configuration handler
  * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
- * Last modification on 2013-03-30
+ * Last modification on 2013-04-02
  *
  * Partially based on the vio*sf framework
  */
@@ -69,6 +69,7 @@
 	static std::wstring versionNumber;
 	// The Create function is not defined in XSFConfig.cpp, it should be defined in your own config's source and return a pointer to your config's class.
 	static XSFConfig *Create();
+	static const String &CommonNameWithVersion();
 
 	virtual ~XSFConfig() { }
 	void LoadConfig();

--- a/src/in_xsf_framework/in_xsf.cpp
+++ b/src/in_xsf_framework/in_xsf.cpp
@@ -1,7 +1,7 @@
 /*
  * xSF - Winamp plugin
  * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
- * Last modification on 2013-03-30
+ * Last modification on 2013-04-02
  *
  * Partially based on the vio*sf framework
  */
@@ -258,7 +258,7 @@
 In_Module inMod =
 {
 	IN_VER,
-	const_cast<char *>(XSFPlayer::WinampDescription), /* Unsafe but Winamp's SDK requires this */
+	const_cast<char *>(XSFConfig::CommonNameWithVersion().GetStrC()), /* Unsafe but Winamp's SDK requires this */
 	nullptr, /* Filled by Winamp */
 	nullptr, /* Filled by Winamp */
 	const_cast<char *>(XSFPlayer::WinampExts), /* Unsafe but Winamp's SDK requires this */