Browse code

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

Naram Qashat authored on 2013/04/02 22:40:32
Showing 7 changed files
... ...
@@ -1,7 +1,7 @@
1 1
 /*
2 2
  * SSEQ Player - Channel structures
3 3
  * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
4
- * Last modification on 2013-03-30
4
+ * Last modification on 2013-04-02
5 5
  *
6 6
  * Adapted from source code of FeOS Sound System
7 7
  * By fincs
... ...
@@ -576,17 +576,97 @@ static const int16_t wavedutytbl[8][8] =
576 576
 static const double M_PI = 3.14159265358979323846;
577 577
 #endif
578 578
 
579
-int32_t Channel::Interpolate(int32_t a, int32_t b, double ratio)
579
+// Linear and Cosine interpolation code originally from DeSmuME
580
+// B-spline, Hermite, and Optimal come from Olli Niemitalo:
581
+// http://www.student.oulu.fi/~oniemita/dsp/deip.pdf
582
+int32_t Channel::Interpolate()
580 583
 {
581
-	float ratiof = static_cast<float>(ratio);
582
-	ratiof -= static_cast<int32_t>(ratiof);
583
-	if (this->ply->interpolation == INTERPOLATION_COSINE)
584
+	double ratio = this->reg.samplePosition;
585
+	ratio -= static_cast<int32_t>(ratio);
586
+
587
+	uint32_t loc = static_cast<uint32_t>(this->reg.samplePosition);
588
+	const auto &data = &this->reg.source->data[loc];
589
+	int32_t a = data[0], b;
590
+	if (loc + 1 < this->reg.loopStart + this->reg.length)
591
+		b = data[1];
592
+	else
593
+	{
594
+		if (loc)
595
+		{
596
+			int32_t am1 = data[-1];
597
+			b = 2 * a - am1;
598
+		}
599
+		else
600
+			b = a;
601
+	}
602
+
603
+	if (this->ply->interpolation == INTERPOLATION_BSPLINE || this->ply->interpolation == INTERPOLATION_HERMITE || this->ply->interpolation == INTERPOLATION_OPTIMAL)
604
+	{
605
+		int32_t c, z;
606
+		if (loc + 2 < this->reg.loopStart + this->reg.length)
607
+			c = data[2];
608
+		else
609
+		{
610
+			if (loc)
611
+			{
612
+				int32_t am1 = data[-1];
613
+				c = 3 * a - 2 * am1;
614
+			}
615
+			else
616
+				c = a;
617
+		}
618
+		if (loc)
619
+			z = data[-1];
620
+		else
621
+		{
622
+			if (loc + 1 < this->reg.loopStart + this->reg.length)
623
+			{
624
+				int32_t ap1 = data[1];
625
+				z = 2 * a - ap1;
626
+			}
627
+			else
628
+				z = a;
629
+		}
630
+
631
+		double c0, c1, c2, c3;
632
+
633
+		if (this->ply->interpolation == INTERPOLATION_BSPLINE)
634
+		{
635
+			double zpb = z + b;
636
+			c0 = 1 / 6.0 * zpb + 2 / 3.0 * a;
637
+			c1 = 0.5 * (b - z);
638
+			c2 = 0.5 * zpb - a;
639
+			c3 = 0.5 * (a - b) + 1 / 6.0 * (c - z);
640
+			return static_cast<int32_t>(((c3 * ratio + c2) * ratio + c1) * ratio + c0);
641
+		}
642
+		if (this->ply->interpolation == INTERPOLATION_HERMITE)
643
+		{
644
+			c0 = a;
645
+			c1 = 0.5 * (b - z);
646
+			c2 = z - 2.5 * a + 2 * b - 0.5 * c;
647
+			c3 = 0.5 * (c - z) + 1.5 * (a - b);
648
+			return static_cast<int32_t>(((c3 * ratio + c2) * ratio + c1) * ratio + c0);
649
+		}
650
+		else
651
+		{
652
+			ratio -= 0.5;
653
+			double even1 = b + a, odd1 = b - a;
654
+			double even2 = c + z, odd2 = c - z;
655
+			c0 = even1 * 0.46835497211269561 + even2 * 0.03164502784253309;
656
+			c1 = odd1 * 0.56001293337091440 + odd2 * 0.14666238593949288;
657
+			c2 = even1 * -0.250038759826233691 + even2 * 0.25003876124297131;
658
+			c3 = odd1 * -0.49949850957839148 + odd2 * 0.16649935475113800;
659
+			double c4 = even1 * 0.00016095224137360 + even2 * -0.00016095810460478;
660
+			return static_cast<int32_t>((((c4 * ratio + c3) * ratio + c2) * ratio + c1) * ratio + c0);
661
+		}
662
+	}
663
+	else if (this->ply->interpolation == INTERPOLATION_COSINE)
584 664
 	{
585
-		double ratio2 = (1.0 - std::cos(ratiof * M_PI)) * 0.5;
586
-		return static_cast<int32_t>((1 - ratio2) * a + ratio2 * b);
665
+		double ratio2 = (1.0 - std::cos(ratio * M_PI)) * 0.5;
666
+		return static_cast<int32_t>(a + ratio2 * (b - a));
587 667
 	}
588 668
 	else
589
-		return static_cast<int32_t>((1 - ratiof) * a + ratiof * b);
669
+		return static_cast<int32_t>(a + ratio * (b - a));
590 670
 }
591 671
 
592 672
 int32_t Channel::GenerateSample()
... ...
@@ -599,16 +679,7 @@ int32_t Channel::GenerateSample()
599 679
 		if (this->ply->interpolation == INTERPOLATION_NONE)
600 680
 			return this->reg.source->data[static_cast<uint32_t>(this->reg.samplePosition)];
601 681
 		else
602
-		{
603
-			uint32_t loc = static_cast<uint32_t>(this->reg.samplePosition);
604
-			int32_t a = this->reg.source->data[loc], b;
605
-			if (loc < static_cast<uint32_t>(this->reg.loopStart + this->reg.length - 1))
606
-			{
607
-				b = this->reg.source->data[loc + 1];
608
-				a = this->Interpolate(a, b, this->reg.samplePosition);
609
-			}
610
-			return a;
611
-		}
682
+			return this->Interpolate();
612 683
 	}
613 684
 	else
614 685
 	{
... ...
@@ -1,7 +1,7 @@
1 1
 /*
2 2
  * SSEQ Player - Channel structures
3 3
  * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
4
- * Last modification on 2013-03-21
4
+ * Last modification on 2013-04-02
5 5
  *
6 6
  * Adapted from source code of FeOS Sound System
7 7
  * By fincs
... ...
@@ -15,6 +15,7 @@
15 15
 #define SSEQPLAYER_CHANNEL_H
16 16
 
17 17
 #include <bitset>
18
+#include <tuple>
18 19
 #include "SWAV.h"
19 20
 #include "Track.h"
20 21
 #include "pstdint.h"
... ...
@@ -135,7 +136,7 @@ struct Channel
135 136
 	void Kill();
136 137
 	void UpdateTrack();
137 138
 	void Update();
138
-	int32_t Interpolate(int32_t a, int32_t b, double ratio);
139
+	int32_t Interpolate();
139 140
 	int32_t GenerateSample();
140 141
 	void IncrementSample();
141 142
 };
... ...
@@ -1,7 +1,7 @@
1 1
 /*
2 2
  * SSEQ Player - Constants/Macros
3 3
  * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
4
- * Last modification on 2013-03-21
4
+ * Last modification on 2013-04-02
5 5
  *
6 6
  * Adapted from source code of FeOS Sound System
7 7
  * By fincs
... ...
@@ -51,6 +51,6 @@ const uint32_t SOUND_FORMAT_PSG = 3 << 29;
51 51
 inline uint32_t SOUND_FORMAT(int n) { return n << 29; }
52 52
 const uint32_t SCHANNEL_ENABLE = BIT(31);
53 53
 
54
-enum Interpolation { INTERPOLATION_NONE, INTERPOLATION_LINEAR, INTERPOLATION_COSINE };
54
+enum Interpolation { INTERPOLATION_NONE, INTERPOLATION_LINEAR, INTERPOLATION_COSINE, INTERPOLATION_BSPLINE, INTERPOLATION_HERMITE, INTERPOLATION_OPTIMAL };
55 55
 
56 56
 #endif
... ...
@@ -1,7 +1,7 @@
1 1
 /*
2 2
  * xSF - NCSF configuration
3 3
  * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
4
- * Last modification on 2013-03-25
4
+ * Last modification on 2013-04-02
5 5
  *
6 6
  * Partially based on the vio*sf framework
7 7
  */
