Browse code

Added B-spline and Optimal interpolations to in_snsf, but I'll probably be changing this later.

Naram Qashat authored on 2013/04/12 10:24:45
Showing 5 changed files
... ...
@@ -96,6 +96,8 @@ INT_PTR CALLBACK XSFConfig_SNSF::ConfigDialogProc(HWND hwndDlg, UINT uMsg, WPARA
96 96
 			// Resampler
97 97
 			SendMessageW(GetDlgItem(hwndDlg, idResampler), CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(L"Linear Resampler"));
98 98
 			SendMessageW(GetDlgItem(hwndDlg, idResampler), CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(L"Hermite Resampler"));
99
+			SendMessageW(GetDlgItem(hwndDlg, idResampler), CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(L"Bspline Resampler"));
100
+			SendMessageW(GetDlgItem(hwndDlg, idResampler), CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(L"Optimal Resampler"));
99 101
 			SendMessageW(GetDlgItem(hwndDlg, idResampler), CB_SETCURSEL, this->resampler, 0);
100 102
 			// Mutes
101 103
 			for (int x = 0, numMutes = this->mutes.size(); x < numMutes; ++x)
... ...
@@ -24,6 +24,8 @@
24 24
 #include "snes9x/apu/apu.h"
25 25
 #include "snes9x/apu/linear_resampler.h"
26 26
 #include "snes9x/apu/hermite_resampler.h"
27
+#include "snes9x/apu/bspline_resampler.h"
28
+#include "snes9x/apu/optimal_resampler.h"
27 29
 #include "snes9x/memmap.h"
28 30
 
29 31
 class XSFPlayer_SNSF : public XSFPlayer
... ...
@@ -228,7 +230,11 @@ bool XSFPlayer_SNSF::Load()
228 230
 
229 231
 	S9xInitAPU();
230 232
 	XSFConfig_SNSF *xSFConfig_SNSF = dynamic_cast<XSFConfig_SNSF *>(xSFConfig);
231
-	if (xSFConfig_SNSF->resampler)
233
+	if (xSFConfig_SNSF->resampler == 3)
234
+		S9xInitSound<OptimalResampler>(10, 0);
235
+	if (xSFConfig_SNSF->resampler == 2)
236
+		S9xInitSound<BsplineResampler>(10, 0);
237
+	else if (xSFConfig_SNSF->resampler == 1)
232 238
 		S9xInitSound<HermiteResampler>(10, 0);
233 239
 	else
234 240
 		S9xInitSound<LinearResampler>(10, 0);
... ...
@@ -182,6 +182,8 @@
182 182
 //#include "display.h"
183 183
 #include "linear_resampler.h"
184 184
 #include "hermite_resampler.h"
185
+#include "bspline_resampler.h"
186
+#include "optimal_resampler.h"
185 187
 
186 188
 #define APU_DEFAULT_INPUT_RATE		32000
187 189
 #define APU_MINIMUM_SAMPLE_COUNT	512
... ...
@@ -475,6 +477,8 @@ template<class ResamplerClass> bool S9xInitSound (int buffer_ms, int lag_ms)
475 477
 
476 478
 template bool S9xInitSound<LinearResampler>(int, int);
477 479
 template bool S9xInitSound<HermiteResampler>(int, int);
480
+template bool S9xInitSound<BsplineResampler>(int, int);
481
+template bool S9xInitSound<OptimalResampler>(int, int);
478 482
 
479 483
 void S9xSetSoundControl (uint8_t voice_switch)
480 484
 {
481 485
new file mode 100644
... ...
@@ -0,0 +1,122 @@
1
+/* Simple resampler based on bsnes's ruby audio library */
2
+
3
+#ifndef __BSPLINE_RESAMPLER_H
4
+#define __BSPLINE_RESAMPLER_H
5
+
6
+#include <cmath>
7
+#include "resampler.h"
8
+
9
+#undef CLAMP
10
+#undef SHORT_CLAMP
11
+template<typename T1, typename T2> static inline T1 CLAMP(T1 x, T2 low, T2 high) { return x > high ? high : (x < low ? low : x); }
12
+template<typename T> static inline short SHORT_CLAMP(T n) { return static_cast<short>(CLAMP(n, -32768, 32767)); }
13
+
14
+class BsplineResampler : public Resampler
15
+{
16
+protected:
17
+	double r_step;
18
+	double r_frac;
19
+	int r_left[4], r_right[4];
20
+
21
+	double bspline(double x, double a, double b, double c, double d)
22
+	{
23
+		double ym1py1 = a + c;
24
+		double c0 = 1 / 6.0 * ym1py1 + 2 / 3.0 * b;
25
+		double c1 = 0.5 * (c - a);
26
+		double c2 = 0.5 * ym1py1 - b;
27
+		double c3 = 0.5 * (b - c) + 1 / 6.0 * (d - a);
28
+		return ((c3 * x + c2) * x + c1) * x + c0;
29
+	}
30
+
31
+public:
32
+	BsplineResampler(int num_samples) : Resampler(num_samples)
33
+	{
34
+		this->clear();
35
+	}
36
+
37
+	void time_ratio(double ratio)
38
+	{
39
+		this->r_step = ratio;
40
+		this->clear();
41
+	}
42
+
43
+	void clear()
44
+	{
45
+		ring_buffer::clear ();
46
+		this->r_frac = 1.0;
47
+		this->r_left[0] = this->r_left[1] = this->r_left[2] = this->r_left[3] = 0;
48
+		this->r_right[0] = this->r_right[1] = this->r_right[2] = this->r_right[3] = 0;
49
+	}
50
+
51
+	void read(short *data, int num_samples)
52
+	{
53
+		int i_position = this->start >> 1;
54
+		short *internal_buffer = reinterpret_cast<short *>(this->buffer);
55
+		int o_position = 0;
56
+		int consumed = 0;
57
+
58
+		while (o_position < num_samples && consumed < this->buffer_size)
59
+		{
60
+			int s_left = internal_buffer[i_position];
61
+			int s_right = internal_buffer[i_position + 1];
62
+			int max_samples = this->buffer_size >> 1;
63
+			const double margin_of_error = 1.0e-10;
64
+
65
+			if (std::abs(this->r_step - 1.0) < margin_of_error)
66
+			{
67
+				data[o_position] = static_cast<short>(s_left);
68
+				data[o_position + 1] = static_cast<short>(s_right);
69
+
70
+				o_position += 2;
71
+				i_position += 2;
72
+				if (i_position >= max_samples)
73
+					i_position -= max_samples;
74
+				consumed += 2;
75
+
76
+				continue;
77
+			}
78
+
79
+			while (this->r_frac <= 1.0 && o_position < num_samples)
80
+			{
81
+				data[o_position] = SHORT_CLAMP(bspline(this->r_frac, this->r_left[0], this->r_left[1], this->r_left[2], this->r_left[3]));
82
+				data[o_position + 1] = SHORT_CLAMP(bspline(this->r_frac, this->r_right[0], this->r_right[1], this->r_right[2], this->r_right[3]));
83
+
84
+				o_position += 2;
85
+
86
+				this->r_frac += this->r_step;
87
+			}
88
+
89
+			if (this->r_frac > 1.0)
90
+			{
91
+				this->r_left[0] = this->r_left[1];
92
+				this->r_left[1] = this->r_left[2];
93
+				this->r_left[2] = this->r_left[3];
94
+				this->r_left[3] = s_left;
95
+
96
+				this->r_right[0] = this->r_right[1];
97
+				this->r_right[1] = this->r_right[2];
98
+				this->r_right[2] = this->r_right[3];
99
+				this->r_right[3] = s_right;
100
+
101
+				this->r_frac -= 1.0;
102
+
103
+				i_position += 2;
104
+				if (i_position >= max_samples)
105
+					i_position -= max_samples;
106
+				consumed += 2;
107
+			}
108
+		}
109
+
110
+		this->size -= consumed << 1;
111
+		this->start += consumed << 1;
112
+		if (this->start >= this->buffer_size)
113
+			this->start -= this->buffer_size;
114
+	}
115
+
116
+	inline int avail()
117
+	{
118
+		return static_cast<int>(std::floor(((this->size >> 2) - this->r_frac) / this->r_step) * 2);
119
+	}
120
+};
121
+
122
+#endif /* __BSPLINE_RESAMPLER_H */
0 123
new file mode 100644
... ...
@@ -0,0 +1,125 @@
1
+/* Simple resampler based on bsnes's ruby audio library */
2
+
3
+#ifndef __OPTIMAL_RESAMPLER_H
4
+#define __OPTIMAL_RESAMPLER_H
5
+
6
+#include <cmath>
7
+#include "resampler.h"
8
+
9
+#undef CLAMP
10
+#undef SHORT_CLAMP
11
+//template<typename T1, typename T2> static inline T1 CLAMP(T1 x, T2 low, T2 high) { return x > high ? high : (x < low ? low : x); }
12
+//template<typename T> static inline short SHORT_CLAMP(T n) { return static_cast<short>(CLAMP(n, -32768, 32767)); }
13
+
14
+class OptimalResampler : public Resampler
15
+{
16
+protected:
17
+	double r_step;
18
+	double r_frac;
19
+	int r_left[4], r_right[4];
20
+
21
+	double optimal(double x, double a, double b, double c, double d)
22
+	{
23
+		double z = x - 0.5;
24
+		double even1 = c + b, odd1 = c - b;
25
+		double even2 = d + a, odd2 = d - a;
26
+		double c0 = even1 * 0.46822774170144532 + even2 * 0.03177225758005808;
27
+		double c1 = odd1 * 0.55890365706150436 + odd2 * 0.14703258836343669;
28
+		double c2 = even1 * -0.250153411893796031 + even2 * 0.25015343462990891;
29
+		double c3 = odd1 * -0.49800710906733769 + odd2 * 0.16600005174304033;
30
+		double c4 = even1 * 0.00064264050033187 + even2 * -0.00064273459469381;
31
+		return (((c4 * z + c3) * z + c2) * z + c1) * z + c0;
32
+	}
33
+
34
+public:
35
+	OptimalResampler(int num_samples) : Resampler(num_samples)
36
+	{
37
+		this->clear();
38
+	}
39
+
40
+	void time_ratio(double ratio)
41
+	{
42
+		this->r_step = ratio;
43
+		this->clear();
44
+	}
45
+
46
+	void clear()
47
+	{
48
+		ring_buffer::clear ();
49
+		this->r_frac = 1.0;
50
+		this->r_left[0] = this->r_left[1] = this->r_left[2] = this->r_left[3] = 0;
51
+		this->r_right[0] = this->r_right[1] = this->r_right[2] = this->r_right[3] = 0;
52
+	}
53
+
54
+	void read(short *data, int num_samples)
55
+	{
56
+		int i_position = this->start >> 1;
57
+		short *internal_buffer = reinterpret_cast<short *>(this->buffer);
58
+		int o_position = 0;
59
+		int consumed = 0;
60
+
61
+		while (o_position < num_samples && consumed < this->buffer_size)
62
+		{
63
+			int s_left = internal_buffer[i_position];
64
+			int s_right = internal_buffer[i_position + 1];
65
+			int max_samples = this->buffer_size >> 1;
66
+			const double margin_of_error = 1.0e-10;
67
+
68
+			if (std::abs(this->r_step - 1.0) < margin_of_error)
69
+			{
70
+				data[o_position] = static_cast<short>(s_left);
71
+				data[o_position + 1] = static_cast<short>(s_right);
72
+
73
+				o_position += 2;
74
+				i_position += 2;
75
+				if (i_position >= max_samples)
76
+					i_position -= max_samples;
77
+				consumed += 2;
78
+
79
+				continue;
80
+			}
81
+
82
+			while (this->r_frac <= 1.0 && o_position < num_samples)
83
+			{
84
+				data[o_position] = SHORT_CLAMP(optimal(this->r_frac, this->r_left[0], this->r_left[1], this->r_left[2], this->r_left[3]));
85
+				data[o_position + 1] = SHORT_CLAMP(optimal(this->r_frac, this->r_right[0], this->r_right[1], this->r_right[2], this->r_right[3]));
86
+
87
+				o_position += 2;
88
+
89
+				this->r_frac += this->r_step;
90
+			}
91
+
92
+			if (this->r_frac > 1.0)
93
+			{
94
+				this->r_left[0] = this->r_left[1];
95
+				this->r_left[1] = this->r_left[2];
96
+				this->r_left[2] = this->r_left[3];
97
+				this->r_left[3] = s_left;
98
+
99
+				this->r_right[0] = this->r_right[1];
100
+				this->r_right[1] = this->r_right[2];
101
+				this->r_right[2] = this->r_right[3];
102
+				this->r_right[3] = s_right;
103
+
104
+				this->r_frac -= 1.0;
105
+
106
+				i_position += 2;
107
+				if (i_position >= max_samples)
108
+					i_position -= max_samples;
109
+				consumed += 2;
110
+			}
111
+		}
112
+
113
+		this->size -= consumed << 1;
114
+		this->start += consumed << 1;
115
+		if (this->start >= this->buffer_size)
116
+			this->start -= this->buffer_size;
117
+	}
118
+
119
+	inline int avail()
120
+	{
121
+		return static_cast<int>(std::floor(((this->size >> 2) - this->r_frac) / this->r_step) * 2);
122
+	}
123
+};
124
+
125
+#endif /* __OPTIMAL_RESAMPLER_H */