Browse code

Fixed up the Lanczos interpolation in NCSF (thanks to kode54), also allowed the NCSF plugin to use 32-bit samples in it's GenerateSamples function.

Naram Qashat authored on 2013/04/26 00:54:28
Showing 8 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-04-23
4
+ * Last modification on 2013-04-26
5 5
  *
6 6
  * Adapted from source code of FeOS Sound System
7 7
  * By fincs
... ...
@@ -44,7 +44,7 @@ TempSndReg::TempSndReg() : CR(0), SOURCE(nullptr), TIMER(0), REPEAT_POINT(0), LE
44 44
 
45 45
 bool Channel::initializedLUTs = false;
46 46
 double Channel::cosine_lut[Channel::COSINE_RESOLUTION];
47
-double Channel::lanczos_lut[Channel::LANCZOS_SAMPLES];
47
+double Channel::lanczos_lut[Channel::LANCZOS_SAMPLES + 1];
48 48
 
49 49
 #ifndef M_PI
50 50
 static const double M_PI = 3.14159265358979323846;
... ...
@@ -65,7 +65,7 @@ Channel::Channel() : chnId(-1), tempReg(), state(CS_NONE), trackId(-1), prio(0),
65 65
 		for (unsigned i = 0; i < COSINE_RESOLUTION; ++i)
66 66
 			this->cosine_lut[i] = (1.0 - std::cos((static_cast<double>(i) / COSINE_RESOLUTION) * M_PI)) * 0.5;
67 67
 		double dx = static_cast<double>(LANCZOS_WIDTH) / LANCZOS_SAMPLES, x = 0.0;
68
-		for (unsigned i = 0; i < LANCZOS_SAMPLES; ++i, x += dx)
68
+		for (unsigned i = 0; i <= LANCZOS_SAMPLES; ++i, x += dx)
69 69
 			this->lanczos_lut[i] = std::abs(x) < LANCZOS_WIDTH ? sinc(x) * sinc(x / LANCZOS_WIDTH) : 0.0;
70 70
 		this->initializedLUTs = true;
71 71
 	}
... ...
@@ -604,37 +604,48 @@ int32_t Channel::Interpolate()
604 604
 	double ratio = this->reg.samplePosition;
605 605
 	ratio -= static_cast<int32_t>(ratio);
606 606
 
607
-	const auto &data = &this->sampleHistory[this->sampleHistoryPtr + 5];
608
-	int32_t a = data[0], b = data[1];
607
+	const auto &data = &this->sampleHistory[this->sampleHistoryPtr + 16];
609 608
 
