View Issue Details

IDProjectCategoryView StatusLast Update
0001102OpenMPTAudio I/Opublic2018-11-25 17:55
ReporterIsaacNorman Assigned Tomanx  
PrioritylowSeverityfeatureReproducibilityN/A
Status resolvedResolutionfixed 
Platformx64OSWindowsOS Version10
Product VersionOpenMPT 1.27.06.00 / libopenmpt 0.3.7 (upgrade first) 
Target VersionOpenMPT 1.28.01.00 / libopenmpt 0.4.0 (upgrade first)Fixed in VersionOpenMPT 1.28.01.00 / libopenmpt 0.4.0 (upgrade first) 
Summary0001102: Rename interpolation filters (was: Sinc interpolation for audio)
Description

I've been using OpenMPT for almost 10 years, and while I didn't find a use for it then, I see one now. I'd like to ask if there will ever be an implementation of sinc interpolation for samples? If this already exists with the current interpolations, then how do I adjust them so they "are" sinc interpolation? (Or at least "close enough"?)

I see MilkyTracker has 2 sinc interpolation methods, one being more precise than the other because of having a higher lookup table than the other. (Albeit it is much slower with complex modules.)

This would save me trouble of having to export my .mptm modules to .xm and then having to lose all of my VST support, which MilkyTracker does not support unfortunately... :\

TagsNo tags attached.
Attached Files
resampler-cleanup-v3.patch (28,918 bytes)   
Index: common/versionNumber.h
===================================================================
--- common/versionNumber.h	(revision 9968)
+++ common/versionNumber.h	(working copy)
@@ -19,7 +19,7 @@
 #define VER_MAJORMAJOR          1
 #define VER_MAJOR               28
 #define VER_MINOR               00
-#define VER_MINORMINOR          15
+#define VER_MINORMINOR          16
 
 //Version string. For example "1.17.02.28"
 #define MPT_VERSION_STR         VER_STRINGIZE(VER_MAJORMAJOR) "." VER_STRINGIZE(VER_MAJOR) "." VER_STRINGIZE(VER_MINOR) "." VER_STRINGIZE(VER_MINORMINOR)
Index: libopenmpt/libopenmpt_impl.cpp
===================================================================
--- libopenmpt/libopenmpt_impl.cpp	(revision 9968)
+++ libopenmpt/libopenmpt_impl.cpp	(working copy)
@@ -316,13 +316,13 @@
 }
 
 static ResamplingMode filterlength_to_resamplingmode(std::int32_t length) {
-	ResamplingMode result = SRCMODE_POLYPHASE;
+	ResamplingMode result = SRCMODE_SINC8LP;
 	if ( length == 0 ) {
-		result = SRCMODE_POLYPHASE;
+		result = SRCMODE_SINC8LP;
 	} else if ( length >= 8 ) {
-		result = SRCMODE_POLYPHASE;
+		result = SRCMODE_SINC8LP;
 	} else if ( length >= 3 ) {
-		result = SRCMODE_SPLINE;
+		result = SRCMODE_CUBIC;
 	} else if ( length >= 2 ) {
 		result = SRCMODE_LINEAR;
 	} else if ( length >= 1 ) {
@@ -340,11 +340,11 @@
 	case SRCMODE_LINEAR:
 		return 2;
 		break;
-	case SRCMODE_SPLINE:
+	case SRCMODE_CUBIC:
 		return 4;
 		break;
-	case SRCMODE_POLYPHASE:
-	case SRCMODE_FIRFILTER:
+	case SRCMODE_SINC8:
+	case SRCMODE_SINC8LP:
 	case SRCMODE_DEFAULT:
 		return 8;
 	default:
Index: mptrack/Ctrl_gen.cpp
===================================================================
--- mptrack/Ctrl_gen.cpp	(revision 9968)
+++ mptrack/Ctrl_gen.cpp	(working copy)
@@ -202,21 +202,21 @@
 	FlagSet<HintType> hintType = hint.GetType();
 	const bool updateAll = hintType[HINT_MODTYPE];
 
-	const ResamplingMode resamplingModes[] = { SRCMODE_NEAREST, SRCMODE_LINEAR, SRCMODE_SPLINE, SRCMODE_POLYPHASE, SRCMODE_FIRFILTER };
+	const auto resamplingModes = Resampling::AllModes();
 
 	if (hintType == HINT_MPTOPTIONS || updateAll)
 	{
-		const TCHAR *defaultResampler;
+		CString defaultResampler;
 		if(m_sndFile.m_SongFlags[SONG_ISAMIGA] && TrackerSettings::Instance().ResamplerEmulateAmiga)
 			defaultResampler = _T("Amiga Resampler");
 		else
-			defaultResampler = CTrackApp::GetResamplingModeName(TrackerSettings::Instance().ResamplerMode, false);
+			defaultResampler = CTrackApp::GetResamplingModeName(TrackerSettings::Instance().ResamplerMode, 1, false);
 
 		m_CbnResampling.ResetContent();
-		m_CbnResampling.SetItemData(m_CbnResampling.AddString(_T("Default (") + CString(defaultResampler) + _T(")")), SRCMODE_DEFAULT);
+		m_CbnResampling.SetItemData(m_CbnResampling.AddString(_T("Default (") + defaultResampler + _T(")")), SRCMODE_DEFAULT);
 		for(auto mode : resamplingModes)
 		{
-			m_CbnResampling.SetItemData(m_CbnResampling.AddString(CTrackApp::GetResamplingModeName(mode, false)), mode);
+			m_CbnResampling.SetItemData(m_CbnResampling.AddString(CTrackApp::GetResamplingModeName(mode, 2, true)), mode);
 		}
 		m_CbnResampling.Invalidate(FALSE);
 	}
@@ -312,12 +312,13 @@
 
 	if(updateAll || hintType == HINT_MPTOPTIONS || (hint.GetCategory() == HINTCAT_GENERAL && hintType[HINT_MODGENERAL]))
 	{
+
 		int srcMode = 0;
-		for(int i = 0; i < CountOf(resamplingModes); i++)
+		for(int i = 0; i < m_CbnResampling.GetCount(); ++i)
 		{
-			if(m_sndFile.m_nResampling == resamplingModes[i]) srcMode = i + 1;
+			if(m_sndFile.m_nResampling == static_cast<int>(m_CbnResampling.GetItemData(i)))
+				m_CbnResampling.SetCurSel(i);
 		}
-		m_CbnResampling.SetCurSel(srcMode);
 	}
 
 	CheckDlgButton(IDC_CHECK_LOOPSONG, (TrackerSettings::Instance().gbLoopSong) ? TRUE : FALSE);
Index: mptrack/Ctrl_ins.cpp
===================================================================
--- mptrack/Ctrl_ins.cpp	(revision 9968)
+++ mptrack/Ctrl_ins.cpp	(working copy)
@@ -995,12 +995,12 @@
 	m_EditPWD.SubclassDlgItem(IDC_PITCHWHEELDEPTH, this);
 	m_EditPWD.AllowFractions(false);
 
+	const auto resamplingModes = Resampling::AllModes();
 	m_CbnResampling.SetItemData(m_CbnResampling.AddString(_T("Default")), SRCMODE_DEFAULT);
-	m_CbnResampling.SetItemData(m_CbnResampling.AddString(_T("None")), SRCMODE_NEAREST);
-	m_CbnResampling.SetItemData(m_CbnResampling.AddString(_T("Linear")), SRCMODE_LINEAR);
-	m_CbnResampling.SetItemData(m_CbnResampling.AddString(_T("Spline")), SRCMODE_SPLINE);
-	m_CbnResampling.SetItemData(m_CbnResampling.AddString(_T("Polyphase")), SRCMODE_POLYPHASE);
-	m_CbnResampling.SetItemData(m_CbnResampling.AddString(_T("XMMS")), SRCMODE_FIRFILTER);
+	for(auto mode : resamplingModes)
+	{
+		m_CbnResampling.SetItemData(m_CbnResampling.AddString(CTrackApp::GetResamplingModeName(mode, 1, false)), mode);
+	}
 
 	m_CbnFilterMode.SetItemData(m_CbnFilterMode.AddString(_T("Channel default")), FLTMODE_UNCHANGED);
 	m_CbnFilterMode.SetItemData(m_CbnFilterMode.AddString(_T("Force lowpass")), FLTMODE_LOWPASS);
Index: mptrack/Mpdlgs.cpp
===================================================================
--- mptrack/Mpdlgs.cpp	(revision 9968)
+++ mptrack/Mpdlgs.cpp	(working copy)
@@ -928,9 +928,7 @@
 	ON_WM_HSCROLL()
 	ON_WM_VSCROLL()
 	ON_CBN_SELCHANGE(IDC_COMBO_FILTER,			OnResamplerChanged)
-	ON_CBN_SELCHANGE(IDC_COMBO_FILTERWINDOW,	OnSettingsChanged)
 	ON_CBN_SELCHANGE(IDC_COMBO_POLYPHONY,		OnSettingsChanged)
-	ON_EN_UPDATE(IDC_WFIRCUTOFF,				OnSettingsChanged)
 	ON_EN_UPDATE(IDC_RAMPING_IN,				OnRampingChanged)
 	ON_EN_UPDATE(IDC_RAMPING_OUT,				OnRampingChanged)
 	ON_COMMAND(IDC_CHECK_SOFTPAN,				OnSettingsChanged)
@@ -943,8 +941,6 @@
 	CPropertyPage::DoDataExchange(pDX);
 	//{{AFX_DATA_MAP(COptionsSoundcard)
 	DDX_Control(pDX, IDC_COMBO_FILTER, m_CbnResampling);
-	DDX_Control(pDX, IDC_WFIRCUTOFF, m_CEditWFIRCutoff);
-	DDX_Control(pDX, IDC_COMBO_FILTERWINDOW, m_CbnWFIRType);
 	DDX_Control(pDX, IDC_RAMPING_IN, m_CEditRampUp);
 	DDX_Control(pDX, IDC_RAMPING_OUT, m_CEditRampDown);
 	DDX_Control(pDX, IDC_EDIT_VOLRAMP_SAMPLES_UP, m_CInfoRampUp);
@@ -963,26 +959,18 @@
 
 	// Resampling type
 	{
-		for(auto mode : { SRCMODE_NEAREST, SRCMODE_LINEAR, SRCMODE_SPLINE, SRCMODE_POLYPHASE, SRCMODE_FIRFILTER })
+		const auto resamplingModes = Resampling::AllModes();
+		for(auto mode : resamplingModes)
 		{
-			int index = m_CbnResampling.AddString(CTrackApp::GetResamplingModeName(mode, true));
+			int index = m_CbnResampling.AddString(CTrackApp::GetResamplingModeName(mode, 2, true));
 			m_CbnResampling.SetItemData(index, mode);
 			if(TrackerSettings::Instance().ResamplerMode == mode)
+			{
 				m_CbnResampling.SetCurSel(index);
+			}
 		}
 	}
 
-	// Resampler bandwidth
-	{
-		m_CEditWFIRCutoff.SetWindowText(mpt::ToCString(mpt::ufmt::val(TrackerSettings::Instance().ResamplerCutoffPercent)));
-		static_cast<CSpinButtonCtrl *>(GetDlgItem(IDC_SPIN1))->SetRange32(1, 99);
-	}
-
-	// Resampler filter window
-	{
-		// done in OnResamplerChanged()
-	}
-
 	// Amiga Resampler
 	CheckDlgButton(IDC_CHECK1, TrackerSettings::Instance().ResamplerEmulateAmiga ? BST_CHECKED : BST_UNCHECKED);
 
@@ -1037,7 +1025,6 @@
 		m_SliderPreAmp.SetPos(n);
 	}
 
-	OnResamplerChanged();
 	m_initialized = true;
 
 	return TRUE;
@@ -1053,61 +1040,6 @@
 
 void COptionsMixer::OnResamplerChanged()
 {
-	ResamplingMode srcMode = static_cast<ResamplingMode>(m_CbnResampling.GetItemData(m_CbnResampling.GetCurSel()));
-	m_CbnWFIRType.ResetContent();
-	switch(srcMode)
-	{
-		case SRCMODE_FIRFILTER:
-			m_CbnWFIRType.AddString(_T("Hann"));
-			m_CbnWFIRType.AddString(_T("Hamming"));
-			m_CbnWFIRType.AddString(_T("Blackman Exact"));
-			m_CbnWFIRType.AddString(_T("Blackman 3 Tap 61"));
-			m_CbnWFIRType.AddString(_T("Blackman 3 Tap 67"));
-			m_CbnWFIRType.AddString(_T("Blackman Harris"));
-			m_CbnWFIRType.AddString(_T("Blackman 4 Tap 74"));
-			m_CbnWFIRType.AddString(_T("Kaiser a=7.5"));
-			break;
-		case SRCMODE_POLYPHASE:
-			m_CbnWFIRType.AddString(_T("Auto"));
-			m_CbnWFIRType.AddString(_T("Auto"));
-			m_CbnWFIRType.AddString(_T("Auto"));
-			m_CbnWFIRType.AddString(_T("Auto"));
-			m_CbnWFIRType.AddString(_T("Auto"));
-			m_CbnWFIRType.AddString(_T("Auto"));
-			m_CbnWFIRType.AddString(_T("Auto"));
-			m_CbnWFIRType.AddString(_T("Auto"));
-			break;
-		default:
-			m_CbnWFIRType.AddString(_T("none"));
-			m_CbnWFIRType.AddString(_T("none"));
-			m_CbnWFIRType.AddString(_T("none"));
-			m_CbnWFIRType.AddString(_T("none"));
-			m_CbnWFIRType.AddString(_T("none"));
-			m_CbnWFIRType.AddString(_T("none"));
-			m_CbnWFIRType.AddString(_T("none"));
-			m_CbnWFIRType.AddString(_T("none"));
-			break;
-	}
-	m_CbnWFIRType.SetCurSel(TrackerSettings::Instance().ResamplerSubMode);
-	CSpinButtonCtrl *spinWFIRCutoff = static_cast<CSpinButtonCtrl *>(GetDlgItem(IDC_SPIN1));
-	switch(srcMode)
-	{
-		case SRCMODE_POLYPHASE:
-			m_CEditWFIRCutoff.EnableWindow(FALSE);
-			spinWFIRCutoff->EnableWindow(FALSE);
-			m_CbnWFIRType.EnableWindow(FALSE);
-			break;
-		case SRCMODE_FIRFILTER:
-			m_CEditWFIRCutoff.EnableWindow(TRUE);
-			spinWFIRCutoff->EnableWindow(TRUE);
-			m_CbnWFIRType.EnableWindow(TRUE);
-			break;
-		default:
-			m_CEditWFIRCutoff.EnableWindow(FALSE);
-			spinWFIRCutoff->EnableWindow(FALSE);
-			m_CbnWFIRType.EnableWindow(FALSE);
-			break;
-	}
 	OnSettingsChanged();
 }
 
@@ -1162,27 +1094,6 @@
 		TrackerSettings::Instance().ResamplerMode = static_cast<ResamplingMode>(m_CbnResampling.GetItemData(m_CbnResampling.GetCurSel()));
 	}
 
-	// resampler bandwidth
-	{
-		CString s;
-		m_CEditWFIRCutoff.GetWindowText(s);
-		if(s != "")
-		{
-			int newCutoff = ConvertStrTo<int>(s);
-			Limit(newCutoff, 0, 100);
-			TrackerSettings::Instance().ResamplerCutoffPercent = newCutoff;
-		}
-		{
-			s.Format(_T("%d"), TrackerSettings::Instance().ResamplerCutoffPercent.Get());
-			m_CEditWFIRCutoff.SetWindowText(s);
-		}
-	}
-
-	// resampler filter window
-	{
-		TrackerSettings::Instance().ResamplerSubMode = (uint8)m_CbnWFIRType.GetCurSel();
-	}
-
 	// Amiga Resampler
 	TrackerSettings::Instance().ResamplerEmulateAmiga = IsDlgButtonChecked(IDC_CHECK1) != BST_UNCHECKED;
 
Index: mptrack/Mpdlgs.h
===================================================================
--- mptrack/Mpdlgs.h	(revision 9968)
+++ mptrack/Mpdlgs.h	(working copy)
@@ -88,8 +88,6 @@
 protected:
 
 	CComboBox m_CbnResampling;
-	CEdit m_CEditWFIRCutoff;
-	CComboBox m_CbnWFIRType;
 
 	CEdit m_CEditRampUp;
 	CEdit m_CEditRampDown;
Index: mptrack/Mptrack.cpp
===================================================================
--- mptrack/Mptrack.cpp	(revision 9968)
+++ mptrack/Mptrack.cpp	(working copy)
@@ -1995,24 +1995,39 @@
 }
 
 
-const TCHAR *CTrackApp::GetResamplingModeName(ResamplingMode mode, bool addTaps)
+CString CTrackApp::GetResamplingModeName(ResamplingMode mode, int length, bool addTaps)
 {
+	CString result;
 	switch(mode)
 	{
 	case SRCMODE_NEAREST:
-		return addTaps ? _T("No Interpolation (1 tap)") : _T("No Interpolation");
+		result = (length > 1) ? _T("No Interpolation") : _T("None") ;
+		break;
 	case SRCMODE_LINEAR:
-		return addTaps ? _T("Linear (2 tap)") : _T("Linear");
-	case SRCMODE_SPLINE:
-		return addTaps ? _T("Cubic Spline (4 tap)") :  _T("Cubic Spline");
-	case SRCMODE_POLYPHASE:
-		return addTaps ? _T("Polyphase (8 tap)") : _T("Polyphase");
-	case SRCMODE_FIRFILTER:
-		return addTaps ? _T("XMMS-ModPlug (8 tap)") : _T("XMMS-ModPlug");
+		result = _T("Linear");
+		break;
+	case SRCMODE_CUBIC:
+		result = (length > 1) ? _T("Cubic Spline") : _T("Cubic");
+		break;
+	case SRCMODE_SINC8:
+		result = _T("Sinc");
+		break;
+	case SRCMODE_SINC8LP:
+		result = _T("Sinc");
+		break;
 	default:
 		MPT_ASSERT_NOTREACHED();
+		break;
 	}
-	return _T("");
+	if(Resampling::HasAA(mode))
+	{
+		result += (length > 1) ? _T(" + Low-Pass") : _T(" + LP");
+	}
+	if(addTaps)
+	{
+		result += mpt::cformat(_T(" (%1 tap%2)"))(Resampling::Length(mode), (Resampling::Length(mode) != 1) ? CString(_T("s")) : CString(_T("")));
+	}
+	return result;
 }
 
 
Index: mptrack/Mptrack.h
===================================================================
--- mptrack/Mptrack.h	(revision 9968)
+++ mptrack/Mptrack.h	(working copy)
@@ -268,7 +268,7 @@
 
 public:
 	// Get name of resampling mode. addTaps = true also adds the number of taps the filter uses.
-	static const TCHAR *GetResamplingModeName(ResamplingMode mode, bool addTaps);
+	static CString GetResamplingModeName(ResamplingMode mode, int length, bool addTaps);
 
 // Overrides
 public:
Index: mptrack/mptrack.rc
===================================================================
--- mptrack/mptrack.rc	(revision 9968)
+++ mptrack/mptrack.rc	(working copy)
@@ -1981,15 +1981,9 @@
 BEGIN
     GROUPBOX        "Resampling",IDC_STATIC,6,6,276,48
     LTEXT           "&Filter:",IDC_STATIC,12,18,24,12,SS_CENTERIMAGE
-    COMBOBOX        IDC_COMBO_FILTER,54,18,96,56,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
-    LTEXT           "&Window:",IDC_STATIC,156,18,30,12,SS_CENTERIMAGE
-    COMBOBOX        IDC_COMBO_FILTERWINDOW,192,18,84,56,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
-    LTEXT           "&Bandwidth:",IDC_STATIC,12,36,42,12,SS_CENTERIMAGE
-    EDITTEXT        IDC_WFIRCUTOFF,54,36,30,12,ES_RIGHT | ES_AUTOHSCROLL | ES_NUMBER
-    CONTROL         "",IDC_SPIN1,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_NOTHOUSANDS,71,31,11,14
-    LTEXT           "%",IDC_STATIC,90,36,24,12,SS_CENTERIMAGE
+    COMBOBOX        IDC_COMBO_FILTER,36,18,102,56,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
     CONTROL         "Use &Amiga resampler for Amiga modules",IDC_CHECK1,
-                    "Button",BS_AUTOCHECKBOX | WS_TABSTOP,126,36,150,12
+                    "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,36,144,12
     GROUPBOX        "Volume Ramping",IDC_STATIC,6,60,276,48
     EDITTEXT        IDC_RAMPING_IN,12,72,36,12,ES_RIGHT | ES_AUTOHSCROLL | ES_NUMBER
     CONTROL         "",IDC_SPIN2,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_NOTHOUSANDS,42,66,11,14
Index: mptrack/resource.h
===================================================================
--- mptrack/resource.h	(revision 9968)
+++ mptrack/resource.h	(working copy)
@@ -684,8 +684,6 @@
 #define IDC_COMMAND_LIST                2129
 #define IDC_STATIC8                     2200
 #define IDC_PATINSTROPLUGGUI            2201
-#define IDC_WFIRCUTOFF                  2202
-#define IDC_WFIRTYPE                    2203
 #define IDC_RAMPING_IN                  2204
 #define IDC_PLAYEROPTIONS               2205
 #define IDC_RAMPING_OUT                 2205
Index: mptrack/SampleEditorDialogs.cpp
===================================================================
--- mptrack/SampleEditorDialogs.cpp	(revision 9968)
+++ mptrack/SampleEditorDialogs.cpp	(working copy)
@@ -530,12 +530,12 @@
 
 	CComboBox *cbnResampling = static_cast<CComboBox *>(GetDlgItem(IDC_COMBO_FILTER));
 	cbnResampling->SetRedraw(FALSE);
-	const ResamplingMode resamplingModes[] = { SRCMODE_NEAREST, SRCMODE_LINEAR, SRCMODE_SPLINE, SRCMODE_POLYPHASE, SRCMODE_FIRFILTER, SRCMODE_DEFAULT };
+	const auto resamplingModes = Resampling::AllModesWithDefault();
 	for(auto mode : resamplingModes)
 	{
-		const TCHAR *desc = _T("r8brain (High Quality)");
+		CString desc = _T("r8brain (High Quality)");
 		if(mode != SRCMODE_DEFAULT)
-			desc = CTrackApp::GetResamplingModeName(mode, false);
+			desc = CTrackApp::GetResamplingModeName(mode, 1, true);
 
 		int index = cbnResampling->AddString(desc);
 		cbnResampling->SetItemData(index, mode);
Index: mptrack/TrackerSettings.cpp
===================================================================
--- mptrack/TrackerSettings.cpp	(revision 9968)
+++ mptrack/TrackerSettings.cpp	(working copy)
@@ -76,29 +76,6 @@
 }
 
 
-static ResamplingMode GetDefaultResamplerMode()
-{
-	ResamplingMode result = CResamplerSettings().SrcMode;
-#ifdef ENABLE_ASM
-	// rough heuristic to select less cpu consuming defaults for old CPUs
-	if(GetRealProcSupport() & PROCSUPPORT_SSE)
-	{
-		result = SRCMODE_POLYPHASE;
-	} else if(GetRealProcSupport() & PROCSUPPORT_MMX)
-	{
-		result = SRCMODE_SPLINE;
-	} else
-	{
-		result = SRCMODE_LINEAR;
-	}
-#else
-	// just use a sane default
-	result = CResamplerSettings().SrcMode;
-#endif
-	return result;
-}
-
-
 static uint32 GetDefaultPatternSetup()
 {
 	return PATTERN_PLAYNEWNOTE | PATTERN_EFFECTHILIGHT
@@ -246,7 +223,7 @@
 	, MixerStereoSeparation(conf, MPT_USTRING("Sound Settings"), MPT_USTRING("StereoSeparation"), MixerSettings().m_nStereoSeparation)
 	, MixerVolumeRampUpMicroseconds(conf, MPT_USTRING("Sound Settings"), MPT_USTRING("VolumeRampUpMicroseconds"), MixerSettings().GetVolumeRampUpMicroseconds())
 	, MixerVolumeRampDownMicroseconds(conf, MPT_USTRING("Sound Settings"), MPT_USTRING("VolumeRampDownMicroseconds"), MixerSettings().GetVolumeRampDownMicroseconds())
-	, ResamplerMode(conf, MPT_USTRING("Sound Settings"), MPT_USTRING("SrcMode"), GetDefaultResamplerMode())
+	, ResamplerMode(conf, MPT_USTRING("Sound Settings"), MPT_USTRING("SrcMode"), CResamplerSettings().SrcMode)
 	, ResamplerSubMode(conf, MPT_USTRING("Sound Settings"), MPT_USTRING("XMMSModplugResamplerWFIRType"), CResamplerSettings().gbWFIRType)
 	, ResamplerCutoffPercent(conf, MPT_USTRING("Sound Settings"), MPT_USTRING("ResamplerWFIRCutoff"), Util::Round<int32>(CResamplerSettings().gdWFIRCutoff * 100.0))
 	, ResamplerEmulateAmiga(conf, MPT_USTRING("Sound Settings"), MPT_USTRING("ResamplerEmulateAmiga"), false)
@@ -548,6 +525,13 @@
 		m_SoundDeviceSettingsDefaults.UseHardwareTiming = m_SoundDeviceUseHardwareTiming;
 		m_SoundDeviceSettingsUseOldDefaults = true;
 	}
+	if(storedVersion < MAKE_VERSION_NUMERIC(1,28,00,16))
+	{
+		// reset this setting to the default when updating,
+		// because we do not provide a GUI any more,
+		// and in general, it should not get changed anyway
+		ResamplerCutoffPercent = Util::Round<int32>(CResamplerSettings().gdWFIRCutoff * 100.0);
+	}
 	if(storedVersion < MAKE_VERSION_NUMERIC(1,25,00,04))
 	{
 		m_SoundDeviceDirectSoundOldDefaultIdentifier = true;
@@ -680,7 +664,7 @@
 	}
 
 	// Sanitize resampling mode for sample editor
-	if(!IsKnownResamplingMode(sampleEditorDefaultResampler) && sampleEditorDefaultResampler != SRCMODE_DEFAULT)
+	if(!Resampling::IsKnownMode(sampleEditorDefaultResampler) && sampleEditorDefaultResampler != SRCMODE_DEFAULT)
 	{
 		sampleEditorDefaultResampler = SRCMODE_DEFAULT;
 	}
Index: soundlib/Load_it.cpp
===================================================================
--- soundlib/Load_it.cpp	(revision 9968)
+++ soundlib/Load_it.cpp	(working copy)
@@ -2357,7 +2357,7 @@
 			case MagicBE("RP.."): if(GetType() != MOD_TYPE_XM) { ORDERINDEX restartPos; ReadField(chunk, size, restartPos); Order().SetRestartPos(restartPos); } break;
 			case MagicLE("RSMP"):
 				ReadFieldCast(chunk, size, m_nResampling);
-				if(!IsKnownResamplingMode(m_nResampling)) m_nResampling = SRCMODE_DEFAULT;
+				if(!Resampling::IsKnownMode(m_nResampling)) m_nResampling = SRCMODE_DEFAULT;
 				break;
 #ifdef MODPLUG_TRACKER
 			case MagicBE("MIMA"): GetMIDIMapper().Deserialize(chunk); break;
Index: soundlib/MixFuncTable.cpp
===================================================================
--- soundlib/MixFuncTable.cpp	(revision 9968)
+++ soundlib/MixFuncTable.cpp	(working copy)
@@ -79,9 +79,9 @@
 	{
 	case SRCMODE_NEAREST:   return ndxNoInterpolation;
 	case SRCMODE_LINEAR:    return ndxLinear;
-	case SRCMODE_SPLINE:    return ndxFastSinc;
-	case SRCMODE_POLYPHASE: return ndxKaiser;
-	case SRCMODE_FIRFILTER: return ndxFIRFilter;
+	case SRCMODE_CUBIC:     return ndxFastSinc;
+	case SRCMODE_SINC8LP:   return ndxKaiser;
+	case SRCMODE_SINC8:     return ndxFIRFilter;
 	case SRCMODE_AMIGA:     return ndxAmigaBlep;
 	default:                MPT_ASSERT_NOTREACHED();
 	}
Index: soundlib/Resampler.h
===================================================================
--- soundlib/Resampler.h	(revision 9968)
+++ soundlib/Resampler.h	(working copy)
@@ -59,12 +59,12 @@
 	uint8 gbWFIRType;
 	bool emulateAmiga;
 public:
-	CResamplerSettings()
+	MPT_CONSTEXPR11_FUN CResamplerSettings()
+		: SrcMode(Resampling::Default())
+		, gdWFIRCutoff(0.97)
+		, gbWFIRType(WFIR_KAISER4T)
+		, emulateAmiga(false)
 	{
-		SrcMode = SRCMODE_POLYPHASE;
-		gdWFIRCutoff = 0.97;
-		gbWFIRType = WFIR_KAISER4T;
-		emulateAmiga = false;
 	}
 	bool operator == (const CResamplerSettings &cmp) const
 	{
@@ -125,8 +125,6 @@
 	{
 		InitializeTablesFromScratch(false);
 	}
-	~CResampler() {}
-	bool IsHQ() const { return m_Settings.SrcMode >= SRCMODE_SPLINE && m_Settings.SrcMode < SRCMODE_DEFAULT; }
 private:
 	void InitFloatmixerTables();
 	void InitializeTablesFromScratch(bool force=false);
Index: soundlib/Snd_defs.h
===================================================================
--- soundlib/Snd_defs.h	(revision 9968)
+++ soundlib/Snd_defs.h	(working copy)
@@ -290,22 +290,55 @@
 {
 	// ATTENTION: Do not change ANY of these values, as they get written out to files in per instrument interpolation settings
 	// and old files have these exact values in them which should not change meaning.
-	SRCMODE_NEAREST   = 0,
-	SRCMODE_LINEAR    = 1,
-	SRCMODE_SPLINE    = 2,
-	SRCMODE_POLYPHASE = 3,
-	SRCMODE_FIRFILTER = 4,
-	SRCMODE_DEFAULT   = 5,
+	SRCMODE_NEAREST   = 0,  // 1 tap, no AA
+	SRCMODE_LINEAR    = 1,  // 2 tap, no AA
+	SRCMODE_CUBIC     = 2,  // 4 tap, no AA
+	SRCMODE_SINC8     = 4,  // 8 tap, no AA   (yes, index 4) (XMMS-ModPlug)
+	SRCMODE_SINC8LP   = 3,  // 8 tap, with AA (yes, index 3) (Polyphase)
 
-	SRCMODE_AMIGA = 0xFF,	// Not explicitely user-selectable
+	SRCMODE_DEFAULT   = 5,  // only used for instrument settings, not used inside the mixer
+
+	SRCMODE_AMIGA  = 0xFF,  // Not explicitely user-selectable
 };
 
-static inline bool IsKnownResamplingMode(int mode)
+namespace Resampling
 {
-	return (mode >= 0) && (mode < SRCMODE_DEFAULT);
+
+static inline std::array<ResamplingMode, 5> AllModes() noexcept { return { SRCMODE_NEAREST, SRCMODE_LINEAR, SRCMODE_CUBIC, SRCMODE_SINC8, SRCMODE_SINC8LP }; }
+
+static inline std::array<ResamplingMode, 6> AllModesWithDefault() noexcept { return { SRCMODE_NEAREST, SRCMODE_LINEAR, SRCMODE_CUBIC, SRCMODE_SINC8, SRCMODE_SINC8LP, SRCMODE_DEFAULT }; }
+
+static MPT_CONSTEXPR11_FUN ResamplingMode Default() noexcept { return SRCMODE_SINC8LP; }
+
+static MPT_CONSTEXPR11_FUN bool IsKnownMode(int mode) noexcept { return (mode >= 0) && (mode < SRCMODE_DEFAULT); }
+
+static MPT_CONSTEXPR11_FUN ResamplingMode ToKnownMode(int mode) noexcept
+{
+	return Resampling::IsKnownMode(mode) ? static_cast<ResamplingMode>(mode)
+		: (mode == SRCMODE_AMIGA) ? SRCMODE_LINEAR
+		: Resampling::Default();
 }
 
+static MPT_CONSTEXPR11_FUN int Length(ResamplingMode mode) noexcept
+{
+	return mode == SRCMODE_NEAREST ? 1
+		: mode == SRCMODE_LINEAR ? 2
+		: mode == SRCMODE_CUBIC ? 4
+		: mode == SRCMODE_SINC8 ? 8
+		: mode == SRCMODE_SINC8LP ? 8
+		: 0;
+}
 
+static MPT_CONSTEXPR11_FUN bool HasAA(ResamplingMode mode) noexcept { return (mode == SRCMODE_SINC8LP); }
+
+static MPT_CONSTEXPR11_FUN ResamplingMode AddAA(ResamplingMode mode) noexcept { return (mode == SRCMODE_SINC8) ? SRCMODE_SINC8LP : mode; }
+
+static MPT_CONSTEXPR11_FUN ResamplingMode RemoveAA(ResamplingMode mode) noexcept { return (mode == SRCMODE_SINC8LP) ? SRCMODE_SINC8 : mode; }
+
+}
+
+
+
 // Release node defines
 #define ENV_RELEASE_NODE_UNSET	0xFF
 #define NOT_YET_RELEASED		(-1)
Index: soundlib/Sndmix.cpp
===================================================================
--- soundlib/Sndmix.cpp	(revision 9968)
+++ soundlib/Sndmix.cpp	(working copy)
@@ -2330,11 +2330,11 @@
 			//if (pChn->nNewRightVol > 0xFFFF) pChn->nNewRightVol = 0xFFFF;
 			//if (pChn->nNewLeftVol > 0xFFFF) pChn->nNewLeftVol = 0xFFFF;
 
-			if(pChn->pModInstrument && IsKnownResamplingMode(pChn->pModInstrument->nResampling))
+			if(pChn->pModInstrument && Resampling::IsKnownMode(pChn->pModInstrument->nResampling))
 			{
 				// For defined resampling modes, use per-instrument resampling mode if set
 				pChn->resamplingMode = static_cast<uint8>(pChn->pModInstrument->nResampling);
-			} else if(IsKnownResamplingMode(m_nResampling))
+			} else if(Resampling::IsKnownMode(m_nResampling))
 			{
 				pChn->resamplingMode = static_cast<uint8>(m_nResampling);
 			} else if(m_SongFlags[SONG_ISAMIGA] && m_Resampler.m_Settings.emulateAmiga)
Index: soundlib/Tables.cpp
===================================================================
--- soundlib/Tables.cpp	(revision 9968)
+++ soundlib/Tables.cpp	(working copy)
@@ -853,42 +853,7 @@
 	}
 }
 
-#if 0
 
-// this code is currently unused
-
-static double GetSpline(double x, double c0, double c1, double c2, double c3)
-{
-	double Xo = c1;
-	double Xa = c0 - Xo;
-	double Xb = c2 - Xo;
-	double Ux = (Xb-Xa)/2;
-	double Vx = (c3 - Xo)/2;
-	double a = Vx+Ux-2*Xb;
-	double b = 3*Xb-2*Ux-Vx;
-	return (((a*x+b)*x)+Ux)*x+Xo;
-}
-
-
-static void getdownsample2x(short int *psinc)
-{
-	for (int i=0; i<SINC_PHASES; i++)
-	{
-		double x = (double)i * (double)(0.5/SINC_PHASES);
-		psinc[i*8+7] = (short int)(GetSpline(x,     0, 0, 0, 1) * 8192);
-		psinc[i*8+6] = (short int)(GetSpline(x+0.5, 0, 0, 0, 1) * 8192);
-		psinc[i*8+5] = (short int)(GetSpline(x,     0, 0, 1, 0) * 8192);
-		psinc[i*8+4] = (short int)(GetSpline(x+0.5, 0, 0, 1, 0) * 8192);
-		psinc[i*8+3] = (short int)(GetSpline(x,     0, 1, 0, 0) * 8192);
-		psinc[i*8+2] = (short int)(GetSpline(x+0.5, 0, 1, 0, 0) * 8192);
-		psinc[i*8+1] = (short int)(GetSpline(x,     1, 0, 0, 0) * 8192);
-		psinc[i*8+0] = (short int)(GetSpline(x+0.5, 1, 0, 0, 0) * 8192);
-	}
-}
-
-#endif
-
-
 #ifdef MODPLUG_TRACKER
 bool CResampler::StaticTablesInitialized = false;
 SINC_TYPE CResampler::gKaiserSinc[SINC_PHASES*8];     // Upsampling