... ...
@@ -42,8 +42,8 @@ public:
42 42
 
43 43
 unsigned XSFConfig::initSampleRate = 44100;
44 44
 std::wstring XSFConfig::commonName = L"NCSF Decoder";
45
-std::wstring XSFConfig::versionNumber = L"1.0";
46
-unsigned XSFConfig_NCSF::initInterpolation = 2;
45
+std::wstring XSFConfig::versionNumber = L"1.1";
46
+unsigned XSFConfig_NCSF::initInterpolation = 5;
47 47
 std::wstring XSFConfig_NCSF::initMutes = L"0000000000000000";
48 48
 
49 49
 XSFConfig *XSFConfig::Create()
... ...
@@ -82,7 +82,7 @@ void XSFConfig_NCSF::SaveSpecificConfig()
82 82
 void XSFConfig_NCSF::GenerateSpecificDialogs()
83 83
 {
84 84
 	this->configDialog.AddLabelControl(DialogLabelBuilder(L"Interpolation").WithSize(50, 8).InGroup(L"Output").WithRelativePositionToSibling(RelativePosition::FROM_BOTTOMLEFT, Point<short>(0, 10), 2).IsLeftJustified());
85
-	this->configDialog.AddComboBoxControl(DialogComboBoxBuilder().WithSize(78, 14).InGroup(L"Output").WithRelativePositionToSibling(RelativePosition::FROM_TOPRIGHT, Point<short>(5, -3)).WithID(idInterpolation).
85
+	this->configDialog.AddComboBoxControl(DialogComboBoxBuilder().WithSize(90, 14).InGroup(L"Output").WithRelativePositionToSibling(RelativePosition::FROM_TOPRIGHT, Point<short>(5, -3)).WithID(idInterpolation).
86 86
 		IsDropDownList().WithTabStop());
87 87
 	this->configDialog.AddLabelControl(DialogLabelBuilder(L"Mute").WithSize(50, 8).InGroup(L"Output").WithRelativePositionToSibling(RelativePosition::FROM_BOTTOMLEFT, Point<short>(0, 10), 2).IsLeftJustified());
88 88
 	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 @@ INT_PTR CALLBACK XSFConfig_NCSF::ConfigDialogProc(HWND hwndDlg, UINT uMsg, WPARA
98 98
 			SendMessageW(GetDlgItem(hwndDlg, idInterpolation), CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(L"No Interpolation"));
99 99
 			SendMessageW(GetDlgItem(hwndDlg, idInterpolation), CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(L"Linear Interpolation"));
100 100
 			SendMessageW(GetDlgItem(hwndDlg, idInterpolation), CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(L"Cosine Interpolation"));
101
+			SendMessageW(GetDlgItem(hwndDlg, idInterpolation), CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(L"B-spline Interpolation"));
102
+			SendMessageW(GetDlgItem(hwndDlg, idInterpolation), CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(L"Hermite Interpolation"));
103
+			SendMessageW(GetDlgItem(hwndDlg, idInterpolation), CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(L"Optimal Interpolation"));
101 104
 			SendMessageW(GetDlgItem(hwndDlg, idInterpolation), CB_SETCURSEL, this->interpolation, 0);
102 105
 			// Mutes
103 106
 			for (int x = 0, numMutes = this->mutes.size(); x < numMutes; ++x)
... ...
@@ -1,7 +1,7 @@
1 1
 /*
2 2
  * xSF - Core configuration handler
3 3
  * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
4
- * Last modification on 2013-03-30
4
+ * Last modification on 2013-04-02
5 5
  *
6 6
  * Partially based on the vio*sf framework
7 7
  */
... ...
@@ -48,6 +48,12 @@ XSFConfig::XSFConfig() : playInfinitely(false), skipSilenceOnStartSec(0), detect
48 48
 {
49 49
 }
50 50
 
51
+const String &XSFConfig::CommonNameWithVersion()
52
+{
53
+	static const auto commonNameWithVersion = String(XSFConfig::commonName + L" v" + XSFConfig::versionNumber);
54
+	return commonNameWithVersion;
55
+}
56
+
51 57
 std::wstring XSFConfig::GetTextFromWindow(HWND hwnd)
52 58
 {
53 59
 	LRESULT length = SendMessageW(hwnd, WM_GETTEXTLENGTH, 0, 0);
... ...
@@ -1,7 +1,7 @@
1 1
 /*
2 2
  * xSF - Core configuration handler
3 3
  * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
4
- * Last modification on 2013-03-30
4
+ * Last modification on 2013-04-02
5 5
  *
6 6
  * Partially based on the vio*sf framework
7 7
  */
... ...
@@ -69,6 +69,7 @@ public:
69 69
 	static std::wstring versionNumber;
70 70
 	// 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.
71 71
 	static XSFConfig *Create();
72
+	static const String &CommonNameWithVersion();
72 73
 
73 74
 	virtual ~XSFConfig() { }
74 75
 	void LoadConfig();
... ...
@@ -1,7 +1,7 @@
1 1
 /*
2 2
  * xSF - Winamp plugin
3 3
  * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
4
- * Last modification on 2013-03-30
4
+ * Last modification on 2013-04-02
5 5
  *
6 6
  * Partially based on the vio*sf framework
7 7
  */
... ...
@@ -258,7 +258,7 @@ void eqSet(int, char [10], int)
258 258
 In_Module inMod =
259 259
 {
260 260
 	IN_VER,
261
-	const_cast<char *>(XSFPlayer::WinampDescription), /* Unsafe but Winamp's SDK requires this */
261
+	const_cast<char *>(XSFConfig::CommonNameWithVersion().GetStrC()), /* Unsafe but Winamp's SDK requires this */
262 262
 	nullptr, /* Filled by Winamp */
263 263
 	nullptr, /* Filled by Winamp */
264 264
 	const_cast<char *>(XSFPlayer::WinampExts), /* Unsafe but Winamp's SDK requires this */