shithub: ft²

Download patch

ref: 65ae4b974e929be2bf6340739a17e9c9dcf70d67
parent: fb2d7b8e8a87528b180a3cd55f8011336573ba7b
author: Olav Sørensen <olav.sorensen@live.no>
date: Fri Feb 23 12:28:14 EST 2024

Sinc 16-point -> sinc 32-point

--- a/README.md
+++ b/README.md
@@ -14,7 +14,7 @@
 If these don't work for you, you'll have to compile the code manually.
 
 # Improvements over original DOS version
-- The channel resampler/mixer uses floating-point arithmetics for less errors, and has extra interpolation options (4-point cubic spline, 8-point/16-point windowed-sinc)
+- The channel resampler/mixer uses floating-point arithmetics for less errors, and has extra interpolation options (4-point cubic spline, 8-point/32-point windowed-sinc)
 - The sample loader supports FLAC/AIFF samples and more WAV types than original FT2. It will also attempt to tune the sample (finetune and rel. note) to its playback frequency on load.
 - It contains a new "Trim" feature, which will remove unused stuff to potentially make the module smaller
 - Drag n' drop of modules/samples
--- a/src/ft2_audio.c
+++ b/src/ft2_audio.c
@@ -195,6 +195,8 @@
 	lockMixerCallback();
 	audio.interpolationType = interpolationType;
 
+	audio.sincInterpolation = false;
+
 	// set sinc LUT pointers
 	if (config.interpolation == INTERPOLATION_SINC8)
 	{
@@ -201,12 +203,23 @@
 		fKaiserSinc = fKaiserSinc_8;
 		fDownSample1 = fDownSample1_8;
 		fDownSample2 = fDownSample2_8;
+
+		// modelled after OpenMPT
+		audio.sincRatio1 = (uintCPUWord_t)(1.1875 * MIXER_FRAC_SCALE);
+		audio.sincRatio2 = (uintCPUWord_t)(1.5    * MIXER_FRAC_SCALE);
+
+		audio.sincInterpolation = true;
 	}
-	else if (config.interpolation == INTERPOLATION_SINC16)
+	else if (config.interpolation == INTERPOLATION_SINC32)
 	{
-		fKaiserSinc = fKaiserSinc_16;
-		fDownSample1 = fDownSample1_16;
-		fDownSample2 = fDownSample2_16;
+		fKaiserSinc = fKaiserSinc_32;
+		fDownSample1 = fDownSample1_32;
+		fDownSample2 = fDownSample2_32;
+
+		audio.sincRatio1 = (uintCPUWord_t)(2.375 * MIXER_FRAC_SCALE);
+		audio.sincRatio2 = (uintCPUWord_t)(3.0   * MIXER_FRAC_SCALE);
+
+		audio.sincInterpolation = true;
 	}
 
 	unlockMixerCallback();
@@ -389,12 +402,13 @@
 				// set voice delta
 				const uintCPUWord_t delta = v->oldDelta = (intCPUWord_t)((dHz * audio.dHz2MixDeltaMul) + 0.5); // Hz -> fixed-point delta (rounded)
 
-				if (audio.interpolationType == INTERPOLATION_SINC8 || audio.interpolationType == INTERPOLATION_SINC16)
+				//const double dRatio = delta / (double)MIXER_FRAC_SCALE;
+
+				if (audio.sincInterpolation) // decide which sinc LUT to use according to the resampling ratio
 				{
-					// decide which sinc LUT to use according to the resampling ratio
-					if (delta <= (uintCPUWord_t)(1.1875 * MIXER_FRAC_SCALE))
+					if (delta <= audio.sincRatio1)
 						v->fSincLUT = fKaiserSinc;
-					else if (delta <= (uintCPUWord_t)(1.5 * MIXER_FRAC_SCALE))
+					else if (delta <= audio.sincRatio2)
 						v->fSincLUT = fDownSample1;
 					else
 						v->fSincLUT = fDownSample2;
--- a/src/ft2_audio.h
+++ b/src/ft2_audio.h
@@ -42,7 +42,7 @@
 	char *currInputDevice, *currOutputDevice, *lastWorkingAudioDeviceName;
 	char *inputDeviceNames[MAX_AUDIO_DEVICES], *outputDeviceNames[MAX_AUDIO_DEVICES];
 	volatile bool locked, resetSyncTickTimeFlag, volumeRampingFlag;
-	bool linearPeriodsFlag, rescanAudioDevicesSupported;
+	bool linearPeriodsFlag, rescanAudioDevicesSupported, sincInterpolation;
 	volatile uint8_t interpolationType;
 	int32_t inputDeviceNum, outputDeviceNum, lastWorkingAudioFreq, lastWorkingAudioBits;
 	uint32_t quickVolRampSamples, freq;
@@ -52,6 +52,7 @@
 
 	uint32_t audLatencyPerfValInt, tickTimeIntTab[(MAX_BPM-MIN_BPM)+1];
 	uint64_t audLatencyPerfValFrac, tickTimeFracTab[(MAX_BPM-MIN_BPM)+1];
+	uintCPUWord_t sincRatio1, sincRatio2;
 
 	uint64_t tickTime64, tickTime64Frac;
 
--- a/src/ft2_config.c
+++ b/src/ft2_config.c
@@ -833,8 +833,8 @@
 		tmpID = RB_CONFIG_AUDIO_INTRP_DISABLED;
 	else if (config.interpolation == INTERPOLATION_LINEAR)
 		tmpID = RB_CONFIG_AUDIO_INTRP_LINEAR;
-	else if (config.interpolation == INTERPOLATION_SINC16)
-		tmpID = RB_CONFIG_AUDIO_INTRP_SINC16;
+	else if (config.interpolation == INTERPOLATION_SINC32)
+		tmpID = RB_CONFIG_AUDIO_INTRP_SINC32;
 	else if (config.interpolation == INTERPOLATION_CUBIC)
 		tmpID = RB_CONFIG_AUDIO_INTRP_CUBIC;
 	else
@@ -1175,7 +1175,7 @@
 			textOutShadow(406, 119, PAL_FORGRND, PAL_DSKTOP2, "Linear (FT2)");
 			textOutShadow(406, 133, PAL_FORGRND, PAL_DSKTOP2, "Cubic spline");
 			textOutShadow(406, 147, PAL_FORGRND, PAL_DSKTOP2, "Sinc (8 point)");
-			textOutShadow(406, 161, PAL_FORGRND, PAL_DSKTOP2, "Sinc (16 point)");
+			textOutShadow(406, 161, PAL_FORGRND, PAL_DSKTOP2, "Sinc (32 point)");
 
 			textOutShadow(509,   3, PAL_FORGRND, PAL_DSKTOP2, "Audio output rate:");
 			textOutShadow(525,  17, PAL_FORGRND, PAL_DSKTOP2, "44100Hz");
@@ -1642,11 +1642,11 @@
 	checkRadioButton(RB_CONFIG_AUDIO_INTRP_SINC8);
 }
 
-void rbConfigAudioIntrp16PointSinc(void)
+void rbConfigAudioIntrp32PointSinc(void)
 {
-	config.interpolation = INTERPOLATION_SINC16;
+	config.interpolation = INTERPOLATION_SINC32;
 	audioSetInterpolationType(config.interpolation);
-	checkRadioButton(RB_CONFIG_AUDIO_INTRP_SINC16);
+	checkRadioButton(RB_CONFIG_AUDIO_INTRP_SINC32);
 }
 
 void rbConfigAudio44kHz(void)