@@ -938,12 +903,8 @@
 		InitFloatmixerTables();
 
 		getsinc(gKaiserSinc, 9.6377, 0.97);
-		//ericus' downsampling improvement.
-		//getsinc(gDownsample13x, 8.5, 3.0/4.0);
-		//getdownsample2x(gDownsample2x);
 		getsinc(gDownsample13x, 8.5, 0.5);
 		getsinc(gDownsample2x, 2.7625, 0.425);
-		//end ericus' downsampling improvement.
 
 		#ifdef MODPLUG_TRACKER
 			StaticTablesInitialized = true;
Index: soundlib/WindowedFIR.h
===================================================================
--- soundlib/WindowedFIR.h	(revision 9968)
+++ soundlib/WindowedFIR.h	(working copy)
@@ -48,25 +48,20 @@
 #define WFIR_LOG2WIDTH		3
 #define WFIR_WIDTH			(1L<<WFIR_LOG2WIDTH)
 // cutoff (1.0 == pi/2)
-//float WFIR_CUTOFF			= 0.5f;//0.75f;	//0.90f;
 // wfir type
 enum WFIRType
 {
-	WFIR_HANN			= 0,
-	WFIR_HAMMING		= 1,
-	WFIR_BLACKMANEXACT	= 2,
-	WFIR_BLACKMAN3T61	= 3,
-	WFIR_BLACKMAN3T67	= 4,
-	WFIR_BLACKMAN4T92	= 5,
-	WFIR_BLACKMAN4T74	= 6,
-	WFIR_KAISER4T		= 7,
+	WFIR_HANN          = 0,  // Hann
+	WFIR_HAMMING       = 1,  // Hamming
+	WFIR_BLACKMANEXACT = 2,  // Blackman Exact
+	WFIR_BLACKMAN3T61  = 3,  // Blackman 3-Tap 61
+	WFIR_BLACKMAN3T67  = 4,  // Blackman 3-Tap 67
+	WFIR_BLACKMAN4T92  = 5,  // Blackman-Harris
+	WFIR_BLACKMAN4T74  = 6,  // Blackman 4-Tap 74
+	WFIR_KAISER4T      = 7,  // Kaiser a=7.5
 };
-//int WFIR_TYPE				= WFIR_KAISER4T;//WFIR_BLACKMANEXACT;
-//int WFIR_TYPE				= TrackerSettings::Instance().gbWFIRType;
 // wfir help
-#ifndef M_zPI
 #define M_zPI				3.1415926535897932384626433832795
-#endif
 #define M_zEPS				1e-8
 
 
Index: test/test.cpp
===================================================================
--- test/test.cpp	(revision 9968)
+++ test/test.cpp	(working copy)
@@ -2739,7 +2739,7 @@
 	VERIFY_EQUAL_NONCONT(pIns->nPPC, NOTE_MIDDLEC - 1);
 
 	VERIFY_EQUAL_NONCONT(pIns->nVolRampUp, 1200);
-	VERIFY_EQUAL_NONCONT(pIns->nResampling, (unsigned)SRCMODE_POLYPHASE);
+	VERIFY_EQUAL_NONCONT(pIns->nResampling, (unsigned)SRCMODE_SINC8LP);
 
 	VERIFY_EQUAL_NONCONT(pIns->IsCutoffEnabled(), false);
 	VERIFY_EQUAL_NONCONT(pIns->GetCutoff(), 0);
@@ -2869,7 +2869,7 @@
 	VERIFY_EQUAL_NONCONT(sndFile.m_nDefaultRowsPerBeat, 6);
 	VERIFY_EQUAL_NONCONT(sndFile.m_nDefaultRowsPerMeasure, 12);
 	VERIFY_EQUAL_NONCONT(sndFile.m_dwCreatedWithVersion, MAKE_VERSION_NUMERIC(1, 19, 02, 05));
-	VERIFY_EQUAL_NONCONT(sndFile.m_nResampling, SRCMODE_POLYPHASE);
+	VERIFY_EQUAL_NONCONT(sndFile.m_nResampling, SRCMODE_SINC8LP);
 	VERIFY_EQUAL_NONCONT(sndFile.m_songArtist, MPT_USTRING("Tester"));
 	VERIFY_EQUAL_NONCONT(sndFile.m_tempoSwing.size(), 6);
 	VERIFY_EQUAL_NONCONT(sndFile.m_tempoSwing[0], 29360125);
@@ -3032,7 +3032,7 @@
 		VERIFY_EQUAL_NONCONT(pIns->nPPC, (NOTE_MIDDLEC - NOTE_MIN) + 6);	// F#5
 
 		VERIFY_EQUAL_NONCONT(pIns->nVolRampUp, 1200);
-		VERIFY_EQUAL_NONCONT(pIns->nResampling, (unsigned)SRCMODE_POLYPHASE);
+		VERIFY_EQUAL_NONCONT(pIns->nResampling, (unsigned)SRCMODE_SINC8LP);
 
 		VERIFY_EQUAL_NONCONT(pIns->IsCutoffEnabled(), true);
 		VERIFY_EQUAL_NONCONT(pIns->GetCutoff(), 0x32);
resampler-cleanup-v3.patch (28,918 bytes)   
resampler-cleanup-v4.patch (28,943 bytes)   
Index: common/versionNumber.h
===================================================================
--- common/versionNumber.h	(revision 10070)
+++ common/versionNumber.h	(working copy)
@@ -19,7 +19,7 @@
 #define VER_MAJORMAJOR  1
 #define VER_MAJOR      28
 #define VER_MINOR      00
-#define VER_MINORMINOR 17
+#define VER_MINORMINOR 18
 
 //Numerical value of the version.
 #define MPT_VERSION_CURRENT MAKE_VERSION_NUMERIC(VER_MAJORMAJOR,VER_MAJOR,VER_MINOR,VER_MINORMINOR)
Index: libopenmpt/libopenmpt_impl.cpp
===================================================================
--- libopenmpt/libopenmpt_impl.cpp	(revision 10070)
+++ libopenmpt/libopenmpt_impl.cpp	(working copy)
@@ -316,13 +316,13 @@
 }
 
 static ResamplingMode filterlength_to_resamplingmode(std::int32_t length) {
-	ResamplingMode result = SRCMODE_POLYPHASE;
+	ResamplingMode result = SRCMODE_SINC8LP;
 	if ( length == 0 ) {
-		result = SRCMODE_POLYPHASE;
+		result = SRCMODE_SINC8LP;
 	} else if ( length >= 8 ) {
-		result = SRCMODE_POLYPHASE;
+		result = SRCMODE_SINC8LP;
 	} else if ( length >= 3 ) {
-		result = SRCMODE_SPLINE;
+		result = SRCMODE_CUBIC;
 	} else if ( length >= 2 ) {
 		result = SRCMODE_LINEAR;
 	} else if ( length >= 1 ) {
@@ -340,11 +340,11 @@
 	case SRCMODE_LINEAR:
 		return 2;
 		break;
-	case SRCMODE_SPLINE:
+	case SRCMODE_CUBIC:
 		return 4;
 		break;
-	case SRCMODE_POLYPHASE:
-	case SRCMODE_FIRFILTER:
+	case SRCMODE_SINC8:
+	case SRCMODE_SINC8LP:
 	case SRCMODE_DEFAULT:
 		return 8;
 	default:
Index: mptrack/Ctrl_gen.cpp
===================================================================
--- mptrack/Ctrl_gen.cpp	(revision 10070)
+++ mptrack/Ctrl_gen.cpp	(working copy)
@@ -202,21 +202,21 @@
 	FlagSet<HintType> hintType = hint.GetType();
 	const bool updateAll = hintType[HINT_MODTYPE];
 
-	const ResamplingMode resamplingModes[] = { SRCMODE_NEAREST, SRCMODE_LINEAR, SRCMODE_SPLINE, SRCMODE_POLYPHASE, SRCMODE_FIRFILTER };
+	const auto resamplingModes = Resampling::AllModes();
 
 	if (hintType == HINT_MPTOPTIONS || updateAll)
 	{
-		const TCHAR *defaultResampler;
+		CString defaultResampler;
 		if(m_sndFile.m_SongFlags[SONG_ISAMIGA] && TrackerSettings::Instance().ResamplerEmulateAmiga)
 			defaultResampler = _T("Amiga Resampler");
 		else
-			defaultResampler = CTrackApp::GetResamplingModeName(TrackerSettings::Instance().ResamplerMode, false);
+			defaultResampler = CTrackApp::GetResamplingModeName(TrackerSettings::Instance().ResamplerMode, 1, false);
 
 		m_CbnResampling.ResetContent();
-		m_CbnResampling.SetItemData(m_CbnResampling.AddString(_T("Default (") + CString(defaultResampler) + _T(")")), SRCMODE_DEFAULT);
+		m_CbnResampling.SetItemData(m_CbnResampling.AddString(_T("Default (") + defaultResampler + _T(")")), SRCMODE_DEFAULT);
 		for(auto mode : resamplingModes)
 		{
-			m_CbnResampling.SetItemData(m_CbnResampling.AddString(CTrackApp::GetResamplingModeName(mode, false)), mode);
+			m_CbnResampling.SetItemData(m_CbnResampling.AddString(CTrackApp::GetResamplingModeName(mode, 2, true)), mode);
 		}
 		m_CbnResampling.Invalidate(FALSE);
 	}
@@ -312,12 +312,13 @@
 
 	if(updateAll || hintType == HINT_MPTOPTIONS || (hint.GetCategory() == HINTCAT_GENERAL && hintType[HINT_MODGENERAL]))
 	{
+
 		int srcMode = 0;
-		for(int i = 0; i < CountOf(resamplingModes); i++)
+		for(int i = 0; i < m_CbnResampling.GetCount(); ++i)
 		{
-			if(m_sndFile.m_nResampling == resamplingModes[i]) srcMode = i + 1;
+			if(m_sndFile.m_nResampling == static_cast<int>(m_CbnResampling.GetItemData(i)))
+				m_CbnResampling.SetCurSel(i);
 		}
-		m_CbnResampling.SetCurSel(srcMode);
 	}
 
 	CheckDlgButton(IDC_CHECK_LOOPSONG, (TrackerSettings::Instance().gbLoopSong) ? TRUE : FALSE);
Index: mptrack/Ctrl_ins.cpp
===================================================================
--- mptrack/Ctrl_ins.cpp	(revision 10070)
+++ mptrack/Ctrl_ins.cpp	(working copy)
@@ -995,12 +995,12 @@
 	m_EditPWD.SubclassDlgItem(IDC_PITCHWHEELDEPTH, this);
 	m_EditPWD.AllowFractions(false);
 
+	const auto resamplingModes = Resampling::AllModes();
 	m_CbnResampling.SetItemData(m_CbnResampling.AddString(_T("Default")), SRCMODE_DEFAULT);
-	m_CbnResampling.SetItemData(m_CbnResampling.AddString(_T("None")), SRCMODE_NEAREST);
-	m_CbnResampling.SetItemData(m_CbnResampling.AddString(_T("Linear")), SRCMODE_LINEAR);
-	m_CbnResampling.SetItemData(m_CbnResampling.AddString(_T("Spline")), SRCMODE_SPLINE);
-	m_CbnResampling.SetItemData(m_CbnResampling.AddString(_T("Polyphase")), SRCMODE_POLYPHASE);
-	m_CbnResampling.SetItemData(m_CbnResampling.AddString(_T("XMMS")), SRCMODE_FIRFILTER);
+	for(auto mode : resamplingModes)
+	{
+		m_CbnResampling.SetItemData(m_CbnResampling.AddString(CTrackApp::GetResamplingModeName(mode, 1, false)), mode);
+	}
 
 	m_CbnFilterMode.SetItemData(m_CbnFilterMode.AddString(_T("Channel default")), FLTMODE_UNCHANGED);
 	m_CbnFilterMode.SetItemData(m_CbnFilterMode.AddString(_T("Force lowpass")), FLTMODE_LOWPASS);
Index: mptrack/Mpdlgs.cpp
===================================================================
--- mptrack/Mpdlgs.cpp	(revision 10070)
+++ mptrack/Mpdlgs.cpp	(working copy)
@@ -928,9 +928,7 @@
 	ON_WM_HSCROLL()
 	ON_WM_VSCROLL()
 	ON_CBN_SELCHANGE(IDC_COMBO_FILTER,			&COptionsMixer::OnResamplerChanged)
-	ON_CBN_SELCHANGE(IDC_COMBO_FILTERWINDOW,	&COptionsMixer::OnSettingsChanged)
 	ON_CBN_SELCHANGE(IDC_COMBO_POLYPHONY,		&COptionsMixer::OnSettingsChanged)
-	ON_EN_UPDATE(IDC_WFIRCUTOFF,				&COptionsMixer::OnSettingsChanged)
 	ON_EN_UPDATE(IDC_RAMPING_IN,				&COptionsMixer::OnRampingChanged)
 	ON_EN_UPDATE(IDC_RAMPING_OUT,				&COptionsMixer::OnRampingChanged)
 	ON_COMMAND(IDC_CHECK_SOFTPAN,				&COptionsMixer::OnSettingsChanged)
@@ -943,8 +941,6 @@
 	CPropertyPage::DoDataExchange(pDX);
 	//{{AFX_DATA_MAP(COptionsSoundcard)
 	DDX_Control(pDX, IDC_COMBO_FILTER, m_CbnResampling);
-	DDX_Control(pDX, IDC_WFIRCUTOFF, m_CEditWFIRCutoff);
-	DDX_Control(pDX, IDC_COMBO_FILTERWINDOW, m_CbnWFIRType);
 	DDX_Control(pDX, IDC_RAMPING_IN, m_CEditRampUp);
 	DDX_Control(pDX, IDC_RAMPING_OUT, m_CEditRampDown);
 	DDX_Control(pDX, IDC_EDIT_VOLRAMP_SAMPLES_UP, m_CInfoRampUp);
@@ -963,26 +959,18 @@
 
 	// Resampling type
 	{
-		for(auto mode : { SRCMODE_NEAREST, SRCMODE_LINEAR, SRCMODE_SPLINE, SRCMODE_POLYPHASE, SRCMODE_FIRFILTER })
+		const auto resamplingModes = Resampling::AllModes();
+		for(auto mode : resamplingModes)
 		{
-			int index = m_CbnResampling.AddString(CTrackApp::GetResamplingModeName(mode, true));
+			int index = m_CbnResampling.AddString(CTrackApp::GetResamplingModeName(mode, 2, true));
 			m_CbnResampling.SetItemData(index, mode);
 			if(TrackerSettings::Instance().ResamplerMode == mode)
+			{
 				m_CbnResampling.SetCurSel(index);
+			}
 		}
 	}
 
-	// Resampler bandwidth
-	{
-		m_CEditWFIRCutoff.SetWindowText(mpt::ToCString(mpt::ufmt::val(TrackerSettings::Instance().ResamplerCutoffPercent)));
-		static_cast<CSpinButtonCtrl *>(GetDlgItem(IDC_SPIN1))->SetRange32(1, 99);
-	}
-
-	// Resampler filter window
-	{
-		// done in OnResamplerChanged()
-	}
-
 	// Amiga Resampler
 	CheckDlgButton(IDC_CHECK1, TrackerSettings::Instance().ResamplerEmulateAmiga ? BST_CHECKED : BST_UNCHECKED);
 
@@ -1037,7 +1025,6 @@
 		m_SliderPreAmp.SetPos(n);
 	}
 
-	OnResamplerChanged();
 	m_initialized = true;
 
 	return TRUE;
@@ -1053,61 +1040,6 @@
 
 void COptionsMixer::OnResamplerChanged()
 {
-	ResamplingMode srcMode = static_cast<ResamplingMode>(m_CbnResampling.GetItemData(m_CbnResampling.GetCurSel()));
-	m_CbnWFIRType.ResetContent();
-	switch(srcMode)
-	{
-		case SRCMODE_FIRFILTER:
-			m_CbnWFIRType.AddString(_T("Hann"));
-			m_CbnWFIRType.AddString(_T("Hamming"));
-			m_CbnWFIRType.AddString(_T("Blackman Exact"));
-			m_CbnWFIRType.AddString(_T("Blackman 3 Tap 61"));
-			m_CbnWFIRType.AddString(_T("Blackman 3 Tap 67"));
-			m_CbnWFIRType.AddString(_T("Blackman Harris"));
-			m_CbnWFIRType.AddString(_T("Blackman 4 Tap 74"));
-			m_CbnWFIRType.AddString(_T("Kaiser a=7.5"));
-			break;
-		case SRCMODE_POLYPHASE:
-			m_CbnWFIRType.AddString(_T("Auto"));
-			m_CbnWFIRType.AddString(_T("Auto"));
-			m_CbnWFIRType.AddString(_T("Auto"));
-			m_CbnWFIRType.AddString(_T("Auto"));
-			m_CbnWFIRType.AddString(_T("Auto"));
-			m_CbnWFIRType.AddString(_T("Auto"));
-			m_CbnWFIRType.AddString(_T("Auto"));
-			m_CbnWFIRType.AddString(_T("Auto"));
-			break;
-		default:
-			m_CbnWFIRType.AddString(_T("none"));
-			m_CbnWFIRType.AddString(_T("none"));
-			m_CbnWFIRType.AddString(_T("none"));
-			m_CbnWFIRType.AddString(_T("none"));
-			m_CbnWFIRType.AddString(_T("none"));
-			m_CbnWFIRType.AddString(_T("none"));
-			m_CbnWFIRType.AddString(_T("none"));
-			m_CbnWFIRType.AddString(_T("none"));
-			break;
-	}
-	m_CbnWFIRType.SetCurSel(TrackerSettings::Instance().ResamplerSubMode);
-	CSpinButtonCtrl *spinWFIRCutoff = static_cast<CSpinButtonCtrl *>(GetDlgItem(IDC_SPIN1));
-	switch(srcMode)
-	{
-		case SRCMODE_POLYPHASE:
-			m_CEditWFIRCutoff.EnableWindow(FALSE);
-			spinWFIRCutoff->EnableWindow(FALSE);
-			m_CbnWFIRType.EnableWindow(FALSE);
-			break;
-		case SRCMODE_FIRFILTER:
-			m_CEditWFIRCutoff.EnableWindow(TRUE);
-			spinWFIRCutoff->EnableWindow(TRUE);
-			m_CbnWFIRType.EnableWindow(TRUE);
-			break;
-		default:
-			m_CEditWFIRCutoff.EnableWindow(FALSE);
-			spinWFIRCutoff->EnableWindow(FALSE);
-			m_CbnWFIRType.EnableWindow(FALSE);
-			break;
-	}
 	OnSettingsChanged();
 }
 
@@ -1162,27 +1094,6 @@
 		TrackerSettings::Instance().ResamplerMode = static_cast<ResamplingMode>(m_CbnResampling.GetItemData(m_CbnResampling.GetCurSel()));
 	}
 
-	// resampler bandwidth
-	{
-		CString s;
-		m_CEditWFIRCutoff.GetWindowText(s);
-		if(s != "")
-		{
-			int newCutoff = ConvertStrTo<int>(s);
-			Limit(newCutoff, 0, 100);
-			TrackerSettings::Instance().ResamplerCutoffPercent = newCutoff;
-		}
-		{
-			s.Format(_T("%d"), TrackerSettings::Instance().ResamplerCutoffPercent.Get());
-			m_CEditWFIRCutoff.SetWindowText(s);
-		}
-	}
-
-	// resampler filter window
-	{
-		TrackerSettings::Instance().ResamplerSubMode = (uint8)m_CbnWFIRType.GetCurSel();
-	}
-
 	// Amiga Resampler
 	TrackerSettings::Instance().ResamplerEmulateAmiga = IsDlgButtonChecked(IDC_CHECK1) != BST_UNCHECKED;
 
Index: mptrack/Mpdlgs.h
===================================================================
--- mptrack/Mpdlgs.h	(revision 10070)
+++ mptrack/Mpdlgs.h	(working copy)
@@ -88,8 +88,6 @@
 protected:
 
 	CComboBox m_CbnResampling;
-	CEdit m_CEditWFIRCutoff;
-	CComboBox m_CbnWFIRType;
 
 	CEdit m_CEditRampUp;
 	CEdit m_CEditRampDown;
Index: mptrack/Mptrack.cpp
===================================================================
--- mptrack/Mptrack.cpp	(revision 10070)
+++ mptrack/Mptrack.cpp	(working copy)
@@ -2064,24 +2064,39 @@
 }
 
 
-const TCHAR *CTrackApp::GetResamplingModeName(ResamplingMode mode, bool addTaps)
+CString CTrackApp::GetResamplingModeName(ResamplingMode mode, int length, bool addTaps)
 {
+	CString result;
 	switch(mode)
 	{
 	case SRCMODE_NEAREST:
-		return addTaps ? _T("No Interpolation (1 tap)") : _T("No Interpolation");
+		result = (length > 1) ? _T("No Interpolation") : _T("None") ;
+		break;
 	case SRCMODE_LINEAR:
-		return addTaps ? _T("Linear (2 tap)") : _T("Linear");
-	case SRCMODE_SPLINE:
-		return addTaps ? _T("Cubic Spline (4 tap)") :  _T("Cubic Spline");
-	case SRCMODE_POLYPHASE:
-		return addTaps ? _T("Polyphase (8 tap)") : _T("Polyphase");
-	case SRCMODE_FIRFILTER:
-		return addTaps ? _T("XMMS-ModPlug (8 tap)") : _T("XMMS-ModPlug");
+		result = _T("Linear");
+		break;
+	case SRCMODE_CUBIC:
+		result = (length > 1) ? _T("Cubic Spline") : _T("Cubic");
+		break;
+	case SRCMODE_SINC8:
+		result = _T("Sinc");
+		break;
+	case SRCMODE_SINC8LP:
+		result = _T("Sinc");
+		break;
 	default:
 		MPT_ASSERT_NOTREACHED();
+		break;
 	}
-	return _T("");
+	if(Resampling::HasAA(mode))
+	{
+		result += (length > 1) ? _T(" + Low-Pass") : _T(" + LP");
+	}
+	if(addTaps)
+	{
+		result += mpt::cformat(_T(" (%1 tap%2)"))(Resampling::Length(mode), (Resampling::Length(mode) != 1) ? CString(_T("s")) : CString(_T("")));
+	}
+	return result;
 }
 
 
Index: mptrack/Mptrack.h
===================================================================
--- mptrack/Mptrack.h	(revision 10070)
+++ mptrack/Mptrack.h	(working copy)
@@ -275,7 +275,7 @@
 
 public:
 	// Get name of resampling mode. addTaps = true also adds the number of taps the filter uses.
-	static const TCHAR *GetResamplingModeName(ResamplingMode mode, bool addTaps);
+	static CString GetResamplingModeName(ResamplingMode mode, int length, bool addTaps);
 
 // Overrides
 public:
Index: mptrack/mptrack.rc
===================================================================
--- mptrack/mptrack.rc	(revision 10070)
+++ mptrack/mptrack.rc	(working copy)
@@ -1981,15 +1981,9 @@
 BEGIN
     GROUPBOX        "Resampling",IDC_STATIC,6,6,276,48
     LTEXT           "&Filter:",IDC_STATIC,12,18,24,12,SS_CENTERIMAGE
-    COMBOBOX        IDC_COMBO_FILTER,54,18,96,56,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
-    LTEXT           "&Window:",IDC_STATIC,156,18,30,12,SS_CENTERIMAGE
-    COMBOBOX        IDC_COMBO_FILTERWINDOW,192,18,84,56,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
-    LTEXT           "&Bandwidth:",IDC_STATIC,12,36,42,12,SS_CENTERIMAGE
-    EDITTEXT        IDC_WFIRCUTOFF,54,36,30,12,ES_RIGHT | ES_AUTOHSCROLL | ES_NUMBER
-    CONTROL         "",IDC_SPIN1,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_NOTHOUSANDS,71,31,11,14
-    LTEXT           "%",IDC_STATIC,90,36,24,12,SS_CENTERIMAGE
+    COMBOBOX        IDC_COMBO_FILTER,36,18,102,56,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
     CONTROL         "Use &Amiga resampler for Amiga modules",IDC_CHECK1,
-                    "Button",BS_AUTOCHECKBOX | WS_TABSTOP,126,36,150,12
+                    "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,36,144,12
     GROUPBOX        "Volume Ramping",IDC_STATIC,6,60,276,48
     EDITTEXT        IDC_RAMPING_IN,12,72,36,12,ES_RIGHT | ES_AUTOHSCROLL | ES_NUMBER
     CONTROL         "",IDC_SPIN2,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_NOTHOUSANDS,42,66,11,14
Index: mptrack/resource.h
===================================================================
--- mptrack/resource.h	(revision 10070)
+++ mptrack/resource.h	(working copy)
@@ -684,8 +684,6 @@
 #define IDC_COMMAND_LIST                2129
 #define IDC_STATIC8                     2200
 #define IDC_PATINSTROPLUGGUI            2201
-#define IDC_WFIRCUTOFF                  2202
-#define IDC_WFIRTYPE                    2203
 #define IDC_RAMPING_IN                  2204
 #define IDC_PLAYEROPTIONS               2205
 #define IDC_RAMPING_OUT                 2205
Index: mptrack/SampleEditorDialogs.cpp
===================================================================
--- mptrack/SampleEditorDialogs.cpp	(revision 10070)
+++ mptrack/SampleEditorDialogs.cpp	(working copy)
@@ -530,12 +530,12 @@
 
 	CComboBox *cbnResampling = static_cast<CComboBox *>(GetDlgItem(IDC_COMBO_FILTER));
 	cbnResampling->SetRedraw(FALSE);
-	const ResamplingMode resamplingModes[] = { SRCMODE_NEAREST, SRCMODE_LINEAR, SRCMODE_SPLINE, SRCMODE_POLYPHASE, SRCMODE_FIRFILTER, SRCMODE_DEFAULT };
+	const auto resamplingModes = Resampling::AllModesWithDefault();
 	for(auto mode : resamplingModes)
 	{
-		const TCHAR *desc = _T("r8brain (High Quality)");
+		CString desc = _T("r8brain (High Quality)");
 		if(mode != SRCMODE_DEFAULT)
-			desc = CTrackApp::GetResamplingModeName(mode, false);
+			desc = CTrackApp::GetResamplingModeName(mode, 1, true);
 
 		int index = cbnResampling->AddString(desc);
 		cbnResampling->SetItemData(index, mode);
Index: mptrack/TrackerSettings.cpp
===================================================================
--- mptrack/TrackerSettings.cpp	(revision 10070)
+++ mptrack/TrackerSettings.cpp	(working copy)
@@ -74,29 +74,6 @@
 }
 
 
-static ResamplingMode GetDefaultResamplerMode()
-{
-	ResamplingMode result = CResamplerSettings().SrcMode;
-#ifdef ENABLE_ASM
-	// rough heuristic to select less cpu consuming defaults for old CPUs
-	if(GetRealProcSupport() & PROCSUPPORT_SSE)
-	{
-		result = SRCMODE_POLYPHASE;
-	} else if(GetRealProcSupport() & PROCSUPPORT_MMX)
-	{
-		result = SRCMODE_SPLINE;
-	} else
-	{
-		result = SRCMODE_LINEAR;
-	}
-#else
-	// just use a sane default
-	result = CResamplerSettings().SrcMode;
-#endif
-	return result;
-}
-
-
 static uint32 GetDefaultPatternSetup()
 {
 	return PATTERN_PLAYNEWNOTE | PATTERN_EFFECTHILIGHT
@@ -244,7 +221,7 @@
 	, MixerStereoSeparation(conf, MPT_USTRING("Sound Settings"), MPT_USTRING("StereoSeparation"), MixerSettings().m_nStereoSeparation)
 	, MixerVolumeRampUpMicroseconds(conf, MPT_USTRING("Sound Settings"), MPT_USTRING("VolumeRampUpMicroseconds"), MixerSettings().GetVolumeRampUpMicroseconds())
 	, MixerVolumeRampDownMicroseconds(conf, MPT_USTRING("Sound Settings"), MPT_USTRING("VolumeRampDownMicroseconds"), MixerSettings().GetVolumeRampDownMicroseconds())
-	, ResamplerMode(conf, MPT_USTRING("Sound Settings"), MPT_USTRING("SrcMode"), GetDefaultResamplerMode())
+	, ResamplerMode(conf, MPT_USTRING("Sound Settings"), MPT_USTRING("SrcMode"), CResamplerSettings().SrcMode)
 	, ResamplerSubMode(conf, MPT_USTRING("Sound Settings"), MPT_USTRING("XMMSModplugResamplerWFIRType"), CResamplerSettings().gbWFIRType)
 	, ResamplerCutoffPercent(conf, MPT_USTRING("Sound Settings"), MPT_USTRING("ResamplerWFIRCutoff"), Util::Round<int32>(CResamplerSettings().gdWFIRCutoff * 100.0))
 	, ResamplerEmulateAmiga(conf, MPT_USTRING("Sound Settings"), MPT_USTRING("ResamplerEmulateAmiga"), false)
@@ -546,6 +523,13 @@
 		m_SoundDeviceSettingsDefaults.UseHardwareTiming = m_SoundDeviceUseHardwareTiming;
 		m_SoundDeviceSettingsUseOldDefaults = true;
 	}
+	if(storedVersion < MAKE_VERSION_NUMERIC(1,28,00,18))
+	{
+		// reset this setting to the default when updating,
+		// because we do not provide a GUI any more,
+		// and in general, it should not get changed anyway
+		ResamplerCutoffPercent = Util::Round<int32>(CResamplerSettings().gdWFIRCutoff * 100.0);
+	}
 	if(storedVersion < MAKE_VERSION_NUMERIC(1,25,00,04))
 	{
 		m_SoundDeviceDirectSoundOldDefaultIdentifier = true;
@@ -678,7 +662,7 @@
 	}
 
 	// Sanitize resampling mode for sample editor
-	if(!IsKnownResamplingMode(sampleEditorDefaultResampler) && sampleEditorDefaultResampler != SRCMODE_DEFAULT)
+	if(!Resampling::IsKnownMode(sampleEditorDefaultResampler) && sampleEditorDefaultResampler != SRCMODE_DEFAULT)
 	{
 		sampleEditorDefaultResampler = SRCMODE_DEFAULT;
 	}
Index: soundlib/Load_it.cpp
===================================================================
--- soundlib/Load_it.cpp	(revision 10070)
+++ soundlib/Load_it.cpp	(working copy)
@@ -2357,7 +2357,7 @@
 			case MagicBE("RP.."): if(GetType() != MOD_TYPE_XM) { ORDERINDEX restartPos; ReadField(chunk, size, restartPos); Order().SetRestartPos(restartPos); } break;
 			case MagicLE("RSMP"):
 				ReadFieldCast(chunk, size, m_nResampling);
-				if(!IsKnownResamplingMode(m_nResampling)) m_nResampling = SRCMODE_DEFAULT;
+				if(!Resampling::IsKnownMode(m_nResampling)) m_nResampling = SRCMODE_DEFAULT;
 				break;
 #ifdef MODPLUG_TRACKER
 			case MagicBE("MIMA"): GetMIDIMapper().Deserialize(chunk); break;
Index: soundlib/MixFuncTable.cpp
===================================================================
--- soundlib/MixFuncTable.cpp	(revision 10070)
+++ soundlib/MixFuncTable.cpp	(working copy)
@@ -79,9 +79,9 @@
 	{
 	case SRCMODE_NEAREST:   return ndxNoInterpolation;
 	case SRCMODE_LINEAR:    return ndxLinear;
-	case SRCMODE_SPLINE:    return ndxFastSinc;
-	case SRCMODE_POLYPHASE: return ndxKaiser;
-	case SRCMODE_FIRFILTER: return ndxFIRFilter;
+	case SRCMODE_CUBIC:     return ndxFastSinc;
+	case SRCMODE_SINC8LP:   return ndxKaiser;
+	case SRCMODE_SINC8:     return ndxFIRFilter;
 	case SRCMODE_AMIGA:     return ndxAmigaBlep;
 	default:                MPT_ASSERT_NOTREACHED();
 	}
Index: soundlib/Resampler.h
===================================================================
--- soundlib/Resampler.h	(revision 10070)
+++ soundlib/Resampler.h	(working copy)
@@ -59,12 +59,12 @@
 	uint8 gbWFIRType;
 	bool emulateAmiga;
 public:
-	CResamplerSettings()
+	MPT_CONSTEXPR11_FUN CResamplerSettings()
+		: SrcMode(Resampling::Default())
+		, gdWFIRCutoff(0.97)
+		, gbWFIRType(WFIR_KAISER4T)
+		, emulateAmiga(false)
 	{
-		SrcMode = SRCMODE_POLYPHASE;
-		gdWFIRCutoff = 0.97;
-		gbWFIRType = WFIR_KAISER4T;
-		emulateAmiga = false;
 	}
 	bool operator == (const CResamplerSettings &cmp) const
 	{
@@ -125,8 +125,6 @@
 	{
 		InitializeTablesFromScratch(false);
 	}
-	~CResampler() {}
-	bool IsHQ() const { return m_Settings.SrcMode >= SRCMODE_SPLINE && m_Settings.SrcMode < SRCMODE_DEFAULT; }
 private:
 	void InitFloatmixerTables();
 	void InitializeTablesFromScratch(bool force=false);
Index: soundlib/Snd_defs.h
===================================================================
--- soundlib/Snd_defs.h	(revision 10070)
+++ soundlib/Snd_defs.h	(working copy)
@@ -290,22 +290,55 @@
 {
 	// ATTENTION: Do not change ANY of these values, as they get written out to files in per instrument interpolation settings
 	// and old files have these exact values in them which should not change meaning.
-	SRCMODE_NEAREST   = 0,
-	SRCMODE_LINEAR    = 1,
-	SRCMODE_SPLINE    = 2,
-	SRCMODE_POLYPHASE = 3,
-	SRCMODE_FIRFILTER = 4,
-	SRCMODE_DEFAULT   = 5,
+	SRCMODE_NEAREST   = 0,  // 1 tap, no AA
+	SRCMODE_LINEAR    = 1,  // 2 tap, no AA
+	SRCMODE_CUBIC     = 2,  // 4 tap, no AA
+	SRCMODE_SINC8     = 4,  // 8 tap, no AA   (yes, index 4) (XMMS-ModPlug)
+	SRCMODE_SINC8LP   = 3,  // 8 tap, with AA (yes, index 3) (Polyphase)
 
-	SRCMODE_AMIGA = 0xFF,	// Not explicitely user-selectable
+	SRCMODE_DEFAULT   = 5,  // only used for instrument settings, not used inside the mixer
+
+	SRCMODE_AMIGA  = 0xFF,  // Not explicitely user-selectable
 };
 
-static inline bool IsKnownResamplingMode(int mode)
+namespace Resampling
 {
-	return (mode >= 0) && (mode < SRCMODE_DEFAULT);
+
+static inline std::array<ResamplingMode, 5> AllModes() noexcept { return { SRCMODE_NEAREST, SRCMODE_LINEAR, SRCMODE_CUBIC, SRCMODE_SINC8, SRCMODE_SINC8LP }; }
+
+static inline std::array<ResamplingMode, 6> AllModesWithDefault() noexcept { return { SRCMODE_NEAREST, SRCMODE_LINEAR, SRCMODE_CUBIC, SRCMODE_SINC8, SRCMODE_SINC8LP, SRCMODE_DEFAULT }; }
+
+static MPT_CONSTEXPR11_FUN ResamplingMode Default() noexcept { return SRCMODE_SINC8LP; }
+
+static MPT_CONSTEXPR11_FUN bool IsKnownMode(int mode) noexcept { return (mode >= 0) && (mode < SRCMODE_DEFAULT); }
+
+static MPT_CONSTEXPR11_FUN ResamplingMode ToKnownMode(int mode) noexcept
+{
+	return Resampling::IsKnownMode(mode) ? static_cast<ResamplingMode>(mode)
+		: (mode == SRCMODE_AMIGA) ? SRCMODE_LINEAR
+		: Resampling::Default();
 }
 
+static MPT_CONSTEXPR11_FUN int Length(ResamplingMode mode) noexcept
+{
+	return mode == SRCMODE_NEAREST ? 1
+		: mode == SRCMODE_LINEAR ? 2
+		: mode == SRCMODE_CUBIC ? 4
+		: mode == SRCMODE_SINC8 ? 8
+		: mode == SRCMODE_SINC8LP ? 8
+		: 0;
+}
 
+static MPT_CONSTEXPR11_FUN bool HasAA(ResamplingMode mode) noexcept { return (mode == SRCMODE_SINC8LP); }
+
+static MPT_CONSTEXPR11_FUN ResamplingMode AddAA(ResamplingMode mode) noexcept { return (mode == SRCMODE_SINC8) ? SRCMODE_SINC8LP : mode; }
+
+static MPT_CONSTEXPR11_FUN ResamplingMode RemoveAA(ResamplingMode mode) noexcept { return (mode == SRCMODE_SINC8LP) ? SRCMODE_SINC8 : mode; }
+
+}
+
+
+
 // Release node defines
 #define ENV_RELEASE_NODE_UNSET	0xFF
 #define NOT_YET_RELEASED		(-1)
Index: soundlib/Sndmix.cpp
===================================================================
--- soundlib/Sndmix.cpp	(revision 10070)
+++ soundlib/Sndmix.cpp	(working copy)
@@ -2330,11 +2330,11 @@
 			//if (pChn->nNewRightVol > 0xFFFF) pChn->nNewRightVol = 0xFFFF;
 			//if (pChn->nNewLeftVol > 0xFFFF) pChn->nNewLeftVol = 0xFFFF;
 
-			if(pChn->pModInstrument && IsKnownResamplingMode(pChn->pModInstrument->nResampling))
+			if(pChn->pModInstrument && Resampling::IsKnownMode(pChn->pModInstrument->nResampling))
 			{
 				// For defined resampling modes, use per-instrument resampling mode if set
 				pChn->resamplingMode = static_cast<uint8>(pChn->pModInstrument->nResampling);
-			} else if(IsKnownResamplingMode(m_nResampling))
+			} else if(Resampling::IsKnownMode(m_nResampling))
 			{
 				pChn->resamplingMode = static_cast<uint8>(m_nResampling);
 			} else if(m_SongFlags[SONG_ISAMIGA] && m_Resampler.m_Settings.emulateAmiga)
