Some conversion replacements:
Some conversion replacements:

* Replace the (w)stringify functions with the standard std::to_(w)string functions.
* Replace convertTo with versions that use type_traits to determine which standard string conversion function to call, as well as handle enums specically.

--- a/src/in_2sf/XSFConfig_2SF.cpp
+++ b/src/in_2sf/XSFConfig_2SF.cpp
@@ -93,7 +93,7 @@
 			// Mutes
 			for (size_t x = 0, numMutes = this->mutes.size(); x < numMutes; ++x)
 			{
-				SendMessageW(GetDlgItem(hwndDlg, idMutes), LB_ADDSTRING, 0, reinterpret_cast<LPARAM>((L"SPU " + wstringify(x + 1)).c_str()));
+				SendMessageW(GetDlgItem(hwndDlg, idMutes), LB_ADDSTRING, 0, reinterpret_cast<LPARAM>((L"SPU " + std::to_wstring(x + 1)).c_str()));
 				SendMessageW(GetDlgItem(hwndDlg, idMutes), LB_SETSEL, this->mutes[x], x);
 			}
 			break;

--- a/src/in_2sf/XSFPlayer_2SF.cpp
+++ b/src/in_2sf/XSFPlayer_2SF.cpp
@@ -162,7 +162,7 @@
 	do
 	{
 		found = false;
-		std::string libTag = "_lib" + stringify(n++);
+		std::string libTag = "_lib" + std::to_string(n++);
 		if (xSFToLoad->GetTagExists(libTag))
 		{
 			found = true;

--- a/src/in_gsf/XSFPlayer_GSF.cpp
+++ b/src/in_gsf/XSFPlayer_GSF.cpp
@@ -168,7 +168,7 @@
 	do
 	{
 		found = false;
-		std::string libTag = "_lib" + stringify(n++);
+		std::string libTag = "_lib" + std::to_string(n++);
 		if (xSF->GetTagExists(libTag))
 		{
 			found = true;

--- a/src/in_ncsf/SSEQPlayer/SDAT.cpp
+++ b/src/in_ncsf/SSEQPlayer/SDAT.cpp
@@ -42,7 +42,7 @@
 		throw std::logic_error("No SSEQ records found in SDAT");
 
 	if (!infoSection.SEQrecord.entries.count(sseqToLoad))
-		throw std::range_error("SSEQ of " + stringify(sseqToLoad) + " is not found");
+		throw std::range_error("SSEQ of " + std::to_string(sseqToLoad) + " is not found");
 
 	// Read SSEQ
 	if (infoSection.SEQrecord.entries.count(sseqToLoad))

--- a/src/in_ncsf/XSFConfig_NCSF.cpp
+++ b/src/in_ncsf/XSFConfig_NCSF.cpp
@@ -85,7 +85,7 @@
 			// Mutes
 			for (int x = 0, numMutes = this->mutes.size(); x < numMutes; ++x)
 			{
-				SendMessageW(GetDlgItem(hwndDlg, idMutes), LB_ADDSTRING, 0, reinterpret_cast<LPARAM>((L"SPU " + wstringify(x + 1)).c_str()));
+				SendMessageW(GetDlgItem(hwndDlg, idMutes), LB_ADDSTRING, 0, reinterpret_cast<LPARAM>((L"SPU " + std::to_wstring(x + 1)).c_str()));
 				SendMessageW(GetDlgItem(hwndDlg, idMutes), LB_SETSEL, this->mutes[x], x);
 			}
 			break;
@@ -259,9 +259,9 @@
 			ProgressSetPosImmediate(hDlg, IDC_SOUND0VOLBAR + chanId, vol);
 
 			if (this->soundViewData->volModeAlternative)
-				buf = wstringify(chn.reg.volumeMul) + L"/" + wstringify(1 << datashift);
+				buf = std::to_wstring(chn.reg.volumeMul) + L"/" + std::to_wstring(1 << datashift);
 			else
-				buf = wstringify(vol);
+				buf = std::to_wstring(vol);
 			SetDlgItemTextW(hDlg, IDC_SOUND0VOL + chanId, buf.c_str());
 
 			if (!chn.reg.panning)
@@ -271,18 +271,18 @@
 			else if (chn.reg.panning == 127)
 				buf = L"R";
 			else if (chn.reg.panning < 64)
-				buf = L"L" + wstringify(64 - chn.reg.panning);
+				buf = L"L" + std::to_wstring(64 - chn.reg.panning);
 			else //if (chn.reg.panning > 64)
-				buf = L"R" + wstringify(chn.reg.panning - 64);
+				buf = L"R" + std::to_wstring(chn.reg.panning - 64);
 			SetDlgItemTextW(hDlg, IDC_SOUND0PAN + chanId, buf.c_str());
 
 			static const std::wstring modes[] = { L"Manual", L"Loop Infinite", L"One-Shot", L"Prohibited" };
-			SetDlgItemTextW(hDlg, IDC_SOUND0REPEATMODE + chanId, (wstringify(chn.reg.repeatMode) + L" (" + modes[chn.reg.repeatMode] + L")").c_str());
+			SetDlgItemTextW(hDlg, IDC_SOUND0REPEATMODE + chanId, (std::to_wstring(chn.reg.repeatMode) + L" (" + modes[chn.reg.repeatMode] + L")").c_str());
 
 			if (chn.reg.format != 3)
 			{
 				static const std::wstring formats[] = { L"PCM8", L"PCM16", L"IMA-ADPCM" };
-				SetDlgItemTextW(hDlg, IDC_SOUND0FORMAT + chanId, (wstringify(chn.reg.format) + L" (" + formats[chn.reg.format] + L")").c_str());
+				SetDlgItemTextW(hDlg, IDC_SOUND0FORMAT + chanId, (std::to_wstring(chn.reg.format) + L" (" + formats[chn.reg.format] + L")").c_str());
 			}
 			else
 			{
@@ -290,7 +290,7 @@
 				if (chanId < 8)
 					buf += L"PSG/Noise?";
 				else if (chanId < 14)
-					buf += wstringify(chn.reg.waveDuty == 7 ? 0 : 12.5 * (chn.reg.waveDuty + 1)) + L"% Square";
+					buf += std::to_wstring(chn.reg.waveDuty == 7 ? 0 : 12.5 * (chn.reg.waveDuty + 1)) + L"% Square";
 				else
 					buf += L"Noise";
 				buf += L")";
@@ -300,17 +300,17 @@
 			static const std::wstring states[] = { L"NONE", L"START", L"ATTACK", L"DECAY", L"SUSTAIN", L"RELEASE" };
 			SetDlgItemTextW(hDlg, IDC_SOUND0STATE + chanId, states[chn.state].c_str());
 
-			SetDlgItemTextW(hDlg, IDC_SOUND0PNT + chanId, (L"samp #" + wstringify(chn.reg.loopStart)).c_str());
+			SetDlgItemTextW(hDlg, IDC_SOUND0PNT + chanId, (L"samp #" + std::to_wstring(chn.reg.loopStart)).c_str());
 
 			std::wstring tmpBuf = ConvertFuncs::StringToWString(NumToHexString(chn.reg.timer)).substr(2);
 			buf = L"$" + tmpBuf + L" (";
-			tmpBuf = wstringify((ARM7_CLOCK / 2) / static_cast<double>(0x10000 - chn.reg.timer) / 8);
+			tmpBuf = std::to_wstring((ARM7_CLOCK / 2) / static_cast<double>(0x10000 - chn.reg.timer) / 8);
 			if (tmpBuf.find('.') != std::wstring::npos)
 				tmpBuf = tmpBuf.substr(0, tmpBuf.find('.') + 2);
 			buf += tmpBuf + L" Hz)";
 			SetDlgItemTextW(hDlg, IDC_SOUND0TMR + chanId, buf.c_str());
 
-			SetDlgItemTextW(hDlg, IDC_SOUND0POSLEN + chanId, (L"samp #" + wstringify(static_cast<uint32_t>(chn.reg.samplePosition)) + L" / " + wstringify(chn.reg.totalLength)).c_str());
+			SetDlgItemTextW(hDlg, IDC_SOUND0POSLEN + chanId, (L"samp #" + std::to_wstring(static_cast<uint32_t>(chn.reg.samplePosition)) + L" / " + std::to_wstring(chn.reg.totalLength)).c_str());
 		}
 		else if (this->soundViewData->channelLastStates[chanId] != CS_NONE)
 		{

--- a/src/in_ncsf/XSFPlayer_NCSF.cpp
+++ b/src/in_ncsf/XSFPlayer_NCSF.cpp
@@ -83,7 +83,7 @@
 	do
 	{
 		found = false;
-		std::string libTag = "_lib" + stringify(n++);
+		std::string libTag = "_lib" + std::to_string(n++);
 		if (xSFToLoad->GetTagExists(libTag))
 		{
 			found = true;

--- a/src/in_snsf/XSFConfig_SNSF.cpp
+++ b/src/in_snsf/XSFConfig_SNSF.cpp
@@ -101,7 +101,7 @@
 			// Mutes
 			for (int x = 0, numMutes = this->mutes.size(); x < numMutes; ++x)
 			{
-				SendMessageW(GetDlgItem(hwndDlg, idMutes), LB_ADDSTRING, 0, reinterpret_cast<LPARAM>((L"BRRPCM " + wstringify(x + 1)).c_str()));
+				SendMessageW(GetDlgItem(hwndDlg, idMutes), LB_ADDSTRING, 0, reinterpret_cast<LPARAM>((L"BRRPCM " + std::to_wstring(x + 1)).c_str()));
 				SendMessageW(GetDlgItem(hwndDlg, idMutes), LB_SETSEL, this->mutes[x], x);
 			}
 			break;

--- a/src/in_snsf/XSFPlayer_SNSF.cpp
+++ b/src/in_snsf/XSFPlayer_SNSF.cpp
@@ -183,7 +183,7 @@
 	do
 	{
 		found = false;
-		std::string libTag = "_lib" + stringify(n++);
+		std::string libTag = "_lib" + std::to_string(n++);
 		if (xSF->GetTagExists(libTag))
 		{
 			found = true;

--- a/src/in_xsf_framework/XSFConfig.cpp
+++ b/src/in_xsf_framework/XSFConfig.cpp
@@ -228,7 +228,7 @@
 			SetWindowTextW(GetDlgItem(hwndDlg, idDefaultFade), ConvertFuncs::MSToWString(this->defaultFade).c_str());
 			SetWindowTextW(GetDlgItem(hwndDlg, idSkipSilenceOnStartSec), ConvertFuncs::MSToWString(this->skipSilenceOnStartSec).c_str());
 			SetWindowTextW(GetDlgItem(hwndDlg, idDetectSilenceSec), ConvertFuncs::MSToWString(this->detectSilenceSec).c_str());
-			SetWindowTextW(GetDlgItem(hwndDlg, idVolume), wstringify(this->volume).c_str());
+			SetWindowTextW(GetDlgItem(hwndDlg, idVolume), std::to_wstring(this->volume).c_str());
 			SendMessageW(GetDlgItem(hwndDlg, idReplayGain), CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(L"Disabled"));
 			SendMessageW(GetDlgItem(hwndDlg, idReplayGain), CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(L"Use Volume Tag"));
 			SendMessageW(GetDlgItem(hwndDlg, idReplayGain), CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(L"Track"));
@@ -241,7 +241,7 @@
 			for (unsigned x = 0, rates = this->supportedSampleRates.size(); x < rates; ++x)
 			{
 				unsigned rate = this->supportedSampleRates[x];
-				SendMessageW(GetDlgItem(hwndDlg, idSampleRate), CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(wstringify(rate).c_str()));
+				SendMessageW(GetDlgItem(hwndDlg, idSampleRate), CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(std::to_wstring(rate).c_str()));
 				if (this->sampleRate == rate)
 					SendMessageW(GetDlgItem(hwndDlg, idSampleRate), CB_SETCURSEL, x, 0);
 			}
@@ -335,7 +335,7 @@
 	SetWindowTextW(GetDlgItem(hwndDlg, idDefaultFade), ConvertFuncs::StringToWString(XSFConfig::initDefaultFade).c_str());
 	SetWindowTextW(GetDlgItem(hwndDlg, idSkipSilenceOnStartSec), ConvertFuncs::StringToWString(XSFConfig::initSkipSilenceOnStartSec).c_str());
 	SetWindowTextW(GetDlgItem(hwndDlg, idDetectSilenceSec), ConvertFuncs::StringToWString(XSFConfig::initDetectSilenceSec).c_str());
-	SetWindowTextW(GetDlgItem(hwndDlg, idVolume), wstringify(XSFConfig::initVolume).c_str());
+	SetWindowTextW(GetDlgItem(hwndDlg, idVolume), std::to_wstring(XSFConfig::initVolume).c_str());
 	SendMessageW(GetDlgItem(hwndDlg, idReplayGain), CB_SETCURSEL, XSFConfig::initVolumeType, 0);
 	SendMessageW(GetDlgItem(hwndDlg, idClipProtect), CB_SETCURSEL, XSFConfig::initPeakType, 0);
 	auto found = std::find(this->supportedSampleRates.begin(), this->supportedSampleRates.end(), XSFConfig::initSampleRate);
@@ -352,7 +352,7 @@
 	this->defaultFade = ConvertFuncs::StringToMS(this->GetTextFromWindow(GetDlgItem(hwndDlg, idDefaultFade)));
 	this->skipSilenceOnStartSec = ConvertFuncs::StringToMS(this->GetTextFromWindow(GetDlgItem(hwndDlg, idSkipSilenceOnStartSec)));
 	this->detectSilenceSec = ConvertFuncs::StringToMS(this->GetTextFromWindow(GetDlgItem(hwndDlg, idDetectSilenceSec)));
-	this->volume = convertTo<double>(this->GetTextFromWindow(GetDlgItem(hwndDlg, idVolume)), false);
+	this->volume = convertTo<double>(this->GetTextFromWindow(GetDlgItem(hwndDlg, idVolume)));
 	this->volumeType = static_cast<VolumeType>(SendMessageW(GetDlgItem(hwndDlg, idReplayGain), CB_GETCURSEL, 0, 0));
 	this->peakType = static_cast<PeakType>(SendMessageW(GetDlgItem(hwndDlg, idClipProtect), CB_GETCURSEL, 0, 0));
 	this->sampleRate = XSFConfig::supportedSampleRates[SendMessageW(GetDlgItem(hwndDlg, idSampleRate), CB_GETCURSEL, 0, 0)];

--- a/src/in_xsf_framework/XSFConfig.h
+++ b/src/in_xsf_framework/XSFConfig.h
@@ -24,10 +24,10 @@
 
 	virtual ~XSFConfigIO() { }
 	virtual void SetValueString(const std::string &name, const std::string &value) = 0;
-	template<typename T> void SetValue(const std::string &name, const T &value) { this->SetValueString(name, stringify(value)); }
+	template<typename T> void SetValue(const std::string &name, const T &value) { this->SetValueString(name, std::to_string(value)); }
 	void SetValue(const std::string &name, const std::string &value) { this->SetValueString(name, value); }
 	virtual std::string GetValueString(const std::string &name, const std::string &defaultValue) const = 0;
-	template<typename T> T GetValue(const std::string &name, const T &defaultValue) const { return convertTo<T>(this->GetValueString(name, stringify(defaultValue))); }
+	template<typename T> T GetValue(const std::string &name, const T &defaultValue) const { return convertTo<T>(this->GetValueString(name, std::to_string(defaultValue))); }
 	std::string GetValue(const std::string &name, const std::string &defaultValue) const { return this->GetValueString(name, defaultValue); }
 	virtual void SetHInstance(HINSTANCE) { }
 	virtual HINSTANCE GetHInstance() const { return nullptr; }

--- a/src/in_xsf_framework/XSFFile.cpp
+++ b/src/in_xsf_framework/XSFFile.cpp
@@ -325,24 +325,24 @@
 	bool hadReplayGain = false;
 	if (preferredVolumeType == VOLUMETYPE_REPLAYGAIN_ALBUM && !replaygain_album_gain.empty())
 	{
-		gain = convertTo<double>(replaygain_album_gain, false);
+		gain = convertTo<double>(replaygain_album_gain);
 		hadReplayGain = true;
 	}
 	if (!hadReplayGain && preferredVolumeType != VOLUMETYPE_VOLUME && !replaygain_track_gain.empty())
 	{
-		gain = convertTo<double>(replaygain_track_gain, false);
+		gain = convertTo<double>(replaygain_track_gain);
 		hadReplayGain = true;
 	}
 	if (hadReplayGain)
 	{
 		double vol = std::pow(10.0, gain / 20.0), peak = 1.0;
 		if (preferredPeakType == PEAKTYPE_REPLAYGAIN_ALBUM && !replaygain_album_peak.empty())
-			peak = convertTo<double>(replaygain_album_peak, false);
+			peak = convertTo<double>(replaygain_album_peak);
 		else if (preferredPeakType != PEAKTYPE_NONE && !replaygain_track_peak.empty())
-			peak = convertTo<double>(replaygain_track_peak, false);
+			peak = convertTo<double>(replaygain_track_peak);
 		return !fEqual(peak, 1.0) ? std::min(vol, 1.0 / peak) : vol;
 	}
-	return volume.empty() ? 1.0 : convertTo<double>(volume, false);
+	return volume.empty() ? 1.0 : convertTo<double>(volume);
 }
 
 std::string XSFFile::FormattedTitleOptionalBlock(const std::string &block, bool &hadReplacement, unsigned level) const

--- a/src/in_xsf_framework/XSFFile.h
+++ b/src/in_xsf_framework/XSFFile.h
@@ -63,7 +63,7 @@
 	std::string GetTagValue(const std::string &name) const;
 	template<typename T> T GetTagValue(const std::string &name, const T &defaultValue) const
 	{
-		return this->GetTagExists(name) ? convertTo<T>(this->GetTagValue(name), false) : defaultValue;
+		return this->GetTagExists(name) ? convertTo<T>(this->GetTagValue(name)) : defaultValue;
 	}
 	unsigned long GetLengthMS(unsigned long defaultLength) const;
 	unsigned long GetFadeMS(unsigned long defaultFade) const;

--- a/src/in_xsf_framework/convert.h
+++ b/src/in_xsf_framework/convert.h
@@ -5,61 +5,54 @@
 
 #pragma once
 
-#include <stdexcept>
 #include <string>
 #include <sstream>
-#include <typeinfo>
 #include <locale>
-#include <codecvt>
 #include <vector>
 #include <memory>
+#include <type_traits>
 #include <cmath>
 #include "windowsh_wrapper.h"
 
-/*
- * The following exception class and the *stringify and convert* functions are
- * from the C++ FAQ, section 39, entry 3:
- * http://www.parashift.com/c++-faq/convert-string-to-any.html
- *
- * The convert and convertTo functions were made into templates of std::basic_string
- * to handle wide-character strings properly, as well as adding wstringify for the
- * same reason.
- */
-class BadConversion : public std::runtime_error
+ /*
+  * Originally the convert* functions came from the C++ FAQ, Miscellaneous Technical Issues:
+  * https://isocpp.org/wiki/faq/misc-technical-issues#convert-string-to-any
+  *
+  * They have been replaced with a couple functions that use the C++11 std::enable_if
+  * construct along with various other type traits constructs to use the proper
+  * string conversions.
+  */
+template<typename T, typename S> inline typename std::enable_if_t<!std::is_enum_v<T> &&std::is_arithmetic_v<T>, T> convertTo(const std::basic_string<S> &s)
 {
-public:
-	BadConversion(const std::string &s) : std::runtime_error(s) { }
-};
-
-template<typename T> inline std::string stringify(const T &x)
+	if (std::is_integral_v<T>)
+	{
+		if (std::is_unsigned_v<T>)
+		{
+			if (std::is_same_v<unsigned long long, std::remove_cv_t<T>>)
+				return static_cast<T>(std::stoull(s));
+			else
+				return static_cast<T>(std::stoul(s));
+		}
+		else if (std::is_same_v<long long, std::remove_cv_t<T>>)
+			return static_cast<T>(std::stoll(s));
+		else if (std::is_same_v<long, std::remove_cv_t<T>>)
+			return static_cast<T>(std::stol(s));
+		else
+			return static_cast<T>(std::stoi(s));
+	}
+	else if (std::is_floating_point_v<T>)
+	{
+		if (std::is_same_v<long double, std::remove_cv_t<T>>)
+			return static_cast<T>(std::stold(s));
+		else if (std::is_same_v<double, std::remove_cv_t<T>>)
+			return static_cast<T>(std::stod(s));
+		else
+			return static_cast<T>(std::stof(s));
+	}
+}
+template<typename T, typename S> inline typename std::enable_if_t<std::is_enum_v<T>, T> convertTo(const std::basic_string<S> &s)
 {
-	std::ostringstream o;
-	if (!(o << x))
-		throw BadConversion(std::string("stringify(") + typeid(x).name() + ")");
-	return o.str();
-}
-
-template<typename T> inline std::wstring wstringify(const T &x)
-{
-	std::wostringstream o;
-	if (!(o << x))
-		throw BadConversion(std::string("wstringify(") + typeid(x).name() + ")");
-	return o.str();
-}
-
-template<typename T, typename S> inline void convert(const std::basic_string<S> &s, T &x, bool failIfLeftoverChars = true)
-{
-	std::basic_istringstream<S> i(s);
-	S c;
-	if (!(i >> x) || (failIfLeftoverChars && i.get(c)))
-		throw BadConversion(std::string("convert(") + typeid(S).name() + ")");
-}
-
-template<typename T, typename S> inline T convertTo(const std::basic_string<S> &s, bool failIfLeftoverChars = true)
-{
-	T x;
-	convert(s, x, failIfLeftoverChars);
-	return x;
+	return static_cast<T>(convertTo<std::underlying_type_t<T>>(s));
 }
 
 // Miscellaneous conversion functions
@@ -107,13 +100,13 @@
 		{
 			if (!ConvertFuncs::IsDigitsOnly(hoursStr))
 				return 0;
-			hours = convertTo<unsigned long>(hoursStr, false);
+			hours = convertTo<unsigned long>(hoursStr);
 		}
 		if (!minutesStr.empty())
 		{
 			if (!ConvertFuncs::IsDigitsOnly(minutesStr))
 				return 0;
-			minutes = convertTo<unsigned long>(minutesStr, false);
+			minutes = convertTo<unsigned long>(minutesStr);
 		}
 		if (!secondsStr.empty())
 		{
@@ -122,7 +115,7 @@
 			size_t comma = secondsStr.find(',');
 			if (comma != std::string::npos)
 				secondsStr[comma] = '.';
-			seconds = convertTo<double>(secondsStr, false);
+			seconds = convertTo<double>(secondsStr);
 		}
 		seconds += minutes * 60 + hours * 1440;
 		return static_cast<unsigned long>(std::floor(seconds * 1000 + 0.5));
@@ -137,14 +130,14 @@
 	{
 		double seconds = time / 1000.0;
 		if (seconds < 60)
-			return stringify(seconds);
+			return std::to_string(seconds);
 		unsigned long minutes = static_cast<unsigned long>(seconds) / 60;
 		seconds -= minutes * 60;
 		if (minutes < 60)
-			return stringify(minutes) + ":" + (seconds < 10 ? "0" : "") + stringify(seconds);
+			return std::to_string(minutes) + ":" + (seconds < 10 ? "0" : "") + std::to_string(seconds);
 		unsigned long hours = minutes / 60;
 		minutes %= 60;
-		return stringify(hours) + ":" + (minutes < 10 ? "0" : "") + stringify(minutes) + ":" + (seconds < 10 ? "0" : "") + stringify(seconds);
+		return std::to_string(hours) + ":" + (minutes < 10 ? "0" : "") + std::to_string(minutes) + ":" + (seconds < 10 ? "0" : "") + std::to_string(seconds);
 	}
 
 	static std::wstring MSToWString(unsigned long time)

--- a/src/in_xsf_framework/in_xsf.cpp
+++ b/src/in_xsf_framework/in_xsf.cpp
@@ -335,7 +335,7 @@
 				return 0;
 			}
 			else if (eqstr(tagToGet, "length"))
-				tag = stringify(file.GetLengthMS(xSFConfig->GetDefaultLength()) + file.GetFadeMS(xSFConfig->GetDefaultFade()));
+				tag = std::to_string(file.GetLengthMS(xSFConfig->GetDefaultLength()) + file.GetFadeMS(xSFConfig->GetDefaultFade()));
 			else
 				tag = file.GetTagValue(tagToGet);
 			CopyToString(tag.substr(0, destlen - 1), dest);