--- a/src/ft2_config.h
+++ b/src/ft2_config.h
@@ -23,7 +23,7 @@
 	INTERPOLATION_DISABLED = 0,
 	INTERPOLATION_SINC8 = 1,
 	INTERPOLATION_LINEAR = 2,
-	INTERPOLATION_SINC16 = 3,
+	INTERPOLATION_SINC32 = 3,
 	INTERPOLATION_CUBIC = 4,
 	// ------
 
@@ -222,7 +222,7 @@
 void rbConfigAudioIntrpLinear(void);
 void rbConfigAudioIntrpCubic(void);
 void rbConfigAudioIntrp8PointSinc(void);
-void rbConfigAudioIntrp16PointSinc(void);
+void rbConfigAudioIntrp32PointSinc(void);
 void rbConfigAudio44kHz(void);
 void rbConfigAudio48kHz(void);
 #if CPU_64BIT
--- a/src/ft2_radiobuttons.c
+++ b/src/ft2_radiobuttons.c
@@ -90,7 +90,7 @@
 	{ 390, 118,  91, RB_GROUP_CONFIG_AUDIO_INTERPOLATION, rbConfigAudioIntrpLinear },
 	{ 390, 132,  86, RB_GROUP_CONFIG_AUDIO_INTERPOLATION, rbConfigAudioIntrpCubic },
 	{ 390, 146,  95, RB_GROUP_CONFIG_AUDIO_INTERPOLATION, rbConfigAudioIntrp8PointSinc },
-	{ 390, 160, 102, RB_GROUP_CONFIG_AUDIO_INTERPOLATION, rbConfigAudioIntrp16PointSinc },
+	{ 390, 160, 102, RB_GROUP_CONFIG_AUDIO_INTERPOLATION, rbConfigAudioIntrp32PointSinc },
 
 	// audio output frequency
 	//x,   y,  w,  group,                      funcOnUp
--- a/src/ft2_radiobuttons.h
+++ b/src/ft2_radiobuttons.h
@@ -60,7 +60,7 @@
 	RB_CONFIG_AUDIO_INTRP_LINEAR,
 	RB_CONFIG_AUDIO_INTRP_CUBIC,
 	RB_CONFIG_AUDIO_INTRP_SINC8,
-	RB_CONFIG_AUDIO_INTRP_SINC16,
+	RB_CONFIG_AUDIO_INTRP_SINC32,
 
 	// AUDIO FREQUENCY
 	RB_CONFIG_AUDIO_44KHZ,
--- a/src/ft2_replayer.h
+++ b/src/ft2_replayer.h
@@ -218,9 +218,9 @@
 	int32_t length, loopStart, loopLength;
 
 	// fix for resampling interpolation taps
-	int8_t leftEdgeTapSamples8[32];
-	int16_t leftEdgeTapSamples16[32];
-	int16_t fixedSmp[32];
+	int8_t leftEdgeTapSamples8[MAX_TAPS*2];
+	int16_t leftEdgeTapSamples16[MAX_TAPS*2];
+	int16_t fixedSmp[MAX_TAPS*2];
 	int32_t fixedPos;
 } sample_t;
 
--- a/src/mixer/ft2_mix.c
+++ b/src/mixer/ft2_mix.c
@@ -9,7 +9,7 @@
 **       (Note: Mixing macros can be found in ft2_mix_macros.h)
 **
 ** Specifications:
-** - Interpolation: None, 2-tap linear, 4-tap cubic spline, 8-tap windowed-sinc, 16-tap windowed-sinc
+** - Interpolation: None, 2-tap linear, 4-tap cubic spline, 8-tap windowed-sinc, 32-tap windowed-sinc
 ** - FT2-styled linear volume ramping (can be turned off)
 ** - 32.32 (16.16 if 32-bit CPU) fixed-point precision for resampling delta/position
 ** - 32-bit floating-point precision for mixing and interpolation
@@ -464,7 +464,7 @@
 	SET_BACK_MIXER_POS
 }
 