Index: soundlib/Tables.cpp
===================================================================
--- soundlib/Tables.cpp	(revision 10070)
+++ soundlib/Tables.cpp	(working copy)
@@ -853,42 +853,7 @@
 	}
 }
 
-#if 0
 
-// this code is currently unused
-
-static double GetSpline(double x, double c0, double c1, double c2, double c3)
-{
-	double Xo = c1;
-	double Xa = c0 - Xo;
-	double Xb = c2 - Xo;
-	double Ux = (Xb-Xa)/2;
-	double Vx = (c3 - Xo)/2;
-	double a = Vx+Ux-2*Xb;
-	double b = 3*Xb-2*Ux-Vx;
-	return (((a*x+b)*x)+Ux)*x+Xo;
-}
-
-
-static void getdownsample2x(short int *psinc)
-{
-	for (int i=0; i<SINC_PHASES; i++)
-	{
-		double x = (double)i * (double)(0.5/SINC_PHASES);
-		psinc[i*8+7] = (short int)(GetSpline(x,     0, 0, 0, 1) * 8192);
-		psinc[i*8+6] = (short int)(GetSpline(x+0.5, 0, 0, 0, 1) * 8192);
-		psinc[i*8+5] = (short int)(GetSpline(x,     0, 0, 1, 0) * 8192);
-		psinc[i*8+4] = (short int)(GetSpline(x+0.5, 0, 0, 1, 0) * 8192);
-		psinc[i*8+3] = (short int)(GetSpline(x,     0, 1, 0, 0) * 8192);
-		psinc[i*8+2] = (short int)(GetSpline(x+0.5, 0, 1, 0, 0) * 8192);
-		psinc[i*8+1] = (short int)(GetSpline(x,     1, 0, 0, 0) * 8192);
-		psinc[i*8+0] = (short int)(GetSpline(x+0.5, 1, 0, 0, 0) * 8192);
-	}
-}
-
-#endif
-
-
 #ifdef MODPLUG_TRACKER
 bool CResampler::StaticTablesInitialized = false;
 SINC_TYPE CResampler::gKaiserSinc[SINC_PHASES*8];     // Upsampling
@@ -938,12 +903,8 @@
 		InitFloatmixerTables();
 
 		getsinc(gKaiserSinc, 9.6377, 0.97);
-		//ericus' downsampling improvement.
-		//getsinc(gDownsample13x, 8.5, 3.0/4.0);
-		//getdownsample2x(gDownsample2x);
 		getsinc(gDownsample13x, 8.5, 0.5);
 		getsinc(gDownsample2x, 2.7625, 0.425);
-		//end ericus' downsampling improvement.
 
 		#ifdef MODPLUG_TRACKER
 			StaticTablesInitialized = true;
Index: soundlib/WindowedFIR.h
===================================================================
--- soundlib/WindowedFIR.h	(revision 10070)
+++ soundlib/WindowedFIR.h	(working copy)
@@ -48,25 +48,20 @@
 #define WFIR_LOG2WIDTH		3
 #define WFIR_WIDTH			(1L<<WFIR_LOG2WIDTH)
 // cutoff (1.0 == pi/2)
-//float WFIR_CUTOFF			= 0.5f;//0.75f;	//0.90f;
 // wfir type
 enum WFIRType
 {
-	WFIR_HANN			= 0,
-	WFIR_HAMMING		= 1,
-	WFIR_BLACKMANEXACT	= 2,
-	WFIR_BLACKMAN3T61	= 3,
-	WFIR_BLACKMAN3T67	= 4,
-	WFIR_BLACKMAN4T92	= 5,
-	WFIR_BLACKMAN4T74	= 6,
-	WFIR_KAISER4T		= 7,
+	WFIR_HANN          = 0,  // Hann
+	WFIR_HAMMING       = 1,  // Hamming
+	WFIR_BLACKMANEXACT = 2,  // Blackman Exact
+	WFIR_BLACKMAN3T61  = 3,  // Blackman 3-Tap 61
+	WFIR_BLACKMAN3T67  = 4,  // Blackman 3-Tap 67
+	WFIR_BLACKMAN4T92  = 5,  // Blackman-Harris
+	WFIR_BLACKMAN4T74  = 6,  // Blackman 4-Tap 74
+	WFIR_KAISER4T      = 7,  // Kaiser a=7.5
 };
-//int WFIR_TYPE				= WFIR_KAISER4T;//WFIR_BLACKMANEXACT;
-//int WFIR_TYPE				= TrackerSettings::Instance().gbWFIRType;
 // wfir help
-#ifndef M_zPI
 #define M_zPI				3.1415926535897932384626433832795
-#endif
 #define M_zEPS				1e-8
 
 
Index: test/test.cpp
===================================================================
--- test/test.cpp	(revision 10070)
+++ test/test.cpp	(working copy)
@@ -2755,7 +2755,7 @@
 	VERIFY_EQUAL_NONCONT(pIns->nPPC, NOTE_MIDDLEC - 1);
 
 	VERIFY_EQUAL_NONCONT(pIns->nVolRampUp, 1200);
-	VERIFY_EQUAL_NONCONT(pIns->nResampling, (unsigned)SRCMODE_POLYPHASE);
+	VERIFY_EQUAL_NONCONT(pIns->nResampling, (unsigned)SRCMODE_SINC8LP);
 
 	VERIFY_EQUAL_NONCONT(pIns->IsCutoffEnabled(), false);
 	VERIFY_EQUAL_NONCONT(pIns->GetCutoff(), 0);
@@ -2885,7 +2885,7 @@
 	VERIFY_EQUAL_NONCONT(sndFile.m_nDefaultRowsPerBeat, 6);
 	VERIFY_EQUAL_NONCONT(sndFile.m_nDefaultRowsPerMeasure, 12);
 	VERIFY_EQUAL_NONCONT(sndFile.m_dwCreatedWithVersion, MAKE_VERSION_NUMERIC(1, 19, 02, 05));
-	VERIFY_EQUAL_NONCONT(sndFile.m_nResampling, SRCMODE_POLYPHASE);
+	VERIFY_EQUAL_NONCONT(sndFile.m_nResampling, SRCMODE_SINC8LP);
 	VERIFY_EQUAL_NONCONT(sndFile.m_songArtist, MPT_USTRING("Tester"));
 	VERIFY_EQUAL_NONCONT(sndFile.m_tempoSwing.size(), 6);
 	VERIFY_EQUAL_NONCONT(sndFile.m_tempoSwing[0], 29360125);
@@ -3048,7 +3048,7 @@
 		VERIFY_EQUAL_NONCONT(pIns->nPPC, (NOTE_MIDDLEC - NOTE_MIN) + 6);	// F#5
 
 		VERIFY_EQUAL_NONCONT(pIns->nVolRampUp, 1200);
-		VERIFY_EQUAL_NONCONT(pIns->nResampling, (unsigned)SRCMODE_POLYPHASE);
+		VERIFY_EQUAL_NONCONT(pIns->nResampling, (unsigned)SRCMODE_SINC8LP);
 
 		VERIFY_EQUAL_NONCONT(pIns->IsCutoffEnabled(), true);
 		VERIFY_EQUAL_NONCONT(pIns->GetCutoff(), 0x32);
resampler-cleanup-v4.patch (28,943 bytes)   
resampler-cleanup-v5.patch (28,900 bytes)   
Index: common/versionNumber.h
===================================================================
--- common/versionNumber.h	(revision 10764)
+++ common/versionNumber.h	(working copy)
@@ -21,7 +21,7 @@
 #define VER_MAJORMAJOR  1
 #define VER_MAJOR      28
 #define VER_MINOR      00
-#define VER_MINORMINOR 31
+#define VER_MINORMINOR 32
 
 //Numerical value of the version.
 #define MPT_VERSION_CURRENT MAKE_VERSION_NUMERIC(VER_MAJORMAJOR,VER_MAJOR,VER_MINOR,VER_MINORMINOR)
Index: libopenmpt/libopenmpt_impl.cpp
===================================================================
--- libopenmpt/libopenmpt_impl.cpp	(revision 10764)
+++ libopenmpt/libopenmpt_impl.cpp	(working copy)
@@ -328,13 +328,13 @@
 }
 
 static ResamplingMode filterlength_to_resamplingmode(std::int32_t length) {
-	ResamplingMode result = SRCMODE_POLYPHASE;
+	ResamplingMode result = SRCMODE_SINC8LP;
 	if ( length == 0 ) {
-		result = SRCMODE_POLYPHASE;
+		result = SRCMODE_SINC8LP;
 	} else if ( length >= 8 ) {
-		result = SRCMODE_POLYPHASE;
+		result = SRCMODE_SINC8LP;
 	} else if ( length >= 3 ) {
-		result = SRCMODE_SPLINE;
+		result = SRCMODE_CUBIC;
 	} else if ( length >= 2 ) {
 		result = SRCMODE_LINEAR;
 	} else if ( length >= 1 ) {
@@ -352,11 +352,11 @@
 	case SRCMODE_LINEAR:
 		return 2;
 		break;
-	case SRCMODE_SPLINE:
+	case SRCMODE_CUBIC:
 		return 4;
 		break;
-	case SRCMODE_POLYPHASE:
-	case SRCMODE_FIRFILTER:
+	case SRCMODE_SINC8:
+	case SRCMODE_SINC8LP:
 	case SRCMODE_DEFAULT:
 		return 8;
 	default:
Index: mptrack/Ctrl_gen.cpp
===================================================================
--- mptrack/Ctrl_gen.cpp	(revision 10764)
+++ mptrack/Ctrl_gen.cpp	(working copy)
@@ -202,21 +202,21 @@
 	FlagSet<HintType> hintType = hint.GetType();
 	const bool updateAll = hintType[HINT_MODTYPE];
 
-	const ResamplingMode resamplingModes[] = { SRCMODE_NEAREST, SRCMODE_LINEAR, SRCMODE_SPLINE, SRCMODE_POLYPHASE, SRCMODE_FIRFILTER };
+	const auto resamplingModes = Resampling::AllModes();
 
 	if (hintType == HINT_MPTOPTIONS || updateAll)
 	{
-		const TCHAR *defaultResampler;
+		CString defaultResampler;
 		if(m_sndFile.m_SongFlags[SONG_ISAMIGA] && TrackerSettings::Instance().ResamplerEmulateAmiga)
 			defaultResampler = _T("Amiga Resampler");
 		else
-			defaultResampler = CTrackApp::GetResamplingModeName(TrackerSettings::Instance().ResamplerMode, false);
+			defaultResampler = CTrackApp::GetResamplingModeName(TrackerSettings::Instance().ResamplerMode, 1, false);
 
 		m_CbnResampling.ResetContent();
-		m_CbnResampling.SetItemData(m_CbnResampling.AddString(_T("Default (") + CString(defaultResampler) + _T(")")), SRCMODE_DEFAULT);
+		m_CbnResampling.SetItemData(m_CbnResampling.AddString(_T("Default (") + defaultResampler + _T(")")), SRCMODE_DEFAULT);
 		for(auto mode : resamplingModes)
 		{
-			m_CbnResampling.SetItemData(m_CbnResampling.AddString(CTrackApp::GetResamplingModeName(mode, false)), mode);
+			m_CbnResampling.SetItemData(m_CbnResampling.AddString(CTrackApp::GetResamplingModeName(mode, 2, true)), mode);
 		}
 		m_CbnResampling.Invalidate(FALSE);
 	}
@@ -312,12 +312,13 @@
 
 	if(updateAll || hintType == HINT_MPTOPTIONS || (hint.GetCategory() == HINTCAT_GENERAL && hintType[HINT_MODGENERAL]))
 	{
+
 		int srcMode = 0;
-		for(int i = 0; i < CountOf(resamplingModes); i++)
+		for(int i = 0; i < m_CbnResampling.GetCount(); ++i)
 		{
-			if(m_sndFile.m_nResampling == resamplingModes[i]) srcMode = i + 1;
+			if(m_sndFile.m_nResampling == static_cast<int>(m_CbnResampling.GetItemData(i)))
+				m_CbnResampling.SetCurSel(i);
 		}
-		m_CbnResampling.SetCurSel(srcMode);
 	}
 
 	CheckDlgButton(IDC_CHECK_LOOPSONG, (TrackerSettings::Instance().gbLoopSong) ? TRUE : FALSE);
Index: mptrack/Ctrl_ins.cpp
===================================================================
--- mptrack/Ctrl_ins.cpp	(revision 10764)
+++ mptrack/Ctrl_ins.cpp	(working copy)
@@ -991,12 +991,12 @@
 	m_EditPWD.SubclassDlgItem(IDC_PITCHWHEELDEPTH, this);
 	m_EditPWD.AllowFractions(false);
 
+	const auto resamplingModes = Resampling::AllModes();
 	m_CbnResampling.SetItemData(m_CbnResampling.AddString(_T("Default")), SRCMODE_DEFAULT);
-	m_CbnResampling.SetItemData(m_CbnResampling.AddString(_T("None")), SRCMODE_NEAREST);
-	m_CbnResampling.SetItemData(m_CbnResampling.AddString(_T("Linear")), SRCMODE_LINEAR);
-	m_CbnResampling.SetItemData(m_CbnResampling.AddString(_T("Spline")), SRCMODE_SPLINE);
-	m_CbnResampling.SetItemData(m_CbnResampling.AddString(_T("Polyphase")), SRCMODE_POLYPHASE);
-	m_CbnResampling.SetItemData(m_CbnResampling.AddString(_T("XMMS")), SRCMODE_FIRFILTER);
+	for(auto mode : resamplingModes)
+	{
+		m_CbnResampling.SetItemData(m_CbnResampling.AddString(CTrackApp::GetResamplingModeName(mode, 1, false)), mode);
+	}
 
 	m_CbnFilterMode.SetItemData(m_CbnFilterMode.AddString(_T("Channel default")), FLTMODE_UNCHANGED);
 	m_CbnFilterMode.SetItemData(m_CbnFilterMode.AddString(_T("Force lowpass")), FLTMODE_LOWPASS);
Index: mptrack/Mpdlgs.cpp
===================================================================
--- mptrack/Mpdlgs.cpp	(revision 10764)
+++ mptrack/Mpdlgs.cpp	(working copy)
@@ -928,9 +928,7 @@
 	ON_WM_HSCROLL()
 	ON_WM_VSCROLL()
 	ON_CBN_SELCHANGE(IDC_COMBO_FILTER,			&COptionsMixer::OnResamplerChanged)
-	ON_CBN_SELCHANGE(IDC_COMBO_FILTERWINDOW,	&COptionsMixer::OnSettingsChanged)
 	ON_CBN_SELCHANGE(IDC_COMBO_POLYPHONY,		&COptionsMixer::OnSettingsChanged)
-	ON_EN_UPDATE(IDC_WFIRCUTOFF,				&COptionsMixer::OnSettingsChanged)
 	ON_EN_UPDATE(IDC_RAMPING_IN,				&COptionsMixer::OnRampingChanged)
 	ON_EN_UPDATE(IDC_RAMPING_OUT,				&COptionsMixer::OnRampingChanged)
 	ON_COMMAND(IDC_CHECK_SOFTPAN,				&COptionsMixer::OnSettingsChanged)
@@ -943,8 +941,6 @@
 	CPropertyPage::DoDataExchange(pDX);
 	//{{AFX_DATA_MAP(COptionsSoundcard)
 	DDX_Control(pDX, IDC_COMBO_FILTER, m_CbnResampling);
-	DDX_Control(pDX, IDC_WFIRCUTOFF, m_CEditWFIRCutoff);
-	DDX_Control(pDX, IDC_COMBO_FILTERWINDOW, m_CbnWFIRType);
 	DDX_Control(pDX, IDC_RAMPING_IN, m_CEditRampUp);
 	DDX_Control(pDX, IDC_RAMPING_OUT, m_CEditRampDown);
 	DDX_Control(pDX, IDC_EDIT_VOLRAMP_SAMPLES_UP, m_CInfoRampUp);
@@ -963,26 +959,18 @@
 
 	// Resampling type
 	{
-		for(auto mode : { SRCMODE_NEAREST, SRCMODE_LINEAR, SRCMODE_SPLINE, SRCMODE_POLYPHASE, SRCMODE_FIRFILTER })
+		const auto resamplingModes = Resampling::AllModes();
+		for(auto mode : resamplingModes)
 		{
-			int index = m_CbnResampling.AddString(CTrackApp::GetResamplingModeName(mode, true));
+			int index = m_CbnResampling.AddString(CTrackApp::GetResamplingModeName(mode, 2, true));
 			m_CbnResampling.SetItemData(index, mode);
 			if(TrackerSettings::Instance().ResamplerMode == mode)
+			{
 				m_CbnResampling.SetCurSel(index);
+			}
 		}
 	}
 
-	// Resampler bandwidth
-	{
-		m_CEditWFIRCutoff.SetWindowText(mpt::ToCString(mpt::ufmt::val(TrackerSettings::Instance().ResamplerCutoffPercent)));
-		static_cast<CSpinButtonCtrl *>(GetDlgItem(IDC_SPIN1))->SetRange32(1, 99);
-	}
-
-	// Resampler filter window
-	{
-		// done in OnResamplerChanged()
-	}
-
 	// Amiga Resampler
 	CheckDlgButton(IDC_CHECK1, TrackerSettings::Instance().ResamplerEmulateAmiga ? BST_CHECKED : BST_UNCHECKED);
 
@@ -1037,7 +1025,6 @@
 		m_SliderPreAmp.SetPos(n);
 	}
 
-	OnResamplerChanged();
 	m_initialized = true;
 
 	return TRUE;
@@ -1053,61 +1040,6 @@
 
 void COptionsMixer::OnResamplerChanged()
 {
-	ResamplingMode srcMode = static_cast<ResamplingMode>(m_CbnResampling.GetItemData(m_CbnResampling.GetCurSel()));
-	m_CbnWFIRType.ResetContent();
-	switch(srcMode)
-	{
-		case SRCMODE_FIRFILTER:
-			m_CbnWFIRType.AddString(_T("Hann"));
-			m_CbnWFIRType.AddString(_T("Hamming"));
-			m_CbnWFIRType.AddString(_T("Blackman Exact"));
-			m_CbnWFIRType.AddString(_T("Blackman 3 Tap 61"));
-			m_CbnWFIRType.AddString(_T("Blackman 3 Tap 67"));
-			m_CbnWFIRType.AddString(_T("Blackman Harris"));
-			m_CbnWFIRType.AddString(_T("Blackman 4 Tap 74"));
-			m_CbnWFIRType.AddString(_T("Kaiser a=7.5"));
-			break;
-		case SRCMODE_POLYPHASE:
-			m_CbnWFIRType.AddString(_T("Auto"));
-			m_CbnWFIRType.AddString(_T("Auto"));
-			m_CbnWFIRType.AddString(_T("Auto"));
-			m_CbnWFIRType.AddString(_T("Auto"));
-			m_CbnWFIRType.AddString(_T("Auto"));
-			m_CbnWFIRType.AddString(_T("Auto"));
-			m_CbnWFIRType.AddString(_T("Auto"));
-			m_CbnWFIRType.AddString(_T("Auto"));
-			break;
-		default:
-			m_CbnWFIRType.AddString(_T("none"));
-			m_CbnWFIRType.AddString(_T("none"));
-			m_CbnWFIRType.AddString(_T("none"));
-			m_CbnWFIRType.AddString(_T("none"));
-			m_CbnWFIRType.AddString(_T("none"));
-			m_CbnWFIRType.AddString(_T("none"));
-			m_CbnWFIRType.AddString(_T("none"));
-			m_CbnWFIRType.AddString(_T("none"));
-			break;
-	}
-	m_CbnWFIRType.SetCurSel(TrackerSettings::Instance().ResamplerSubMode);
-	CSpinButtonCtrl *spinWFIRCutoff = static_cast<CSpinButtonCtrl *>(GetDlgItem(IDC_SPIN1));
-	switch(srcMode)
-	{
-		case SRCMODE_POLYPHASE:
-			m_CEditWFIRCutoff.EnableWindow(FALSE);
-			spinWFIRCutoff->EnableWindow(FALSE);
-			m_CbnWFIRType.EnableWindow(FALSE);
-			break;
-		case SRCMODE_FIRFILTER:
-			m_CEditWFIRCutoff.EnableWindow(TRUE);
-			spinWFIRCutoff->EnableWindow(TRUE);
-			m_CbnWFIRType.EnableWindow(TRUE);
-			break;
-		default:
-			m_CEditWFIRCutoff.EnableWindow(FALSE);
-			spinWFIRCutoff->EnableWindow(FALSE);
-			m_CbnWFIRType.EnableWindow(FALSE);
-			break;
-	}
 	OnSettingsChanged();
 }
 
@@ -1162,27 +1094,6 @@
 		TrackerSettings::Instance().ResamplerMode = static_cast<ResamplingMode>(m_CbnResampling.GetItemData(m_CbnResampling.GetCurSel()));
 	}
 
-	// resampler bandwidth
-	{
-		CString s;
-		m_CEditWFIRCutoff.GetWindowText(s);
-		if(s != "")
-		{
-			int newCutoff = ConvertStrTo<int>(s);
-			Limit(newCutoff, 0, 100);
-			TrackerSettings::Instance().ResamplerCutoffPercent = newCutoff;
-		}
-		{
-			s.Format(_T("%d"), TrackerSettings::Instance().ResamplerCutoffPercent.Get());
-			m_CEditWFIRCutoff.SetWindowText(s);
-		}
-	}
-
-	// resampler filter window
-	{
-		TrackerSettings::Instance().ResamplerSubMode = (uint8)m_CbnWFIRType.GetCurSel();
-	}
-
 	// Amiga Resampler
 	TrackerSettings::Instance().ResamplerEmulateAmiga = IsDlgButtonChecked(IDC_CHECK1) != BST_UNCHECKED;
 
Index: mptrack/Mpdlgs.h
===================================================================
--- mptrack/Mpdlgs.h	(revision 10764)
+++ mptrack/Mpdlgs.h	(working copy)
@@ -90,8 +90,6 @@
 protected:
 
 	CComboBox m_CbnResampling;
-	CEdit m_CEditWFIRCutoff;
-	CComboBox m_CbnWFIRType;
 
 	CEdit m_CEditRampUp;
 	CEdit m_CEditRampDown;
Index: mptrack/Mptrack.cpp
===================================================================
--- mptrack/Mptrack.cpp	(revision 10764)
+++ mptrack/Mptrack.cpp	(working copy)
@@ -2022,24 +2022,39 @@
 }
 
 
-const TCHAR *CTrackApp::GetResamplingModeName(ResamplingMode mode, bool addTaps)
+CString CTrackApp::GetResamplingModeName(ResamplingMode mode, int length, bool addTaps)
 {
+	CString result;
 	switch(mode)
 	{
 	case SRCMODE_NEAREST:
-		return addTaps ? _T("No Interpolation (1 tap)") : _T("No Interpolation");
+		result = (length > 1) ? _T("No Interpolation") : _T("None") ;
+		break;
 	case SRCMODE_LINEAR:
-		return addTaps ? _T("Linear (2 tap)") : _T("Linear");
-	case SRCMODE_SPLINE:
-		return addTaps ? _T("Cubic Spline (4 tap)") :  _T("Cubic Spline");
-	case SRCMODE_POLYPHASE:
-		return addTaps ? _T("Polyphase (8 tap)") : _T("Polyphase");
-	case SRCMODE_FIRFILTER:
-		return addTaps ? _T("XMMS-ModPlug (8 tap)") : _T("XMMS-ModPlug");
+		result = _T("Linear");
+		break;
+	case SRCMODE_CUBIC:
+		result = _T("Cubic");
+		break;
+	case SRCMODE_SINC8:
+		result = _T("Sinc");
+		break;
+	case SRCMODE_SINC8LP:
+		result = _T("Sinc");
+		break;
 	default:
 		MPT_ASSERT_NOTREACHED();
+		break;
 	}
-	return _T("");
+	if(Resampling::HasAA(mode))
+	{
+		result += (length > 1) ? _T(" + Low-Pass") : _T(" + LP");
+	}
+	if(addTaps)
+	{
+		result += mpt::cformat(_T(" (%1 tap%2)"))(Resampling::Length(mode), (Resampling::Length(mode) != 1) ? CString(_T("s")) : CString(_T("")));
+	}
+	return result;
 }
 
 
Index: mptrack/Mptrack.h
===================================================================
--- mptrack/Mptrack.h	(revision 10764)
+++ mptrack/Mptrack.h	(working copy)
@@ -274,7 +274,7 @@
 
 public:
 	// Get name of resampling mode. addTaps = true also adds the number of taps the filter uses.
-	static const TCHAR *GetResamplingModeName(ResamplingMode mode, bool addTaps);
+	static CString GetResamplingModeName(ResamplingMode mode, int length, bool addTaps);
 
 // Overrides
 public:
Index: mptrack/mptrack.rc
===================================================================
--- mptrack/mptrack.rc	(revision 10764)
+++ mptrack/mptrack.rc	(working copy)
@@ -2093,15 +2093,9 @@
 BEGIN
     GROUPBOX        "Resampling",IDC_STATIC,6,6,276,48
     LTEXT           "&Filter:",IDC_STATIC,12,18,24,12,SS_CENTERIMAGE
-    COMBOBOX        IDC_COMBO_FILTER,54,18,96,56,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
-    LTEXT           "&Window:",IDC_STATIC,156,18,30,12,SS_CENTERIMAGE
-    COMBOBOX        IDC_COMBO_FILTERWINDOW,192,18,84,56,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
-    LTEXT           "&Bandwidth:",IDC_STATIC,12,36,42,12,SS_CENTERIMAGE
-    EDITTEXT        IDC_WFIRCUTOFF,54,36,30,12,ES_RIGHT | ES_AUTOHSCROLL | ES_NUMBER
-    CONTROL         "",IDC_SPIN1,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_NOTHOUSANDS,71,31,11,14
-    LTEXT           "%",IDC_STATIC,90,36,24,12,SS_CENTERIMAGE
+    COMBOBOX        IDC_COMBO_FILTER,36,18,102,56,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
     CONTROL         "Use &Amiga resampler for Amiga modules",IDC_CHECK1,
-                    "Button",BS_AUTOCHECKBOX | WS_TABSTOP,126,36,150,12
+                    "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,36,144,12
     GROUPBOX        "Volume Ramping",IDC_STATIC,6,60,276,48
     EDITTEXT        IDC_RAMPING_IN,12,72,36,12,ES_RIGHT | ES_AUTOHSCROLL | ES_NUMBER
     CONTROL         "",IDC_SPIN2,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_NOTHOUSANDS,42,66,11,14
Index: mptrack/resource.h
===================================================================
--- mptrack/resource.h	(revision 10764)
+++ mptrack/resource.h	(working copy)
@@ -685,8 +685,6 @@
 #define IDC_COMMAND_LIST                2129
 #define IDC_STATIC8                     2200
 #define IDC_PATINSTROPLUGGUI            2201
-#define IDC_WFIRCUTOFF                  2202
-#define IDC_WFIRTYPE                    2203
 #define IDC_RAMPING_IN                  2204
 #define IDC_PLAYEROPTIONS               2205
 #define IDC_RAMPING_OUT                 2205
Index: mptrack/SampleEditorDialogs.cpp
===================================================================
--- mptrack/SampleEditorDialogs.cpp	(revision 10764)
+++ mptrack/SampleEditorDialogs.cpp	(working copy)
@@ -534,12 +534,12 @@
 
 	CComboBox *cbnResampling = static_cast<CComboBox *>(GetDlgItem(IDC_COMBO_FILTER));
 	cbnResampling->SetRedraw(FALSE);
-	const ResamplingMode resamplingModes[] = { SRCMODE_NEAREST, SRCMODE_LINEAR, SRCMODE_SPLINE, SRCMODE_POLYPHASE, SRCMODE_FIRFILTER, SRCMODE_DEFAULT };
+	const auto resamplingModes = Resampling::AllModesWithDefault();
 	for(auto mode : resamplingModes)
 	{
-		const TCHAR *desc = _T("r8brain (High Quality)");
+		CString desc = _T("r8brain (High Quality)");
 		if(mode != SRCMODE_DEFAULT)
-			desc = CTrackApp::GetResamplingModeName(mode, false);
+			desc = CTrackApp::GetResamplingModeName(mode, 1, true);
 
 		int index = cbnResampling->AddString(desc);
 		cbnResampling->SetItemData(index, mode);
Index: mptrack/TrackerSettings.cpp
===================================================================
--- mptrack/TrackerSettings.cpp	(revision 10764)
+++ mptrack/TrackerSettings.cpp	(working copy)
@@ -74,29 +74,6 @@
 }
 
 
-static ResamplingMode GetDefaultResamplerMode()
-{
-	ResamplingMode result = CResamplerSettings().SrcMode;
-#ifdef ENABLE_ASM
-	// rough heuristic to select less cpu consuming defaults for old CPUs
-	if(GetRealProcSupport() & PROCSUPPORT_SSE)
-	{
-		result = SRCMODE_POLYPHASE;
-	} else if(GetRealProcSupport() & PROCSUPPORT_MMX)
-	{
-		result = SRCMODE_SPLINE;
-	} else
-	{
-		result = SRCMODE_LINEAR;
-	}
-#else
-	// just use a sane default
-	result = CResamplerSettings().SrcMode;
-#endif
-	return result;
-}
-
-
 static uint32 GetDefaultPatternSetup()
 {
 	return PATTERN_PLAYNEWNOTE | PATTERN_EFFECTHILIGHT
@@ -244,7 +221,7 @@
 	, MixerStereoSeparation(conf, MPT_USTRING("Sound Settings"), MPT_USTRING("StereoSeparation"), MixerSettings().m_nStereoSeparation)
 	, MixerVolumeRampUpMicroseconds(conf, MPT_USTRING("Sound Settings"), MPT_USTRING("VolumeRampUpMicroseconds"), MixerSettings().GetVolumeRampUpMicroseconds())
 	, MixerVolumeRampDownMicroseconds(conf, MPT_USTRING("Sound Settings"), MPT_USTRING("VolumeRampDownMicroseconds"), MixerSettings().GetVolumeRampDownMicroseconds())
-	, ResamplerMode(conf, MPT_USTRING("Sound Settings"), MPT_USTRING("SrcMode"), GetDefaultResamplerMode())
+	, ResamplerMode(conf, MPT_USTRING("Sound Settings"), MPT_USTRING("SrcMode"), CResamplerSettings().SrcMode)
 	, ResamplerSubMode(conf, MPT_USTRING("Sound Settings"), MPT_USTRING("XMMSModplugResamplerWFIRType"), CResamplerSettings().gbWFIRType)
 	, ResamplerCutoffPercent(conf, MPT_USTRING("Sound Settings"), MPT_USTRING("ResamplerWFIRCutoff"), mpt::saturate_round<int32>(CResamplerSettings().gdWFIRCutoff * 100.0))
 	, ResamplerEmulateAmiga(conf, MPT_USTRING("Sound Settings"), MPT_USTRING("ResamplerEmulateAmiga"), true)
@@ -546,6 +523,13 @@
 		m_SoundDeviceSettingsDefaults.UseHardwareTiming = m_SoundDeviceUseHardwareTiming;
 		m_SoundDeviceSettingsUseOldDefaults = true;
 	}
+	if(storedVersion < MAKE_VERSION_NUMERIC(1,28,00,32))
+	{
+		// reset this setting to the default when updating,
+		// because we do not provide a GUI any more,
+		// and in general, it should not get changed anyway
+		ResamplerCutoffPercent = mpt::saturate_round<int32>(CResamplerSettings().gdWFIRCutoff * 100.0);
+	}
 	if(storedVersion < MAKE_VERSION_NUMERIC(1,25,00,04))
 	{
 		m_SoundDeviceDirectSoundOldDefaultIdentifier = true;
@@ -678,7 +662,7 @@
 	}
 
 	// Sanitize resampling mode for sample editor
-	if(!IsKnownResamplingMode(sampleEditorDefaultResampler) && sampleEditorDefaultResampler != SRCMODE_DEFAULT)
+	if(!Resampling::IsKnownMode(sampleEditorDefaultResampler) && sampleEditorDefaultResampler != SRCMODE_DEFAULT)
 	{
 		sampleEditorDefaultResampler = SRCMODE_DEFAULT;
 	}
Index: soundlib/Load_it.cpp
===================================================================
--- soundlib/Load_it.cpp	(revision 10764)
+++ soundlib/Load_it.cpp	(working copy)
@@ -2381,7 +2381,7 @@
 			case MagicBE("RP.."): if(GetType() != MOD_TYPE_XM) { ORDERINDEX restartPos; ReadField(chunk, size, restartPos); Order().SetRestartPos(restartPos); } break;
 			case MagicLE("RSMP"):
 				ReadFieldCast(chunk, size, m_nResampling);
-				if(!IsKnownResamplingMode(m_nResampling)) m_nResampling = SRCMODE_DEFAULT;
+				if(!Resampling::IsKnownMode(m_nResampling)) m_nResampling = SRCMODE_DEFAULT;
 				break;
 #ifdef MODPLUG_TRACKER
 			case MagicBE("MIMA"): GetMIDIMapper().Deserialize(chunk); break;
Index: soundlib/MixFuncTable.cpp
===================================================================
--- soundlib/MixFuncTable.cpp	(revision 10764)
+++ soundlib/MixFuncTable.cpp	(working copy)
@@ -79,9 +79,9 @@
 	{
 	case SRCMODE_NEAREST:   return ndxNoInterpolation;
 	case SRCMODE_LINEAR:    return ndxLinear;
-	case SRCMODE_SPLINE:    return ndxFastSinc;
-	case SRCMODE_POLYPHASE: return ndxKaiser;
-	case SRCMODE_FIRFILTER: return ndxFIRFilter;
+	case SRCMODE_CUBIC:     return ndxFastSinc;
+	case SRCMODE_SINC8LP:   return ndxKaiser;
+	case SRCMODE_SINC8:     return ndxFIRFilter;
 	case SRCMODE_AMIGA:     return ndxAmigaBlep;
 	default:                MPT_ASSERT_NOTREACHED();
 	}