610
-	double c0, c1, c2, c3, c4, c5;
611
-	if (this->ply->interpolation > INTERPOLATION_COSINE)
609
+	if (this->ply->interpolation == INTERPOLATION_LANCZOS)
612 610
 	{
613
-		int32_t c = data[2], z = data[-1];
611
+		double kernel[LANCZOS_WIDTH * 2], kernel_sum = 0.0;
612
+		int i = LANCZOS_WIDTH, shift = static_cast<int>(std::floor(ratio * LANCZOS_RESOLUTION));
613
+		int step = this->reg.sampleIncrease > 1.0 ? static_cast<int>(LANCZOS_RESOLUTION / this->reg.sampleIncrease) : LANCZOS_RESOLUTION;
614
+		for (; i >= -static_cast<int>(LANCZOS_WIDTH - 1); --i)
615
+		{
616
+			int pos = i * step;
617
+			kernel_sum += kernel[i + LANCZOS_WIDTH - 1] = this->lanczos_lut[std::abs(shift - pos)];
618
+		}
619
+		double sum = 0.0;
620
+		for (i = 0; i < static_cast<int>(LANCZOS_WIDTH * 2); ++i)
621
+			sum += data[i - static_cast<int>(LANCZOS_WIDTH) + 1] * kernel[i];
622
+		return static_cast<int32_t>(sum / kernel_sum);
623
+	}
624
+	else if (this->ply->interpolation > INTERPOLATION_COSINE)
625
+	{
626
+		double c0, c1, c2, c3, c4, c5;
614 627
 
615 628
 		if (this->ply->interpolation > INTERPOLATION_4POINTBSPLINE)
616 629
 		{
617
-			int32_t d = data[3], y = data[-2];
618
-
619 630
 			if (this->ply->interpolation == INTERPOLATION_6POINTBSPLINE)
620 631
 			{
621
-				double ym2py2 = y + c, ym1py1 = z + b;
622
-				double y2mym2 = c - y, y1mym1 = b - z;
632
+				double ym2py2 = data[-2] + data[2], ym1py1 = data[-1] + data[1];
633
+				double y2mym2 = data[2] - data[-2], y1mym1 = data[1] - data[-1];
623 634
 				double sixthym1py1 = 1 / 6.0 * ym1py1;
624
-				c0 = 1 / 120.0 * ym2py2 + 13 / 60.0 * ym1py1 + 0.55 * a;
635
+				c0 = 1 / 120.0 * ym2py2 + 13 / 60.0 * ym1py1 + 0.55 * data[0];
625 636
 				c1 = 1 / 24.0 * y2mym2 + 5 / 12.0 * y1mym1;
626
-				c2 = 1 / 12.0 * ym2py2 + sixthym1py1 - 0.5 * a;
637
+				c2 = 1 / 12.0 * ym2py2 + sixthym1py1 - 0.5 * data[0];
627 638
 				c3 = 1 / 12.0 * y2mym2 - 1 / 6.0 * y1mym1;
628
-				c4 = 1 / 24.0 * ym2py2 - sixthym1py1 + 0.25 * a;
629
-				c5 = 1 / 120.0 * (d - y) + 1 / 24.0 * (z - c) + 1 / 12.0 * (b - a);
639
+				c4 = 1 / 24.0 * ym2py2 - sixthym1py1 + 0.25 * data[0];
640
+				c5 = 1 / 120.0 * (data[3] - data[-2]) + 1 / 24.0 * (data[-1] - data[2]) + 1 / 12.0 * (data[1] - data[0]);
630 641
 				return static_cast<int32_t>(((((c5 * ratio + c4) * ratio + c3) * ratio + c2) * ratio + c1) * ratio + c0);
631 642
 			}
632
-			else if (this->ply->interpolation == INTERPOLATION_6POINTOSCULATING)
643
+			else // INTERPOLATION_6POINTOSCULATING
633 644
 			{
634 645
 				ratio -= 0.5;
635
-				double even1 = y + d, odd1 = y - d;
636
-				double even2 = z + c, odd2 = z - c;
637
-				double even3 = a + b, odd3 = a - b;
646
+				double even1 = data[-2] + data[3], odd1 = data[-2] - data[3];
647
+				double even2 = data[-1] + data[2], odd2 = data[-1] - data[2];
648
+				double even3 = data[0] + data[1], odd3 = data[0] - data[1];
638 649
 				c0 = 0.01171875 * even1 - 0.09765625 * even2 + 0.5859375 * even3;
639 650
 				c1 = 0.2109375 * odd2 - 281 / 192.0 * odd3 - 13 / 384.0 * odd1;
640 651
 				c2 = 0.40625 * even2 - 17 / 48.0 * even3 - 5 / 96.0 * even1;
... ...
@@ -643,34 +654,21 @@ int32_t Channel::Interpolate()
643 654
 				c5 = 25 / 24.0 * odd2 - 25 / 12.0 * odd3 - 5 / 24.0 * odd1;
644 655
 				return static_cast<int32_t>(((((c5 * ratio + c4) * ratio + c3) * ratio + c2) * ratio + c1) * ratio + c0);
645 656
 			}
646
-			else // INTERPOLATION_6POINTLANCZOS
647
-			{
648
-				double kernel[6], kernel_sum = 0.0;
649
-				int i = 3, shift = static_cast<int>(std::floor(ratio * LANCZOS_RESOLUTION));
650
-				for (; i >= -2; --i)
651
-				{
652
-					int pos = i * LANCZOS_RESOLUTION;
653
-					kernel_sum += kernel[i + 2] = this->lanczos_lut[std::abs(shift - pos)];
654
-				}
655
-				for (i = 0; i < 6; ++i)
656
-					kernel[i] /= kernel_sum;
657
-				return static_cast<int32_t>(y * kernel[0] + z * kernel[1] + a * kernel[2] + b * kernel[3] + c * kernel[4] + d * kernel[5]);
658
-			}
659 657
 		}
660 658
 		else // INTERPOLATION_4POINTBSPLINE
661 659
 		{
662
-			double ym1py1 = z + b;
663
-			c0 = 1 / 6.0 * ym1py1 + 2 / 3.0 * a;
664
-			c1 = 0.5 * (b - z);
665
-			c2 = 0.5 * ym1py1 - a;
666
-			c3 = 0.5 * (a - b) + 1 / 6.0 * (c - z);
660
+			double ym1py1 = data[-1] + data[1];
661
+			c0 = 1 / 6.0 * ym1py1 + 2 / 3.0 * data[0];
662
+			c1 = 0.5 * (data[1] - data[-1]);
663
+			c2 = 0.5 * ym1py1 - data[0];
664
+			c3 = 0.5 * (data[0] - data[1]) + 1 / 6.0 * (data[2] - data[-1]);
667 665
 			return static_cast<int32_t>(((c3 * ratio + c2) * ratio + c1) * ratio + c0);
668 666
 		}
669 667
 	}