-static void mix8bNoLoopS16Intrp(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
+static void mix8bNoLoopS32Intrp(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
 {
 	const int8_t *base, *smpPtr;
 	float fSample, *fMixBufferL, *fMixBufferR;
@@ -484,19 +484,19 @@
 
 		for (i = 0; i < (samplesToMix & 3); i++)
 		{
-			RENDER_8BIT_SMP_S16INTRP
+			RENDER_8BIT_SMP_S32INTRP
 			INC_POS
 		}
 		samplesToMix >>= 2;
 		for (i = 0; i < samplesToMix; i++)
 		{
-			RENDER_8BIT_SMP_S16INTRP
+			RENDER_8BIT_SMP_S32INTRP
 			INC_POS
-			RENDER_8BIT_SMP_S16INTRP
+			RENDER_8BIT_SMP_S32INTRP
 			INC_POS
-			RENDER_8BIT_SMP_S16INTRP
+			RENDER_8BIT_SMP_S32INTRP
 			INC_POS
-			RENDER_8BIT_SMP_S16INTRP
+			RENDER_8BIT_SMP_S32INTRP
 			INC_POS
 		}
 
@@ -506,7 +506,7 @@
 	SET_BACK_MIXER_POS
 }
 
-static void mix8bLoopS16Intrp(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
+static void mix8bLoopS32Intrp(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
 {
 	const int8_t *base, *smpPtr;
 	int8_t *smpTapPtr;
@@ -530,19 +530,19 @@
 		{
 			for (i = 0; i < (samplesToMix & 3); i++)
 			{
-				RENDER_8BIT_SMP_S16INTRP_TAP_FIX
+				RENDER_8BIT_SMP_S32INTRP_TAP_FIX
 				INC_POS
 			}
 			samplesToMix >>= 2;
 			for (i = 0; i < samplesToMix; i++)
 			{
-				RENDER_8BIT_SMP_S16INTRP_TAP_FIX
+				RENDER_8BIT_SMP_S32INTRP_TAP_FIX
 				INC_POS
-				RENDER_8BIT_SMP_S16INTRP_TAP_FIX
+				RENDER_8BIT_SMP_S32INTRP_TAP_FIX
 				INC_POS
-				RENDER_8BIT_SMP_S16INTRP_TAP_FIX
+				RENDER_8BIT_SMP_S32INTRP_TAP_FIX
 				INC_POS
-				RENDER_8BIT_SMP_S16INTRP_TAP_FIX
+				RENDER_8BIT_SMP_S32INTRP_TAP_FIX
 				INC_POS
 			}
 		}
@@ -550,19 +550,19 @@
 		{
 			for (i = 0; i < (samplesToMix & 3); i++)
 			{
-				RENDER_8BIT_SMP_S16INTRP
+				RENDER_8BIT_SMP_S32INTRP
 				INC_POS
 			}
 			samplesToMix >>= 2;
 			for (i = 0; i < samplesToMix; i++)
 			{
-				RENDER_8BIT_SMP_S16INTRP
+				RENDER_8BIT_SMP_S32INTRP
 				INC_POS
-				RENDER_8BIT_SMP_S16INTRP
+				RENDER_8BIT_SMP_S32INTRP
 				INC_POS
-				RENDER_8BIT_SMP_S16INTRP
+				RENDER_8BIT_SMP_S32INTRP
 				INC_POS
-				RENDER_8BIT_SMP_S16INTRP
+				RENDER_8BIT_SMP_S32INTRP
 				INC_POS
 			}
 		}
@@ -573,7 +573,7 @@
 	SET_BACK_MIXER_POS
 }
 
-static void mix8bBidiLoopS16Intrp(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
+static void mix8bBidiLoopS32Intrp(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
 {
 	const int8_t *base, *revBase, *smpPtr;
 	int8_t *smpTapPtr;
@@ -598,19 +598,19 @@
 		{
 			for (i = 0; i < (samplesToMix & 3); i++)
 			{
-				RENDER_8BIT_SMP_S16INTRP_TAP_FIX
+				RENDER_8BIT_SMP_S32INTRP_TAP_FIX
 				INC_POS_BIDI
 			}
 			samplesToMix >>= 2;
 			for (i = 0; i < samplesToMix; i++)
 			{
-				RENDER_8BIT_SMP_S16INTRP_TAP_FIX
+				RENDER_8BIT_SMP_S32INTRP_TAP_FIX
 				INC_POS_BIDI
-				RENDER_8BIT_SMP_S16INTRP_TAP_FIX
+				RENDER_8BIT_SMP_S32INTRP_TAP_FIX
 				INC_POS_BIDI
-				RENDER_8BIT_SMP_S16INTRP_TAP_FIX
+				RENDER_8BIT_SMP_S32INTRP_TAP_FIX
 				INC_POS_BIDI
-				RENDER_8BIT_SMP_S16INTRP_TAP_FIX
+				RENDER_8BIT_SMP_S32INTRP_TAP_FIX
 				INC_POS_BIDI
 			}
 		}
@@ -618,19 +618,19 @@
 		{
 			for (i = 0; i < (samplesToMix & 3); i++)
 			{
-				RENDER_8BIT_SMP_S16INTRP
+				RENDER_8BIT_SMP_S32INTRP
 				INC_POS_BIDI
 			}
 			samplesToMix >>= 2;
 			for (i = 0; i < samplesToMix; i++)
 			{
-				RENDER_8BIT_SMP_S16INTRP
+				RENDER_8BIT_SMP_S32INTRP
 				INC_POS_BIDI
-				RENDER_8BIT_SMP_S16INTRP
+				RENDER_8BIT_SMP_S32INTRP
 				INC_POS_BIDI
-				RENDER_8BIT_SMP_S16INTRP
+				RENDER_8BIT_SMP_S32INTRP
 				INC_POS_BIDI
-				RENDER_8BIT_SMP_S16INTRP
+				RENDER_8BIT_SMP_S32INTRP
 				INC_POS_BIDI
 			}
 		}
@@ -1336,7 +1336,7 @@
 	SET_BACK_MIXER_POS
 }
 
-static void mix8bRampNoLoopS16Intrp(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
+static void mix8bRampNoLoopS32Intrp(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
 {
 	const int8_t *base, *smpPtr;
 	float fSample, *fMixBufferL, *fMixBufferR;
@@ -1358,7 +1358,7 @@
 
 		for (i = 0; i < (samplesToMix & 3); i++)
 		{
-			RENDER_8BIT_SMP_S16INTRP
+			RENDER_8BIT_SMP_S32INTRP
 			VOLUME_RAMPING
 			INC_POS
 		}
@@ -1365,16 +1365,16 @@
 		samplesToMix >>= 2;
 		for (i = 0; i < samplesToMix; i++)
 		{
-			RENDER_8BIT_SMP_S16INTRP
+			RENDER_8BIT_SMP_S32INTRP
 			VOLUME_RAMPING
 			INC_POS
-			RENDER_8BIT_SMP_S16INTRP
+			RENDER_8BIT_SMP_S32INTRP
 			VOLUME_RAMPING
 			INC_POS
-			RENDER_8BIT_SMP_S16INTRP
+			RENDER_8BIT_SMP_S32INTRP
 			VOLUME_RAMPING
 			INC_POS
-			RENDER_8BIT_SMP_S16INTRP
+			RENDER_8BIT_SMP_S32INTRP
 			VOLUME_RAMPING
 			INC_POS
 		}
@@ -1386,7 +1386,7 @@
 	SET_BACK_MIXER_POS
 }
 
-static void mix8bRampLoopS16Intrp(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
+static void mix8bRampLoopS32Intrp(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
 {
 	const int8_t *base, *smpPtr;
 	int8_t *smpTapPtr;
@@ -1412,7 +1412,7 @@
 		{
 			for (i = 0; i < (samplesToMix & 3); i++)
 			{
-				RENDER_8BIT_SMP_S16INTRP_TAP_FIX
+				RENDER_8BIT_SMP_S32INTRP_TAP_FIX
 				VOLUME_RAMPING
 				INC_POS
 			}
@@ -1419,16 +1419,16 @@
 			samplesToMix >>= 2;
 			for (i = 0; i < samplesToMix; i++)
 			{
-				RENDER_8BIT_SMP_S16INTRP_TAP_FIX
+				RENDER_8BIT_SMP_S32INTRP_TAP_FIX
 				VOLUME_RAMPING
 				INC_POS
-				RENDER_8BIT_SMP_S16INTRP_TAP_FIX
+				RENDER_8BIT_SMP_S32INTRP_TAP_FIX
 				VOLUME_RAMPING
 				INC_POS
-				RENDER_8BIT_SMP_S16INTRP_TAP_FIX
+				RENDER_8BIT_SMP_S32INTRP_TAP_FIX
 				VOLUME_RAMPING
 				INC_POS
-				RENDER_8BIT_SMP_S16INTRP_TAP_FIX
+				RENDER_8BIT_SMP_S32INTRP_TAP_FIX
 				VOLUME_RAMPING
 				INC_POS
 			}
@@ -1437,7 +1437,7 @@
 		{
 			for (i = 0; i < (samplesToMix & 3); i++)
 			{
-				RENDER_8BIT_SMP_S16INTRP
+				RENDER_8BIT_SMP_S32INTRP
 				VOLUME_RAMPING
 				INC_POS
 			}
@@ -1444,16 +1444,16 @@
 			samplesToMix >>= 2;
 			for (i = 0; i < samplesToMix; i++)
 			{
-				RENDER_8BIT_SMP_S16INTRP
+				RENDER_8BIT_SMP_S32INTRP
 				VOLUME_RAMPING
 				INC_POS
-				RENDER_8BIT_SMP_S16INTRP
+				RENDER_8BIT_SMP_S32INTRP
 				VOLUME_RAMPING
 				INC_POS
-				RENDER_8BIT_SMP_S16INTRP
+				RENDER_8BIT_SMP_S32INTRP
 				VOLUME_RAMPING
 				INC_POS
-				RENDER_8BIT_SMP_S16INTRP
+				RENDER_8BIT_SMP_S32INTRP
 				VOLUME_RAMPING
 				INC_POS
 			}
@@ -1466,7 +1466,7 @@
 	SET_BACK_MIXER_POS
 }
 
-static void mix8bRampBidiLoopS16Intrp(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
+static void mix8bRampBidiLoopS32Intrp(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
 {
 	const int8_t *base, *revBase, *smpPtr;
 	int8_t *smpTapPtr;
@@ -1493,7 +1493,7 @@
 		{
 			for (i = 0; i < (samplesToMix & 3); i++)
 			{
-				RENDER_8BIT_SMP_S16INTRP_TAP_FIX
+				RENDER_8BIT_SMP_S32INTRP_TAP_FIX
 				VOLUME_RAMPING
 				INC_POS_BIDI
 			}
@@ -1500,16 +1500,16 @@
 			samplesToMix >>= 2;
 			for (i = 0; i < samplesToMix; i++)
 			{
-				RENDER_8BIT_SMP_S16INTRP_TAP_FIX
+				RENDER_8BIT_SMP_S32INTRP_TAP_FIX
 				VOLUME_RAMPING
 				INC_POS_BIDI
-				RENDER_8BIT_SMP_S16INTRP_TAP_FIX
+				RENDER_8BIT_SMP_S32INTRP_TAP_FIX
 				VOLUME_RAMPING
 				INC_POS_BIDI
-				RENDER_8BIT_SMP_S16INTRP_TAP_FIX
+				RENDER_8BIT_SMP_S32INTRP_TAP_FIX
 				VOLUME_RAMPING
 				INC_POS_BIDI
-				RENDER_8BIT_SMP_S16INTRP_TAP_FIX
+				RENDER_8BIT_SMP_S32INTRP_TAP_FIX
 				VOLUME_RAMPING
 				INC_POS_BIDI
 			}
@@ -1518,7 +1518,7 @@
 		{
 			for (i = 0; i < (samplesToMix & 3); i++)
 			{
-				RENDER_8BIT_SMP_S16INTRP
+				RENDER_8BIT_SMP_S32INTRP
 				VOLUME_RAMPING
 				INC_POS_BIDI
 			}
@@ -1525,16 +1525,16 @@
 			samplesToMix >>= 2;
 			for (i = 0; i < samplesToMix; i++)
 			{
-				RENDER_8BIT_SMP_S16INTRP
+				RENDER_8BIT_SMP_S32INTRP
 				VOLUME_RAMPING
 				INC_POS_BIDI
-				RENDER_8BIT_SMP_S16INTRP
+				RENDER_8BIT_SMP_S32INTRP
 				VOLUME_RAMPING
 				INC_POS_BIDI
-				RENDER_8BIT_SMP_S16INTRP
+				RENDER_8BIT_SMP_S32INTRP
 				VOLUME_RAMPING
 				INC_POS_BIDI
-				RENDER_8BIT_SMP_S16INTRP
+				RENDER_8BIT_SMP_S32INTRP
 				VOLUME_RAMPING
 				INC_POS_BIDI
 			}
@@ -2198,7 +2198,7 @@
 	SET_BACK_MIXER_POS
 }
 
-static void mix16bNoLoopS16Intrp(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
+static void mix16bNoLoopS32Intrp(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
 {
 	const int16_t *base, *smpPtr;
 	float fSample, *fMixBufferL, *fMixBufferR;
@@ -2218,19 +2218,19 @@
 
 		for (i = 0; i < (samplesToMix & 3); i++)
 		{
-			RENDER_16BIT_SMP_S16INTRP
+			RENDER_16BIT_SMP_S32INTRP
 			INC_POS
 		}
 		samplesToMix >>= 2;
 		for (i = 0; i < samplesToMix; i++)
 		{
-			RENDER_16BIT_SMP_S16INTRP
+			RENDER_16BIT_SMP_S32INTRP
 			INC_POS
-			RENDER_16BIT_SMP_S16INTRP
+			RENDER_16BIT_SMP_S32INTRP
 			INC_POS
-			RENDER_16BIT_SMP_S16INTRP
+			RENDER_16BIT_SMP_S32INTRP
 			INC_POS
-			RENDER_16BIT_SMP_S16INTRP
+			RENDER_16BIT_SMP_S32INTRP
 			INC_POS
 		}
 
@@ -2240,7 +2240,7 @@
 	SET_BACK_MIXER_POS
 }
 
-static void mix16bLoopS16Intrp(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
+static void mix16bLoopS32Intrp(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
 {
 	const int16_t *base, *smpPtr;
 	int16_t *smpTapPtr;
@@ -2264,19 +2264,19 @@
 		{
 			for (i = 0; i < (samplesToMix & 3); i++)
 			{
-				RENDER_16BIT_SMP_S16INTRP_TAP_FIX
+				RENDER_16BIT_SMP_S32INTRP_TAP_FIX
 				INC_POS
 			}
 			samplesToMix >>= 2;
 			for (i = 0; i < samplesToMix; i++)
 			{
-				RENDER_16BIT_SMP_S16INTRP_TAP_FIX
+				RENDER_16BIT_SMP_S32INTRP_TAP_FIX
 				INC_POS
-				RENDER_16BIT_SMP_S16INTRP_TAP_FIX
+				RENDER_16BIT_SMP_S32INTRP_TAP_FIX
 				INC_POS
-				RENDER_16BIT_SMP_S16INTRP_TAP_FIX
+				RENDER_16BIT_SMP_S32INTRP_TAP_FIX
 				INC_POS
-				RENDER_16BIT_SMP_S16INTRP_TAP_FIX
+				RENDER_16BIT_SMP_S32INTRP_TAP_FIX
 				INC_POS
 			}
 		}
@@ -2284,19 +2284,19 @@
 		{
 			for (i = 0; i < (samplesToMix & 3); i++)
 			{
-				RENDER_16BIT_SMP_S16INTRP
+				RENDER_16BIT_SMP_S32INTRP
 				INC_POS
 			}
 			samplesToMix >>= 2;
 			for (i = 0; i < samplesToMix; i++)
 			{
-				RENDER_16BIT_SMP_S16INTRP
+				RENDER_16BIT_SMP_S32INTRP
 				INC_POS
-				RENDER_16BIT_SMP_S16INTRP
+				RENDER_16BIT_SMP_S32INTRP
 				INC_POS
-				RENDER_16BIT_SMP_S16INTRP
+				RENDER_16BIT_SMP_S32INTRP
 				INC_POS
-				RENDER_16BIT_SMP_S16INTRP
+				RENDER_16BIT_SMP_S32INTRP
 				INC_POS
 			}
 		}
@@ -2307,7 +2307,7 @@
 	SET_BACK_MIXER_POS
 }
 
-static void mix16bBidiLoopS16Intrp(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
+static void mix16bBidiLoopS32Intrp(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
 {
 	const int16_t *base, *revBase, *smpPtr;
 	int16_t *smpTapPtr;
@@ -2332,19 +2332,19 @@
 		{
 			for (i = 0; i < (samplesToMix & 3); i++)
 			{
-				RENDER_16BIT_SMP_S16INTRP_TAP_FIX
+				RENDER_16BIT_SMP_S32INTRP_TAP_FIX
 				INC_POS_BIDI
 			}
 			samplesToMix >>= 2;
 			for (i = 0; i < samplesToMix; i++)
 			{
-				RENDER_16BIT_SMP_S16INTRP_TAP_FIX
+				RENDER_16BIT_SMP_S32INTRP_TAP_FIX
 				INC_POS_BIDI
-				RENDER_16BIT_SMP_S16INTRP_TAP_FIX
+				RENDER_16BIT_SMP_S32INTRP_TAP_FIX
 				INC_POS_BIDI
-				RENDER_16BIT_SMP_S16INTRP_TAP_FIX
+				RENDER_16BIT_SMP_S32INTRP_TAP_FIX
 				INC_POS_BIDI
-				RENDER_16BIT_SMP_S16INTRP_TAP_FIX
+				RENDER_16BIT_SMP_S32INTRP_TAP_FIX
 				INC_POS_BIDI
 			}
 		}
@@ -2352,19 +2352,19 @@
 		{
 			for (i = 0; i < (samplesToMix & 3); i++)
 			{
-				RENDER_16BIT_SMP_S16INTRP
+				RENDER_16BIT_SMP_S32INTRP
 				INC_POS_BIDI
 			}
 			samplesToMix >>= 2;
 			for (i = 0; i < samplesToMix; i++)
 			{
-				RENDER_16BIT_SMP_S16INTRP
+				RENDER_16BIT_SMP_S32INTRP
 				INC_POS_BIDI
-				RENDER_16BIT_SMP_S16INTRP
+				RENDER_16BIT_SMP_S32INTRP
 				INC_POS_BIDI
-				RENDER_16BIT_SMP_S16INTRP
+				RENDER_16BIT_SMP_S32INTRP
 				INC_POS_BIDI
-				RENDER_16BIT_SMP_S16INTRP
+				RENDER_16BIT_SMP_S32INTRP
 				INC_POS_BIDI
 			}
 		}
@@ -3070,7 +3070,7 @@
 	SET_BACK_MIXER_POS
 }
 
-static void mix16bRampNoLoopS16Intrp(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
+static void mix16bRampNoLoopS32Intrp(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
 {
 	const int16_t *base, *smpPtr;
 	float fSample, *fMixBufferL, *fMixBufferR;
@@ -3092,7 +3092,7 @@
 
 		for (i = 0; i < (samplesToMix & 3); i++)
 		{
-			RENDER_16BIT_SMP_S16INTRP
+			RENDER_16BIT_SMP_S32INTRP
 			VOLUME_RAMPING
 			INC_POS
 		}
@@ -3099,16 +3099,16 @@
 		samplesToMix >>= 2;
 		for (i = 0; i < samplesToMix; i++)
 		{
-			RENDER_16BIT_SMP_S16INTRP
+			RENDER_16BIT_SMP_S32INTRP
 			VOLUME_RAMPING
 			INC_POS
-			RENDER_16BIT_SMP_S16INTRP
+			RENDER_16BIT_SMP_S32INTRP
 			VOLUME_RAMPING
 			INC_POS
-			RENDER_16BIT_SMP_S16INTRP
+			RENDER_16BIT_SMP_S32INTRP
 			VOLUME_RAMPING
 			INC_POS
-			RENDER_16BIT_SMP_S16INTRP
+			RENDER_16BIT_SMP_S32INTRP
 			VOLUME_RAMPING
 			INC_POS
 		}
@@ -3120,7 +3120,7 @@
 	SET_BACK_MIXER_POS
 }
 
-static void mix16bRampLoopS16Intrp(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
+static void mix16bRampLoopS32Intrp(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
 {
 	const int16_t *base, *smpPtr;
 	int16_t *smpTapPtr;
@@ -3146,7 +3146,7 @@
 		{
 			for (i = 0; i < (samplesToMix & 3); i++)
 			{
-				RENDER_16BIT_SMP_S16INTRP_TAP_FIX
+				RENDER_16BIT_SMP_S32INTRP_TAP_FIX
 				VOLUME_RAMPING
 				INC_POS
 			}
@@ -3153,16 +3153,16 @@
 			samplesToMix >>= 2;
 			for (i = 0; i < samplesToMix; i++)
 			{
-				RENDER_16BIT_SMP_S16INTRP_TAP_FIX
+				RENDER_16BIT_SMP_S32INTRP_TAP_FIX
 				VOLUME_RAMPING
 				INC_POS
-				RENDER_16BIT_SMP_S16INTRP_TAP_FIX
+				RENDER_16BIT_SMP_S32INTRP_TAP_FIX
 				VOLUME_RAMPING
 				INC_POS
-				RENDER_16BIT_SMP_S16INTRP_TAP_FIX
+				RENDER_16BIT_SMP_S32INTRP_TAP_FIX
 				VOLUME_RAMPING
 				INC_POS
-				RENDER_16BIT_SMP_S16INTRP_TAP_FIX
+				RENDER_16BIT_SMP_S32INTRP_TAP_FIX
 				VOLUME_RAMPING
 				INC_POS
 			}
@@ -3171,7 +3171,7 @@
 		{
 			for (i = 0; i < (samplesToMix & 3); i++)
 			{
-				RENDER_16BIT_SMP_S16INTRP
+				RENDER_16BIT_SMP_S32INTRP
 				VOLUME_RAMPING
 				INC_POS
 			}
@@ -3178,16 +3178,16 @@
 			samplesToMix >>= 2;
 			for (i = 0; i < samplesToMix; i++)
 			{
-				RENDER_16BIT_SMP_S16INTRP
+				RENDER_16BIT_SMP_S32INTRP
 				VOLUME_RAMPING
 				INC_POS
-				RENDER_16BIT_SMP_S16INTRP
+				RENDER_16BIT_SMP_S32INTRP
 				VOLUME_RAMPING
 				INC_POS
-				RENDER_16BIT_SMP_S16INTRP
+				RENDER_16BIT_SMP_S32INTRP
 				VOLUME_RAMPING
 				INC_POS
-				RENDER_16BIT_SMP_S16INTRP
+				RENDER_16BIT_SMP_S32INTRP
 				VOLUME_RAMPING
 				INC_POS
 			}
@@ -3200,7 +3200,7 @@
 	SET_BACK_MIXER_POS
 }
 
-static void mix16bRampBidiLoopS16Intrp(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
+static void mix16bRampBidiLoopS32Intrp(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
 {
 	const int16_t *base, *revBase, *smpPtr;
 	int16_t *smpTapPtr;
@@ -3227,7 +3227,7 @@
 		{
 			for (i = 0; i < (samplesToMix & 3); i++)
 			{
-				RENDER_16BIT_SMP_S16INTRP_TAP_FIX
+				RENDER_16BIT_SMP_S32INTRP_TAP_FIX
 				VOLUME_RAMPING
 				INC_POS_BIDI
 			}
@@ -3234,16 +3234,16 @@
 			samplesToMix >>= 2;
 			for (i = 0; i < samplesToMix; i++)
 			{
-				RENDER_16BIT_SMP_S16INTRP_TAP_FIX
+				RENDER_16BIT_SMP_S32INTRP_TAP_FIX
 				VOLUME_RAMPING
 				INC_POS_BIDI
-				RENDER_16BIT_SMP_S16INTRP_TAP_FIX
+				RENDER_16BIT_SMP_S32INTRP_TAP_FIX
 				VOLUME_RAMPING
 				INC_POS_BIDI
-				RENDER_16BIT_SMP_S16INTRP_TAP_FIX
+				RENDER_16BIT_SMP_S32INTRP_TAP_FIX
 				VOLUME_RAMPING
 				INC_POS_BIDI
-				RENDER_16BIT_SMP_S16INTRP_TAP_FIX
+				RENDER_16BIT_SMP_S32INTRP_TAP_FIX
 				VOLUME_RAMPING
 				INC_POS_BIDI
 			}
@@ -3252,7 +3252,7 @@
 		{
 			for (i = 0; i < (samplesToMix & 3); i++)
 			{
-				RENDER_16BIT_SMP_S16INTRP
+				RENDER_16BIT_SMP_S32INTRP
 				VOLUME_RAMPING
 				INC_POS_BIDI
 			}
@@ -3259,16 +3259,16 @@
 			samplesToMix >>= 2;
 			for (i = 0; i < samplesToMix; i++)
 			{
-				RENDER_16BIT_SMP_S16INTRP
+				RENDER_16BIT_SMP_S32INTRP
 				VOLUME_RAMPING
 				INC_POS_BIDI
-				RENDER_16BIT_SMP_S16INTRP
+				RENDER_16BIT_SMP_S32INTRP
 				VOLUME_RAMPING
 				INC_POS_BIDI
-				RENDER_16BIT_SMP_S16INTRP
+				RENDER_16BIT_SMP_S32INTRP
 				VOLUME_RAMPING
 				INC_POS_BIDI
-				RENDER_16BIT_SMP_S16INTRP
+				RENDER_16BIT_SMP_S32INTRP
 				VOLUME_RAMPING
 				INC_POS_BIDI
 			}
@@ -3510,9 +3510,9 @@
 	(mixFunc)mix8bNoLoopLIntrp,
 	(mixFunc)mix8bLoopLIntrp,
 	(mixFunc)mix8bBidiLoopLIntrp,
-	(mixFunc)mix8bNoLoopS16Intrp,
-	(mixFunc)mix8bLoopS16Intrp,
-	(mixFunc)mix8bBidiLoopS16Intrp,
+	(mixFunc)mix8bNoLoopS32Intrp,
+	(mixFunc)mix8bLoopS32Intrp,
+	(mixFunc)mix8bBidiLoopS32Intrp,
 	(mixFunc)mix8bNoLoopCIntrp,
 	(mixFunc)mix8bLoopCIntrp,
 	(mixFunc)mix8bBidiLoopCIntrp,
@@ -3527,9 +3527,9 @@
 	(mixFunc)mix16bNoLoopLIntrp,
 	(mixFunc)mix16bLoopLIntrp,
 	(mixFunc)mix16bBidiLoopLIntrp,
-	(mixFunc)mix16bNoLoopS16Intrp,
-	(mixFunc)mix16bLoopS16Intrp,
-	(mixFunc)mix16bBidiLoopS16Intrp,
+	(mixFunc)mix16bNoLoopS32Intrp,
+	(mixFunc)mix16bLoopS32Intrp,
+	(mixFunc)mix16bBidiLoopS32Intrp,
 	(mixFunc)mix16bNoLoopCIntrp,
 	(mixFunc)mix16bLoopCIntrp,
 	(mixFunc)mix16bBidiLoopCIntrp,
@@ -3546,9 +3546,9 @@
 	(mixFunc)mix8bRampNoLoopLIntrp,
 	(mixFunc)mix8bRampLoopLIntrp,
 	(mixFunc)mix8bRampBidiLoopLIntrp,
-	(mixFunc)mix8bRampNoLoopS16Intrp,
-	(mixFunc)mix8bRampLoopS16Intrp,
-	(mixFunc)mix8bRampBidiLoopS16Intrp,
+	(mixFunc)mix8bRampNoLoopS32Intrp,
+	(mixFunc)mix8bRampLoopS32Intrp,
+	(mixFunc)mix8bRampBidiLoopS32Intrp,
 	(mixFunc)mix8bRampNoLoopCIntrp,
 	(mixFunc)mix8bRampLoopCIntrp,
 	(mixFunc)mix8bRampBidiLoopCIntrp,
@@ -3563,9 +3563,9 @@
 	(mixFunc)mix16bRampNoLoopLIntrp,
 	(mixFunc)mix16bRampLoopLIntrp,
 	(mixFunc)mix16bRampBidiLoopLIntrp,
-	(mixFunc)mix16bRampNoLoopS16Intrp,
-	(mixFunc)mix16bRampLoopS16Intrp,
-	(mixFunc)mix16bRampBidiLoopS16Intrp,
+	(mixFunc)mix16bRampNoLoopS32Intrp,
+	(mixFunc)mix16bRampLoopS32Intrp,
+	(mixFunc)mix16bRampBidiLoopS32Intrp,
 	(mixFunc)mix16bRampNoLoopCIntrp,
 	(mixFunc)mix16bRampLoopCIntrp,
 	(mixFunc)mix16bRampBidiLoopCIntrp
--- a/src/mixer/ft2_mix.h
+++ b/src/mixer/ft2_mix.h
@@ -3,7 +3,7 @@
 #include <stdint.h>
 #include "../ft2_cpu.h"
 
-#define MAX_TAPS 16
+#define MAX_TAPS 32
 #define MAX_LEFT_TAPS ((MAX_TAPS/2)-1)
 #define MAX_RIGHT_TAPS (MAX_TAPS/2)
 
--- a/src/mixer/ft2_mix_macros.h
+++ b/src/mixer/ft2_mix_macros.h
@@ -218,47 +218,79 @@
 }
 #endif
 
-#if SINC16_FSHIFT>=0
-#define WINDOWED_SINC16_INTERPOLATION(s, f, scale) \
+#if SINC32_FSHIFT>=0
+#define WINDOWED_SINC32_INTERPOLATION(s, f, scale) \
 { \
-	const float *t = v->fSincLUT + (((uint32_t)(f) >> SINC16_FSHIFT) & SINC16_FMASK); \
-	fSample = ((s[-7] * t[0]) + \
-	           (s[-6] * t[1]) + \
-	           (s[-5] * t[2]) + \
-	           (s[-4] * t[3]) + \
-	           (s[-3] * t[4]) + \
-	           (s[-2] * t[5]) + \
-	           (s[-1] * t[6]) + \
-	           ( s[0] * t[7]) + \
-	           ( s[1] * t[8]) + \
-	           ( s[2] * t[9]) + \
-	           ( s[3] * t[10]) + \
-	           ( s[4] * t[11]) + \
-	           ( s[5] * t[12]) + \
-	           ( s[6] * t[13]) + \
-	           ( s[7] * t[14]) + \
-	           ( s[8] * t[15])) * (1.0f / scale); \
+	const float *t = v->fSincLUT + (((uint32_t)(f) >> SINC32_FSHIFT) & SINC32_FMASK); \
+	fSample = ((s[-15] * t[0]) + \
+	           (s[-14] * t[1]) + \
+	           (s[-13] * t[2]) + \
+	           (s[-12] * t[3]) + \
+	           (s[-11] * t[4]) + \
+	           (s[-10] * t[5]) + \
+	           ( s[-9] * t[6]) + \
+	           ( s[-8] * t[7]) + \
+	           ( s[-7] * t[8]) + \
+	           ( s[-6] * t[9]) + \
+	           ( s[-5] * t[10]) + \
+	           ( s[-4] * t[11]) + \
+	           ( s[-3] * t[12]) + \
+	           ( s[-2] * t[13]) + \
+	           ( s[-1] * t[14]) + \
+	           (  s[0] * t[15]) + \
+	           (  s[1] * t[16]) + \
+	           (  s[2] * t[17]) + \
+	           (  s[3] * t[18]) + \
+	           (  s[4] * t[19]) + \
+	           (  s[5] * t[20]) + \
+	           (  s[6] * t[21]) + \
+	           (  s[7] * t[22]) + \
+	           (  s[8] * t[23]) + \
+	           (  s[9] * t[24]) + \
+	           ( s[10] * t[25]) + \
+	           ( s[11] * t[26]) + \
+	           ( s[12] * t[27]) + \
+	           ( s[13] * t[28]) + \
+	           ( s[14] * t[29]) + \
+	           ( s[15] * t[30]) + \
+	           ( s[16] * t[31])) * (1.0f / scale); \
 }
 #else
-#define WINDOWED_SINC16_INTERPOLATION(s, f, scale) \
+#define WINDOWED_SINC32_INTERPOLATION(s, f, scale) \
 { \
-	const float *t = v->fSincLUT + (((uint32_t)(f) << -SINC16_FSHIFT) & SINC16_FMASK); \
-	fSample = ((s[-7] * t[0]) + \
-	           (s[-6] * t[1]) + \
-	           (s[-5] * t[2]) + \
-	           (s[-4] * t[3]) + \
-	           (s[-3] * t[4]) + \
-	           (s[-2] * t[5]) + \
-	           (s[-1] * t[6]) + \
-	           ( s[0] * t[7]) + \
-	           ( s[1] * t[8]) + \
-	           ( s[2] * t[9]) + \
-	           ( s[3] * t[10]) + \
-	           ( s[4] * t[11]) + \
-	           ( s[5] * t[12]) + \
-	           ( s[6] * t[13]) + \
-	           ( s[7] * t[14]) + \
-	           ( s[8] * t[15])) * (1.0f / scale); \
+	const float *t = v->fSincLUT + (((uint32_t)(f) << -SINC32_FSHIFT) & SINC32_FMASK); \
+	fSample = ((s[-15] * t[0]) + \
+	           (s[-14] * t[1]) + \
+	           (s[-13] * t[2]) + \
+	           (s[-12] * t[3]) + \
+	           (s[-11] * t[4]) + \
+	           (s[-10] * t[5]) + \
+	           ( s[-9] * t[6]) + \
+	           ( s[-8] * t[7]) + \
+	           ( s[-7] * t[8]) + \
+	           ( s[-6] * t[9]) + \
+	           ( s[-5] * t[10]) + \
+	           ( s[-4] * t[11]) + \
+	           ( s[-3] * t[12]) + \
+	           ( s[-2] * t[13]) + \
+	           ( s[-1] * t[14]) + \
+	           (  s[0] * t[15]) + \
+	           (  s[1] * t[16]) + \
+	           (  s[2] * t[17]) + \
+	           (  s[3] * t[18]) + \
+	           (  s[4] * t[19]) + \
+	           (  s[5] * t[20]) + \
+	           (  s[6] * t[21]) + \
+	           (  s[7] * t[22]) + \
+	           (  s[8] * t[23]) + \
+	           (  s[9] * t[24]) + \
+	           ( s[10] * t[25]) + \
+	           ( s[11] * t[26]) + \
+	           ( s[12] * t[27]) + \
+	           ( s[13] * t[28]) + \
+	           ( s[14] * t[29]) + \
+	           ( s[15] * t[30]) + \
+	           ( s[16] * t[31])) * (1.0f / scale); \
 }
 #endif
 
@@ -272,13 +304,13 @@
 	*fMixBufferL++ += fSample * fVolumeL; \
 	*fMixBufferR++ += fSample * fVolumeR;
 
-#define RENDER_8BIT_SMP_S16INTRP \
-	WINDOWED_SINC16_INTERPOLATION(smpPtr, positionFrac, 128) \
+#define RENDER_8BIT_SMP_S32INTRP \
+	WINDOWED_SINC32_INTERPOLATION(smpPtr, positionFrac, 128) \
 	*fMixBufferL++ += fSample * fVolumeL; \
 	*fMixBufferR++ += fSample * fVolumeR;
 
-#define RENDER_16BIT_SMP_S16INTRP \
-	WINDOWED_SINC16_INTERPOLATION(smpPtr, positionFrac, 32768) \
+#define RENDER_16BIT_SMP_S32INTRP \
+	WINDOWED_SINC32_INTERPOLATION(smpPtr, positionFrac, 32768) \
 	*fMixBufferL++ += fSample * fVolumeL; \
 	*fMixBufferR++ += fSample * fVolumeR;
 
@@ -298,15 +330,15 @@
 	*fMixBufferL++ += fSample * fVolumeL; \
 	*fMixBufferR++ += fSample * fVolumeR;
 
-#define RENDER_8BIT_SMP_S16INTRP_TAP_FIX  \
+#define RENDER_8BIT_SMP_S32INTRP_TAP_FIX  \
 	smpTapPtr = (smpPtr <= leftEdgePtr) ? (int8_t *)&v->leftEdgeTaps8[(int32_t)(smpPtr-loopStartPtr)] : (int8_t *)smpPtr; \
-	WINDOWED_SINC16_INTERPOLATION(smpTapPtr, positionFrac, 128) \
+	WINDOWED_SINC32_INTERPOLATION(smpTapPtr, positionFrac, 128) \
 	*fMixBufferL++ += fSample * fVolumeL; \
 	*fMixBufferR++ += fSample * fVolumeR;
 
-#define RENDER_16BIT_SMP_S16INTRP_TAP_FIX \
+#define RENDER_16BIT_SMP_S32INTRP_TAP_FIX \
 	smpTapPtr = (smpPtr <= leftEdgePtr) ? (int16_t *)&v->leftEdgeTaps16[(int32_t)(smpPtr-loopStartPtr)] : (int16_t *)smpPtr; \
-	WINDOWED_SINC16_INTERPOLATION(smpTapPtr, positionFrac, 32768) \
+	WINDOWED_SINC32_INTERPOLATION(smpTapPtr, positionFrac, 32768) \
 	*fMixBufferL++ += fSample * fVolumeL; \
 	*fMixBufferR++ += fSample * fVolumeR;
 
--- a/src/mixer/ft2_windowed_sinc.c
+++ b/src/mixer/ft2_windowed_sinc.c
@@ -1,7 +1,5 @@
-/* Code taken from the OpenMPT project, which has a BSD license which is
-** compatible with this project.
-**
-** The code has been slightly modified.
+/* The code in this file is based on code from the OpenMPT project,
+** which shares the same coding license as this project.
 */
 
 #include <stdint.h>
@@ -15,24 +13,23 @@
 
 // globalized
 float *fKaiserSinc_8 = NULL, *fDownSample1_8 = NULL, *fDownSample2_8 = NULL;
-float *fKaiserSinc_16 = NULL, *fDownSample1_16 = NULL, *fDownSample2_16 = NULL;
+float *fKaiserSinc_32 = NULL, *fDownSample1_32 = NULL, *fDownSample2_32 = NULL;
 
-// set based on selected sinc interpolator (8 point or 16 point)
+// set based on selected sinc interpolator (8 point or 32 point)
 float *fKaiserSinc = NULL, *fDownSample1 = NULL, *fDownSample2 = NULL;
 
-static double Izero(double y) // Compute Bessel function Izero(y) using a series approximation
+// zeroth-order modified Bessel function of the first kind (series approximation)
+static double besselI0(double z)
 {
-	double s = 1.0, ds = 1.0, d = 0.0;
+	double s = 1.0, ds = 1.0, d = 2.0;
 
-	const double epsilon = 1E-9; // 8bitbubsy: 1E-7 -> 1E-9 for added precision (still fast to calculate)
-
 	do
 	{
-		d = d + 2.0;
-		ds = ds * (y * y) / (d * d);
-		s = s + ds;
+		ds *= (z * z) / (d * d);
+		s += ds;
+		d += 2.0;
 	}
-	while (ds > epsilon * s);
+	while (ds > s*1E-15);
 
 	return s;
 }
@@ -39,7 +36,7 @@
 
 static void getSinc(uint32_t numTaps, float *fLUTPtr, const double beta, const double cutoff)
 {
-	const double izeroBeta = Izero(beta);
+	const double I0Beta = besselI0(beta);
 	const double kPi = MY_PI * cutoff;
 
 	const uint32_t length = numTaps * SINC_PHASES;
@@ -50,18 +47,16 @@
 
 	for (uint32_t i = 0; i < length; i++)
 	{
-		const int32_t ix = ((tapsMinus1 - (i & tapsMinus1)) * SINC_PHASES) + (i >> tapBits);
+		const int32_t ix = ((tapsMinus1 - (i & tapsMinus1)) << SINC_PHASES_BITS) + (i >> tapBits);
 
-		double dSinc;
-		if (ix == midTap)
+		double dSinc = 1.0;
+		if (ix != midTap)
 		{
-			dSinc = 1.0;
-		}
-		else
-		{
 			const double x = (ix - midTap) * (1.0 / SINC_PHASES);
 			const double xPi = x * kPi;
-			dSinc = sin(xPi) * Izero(beta * sqrt(1.0 - x * x * xMul)) / (izeroBeta * xPi); // Kaiser window
+
+			// sinc with Kaiser window
+			dSinc = (sin(xPi) * besselI0(beta * sqrt(1.0 - (x * x * xMul)))) / (I0Beta * xPi);
 		}
 
 		fLUTPtr[i] = (float)(dSinc * cutoff);
@@ -68,30 +63,42 @@
 	}
 }
 
+static double dBToKaiserBeta(double dB)
+{
+	if (dB < 21.0)
+		return 0.0;
+	else if (dB <= 50.0)
+		return 0.5842 * pow(dB - 21.0, 0.4) + 0.07886 * (dB - 21.0);
+	else
+		return 0.1102 * (dB - 8.7);
+}
+
 bool calcWindowedSincTables(void)
-{ 
-	fKaiserSinc_8  = (float *)malloc(8*SINC_PHASES * sizeof (float));
-	fDownSample1_8 = (float *)malloc(8*SINC_PHASES * sizeof (float));
-	fDownSample2_8 = (float *)malloc(8*SINC_PHASES * sizeof (float));
+{
+	fKaiserSinc_8  = (float *)malloc(SINC1_TAPS*SINC_PHASES * sizeof (float));
+	fDownSample1_8 = (float *)malloc(SINC1_TAPS*SINC_PHASES * sizeof (float));
+	fDownSample2_8 = (float *)malloc(SINC1_TAPS*SINC_PHASES * sizeof (float));
 
-	fKaiserSinc_16  = (float *)malloc(16*SINC_PHASES * sizeof (float));
-	fDownSample1_16 = (float *)malloc(16*SINC_PHASES * sizeof (float));
-	fDownSample2_16 = (float *)malloc(16*SINC_PHASES * sizeof (float));
+	fKaiserSinc_32  = (float *)malloc(SINC2_TAPS*SINC_PHASES * sizeof (float));
+	fDownSample1_32 = (float *)malloc(SINC2_TAPS*SINC_PHASES * sizeof (float));
+	fDownSample2_32 = (float *)malloc(SINC2_TAPS*SINC_PHASES * sizeof (float));
 
 	if (fKaiserSinc_8  == NULL || fDownSample1_8  == NULL || fDownSample2_8  == NULL ||
-		fKaiserSinc_16 == NULL || fDownSample1_16 == NULL || fDownSample2_16 == NULL)
+		fKaiserSinc_32 == NULL || fDownSample1_32 == NULL || fDownSample2_32 == NULL)
 	{
 		showErrorMsgBox("Not enough memory!");
 		return false;
 	}
 
-	getSinc(8, fKaiserSinc_8, 9.6377, 1.0);
-	getSinc(8, fDownSample1_8, 8.5, 0.5);
-	getSinc(8, fDownSample2_8, 7.3, 0.425);
+	// 8 point (modelled after OpenMPT)
+	getSinc(SINC1_TAPS, fKaiserSinc_8,  dBToKaiserBeta(96.15645), 1.000);
+	getSinc(SINC1_TAPS, fDownSample1_8, dBToKaiserBeta(85.83249), 0.500);
+	getSinc(SINC1_TAPS, fDownSample2_8, dBToKaiserBeta(72.22088), 0.425);
 
-	getSinc(16, fKaiserSinc_16, 9.6377, 1.0);
-	getSinc(16, fDownSample1_16, 8.5, 0.5);
-	getSinc(16, fDownSample2_16, 7.3, 0.425);
+	// 32 point
+	getSinc(SINC2_TAPS, fKaiserSinc_32,  dBToKaiserBeta(96.0), 1.000);
+	getSinc(SINC2_TAPS, fDownSample1_32, dBToKaiserBeta(86.0), 0.500);
+	getSinc(SINC2_TAPS, fDownSample2_32, dBToKaiserBeta(74.0), 0.425);
 
 	return true;
 }
@@ -116,21 +123,21 @@
 		fDownSample2_8 = NULL;
 	}
 
-	if (fKaiserSinc_16 != NULL)
+	if (fKaiserSinc_32 != NULL)
 	{
-		free(fKaiserSinc_16);
-		fKaiserSinc_16 = NULL;
+		free(fKaiserSinc_32);
+		fKaiserSinc_32 = NULL;
 	}
 
-	if (fDownSample1_16 != NULL)
+	if (fDownSample1_32 != NULL)
 	{
-		free(fDownSample1_16);
-		fDownSample1_16 = NULL;
+		free(fDownSample1_32);
+		fDownSample1_32 = NULL;
 	}
 
-	if (fDownSample2_16 != NULL)
+	if (fDownSample2_32 != NULL)
 	{
-		free(fDownSample2_16);
-		fDownSample2_16 = NULL;
+		free(fDownSample2_32);
+		fDownSample2_32 = NULL;
 	}
 }
--- a/src/mixer/ft2_windowed_sinc.h
+++ b/src/mixer/ft2_windowed_sinc.h
@@ -9,15 +9,19 @@
 #define SINC_PHASES_BITS 13 // log2(SINC_PHASES)
 
 // do not change these!
-#define SINC8_WIDTH_BITS 3 // log2(8)
+
+#define SINC1_TAPS 8
+#define SINC8_WIDTH_BITS 3 // log2(SINC1_TAPS)
 #define SINC8_FSHIFT (MIXER_FRAC_BITS-(SINC_PHASES_BITS+SINC8_WIDTH_BITS))
-#define SINC8_FMASK ((8*SINC_PHASES)-8)
-#define SINC16_WIDTH_BITS 4 // log2(16)
-#define SINC16_FSHIFT (MIXER_FRAC_BITS-(SINC_PHASES_BITS+SINC16_WIDTH_BITS))
-#define SINC16_FMASK ((16*SINC_PHASES)-16)
+#define SINC8_FMASK ((SINC1_TAPS*SINC_PHASES)-SINC1_TAPS)
 
+#define SINC2_TAPS 32
+#define SINC32_WIDTH_BITS 5 // log2(SINC2_TAPS)
+#define SINC32_FSHIFT (MIXER_FRAC_BITS-(SINC_PHASES_BITS+SINC32_WIDTH_BITS))
+#define SINC32_FMASK ((SINC2_TAPS*SINC_PHASES)-SINC2_TAPS)
+
 extern float *fKaiserSinc_8, *fDownSample1_8, *fDownSample2_8;
-extern float *fKaiserSinc_16, *fDownSample1_16, *fDownSample2_16;
+extern float *fKaiserSinc_32, *fDownSample1_32, *fDownSample2_32;
 
 extern float *fKaiserSinc, *fDownSample1, *fDownSample2;