Index: soundlib/Resampler.h
===================================================================
--- soundlib/Resampler.h	(revision 10764)
+++ soundlib/Resampler.h	(working copy)
@@ -61,12 +61,12 @@
 	uint8 gbWFIRType;
 	bool emulateAmiga;
 public:
-	CResamplerSettings()
+	MPT_CONSTEXPR11_FUN CResamplerSettings()
+		: SrcMode(Resampling::Default())
+		, gdWFIRCutoff(0.97)
+		, gbWFIRType(WFIR_KAISER4T)
+		, emulateAmiga(false)
 	{
-		SrcMode = SRCMODE_POLYPHASE;
-		gdWFIRCutoff = 0.97;
-		gbWFIRType = WFIR_KAISER4T;
-		emulateAmiga = false;
 	}
 	bool operator == (const CResamplerSettings &cmp) const
 	{
@@ -127,8 +127,6 @@
 	{
 		InitializeTablesFromScratch(false);
 	}
-	~CResampler() {}
-	bool IsHQ() const { return m_Settings.SrcMode >= SRCMODE_SPLINE && m_Settings.SrcMode < SRCMODE_DEFAULT; }
 private:
 	void InitFloatmixerTables();
 	void InitializeTablesFromScratch(bool force=false);
Index: soundlib/Snd_defs.h
===================================================================
--- soundlib/Snd_defs.h	(revision 10764)
+++ soundlib/Snd_defs.h	(working copy)
@@ -299,22 +299,55 @@
 {
 	// ATTENTION: Do not change ANY of these values, as they get written out to files in per instrument interpolation settings
 	// and old files have these exact values in them which should not change meaning.
-	SRCMODE_NEAREST   = 0,
-	SRCMODE_LINEAR    = 1,
-	SRCMODE_SPLINE    = 2,
-	SRCMODE_POLYPHASE = 3,
-	SRCMODE_FIRFILTER = 4,
-	SRCMODE_DEFAULT   = 5,
+	SRCMODE_NEAREST   = 0,  // 1 tap, no AA
+	SRCMODE_LINEAR    = 1,  // 2 tap, no AA
+	SRCMODE_CUBIC     = 2,  // 4 tap, no AA
+	SRCMODE_SINC8     = 4,  // 8 tap, no AA   (yes, index 4) (XMMS-ModPlug)
+	SRCMODE_SINC8LP   = 3,  // 8 tap, with AA (yes, index 3) (Polyphase)
 
-	SRCMODE_AMIGA = 0xFF,	// Not explicitely user-selectable
+	SRCMODE_DEFAULT   = 5,  // only used for instrument settings, not used inside the mixer
+
+	SRCMODE_AMIGA  = 0xFF,  // Not explicitely user-selectable
 };
 
-static inline bool IsKnownResamplingMode(int mode)
+namespace Resampling
 {
-	return (mode >= 0) && (mode < SRCMODE_DEFAULT);
+
+static inline std::array<ResamplingMode, 5> AllModes() noexcept { return { SRCMODE_NEAREST, SRCMODE_LINEAR, SRCMODE_CUBIC, SRCMODE_SINC8, SRCMODE_SINC8LP }; }
+
+static inline std::array<ResamplingMode, 6> AllModesWithDefault() noexcept { return { SRCMODE_NEAREST, SRCMODE_LINEAR, SRCMODE_CUBIC, SRCMODE_SINC8, SRCMODE_SINC8LP, SRCMODE_DEFAULT }; }
+
+static MPT_CONSTEXPR11_FUN ResamplingMode Default() noexcept { return SRCMODE_SINC8LP; }
+
+static MPT_CONSTEXPR11_FUN bool IsKnownMode(int mode) noexcept { return (mode >= 0) && (mode < SRCMODE_DEFAULT); }
+
+static MPT_CONSTEXPR11_FUN ResamplingMode ToKnownMode(int mode) noexcept
+{
+	return Resampling::IsKnownMode(mode) ? static_cast<ResamplingMode>(mode)
+		: (mode == SRCMODE_AMIGA) ? SRCMODE_LINEAR
+		: Resampling::Default();
 }
 
+static MPT_CONSTEXPR11_FUN int Length(ResamplingMode mode) noexcept
+{
+	return mode == SRCMODE_NEAREST ? 1
+		: mode == SRCMODE_LINEAR ? 2
+		: mode == SRCMODE_CUBIC ? 4
+		: mode == SRCMODE_SINC8 ? 8
+		: mode == SRCMODE_SINC8LP ? 8
+		: 0;
+}
 
+static MPT_CONSTEXPR11_FUN bool HasAA(ResamplingMode mode) noexcept { return (mode == SRCMODE_SINC8LP); }
+
+static MPT_CONSTEXPR11_FUN ResamplingMode AddAA(ResamplingMode mode) noexcept { return (mode == SRCMODE_SINC8) ? SRCMODE_SINC8LP : mode; }
+
+static MPT_CONSTEXPR11_FUN ResamplingMode RemoveAA(ResamplingMode mode) noexcept { return (mode == SRCMODE_SINC8LP) ? SRCMODE_SINC8 : mode; }
+
+}
+
+
+
 // Release node defines
 #define ENV_RELEASE_NODE_UNSET	0xFF
 #define NOT_YET_RELEASED		(-1)
Index: soundlib/Sndmix.cpp
===================================================================
--- soundlib/Sndmix.cpp	(revision 10764)
+++ soundlib/Sndmix.cpp	(working copy)
@@ -2376,11 +2376,11 @@
 			//if (chn.nNewRightVol > 0xFFFF) chn.nNewRightVol = 0xFFFF;
 			//if (chn.nNewLeftVol > 0xFFFF) chn.nNewLeftVol = 0xFFFF;
 
-			if(chn.pModInstrument && IsKnownResamplingMode(chn.pModInstrument->nResampling))
+			if(chn.pModInstrument && Resampling::IsKnownMode(chn.pModInstrument->nResampling))
 			{
 				// For defined resampling modes, use per-instrument resampling mode if set
 				chn.resamplingMode = static_cast<uint8>(chn.pModInstrument->nResampling);
-			} else if(IsKnownResamplingMode(m_nResampling))
+			} else if(Resampling::IsKnownMode(m_nResampling))
 			{
 				chn.resamplingMode = static_cast<uint8>(m_nResampling);
 			} else if(m_SongFlags[SONG_ISAMIGA] && m_Resampler.m_Settings.emulateAmiga)
Index: soundlib/Tables.cpp
===================================================================
--- soundlib/Tables.cpp	(revision 10764)
+++ soundlib/Tables.cpp	(working copy)
@@ -748,42 +748,7 @@
 	}
 }
 
-#if 0
 
-// this code is currently unused
-
-static double GetSpline(double x, double c0, double c1, double c2, double c3)
-{
-	double Xo = c1;
-	double Xa = c0 - Xo;
-	double Xb = c2 - Xo;
-	double Ux = (Xb-Xa)/2;
-	double Vx = (c3 - Xo)/2;
-	double a = Vx+Ux-2*Xb;
-	double b = 3*Xb-2*Ux-Vx;
-	return (((a*x+b)*x)+Ux)*x+Xo;
-}
-
-
-static void getdownsample2x(short int *psinc)
-{
-	for (int i=0; i<SINC_PHASES; i++)
-	{
-		double x = (double)i * (double)(0.5/SINC_PHASES);
-		psinc[i*8+7] = (short int)(GetSpline(x,     0, 0, 0, 1) * 8192);
-		psinc[i*8+6] = (short int)(GetSpline(x+0.5, 0, 0, 0, 1) * 8192);
-		psinc[i*8+5] = (short int)(GetSpline(x,     0, 0, 1, 0) * 8192);
-		psinc[i*8+4] = (short int)(GetSpline(x+0.5, 0, 0, 1, 0) * 8192);
-		psinc[i*8+3] = (short int)(GetSpline(x,     0, 1, 0, 0) * 8192);
-		psinc[i*8+2] = (short int)(GetSpline(x+0.5, 0, 1, 0, 0) * 8192);
-		psinc[i*8+1] = (short int)(GetSpline(x,     1, 0, 0, 0) * 8192);
-		psinc[i*8+0] = (short int)(GetSpline(x+0.5, 1, 0, 0, 0) * 8192);
-	}
-}
-
-#endif
-
-
 #ifdef MODPLUG_TRACKER
 bool CResampler::StaticTablesInitialized = false;
 SINC_TYPE CResampler::gKaiserSinc[SINC_PHASES*8];     // Upsampling
@@ -833,12 +798,8 @@
 		InitFloatmixerTables();
 
 		getsinc(gKaiserSinc, 9.6377, 0.97);
-		//ericus' downsampling improvement.
-		//getsinc(gDownsample13x, 8.5, 3.0/4.0);
-		//getdownsample2x(gDownsample2x);
 		getsinc(gDownsample13x, 8.5, 0.5);
 		getsinc(gDownsample2x, 2.7625, 0.425);
-		//end ericus' downsampling improvement.
 
 		#ifdef MODPLUG_TRACKER
 			StaticTablesInitialized = true;
Index: soundlib/WindowedFIR.h
===================================================================
--- soundlib/WindowedFIR.h	(revision 10764)
+++ soundlib/WindowedFIR.h	(working copy)
@@ -50,25 +50,20 @@
 #define WFIR_LOG2WIDTH		3
 #define WFIR_WIDTH			(1L<<WFIR_LOG2WIDTH)
 // cutoff (1.0 == pi/2)
-//float WFIR_CUTOFF			= 0.5f;//0.75f;	//0.90f;
 // wfir type
 enum WFIRType
 {
-	WFIR_HANN			= 0,
-	WFIR_HAMMING		= 1,
-	WFIR_BLACKMANEXACT	= 2,
-	WFIR_BLACKMAN3T61	= 3,
-	WFIR_BLACKMAN3T67	= 4,
-	WFIR_BLACKMAN4T92	= 5,
-	WFIR_BLACKMAN4T74	= 6,
-	WFIR_KAISER4T		= 7,
+	WFIR_HANN          = 0,  // Hann
+	WFIR_HAMMING       = 1,  // Hamming
+	WFIR_BLACKMANEXACT = 2,  // Blackman Exact
+	WFIR_BLACKMAN3T61  = 3,  // Blackman 3-Tap 61
+	WFIR_BLACKMAN3T67  = 4,  // Blackman 3-Tap 67
+	WFIR_BLACKMAN4T92  = 5,  // Blackman-Harris
+	WFIR_BLACKMAN4T74  = 6,  // Blackman 4-Tap 74
+	WFIR_KAISER4T      = 7,  // Kaiser a=7.5
 };
-//int WFIR_TYPE				= WFIR_KAISER4T;//WFIR_BLACKMANEXACT;
-//int WFIR_TYPE				= TrackerSettings::Instance().gbWFIRType;
 // wfir help
-#ifndef M_zPI
 #define M_zPI				3.1415926535897932384626433832795
-#endif
 #define M_zEPS				1e-8
 
 
Index: test/test.cpp
===================================================================
--- test/test.cpp	(revision 10764)
+++ test/test.cpp	(working copy)
@@ -3070,7 +3070,7 @@
 	VERIFY_EQUAL_NONCONT(pIns->nPPC, NOTE_MIDDLEC - 1);
 
 	VERIFY_EQUAL_NONCONT(pIns->nVolRampUp, 1200);
-	VERIFY_EQUAL_NONCONT(pIns->nResampling, (unsigned)SRCMODE_POLYPHASE);
+	VERIFY_EQUAL_NONCONT(pIns->nResampling, (unsigned)SRCMODE_SINC8LP);
 
 	VERIFY_EQUAL_NONCONT(pIns->IsCutoffEnabled(), false);
 	VERIFY_EQUAL_NONCONT(pIns->GetCutoff(), 0);
@@ -3200,7 +3200,7 @@
 	VERIFY_EQUAL_NONCONT(sndFile.m_nDefaultRowsPerBeat, 6);
 	VERIFY_EQUAL_NONCONT(sndFile.m_nDefaultRowsPerMeasure, 12);
 	VERIFY_EQUAL_NONCONT(sndFile.m_dwCreatedWithVersion, MAKE_VERSION_NUMERIC(1, 19, 02, 05));
-	VERIFY_EQUAL_NONCONT(sndFile.m_nResampling, SRCMODE_POLYPHASE);
+	VERIFY_EQUAL_NONCONT(sndFile.m_nResampling, SRCMODE_SINC8LP);
 	VERIFY_EQUAL_NONCONT(sndFile.m_songArtist, MPT_USTRING("Tester"));
 	VERIFY_EQUAL_NONCONT(sndFile.m_tempoSwing.size(), 6);
 	VERIFY_EQUAL_NONCONT(sndFile.m_tempoSwing[0], 29360125);
@@ -3363,7 +3363,7 @@
 		VERIFY_EQUAL_NONCONT(pIns->nPPC, (NOTE_MIDDLEC - NOTE_MIN) + 6);	// F#5
 
 		VERIFY_EQUAL_NONCONT(pIns->nVolRampUp, 1200);
-		VERIFY_EQUAL_NONCONT(pIns->nResampling, (unsigned)SRCMODE_POLYPHASE);
+		VERIFY_EQUAL_NONCONT(pIns->nResampling, (unsigned)SRCMODE_SINC8LP);
 
 		VERIFY_EQUAL_NONCONT(pIns->IsCutoffEnabled(), true);
 		VERIFY_EQUAL_NONCONT(pIns->GetCutoff(), 0x32);
resampler-cleanup-v5.patch (28,900 bytes)   
resampler-cleanup-v7.patch (28,900 bytes)   
Index: common/versionNumber.h
===================================================================
--- common/versionNumber.h	(revision 10963)
+++ common/versionNumber.h	(working copy)
@@ -21,7 +21,7 @@
 #define VER_MAJORMAJOR  1
 #define VER_MAJOR      28
 #define VER_MINOR      00
-#define VER_MINORMINOR 37
+#define VER_MINORMINOR 38
 
 //Numerical value of the version.
 #define MPT_VERSION_CURRENT MAKE_VERSION_NUMERIC(VER_MAJORMAJOR,VER_MAJOR,VER_MINOR,VER_MINORMINOR)
Index: libopenmpt/libopenmpt_impl.cpp
===================================================================
--- libopenmpt/libopenmpt_impl.cpp	(revision 10963)
+++ libopenmpt/libopenmpt_impl.cpp	(working copy)
@@ -332,13 +332,13 @@
 }
 
 static ResamplingMode filterlength_to_resamplingmode(std::int32_t length) {
-	ResamplingMode result = SRCMODE_POLYPHASE;
+	ResamplingMode result = SRCMODE_SINC8LP;
 	if ( length == 0 ) {
-		result = SRCMODE_POLYPHASE;
+		result = SRCMODE_SINC8LP;
 	} else if ( length >= 8 ) {
-		result = SRCMODE_POLYPHASE;
+		result = SRCMODE_SINC8LP;
 	} else if ( length >= 3 ) {
-		result = SRCMODE_SPLINE;
+		result = SRCMODE_CUBIC;
 	} else if ( length >= 2 ) {
 		result = SRCMODE_LINEAR;
 	} else if ( length >= 1 ) {
@@ -356,11 +356,11 @@
 	case SRCMODE_LINEAR:
 		return 2;
 		break;
-	case SRCMODE_SPLINE:
+	case SRCMODE_CUBIC:
 		return 4;
 		break;
-	case SRCMODE_POLYPHASE:
-	case SRCMODE_FIRFILTER:
+	case SRCMODE_SINC8:
+	case SRCMODE_SINC8LP:
 	case SRCMODE_DEFAULT:
 		return 8;
 	default:
Index: mptrack/Ctrl_gen.cpp
===================================================================
--- mptrack/Ctrl_gen.cpp	(revision 10963)
+++ mptrack/Ctrl_gen.cpp	(working copy)
@@ -202,21 +202,21 @@
 	FlagSet<HintType> hintType = hint.GetType();
 	const bool updateAll = hintType[HINT_MODTYPE];
 
-	const ResamplingMode resamplingModes[] = { SRCMODE_NEAREST, SRCMODE_LINEAR, SRCMODE_SPLINE, SRCMODE_POLYPHASE, SRCMODE_FIRFILTER };
+	const auto resamplingModes = Resampling::AllModes();
 
 	if (hintType == HINT_MPTOPTIONS || updateAll)
 	{
-		const TCHAR *defaultResampler;
+		CString defaultResampler;
 		if(m_sndFile.m_SongFlags[SONG_ISAMIGA] && TrackerSettings::Instance().ResamplerEmulateAmiga)
 			defaultResampler = _T("Amiga Resampler");
 		else
-			defaultResampler = CTrackApp::GetResamplingModeName(TrackerSettings::Instance().ResamplerMode, false);
+			defaultResampler = CTrackApp::GetResamplingModeName(TrackerSettings::Instance().ResamplerMode, 1, false);
 
 		m_CbnResampling.ResetContent();
-		m_CbnResampling.SetItemData(m_CbnResampling.AddString(_T("Default (") + CString(defaultResampler) + _T(")")), SRCMODE_DEFAULT);
+		m_CbnResampling.SetItemData(m_CbnResampling.AddString(_T("Default (") + defaultResampler + _T(")")), SRCMODE_DEFAULT);
 		for(auto mode : resamplingModes)
 		{
-			m_CbnResampling.SetItemData(m_CbnResampling.AddString(CTrackApp::GetResamplingModeName(mode, false)), mode);
+			m_CbnResampling.SetItemData(m_CbnResampling.AddString(CTrackApp::GetResamplingModeName(mode, 2, true)), mode);
 		}
 		m_CbnResampling.Invalidate(FALSE);
 	}
@@ -312,12 +312,13 @@
 
 	if(updateAll || hintType == HINT_MPTOPTIONS || (hint.GetCategory() == HINTCAT_GENERAL && hintType[HINT_MODGENERAL]))
 	{
+
 		int srcMode = 0;
-		for(int i = 0; i < CountOf(resamplingModes); i++)
+		for(int i = 0; i < m_CbnResampling.GetCount(); ++i)
 		{
-			if(m_sndFile.m_nResampling == resamplingModes[i]) srcMode = i + 1;
+			if(m_sndFile.m_nResampling == static_cast<int>(m_CbnResampling.GetItemData(i)))
+				m_CbnResampling.SetCurSel(i);
 		}
-		m_CbnResampling.SetCurSel(srcMode);
 	}
 
 	CheckDlgButton(IDC_CHECK_LOOPSONG, (TrackerSettings::Instance().gbLoopSong) ? TRUE : FALSE);
Index: mptrack/Ctrl_ins.cpp
===================================================================
--- mptrack/Ctrl_ins.cpp	(revision 10963)
+++ mptrack/Ctrl_ins.cpp	(working copy)
@@ -992,12 +992,12 @@
 	m_EditPWD.SubclassDlgItem(IDC_PITCHWHEELDEPTH, this);
 	m_EditPWD.AllowFractions(false);
 
+	const auto resamplingModes = Resampling::AllModes();
 	m_CbnResampling.SetItemData(m_CbnResampling.AddString(_T("Default")), SRCMODE_DEFAULT);
-	m_CbnResampling.SetItemData(m_CbnResampling.AddString(_T("None")), SRCMODE_NEAREST);
-	m_CbnResampling.SetItemData(m_CbnResampling.AddString(_T("Linear")), SRCMODE_LINEAR);
-	m_CbnResampling.SetItemData(m_CbnResampling.AddString(_T("Spline")), SRCMODE_SPLINE);
-	m_CbnResampling.SetItemData(m_CbnResampling.AddString(_T("Polyphase")), SRCMODE_POLYPHASE);
-	m_CbnResampling.SetItemData(m_CbnResampling.AddString(_T("XMMS")), SRCMODE_FIRFILTER);
+	for(auto mode : resamplingModes)
+	{
+		m_CbnResampling.SetItemData(m_CbnResampling.AddString(CTrackApp::GetResamplingModeName(mode, 1, false)), mode);
+	}
 
 	m_CbnFilterMode.SetItemData(m_CbnFilterMode.AddString(_T("Channel default")), FLTMODE_UNCHANGED);
 	m_CbnFilterMode.SetItemData(m_CbnFilterMode.AddString(_T("Force lowpass")), FLTMODE_LOWPASS);
Index: mptrack/Mpdlgs.cpp
===================================================================
--- mptrack/Mpdlgs.cpp	(revision 10963)
+++ mptrack/Mpdlgs.cpp	(working copy)
@@ -928,9 +928,7 @@
 	ON_WM_HSCROLL()
 	ON_WM_VSCROLL()
 	ON_CBN_SELCHANGE(IDC_COMBO_FILTER,			&COptionsMixer::OnResamplerChanged)
-	ON_CBN_SELCHANGE(IDC_COMBO_FILTERWINDOW,	&COptionsMixer::OnSettingsChanged)
 	ON_CBN_SELCHANGE(IDC_COMBO_POLYPHONY,		&COptionsMixer::OnSettingsChanged)
-	ON_EN_UPDATE(IDC_WFIRCUTOFF,				&COptionsMixer::OnSettingsChanged)
 	ON_EN_UPDATE(IDC_RAMPING_IN,				&COptionsMixer::OnRampingChanged)
 	ON_EN_UPDATE(IDC_RAMPING_OUT,				&COptionsMixer::OnRampingChanged)
 	ON_COMMAND(IDC_CHECK_SOFTPAN,				&COptionsMixer::OnSettingsChanged)
@@ -943,8 +941,6 @@
 	CPropertyPage::DoDataExchange(pDX);
 	//{{AFX_DATA_MAP(COptionsSoundcard)
 	DDX_Control(pDX, IDC_COMBO_FILTER, m_CbnResampling);
-	DDX_Control(pDX, IDC_WFIRCUTOFF, m_CEditWFIRCutoff);
-	DDX_Control(pDX, IDC_COMBO_FILTERWINDOW, m_CbnWFIRType);
 	DDX_Control(pDX, IDC_RAMPING_IN, m_CEditRampUp);
 	DDX_Control(pDX, IDC_RAMPING_OUT, m_CEditRampDown);
 	DDX_Control(pDX, IDC_EDIT_VOLRAMP_SAMPLES_UP, m_CInfoRampUp);
@@ -963,26 +959,18 @@
 
 	// Resampling type
 	{
-		for(auto mode : { SRCMODE_NEAREST, SRCMODE_LINEAR, SRCMODE_SPLINE, SRCMODE_POLYPHASE, SRCMODE_FIRFILTER })
+		const auto resamplingModes = Resampling::AllModes();
+		for(auto mode : resamplingModes)
 		{
-			int index = m_CbnResampling.AddString(CTrackApp::GetResamplingModeName(mode, true));
+			int index = m_CbnResampling.AddString(CTrackApp::GetResamplingModeName(mode, 2, true));
 			m_CbnResampling.SetItemData(index, mode);
 			if(TrackerSettings::Instance().ResamplerMode == mode)
+			{
 				m_CbnResampling.SetCurSel(index);
+			}
 		}
 	}
 
-	// Resampler bandwidth
-	{
-		m_CEditWFIRCutoff.SetWindowText(mpt::ToCString(mpt::ufmt::val(TrackerSettings::Instance().ResamplerCutoffPercent)));
-		static_cast<CSpinButtonCtrl *>(GetDlgItem(IDC_SPIN1))->SetRange32(1, 99);
-	}
-
-	// Resampler filter window
-	{
-		// done in OnResamplerChanged()
-	}
-
 	// Amiga Resampler
 	CheckDlgButton(IDC_CHECK1, TrackerSettings::Instance().ResamplerEmulateAmiga ? BST_CHECKED : BST_UNCHECKED);
 
@@ -1037,7 +1025,6 @@
 		m_SliderPreAmp.SetPos(n);
 	}
 
-	OnResamplerChanged();
 	m_initialized = true;
 
 	return TRUE;
@@ -1053,61 +1040,6 @@
 
 void COptionsMixer::OnResamplerChanged()
 {
-	ResamplingMode srcMode = static_cast<ResamplingMode>(m_CbnResampling.GetItemData(m_CbnResampling.GetCurSel()));
-	m_CbnWFIRType.ResetContent();
-	switch(srcMode)
-	{
-		case SRCMODE_FIRFILTER:
-			m_CbnWFIRType.AddString(_T("Hann"));
-			m_CbnWFIRType.AddString(_T("Hamming"));
-			m_CbnWFIRType.AddString(_T("Blackman Exact"));
-			m_CbnWFIRType.AddString(_T("Blackman 3 Tap 61"));
-			m_CbnWFIRType.AddString(_T("Blackman 3 Tap 67"));
-			m_CbnWFIRType.AddString(_T("Blackman Harris"));
-			m_CbnWFIRType.AddString(_T("Blackman 4 Tap 74"));
-			m_CbnWFIRType.AddString(_T("Kaiser a=7.5"));
-			break;
-		case SRCMODE_POLYPHASE:
-			m_CbnWFIRType.AddString(_T("Auto"));
-			m_CbnWFIRType.AddString(_T("Auto"));
-			m_CbnWFIRType.AddString(_T("Auto"));
-			m_CbnWFIRType.AddString(_T("Auto"));
-			m_CbnWFIRType.AddString(_T("Auto"));
-			m_CbnWFIRType.AddString(_T("Auto"));
-			m_CbnWFIRType.AddString(_T("Auto"));
-			m_CbnWFIRType.AddString(_T("Auto"));
-			break;
-		default:
-			m_CbnWFIRType.AddString(_T("none"));
-			m_CbnWFIRType.AddString(_T("none"));
-			m_CbnWFIRType.AddString(_T("none"));
-			m_CbnWFIRType.AddString(_T("none"));
-			m_CbnWFIRType.AddString(_T("none"));
-			m_CbnWFIRType.AddString(_T("none"));
-			m_CbnWFIRType.AddString(_T("none"));
-			m_CbnWFIRType.AddString(_T("none"));
-			break;
-	}
-	m_CbnWFIRType.SetCurSel(TrackerSettings::Instance().ResamplerSubMode);
-	CSpinButtonCtrl *spinWFIRCutoff = static_cast<CSpinButtonCtrl *>(GetDlgItem(IDC_SPIN1));
-	switch(srcMode)
-	{
-		case SRCMODE_POLYPHASE:
-			m_CEditWFIRCutoff.EnableWindow(FALSE);
-			spinWFIRCutoff->EnableWindow(FALSE);
-			m_CbnWFIRType.EnableWindow(FALSE);
-			break;
-		case SRCMODE_FIRFILTER:
-			m_CEditWFIRCutoff.EnableWindow(TRUE);
-			spinWFIRCutoff->EnableWindow(TRUE);
-			m_CbnWFIRType.EnableWindow(TRUE);
-			break;
-		default:
-			m_CEditWFIRCutoff.EnableWindow(FALSE);
-			spinWFIRCutoff->EnableWindow(FALSE);
-			m_CbnWFIRType.EnableWindow(FALSE);
-			break;
-	}
 	OnSettingsChanged();
 }
 
@@ -1162,27 +1094,6 @@
 		TrackerSettings::Instance().ResamplerMode = static_cast<ResamplingMode>(m_CbnResampling.GetItemData(m_CbnResampling.GetCurSel()));
 	}
 
-	// resampler bandwidth
-	{
-		CString s;
-		m_CEditWFIRCutoff.GetWindowText(s);
-		if(s != "")
-		{
-			int newCutoff = ConvertStrTo<int>(s);
-			Limit(newCutoff, 0, 100);
-			TrackerSettings::Instance().ResamplerCutoffPercent = newCutoff;
-		}
-		{
-			s.Format(_T("%d"), TrackerSettings::Instance().ResamplerCutoffPercent.Get());
-			m_CEditWFIRCutoff.SetWindowText(s);
-		}
-	}
-
-	// resampler filter window
-	{
-		TrackerSettings::Instance().ResamplerSubMode = (uint8)m_CbnWFIRType.GetCurSel();
-	}
-
 	// Amiga Resampler
 	TrackerSettings::Instance().ResamplerEmulateAmiga = IsDlgButtonChecked(IDC_CHECK1) != BST_UNCHECKED;
 
Index: mptrack/Mpdlgs.h
===================================================================
--- mptrack/Mpdlgs.h	(revision 10963)
+++ mptrack/Mpdlgs.h	(working copy)
@@ -90,8 +90,6 @@
 protected:
 
 	CComboBox m_CbnResampling;
-	CEdit m_CEditWFIRCutoff;
-	CComboBox m_CbnWFIRType;
 
 	CEdit m_CEditRampUp;
 	CEdit m_CEditRampDown;
Index: mptrack/Mptrack.cpp
===================================================================
--- mptrack/Mptrack.cpp	(revision 10963)
+++ mptrack/Mptrack.cpp	(working copy)
@@ -2022,24 +2022,39 @@
 }
 
 
-const TCHAR *CTrackApp::GetResamplingModeName(ResamplingMode mode, bool addTaps)
+CString CTrackApp::GetResamplingModeName(ResamplingMode mode, int length, bool addTaps)
 {
+	CString result;
 	switch(mode)
 	{
 	case SRCMODE_NEAREST:
-		return addTaps ? _T("No Interpolation (1 tap)") : _T("No Interpolation");
+		result = (length > 1) ? _T("No Interpolation") : _T("None") ;
+		break;
 	case SRCMODE_LINEAR:
-		return addTaps ? _T("Linear (2 tap)") : _T("Linear");
-	case SRCMODE_SPLINE:
-		return addTaps ? _T("Cubic Spline (4 tap)") :  _T("Cubic Spline");
-	case SRCMODE_POLYPHASE:
-		return addTaps ? _T("Polyphase (8 tap)") : _T("Polyphase");
-	case SRCMODE_FIRFILTER:
-		return addTaps ? _T("XMMS-ModPlug (8 tap)") : _T("XMMS-ModPlug");
+		result = _T("Linear");
+		break;
+	case SRCMODE_CUBIC:
+		result = _T("Cubic");
+		break;
+	case SRCMODE_SINC8:
+		result = _T("Sinc");
+		break;
+	case SRCMODE_SINC8LP:
+		result = _T("Sinc");
+		break;
 	default:
 		MPT_ASSERT_NOTREACHED();
+		break;
 	}
-	return _T("");
+	if(Resampling::HasAA(mode))
+	{
+		result += (length > 1) ? _T(" + Low-Pass") : _T(" + LP");
+	}
+	if(addTaps)
+	{
+		result += mpt::cformat(_T(" (%1 tap%2)"))(Resampling::Length(mode), (Resampling::Length(mode) != 1) ? CString(_T("s")) : CString(_T("")));
+	}
+	return result;
 }
 
 
Index: mptrack/Mptrack.h
===================================================================
--- mptrack/Mptrack.h	(revision 10963)
+++ mptrack/Mptrack.h	(working copy)
@@ -269,7 +269,7 @@
 
 public:
 	// Get name of resampling mode. addTaps = true also adds the number of taps the filter uses.
-	static const TCHAR *GetResamplingModeName(ResamplingMode mode, bool addTaps);
+	static CString GetResamplingModeName(ResamplingMode mode, int length, bool addTaps);
 
 // Overrides
 public:
Index: mptrack/mptrack.rc
===================================================================
--- mptrack/mptrack.rc	(revision 10963)
+++ mptrack/mptrack.rc	(working copy)
@@ -2143,15 +2143,9 @@
 BEGIN
     GROUPBOX        "Resampling",IDC_STATIC,6,6,276,48
     LTEXT           "&Filter:",IDC_STATIC,12,18,24,12,SS_CENTERIMAGE
-    COMBOBOX        IDC_COMBO_FILTER,54,18,96,56,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
-    LTEXT           "&Window:",IDC_STATIC,156,18,30,12,SS_CENTERIMAGE
-    COMBOBOX        IDC_COMBO_FILTERWINDOW,192,18,84,56,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
-    LTEXT           "&Bandwidth:",IDC_STATIC,12,36,42,12,SS_CENTERIMAGE
-    EDITTEXT        IDC_WFIRCUTOFF,54,36,30,12,ES_RIGHT | ES_AUTOHSCROLL | ES_NUMBER
-    CONTROL         "",IDC_SPIN1,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_NOTHOUSANDS,71,31,11,14
-    LTEXT           "%",IDC_STATIC,90,36,24,12,SS_CENTERIMAGE
+    COMBOBOX        IDC_COMBO_FILTER,36,18,102,56,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
     CONTROL         "Use &Amiga resampler for Amiga modules",IDC_CHECK1,
-                    "Button",BS_AUTOCHECKBOX | WS_TABSTOP,126,36,150,12
+                    "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,36,144,12
     GROUPBOX        "Volume Ramping",IDC_STATIC,6,60,276,48
     EDITTEXT        IDC_RAMPING_IN,12,72,36,12,ES_RIGHT | ES_AUTOHSCROLL | ES_NUMBER
     CONTROL         "",IDC_SPIN2,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_NOTHOUSANDS,42,66,11,14
Index: mptrack/resource.h
===================================================================
--- mptrack/resource.h	(revision 10963)
+++ mptrack/resource.h	(working copy)
@@ -686,8 +686,6 @@
 #define IDC_COMMAND_LIST                2129
 #define IDC_STATIC8                     2200
 #define IDC_PATINSTROPLUGGUI            2201
-#define IDC_WFIRCUTOFF                  2202
-#define IDC_WFIRTYPE                    2203
 #define IDC_RAMPING_IN                  2204
 #define IDC_PLAYEROPTIONS               2205
 #define IDC_RAMPING_OUT                 2205
Index: mptrack/SampleEditorDialogs.cpp
===================================================================
--- mptrack/SampleEditorDialogs.cpp	(revision 10963)
+++ mptrack/SampleEditorDialogs.cpp	(working copy)
@@ -534,12 +534,12 @@
 
 	CComboBox *cbnResampling = static_cast<CComboBox *>(GetDlgItem(IDC_COMBO_FILTER));
 	cbnResampling->SetRedraw(FALSE);
-	const ResamplingMode resamplingModes[] = { SRCMODE_NEAREST, SRCMODE_LINEAR, SRCMODE_SPLINE, SRCMODE_POLYPHASE, SRCMODE_FIRFILTER, SRCMODE_DEFAULT };
+	const auto resamplingModes = Resampling::AllModesWithDefault();
 	for(auto mode : resamplingModes)
 	{
-		const TCHAR *desc = _T("r8brain (High Quality)");
+		CString desc = _T("r8brain (High Quality)");
 		if(mode != SRCMODE_DEFAULT)
-			desc = CTrackApp::GetResamplingModeName(mode, false);
+			desc = CTrackApp::GetResamplingModeName(mode, 1, true);
 
 		int index = cbnResampling->AddString(desc);
 		cbnResampling->SetItemData(index, mode);
Index: mptrack/TrackerSettings.cpp
===================================================================
--- mptrack/TrackerSettings.cpp	(revision 10963)
+++ mptrack/TrackerSettings.cpp	(working copy)
@@ -74,29 +74,6 @@
 }
 
 
-static ResamplingMode GetDefaultResamplerMode()
-{
-	ResamplingMode result = CResamplerSettings().SrcMode;
-#ifdef ENABLE_ASM
-	// rough heuristic to select less cpu consuming defaults for old CPUs
-	if(GetRealProcSupport() & PROCSUPPORT_SSE)
-	{
-		result = SRCMODE_POLYPHASE;
-	} else if(GetRealProcSupport() & PROCSUPPORT_MMX)
-	{
-		result = SRCMODE_SPLINE;
-	} else
-	{
-		result = SRCMODE_LINEAR;
-	}
-#else
-	// just use a sane default
-	result = CResamplerSettings().SrcMode;
-#endif
-	return result;
-}
-
-
 static uint32 GetDefaultPatternSetup()
 {
 	return PATTERN_PLAYNEWNOTE | PATTERN_EFFECTHILIGHT
@@ -244,7 +221,7 @@
 	, MixerStereoSeparation(conf, MPT_USTRING("Sound Settings"), MPT_USTRING("StereoSeparation"), MixerSettings().m_nStereoSeparation)
 	, MixerVolumeRampUpMicroseconds(conf, MPT_USTRING("Sound Settings"), MPT_USTRING("VolumeRampUpMicroseconds"), MixerSettings().GetVolumeRampUpMicroseconds())
 	, MixerVolumeRampDownMicroseconds(conf, MPT_USTRING("Sound Settings"), MPT_USTRING("VolumeRampDownMicroseconds"), MixerSettings().GetVolumeRampDownMicroseconds())
-	, ResamplerMode(conf, MPT_USTRING("Sound Settings"), MPT_USTRING("SrcMode"), GetDefaultResamplerMode())
+	, ResamplerMode(conf, MPT_USTRING("Sound Settings"), MPT_USTRING("SrcMode"), CResamplerSettings().SrcMode)
 	, ResamplerSubMode(conf, MPT_USTRING("Sound Settings"), MPT_USTRING("XMMSModplugResamplerWFIRType"), CResamplerSettings().gbWFIRType)
 	, ResamplerCutoffPercent(conf, MPT_USTRING("Sound Settings"), MPT_USTRING("ResamplerWFIRCutoff"), mpt::saturate_round<int32>(CResamplerSettings().gdWFIRCutoff * 100.0))
 	, ResamplerEmulateAmiga(conf, MPT_USTRING("Sound Settings"), MPT_USTRING("ResamplerEmulateAmiga"), true)
@@ -546,6 +523,13 @@
 		m_SoundDeviceSettingsDefaults.UseHardwareTiming = m_SoundDeviceUseHardwareTiming;
 		m_SoundDeviceSettingsUseOldDefaults = true;
 	}