670 668
 	else if (this->ply->interpolation == INTERPOLATION_COSINE)
671
-		return static_cast<int32_t>(a + this->cosine_lut[static_cast<unsigned>(ratio * COSINE_RESOLUTION)] * (b - a));
669
+		return static_cast<int32_t>(data[0] + this->cosine_lut[static_cast<unsigned>(ratio * COSINE_RESOLUTION)] * (data[1] - data[0]));
672 670
 	else // INTERPOLATION_LINEAR
673
-		return static_cast<int32_t>(a + ratio * (b - a));
671
+		return static_cast<int32_t>(data[0] + ratio * (data[1] - data[0]));
674 672
 }
675 673
 
676 674
 int32_t Channel::GenerateSample()
... ...
@@ -732,9 +730,9 @@ void Channel::IncrementSample()
732 730
 
733 731
 		while (loc != newloc)
734 732
 		{
735
-			this->sampleHistory[this->sampleHistoryPtr] = this->sampleHistory[this->sampleHistoryPtr + 8] = this->reg.source->dataptr[loc++];
733
+			this->sampleHistory[this->sampleHistoryPtr] = this->sampleHistory[this->sampleHistoryPtr + 32] = this->reg.source->dataptr[loc++];
736 734
 
737
-			this->sampleHistoryPtr = (this->sampleHistoryPtr + 1) & 7;
735
+			this->sampleHistoryPtr = (this->sampleHistoryPtr + 1) & 31;
738 736
 
739 737
 			if (loc >= this->reg.totalLength)
740 738
 				loc -= this->reg.length;
... ...
@@ -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-04-23
4
+ * Last modification on 2013-04-26
5 5
  *
6 6
  * Adapted from source code of FeOS Sound System
7 7
  * By fincs
... ...
@@ -132,7 +132,7 @@ struct Channel
132 132
 	 * simplify the case of wrapping. Thanks to kode54 for providing this.
133 133
 	 */
134 134
 	uint32_t sampleHistoryPtr;
135
-	int16_t sampleHistory[16];
135
+	int16_t sampleHistory[64];
136 136
 
137 137
 	/*
138 138
 	 * Lookup tables for the cosine and Lanczos Sinc interpolations, to
... ...
@@ -143,10 +143,10 @@ struct Channel
143 143
 	static bool initializedLUTs;
144 144
 	static const unsigned COSINE_RESOLUTION = 8192;
145 145
 	static const unsigned LANCZOS_RESOLUTION = 8192;
146
-	static const unsigned LANCZOS_WIDTH = 3;
146
+	static const unsigned LANCZOS_WIDTH = 8;
147 147
 	static const unsigned LANCZOS_SAMPLES = LANCZOS_RESOLUTION * LANCZOS_WIDTH;
148 148
 	static double cosine_lut[COSINE_RESOLUTION];
149
-	static double lanczos_lut[LANCZOS_SAMPLES];
149
+	static double lanczos_lut[LANCZOS_SAMPLES + 1];
150 150
 
151 151
 	Channel();
152 152
 
... ...
@@ -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-04-23
4
+ * Last modification on 2013-04-26
5 5
  *
6 6
  * Adapted from source code of FeOS Sound System
7 7
  * By fincs
... ...
@@ -59,7 +59,7 @@ enum Interpolation
59 59
 	INTERPOLATION_4POINTBSPLINE,
60 60
 	INTERPOLATION_6POINTOSCULATING,
61 61
 	INTERPOLATION_6POINTBSPLINE,
62
-	INTERPOLATION_6POINTLANCZOS
62
+	INTERPOLATION_LANCZOS
63 63
 };
64 64
 
65 65
 #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-04-23
4
+ * Last modification on 2013-04-26
5 5
  *
6 6
  * Partially based on the vio*sf framework
7 7
  */
... ...
@@ -42,7 +42,7 @@ 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.6";
45
+std::wstring XSFConfig::versionNumber = L"1.7";
46 46
 unsigned XSFConfig_NCSF::initInterpolation = 5;
47 47
 std::wstring XSFConfig_NCSF::initMutes = L"0000000000000000";
48 48
 
... ...
@@ -101,7 +101,7 @@ INT_PTR CALLBACK XSFConfig_NCSF::ConfigDialogProc(HWND hwndDlg, UINT uMsg, WPARA
101 101
 			SendMessageW(GetDlgItem(hwndDlg, idInterpolation), CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(L"4-point, 3rd-order B-spline"));
102 102
 			SendMessageW(GetDlgItem(hwndDlg, idInterpolation), CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(L"6-point, 5th-order Osculating"));
103 103
 			SendMessageW(GetDlgItem(hwndDlg, idInterpolation), CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(L"6-point, 5th-order B-spline"));
104
-			SendMessageW(GetDlgItem(hwndDlg, idInterpolation), CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(L"6-point Lanczos (Sinc)"));
104
+			SendMessageW(GetDlgItem(hwndDlg, idInterpolation), CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(L"Lanczos (Sinc)"));
105 105
 			SendMessageW(GetDlgItem(hwndDlg, idInterpolation), CB_SETCURSEL, this->interpolation, 0);
106 106
 			// Mutes
107 107
 			for (int x = 0, numMutes = this->mutes.size(); x < numMutes; ++x)
... ...
@@ -1,7 +1,7 @@
1 1
 /*
2 2
  * xSF - NCSF Player
3 3
  * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
4
- * Last modification on 2013-04-23
4
+ * Last modification on 2013-04-26
5 5
  *
6 6
  * Partially based on the vio*sf framework
7 7
  *
... ...
@@ -101,11 +101,13 @@ bool XSFPlayer_NCSF::LoadNCSF()
101 101
 
102 102
 XSFPlayer_NCSF::XSFPlayer_NCSF(const std::string &filename) : XSFPlayer()
103 103
 {
104
+	this->uses32BitSamplesClampedTo16Bit = true;
104 105
 	this->xSF.reset(new XSFFile(filename, 8, 12));
105 106
 }
106 107
 
107 108
 XSFPlayer_NCSF::XSFPlayer_NCSF(const std::wstring &filename) : XSFPlayer()
108 109
 {
110
+	this->uses32BitSamplesClampedTo16Bit = true;
109 111
 	this->xSF.reset(new XSFFile(filename, 8, 12));
110 112
 }
111 113
 
... ...
@@ -130,14 +132,6 @@ bool XSFPlayer_NCSF::Load()
130 132
 	return XSFPlayer::Load();
131 133
 }
132 134
 
133
-template<typename T1, typename T2> static inline void clamp(T1 &valueToClamp, const T2 &minValue, const T2 &maxValue)
134
-{
135
-	if (valueToClamp < minValue)
136
-		valueToClamp = minValue;
137
-	else if (valueToClamp > maxValue)
138
-		valueToClamp = maxValue;
139
-}
140
-
141 135
 static inline int32_t muldiv7(int32_t val, uint8_t mul)
142 136
 {
143 137
 	return mul == 127 ? val : ((val * mul) >> 7);
... ...
@@ -182,13 +176,14 @@ void XSFPlayer_NCSF::GenerateSamples(std::vector<uint8_t> &buf, unsigned offset,
182 176
 		leftChannel = muldiv7(leftChannel, this->sseqVol);
183 177
 		rightChannel = muldiv7(rightChannel, this->sseqVol);
184 178
 
185
-		clamp(leftChannel, -0x8000, 0x7FFF);
186
-		clamp(rightChannel, -0x8000, 0x7FFF);
187
-
188 179
 		buf[offset++] = leftChannel & 0xFF;
189 180
 		buf[offset++] = (leftChannel >> 8) & 0xFF;
181
+		buf[offset++] = (leftChannel >> 16) & 0xFF;
182
+		buf[offset++] = (leftChannel >> 24) & 0xFF;
190 183
 		buf[offset++] = rightChannel & 0xFF;
191 184
 		buf[offset++] = (rightChannel >> 8) & 0xFF;
185
+		buf[offset++] = (rightChannel >> 16) & 0xFF;
186
+		buf[offset++] = (rightChannel >> 24) & 0xFF;
192 187
 
193 188
 		if (this->secondsIntoPlayback > this->secondsUntilNextClock)
194 189
 		{
... ...
@@ -1,7 +1,7 @@
1 1
 /*
2 2
  * xSF - Common functions
3 3
  * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
4
- * Last modification on 2013-04-23
4
+ * Last modification on 2013-04-26
5 5
  *
6 6
  * Partially based on the vio*sf framework
7 7
  */
... ...
@@ -66,6 +66,15 @@ template<typename T> inline T NextHighestPowerOf2(T value)
66 66
 	return value + 1;
67 67
 }
68 68
 
69
+// Clamp a value between a minimum and maximum value
70
+template<typename T1, typename T2> inline void clamp(T1 &valueToClamp, const T2 &minValue, const T2 &maxValue)
71
+{
72
+	if (valueToClamp < minValue)
73
+		valueToClamp = minValue;
74
+	else if (valueToClamp > maxValue)
75
+		valueToClamp = maxValue;
76
+}
77
+
69 78
 inline bool FileExists(const std::string &filename)
70 79
 {
71 80
 	std::ifstream file((filename.c_str()));
... ...
@@ -1,7 +1,7 @@
1 1
 /*
2 2
  * xSF - Core Player
3 3
  * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
4
- * Last modification on 2013-04-23
4
+ * Last modification on 2013-04-26
5 5
  *
6 6
  * Partially based on the vio*sf framework
7 7
  */
... ...
@@ -14,13 +14,14 @@
14 14
 extern XSFConfig *xSFConfig;
15 15
 
16 16
 XSFPlayer::XSFPlayer() : xSF(), sampleRate(0), detectedSilenceSample(0), detectedSilenceSec(0), skipSilenceOnStartSec(5), lengthSample(0), fadeSample(0), currentSample(0),
17
-	prevSampleL(CHECK_SILENCE_BIAS), prevSampleR(CHECK_SILENCE_BIAS), lengthInMS(-1), fadeInMS(-1), volume(1.0), ignoreVolume(false)
17
+	prevSampleL(CHECK_SILENCE_BIAS), prevSampleR(CHECK_SILENCE_BIAS), lengthInMS(-1), fadeInMS(-1), volume(1.0), ignoreVolume(false), uses32BitSamplesClampedTo16Bit(false)
18 18
 {
19 19
 }
20 20
 
21 21
 XSFPlayer::XSFPlayer(const XSFPlayer &xSFPlayer) : xSF(new XSFFile()), sampleRate(xSFPlayer.sampleRate), detectedSilenceSample(xSFPlayer.detectedSilenceSample), detectedSilenceSec(xSFPlayer.detectedSilenceSec),
22 22
 	skipSilenceOnStartSec(xSFPlayer.skipSilenceOnStartSec), lengthSample(xSFPlayer.lengthSample), fadeSample(xSFPlayer.fadeSample), currentSample(xSFPlayer.currentSample), prevSampleL(xSFPlayer.prevSampleL),
23
-	prevSampleR(xSFPlayer.prevSampleR), lengthInMS(xSFPlayer.lengthInMS), fadeInMS(xSFPlayer.fadeInMS), volume(xSFPlayer.volume), ignoreVolume(xSFPlayer.ignoreVolume)
23
+	prevSampleR(xSFPlayer.prevSampleR), lengthInMS(xSFPlayer.lengthInMS), fadeInMS(xSFPlayer.fadeInMS), volume(xSFPlayer.volume), ignoreVolume(xSFPlayer.ignoreVolume),
24
+	uses32BitSamplesClampedTo16Bit(xSFPlayer.uses32BitSamplesClampedTo16Bit)
24 25
 {
25 26
 	*this->xSF = *xSFPlayer.xSF;
26 27
 }
... ...
@@ -45,6 +46,7 @@ XSFPlayer &XSFPlayer::operator=(const XSFPlayer &xSFPlayer)
45 46
 		this->fadeInMS = xSFPlayer.fadeInMS;
46 47
 		this->volume = xSFPlayer.volume;
47 48
 		this->ignoreVolume = xSFPlayer.ignoreVolume;
49
+		this->uses32BitSamplesClampedTo16Bit = xSFPlayer.uses32BitSamplesClampedTo16Bit;
48 50
 	}
49 51
 	return *this;
50 52
 }