+	if(storedVersion < MAKE_VERSION_NUMERIC(1,28,00,38))
+	{
+		// reset this setting to the default when updating,
+		// because we do not provide a GUI any more,
+		// and in general, it should not get changed anyway
+		ResamplerCutoffPercent = mpt::saturate_round<int32>(CResamplerSettings().gdWFIRCutoff * 100.0);
+	}
 	if(storedVersion < MAKE_VERSION_NUMERIC(1,25,00,04))
 	{
 		m_SoundDeviceDirectSoundOldDefaultIdentifier = true;
@@ -678,7 +662,7 @@
 	}
 
 	// Sanitize resampling mode for sample editor
-	if(!IsKnownResamplingMode(sampleEditorDefaultResampler) && sampleEditorDefaultResampler != SRCMODE_DEFAULT)
+	if(!Resampling::IsKnownMode(sampleEditorDefaultResampler) && sampleEditorDefaultResampler != SRCMODE_DEFAULT)
 	{
 		sampleEditorDefaultResampler = SRCMODE_DEFAULT;
 	}
Index: soundlib/Load_it.cpp
===================================================================
--- soundlib/Load_it.cpp	(revision 10963)
+++ soundlib/Load_it.cpp	(working copy)
@@ -2366,7 +2366,7 @@
 			case MagicBE("RP.."): if(GetType() != MOD_TYPE_XM) { ORDERINDEX restartPos; ReadField(chunk, size, restartPos); Order().SetRestartPos(restartPos); } break;
 			case MagicLE("RSMP"):
 				ReadFieldCast(chunk, size, m_nResampling);
-				if(!IsKnownResamplingMode(m_nResampling)) m_nResampling = SRCMODE_DEFAULT;
+				if(!Resampling::IsKnownMode(m_nResampling)) m_nResampling = SRCMODE_DEFAULT;
 				break;
 #ifdef MODPLUG_TRACKER
 			case MagicBE("MIMA"): GetMIDIMapper().Deserialize(chunk); break;
Index: soundlib/MixFuncTable.cpp
===================================================================
--- soundlib/MixFuncTable.cpp	(revision 10963)
+++ soundlib/MixFuncTable.cpp	(working copy)
@@ -79,9 +79,9 @@
 	{
 	case SRCMODE_NEAREST:   return ndxNoInterpolation;
 	case SRCMODE_LINEAR:    return ndxLinear;
-	case SRCMODE_SPLINE:    return ndxFastSinc;
-	case SRCMODE_POLYPHASE: return ndxKaiser;
-	case SRCMODE_FIRFILTER: return ndxFIRFilter;
+	case SRCMODE_CUBIC:     return ndxFastSinc;
+	case SRCMODE_SINC8LP:   return ndxKaiser;
+	case SRCMODE_SINC8:     return ndxFIRFilter;
 	case SRCMODE_AMIGA:     return ndxAmigaBlep;
 	default:                MPT_ASSERT_NOTREACHED();
 	}
Index: soundlib/Resampler.h
===================================================================
--- soundlib/Resampler.h	(revision 10963)
+++ soundlib/Resampler.h	(working copy)
@@ -61,12 +61,12 @@
 	uint8 gbWFIRType;
 	bool emulateAmiga;
 public:
-	CResamplerSettings()
+	MPT_CONSTEXPR11_FUN CResamplerSettings()
+		: SrcMode(Resampling::Default())
+		, gdWFIRCutoff(0.97)
+		, gbWFIRType(WFIR_KAISER4T)
+		, emulateAmiga(false)
 	{
-		SrcMode = SRCMODE_POLYPHASE;
-		gdWFIRCutoff = 0.97;
-		gbWFIRType = WFIR_KAISER4T;
-		emulateAmiga = false;
 	}
 	bool operator == (const CResamplerSettings &cmp) const
 	{
@@ -127,8 +127,6 @@
 	{
 		InitializeTablesFromScratch(false);
 	}
-	~CResampler() {}
-	bool IsHQ() const { return m_Settings.SrcMode >= SRCMODE_SPLINE && m_Settings.SrcMode < SRCMODE_DEFAULT; }
 private:
 	void InitFloatmixerTables();
 	void InitializeTablesFromScratch(bool force=false);
Index: soundlib/Snd_defs.h
===================================================================
--- soundlib/Snd_defs.h	(revision 10963)
+++ soundlib/Snd_defs.h	(working copy)
@@ -297,22 +297,55 @@
 {
 	// ATTENTION: Do not change ANY of these values, as they get written out to files in per instrument interpolation settings
 	// and old files have these exact values in them which should not change meaning.
-	SRCMODE_NEAREST   = 0,
-	SRCMODE_LINEAR    = 1,
-	SRCMODE_SPLINE    = 2,
-	SRCMODE_POLYPHASE = 3,
-	SRCMODE_FIRFILTER = 4,
-	SRCMODE_DEFAULT   = 5,
+	SRCMODE_NEAREST   = 0,  // 1 tap, no AA
+	SRCMODE_LINEAR    = 1,  // 2 tap, no AA
+	SRCMODE_CUBIC     = 2,  // 4 tap, no AA
+	SRCMODE_SINC8     = 4,  // 8 tap, no AA   (yes, index 4) (XMMS-ModPlug)
+	SRCMODE_SINC8LP   = 3,  // 8 tap, with AA (yes, index 3) (Polyphase)
 
-	SRCMODE_AMIGA = 0xFF,	// Not explicitely user-selectable
+	SRCMODE_DEFAULT   = 5,  // only used for instrument settings, not used inside the mixer
+
+	SRCMODE_AMIGA  = 0xFF,  // Not explicitely user-selectable
 };
 
-static inline bool IsKnownResamplingMode(int mode)
+namespace Resampling
 {
-	return (mode >= 0) && (mode < SRCMODE_DEFAULT);
+
+static inline std::array<ResamplingMode, 5> AllModes() noexcept { return { SRCMODE_NEAREST, SRCMODE_LINEAR, SRCMODE_CUBIC, SRCMODE_SINC8, SRCMODE_SINC8LP }; }
+
+static inline std::array<ResamplingMode, 6> AllModesWithDefault() noexcept { return { SRCMODE_NEAREST, SRCMODE_LINEAR, SRCMODE_CUBIC, SRCMODE_SINC8, SRCMODE_SINC8LP, SRCMODE_DEFAULT }; }
+
+static MPT_CONSTEXPR11_FUN ResamplingMode Default() noexcept { return SRCMODE_SINC8LP; }
+
+static MPT_CONSTEXPR11_FUN bool IsKnownMode(int mode) noexcept { return (mode >= 0) && (mode < SRCMODE_DEFAULT); }
+
+static MPT_CONSTEXPR11_FUN ResamplingMode ToKnownMode(int mode) noexcept
+{
+	return Resampling::IsKnownMode(mode) ? static_cast<ResamplingMode>(mode)
+		: (mode == SRCMODE_AMIGA) ? SRCMODE_LINEAR
+		: Resampling::Default();
 }
 
+static MPT_CONSTEXPR11_FUN int Length(ResamplingMode mode) noexcept
+{
+	return mode == SRCMODE_NEAREST ? 1
+		: mode == SRCMODE_LINEAR ? 2
+		: mode == SRCMODE_CUBIC ? 4
+		: mode == SRCMODE_SINC8 ? 8
+		: mode == SRCMODE_SINC8LP ? 8
+		: 0;
+}
 
+static MPT_CONSTEXPR11_FUN bool HasAA(ResamplingMode mode) noexcept { return (mode == SRCMODE_SINC8LP); }
+
+static MPT_CONSTEXPR11_FUN ResamplingMode AddAA(ResamplingMode mode) noexcept { return (mode == SRCMODE_SINC8) ? SRCMODE_SINC8LP : mode; }
+
+static MPT_CONSTEXPR11_FUN ResamplingMode RemoveAA(ResamplingMode mode) noexcept { return (mode == SRCMODE_SINC8LP) ? SRCMODE_SINC8 : mode; }
+
+}
+
+
+
 // Release node defines
 #define ENV_RELEASE_NODE_UNSET	0xFF
 #define NOT_YET_RELEASED		(-1)
Index: soundlib/Sndmix.cpp
===================================================================
--- soundlib/Sndmix.cpp	(revision 10963)
+++ soundlib/Sndmix.cpp	(working copy)
@@ -2375,11 +2375,11 @@
 			//if (chn.nNewRightVol > 0xFFFF) chn.nNewRightVol = 0xFFFF;
 			//if (chn.nNewLeftVol > 0xFFFF) chn.nNewLeftVol = 0xFFFF;
 
-			if(chn.pModInstrument && IsKnownResamplingMode(chn.pModInstrument->nResampling))
+			if(chn.pModInstrument && Resampling::IsKnownMode(chn.pModInstrument->nResampling))
 			{
 				// For defined resampling modes, use per-instrument resampling mode if set
 				chn.resamplingMode = static_cast<uint8>(chn.pModInstrument->nResampling);
-			} else if(IsKnownResamplingMode(m_nResampling))
+			} else if(Resampling::IsKnownMode(m_nResampling))
 			{
 				chn.resamplingMode = static_cast<uint8>(m_nResampling);
 			} else if(m_SongFlags[SONG_ISAMIGA] && m_Resampler.m_Settings.emulateAmiga)
Index: soundlib/Tables.cpp
===================================================================
--- soundlib/Tables.cpp	(revision 10963)
+++ soundlib/Tables.cpp	(working copy)
@@ -749,42 +749,7 @@
 	}
 }
 
-#if 0
 
-// this code is currently unused
-
-static double GetSpline(double x, double c0, double c1, double c2, double c3)
-{
-	double Xo = c1;
-	double Xa = c0 - Xo;
-	double Xb = c2 - Xo;
-	double Ux = (Xb-Xa)/2;
-	double Vx = (c3 - Xo)/2;
-	double a = Vx+Ux-2*Xb;
-	double b = 3*Xb-2*Ux-Vx;
-	return (((a*x+b)*x)+Ux)*x+Xo;
-}
-
-
-static void getdownsample2x(short int *psinc)
-{
-	for (int i=0; i<SINC_PHASES; i++)
-	{
-		double x = (double)i * (double)(0.5/SINC_PHASES);
-		psinc[i*8+7] = (short int)(GetSpline(x,     0, 0, 0, 1) * 8192);
-		psinc[i*8+6] = (short int)(GetSpline(x+0.5, 0, 0, 0, 1) * 8192);
-		psinc[i*8+5] = (short int)(GetSpline(x,     0, 0, 1, 0) * 8192);
-		psinc[i*8+4] = (short int)(GetSpline(x+0.5, 0, 0, 1, 0) * 8192);
-		psinc[i*8+3] = (short int)(GetSpline(x,     0, 1, 0, 0) * 8192);
-		psinc[i*8+2] = (short int)(GetSpline(x+0.5, 0, 1, 0, 0) * 8192);
-		psinc[i*8+1] = (short int)(GetSpline(x,     1, 0, 0, 0) * 8192);
-		psinc[i*8+0] = (short int)(GetSpline(x+0.5, 1, 0, 0, 0) * 8192);
-	}
-}
-
-#endif
-
-
 #ifdef MODPLUG_TRACKER
 bool CResampler::StaticTablesInitialized = false;
 SINC_TYPE CResampler::gKaiserSinc[SINC_PHASES*8];     // Upsampling
@@ -834,12 +799,8 @@
 		InitFloatmixerTables();
 
 		getsinc(gKaiserSinc, 9.6377, 0.97);
-		//ericus' downsampling improvement.
-		//getsinc(gDownsample13x, 8.5, 3.0/4.0);
-		//getdownsample2x(gDownsample2x);
 		getsinc(gDownsample13x, 8.5, 0.5);
 		getsinc(gDownsample2x, 2.7625, 0.425);
-		//end ericus' downsampling improvement.
 
 		#ifdef MODPLUG_TRACKER
 			StaticTablesInitialized = true;
Index: soundlib/WindowedFIR.h
===================================================================
--- soundlib/WindowedFIR.h	(revision 10963)
+++ soundlib/WindowedFIR.h	(working copy)
@@ -50,25 +50,20 @@
 #define WFIR_LOG2WIDTH		3
 #define WFIR_WIDTH			(1L<<WFIR_LOG2WIDTH)
 // cutoff (1.0 == pi/2)
-//float WFIR_CUTOFF			= 0.5f;//0.75f;	//0.90f;
 // wfir type
 enum WFIRType
 {
-	WFIR_HANN			= 0,
-	WFIR_HAMMING		= 1,
-	WFIR_BLACKMANEXACT	= 2,
-	WFIR_BLACKMAN3T61	= 3,
-	WFIR_BLACKMAN3T67	= 4,
-	WFIR_BLACKMAN4T92	= 5,
-	WFIR_BLACKMAN4T74	= 6,
-	WFIR_KAISER4T		= 7,
+	WFIR_HANN          = 0,  // Hann
+	WFIR_HAMMING       = 1,  // Hamming
+	WFIR_BLACKMANEXACT = 2,  // Blackman Exact
+	WFIR_BLACKMAN3T61  = 3,  // Blackman 3-Tap 61
+	WFIR_BLACKMAN3T67  = 4,  // Blackman 3-Tap 67
+	WFIR_BLACKMAN4T92  = 5,  // Blackman-Harris
+	WFIR_BLACKMAN4T74  = 6,  // Blackman 4-Tap 74
+	WFIR_KAISER4T      = 7,  // Kaiser a=7.5
 };
-//int WFIR_TYPE				= WFIR_KAISER4T;//WFIR_BLACKMANEXACT;
-//int WFIR_TYPE				= TrackerSettings::Instance().gbWFIRType;
 // wfir help
-#ifndef M_zPI
 #define M_zPI				3.1415926535897932384626433832795
-#endif
 #define M_zEPS				1e-8
 
 
Index: test/test.cpp
===================================================================
--- test/test.cpp	(revision 10963)
+++ test/test.cpp	(working copy)
@@ -3077,7 +3077,7 @@
 	VERIFY_EQUAL_NONCONT(pIns->nPPC, NOTE_MIDDLEC - 1);
 
 	VERIFY_EQUAL_NONCONT(pIns->nVolRampUp, 1200);
-	VERIFY_EQUAL_NONCONT(pIns->nResampling, (unsigned)SRCMODE_POLYPHASE);
+	VERIFY_EQUAL_NONCONT(pIns->nResampling, (unsigned)SRCMODE_SINC8LP);
 
 	VERIFY_EQUAL_NONCONT(pIns->IsCutoffEnabled(), false);
 	VERIFY_EQUAL_NONCONT(pIns->GetCutoff(), 0);
@@ -3207,7 +3207,7 @@
 	VERIFY_EQUAL_NONCONT(sndFile.m_nDefaultRowsPerBeat, 6);
 	VERIFY_EQUAL_NONCONT(sndFile.m_nDefaultRowsPerMeasure, 12);
 	VERIFY_EQUAL_NONCONT(sndFile.m_dwCreatedWithVersion, MAKE_VERSION_NUMERIC(1, 19, 02, 05));
-	VERIFY_EQUAL_NONCONT(sndFile.m_nResampling, SRCMODE_POLYPHASE);
+	VERIFY_EQUAL_NONCONT(sndFile.m_nResampling, SRCMODE_SINC8LP);
 	VERIFY_EQUAL_NONCONT(sndFile.m_songArtist, MPT_USTRING("Tester"));
 	VERIFY_EQUAL_NONCONT(sndFile.m_tempoSwing.size(), 6);
 	VERIFY_EQUAL_NONCONT(sndFile.m_tempoSwing[0], 29360125);
@@ -3370,7 +3370,7 @@
 		VERIFY_EQUAL_NONCONT(pIns->nPPC, (NOTE_MIDDLEC - NOTE_MIN) + 6);	// F#5
 
 		VERIFY_EQUAL_NONCONT(pIns->nVolRampUp, 1200);
-		VERIFY_EQUAL_NONCONT(pIns->nResampling, (unsigned)SRCMODE_POLYPHASE);
+		VERIFY_EQUAL_NONCONT(pIns->nResampling, (unsigned)SRCMODE_SINC8LP);
 
 		VERIFY_EQUAL_NONCONT(pIns->IsCutoffEnabled(), true);
 		VERIFY_EQUAL_NONCONT(pIns->GetCutoff(), 0x32);
resampler-cleanup-v7.patch (28,900 bytes)   
resampler-cleanup-v8.patch (28,900 bytes)   
Index: common/versionNumber.h
===================================================================
--- common/versionNumber.h	(revision 10980)
+++ common/versionNumber.h	(working copy)
@@ -21,7 +21,7 @@
 #define VER_MAJORMAJOR  1
 #define VER_MAJOR      28
 #define VER_MINOR      00
-#define VER_MINORMINOR 40
+#define VER_MINORMINOR 41
 
 //Numerical value of the version.
 #define MPT_VERSION_CURRENT MAKE_VERSION_NUMERIC(VER_MAJORMAJOR,VER_MAJOR,VER_MINOR,VER_MINORMINOR)
Index: libopenmpt/libopenmpt_impl.cpp
===================================================================
--- libopenmpt/libopenmpt_impl.cpp	(revision 10980)
+++ libopenmpt/libopenmpt_impl.cpp	(working copy)
@@ -332,13 +332,13 @@
 }
 
 static ResamplingMode filterlength_to_resamplingmode(std::int32_t length) {
-	ResamplingMode result = SRCMODE_POLYPHASE;
+	ResamplingMode result = SRCMODE_SINC8LP;
 	if ( length == 0 ) {
-		result = SRCMODE_POLYPHASE;
+		result = SRCMODE_SINC8LP;
 	} else if ( length >= 8 ) {
-		result = SRCMODE_POLYPHASE;
+		result = SRCMODE_SINC8LP;
 	} else if ( length >= 3 ) {
-		result = SRCMODE_SPLINE;
+		result = SRCMODE_CUBIC;
 	} else if ( length >= 2 ) {
 		result = SRCMODE_LINEAR;
 	} else if ( length >= 1 ) {
@@ -356,11 +356,11 @@
 	case SRCMODE_LINEAR:
 		return 2;
 		break;
-	case SRCMODE_SPLINE:
+	case SRCMODE_CUBIC:
 		return 4;
 		break;
-	case SRCMODE_POLYPHASE:
-	case SRCMODE_FIRFILTER:
+	case SRCMODE_SINC8:
+	case SRCMODE_SINC8LP:
 	case SRCMODE_DEFAULT:
 		return 8;
 	default:
Index: mptrack/Ctrl_gen.cpp
===================================================================
--- mptrack/Ctrl_gen.cpp	(revision 10980)
+++ mptrack/Ctrl_gen.cpp	(working copy)
@@ -202,21 +202,21 @@
 	FlagSet<HintType> hintType = hint.GetType();
 	const bool updateAll = hintType[HINT_MODTYPE];
 
-	const ResamplingMode resamplingModes[] = { SRCMODE_NEAREST, SRCMODE_LINEAR, SRCMODE_SPLINE, SRCMODE_POLYPHASE, SRCMODE_FIRFILTER };
+	const auto resamplingModes = Resampling::AllModes();
 
 	if (hintType == HINT_MPTOPTIONS || updateAll)
 	{
-		const TCHAR *defaultResampler;
+		CString defaultResampler;
 		if(m_sndFile.m_SongFlags[SONG_ISAMIGA] && TrackerSettings::Instance().ResamplerEmulateAmiga)
 			defaultResampler = _T("Amiga Resampler");
 		else
-			defaultResampler = CTrackApp::GetResamplingModeName(TrackerSettings::Instance().ResamplerMode, false);
+			defaultResampler = CTrackApp::GetResamplingModeName(TrackerSettings::Instance().ResamplerMode, 1, false);
 
 		m_CbnResampling.ResetContent();
-		m_CbnResampling.SetItemData(m_CbnResampling.AddString(_T("Default (") + CString(defaultResampler) + _T(")")), SRCMODE_DEFAULT);
+		m_CbnResampling.SetItemData(m_CbnResampling.AddString(_T("Default (") + defaultResampler + _T(")")), SRCMODE_DEFAULT);
 		for(auto mode : resamplingModes)
 		{
-			m_CbnResampling.SetItemData(m_CbnResampling.AddString(CTrackApp::GetResamplingModeName(mode, false)), mode);
+			m_CbnResampling.SetItemData(m_CbnResampling.AddString(CTrackApp::GetResamplingModeName(mode, 2, true)), mode);
 		}
 		m_CbnResampling.Invalidate(FALSE);
 	}
@@ -312,12 +312,13 @@
 
 	if(updateAll || hintType == HINT_MPTOPTIONS || (hint.GetCategory() == HINTCAT_GENERAL && hintType[HINT_MODGENERAL]))
 	{
+
 		int srcMode = 0;
-		for(int i = 0; i < CountOf(resamplingModes); i++)
+		for(int i = 0; i < m_CbnResampling.GetCount(); ++i)
 		{
-			if(m_sndFile.m_nResampling == resamplingModes[i]) srcMode = i + 1;
+			if(m_sndFile.m_nResampling == static_cast<int>(m_CbnResampling.GetItemData(i)))
+				m_CbnResampling.SetCurSel(i);
 		}
-		m_CbnResampling.SetCurSel(srcMode);
 	}
 
 	CheckDlgButton(IDC_CHECK_LOOPSONG, (TrackerSettings::Instance().gbLoopSong) ? TRUE : FALSE);
Index: mptrack/Ctrl_ins.cpp
===================================================================
--- mptrack/Ctrl_ins.cpp	(revision 10980)
+++ mptrack/Ctrl_ins.cpp	(working copy)
@@ -992,12 +992,12 @@
 	m_EditPWD.SubclassDlgItem(IDC_PITCHWHEELDEPTH, this);
 	m_EditPWD.AllowFractions(false);
 
+	const auto resamplingModes = Resampling::AllModes();
 	m_CbnResampling.SetItemData(m_CbnResampling.AddString(_T("Default")), SRCMODE_DEFAULT);
-	m_CbnResampling.SetItemData(m_CbnResampling.AddString(_T("None")), SRCMODE_NEAREST);
-	m_CbnResampling.SetItemData(m_CbnResampling.AddString(_T("Linear")), SRCMODE_LINEAR);
-	m_CbnResampling.SetItemData(m_CbnResampling.AddString(_T("Spline")), SRCMODE_SPLINE);
-	m_CbnResampling.SetItemData(m_CbnResampling.AddString(_T("Polyphase")), SRCMODE_POLYPHASE);
-	m_CbnResampling.SetItemData(m_CbnResampling.AddString(_T("XMMS")), SRCMODE_FIRFILTER);
+	for(auto mode : resamplingModes)
+	{
+		m_CbnResampling.SetItemData(m_CbnResampling.AddString(CTrackApp::GetResamplingModeName(mode, 1, false)), mode);
+	}
 
 	m_CbnFilterMode.SetItemData(m_CbnFilterMode.AddString(_T("Channel default")), FLTMODE_UNCHANGED);
 	m_CbnFilterMode.SetItemData(m_CbnFilterMode.AddString(_T("Force lowpass")), FLTMODE_LOWPASS);
Index: mptrack/Mpdlgs.cpp
===================================================================
--- mptrack/Mpdlgs.cpp	(revision 10980)
+++ mptrack/Mpdlgs.cpp	(working copy)
@@ -928,9 +928,7 @@
 	ON_WM_HSCROLL()
 	ON_WM_VSCROLL()
 	ON_CBN_SELCHANGE(IDC_COMBO_FILTER,			&COptionsMixer::OnResamplerChanged)
-	ON_CBN_SELCHANGE(IDC_COMBO_FILTERWINDOW,	&COptionsMixer::OnSettingsChanged)
 	ON_CBN_SELCHANGE(IDC_COMBO_POLYPHONY,		&COptionsMixer::OnSettingsChanged)
-	ON_EN_UPDATE(IDC_WFIRCUTOFF,				&COptionsMixer::OnSettingsChanged)
 	ON_EN_UPDATE(IDC_RAMPING_IN,				&COptionsMixer::OnRampingChanged)
 	ON_EN_UPDATE(IDC_RAMPING_OUT,				&COptionsMixer::OnRampingChanged)
 	ON_COMMAND(IDC_CHECK_SOFTPAN,				&COptionsMixer::OnSettingsChanged)
@@ -943,8 +941,6 @@
 	CPropertyPage::DoDataExchange(pDX);
 	//{{AFX_DATA_MAP(COptionsSoundcard)
 	DDX_Control(pDX, IDC_COMBO_FILTER, m_CbnResampling);
-	DDX_Control(pDX, IDC_WFIRCUTOFF, m_CEditWFIRCutoff);
-	DDX_Control(pDX, IDC_COMBO_FILTERWINDOW, m_CbnWFIRType);
 	DDX_Control(pDX, IDC_RAMPING_IN, m_CEditRampUp);
 	DDX_Control(pDX, IDC_RAMPING_OUT, m_CEditRampDown);
 	DDX_Control(pDX, IDC_EDIT_VOLRAMP_SAMPLES_UP, m_CInfoRampUp);
@@ -963,26 +959,18 @@
 
 	// Resampling type
 	{
-		for(auto mode : { SRCMODE_NEAREST, SRCMODE_LINEAR, SRCMODE_SPLINE, SRCMODE_POLYPHASE, SRCMODE_FIRFILTER })
+		const auto resamplingModes = Resampling::AllModes();
+		for(auto mode : resamplingModes)
 		{
-			int index = m_CbnResampling.AddString(CTrackApp::GetResamplingModeName(mode, true));
+			int index = m_CbnResampling.AddString(CTrackApp::GetResamplingModeName(mode, 2, true));
 			m_CbnResampling.SetItemData(index, mode);
 			if(TrackerSettings::Instance().ResamplerMode == mode)
+			{
 				m_CbnResampling.SetCurSel(index);
+			}
 		}
 	}
 
-	// Resampler bandwidth
-	{
-		m_CEditWFIRCutoff.SetWindowText(mpt::ToCString(mpt::ufmt::val(TrackerSettings::Instance().ResamplerCutoffPercent)));
-		static_cast<CSpinButtonCtrl *>(GetDlgItem(IDC_SPIN1))->SetRange32(1, 99);
-	}
-
-	// Resampler filter window
-	{
-		// done in OnResamplerChanged()
-	}
-
 	// Amiga Resampler
 	CheckDlgButton(IDC_CHECK1, TrackerSettings::Instance().ResamplerEmulateAmiga ? BST_CHECKED : BST_UNCHECKED);
 
@@ -1037,7 +1025,6 @@
 		m_SliderPreAmp.SetPos(n);
 	}
 
-	OnResamplerChanged();
 	m_initialized = true;
 
 	return TRUE;
@@ -1053,61 +1040,6 @@
 
 void COptionsMixer::OnResamplerChanged()
 {
-	ResamplingMode srcMode = static_cast<ResamplingMode>(m_CbnResampling.GetItemData(m_CbnResampling.GetCurSel()));
-	m_CbnWFIRType.ResetContent();
-	switch(srcMode)
-	{
-		case SRCMODE_FIRFILTER:
-			m_CbnWFIRType.AddString(_T("Hann"));
-			m_CbnWFIRType.AddString(_T("Hamming"));
-			m_CbnWFIRType.AddString(_T("Blackman Exact"));
-			m_CbnWFIRType.AddString(_T("Blackman 3 Tap 61"));
-			m_CbnWFIRType.AddString(_T("Blackman 3 Tap 67"));
-			m_CbnWFIRType.AddString(_T("Blackman Harris"));
-			m_CbnWFIRType.AddString(_T("Blackman 4 Tap 74"));
-			m_CbnWFIRType.AddString(_T("Kaiser a=7.5"));
-			break;
-		case SRCMODE_POLYPHASE:
-			m_CbnWFIRType.AddString(_T("Auto"));
-			m_CbnWFIRType.AddString(_T("Auto"));
-			m_CbnWFIRType.AddString(_T("Auto"));
-			m_CbnWFIRType.AddString(_T("Auto"));
-			m_CbnWFIRType.AddString(_T("Auto"));
-			m_CbnWFIRType.AddString(_T("Auto"));
-			m_CbnWFIRType.AddString(_T("Auto"));
-			m_CbnWFIRType.AddString(_T("Auto"));
-			break;
-		default:
-			m_CbnWFIRType.AddString(_T("none"));
-			m_CbnWFIRType.AddString(_T("none"));
-			m_CbnWFIRType.AddString(_T("none"));
-			m_CbnWFIRType.AddString(_T("none"));
-			m_CbnWFIRType.AddString(_T("none"));
-			m_CbnWFIRType.AddString(_T("none"));
-			m_CbnWFIRType.AddString(_T("none"));
-			m_CbnWFIRType.AddString(_T("none"));
-			break;
-	}
-	m_CbnWFIRType.SetCurSel(TrackerSettings::Instance().ResamplerSubMode);
-	CSpinButtonCtrl *spinWFIRCutoff = static_cast<CSpinButtonCtrl *>(GetDlgItem(IDC_SPIN1));
-	switch(srcMode)
-	{
-		case SRCMODE_POLYPHASE:
-			m_CEditWFIRCutoff.EnableWindow(FALSE);
-			spinWFIRCutoff->EnableWindow(FALSE);
-			m_CbnWFIRType.EnableWindow(FALSE);
-			break;
-		case SRCMODE_FIRFILTER:
-			m_CEditWFIRCutoff.EnableWindow(TRUE);
-			spinWFIRCutoff->EnableWindow(TRUE);
-			m_CbnWFIRType.EnableWindow(TRUE);
-			break;
-		default:
-			m_CEditWFIRCutoff.EnableWindow(FALSE);
-			spinWFIRCutoff->EnableWindow(FALSE);
-			m_CbnWFIRType.EnableWindow(FALSE);
-			break;
-	}
 	OnSettingsChanged();
 }
 
@@ -1162,27 +1094,6 @@
 		TrackerSettings::Instance().ResamplerMode = static_cast<ResamplingMode>(m_CbnResampling.GetItemData(m_CbnResampling.GetCurSel()));
 	}
 
-	// resampler bandwidth
-	{
-		CString s;
-		m_CEditWFIRCutoff.GetWindowText(s);
-		if(s != "")
-		{
-			int newCutoff = ConvertStrTo<int>(s);
-			Limit(newCutoff, 0, 100);
-			TrackerSettings::Instance().ResamplerCutoffPercent = newCutoff;
-		}
-		{
-			s.Format(_T("%d"), TrackerSettings::Instance().ResamplerCutoffPercent.Get());
-			m_CEditWFIRCutoff.SetWindowText(s);
-		}
-	}
-
-	// resampler filter window
-	{
-		TrackerSettings::Instance().ResamplerSubMode = (uint8)m_CbnWFIRType.GetCurSel();
-	}
-
 	// Amiga Resampler
 	TrackerSettings::Instance().ResamplerEmulateAmiga = IsDlgButtonChecked(IDC_CHECK1) != BST_UNCHECKED;
 
Index: mptrack/Mpdlgs.h
===================================================================
--- mptrack/Mpdlgs.h	(revision 10980)
+++ mptrack/Mpdlgs.h	(working copy)
@@ -90,8 +90,6 @@
 protected:
 
 	CComboBox m_CbnResampling;
-	CEdit m_CEditWFIRCutoff;
-	CComboBox m_CbnWFIRType;
 
 	CEdit m_CEditRampUp;
 	CEdit m_CEditRampDown;
Index: mptrack/Mptrack.cpp
===================================================================
--- mptrack/Mptrack.cpp	(revision 10980)
+++ mptrack/Mptrack.cpp	(working copy)
@@ -2026,24 +2026,39 @@
 }
 
 
-const TCHAR *CTrackApp::GetResamplingModeName(ResamplingMode mode, bool addTaps)
+CString CTrackApp::GetResamplingModeName(ResamplingMode mode, int length, bool addTaps)
 {
+	CString result;
 	switch(mode)
 	{
 	case SRCMODE_NEAREST:
-		return addTaps ? _T("No Interpolation (1 tap)") : _T("No Interpolation");
+		result = (length > 1) ? _T("No Interpolation") : _T("None") ;
+		break;
 	case SRCMODE_LINEAR:
-		return addTaps ? _T("Linear (2 tap)") : _T("Linear");
-	case SRCMODE_SPLINE:
-		return addTaps ? _T("Cubic Spline (4 tap)") :  _T("Cubic Spline");
-	case SRCMODE_POLYPHASE:
-		return addTaps ? _T("Polyphase (8 tap)") : _T("Polyphase");
-	case SRCMODE_FIRFILTER:
-		return addTaps ? _T("XMMS-ModPlug (8 tap)") : _T("XMMS-ModPlug");
+		result = _T("Linear");
+		break;
+	case SRCMODE_CUBIC:
+		result = _T("Cubic");
+		break;
+	case SRCMODE_SINC8:
+		result = _T("Sinc");
+		break;
+	case SRCMODE_SINC8LP:
+		result = _T("Sinc");
+		break;
 	default:
 		MPT_ASSERT_NOTREACHED();
+		break;
 	}
-	return _T("");
+	if(Resampling::HasAA(mode))
+	{
+		result += (length > 1) ? _T(" + Low-Pass") : _T(" + LP");
+	}
+	if(addTaps)
+	{
+		result += mpt::cformat(_T(" (%1 tap%2)"))(Resampling::Length(mode), (Resampling::Length(mode) != 1) ? CString(_T("s")) : CString(_T("")));
+	}
+	return result;
 }
 
 
Index: mptrack/Mptrack.h
===================================================================
--- mptrack/Mptrack.h	(revision 10980)
+++ mptrack/Mptrack.h	(working copy)
@@ -269,7 +269,7 @@
 
 public:
 	// Get name of resampling mode. addTaps = true also adds the number of taps the filter uses.
-	static const TCHAR *GetResamplingModeName(ResamplingMode mode, bool addTaps);
+	static CString GetResamplingModeName(ResamplingMode mode, int length, bool addTaps);
 
 // Overrides
 public:
Index: mptrack/mptrack.rc
===================================================================
--- mptrack/mptrack.rc	(revision 10980)
+++ mptrack/mptrack.rc	(working copy)
@@ -2159,15 +2159,9 @@
 BEGIN
     GROUPBOX        "Resampling",IDC_STATIC,6,6,276,48
     LTEXT           "&Filter:",IDC_STATIC,12,18,24,12,SS_CENTERIMAGE
-    COMBOBOX        IDC_COMBO_FILTER,54,18,96,56,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
-    LTEXT           "&Window:",IDC_STATIC,156,18,30,12,SS_CENTERIMAGE
-    COMBOBOX        IDC_COMBO_FILTERWINDOW,192,18,84,56,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
-    LTEXT           "&Bandwidth:",IDC_STATIC,12,36,42,12,SS_CENTERIMAGE
-    EDITTEXT        IDC_WFIRCUTOFF,54,36,30,12,ES_RIGHT | ES_AUTOHSCROLL | ES_NUMBER
-    CONTROL         "",IDC_SPIN1,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_NOTHOUSANDS,71,31,11,14
-    LTEXT           "%",IDC_STATIC,90,36,24,12,SS_CENTERIMAGE
+    COMBOBOX        IDC_COMBO_FILTER,36,18,102,56,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
     CONTROL         "Use &Amiga resampler for Amiga modules",IDC_CHECK1,
-                    "Button",BS_AUTOCHECKBOX | WS_TABSTOP,126,36,150,12
+                    "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,36,144,12
     GROUPBOX        "Volume Ramping",IDC_STATIC,6,60,276,48
     EDITTEXT        IDC_RAMPING_IN,12,72,36,12,ES_RIGHT | ES_AUTOHSCROLL | ES_NUMBER
     CONTROL         "",IDC_SPIN2,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_NOTHOUSANDS,42,66,11,14
Index: mptrack/resource.h
===================================================================
--- mptrack/resource.h	(revision 10980)
+++ mptrack/resource.h	(working copy)
@@ -686,8 +686,6 @@
 #define IDC_COMMAND_LIST                2129
 #define IDC_STATIC8                     2200
 #define IDC_PATINSTROPLUGGUI            2201
-#define IDC_WFIRCUTOFF                  2202
-#define IDC_WFIRTYPE                    2203
 #define IDC_RAMPING_IN                  2204
 #define IDC_PLAYEROPTIONS               2205
 #define IDC_RAMPING_OUT                 2205
Index: mptrack/SampleEditorDialogs.cpp
===================================================================
--- mptrack/SampleEditorDialogs.cpp	(revision 10980)
+++ mptrack/SampleEditorDialogs.cpp	(working copy)
@@ -534,12 +534,12 @@
 
 	CComboBox *cbnResampling = static_cast<CComboBox *>(GetDlgItem(IDC_COMBO_FILTER));
 	cbnResampling->SetRedraw(FALSE);
-	const ResamplingMode resamplingModes[] = { SRCMODE_NEAREST, SRCMODE_LINEAR, SRCMODE_SPLINE, SRCMODE_POLYPHASE, SRCMODE_FIRFILTER, SRCMODE_DEFAULT };
+	const auto resamplingModes = Resampling::AllModesWithDefault();
 	for(auto mode : resamplingModes)
 	{
-		const TCHAR *desc = _T("r8brain (High Quality)");
+		CString desc = _T("r8brain (High Quality)");
 		if(mode != SRCMODE_DEFAULT)
-			desc = CTrackApp::GetResamplingModeName(mode, false);
+			desc = CTrackApp::GetResamplingModeName(mode, 1, true);
 
 		int index = cbnResampling->AddString(desc);
 		cbnResampling->SetItemData(index, mode);
Index: mptrack/TrackerSettings.cpp
===================================================================
--- mptrack/TrackerSettings.cpp	(revision 10980)
+++ mptrack/TrackerSettings.cpp	(working copy)
@@ -74,29 +74,6 @@
 }
 
 
-static ResamplingMode GetDefaultResamplerMode()
-{
-	ResamplingMode result = CResamplerSettings().SrcMode;
-#ifdef ENABLE_ASM
-	// rough heuristic to select less cpu consuming defaults for old CPUs
-	if(GetRealProcSupport() & PROCSUPPORT_SSE)
-	{
-		result = SRCMODE_POLYPHASE;
-	} else if(GetRealProcSupport() & PROCSUPPORT_MMX)
-	{
-		result = SRCMODE_SPLINE;
-	} else
-	{
-		result = SRCMODE_LINEAR;
-	}
-#else
-	// just use a sane default
-	result = CResamplerSettings().SrcMode;
-#endif
-	return result;
-}
-
-
 static uint32 GetDefaultPatternSetup()
 {
 	return PATTERN_PLAYNEWNOTE | PATTERN_EFFECTHILIGHT
@@ -245,7 +222,7 @@
 	, MixerStereoSeparation(conf, MPT_USTRING("Sound Settings"), MPT_USTRING("StereoSeparation"), MixerSettings().m_nStereoSeparation)
 	, MixerVolumeRampUpMicroseconds(conf, MPT_USTRING("Sound Settings"), MPT_USTRING("VolumeRampUpMicroseconds"), MixerSettings().GetVolumeRampUpMicroseconds())
 	, MixerVolumeRampDownMicroseconds(conf, MPT_USTRING("Sound Settings"), MPT_USTRING("VolumeRampDownMicroseconds"), MixerSettings().GetVolumeRampDownMicroseconds())
-	, ResamplerMode(conf, MPT_USTRING("Sound Settings"), MPT_USTRING("SrcMode"), GetDefaultResamplerMode())
+	, ResamplerMode(conf, MPT_USTRING("Sound Settings"), MPT_USTRING("SrcMode"), CResamplerSettings().SrcMode)
 	, ResamplerSubMode(conf, MPT_USTRING("Sound Settings"), MPT_USTRING("XMMSModplugResamplerWFIRType"), CResamplerSettings().gbWFIRType)
 	, ResamplerCutoffPercent(conf, MPT_USTRING("Sound Settings"), MPT_USTRING("ResamplerWFIRCutoff"), mpt::saturate_round<int32>(CResamplerSettings().gdWFIRCutoff * 100.0))
 	, ResamplerEmulateAmiga(conf, MPT_USTRING("Sound Settings"), MPT_USTRING("ResamplerEmulateAmiga"), true)
@@ -556,6 +533,13 @@
 		m_SoundDeviceSettingsDefaults.UseHardwareTiming = m_SoundDeviceUseHardwareTiming;
 		m_SoundDeviceSettingsUseOldDefaults = true;
 	}
+	if(storedVersion < MAKE_VERSION_NUMERIC(1,28,00,41))
+	{
+		// reset this setting to the default when updating,
+		// because we do not provide a GUI any more,
+		// and in general, it should not get changed anyway
+		ResamplerCutoffPercent = mpt::saturate_round<int32>(CResamplerSettings().gdWFIRCutoff * 100.0);
+	}
 	if(storedVersion < MAKE_VERSION_NUMERIC(1,25,00,04))
 	{
 		m_SoundDeviceDirectSoundOldDefaultIdentifier = true;
@@ -726,7 +710,7 @@
 	}
 
 	// Sanitize resampling mode for sample editor
-	if(!IsKnownResamplingMode(sampleEditorDefaultResampler) && sampleEditorDefaultResampler != SRCMODE_DEFAULT)
+	if(!Resampling::IsKnownMode(sampleEditorDefaultResampler) && sampleEditorDefaultResampler != SRCMODE_DEFAULT)
 	{
 		sampleEditorDefaultResampler = SRCMODE_DEFAULT;
 	}
Index: soundlib/Load_it.cpp
===================================================================
--- soundlib/Load_it.cpp	(revision 10980)
+++ soundlib/Load_it.cpp	(working copy)
@@ -2369,7 +2369,7 @@
 			case MagicBE("RP.."): if(GetType() != MOD_TYPE_XM) { ORDERINDEX restartPos; ReadField(chunk, size, restartPos); Order().SetRestartPos(restartPos); } break;
 			case MagicLE("RSMP"):
 				ReadFieldCast(chunk, size, m_nResampling);
-				if(!IsKnownResamplingMode(m_nResampling)) m_nResampling = SRCMODE_DEFAULT;
+				if(!Resampling::IsKnownMode(m_nResampling)) m_nResampling = SRCMODE_DEFAULT;
 				break;
 #ifdef MODPLUG_TRACKER
 			case MagicBE("MIMA"): GetMIDIMapper().Deserialize(chunk); break;
Index: soundlib/MixFuncTable.cpp
===================================================================
--- soundlib/MixFuncTable.cpp	(revision 10980)
+++ soundlib/MixFuncTable.cpp	(working copy)
@@ -79,9 +79,9 @@
 	{
 	case SRCMODE_NEAREST:   return ndxNoInterpolation;
 	case SRCMODE_LINEAR:    return ndxLinear;
-	case SRCMODE_SPLINE:    return ndxFastSinc;
-	case SRCMODE_POLYPHASE: return ndxKaiser;
-	case SRCMODE_FIRFILTER: return ndxFIRFilter;
+	case SRCMODE_CUBIC:     return ndxFastSinc;
+	case SRCMODE_SINC8LP:   return ndxKaiser;
+	case SRCMODE_SINC8:     return ndxFIRFilter;
 	case SRCMODE_AMIGA:     return ndxAmigaBlep;
 	default:                MPT_ASSERT_NOTREACHED();
 	}
Index: soundlib/Resampler.h
===================================================================
--- soundlib/Resampler.h	(revision 10980)
+++ soundlib/Resampler.h	(working copy)
@@ -61,12 +61,12 @@
 	uint8 gbWFIRType;
 	bool emulateAmiga;
 public:
-	CResamplerSettings()
+	MPT_CONSTEXPR11_FUN CResamplerSettings()
+		: SrcMode(Resampling::Default())
+		, gdWFIRCutoff(0.97)
+		, gbWFIRType(WFIR_KAISER4T)
+		, emulateAmiga(false)
 	{
-		SrcMode = SRCMODE_POLYPHASE;
-		gdWFIRCutoff = 0.97;
-		gbWFIRType = WFIR_KAISER4T;
-		emulateAmiga = false;
 	}
 	bool operator == (const CResamplerSettings &cmp) const
 	{
@@ -127,8 +127,6 @@
 	{
 		InitializeTablesFromScratch(false);
 	}
-	~CResampler() {}
-	bool IsHQ() const { return m_Settings.SrcMode >= SRCMODE_SPLINE && m_Settings.SrcMode < SRCMODE_DEFAULT; }
 private:
 	void InitFloatmixerTables();
 	void InitializeTablesFromScratch(bool force=false);
Index: soundlib/Snd_defs.h
===================================================================
--- soundlib/Snd_defs.h	(revision 10980)
+++ soundlib/Snd_defs.h	(working copy)
@@ -297,22 +297,55 @@
 {
 	// ATTENTION: Do not change ANY of these values, as they get written out to files in per instrument interpolation settings
 	// and old files have these exact values in them which should not change meaning.
-	SRCMODE_NEAREST   = 0,
-	SRCMODE_LINEAR    = 1,
-	SRCMODE_SPLINE    = 2,
-	SRCMODE_POLYPHASE = 3,
-	SRCMODE_FIRFILTER = 4,
-	SRCMODE_DEFAULT   = 5,
+	SRCMODE_NEAREST   = 0,  // 1 tap, no AA
+	SRCMODE_LINEAR    = 1,  // 2 tap, no AA
+	SRCMODE_CUBIC     = 2,  // 4 tap, no AA
+	SRCMODE_SINC8     = 4,  // 8 tap, no AA   (yes, index 4) (XMMS-ModPlug)
+	SRCMODE_SINC8LP   = 3,  // 8 tap, with AA (yes, index 3) (Polyphase)
 
-	SRCMODE_AMIGA = 0xFF,	// Not explicitely user-selectable
+	SRCMODE_DEFAULT   = 5,  // only used for instrument settings, not used inside the mixer
+
+	SRCMODE_AMIGA  = 0xFF,  // Not explicitely user-selectable
 };
 
-static inline bool IsKnownResamplingMode(int mode)
+namespace Resampling
 {
-	return (mode >= 0) && (mode < SRCMODE_DEFAULT);
+
+static inline std::array<ResamplingMode, 5> AllModes() noexcept { return { SRCMODE_NEAREST, SRCMODE_LINEAR, SRCMODE_CUBIC, SRCMODE_SINC8, SRCMODE_SINC8LP }; }
+
+static inline std::array<ResamplingMode, 6> AllModesWithDefault() noexcept { return { SRCMODE_NEAREST, SRCMODE_LINEAR, SRCMODE_CUBIC, SRCMODE_SINC8, SRCMODE_SINC8LP, SRCMODE_DEFAULT }; }
+
+static MPT_CONSTEXPR11_FUN ResamplingMode Default() noexcept { return SRCMODE_SINC8LP; }
+
+static MPT_CONSTEXPR11_FUN bool IsKnownMode(int mode) noexcept { return (mode >= 0) && (mode < SRCMODE_DEFAULT); }
+
+static MPT_CONSTEXPR11_FUN ResamplingMode ToKnownMode(int mode) noexcept
+{
+	return Resampling::IsKnownMode(mode) ? static_cast<ResamplingMode>(mode)
+		: (mode == SRCMODE_AMIGA) ? SRCMODE_LINEAR
+		: Resampling::Default();
 }
 
+static MPT_CONSTEXPR11_FUN int Length(ResamplingMode mode) noexcept
+{
+	return mode == SRCMODE_NEAREST ? 1
+		: mode == SRCMODE_LINEAR ? 2
+		: mode == SRCMODE_CUBIC ? 4
+		: mode == SRCMODE_SINC8 ? 8
+		: mode == SRCMODE_SINC8LP ? 8
+		: 0;
+}
 
+static MPT_CONSTEXPR11_FUN bool HasAA(ResamplingMode mode) noexcept { return (mode == SRCMODE_SINC8LP); }
+
+static MPT_CONSTEXPR11_FUN ResamplingMode AddAA(ResamplingMode mode) noexcept { return (mode == SRCMODE_SINC8) ? SRCMODE_SINC8LP : mode; }
+
+static MPT_CONSTEXPR11_FUN ResamplingMode RemoveAA(ResamplingMode mode) noexcept { return (mode == SRCMODE_SINC8LP) ? SRCMODE_SINC8 : mode; }
+
+}
+
+
+
 // Release node defines
 #define ENV_RELEASE_NODE_UNSET	0xFF
 #define NOT_YET_RELEASED		(-1)
Index: soundlib/Sndmix.cpp
===================================================================
--- soundlib/Sndmix.cpp	(revision 10980)
+++ soundlib/Sndmix.cpp	(working copy)
@@ -2375,11 +2375,11 @@
 			//if (chn.nNewRightVol > 0xFFFF) chn.nNewRightVol = 0xFFFF;
 			//if (chn.nNewLeftVol > 0xFFFF) chn.nNewLeftVol = 0xFFFF;
 
-			if(chn.pModInstrument && IsKnownResamplingMode(chn.pModInstrument->nResampling))
+			if(chn.pModInstrument && Resampling::IsKnownMode(chn.pModInstrument->nResampling))
 			{
 				// For defined resampling modes, use per-instrument resampling mode if set
 				chn.resamplingMode = static_cast<uint8>(chn.pModInstrument->nResampling);
-			} else if(IsKnownResamplingMode(m_nResampling))
+			} else if(Resampling::IsKnownMode(m_nResampling))
 			{
 				chn.resamplingMode = static_cast<uint8>(m_nResampling);
 			} else if(m_SongFlags[SONG_ISAMIGA] && m_Resampler.m_Settings.emulateAmiga)
Index: soundlib/Tables.cpp
===================================================================
--- soundlib/Tables.cpp	(revision 10980)
+++ soundlib/Tables.cpp	(working copy)
@@ -750,42 +750,7 @@
 	}
 }
 
-#if 0
 
-// this code is currently unused
-
-static double GetSpline(double x, double c0, double c1, double c2, double c3)
-{
-	double Xo = c1;
-	double Xa = c0 - Xo;
-	double Xb = c2 - Xo;
-	double Ux = (Xb-Xa)/2;
-	double Vx = (c3 - Xo)/2;
-	double a = Vx+Ux-2*Xb;
-	double b = 3*Xb-2*Ux-Vx;
-	return (((a*x+b)*x)+Ux)*x+Xo;
-}
-
-
-static void getdownsample2x(short int *psinc)
-{
-	for (int i=0; i<SINC_PHASES; i++)
-	{
-		double x = (double)i * (double)(0.5/SINC_PHASES);
-		psinc[i*8+7] = (short int)(GetSpline(x,     0, 0, 0, 1) * 8192);
-		psinc[i*8+6] = (short int)(GetSpline(x+0.5, 0, 0, 0, 1) * 8192);
-		psinc[i*8+5] = (short int)(GetSpline(x,     0, 0, 1, 0) * 8192);
-		psinc[i*8+4] = (short int)(GetSpline(x+0.5, 0, 0, 1, 0) * 8192);
-		psinc[i*8+3] = (short int)(GetSpline(x,     0, 1, 0, 0) * 8192);
-		psinc[i*8+2] = (short int)(GetSpline(x+0.5, 0, 1, 0, 0) * 8192);
-		psinc[i*8+1] = (short int)(GetSpline(x,     1, 0, 0, 0) * 8192);
-		psinc[i*8+0] = (short int)(GetSpline(x+0.5, 1, 0, 0, 0) * 8192);
-	}
-}
-
-#endif
-
-
 #ifdef MODPLUG_TRACKER
 bool CResampler::StaticTablesInitialized = false;
 SINC_TYPE CResampler::gKaiserSinc[SINC_PHASES*8];     // Upsampling
@@ -835,12 +800,8 @@
 		InitFloatmixerTables();
 
 		getsinc(gKaiserSinc, 9.6377, 0.97);
-		//ericus' downsampling improvement.
-		//getsinc(gDownsample13x, 8.5, 3.0/4.0);
-		//getdownsample2x(gDownsample2x);
 		getsinc(gDownsample13x, 8.5, 0.5);
 		getsinc(gDownsample2x, 2.7625, 0.425);
-		//end ericus' downsampling improvement.
 
 		#ifdef MODPLUG_TRACKER
 			StaticTablesInitialized = true;
Index: soundlib/WindowedFIR.h
===================================================================
--- soundlib/WindowedFIR.h	(revision 10980)
+++ soundlib/WindowedFIR.h	(working copy)
@@ -50,25 +50,20 @@
 #define WFIR_LOG2WIDTH		3
 #define WFIR_WIDTH			(1L<<WFIR_LOG2WIDTH)
 // cutoff (1.0 == pi/2)
-//float WFIR_CUTOFF			= 0.5f;//0.75f;	//0.90f;
 // wfir type
 enum WFIRType
 {
-	WFIR_HANN			= 0,
-	WFIR_HAMMING		= 1,
-	WFIR_BLACKMANEXACT	= 2,
-	WFIR_BLACKMAN3T61	= 3,
-	WFIR_BLACKMAN3T67	= 4,
-	WFIR_BLACKMAN4T92	= 5,
-	WFIR_BLACKMAN4T74	= 6,
-	WFIR_KAISER4T		= 7,
+	WFIR_HANN          = 0,  // Hann
+	WFIR_HAMMING       = 1,  // Hamming
+	WFIR_BLACKMANEXACT = 2,  // Blackman Exact
+	WFIR_BLACKMAN3T61  = 3,  // Blackman 3-Tap 61
+	WFIR_BLACKMAN3T67  = 4,  // Blackman 3-Tap 67
+	WFIR_BLACKMAN4T92  = 5,  // Blackman-Harris
+	WFIR_BLACKMAN4T74  = 6,  // Blackman 4-Tap 74
+	WFIR_KAISER4T      = 7,  // Kaiser a=7.5
 };
-//int WFIR_TYPE				= WFIR_KAISER4T;//WFIR_BLACKMANEXACT;
-//int WFIR_TYPE				= TrackerSettings::Instance().gbWFIRType;
 // wfir help
-#ifndef M_zPI
 #define M_zPI				3.1415926535897932384626433832795
-#endif
 #define M_zEPS				1e-8
 
 
Index: test/test.cpp
===================================================================
--- test/test.cpp	(revision 10980)
+++ test/test.cpp	(working copy)
@@ -3077,7 +3077,7 @@
 	VERIFY_EQUAL_NONCONT(pIns->nPPC, NOTE_MIDDLEC - 1);
 
 	VERIFY_EQUAL_NONCONT(pIns->nVolRampUp, 1200);
-	VERIFY_EQUAL_NONCONT(pIns->nResampling, (unsigned)SRCMODE_POLYPHASE);
+	VERIFY_EQUAL_NONCONT(pIns->nResampling, (unsigned)SRCMODE_SINC8LP);
 
 	VERIFY_EQUAL_NONCONT(pIns->IsCutoffEnabled(), false);
 	VERIFY_EQUAL_NONCONT(pIns->GetCutoff(), 0);
@@ -3207,7 +3207,7 @@
 	VERIFY_EQUAL_NONCONT(sndFile.m_nDefaultRowsPerBeat, 6);
 	VERIFY_EQUAL_NONCONT(sndFile.m_nDefaultRowsPerMeasure, 12);
 	VERIFY_EQUAL_NONCONT(sndFile.m_dwCreatedWithVersion, MAKE_VERSION_NUMERIC(1, 19, 02, 05));
-	VERIFY_EQUAL_NONCONT(sndFile.m_nResampling, SRCMODE_POLYPHASE);
+	VERIFY_EQUAL_NONCONT(sndFile.m_nResampling, SRCMODE_SINC8LP);
 	VERIFY_EQUAL_NONCONT(sndFile.m_songArtist, MPT_USTRING("Tester"));
 	VERIFY_EQUAL_NONCONT(sndFile.m_tempoSwing.size(), 6);
 	VERIFY_EQUAL_NONCONT(sndFile.m_tempoSwing[0], 29360125);
@@ -3370,7 +3370,7 @@
 		VERIFY_EQUAL_NONCONT(pIns->nPPC, (NOTE_MIDDLEC - NOTE_MIN) + 6);	// F#5
 
 		VERIFY_EQUAL_NONCONT(pIns->nVolRampUp, 1200);
-		VERIFY_EQUAL_NONCONT(pIns->nResampling, (unsigned)SRCMODE_POLYPHASE);
+		VERIFY_EQUAL_NONCONT(pIns->nResampling, (unsigned)SRCMODE_SINC8LP);
 
 		VERIFY_EQUAL_NONCONT(pIns->IsCutoffEnabled(), true);
 		VERIFY_EQUAL_NONCONT(pIns->GetCutoff(), 0x32);
resampler-cleanup-v8.patch (28,900 bytes)   
Has the bug occurred in previous versions?
Tested code revision (in case you know it)

Activities

manx

manx

2018-03-11 20:25

administrator   ~0003475

The 4-tap filter and both 8-tap filters are implemented as truncated sinc filters. Naming of interpolation/resampling filters is confusing at best, because there is just no well established standard in how to name them.
The distinguishing aspect, quality wise, of interpolation filters is basically only the filter length as well as the cutoff frequency and stop-band attenuation of the low-pass filter which avoid aliasing when down-sampling.
Having said that, talking about the specific implementations in OpenMPT, "Cubic Spline" has no low-pass filter, and "XMMS-ModPlug" has also no low-pass filter. "Polyphase" implements a very crude low-pass filter (though probably as good as it can get when only using 8 filter taps.
Thus, "Polyphase" in better than "XMMS-ModPlug" is better than "Cubic Spline". However, given that even "Polyphase" is not that good compared to other software, the best quality can be achieved by increasing the mixer sample rate and downsampling the result with an external tool.

We should really improve documentation, filter selection UI and naming of the filters.

IsaacNorman

IsaacNorman

2018-03-11 20:37

reporter   ~0003476

I agree with you on the last statement, because I've never heard of the last two filters. If they're MPT-exclusive then that explains it. I've only heard of the standard Linear, Cubic, Sinc, (the rare Gaussian that no one seems to use for some reason...), and FIR interpolations. It's a shame that MPT doesn't include a couple more of those, because other applications do. I hope to see the descriptions, documentations and names updated in a future release so they're more precise.

manx

manx

2018-03-11 20:42

administrator   ~0003477

Both 8-tap filters in OpenMPT can rightfully be called FIR, can rightfully be called Polyphase, can rightfully be called Sinc, can even rightfully be called Polynomial.
Truncating the sinc function is a way to derive FIR filter coefficients which are for performance reasons then sampled at a set of varying phases (thus polyphase). The resulting filter can be interpreted as a polynomial. It's all the same.
The name "XMMS-ModPlug" originates from the fact that is was ported from that branch of ModPlug in (by now) ancient history. It's thus only a description of origin and not of implementation aspects (which are fundamentally identical to those of the "Polyphase" filter).

I guess you are right about the fact that "Sinc" might be a more usual name.

IsaacNorman

IsaacNorman

2018-03-11 20:47

reporter   ~0003478

Will the proper names be implemented in a nearby future release? (Yes, I am an audiophile when it comes to quality.)

Saga Musix

Saga Musix

2018-03-12 11:28

administrator   ~0003479

It's a shame that MPT doesn't include a couple more of those, because other applications do.

Including more filters just "because others have it" or to fill up the buzzword bingo card leads us exactly nowhere. As manx says, it's just as appropriate to call it Polyphase as to call it a FIR filter or Sinc filter. All of those just describe different details of the filter. None of these terms describe the filter in its full nature.

manx

manx

2018-03-12 16:06

administrator   ~0003480

Last edited: 2018-03-12 16:16

Will the proper names be implemented in a nearby future release?

Leaving aside "XMMS-ModPlug", which is really no useful description of the filter at all, there simply is no naming scheme that is more "proper" than any other.

(Yes, I am an audiophile when it comes to quality.)

The default ("Polyphase") is the best filter currently available.

I think, we should rename "XMMS-ModPlug" to "Sinc (8 taps)" and "Polyphase" to "Sinc with Low-Pass (8 taps)" and re-order the list so that "Sinc with Low-Pass (8 taps)" comes after ""Sinc (8 taps)", making it increasing in quality. While at it, we should also remove the selection of the windowing function and the filter bandwidth selection. These really serve no purpose other than confuse users. We can keep them as hidden options.

@IsaacNorman: Note that none of these changes will change any behaviour. This is PURELY cosmetic and only about using (hopefully) clearer naming.

manx

manx

2018-03-12 16:11

administrator   ~0003481

I do not have a particularly strong opinion about the "Sinc" name. However, "FIR" would not be useful at all, because by context each and every filter we could implement here would be FIR. "Polyphase" is kind of a long name and is afaik not a very common description used in the wild.

resampler-cleanup-v1.patch (28,622 bytes)   
Index: common/versionNumber.h
===================================================================
--- common/versionNumber.h	(revision 9920)
+++ common/versionNumber.h	(working copy)
@@ -19,7 +19,7 @@
 #define VER_MAJORMAJOR          1
 #define VER_MAJOR               28
 #define VER_MINOR               00
-#define VER_MINORMINOR          14
+#define VER_MINORMINOR          15
 
 //Version string. For example "1.17.02.28"
 #define MPT_VERSION_STR         VER_STRINGIZE(VER_MAJORMAJOR) "." VER_STRINGIZE(VER_MAJOR) "." VER_STRINGIZE(VER_MINOR) "." VER_STRINGIZE(VER_MINORMINOR)
Index: libopenmpt/libopenmpt_impl.cpp
===================================================================
--- libopenmpt/libopenmpt_impl.cpp	(revision 9920)
+++ libopenmpt/libopenmpt_impl.cpp	(working copy)
@@ -316,11 +316,11 @@
 }
 
 static ResamplingMode filterlength_to_resamplingmode(std::int32_t length) {
-	ResamplingMode result = SRCMODE_POLYPHASE;
+	ResamplingMode result = SRCMODE_SINC8LP;
 	if ( length == 0 ) {
-		result = SRCMODE_POLYPHASE;
+		result = SRCMODE_SINC8LP;
 	} else if ( length >= 8 ) {
-		result = SRCMODE_POLYPHASE;
+		result = SRCMODE_SINC8LP;
 	} else if ( length >= 3 ) {
 		result = SRCMODE_SPLINE;
 	} else if ( length >= 2 ) {
@@ -343,8 +343,8 @@
 	case SRCMODE_SPLINE:
 		return 4;
 		break;
-	case SRCMODE_POLYPHASE:
-	case SRCMODE_FIRFILTER:
+	case SRCMODE_SINC8:
+	case SRCMODE_SINC8LP:
 	case SRCMODE_DEFAULT:
 		return 8;
 	default:
Index: mptrack/Ctrl_gen.cpp
===================================================================
--- mptrack/Ctrl_gen.cpp	(revision 9920)
+++ mptrack/Ctrl_gen.cpp	(working copy)
@@ -202,21 +202,21 @@
 	FlagSet<HintType> hintType = hint.GetType();
 	const bool updateAll = hintType[HINT_MODTYPE];
 
-	const ResamplingMode resamplingModes[] = { SRCMODE_NEAREST, SRCMODE_LINEAR, SRCMODE_SPLINE, SRCMODE_POLYPHASE, SRCMODE_FIRFILTER };
+	const auto resamplingModes = Resampling::AllModes();
 
 	if (hintType == HINT_MPTOPTIONS || updateAll)
 	{
-		const TCHAR *defaultResampler;
+		CString defaultResampler;
 		if(m_sndFile.m_SongFlags[SONG_ISAMIGA] && TrackerSettings::Instance().ResamplerEmulateAmiga)
 			defaultResampler = _T("Amiga Resampler");
 		else
-			defaultResampler = CTrackApp::GetResamplingModeName(TrackerSettings::Instance().ResamplerMode, false);
+			defaultResampler = CTrackApp::GetResamplingModeName(TrackerSettings::Instance().ResamplerMode, 1, false);
 
 		m_CbnResampling.ResetContent();
-		m_CbnResampling.SetItemData(m_CbnResampling.AddString(_T("Default (") + CString(defaultResampler) + _T(")")), SRCMODE_DEFAULT);
+		m_CbnResampling.SetItemData(m_CbnResampling.AddString(_T("Default (") + defaultResampler + _T(")")), SRCMODE_DEFAULT);
 		for(auto mode : resamplingModes)
 		{
-			m_CbnResampling.SetItemData(m_CbnResampling.AddString(CTrackApp::GetResamplingModeName(mode, false)), mode);
+			m_CbnResampling.SetItemData(m_CbnResampling.AddString(CTrackApp::GetResamplingModeName(mode, 2, true)), mode);
 		}
 		m_CbnResampling.Invalidate(FALSE);
 	}
@@ -312,12 +312,13 @@
 
 	if(updateAll || hintType == HINT_MPTOPTIONS || (hint.GetCategory() == HINTCAT_GENERAL && hintType[HINT_MODGENERAL]))
 	{
+
 		int srcMode = 0;
-		for(int i = 0; i < CountOf(resamplingModes); i++)
+		for(int i = 0; i < m_CbnResampling.GetCount(); ++i)
 		{
-			if(m_sndFile.m_nResampling == resamplingModes[i]) srcMode = i + 1;
+			if(m_sndFile.m_nResampling == static_cast<int>(m_CbnResampling.GetItemData(i)))
+				m_CbnResampling.SetCurSel(i);
 		}
-		m_CbnResampling.SetCurSel(srcMode);
 	}
 
 	CheckDlgButton(IDC_CHECK_LOOPSONG, (TrackerSettings::Instance().gbLoopSong) ? TRUE : FALSE);
Index: mptrack/Ctrl_ins.cpp
===================================================================
--- mptrack/Ctrl_ins.cpp	(revision 9920)
+++ mptrack/Ctrl_ins.cpp	(working copy)
@@ -995,12 +995,12 @@
 	m_EditPWD.SubclassDlgItem(IDC_PITCHWHEELDEPTH, this);
 	m_EditPWD.AllowFractions(false);
 
+	const auto resamplingModes = Resampling::AllModes();
 	m_CbnResampling.SetItemData(m_CbnResampling.AddString(_T("Default")), SRCMODE_DEFAULT);
-	m_CbnResampling.SetItemData(m_CbnResampling.AddString(_T("None")), SRCMODE_NEAREST);
-	m_CbnResampling.SetItemData(m_CbnResampling.AddString(_T("Linear")), SRCMODE_LINEAR);
-	m_CbnResampling.SetItemData(m_CbnResampling.AddString(_T("Spline")), SRCMODE_SPLINE);
-	m_CbnResampling.SetItemData(m_CbnResampling.AddString(_T("Polyphase")), SRCMODE_POLYPHASE);
-	m_CbnResampling.SetItemData(m_CbnResampling.AddString(_T("XMMS")), SRCMODE_FIRFILTER);
+	for(auto mode : resamplingModes)
+	{
+		m_CbnResampling.SetItemData(m_CbnResampling.AddString(CTrackApp::GetResamplingModeName(mode, 1, false)), mode);
+	}
 
 	m_CbnFilterMode.SetItemData(m_CbnFilterMode.AddString(_T("Channel default")), FLTMODE_UNCHANGED);
 	m_CbnFilterMode.SetItemData(m_CbnFilterMode.AddString(_T("Force lowpass")), FLTMODE_LOWPASS);
Index: mptrack/Mpdlgs.cpp
===================================================================
--- mptrack/Mpdlgs.cpp	(revision 9920)
+++ mptrack/Mpdlgs.cpp	(working copy)
@@ -928,9 +928,7 @@
 	ON_WM_HSCROLL()
 	ON_WM_VSCROLL()
 	ON_CBN_SELCHANGE(IDC_COMBO_FILTER,			OnResamplerChanged)
-	ON_CBN_SELCHANGE(IDC_COMBO_FILTERWINDOW,	OnSettingsChanged)
 	ON_CBN_SELCHANGE(IDC_COMBO_POLYPHONY,		OnSettingsChanged)
-	ON_EN_UPDATE(IDC_WFIRCUTOFF,				OnSettingsChanged)
 	ON_EN_UPDATE(IDC_RAMPING_IN,				OnRampingChanged)
 	ON_EN_UPDATE(IDC_RAMPING_OUT,				OnRampingChanged)
 	ON_COMMAND(IDC_CHECK_SOFTPAN,				OnSettingsChanged)
@@ -943,8 +941,6 @@
 	CPropertyPage::DoDataExchange(pDX);
 	//{{AFX_DATA_MAP(COptionsSoundcard)
 	DDX_Control(pDX, IDC_COMBO_FILTER, m_CbnResampling);
-	DDX_Control(pDX, IDC_WFIRCUTOFF, m_CEditWFIRCutoff);
-	DDX_Control(pDX, IDC_COMBO_FILTERWINDOW, m_CbnWFIRType);
 	DDX_Control(pDX, IDC_RAMPING_IN, m_CEditRampUp);
 	DDX_Control(pDX, IDC_RAMPING_OUT, m_CEditRampDown);
 	DDX_Control(pDX, IDC_EDIT_VOLRAMP_SAMPLES_UP, m_CInfoRampUp);
@@ -963,26 +959,18 @@
 
 	// Resampling type
 	{
-		for(auto mode : { SRCMODE_NEAREST, SRCMODE_LINEAR, SRCMODE_SPLINE, SRCMODE_POLYPHASE, SRCMODE_FIRFILTER })
+		const auto resamplingModes = Resampling::AllModes();
+		for(auto mode : resamplingModes)
 		{
-			int index = m_CbnResampling.AddString(CTrackApp::GetResamplingModeName(mode, true));
+			int index = m_CbnResampling.AddString(CTrackApp::GetResamplingModeName(mode, 2, true));
 			m_CbnResampling.SetItemData(index, mode);
 			if(TrackerSettings::Instance().ResamplerMode == mode)
+			{
 				m_CbnResampling.SetCurSel(index);
+			}
 		}
 	}
 
-	// Resampler bandwidth
-	{
-		m_CEditWFIRCutoff.SetWindowText(mpt::ToCString(mpt::ufmt::val(TrackerSettings::Instance().ResamplerCutoffPercent)));
-		static_cast<CSpinButtonCtrl *>(GetDlgItem(IDC_SPIN1))->SetRange32(1, 99);
-	}
-
-	// Resampler filter window
-	{
-		// done in OnResamplerChanged()
-	}
-
 	// Amiga Resampler
 	CheckDlgButton(IDC_CHECK1, TrackerSettings::Instance().ResamplerEmulateAmiga ? BST_CHECKED : BST_UNCHECKED);
 
@@ -1037,7 +1025,6 @@
 		m_SliderPreAmp.SetPos(n);
 	}
 
-	OnResamplerChanged();
 	m_initialized = true;
 
 	return TRUE;
@@ -1053,61 +1040,6 @@
 
 void COptionsMixer::OnResamplerChanged()
 {
-	ResamplingMode srcMode = static_cast<ResamplingMode>(m_CbnResampling.GetItemData(m_CbnResampling.GetCurSel()));
-	m_CbnWFIRType.ResetContent();
-	switch(srcMode)
-	{
-		case SRCMODE_FIRFILTER:
-			m_CbnWFIRType.AddString(_T("Hann"));
-			m_CbnWFIRType.AddString(_T("Hamming"));
-			m_CbnWFIRType.AddString(_T("Blackman Exact"));
-			m_CbnWFIRType.AddString(_T("Blackman 3 Tap 61"));
-			m_CbnWFIRType.AddString(_T("Blackman 3 Tap 67"));
-			m_CbnWFIRType.AddString(_T("Blackman Harris"));
-			m_CbnWFIRType.AddString(_T("Blackman 4 Tap 74"));
-			m_CbnWFIRType.AddString(_T("Kaiser a=7.5"));
-			break;
-		case SRCMODE_POLYPHASE:
-			m_CbnWFIRType.AddString(_T("Auto"));
-			m_CbnWFIRType.AddString(_T("Auto"));
-			m_CbnWFIRType.AddString(_T("Auto"));
-			m_CbnWFIRType.AddString(_T("Auto"));
-			m_CbnWFIRType.AddString(_T("Auto"));
-			m_CbnWFIRType.AddString(_T("Auto"));
-			m_CbnWFIRType.AddString(_T("Auto"));
-			m_CbnWFIRType.AddString(_T("Auto"));
-			break;
-		default:
-			m_CbnWFIRType.AddString(_T("none"));
-			m_CbnWFIRType.AddString(_T("none"));
-			m_CbnWFIRType.AddString(_T("none"));
-			m_CbnWFIRType.AddString(_T("none"));
-			m_CbnWFIRType.AddString(_T("none"));
-			m_CbnWFIRType.AddString(_T("none"));
-			m_CbnWFIRType.AddString(_T("none"));
-			m_CbnWFIRType.AddString(_T("none"));
-			break;
-	}
-	m_CbnWFIRType.SetCurSel(TrackerSettings::Instance().ResamplerSubMode);
-	CSpinButtonCtrl *spinWFIRCutoff = static_cast<CSpinButtonCtrl *>(GetDlgItem(IDC_SPIN1));
-	switch(srcMode)
-	{
-		case SRCMODE_POLYPHASE:
-			m_CEditWFIRCutoff.EnableWindow(FALSE);
-			spinWFIRCutoff->EnableWindow(FALSE);
-			m_CbnWFIRType.EnableWindow(FALSE);
-			break;
-		case SRCMODE_FIRFILTER:
-			m_CEditWFIRCutoff.EnableWindow(TRUE);
-			spinWFIRCutoff->EnableWindow(TRUE);
-			m_CbnWFIRType.EnableWindow(TRUE);
-			break;
-		default:
-			m_CEditWFIRCutoff.EnableWindow(FALSE);
-			spinWFIRCutoff->EnableWindow(FALSE);
-			m_CbnWFIRType.EnableWindow(FALSE);
-			break;
-	}
 	OnSettingsChanged();
 }
 
@@ -1162,27 +1094,6 @@
 		TrackerSettings::Instance().ResamplerMode = static_cast<ResamplingMode>(m_CbnResampling.GetItemData(m_CbnResampling.GetCurSel()));
 	}
 