... ...
@@ -54,17 +56,33 @@ bool XSFPlayer::FillBuffer(std::vector<uint8_t> &buf, unsigned &samplesWritten)
54 56
 	bool endFlag = false;
55 57
 	unsigned detectSilence = xSFConfig->GetDetectSilenceSec();
56 58
 	unsigned pos = 0, bufsize = buf.size() >> 2;
59
+	std::vector<uint8_t> trueBuffer;
60
+	if (this->uses32BitSamplesClampedTo16Bit)
61
+		trueBuffer.resize(bufsize << 3);
62
+	else
63
+		trueBuffer.resize(bufsize << 2);
64
+	auto longBuffer = std::vector<uint8_t>(bufsize << 3);
65
+	int32_t *bufLong = reinterpret_cast<int32_t *>(&longBuffer[0]);
57 66
 	while (pos < bufsize)
58 67
 	{
59 68
 		unsigned remain = bufsize - pos, offset = pos;
60
-		this->GenerateSamples(buf, pos << 1, remain);
69
+		this->GenerateSamples(trueBuffer, pos << (this->uses32BitSamplesClampedTo16Bit ? 2 : 1), remain);
70
+		if (this->uses32BitSamplesClampedTo16Bit)
71
+		{
72
+			int32_t *trueBufLong = reinterpret_cast<int32_t *>(&trueBuffer[0]);
73
+			std::copy(&trueBufLong[0], &trueBufLong[bufsize << 1], &bufLong[0]);
74
+		}
75
+		else
76
+		{
77
+			int16_t *trueBufShort = reinterpret_cast<int16_t *>(&trueBuffer[0]);
78
+			std::copy(&trueBufShort[0], &trueBufShort[bufsize << 1], &bufLong[0]);
79
+		}
61 80
 		if (detectSilence || skipSilenceOnStartSec)
62 81
 		{
63 82
 			unsigned skipOffset = 0;
64 83
 			for (unsigned ofs = 0; ofs < remain; ++ofs)
65 84
 			{
66
-				short *bufShort = reinterpret_cast<short *>(&buf[0]);
67
-				unsigned long sampleL = bufShort[2 * (offset + ofs)], sampleR = bufShort[2 * (offset + ofs) + 1];
85
+				uint32_t sampleL = bufLong[2 * (offset + ofs)], sampleR = bufLong[2 * (offset + ofs) + 1];
68 86
 				bool silence = (sampleL + CHECK_SILENCE_BIAS + CHECK_SILENCE_LEVEL) - this->prevSampleL <= CHECK_SILENCE_LEVEL * 2 &&
69 87
 					(sampleR + CHECK_SILENCE_BIAS + CHECK_SILENCE_LEVEL) - this->prevSampleR <= CHECK_SILENCE_LEVEL * 2;
70 88
 
... ...
@@ -101,9 +119,9 @@ bool XSFPlayer::FillBuffer(std::vector<uint8_t> &buf, unsigned &samplesWritten)
101 119
 			{
102 120
 				if (skipOffset)
103 121
 				{
104
-					auto tmpBuf = std::vector<uint8_t>(2 * skipOffset);
105
-					memcpy(&tmpBuf[0], &buf[offset + 2 * skipOffset], 2 * skipOffset);
106
-					memcpy(&buf[offset], &tmpBuf[0], 2 * skipOffset);
122
+					auto tmpBuf = std::vector<int32_t>((bufsize - skipOffset) << 1);
123
+					std::copy(&bufLong[(offset + skipOffset) << 1], &bufLong[bufsize << 1], &tmpBuf[0]);
124
+					std::copy(&tmpBuf[0], &tmpBuf[(bufsize - skipOffset) << 1], &bufLong[offset << 1]);
107 125
 					pos += skipOffset;
108 126
 				}
109 127
 				else
... ...
@@ -112,6 +130,19 @@ bool XSFPlayer::FillBuffer(std::vector<uint8_t> &buf, unsigned &samplesWritten)
112 130
 		}
113 131
 		else
114 132
 			pos += remain;
133
+		if (pos < bufsize)
134
+		{
135
+			if (this->uses32BitSamplesClampedTo16Bit)
136
+			{
137
+				int32_t *trueBufLong = reinterpret_cast<int32_t *>(&trueBuffer[0]);
138
+				std::copy(&bufLong[0], &bufLong[bufsize << 1], &trueBufLong[0]);
139
+			}
140
+			else
141
+			{
142
+				int16_t *trueBufShort = reinterpret_cast<int16_t *>(&trueBuffer[0]);
143
+				std::copy(&bufLong[0], &bufLong[bufsize << 1], &trueBufShort[0]);
144
+			}
145
+		}
115 146
 	}
116 147
 
117 148
 	/* Detect end of song */
... ...
@@ -133,27 +164,42 @@ bool XSFPlayer::FillBuffer(std::vector<uint8_t> &buf, unsigned &samplesWritten)
133 164
 	if (!this->ignoreVolume && (!fEqual(this->volume, 1.0) || !fEqual(xSFConfig->GetVolume(), 1.0)))
134 165
 	{
135 166
 		double scale = this->volume * xSFConfig->GetVolume();
136
-		short *bufShort = reinterpret_cast<short *>(&buf[0]);
137 167
 		for (unsigned ofs = 0; ofs < bufsize; ++ofs)
138 168
 		{
139
-			double s1 = bufShort[2 * ofs] * scale, s2 = bufShort[2 * ofs + 1] * scale;
140
-			if (s1 > 0x7FFF)
141
-				s1 = 0x7FFF;
142
-			else if (s1 < -0x8000)
143
-				s1 = -0x8000;
144
-			if (s2 > 0x7FFF)
145
-				s2 = 0x7FFF;
146
-			else if (s2 < -0x8000)
147
-				s2 = -0x8000;
148
-			bufShort[2 * ofs] = static_cast<short>(s1);
149
-			bufShort[2 * ofs + 1] = static_cast<short>(s2);
169
+			double s1 = bufLong[2 * ofs] * scale, s2 = bufLong[2 * ofs + 1] * scale;
170
+			if (!this->uses32BitSamplesClampedTo16Bit)
171
+			{
172
+				clamp(s1, -0x7FFF, 0x8000);
173
+				clamp(s2, -0x7FFF, 0x8000);
174
+			}
175
+			bufLong[2 * ofs] = static_cast<int32_t>(s1);
176
+			bufLong[2 * ofs + 1] = static_cast<int32_t>(s2);
177
+		}
178
+	}
179
+
180
+	if (this->uses32BitSamplesClampedTo16Bit)
181
+	{
182
+		int16_t *bufShort = reinterpret_cast<int16_t *>(&buf[0]);
183
+		for (unsigned ofs = 0; ofs < bufsize; ++ofs)
184
+		{
185
+			int32_t s1 = bufLong[2 * ofs], s2 = bufLong[2 * ofs + 1];
186
+			clamp(s1, -0x7FFF, 0x8000);
187
+			clamp(s2, -0x7FFF, 0x8000);
188
+			bufShort[2 * ofs] = static_cast<int16_t>(s1);
189
+			bufShort[2 * ofs + 1] = static_cast<int16_t>(s2);
150 190
 		}
151 191
 	}
192
+	else
193
+	{
194
+		int16_t *trueBufShort = reinterpret_cast<int16_t *>(&trueBuffer[0]);
195
+		std::copy(&bufLong[0], &bufLong[bufsize << 1], &trueBufShort[0]);
196
+		std::copy(&trueBuffer[0], &trueBuffer[bufsize << 2], &buf[0]);
197
+	}
152 198
 
153 199
 	/* Fading */
154 200
 	if (!xSFConfig->GetPlayInfinitely() && this->fadeSample && this->currentSample + bufsize >= this->lengthSample)
155 201
 	{
156
-		short *bufShort = reinterpret_cast<short *>(&buf[0]);
202
+		int16_t *bufShort = reinterpret_cast<int16_t *>(&buf[0]);
157 203
 		for (unsigned ofs = 0; ofs < bufsize; ++ofs)
158 204
 		{
159 205
 			if (this->currentSample + ofs >= this->lengthSample && this->currentSample + ofs < this->lengthSample + this->fadeSample)
... ...
@@ -1,7 +1,7 @@
1 1
 /*
2 2
  * xSF - Core Player
3 3
  * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
4
- * Last modification on 2013-04-23
4
+ * Last modification on 2013-04-26
5 5
  *
6 6
  * Partially based on the vio*sf framework
7 7
  */
... ...
@@ -19,15 +19,15 @@
19 19
 class XSFPlayer
20 20
 {
21 21
 protected:
22
-	static const unsigned CHECK_SILENCE_BIAS = 0x8000000;
23
-	static const unsigned CHECK_SILENCE_LEVEL = 7;
22
+	static const uint32_t CHECK_SILENCE_BIAS = 0x8000000;
23
+	static const uint32_t CHECK_SILENCE_LEVEL = 7;
24 24
 
25 25
 	std::unique_ptr<XSFFile> xSF;
26 26
 	unsigned sampleRate, detectedSilenceSample, detectedSilenceSec, skipSilenceOnStartSec, lengthSample, fadeSample, currentSample;
27
-	unsigned long prevSampleL, prevSampleR;
27
+	uint32_t prevSampleL, prevSampleR;
28 28
 	int lengthInMS, fadeInMS;
29 29
 	double volume;
30
-	bool ignoreVolume;
30
+	bool ignoreVolume, uses32BitSamplesClampedTo16Bit;
31 31
 
32 32
 	XSFPlayer();
33 33
 	XSFPlayer(const XSFPlayer &xSFPLayer);