-	// resampler bandwidth
-	{
-		CString s;
-		m_CEditWFIRCutoff.GetWindowText(s);
-		if(s != "")
-		{
-			int newCutoff = ConvertStrTo<int>(s);
-			Limit(newCutoff, 0, 100);
-			TrackerSettings::Instance().ResamplerCutoffPercent = newCutoff;
-		}
-		{
-			s.Format(_T("%d"), TrackerSettings::Instance().ResamplerCutoffPercent.Get());
-			m_CEditWFIRCutoff.SetWindowText(s);
-		}
-	}
-
-	// resampler filter window
-	{
-		TrackerSettings::Instance().ResamplerSubMode = (uint8)m_CbnWFIRType.GetCurSel();
-	}
-
 	// Amiga Resampler
 	TrackerSettings::Instance().ResamplerEmulateAmiga = IsDlgButtonChecked(IDC_CHECK1) != BST_UNCHECKED;
 
Index: mptrack/Mpdlgs.h
===================================================================
--- mptrack/Mpdlgs.h	(revision 9920)
+++ mptrack/Mpdlgs.h	(working copy)
@@ -88,8 +88,6 @@
 protected:
 
 	CComboBox m_CbnResampling;
-	CEdit m_CEditWFIRCutoff;
-	CComboBox m_CbnWFIRType;
 
 	CEdit m_CEditRampUp;
 	CEdit m_CEditRampDown;
Index: mptrack/Mptrack.cpp
===================================================================
--- mptrack/Mptrack.cpp	(revision 9920)
+++ mptrack/Mptrack.cpp	(working copy)
@@ -1995,24 +1995,39 @@
 }
 
 
-const TCHAR *CTrackApp::GetResamplingModeName(ResamplingMode mode, bool addTaps)
+CString CTrackApp::GetResamplingModeName(ResamplingMode mode, int length, bool addTaps)
 {
+	CString result;
 	switch(mode)
 	{
 	case SRCMODE_NEAREST:
-		return addTaps ? _T("No Interpolation (1 tap)") : _T("No Interpolation");
+		result = (length > 1) ? _T("No Interpolation") : _T("None") ;
+		break;
 	case SRCMODE_LINEAR:
-		return addTaps ? _T("Linear (2 tap)") : _T("Linear");
+		result = _T("Linear");
+		break;
 	case SRCMODE_SPLINE:
-		return addTaps ? _T("Cubic Spline (4 tap)") :  _T("Cubic Spline");
-	case SRCMODE_POLYPHASE:
-		return addTaps ? _T("Polyphase (8 tap)") : _T("Polyphase");
-	case SRCMODE_FIRFILTER:
-		return addTaps ? _T("XMMS-ModPlug (8 tap)") : _T("XMMS-ModPlug");
+		result = (length > 1) ? _T("Cubic Spline") : _T("Cubic");
+		break;
+	case SRCMODE_SINC8:
+		result = _T("Sinc");
+		break;
+	case SRCMODE_SINC8LP:
+		result = _T("Sinc");
+		break;
 	default:
 		MPT_ASSERT_NOTREACHED();
+		break;
 	}
-	return _T("");
+	if(Resampling::HasAA(mode))
+	{
+		result += (length > 1) ? _T(" w/ Low-Pass") : _T(" w/ LP");
+	}
+	if(addTaps)
+	{
+		result += mpt::cformat(_T(" (%1 tap%2)"))(Resampling::Length(mode), (Resampling::Length(mode) != 1) ? CString(_T("s")) : CString(_T("")));
+	}
+	return result;
 }
 
 
Index: mptrack/Mptrack.h
===================================================================
--- mptrack/Mptrack.h	(revision 9920)
+++ mptrack/Mptrack.h	(working copy)
@@ -268,7 +268,7 @@
 
 public:
 	// Get name of resampling mode. addTaps = true also adds the number of taps the filter uses.
-	static const TCHAR *GetResamplingModeName(ResamplingMode mode, bool addTaps);
+	static CString GetResamplingModeName(ResamplingMode mode, int length, bool addTaps);
 
 // Overrides
 public:
Index: mptrack/mptrack.rc
===================================================================
--- mptrack/mptrack.rc	(revision 9920)
+++ mptrack/mptrack.rc	(working copy)
@@ -1981,15 +1981,9 @@
 BEGIN
     GROUPBOX        "Resampling",IDC_STATIC,6,6,276,48
     LTEXT           "&Filter:",IDC_STATIC,12,18,24,12,SS_CENTERIMAGE
-    COMBOBOX        IDC_COMBO_FILTER,54,18,96,56,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
-    LTEXT           "&Window:",IDC_STATIC,156,18,30,12,SS_CENTERIMAGE
-    COMBOBOX        IDC_COMBO_FILTERWINDOW,192,18,84,56,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
-    LTEXT           "&Bandwidth:",IDC_STATIC,12,36,42,12,SS_CENTERIMAGE
-    EDITTEXT        IDC_WFIRCUTOFF,54,36,30,12,ES_RIGHT | ES_AUTOHSCROLL | ES_NUMBER
-    CONTROL         "",IDC_SPIN1,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_NOTHOUSANDS,71,31,11,14
-    LTEXT           "%",IDC_STATIC,90,36,24,12,SS_CENTERIMAGE
+    COMBOBOX        IDC_COMBO_FILTER,36,18,102,56,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
     CONTROL         "Use &Amiga resampler for Amiga modules",IDC_CHECK1,
-                    "Button",BS_AUTOCHECKBOX | WS_TABSTOP,126,36,150,12
+                    "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,36,144,12
     GROUPBOX        "Volume Ramping",IDC_STATIC,6,60,276,48
     EDITTEXT        IDC_RAMPING_IN,12,72,36,12,ES_RIGHT | ES_AUTOHSCROLL | ES_NUMBER
     CONTROL         "",IDC_SPIN2,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_NOTHOUSANDS,42,66,11,14
Index: mptrack/resource.h
===================================================================
--- mptrack/resource.h	(revision 9920)
+++ mptrack/resource.h	(working copy)
@@ -684,8 +684,6 @@
 #define IDC_COMMAND_LIST                2129
 #define IDC_STATIC8                     2200
 #define IDC_PATINSTROPLUGGUI            2201
-#define IDC_WFIRCUTOFF                  2202
-#define IDC_WFIRTYPE                    2203
 #define IDC_RAMPING_IN                  2204
 #define IDC_PLAYEROPTIONS               2205
 #define IDC_RAMPING_OUT                 2205
Index: mptrack/SampleEditorDialogs.cpp
===================================================================
--- mptrack/SampleEditorDialogs.cpp	(revision 9920)
+++ mptrack/SampleEditorDialogs.cpp	(working copy)
@@ -530,12 +530,12 @@
 
 	CComboBox *cbnResampling = static_cast<CComboBox *>(GetDlgItem(IDC_COMBO_FILTER));
 	cbnResampling->SetRedraw(FALSE);
-	const ResamplingMode resamplingModes[] = { SRCMODE_NEAREST, SRCMODE_LINEAR, SRCMODE_SPLINE, SRCMODE_POLYPHASE, SRCMODE_FIRFILTER, SRCMODE_DEFAULT };
+	const auto resamplingModes = Resampling::AllModesWithDefault();
 	for(auto mode : resamplingModes)
 	{
-		const TCHAR *desc = _T("r8brain (High Quality)");
+		CString desc = _T("r8brain (High Quality)");
 		if(mode != SRCMODE_DEFAULT)
-			desc = CTrackApp::GetResamplingModeName(mode, false);
+			desc = CTrackApp::GetResamplingModeName(mode, 1, true);
 
 		int index = cbnResampling->AddString(desc);
 		cbnResampling->SetItemData(index, mode);
Index: mptrack/TrackerSettings.cpp
===================================================================
--- mptrack/TrackerSettings.cpp	(revision 9920)
+++ mptrack/TrackerSettings.cpp	(working copy)
@@ -76,29 +76,6 @@
 }
 
 
-static ResamplingMode GetDefaultResamplerMode()
-{
-	ResamplingMode result = CResamplerSettings().SrcMode;
-#ifdef ENABLE_ASM
-	// rough heuristic to select less cpu consuming defaults for old CPUs
-	if(GetRealProcSupport() & PROCSUPPORT_SSE)
-	{
-		result = SRCMODE_POLYPHASE;
-	} else if(GetRealProcSupport() & PROCSUPPORT_MMX)
-	{
-		result = SRCMODE_SPLINE;
-	} else
-	{
-		result = SRCMODE_LINEAR;
-	}
-#else
-	// just use a sane default
-	result = CResamplerSettings().SrcMode;
-#endif
-	return result;
-}
-
-
 static uint32 GetDefaultPatternSetup()
 {
 	return PATTERN_PLAYNEWNOTE | PATTERN_EFFECTHILIGHT
@@ -246,7 +223,7 @@
 	, MixerStereoSeparation(conf, MPT_USTRING("Sound Settings"), MPT_USTRING("StereoSeparation"), MixerSettings().m_nStereoSeparation)
 	, MixerVolumeRampUpMicroseconds(conf, MPT_USTRING("Sound Settings"), MPT_USTRING("VolumeRampUpMicroseconds"), MixerSettings().GetVolumeRampUpMicroseconds())
 	, MixerVolumeRampDownMicroseconds(conf, MPT_USTRING("Sound Settings"), MPT_USTRING("VolumeRampDownMicroseconds"), MixerSettings().GetVolumeRampDownMicroseconds())
-	, ResamplerMode(conf, MPT_USTRING("Sound Settings"), MPT_USTRING("SrcMode"), GetDefaultResamplerMode())
+	, ResamplerMode(conf, MPT_USTRING("Sound Settings"), MPT_USTRING("SrcMode"), CResamplerSettings().SrcMode)
 	, ResamplerSubMode(conf, MPT_USTRING("Sound Settings"), MPT_USTRING("XMMSModplugResamplerWFIRType"), CResamplerSettings().gbWFIRType)
 	, ResamplerCutoffPercent(conf, MPT_USTRING("Sound Settings"), MPT_USTRING("ResamplerWFIRCutoff"), Util::Round<int32>(CResamplerSettings().gdWFIRCutoff * 100.0))
 	, ResamplerEmulateAmiga(conf, MPT_USTRING("Sound Settings"), MPT_USTRING("ResamplerEmulateAmiga"), false)
@@ -548,6 +525,13 @@
 		m_SoundDeviceSettingsDefaults.UseHardwareTiming = m_SoundDeviceUseHardwareTiming;
 		m_SoundDeviceSettingsUseOldDefaults = true;
 	}
+	if(storedVersion < MAKE_VERSION_NUMERIC(1,28,00,15))
+	{
+		// reset this setting to the default when updating,
+		// because we do not provide a GUI any more,
+		// and in general, it should not get changed anyway
+		ResamplerCutoffPercent = Util::Round<int32>(CResamplerSettings().gdWFIRCutoff * 100.0);
+	}
 	if(storedVersion < MAKE_VERSION_NUMERIC(1,25,00,04))
 	{
 		m_SoundDeviceDirectSoundOldDefaultIdentifier = true;
@@ -680,7 +664,7 @@
 	}
 
 	// Sanitize resampling mode for sample editor
-	if(!IsKnownResamplingMode(sampleEditorDefaultResampler) && sampleEditorDefaultResampler != SRCMODE_DEFAULT)
+	if(!Resampling::IsKnownMode(sampleEditorDefaultResampler) && sampleEditorDefaultResampler != SRCMODE_DEFAULT)
 	{
 		sampleEditorDefaultResampler = SRCMODE_DEFAULT;
 	}
Index: soundlib/Load_it.cpp
===================================================================
--- soundlib/Load_it.cpp	(revision 9920)
+++ soundlib/Load_it.cpp	(working copy)
@@ -2358,7 +2358,7 @@
 			case MagicBE("RP.."): if(GetType() != MOD_TYPE_XM) { ORDERINDEX restartPos; ReadField(chunk, size, restartPos); Order().SetRestartPos(restartPos); } break;
 			case MagicLE("RSMP"):
 				ReadFieldCast(chunk, size, m_nResampling);
-				if(!IsKnownResamplingMode(m_nResampling)) m_nResampling = SRCMODE_DEFAULT;
+				if(!Resampling::IsKnownMode(m_nResampling)) m_nResampling = SRCMODE_DEFAULT;
 				break;
 #ifdef MODPLUG_TRACKER
 			case MagicBE("MIMA"): GetMIDIMapper().Deserialize(chunk); break;
Index: soundlib/MixFuncTable.cpp
===================================================================
--- soundlib/MixFuncTable.cpp	(revision 9920)
+++ soundlib/MixFuncTable.cpp	(working copy)
@@ -80,8 +80,8 @@
 	case SRCMODE_NEAREST:   return ndxNoInterpolation;
 	case SRCMODE_LINEAR:    return ndxLinear;
 	case SRCMODE_SPLINE:    return ndxFastSinc;
-	case SRCMODE_POLYPHASE: return ndxKaiser;
-	case SRCMODE_FIRFILTER: return ndxFIRFilter;
+	case SRCMODE_SINC8LP:   return ndxKaiser;
+	case SRCMODE_SINC8:     return ndxFIRFilter;
 	case SRCMODE_AMIGA:     return ndxAmigaBlep;
 	default:                MPT_ASSERT_NOTREACHED();
 	}
Index: soundlib/Resampler.h
===================================================================
--- soundlib/Resampler.h	(revision 9920)
+++ soundlib/Resampler.h	(working copy)
@@ -59,12 +59,12 @@
 	uint8 gbWFIRType;
 	bool emulateAmiga;
 public:
-	CResamplerSettings()
+	MPT_CONSTEXPR11_FUN CResamplerSettings()
+		: SrcMode(Resampling::Default())
+		, gdWFIRCutoff(0.97)
+		, gbWFIRType(WFIR_KAISER4T)
+		, emulateAmiga(false)
 	{
-		SrcMode = SRCMODE_POLYPHASE;
-		gdWFIRCutoff = 0.97;
-		gbWFIRType = WFIR_KAISER4T;
-		emulateAmiga = false;
 	}
 	bool operator == (const CResamplerSettings &cmp) const
 	{
@@ -125,8 +125,6 @@
 	{
 		InitializeTablesFromScratch(false);
 	}
-	~CResampler() {}
-	bool IsHQ() const { return m_Settings.SrcMode >= SRCMODE_SPLINE && m_Settings.SrcMode < SRCMODE_DEFAULT; }
 private:
 	void InitFloatmixerTables();
 	void InitializeTablesFromScratch(bool force=false);
Index: soundlib/Snd_defs.h
===================================================================
--- soundlib/Snd_defs.h	(revision 9920)
+++ soundlib/Snd_defs.h	(working copy)
@@ -290,22 +290,55 @@
 {
 	// ATTENTION: Do not change ANY of these values, as they get written out to files in per instrument interpolation settings
 	// and old files have these exact values in them which should not change meaning.
-	SRCMODE_NEAREST   = 0,
-	SRCMODE_LINEAR    = 1,
-	SRCMODE_SPLINE    = 2,
-	SRCMODE_POLYPHASE = 3,
-	SRCMODE_FIRFILTER = 4,
-	SRCMODE_DEFAULT   = 5,
+	SRCMODE_NEAREST   = 0,  // 1 tap, no AA
+	SRCMODE_LINEAR    = 1,  // 2 tap, no AA
+	SRCMODE_SPLINE    = 2,  // 4 tap, no AA
+	SRCMODE_SINC8     = 4,  // 8 tap, no AA   (yes, index 4) (XMMS-ModPlug)
+	SRCMODE_SINC8LP   = 3,  // 8 tap, with AA (yes, index 3) (Ericus-Polyphase)
 
-	SRCMODE_AMIGA = 0xFF,	// Not explicitely user-selectable
+	SRCMODE_DEFAULT   = 5,  // only used for instrument settings, not used inside the mixer
+
+	SRCMODE_AMIGA  = 0xFF,  // Not explicitely user-selectable
 };
 
-static inline bool IsKnownResamplingMode(int mode)
+namespace Resampling
 {
-	return (mode >= 0) && (mode < SRCMODE_DEFAULT);
+
+static inline std::array<ResamplingMode, 5> AllModes() { return { SRCMODE_NEAREST, SRCMODE_LINEAR, SRCMODE_SPLINE, SRCMODE_SINC8, SRCMODE_SINC8LP }; }
+
+static inline std::array<ResamplingMode, 6> AllModesWithDefault() { return { SRCMODE_NEAREST, SRCMODE_LINEAR, SRCMODE_SPLINE, SRCMODE_SINC8, SRCMODE_SINC8LP, SRCMODE_DEFAULT }; }
+
+static MPT_CONSTEXPR11_FUN ResamplingMode Default() { return SRCMODE_SINC8LP; }
+
+static MPT_CONSTEXPR11_FUN bool IsKnownMode(int mode) { return (mode >= 0) && (mode < SRCMODE_DEFAULT); }
+
+static MPT_CONSTEXPR11_FUN ResamplingMode ToKnownMode(int mode)
+{
+	return Resampling::IsKnownMode(mode) ? static_cast<ResamplingMode>(mode)
+		: (mode == SRCMODE_AMIGA) ? SRCMODE_LINEAR
+		: Resampling::Default();
 }
 
+static MPT_CONSTEXPR11_FUN int Length(ResamplingMode mode)
+{
+	return mode == SRCMODE_NEAREST ? 1
+		: mode == SRCMODE_LINEAR ? 2
+		: mode == SRCMODE_SPLINE ? 4
+		: mode == SRCMODE_SINC8 ? 8
+		: mode == SRCMODE_SINC8LP ? 8
+		: 0;
+}
 
+static MPT_CONSTEXPR11_FUN bool HasAA(ResamplingMode mode) { return (mode == SRCMODE_SINC8LP); }
+
+static MPT_CONSTEXPR11_FUN ResamplingMode AddAA(ResamplingMode mode) { return (mode == SRCMODE_SINC8) ? SRCMODE_SINC8LP : mode; }
+
+static MPT_CONSTEXPR11_FUN ResamplingMode RemoveAA(ResamplingMode mode) { return (mode == SRCMODE_SINC8LP) ? SRCMODE_SINC8 : mode; }
+
+}
+
+
+
 // Release node defines
 #define ENV_RELEASE_NODE_UNSET	0xFF
 #define NOT_YET_RELEASED		(-1)
Index: soundlib/Sndmix.cpp
===================================================================
--- soundlib/Sndmix.cpp	(revision 9920)
+++ soundlib/Sndmix.cpp	(working copy)
@@ -2330,11 +2330,11 @@
 			//if (pChn->nNewRightVol > 0xFFFF) pChn->nNewRightVol = 0xFFFF;
 			//if (pChn->nNewLeftVol > 0xFFFF) pChn->nNewLeftVol = 0xFFFF;
 
-			if(pChn->pModInstrument && IsKnownResamplingMode(pChn->pModInstrument->nResampling))
+			if(pChn->pModInstrument && Resampling::IsKnownMode(pChn->pModInstrument->nResampling))
 			{
 				// For defined resampling modes, use per-instrument resampling mode if set
 				pChn->resamplingMode = static_cast<uint8>(pChn->pModInstrument->nResampling);
-			} else if(IsKnownResamplingMode(m_nResampling))
+			} else if(Resampling::IsKnownMode(m_nResampling))
 			{
 				pChn->resamplingMode = static_cast<uint8>(m_nResampling);
 			} else if(m_SongFlags[SONG_ISAMIGA] && m_Resampler.m_Settings.emulateAmiga)
Index: soundlib/Tables.cpp
===================================================================
--- soundlib/Tables.cpp	(revision 9920)
+++ soundlib/Tables.cpp	(working copy)
@@ -853,42 +853,7 @@
 	}
 }
 
-#if 0
 
-// this code is currently unused
-
-static double GetSpline(double x, double c0, double c1, double c2, double c3)
-{
-	double Xo = c1;
-	double Xa = c0 - Xo;
-	double Xb = c2 - Xo;
-	double Ux = (Xb-Xa)/2;
-	double Vx = (c3 - Xo)/2;
-	double a = Vx+Ux-2*Xb;
-	double b = 3*Xb-2*Ux-Vx;
-	return (((a*x+b)*x)+Ux)*x+Xo;
-}
-
-
-static void getdownsample2x(short int *psinc)
-{
-	for (int i=0; i<SINC_PHASES; i++)
-	{
-		double x = (double)i * (double)(0.5/SINC_PHASES);
-		psinc[i*8+7] = (short int)(GetSpline(x,     0, 0, 0, 1) * 8192);
-		psinc[i*8+6] = (short int)(GetSpline(x+0.5, 0, 0, 0, 1) * 8192);
-		psinc[i*8+5] = (short int)(GetSpline(x,     0, 0, 1, 0) * 8192);
-		psinc[i*8+4] = (short int)(GetSpline(x+0.5, 0, 0, 1, 0) * 8192);
-		psinc[i*8+3] = (short int)(GetSpline(x,     0, 1, 0, 0) * 8192);
-		psinc[i*8+2] = (short int)(GetSpline(x+0.5, 0, 1, 0, 0) * 8192);
-		psinc[i*8+1] = (short int)(GetSpline(x,     1, 0, 0, 0) * 8192);
-		psinc[i*8+0] = (short int)(GetSpline(x+0.5, 1, 0, 0, 0) * 8192);
-	}
-}
-
-#endif
-
-
 #ifdef MODPLUG_TRACKER
 bool CResampler::StaticTablesInitialized = false;
 SINC_TYPE CResampler::gKaiserSinc[SINC_PHASES*8];     // Upsampling
@@ -938,12 +903,8 @@
 		InitFloatmixerTables();
 
 		getsinc(gKaiserSinc, 9.6377, 0.97);
-		//ericus' downsampling improvement.
-		//getsinc(gDownsample13x, 8.5, 3.0/4.0);
-		//getdownsample2x(gDownsample2x);
 		getsinc(gDownsample13x, 8.5, 0.5);
 		getsinc(gDownsample2x, 2.7625, 0.425);
-		//end ericus' downsampling improvement.
 
 		#ifdef MODPLUG_TRACKER
 			StaticTablesInitialized = true;
Index: soundlib/WindowedFIR.h
===================================================================
--- soundlib/WindowedFIR.h	(revision 9920)
+++ soundlib/WindowedFIR.h	(working copy)
@@ -48,25 +48,20 @@
 #define WFIR_LOG2WIDTH		3
 #define WFIR_WIDTH			(1L<<WFIR_LOG2WIDTH)
 // cutoff (1.0 == pi/2)
-//float WFIR_CUTOFF			= 0.5f;//0.75f;	//0.90f;
 // wfir type
 enum WFIRType
 {
-	WFIR_HANN			= 0,
-	WFIR_HAMMING		= 1,
-	WFIR_BLACKMANEXACT	= 2,
-	WFIR_BLACKMAN3T61	= 3,
-	WFIR_BLACKMAN3T67	= 4,
-	WFIR_BLACKMAN4T92	= 5,
-	WFIR_BLACKMAN4T74	= 6,
-	WFIR_KAISER4T		= 7,
+	WFIR_HANN          = 0,  // Hann
+	WFIR_HAMMING       = 1,  // Hamming
+	WFIR_BLACKMANEXACT = 2,  // Blackman Exact
+	WFIR_BLACKMAN3T61  = 3,  // Blackman 3-Tap 61
+	WFIR_BLACKMAN3T67  = 4,  // Blackman 3-Tap 67
+	WFIR_BLACKMAN4T92  = 5,  // Blackman-Harris
+	WFIR_BLACKMAN4T74  = 6,  // Blackman 4-Tap 74
+	WFIR_KAISER4T      = 7,  // Kaiser a=7.5
 };
-//int WFIR_TYPE				= WFIR_KAISER4T;//WFIR_BLACKMANEXACT;
-//int WFIR_TYPE				= TrackerSettings::Instance().gbWFIRType;
 // wfir help
-#ifndef M_zPI
 #define M_zPI				3.1415926535897932384626433832795
-#endif
 #define M_zEPS				1e-8
 
 
Index: test/test.cpp
===================================================================
--- test/test.cpp	(revision 9920)
+++ test/test.cpp	(working copy)
@@ -2716,7 +2716,7 @@
 	VERIFY_EQUAL_NONCONT(pIns->nPPC, NOTE_MIDDLEC - 1);
 
 	VERIFY_EQUAL_NONCONT(pIns->nVolRampUp, 1200);
-	VERIFY_EQUAL_NONCONT(pIns->nResampling, (unsigned)SRCMODE_POLYPHASE);
+	VERIFY_EQUAL_NONCONT(pIns->nResampling, (unsigned)SRCMODE_SINC8LP);
 
 	VERIFY_EQUAL_NONCONT(pIns->IsCutoffEnabled(), false);
 	VERIFY_EQUAL_NONCONT(pIns->GetCutoff(), 0);
@@ -2846,7 +2846,7 @@
 	VERIFY_EQUAL_NONCONT(sndFile.m_nDefaultRowsPerBeat, 6);
 	VERIFY_EQUAL_NONCONT(sndFile.m_nDefaultRowsPerMeasure, 12);
 	VERIFY_EQUAL_NONCONT(sndFile.m_dwCreatedWithVersion, MAKE_VERSION_NUMERIC(1, 19, 02, 05));
-	VERIFY_EQUAL_NONCONT(sndFile.m_nResampling, SRCMODE_POLYPHASE);
+	VERIFY_EQUAL_NONCONT(sndFile.m_nResampling, SRCMODE_SINC8LP);
 	VERIFY_EQUAL_NONCONT(sndFile.m_songArtist, MPT_USTRING("Tester"));
 	VERIFY_EQUAL_NONCONT(sndFile.m_tempoSwing.size(), 6);
 	VERIFY_EQUAL_NONCONT(sndFile.m_tempoSwing[0], 29360125);
@@ -3009,7 +3009,7 @@
 		VERIFY_EQUAL_NONCONT(pIns->nPPC, (NOTE_MIDDLEC - NOTE_MIN) + 6);	// F#5
 
 		VERIFY_EQUAL_NONCONT(pIns->nVolRampUp, 1200);
-		VERIFY_EQUAL_NONCONT(pIns->nResampling, (unsigned)SRCMODE_POLYPHASE);
+		VERIFY_EQUAL_NONCONT(pIns->nResampling, (unsigned)SRCMODE_SINC8LP);
 
 		VERIFY_EQUAL_NONCONT(pIns->IsCutoffEnabled(), true);
 		VERIFY_EQUAL_NONCONT(pIns->GetCutoff(), 0x32);
resampler-cleanup-v1.patch (28,622 bytes)   
Saga Musix

Saga Musix

2018-03-12 16:13

administrator   ~0003482

Also, on the topic of "why not add more interpolation types": Based on its mathematical properties, sinc resampling is ideal (but the resulting quality of course depends on the number of taps), so there really is no practical reason to implement other filter types. In the best case, you won't hear a difference, and in the worst case they sound worse.

While at it, we should also remove the selection of the windowing function and the filter bandwidth selection. These really serve no purpose other than confuse users.

I agree about the windowing function, but I think especially when taking higher mixing rates > 48 kHz into account, it makes sense to keep this configurable. On the other hand, most people do not understand what this option really does and increase the bandwidth to its maximum value because it sounds "brighter" (without realizing that it also causes more aliasing).

manx

manx

2018-03-21 11:31

administrator   ~0003487

Updated patch, no functional changes.

resampler-cleanup-v2.patch (28,332 bytes)   
Index: libopenmpt/libopenmpt_impl.cpp
===================================================================
--- libopenmpt/libopenmpt_impl.cpp	(revision 9968)
+++ libopenmpt/libopenmpt_impl.cpp	(working copy)
@@ -316,13 +316,13 @@
 }
 
 static ResamplingMode filterlength_to_resamplingmode(std::int32_t length) {
-	ResamplingMode result = SRCMODE_POLYPHASE;
+	ResamplingMode result = SRCMODE_SINC8LP;
 	if ( length == 0 ) {
-		result = SRCMODE_POLYPHASE;
+		result = SRCMODE_SINC8LP;
 	} else if ( length >= 8 ) {
-		result = SRCMODE_POLYPHASE;
+		result = SRCMODE_SINC8LP;
 	} else if ( length >= 3 ) {
-		result = SRCMODE_SPLINE;
+		result = SRCMODE_CUBIC;
 	} else if ( length >= 2 ) {
 		result = SRCMODE_LINEAR;
 	} else if ( length >= 1 ) {
@@ -340,11 +340,11 @@
 	case SRCMODE_LINEAR:
 		return 2;
 		break;
-	case SRCMODE_SPLINE:
+	case SRCMODE_CUBIC:
 		return 4;
 		break;
-	case SRCMODE_POLYPHASE:
-	case SRCMODE_FIRFILTER:
+	case SRCMODE_SINC8:
+	case SRCMODE_SINC8LP:
 	case SRCMODE_DEFAULT:
 		return 8;
 	default:
Index: mptrack/Ctrl_gen.cpp
===================================================================
--- mptrack/Ctrl_gen.cpp	(revision 9968)
+++ mptrack/Ctrl_gen.cpp	(working copy)
@@ -202,21 +202,21 @@
 	FlagSet<HintType> hintType = hint.GetType();
 	const bool updateAll = hintType[HINT_MODTYPE];
 
-	const ResamplingMode resamplingModes[] = { SRCMODE_NEAREST, SRCMODE_LINEAR, SRCMODE_SPLINE, SRCMODE_POLYPHASE, SRCMODE_FIRFILTER };
+	const auto resamplingModes = Resampling::AllModes();
 
 	if (hintType == HINT_MPTOPTIONS || updateAll)
 	{
-		const TCHAR *defaultResampler;
+		CString defaultResampler;
 		if(m_sndFile.m_SongFlags[SONG_ISAMIGA] && TrackerSettings::Instance().ResamplerEmulateAmiga)
 			defaultResampler = _T("Amiga Resampler");
 		else
-			defaultResampler = CTrackApp::GetResamplingModeName(TrackerSettings::Instance().ResamplerMode, false);
+			defaultResampler = CTrackApp::GetResamplingModeName(TrackerSettings::Instance().ResamplerMode, 1, false);
 
 		m_CbnResampling.ResetContent();
-		m_CbnResampling.SetItemData(m_CbnResampling.AddString(_T("Default (") + CString(defaultResampler) + _T(")")), SRCMODE_DEFAULT);
+		m_CbnResampling.SetItemData(m_CbnResampling.AddString(_T("Default (") + defaultResampler + _T(")")), SRCMODE_DEFAULT);
 		for(auto mode : resamplingModes)
 		{
-			m_CbnResampling.SetItemData(m_CbnResampling.AddString(CTrackApp::GetResamplingModeName(mode, false)), mode);
+			m_CbnResampling.SetItemData(m_CbnResampling.AddString(CTrackApp::GetResamplingModeName(mode, 2, true)), mode);
 		}
 		m_CbnResampling.Invalidate(FALSE);
 	}
@@ -312,12 +312,13 @@
 
 	if(updateAll || hintType == HINT_MPTOPTIONS || (hint.GetCategory() == HINTCAT_GENERAL && hintType[HINT_MODGENERAL]))
 	{
+
 		int srcMode = 0;
-		for(int i = 0; i < CountOf(resamplingModes); i++)
+		for(int i = 0; i < m_CbnResampling.GetCount(); ++i)
 		{
-			if(m_sndFile.m_nResampling == resamplingModes[i]) srcMode = i + 1;
+			if(m_sndFile.m_nResampling == static_cast<int>(m_CbnResampling.GetItemData(i)))
+				m_CbnResampling.SetCurSel(i);
 		}
-		m_CbnResampling.SetCurSel(srcMode);
 	}
 
 	CheckDlgButton(IDC_CHECK_LOOPSONG, (TrackerSettings::Instance().gbLoopSong) ? TRUE : FALSE);
Index: mptrack/Ctrl_ins.cpp
===================================================================
--- mptrack/Ctrl_ins.cpp	(revision 9968)
+++ mptrack/Ctrl_ins.cpp	(working copy)
@@ -995,12 +995,12 @@
 	m_EditPWD.SubclassDlgItem(IDC_PITCHWHEELDEPTH, this);
 	m_EditPWD.AllowFractions(false);
 
+	const auto resamplingModes = Resampling::AllModes();
 	m_CbnResampling.SetItemData(m_CbnResampling.AddString(_T("Default")), SRCMODE_DEFAULT);
-	m_CbnResampling.SetItemData(m_CbnResampling.AddString(_T("None")), SRCMODE_NEAREST);
-	m_CbnResampling.SetItemData(m_CbnResampling.AddString(_T("Linear")), SRCMODE_LINEAR);
-	m_CbnResampling.SetItemData(m_CbnResampling.AddString(_T("Spline")), SRCMODE_SPLINE);
-	m_CbnResampling.SetItemData(m_CbnResampling.AddString(_T("Polyphase")), SRCMODE_POLYPHASE);
-	m_CbnResampling.SetItemData(m_CbnResampling.AddString(_T("XMMS")), SRCMODE_FIRFILTER);
+	for(auto mode : resamplingModes)
+	{
+		m_CbnResampling.SetItemData(m_CbnResampling.AddString(CTrackApp::GetResamplingModeName(mode, 1, false)), mode);
+	}
 
 	m_CbnFilterMode.SetItemData(m_CbnFilterMode.AddString(_T("Channel default")), FLTMODE_UNCHANGED);
 	m_CbnFilterMode.SetItemData(m_CbnFilterMode.AddString(_T("Force lowpass")), FLTMODE_LOWPASS);
Index: mptrack/Mpdlgs.cpp
===================================================================
--- mptrack/Mpdlgs.cpp	(revision 9968)
+++ mptrack/Mpdlgs.cpp	(working copy)
@@ -928,9 +928,7 @@
 	ON_WM_HSCROLL()
 	ON_WM_VSCROLL()
 	ON_CBN_SELCHANGE(IDC_COMBO_FILTER,			OnResamplerChanged)
-	ON_CBN_SELCHANGE(IDC_COMBO_FILTERWINDOW,	OnSettingsChanged)
 	ON_CBN_SELCHANGE(IDC_COMBO_POLYPHONY,		OnSettingsChanged)
-	ON_EN_UPDATE(IDC_WFIRCUTOFF,				OnSettingsChanged)
 	ON_EN_UPDATE(IDC_RAMPING_IN,				OnRampingChanged)
 	ON_EN_UPDATE(IDC_RAMPING_OUT,				OnRampingChanged)
 	ON_COMMAND(IDC_CHECK_SOFTPAN,				OnSettingsChanged)
@@ -943,8 +941,6 @@
 	CPropertyPage::DoDataExchange(pDX);
 	//{{AFX_DATA_MAP(COptionsSoundcard)
 	DDX_Control(pDX, IDC_COMBO_FILTER, m_CbnResampling);
-	DDX_Control(pDX, IDC_WFIRCUTOFF, m_CEditWFIRCutoff);
-	DDX_Control(pDX, IDC_COMBO_FILTERWINDOW, m_CbnWFIRType);
 	DDX_Control(pDX, IDC_RAMPING_IN, m_CEditRampUp);
 	DDX_Control(pDX, IDC_RAMPING_OUT, m_CEditRampDown);
 	DDX_Control(pDX, IDC_EDIT_VOLRAMP_SAMPLES_UP, m_CInfoRampUp);
@@ -963,26 +959,18 @@
 
 	// Resampling type
 	{
-		for(auto mode : { SRCMODE_NEAREST, SRCMODE_LINEAR, SRCMODE_SPLINE, SRCMODE_POLYPHASE, SRCMODE_FIRFILTER })
+		const auto resamplingModes = Resampling::AllModes();
+		for(auto mode : resamplingModes)
 		{
-			int index = m_CbnResampling.AddString(CTrackApp::GetResamplingModeName(mode, true));
+			int index = m_CbnResampling.AddString(CTrackApp::GetResamplingModeName(mode, 2, true));
 			m_CbnResampling.SetItemData(index, mode);
 			if(TrackerSettings::Instance().ResamplerMode == mode)
+			{
 				m_CbnResampling.SetCurSel(index);
+			}
 		}
 	}
 
-	// Resampler bandwidth
-	{
-		m_CEditWFIRCutoff.SetWindowText(mpt::ToCString(mpt::ufmt::val(TrackerSettings::Instance().ResamplerCutoffPercent)));
-		static_cast<CSpinButtonCtrl *>(GetDlgItem(IDC_SPIN1))->SetRange32(1, 99);
-	}
-
-	// Resampler filter window
-	{
-		// done in OnResamplerChanged()
-	}
-
 	// Amiga Resampler
 	CheckDlgButton(IDC_CHECK1, TrackerSettings::Instance().ResamplerEmulateAmiga ? BST_CHECKED : BST_UNCHECKED);
 
@@ -1037,7 +1025,6 @@
 		m_SliderPreAmp.SetPos(n);
 	}
 
-	OnResamplerChanged();
 	m_initialized = true;
 
 	return TRUE;
@@ -1053,61 +1040,6 @@
 
 void COptionsMixer::OnResamplerChanged()
 {
-	ResamplingMode srcMode = static_cast<ResamplingMode>(m_CbnResampling.GetItemData(m_CbnResampling.GetCurSel()));
-	m_CbnWFIRType.ResetContent();
-	switch(srcMode)
-	{
-		case SRCMODE_FIRFILTER:
-			m_CbnWFIRType.AddString(_T("Hann"));
-			m_CbnWFIRType.AddString(_T("Hamming"));
-			m_CbnWFIRType.AddString(_T("Blackman Exact"));
-			m_CbnWFIRType.AddString(_T("Blackman 3 Tap 61"));
-			m_CbnWFIRType.AddString(_T("Blackman 3 Tap 67"));
-			m_CbnWFIRType.AddString(_T("Blackman Harris"));
-			m_CbnWFIRType.AddString(_T("Blackman 4 Tap 74"));
-			m_CbnWFIRType.AddString(_T("Kaiser a=7.5"));
-			break;
-		case SRCMODE_POLYPHASE:
-			m_CbnWFIRType.AddString(_T("Auto"));
-			m_CbnWFIRType.AddString(_T("Auto"));
-			m_CbnWFIRType.AddString(_T("Auto"));
-			m_CbnWFIRType.AddString(_T("Auto"));
-			m_CbnWFIRType.AddString(_T("Auto"));
-			m_CbnWFIRType.AddString(_T("Auto"));
-			m_CbnWFIRType.AddString(_T("Auto"));
-			m_CbnWFIRType.AddString(_T("Auto"));
-			break;
-		default:
-			m_CbnWFIRType.AddString(_T("none"));
-			m_CbnWFIRType.AddString(_T("none"));
-			m_CbnWFIRType.AddString(_T("none"));
-			m_CbnWFIRType.AddString(_T("none"));
-			m_CbnWFIRType.AddString(_T("none"));
-			m_CbnWFIRType.AddString(_T("none"));
-			m_CbnWFIRType.AddString(_T("none"));
-			m_CbnWFIRType.AddString(_T("none"));
-			break;
-	}
-	m_CbnWFIRType.SetCurSel(TrackerSettings::Instance().ResamplerSubMode);
-	CSpinButtonCtrl *spinWFIRCutoff = static_cast<CSpinButtonCtrl *>(GetDlgItem(IDC_SPIN1));
-	switch(srcMode)
-	{
-		case SRCMODE_POLYPHASE:
-			m_CEditWFIRCutoff.EnableWindow(FALSE);
-			spinWFIRCutoff->EnableWindow(FALSE);
-			m_CbnWFIRType.EnableWindow(FALSE);
-			break;
-		case SRCMODE_FIRFILTER:
-			m_CEditWFIRCutoff.EnableWindow(TRUE);
-			spinWFIRCutoff->EnableWindow(TRUE);
-			m_CbnWFIRType.EnableWindow(TRUE);
-			break;
-		default:
-			m_CEditWFIRCutoff.EnableWindow(FALSE);
-			spinWFIRCutoff->EnableWindow(FALSE);
-			m_CbnWFIRType.EnableWindow(FALSE);
-			break;
-	}
 	OnSettingsChanged();
 }
 
@@ -1162,27 +1094,6 @@
 		TrackerSettings::Instance().ResamplerMode = static_cast<ResamplingMode>(m_CbnResampling.GetItemData(m_CbnResampling.GetCurSel()));
 	}
 
-	// resampler bandwidth
-	{
-		CString s;
-		m_CEditWFIRCutoff.GetWindowText(s);
-		if(s != "")
-		{
-			int newCutoff = ConvertStrTo<int>(s);
-			Limit(newCutoff, 0, 100);
-			TrackerSettings::Instance().ResamplerCutoffPercent = newCutoff;
-		}
-		{
-			s.Format(_T("%d"), TrackerSettings::Instance().ResamplerCutoffPercent.Get());
-			m_CEditWFIRCutoff.SetWindowText(s);
-		}
-	}
-
-	// resampler filter window
-	{
-		TrackerSettings::Instance().ResamplerSubMode = (uint8)m_CbnWFIRType.GetCurSel();
-	}
-
 	// Amiga Resampler
 	TrackerSettings::Instance().ResamplerEmulateAmiga = IsDlgButtonChecked(IDC_CHECK1) != BST_UNCHECKED;
 
Index: mptrack/Mpdlgs.h
===================================================================
--- mptrack/Mpdlgs.h	(revision 9968)
+++ mptrack/Mpdlgs.h	(working copy)
@@ -88,8 +88,6 @@
 protected:
 
 	CComboBox m_CbnResampling;
-	CEdit m_CEditWFIRCutoff;
-	CComboBox m_CbnWFIRType;
 
 	CEdit m_CEditRampUp;
 	CEdit m_CEditRampDown;
Index: mptrack/Mptrack.cpp
===================================================================
--- mptrack/Mptrack.cpp	(revision 9968)
+++ mptrack/Mptrack.cpp	(working copy)
@@ -1995,24 +1995,39 @@
 }
 
 
-const TCHAR *CTrackApp::GetResamplingModeName(ResamplingMode mode, bool addTaps)
+CString CTrackApp::GetResamplingModeName(ResamplingMode mode, int length, bool addTaps)
 {
+	CString result;
 	switch(mode)
 	{
 	case SRCMODE_NEAREST:
-		return addTaps ? _T("No Interpolation (1 tap)") : _T("No Interpolation");
+		result = (length > 1) ? _T("No Interpolation") : _T("None") ;
+		break;
 	case SRCMODE_LINEAR:
-		return addTaps ? _T("Linear (2 tap)") : _T("Linear");
-	case SRCMODE_SPLINE:
-		return addTaps ? _T("Cubic Spline (4 tap)") :  _T("Cubic Spline");
-	case SRCMODE_POLYPHASE:
-		return addTaps ? _T("Polyphase (8 tap)") : _T("Polyphase");
-	case SRCMODE_FIRFILTER:
-		return addTaps ? _T("XMMS-ModPlug (8 tap)") : _T("XMMS-ModPlug");
+		result = _T("Linear");
+		break;
+	case SRCMODE_CUBIC:
+		result = (length > 1) ? _T("Cubic Spline") : _T("Cubic");
+		break;
+	case SRCMODE_SINC8:
+		result = _T("Sinc");
+		break;
+	case SRCMODE_SINC8LP:
+		result = _T("Sinc");
+		break;
 	default:
 		MPT_ASSERT_NOTREACHED();
+		break;
 	}
-	return _T("");
+	if(Resampling::HasAA(mode))
+	{
+		result += (length > 1) ? _T(" + Low-Pass") : _T(" + LP");
+	}
+	if(addTaps)
+	{
+		result += mpt::cformat(_T(" (%1 tap%2)"))(Resampling::Length(mode), (Resampling::Length(mode) != 1) ? CString(_T("s")) : CString(_T("")));
+	}
+	return result;
 }
 
 
Index: mptrack/Mptrack.h
===================================================================
--- mptrack/Mptrack.h	(revision 9968)
+++ mptrack/Mptrack.h	(working copy)
@@ -268,7 +268,7 @@
 
 public:
 	// Get name of resampling mode. addTaps = true also adds the number of taps the filter uses.
-	static const TCHAR *GetResamplingModeName(ResamplingMode mode, bool addTaps);
+	static CString GetResamplingModeName(ResamplingMode mode, int length, bool addTaps);
 
 // Overrides
 public:
Index: mptrack/mptrack.rc
===================================================================
--- mptrack/mptrack.rc	(revision 9968)
+++ mptrack/mptrack.rc	(working copy)
@@ -1981,15 +1981,9 @@
 BEGIN
     GROUPBOX        "Resampling",IDC_STATIC,6,6,276,48
     LTEXT           "&Filter:",IDC_STATIC,12,18,24,12,SS_CENTERIMAGE
-    COMBOBOX        IDC_COMBO_FILTER,54,18,96,56,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
-    LTEXT           "&Window:",IDC_STATIC,156,18,30,12,SS_CENTERIMAGE
-    COMBOBOX        IDC_COMBO_FILTERWINDOW,192,18,84,56,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
-    LTEXT           "&Bandwidth:",IDC_STATIC,12,36,42,12,SS_CENTERIMAGE
-    EDITTEXT        IDC_WFIRCUTOFF,54,36,30,12,ES_RIGHT | ES_AUTOHSCROLL | ES_NUMBER
-    CONTROL         "",IDC_SPIN1,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_NOTHOUSANDS,71,31,11,14
-    LTEXT           "%",IDC_STATIC,90,36,24,12,SS_CENTERIMAGE
+    COMBOBOX        IDC_COMBO_FILTER,36,18,102,56,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
     CONTROL         "Use &Amiga resampler for Amiga modules",IDC_CHECK1,
-                    "Button",BS_AUTOCHECKBOX | WS_TABSTOP,126,36,150,12
+                    "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,36,144,12
     GROUPBOX        "Volume Ramping",IDC_STATIC,6,60,276,48
     EDITTEXT        IDC_RAMPING_IN,12,72,36,12,ES_RIGHT | ES_AUTOHSCROLL | ES_NUMBER
     CONTROL         "",IDC_SPIN2,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_NOTHOUSANDS,42,66,11,14
Index: mptrack/resource.h
===================================================================
--- mptrack/resource.h	(revision 9968)
+++ mptrack/resource.h	(working copy)
@@ -684,8 +684,6 @@
 #define IDC_COMMAND_LIST                2129
 #define IDC_STATIC8                     2200
 #define IDC_PATINSTROPLUGGUI            2201
-#define IDC_WFIRCUTOFF                  2202
-#define IDC_WFIRTYPE                    2203
 #define IDC_RAMPING_IN                  2204
 #define IDC_PLAYEROPTIONS               2205
 #define IDC_RAMPING_OUT                 2205
Index: mptrack/SampleEditorDialogs.cpp
===================================================================
--- mptrack/SampleEditorDialogs.cpp	(revision 9968)
+++ mptrack/SampleEditorDialogs.cpp	(working copy)
@@ -530,12 +530,12 @@
 
 	CComboBox *cbnResampling = static_cast<CComboBox *>(GetDlgItem(IDC_COMBO_FILTER));
 	cbnResampling->SetRedraw(FALSE);
-	const ResamplingMode resamplingModes[] = { SRCMODE_NEAREST, SRCMODE_LINEAR, SRCMODE_SPLINE, SRCMODE_POLYPHASE, SRCMODE_FIRFILTER, SRCMODE_DEFAULT };
+	const auto resamplingModes = Resampling::AllModesWithDefault();
 	for(auto mode : resamplingModes)
 	{
-		const TCHAR *desc = _T("r8brain (High Quality)");
+		CString desc = _T("r8brain (High Quality)");
 		if(mode != SRCMODE_DEFAULT)
-			desc = CTrackApp::GetResamplingModeName(mode, false);
+			desc = CTrackApp::GetResamplingModeName(mode, 1, true);
 
 		int index = cbnResampling->AddString(desc);
 		cbnResampling->SetItemData(index, mode);
Index: mptrack/TrackerSettings.cpp
===================================================================
--- mptrack/TrackerSettings.cpp	(revision 9968)
+++ mptrack/TrackerSettings.cpp	(working copy)
@@ -76,29 +76,6 @@
 }
 
 
-static ResamplingMode GetDefaultResamplerMode()
-{
-	ResamplingMode result = CResamplerSettings().SrcMode;
-#ifdef ENABLE_ASM
-	// rough heuristic to select less cpu consuming defaults for old CPUs
-	if(GetRealProcSupport() & PROCSUPPORT_SSE)
-	{
-		result = SRCMODE_POLYPHASE;
-	} else if(GetRealProcSupport() & PROCSUPPORT_MMX)
-	{
-		result = SRCMODE_SPLINE;
-	} else
-	{
-		result = SRCMODE_LINEAR;
-	}
-#else
-	// just use a sane default
-	result = CResamplerSettings().SrcMode;
-#endif
-	return result;
-}
-
-
 static uint32 GetDefaultPatternSetup()
 {
 	return PATTERN_PLAYNEWNOTE | PATTERN_EFFECTHILIGHT
@@ -246,7 +223,7 @@
 	, MixerStereoSeparation(conf, MPT_USTRING("Sound Settings"), MPT_USTRING("StereoSeparation"), MixerSettings().m_nStereoSeparation)
 	, MixerVolumeRampUpMicroseconds(conf, MPT_USTRING("Sound Settings"), MPT_USTRING("VolumeRampUpMicroseconds"), MixerSettings().GetVolumeRampUpMicroseconds())
 	, MixerVolumeRampDownMicroseconds(conf, MPT_USTRING("Sound Settings"), MPT_USTRING("VolumeRampDownMicroseconds"), MixerSettings().GetVolumeRampDownMicroseconds())
-	, ResamplerMode(conf, MPT_USTRING("Sound Settings"), MPT_USTRING("SrcMode"), GetDefaultResamplerMode())
+	, ResamplerMode(conf, MPT_USTRING("Sound Settings"), MPT_USTRING("SrcMode"), CResamplerSettings().SrcMode)
 	, ResamplerSubMode(conf, MPT_USTRING("Sound Settings"), MPT_USTRING("XMMSModplugResamplerWFIRType"), CResamplerSettings().gbWFIRType)
 	, ResamplerCutoffPercent(conf, MPT_USTRING("Sound Settings"), MPT_USTRING("ResamplerWFIRCutoff"), Util::Round<int32>(CResamplerSettings().gdWFIRCutoff * 100.0))
 	, ResamplerEmulateAmiga(conf, MPT_USTRING("Sound Settings"), MPT_USTRING("ResamplerEmulateAmiga"), false)
@@ -548,6 +525,13 @@
 		m_SoundDeviceSettingsDefaults.UseHardwareTiming = m_SoundDeviceUseHardwareTiming;
 		m_SoundDeviceSettingsUseOldDefaults = true;
 	}
+	if(storedVersion < MAKE_VERSION_NUMERIC(1,28,00,15))
+	{
+		// reset this setting to the default when updating,
+		// because we do not provide a GUI any more,
+		// and in general, it should not get changed anyway
+		ResamplerCutoffPercent = Util::Round<int32>(CResamplerSettings().gdWFIRCutoff * 100.0);
+	}
 	if(storedVersion < MAKE_VERSION_NUMERIC(1,25,00,04))
 	{
 		m_SoundDeviceDirectSoundOldDefaultIdentifier = true;
@@ -680,7 +664,7 @@
 	}
 
 	// Sanitize resampling mode for sample editor
-	if(!IsKnownResamplingMode(sampleEditorDefaultResampler) && sampleEditorDefaultResampler != SRCMODE_DEFAULT)
+	if(!Resampling::IsKnownMode(sampleEditorDefaultResampler) && sampleEditorDefaultResampler != SRCMODE_DEFAULT)
 	{
 		sampleEditorDefaultResampler = SRCMODE_DEFAULT;
 	}
Index: soundlib/Load_it.cpp
===================================================================
--- soundlib/Load_it.cpp	(revision 9968)
+++ soundlib/Load_it.cpp	(working copy)
@@ -2357,7 +2357,7 @@
 			case MagicBE("RP.."): if(GetType() != MOD_TYPE_XM) { ORDERINDEX restartPos; ReadField(chunk, size, restartPos); Order().SetRestartPos(restartPos); } break;
 			case MagicLE("RSMP"):
 				ReadFieldCast(chunk, size, m_nResampling);
-				if(!IsKnownResamplingMode(m_nResampling)) m_nResampling = SRCMODE_DEFAULT;
+				if(!Resampling::IsKnownMode(m_nResampling)) m_nResampling = SRCMODE_DEFAULT;
 				break;
 #ifdef MODPLUG_TRACKER
 			case MagicBE("MIMA"): GetMIDIMapper().Deserialize(chunk); break;
Index: soundlib/MixFuncTable.cpp
===================================================================
--- soundlib/MixFuncTable.cpp	(revision 9968)
+++ soundlib/MixFuncTable.cpp	(working copy)
@@ -79,9 +79,9 @@
 	{
 	case SRCMODE_NEAREST:   return ndxNoInterpolation;
 	case SRCMODE_LINEAR:    return ndxLinear;
-	case SRCMODE_SPLINE:    return ndxFastSinc;
-	case SRCMODE_POLYPHASE: return ndxKaiser;
-	case SRCMODE_FIRFILTER: return ndxFIRFilter;
+	case SRCMODE_CUBIC:     return ndxFastSinc;
+	case SRCMODE_SINC8LP:   return ndxKaiser;
+	case SRCMODE_SINC8:     return ndxFIRFilter;
 	case SRCMODE_AMIGA:     return ndxAmigaBlep;
 	default:                MPT_ASSERT_NOTREACHED();
 	}
Index: soundlib/Resampler.h
===================================================================
--- soundlib/Resampler.h	(revision 9968)
+++ soundlib/Resampler.h	(working copy)
@@ -59,12 +59,12 @@
 	uint8 gbWFIRType;
 	bool emulateAmiga;
 public:
-	CResamplerSettings()
+	MPT_CONSTEXPR11_FUN CResamplerSettings()
+		: SrcMode(Resampling::Default())
+		, gdWFIRCutoff(0.97)
+		, gbWFIRType(WFIR_KAISER4T)
+		, emulateAmiga(false)
 	{
-		SrcMode = SRCMODE_POLYPHASE;
-		gdWFIRCutoff = 0.97;
-		gbWFIRType = WFIR_KAISER4T;
-		emulateAmiga = false;
 	}
 	bool operator == (const CResamplerSettings &cmp) const
 	{
@@ -125,8 +125,6 @@
 	{
 		InitializeTablesFromScratch(false);
 	}
-	~CResampler() {}
-	bool IsHQ() const { return m_Settings.SrcMode >= SRCMODE_SPLINE && m_Settings.SrcMode < SRCMODE_DEFAULT; }
 private:
 	void InitFloatmixerTables();
 	void InitializeTablesFromScratch(bool force=false);
Index: soundlib/Snd_defs.h
===================================================================
--- soundlib/Snd_defs.h	(revision 9968)
+++ soundlib/Snd_defs.h	(working copy)
@@ -290,22 +290,55 @@
 {
 	// ATTENTION: Do not change ANY of these values, as they get written out to files in per instrument interpolation settings
 	// and old files have these exact values in them which should not change meaning.
-	SRCMODE_NEAREST   = 0,
-	SRCMODE_LINEAR    = 1,
-	SRCMODE_SPLINE    = 2,
-	SRCMODE_POLYPHASE = 3,
-	SRCMODE_FIRFILTER = 4,
-	SRCMODE_DEFAULT   = 5,
+	SRCMODE_NEAREST   = 0,  // 1 tap, no AA
+	SRCMODE_LINEAR    = 1,  // 2 tap, no AA
+	SRCMODE_CUBIC     = 2,  // 4 tap, no AA
+	SRCMODE_SINC8     = 4,  // 8 tap, no AA   (yes, index 4) (XMMS-ModPlug)
+	SRCMODE_SINC8LP   = 3,  // 8 tap, with AA (yes, index 3) (Polyphase)
 
-	SRCMODE_AMIGA = 0xFF,	// Not explicitely user-selectable
+	SRCMODE_DEFAULT   = 5,  // only used for instrument settings, not used inside the mixer
+
+	SRCMODE_AMIGA  = 0xFF,  // Not explicitely user-selectable
 };
 
-static inline bool IsKnownResamplingMode(int mode)
+namespace Resampling
 {
-	return (mode >= 0) && (mode < SRCMODE_DEFAULT);
+
+static inline std::array<ResamplingMode, 5> AllModes() noexcept { return { SRCMODE_NEAREST, SRCMODE_LINEAR, SRCMODE_CUBIC, SRCMODE_SINC8, SRCMODE_SINC8LP }; }
+
+static inline std::array<ResamplingMode, 6> AllModesWithDefault() noexcept { return { SRCMODE_NEAREST, SRCMODE_LINEAR, SRCMODE_CUBIC, SRCMODE_SINC8, SRCMODE_SINC8LP, SRCMODE_DEFAULT }; }
+
+static MPT_CONSTEXPR11_FUN ResamplingMode Default() noexcept { return SRCMODE_SINC8LP; }
+
+static MPT_CONSTEXPR11_FUN bool IsKnownMode(int mode) noexcept { return (mode >= 0) && (mode < SRCMODE_DEFAULT); }
+
+static MPT_CONSTEXPR11_FUN ResamplingMode ToKnownMode(int mode) noexcept
+{
+	return Resampling::IsKnownMode(mode) ? static_cast<ResamplingMode>(mode)
+		: (mode == SRCMODE_AMIGA) ? SRCMODE_LINEAR
+		: Resampling::Default();
 }
 
+static MPT_CONSTEXPR11_FUN int Length(ResamplingMode mode) noexcept
+{
+	return mode == SRCMODE_NEAREST ? 1
+		: mode == SRCMODE_LINEAR ? 2
+		: mode == SRCMODE_CUBIC ? 4
+		: mode == SRCMODE_SINC8 ? 8
+		: mode == SRCMODE_SINC8LP ? 8
+		: 0;
+}
 
+static MPT_CONSTEXPR11_FUN bool HasAA(ResamplingMode mode) noexcept { return (mode == SRCMODE_SINC8LP); }
+
+static MPT_CONSTEXPR11_FUN ResamplingMode AddAA(ResamplingMode mode) noexcept { return (mode == SRCMODE_SINC8) ? SRCMODE_SINC8LP : mode; }
+
+static MPT_CONSTEXPR11_FUN ResamplingMode RemoveAA(ResamplingMode mode) noexcept { return (mode == SRCMODE_SINC8LP) ? SRCMODE_SINC8 : mode; }
+
+}
+
+
+
 // Release node defines
 #define ENV_RELEASE_NODE_UNSET	0xFF
 #define NOT_YET_RELEASED		(-1)
Index: soundlib/Sndmix.cpp
===================================================================
--- soundlib/Sndmix.cpp	(revision 9968)
+++ soundlib/Sndmix.cpp	(working copy)
@@ -2330,11 +2330,11 @@
 			//if (pChn->nNewRightVol > 0xFFFF) pChn->nNewRightVol = 0xFFFF;
 			//if (pChn->nNewLeftVol > 0xFFFF) pChn->nNewLeftVol = 0xFFFF;
 
-			if(pChn->pModInstrument && IsKnownResamplingMode(pChn->pModInstrument->nResampling))
+			if(pChn->pModInstrument && Resampling::IsKnownMode(pChn->pModInstrument->nResampling))
 			{
 				// For defined resampling modes, use per-instrument resampling mode if set
 				pChn->resamplingMode = static_cast<uint8>(pChn->pModInstrument->nResampling);
-			} else if(IsKnownResamplingMode(m_nResampling))
+			} else if(Resampling::IsKnownMode(m_nResampling))
 			{
 				pChn->resamplingMode = static_cast<uint8>(m_nResampling);
 			} else if(m_SongFlags[SONG_ISAMIGA] && m_Resampler.m_Settings.emulateAmiga)
Index: soundlib/Tables.cpp
===================================================================
--- soundlib/Tables.cpp	(revision 9968)
+++ soundlib/Tables.cpp	(working copy)
@@ -853,42 +853,7 @@
 	}
 }
 
-#if 0
 
-// this code is currently unused
-
-static double GetSpline(double x, double c0, double c1, double c2, double c3)
-{
-	double Xo = c1;
-	double Xa = c0 - Xo;
-	double Xb = c2 - Xo;
-	double Ux = (Xb-Xa)/2;
-	double Vx = (c3 - Xo)/2;
-	double a = Vx+Ux-2*Xb;
-	double b = 3*Xb-2*Ux-Vx;
-	return (((a*x+b)*x)+Ux)*x+Xo;
-}
-
-
-static void getdownsample2x(short int *psinc)
-{
-	for (int i=0; i<SINC_PHASES; i++)
-	{
-		double x = (double)i * (double)(0.5/SINC_PHASES);
-		psinc[i*8+7] = (short int)(GetSpline(x,     0, 0, 0, 1) * 8192);
-		psinc[i*8+6] = (short int)(GetSpline(x+0.5, 0, 0, 0, 1) * 8192);
-		psinc[i*8+5] = (short int)(GetSpline(x,     0, 0, 1, 0) * 8192);
-		psinc[i*8+4] = (short int)(GetSpline(x+0.5, 0, 0, 1, 0) * 8192);
-		psinc[i*8+3] = (short int)(GetSpline(x,     0, 1, 0, 0) * 8192);
-		psinc[i*8+2] = (short int)(GetSpline(x+0.5, 0, 1, 0, 0) * 8192);
-		psinc[i*8+1] = (short int)(GetSpline(x,     1, 0, 0, 0) * 8192);
-		psinc[i*8+0] = (short int)(GetSpline(x+0.5, 1, 0, 0, 0) * 8192);
-	}
-}
-
-#endif
-
-
 #ifdef MODPLUG_TRACKER
 bool CResampler::StaticTablesInitialized = false;
 SINC_TYPE CResampler::gKaiserSinc[SINC_PHASES*8];     // Upsampling
@@ -938,12 +903,8 @@
 		InitFloatmixerTables();
 
 		getsinc(gKaiserSinc, 9.6377, 0.97);
-		//ericus' downsampling improvement.
-		//getsinc(gDownsample13x, 8.5, 3.0/4.0);
-		//getdownsample2x(gDownsample2x);
 		getsinc(gDownsample13x, 8.5, 0.5);
 		getsinc(gDownsample2x, 2.7625, 0.425);
-		//end ericus' downsampling improvement.
 
 		#ifdef MODPLUG_TRACKER
 			StaticTablesInitialized = true;
Index: soundlib/WindowedFIR.h
===================================================================
--- soundlib/WindowedFIR.h	(revision 9968)
+++ soundlib/WindowedFIR.h	(working copy)
@@ -48,25 +48,20 @@
 #define WFIR_LOG2WIDTH		3
 #define WFIR_WIDTH			(1L<<WFIR_LOG2WIDTH)
 // cutoff (1.0 == pi/2)
-//float WFIR_CUTOFF			= 0.5f;//0.75f;	//0.90f;
 // wfir type
 enum WFIRType
 {
-	WFIR_HANN			= 0,
-	WFIR_HAMMING		= 1,
-	WFIR_BLACKMANEXACT	= 2,
-	WFIR_BLACKMAN3T61	= 3,
-	WFIR_BLACKMAN3T67	= 4,
-	WFIR_BLACKMAN4T92	= 5,
-	WFIR_BLACKMAN4T74	= 6,
-	WFIR_KAISER4T		= 7,
+	WFIR_HANN          = 0,  // Hann
+	WFIR_HAMMING       = 1,  // Hamming
+	WFIR_BLACKMANEXACT = 2,  // Blackman Exact
+	WFIR_BLACKMAN3T61  = 3,  // Blackman 3-Tap 61
+	WFIR_BLACKMAN3T67  = 4,  // Blackman 3-Tap 67
+	WFIR_BLACKMAN4T92  = 5,  // Blackman-Harris
+	WFIR_BLACKMAN4T74  = 6,  // Blackman 4-Tap 74
+	WFIR_KAISER4T      = 7,  // Kaiser a=7.5
 };
-//int WFIR_TYPE				= WFIR_KAISER4T;//WFIR_BLACKMANEXACT;
-//int WFIR_TYPE				= TrackerSettings::Instance().gbWFIRType;
 // wfir help
-#ifndef M_zPI
 #define M_zPI				3.1415926535897932384626433832795
-#endif
 #define M_zEPS				1e-8
 
 
Index: test/test.cpp
===================================================================
--- test/test.cpp	(revision 9968)
+++ test/test.cpp	(working copy)
@@ -2739,7 +2739,7 @@
 	VERIFY_EQUAL_NONCONT(pIns->nPPC, NOTE_MIDDLEC - 1);
 
 	VERIFY_EQUAL_NONCONT(pIns->nVolRampUp, 1200);
-	VERIFY_EQUAL_NONCONT(pIns->nResampling, (unsigned)SRCMODE_POLYPHASE);
+	VERIFY_EQUAL_NONCONT(pIns->nResampling, (unsigned)SRCMODE_SINC8LP);
 
 	VERIFY_EQUAL_NONCONT(pIns->IsCutoffEnabled(), false);
 	VERIFY_EQUAL_NONCONT(pIns->GetCutoff(), 0);
@@ -2869,7 +2869,7 @@
 	VERIFY_EQUAL_NONCONT(sndFile.m_nDefaultRowsPerBeat, 6);
 	VERIFY_EQUAL_NONCONT(sndFile.m_nDefaultRowsPerMeasure, 12);
 	VERIFY_EQUAL_NONCONT(sndFile.m_dwCreatedWithVersion, MAKE_VERSION_NUMERIC(1, 19, 02, 05));
-	VERIFY_EQUAL_NONCONT(sndFile.m_nResampling, SRCMODE_POLYPHASE);
+	VERIFY_EQUAL_NONCONT(sndFile.m_nResampling, SRCMODE_SINC8LP);
 	VERIFY_EQUAL_NONCONT(sndFile.m_songArtist, MPT_USTRING("Tester"));
 	VERIFY_EQUAL_NONCONT(sndFile.m_tempoSwing.size(), 6);
 	VERIFY_EQUAL_NONCONT(sndFile.m_tempoSwing[0], 29360125);
@@ -3032,7 +3032,7 @@
 		VERIFY_EQUAL_NONCONT(pIns->nPPC, (NOTE_MIDDLEC - NOTE_MIN) + 6);	// F#5
 
 		VERIFY_EQUAL_NONCONT(pIns->nVolRampUp, 1200);
-		VERIFY_EQUAL_NONCONT(pIns->nResampling, (unsigned)SRCMODE_POLYPHASE);
+		VERIFY_EQUAL_NONCONT(pIns->nResampling, (unsigned)SRCMODE_SINC8LP);
 
 		VERIFY_EQUAL_NONCONT(pIns->IsCutoffEnabled(), true);
 		VERIFY_EQUAL_NONCONT(pIns->GetCutoff(), 0x32);
resampler-cleanup-v2.patch (28,332 bytes)   
manx

manx

2018-11-20 17:22

administrator   ~0003720

  • [Imp] Rename resampling filters. Rename "Spline" to "Cubic", "XMMS-ModPlug" to "Sinc", and "Polyphase" to "Sinc with LowPass".
    • [Imp] Reorder resampling filters such that "Sync with Low-Pass" is the last filter, resulting in an order of increasing quality characteristics.
    • [Reg] Remove bandwidth and windowing function selection from configuration dialog. These are often misunderstood by users and changing them can result in reduced resampling quality if one does not fully understand the consequences. Move them to hidden settings and revert their setting to the default.
    • [Mod] Remove heuristic to select faster interpolation filters on slower CPUs by default. Although theoretically possible, it is rather unlike that people are still using OpenMPT on extremely slow CPUs that can still run Windows XP. Therefore, stick to consistency of defaults across all system configuration, rather than implement arbitrary heuristics that reduce quality on very old systems.
    • [Var] See <https://bugs.openmpt.org/view.php?id=1102>.
manx

manx

2018-11-25 17:55

administrator   ~0003744

Implemented in r10998 .

Issue History

Date Modified Username Field Change
2018-03-11 20:06 IsaacNorman New Issue
2018-03-11 20:25 manx Note Added: 0003475
2018-03-11 20:26 manx Target Version => OpenMPT 1.28.01.00 / libopenmpt 0.4.0 (upgrade first)
2018-03-11 20:37 IsaacNorman Note Added: 0003476
2018-03-11 20:42 manx Note Added: 0003477
2018-03-11 20:47 IsaacNorman Note Added: 0003478
2018-03-12 11:28 Saga Musix Note Added: 0003479
2018-03-12 16:06 manx Note Added: 0003480
2018-03-12 16:06 manx Assigned To => manx
2018-03-12 16:06 manx Status new => assigned
2018-03-12 16:11 manx File Added: resampler-cleanup-v1.patch
2018-03-12 16:11 manx Note Added: 0003481
2018-03-12 16:13 manx Summary Sinc interpolation for audio => Rename interpolation filters (was: Sinc interpolation for audio)
2018-03-12 16:13 Saga Musix Note Added: 0003482
2018-03-12 16:16 manx Note Edited: 0003480
2018-03-21 11:31 manx File Added: resampler-cleanup-v2.patch
2018-03-21 11:31 manx Note Added: 0003487
2018-03-21 15:04 manx File Added: resampler-cleanup-v3.patch
2018-04-11 09:13 manx File Added: resampler-cleanup-v4.patch
2018-09-12 13:43 manx File Added: resampler-cleanup-v5.patch
2018-11-04 15:12 manx File Added: resampler-cleanup-v7.patch
2018-11-13 09:50 manx File Added: resampler-cleanup-v8.patch
2018-11-20 17:22 manx Note Added: 0003720
2018-11-25 17:55 manx Status assigned => resolved
2018-11-25 17:55 manx Resolution open => fixed
2018-11-25 17:55 manx Fixed in Version => OpenMPT 1.28.01.00 / libopenmpt 0.4.0 (upgrade first)
2018-11-25 17:55 manx Note Added: 0003744