Index: common/versionNumber.h
===================================================================
--- common/versionNumber.h	(revision 14171)
+++ common/versionNumber.h	(working copy)
@@ -18,6 +18,6 @@
 #define VER_MAJORMAJOR  1
 #define VER_MAJOR      30
 #define VER_MINOR      00
-#define VER_MINORMINOR 27
+#define VER_MINORMINOR 28
 
 OPENMPT_NAMESPACE_END
Index: mptrack/MainFrm.cpp
===================================================================
--- mptrack/MainFrm.cpp	(revision 14175)
+++ mptrack/MainFrm.cpp	(working copy)
@@ -642,14 +642,15 @@
 }
 
 
+template <typename Tsample>
 class StereoVuMeterSourceWrapper
 	: public IAudioSource
 {
 private:
-	SoundDevice::BufferIO &bufferio;
+	SoundDevice::BufferIO<Tsample> &bufferio;
 	VUMeter &vumeter;
 public:
-	inline StereoVuMeterSourceWrapper(SoundDevice::BufferIO &bufferIO, VUMeter &vumeter)
+	inline StereoVuMeterSourceWrapper(SoundDevice::BufferIO<Tsample> &bufferIO, VUMeter &vumeter)
 		: bufferio(bufferIO)
 		, vumeter(vumeter)
 	{
@@ -670,14 +671,15 @@
 };
 
 
+template <typename Tsample>
 class StereoVuMeterTargetWrapper
 	: public IAudioReadTarget
 {
 private:
-	SoundDevice::BufferIO &bufferio;
+	SoundDevice::BufferIO<Tsample> &bufferio;
 	VUMeter &vumeter;
 public:
-	inline StereoVuMeterTargetWrapper(SoundDevice::BufferIO &bufferIO, VUMeter &vumeter)
+	inline StereoVuMeterTargetWrapper(SoundDevice::BufferIO<Tsample> &bufferIO, VUMeter &vumeter)
 		: bufferio(bufferIO)
 		, vumeter(vumeter)
 	{
@@ -711,7 +713,8 @@
 }
 
 
-void CMainFrame::SoundSourceLockedRead(SoundDevice::BufferFormat bufferFormat, std::size_t numFrames, void *buffer, const void *inputBuffer)
+template <typename Tsample>
+void CMainFrame::SoundSourceLockedReadImpl(SoundDevice::BufferFormat bufferFormat, std::size_t numFrames, Tsample *buffer, const Tsample *inputBuffer)
 {
 	MPT_TRACE_SCOPE();
 	MPT_ASSERT(InAudioThread());
@@ -719,9 +722,9 @@
 	MPT_ASSERT(numFrames <= std::numeric_limits<CSoundFile::samplecount_t>::max());
 	CSoundFile::samplecount_t framesToRender = static_cast<CSoundFile::samplecount_t>(numFrames);
 	m_Dither.SetMode((DitherMode)bufferFormat.DitherType);
-	SoundDevice::BufferIO bufferIO(buffer, inputBuffer, numFrames, m_Dither, bufferFormat);
-	StereoVuMeterSourceWrapper source(bufferIO, m_VUMeterInput);
-	StereoVuMeterTargetWrapper target(bufferIO, m_VUMeterOutput);
+	SoundDevice::BufferIO<Tsample> bufferIO(buffer, inputBuffer, numFrames, m_Dither, bufferFormat);
+	StereoVuMeterSourceWrapper<Tsample> source(bufferIO, m_VUMeterInput);
+	StereoVuMeterTargetWrapper<Tsample> target(bufferIO, m_VUMeterOutput);
 	CSoundFile::samplecount_t renderedFrames = m_pSndFile->Read(framesToRender, target, source);
 	MPT_ASSERT(renderedFrames <= framesToRender);
 	CSoundFile::samplecount_t remainingFrames = framesToRender - renderedFrames;
@@ -732,15 +735,51 @@
 		std::size_t frameSize = bufferFormat.Channels * (bufferFormat.sampleFormat.GetBitsPerSample()/8);
 		if(bufferFormat.sampleFormat.IsUnsigned())
 		{
-			std::memset(mpt::void_cast<std::byte*>(buffer) + renderedFrames * frameSize, 0x80, remainingFrames * frameSize);
+			std::memset(buffer + renderedFrames * bufferFormat.Channels, 0x80, remainingFrames * frameSize);
 		} else
 		{
-			std::memset(mpt::void_cast<std::byte*>(buffer) + renderedFrames * frameSize, 0, remainingFrames * frameSize);
+			std::memset(buffer + renderedFrames * bufferFormat.Channels, 0, remainingFrames * frameSize);
 		}
 	}
 }
 
 
+void CMainFrame::SoundSourceLockedRead(SoundDevice::BufferFormat bufferFormat, std::size_t numFrames, uint8 *buffer, const uint8 *inputBuffer)
+{
+	SoundSourceLockedReadImpl(bufferFormat, numFrames, buffer, inputBuffer);
+}
+
+void CMainFrame::SoundSourceLockedRead(SoundDevice::BufferFormat bufferFormat, std::size_t numFrames, int8 *buffer, const int8 *inputBuffer)
+{
+	SoundSourceLockedReadImpl(bufferFormat, numFrames, buffer, inputBuffer);
+}
+
+void CMainFrame::SoundSourceLockedRead(SoundDevice::BufferFormat bufferFormat, std::size_t numFrames, int16 *buffer, const int16 *inputBuffer)
+{
+	SoundSourceLockedReadImpl(bufferFormat, numFrames, buffer, inputBuffer);
+}
+
+void CMainFrame::SoundSourceLockedRead(SoundDevice::BufferFormat bufferFormat, std::size_t numFrames, int24 *buffer, const int24 *inputBuffer)
+{
+	SoundSourceLockedReadImpl(bufferFormat, numFrames, buffer, inputBuffer);
+}
+
+void CMainFrame::SoundSourceLockedRead(SoundDevice::BufferFormat bufferFormat, std::size_t numFrames, int32 *buffer, const int32 *inputBuffer)
+{
+	SoundSourceLockedReadImpl(bufferFormat, numFrames, buffer, inputBuffer);
+}
+
+void CMainFrame::SoundSourceLockedRead(SoundDevice::BufferFormat bufferFormat, std::size_t numFrames, float *buffer, const float *inputBuffer)
+{
+	SoundSourceLockedReadImpl(bufferFormat, numFrames, buffer, inputBuffer);
+}
+
+void CMainFrame::SoundSourceLockedRead(SoundDevice::BufferFormat bufferFormat, std::size_t numFrames, double *buffer, const double *inputBuffer)
+{
+	SoundSourceLockedReadImpl(bufferFormat, numFrames, buffer, inputBuffer);
+}
+
+
 void CMainFrame::SoundSourceLockedReadDone(SoundDevice::TimeInfo timeInfo)
 {
 	MPT_TRACE_SCOPE();
Index: mptrack/Mainfrm.h
===================================================================
--- mptrack/Mainfrm.h	(revision 14171)
+++ mptrack/Mainfrm.h	(working copy)
@@ -341,7 +341,15 @@
 	void SoundSourceLock() override;
 	uint64 SoundSourceLockedGetReferenceClockNowNanoseconds() const override;
 	void SoundSourceLockedReadPrepare(SoundDevice::TimeInfo timeInfo) override;
-	void SoundSourceLockedRead(SoundDevice::BufferFormat bufferFormat, std::size_t numFrames, void *buffer, const void *inputBuffer) override;
+	template <typename Tsample>
+	void SoundSourceLockedReadImpl(SoundDevice::BufferFormat bufferFormat, std::size_t numFrames, Tsample *buffer, const Tsample *inputBuffer);
+	void SoundSourceLockedRead(SoundDevice::BufferFormat bufferFormat, std::size_t numFrames, uint8 *buffer, const uint8 *inputBuffer) override;
+	void SoundSourceLockedRead(SoundDevice::BufferFormat bufferFormat, std::size_t numFrames, int8 *buffer, const int8 *inputBuffer) override;
+	void SoundSourceLockedRead(SoundDevice::BufferFormat bufferFormat, std::size_t numFrames, int16 *buffer, const int16 *inputBuffer) override;
+	void SoundSourceLockedRead(SoundDevice::BufferFormat bufferFormat, std::size_t numFrames, int24 *buffer, const int24 *inputBuffer) override;
+	void SoundSourceLockedRead(SoundDevice::BufferFormat bufferFormat, std::size_t numFrames, int32 *buffer, const int32 *inputBuffer) override;
+	void SoundSourceLockedRead(SoundDevice::BufferFormat bufferFormat, std::size_t numFrames, float *buffer, const float *inputBuffer) override;
+	void SoundSourceLockedRead(SoundDevice::BufferFormat bufferFormat, std::size_t numFrames, double *buffer, const double *inputBuffer) override;
 	void SoundSourceLockedReadDone(SoundDevice::TimeInfo timeInfo) override;
 	void SoundSourceUnlock() override;
 
Index: mptrack/MPTrackWine.h
===================================================================
--- mptrack/MPTrackWine.h	(revision 14171)
+++ mptrack/MPTrackWine.h	(working copy)
@@ -18,6 +18,8 @@
 
 extern "C" {
 
+typedef void OpenMPT_int24;
+
 typedef struct OpenMPT_SoundDevice_StreamPosition OpenMPT_SoundDevice_StreamPosition;
 typedef struct OpenMPT_SoundDevice_TimeInfo OpenMPT_SoundDevice_TimeInfo;
 typedef struct OpenMPT_SoundDevice_Flags OpenMPT_SoundDevice_Flags;
@@ -42,7 +44,13 @@
 	void (__cdecl * SoundSourceLockFunc)( void * inst );
 	void (__cdecl * SoundSourceLockedGetReferenceClockNowNanosecondsFunc)( void * inst, uint64_t * result );
 	void (__cdecl * SoundSourceLockedReadPrepareFunc)( void * inst, const OpenMPT_SoundDevice_TimeInfo * timeInfo );
-	void (__cdecl * SoundSourceLockedReadFunc)( void * inst, const OpenMPT_SoundDevice_BufferFormat * bufferFormat, uintptr_t numFrames, void * buffer, const void * inputBuffer );
+	void (__cdecl * SoundSourceLockedReadUint8Func)( void * inst, const OpenMPT_SoundDevice_BufferFormat * bufferFormat, uintptr_t numFrames, uint8_t * buffer, const uint8_t * inputBuffer );
+	void (__cdecl * SoundSourceLockedReadInt8Func)( void * inst, const OpenMPT_SoundDevice_BufferFormat * bufferFormat, uintptr_t numFrames, int8_t * buffer, const int8_t * inputBuffer );
+	void (__cdecl * SoundSourceLockedReadInt16Func)( void * inst, const OpenMPT_SoundDevice_BufferFormat * bufferFormat, uintptr_t numFrames, int16_t * buffer, const int16_t * inputBuffer );
+	void (__cdecl * SoundSourceLockedReadInt24Func)( void * inst, const OpenMPT_SoundDevice_BufferFormat * bufferFormat, uintptr_t numFrames, OpenMPT_int24 * buffer, const OpenMPT_int24 * inputBuffer );
+	void (__cdecl * SoundSourceLockedReadInt32Func)( void * inst, const OpenMPT_SoundDevice_BufferFormat * bufferFormat, uintptr_t numFrames, int32_t * buffer, const int32_t * inputBuffer );
+	void (__cdecl * SoundSourceLockedReadFloatFunc)( void * inst, const OpenMPT_SoundDevice_BufferFormat * bufferFormat, uintptr_t numFrames, float * buffer, const float * inputBuffer );
+	void (__cdecl * SoundSourceLockedReadDoubleFunc)( void * inst, const OpenMPT_SoundDevice_BufferFormat * bufferFormat, uintptr_t numFrames, double * buffer, const double * inputBuffer );
 	void (__cdecl * SoundSourceLockedReadDoneFunc)( void * inst, const OpenMPT_SoundDevice_TimeInfo * timeInfo );
 	void (__cdecl * SoundSourceUnlockFunc)( void * inst );
 } OpenMPT_Wine_Wrapper_SoundDevice_ISource;
Index: mptrack/wine/NativeSoundDevice.cpp
===================================================================
--- mptrack/wine/NativeSoundDevice.cpp	(revision 14171)
+++ mptrack/wine/NativeSoundDevice.cpp	(working copy)
@@ -215,15 +215,69 @@
 		OpenMPT_SoundDevice_TimeInfo c_timeInfo = C::encode(timeInfo);
 		return impl.SoundSourceLockedReadPrepareFunc(impl.inst, &c_timeInfo);
 	}
-	virtual void SoundSourceLockedRead(SoundDevice::BufferFormat bufferFormat, std::size_t numFrames, void *buffer, const void *inputBuffer)
+	virtual void SoundSourceLockedRead(SoundDevice::BufferFormat bufferFormat, std::size_t numFrames, uint8 *buffer, const uint8 *inputBuffer)
 	{
-		if(!impl.SoundSourceLockedReadFunc)
+		if(!impl.SoundSourceLockedReadUint8Func)
 		{
 			return;
 		}
 		OpenMPT_SoundDevice_BufferFormat c_bufferFormat = C::encode(bufferFormat);
-		return impl.SoundSourceLockedReadFunc(impl.inst, &c_bufferFormat, numFrames, buffer, inputBuffer);
+		return impl.SoundSourceLockedReadUint8Func(impl.inst, &c_bufferFormat, numFrames, buffer, inputBuffer);
 	}
+	virtual void SoundSourceLockedRead(SoundDevice::BufferFormat bufferFormat, std::size_t numFrames, int8 *buffer, const int8 *inputBuffer)
+	{
+		if(!impl.SoundSourceLockedReadInt8Func)
+		{
+			return;
+		}
+		OpenMPT_SoundDevice_BufferFormat c_bufferFormat = C::encode(bufferFormat);
+		return impl.SoundSourceLockedReadInt8Func(impl.inst, &c_bufferFormat, numFrames, buffer, inputBuffer);
+	}
+	virtual void SoundSourceLockedRead(SoundDevice::BufferFormat bufferFormat, std::size_t numFrames, int16 *buffer, const int16 *inputBuffer)
+	{
+		if(!impl.SoundSourceLockedReadInt16Func)
+		{
+			return;
+		}
+		OpenMPT_SoundDevice_BufferFormat c_bufferFormat = C::encode(bufferFormat);
+		return impl.SoundSourceLockedReadInt16Func(impl.inst, &c_bufferFormat, numFrames, buffer, inputBuffer);
+	}
+	virtual void SoundSourceLockedRead(SoundDevice::BufferFormat bufferFormat, std::size_t numFrames, int24 *buffer, const int24 *inputBuffer)
+	{
+		if(!impl.SoundSourceLockedReadInt24Func)
+		{
+			return;
+		}
+		OpenMPT_SoundDevice_BufferFormat c_bufferFormat = C::encode(bufferFormat);
+		return impl.SoundSourceLockedReadInt24Func(impl.inst, &c_bufferFormat, numFrames, buffer, inputBuffer);
+	}
+	virtual void SoundSourceLockedRead(SoundDevice::BufferFormat bufferFormat, std::size_t numFrames, int32 *buffer, const int32 *inputBuffer)
+	{
+		if(!impl.SoundSourceLockedReadInt32Func)
+		{
+			return;
+		}
+		OpenMPT_SoundDevice_BufferFormat c_bufferFormat = C::encode(bufferFormat);
+		return impl.SoundSourceLockedReadInt32Func(impl.inst, &c_bufferFormat, numFrames, buffer, inputBuffer);
+	}
+	virtual void SoundSourceLockedRead(SoundDevice::BufferFormat bufferFormat, std::size_t numFrames, float *buffer, const float *inputBuffer)
+	{
+		if(!impl.SoundSourceLockedReadFloatFunc)
+		{
+			return;
+		}
+		OpenMPT_SoundDevice_BufferFormat c_bufferFormat = C::encode(bufferFormat);
+		return impl.SoundSourceLockedReadFloatFunc(impl.inst, &c_bufferFormat, numFrames, buffer, inputBuffer);
+	}
+	virtual void SoundSourceLockedRead(SoundDevice::BufferFormat bufferFormat, std::size_t numFrames, double *buffer, const double *inputBuffer)
+	{
+		if(!impl.SoundSourceLockedReadDoubleFunc)
+		{
+			return;
+		}
+		OpenMPT_SoundDevice_BufferFormat c_bufferFormat = C::encode(bufferFormat);
+		return impl.SoundSourceLockedReadDoubleFunc(impl.inst, &c_bufferFormat, numFrames, buffer, inputBuffer);
+	}
 	virtual void SoundSourceLockedReadDone(SoundDevice::TimeInfo timeInfo)
 	{
 		if(!impl.SoundSourceLockedReadDoneFunc)
Index: mptrack/wine/NativeSoundDevice.h
===================================================================
--- mptrack/wine/NativeSoundDevice.h	(revision 14171)
+++ mptrack/wine/NativeSoundDevice.h	(working copy)
@@ -12,6 +12,8 @@
 
 OPENMPT_WINESUPPORT_API char * OPENMPT_WINESUPPORT_CALL OpenMPT_SoundDevice_EnumerateDevices();
 
+typedef void OpenMPT_int24;
+
 typedef struct OpenMPT_SoundDevice_StreamPosition {
 	int64_t Frames;
 	double Seconds;
@@ -76,7 +78,13 @@
 	void (OPENMPT_WINESUPPORT_CALL * SoundSourceLockFunc)( void * inst );
 	void (OPENMPT_WINESUPPORT_CALL * SoundSourceLockedGetReferenceClockNowNanosecondsFunc)( void * inst, uint64_t * result );
 	void (OPENMPT_WINESUPPORT_CALL * SoundSourceLockedReadPrepareFunc)( void * inst, const OpenMPT_SoundDevice_TimeInfo * timeInfo );
-	void (OPENMPT_WINESUPPORT_CALL * SoundSourceLockedReadFunc)( void * inst, const OpenMPT_SoundDevice_BufferFormat * bufferFormat, uintptr_t numFrames, void * buffer, const void * inputBuffer );
+	void (OPENMPT_WINESUPPORT_CALL * SoundSourceLockedReadUint8Func)( void * inst, const OpenMPT_SoundDevice_BufferFormat * bufferFormat, uintptr_t numFrames, uint8_t * buffer, const uint8_t * inputBuffer );
+	void (OPENMPT_WINESUPPORT_CALL * SoundSourceLockedReadInt8Func)( void * inst, const OpenMPT_SoundDevice_BufferFormat * bufferFormat, uintptr_t numFrames, int8_t * buffer, const int8_t * inputBuffer );
+	void (OPENMPT_WINESUPPORT_CALL * SoundSourceLockedReadInt16Func)( void * inst, const OpenMPT_SoundDevice_BufferFormat * bufferFormat, uintptr_t numFrames, int16_t * buffer, const int16_t * inputBuffer );
+	void (OPENMPT_WINESUPPORT_CALL * SoundSourceLockedReadInt24Func)( void * inst, const OpenMPT_SoundDevice_BufferFormat * bufferFormat, uintptr_t numFrames, OpenMPT_int24 * buffer, const OpenMPT_int24 * inputBuffer );
+	void (OPENMPT_WINESUPPORT_CALL * SoundSourceLockedReadInt32Func)( void * inst, const OpenMPT_SoundDevice_BufferFormat * bufferFormat, uintptr_t numFrames, int32_t * buffer, const int32_t * inputBuffer );
+	void (OPENMPT_WINESUPPORT_CALL * SoundSourceLockedReadFloatFunc)( void * inst, const OpenMPT_SoundDevice_BufferFormat * bufferFormat, uintptr_t numFrames, float * buffer, const float * inputBuffer );
+	void (OPENMPT_WINESUPPORT_CALL * SoundSourceLockedReadDoubleFunc)( void * inst, const OpenMPT_SoundDevice_BufferFormat * bufferFormat, uintptr_t numFrames, double * buffer, const double * inputBuffer );
 	void (OPENMPT_WINESUPPORT_CALL * SoundSourceLockedReadDoneFunc)( void * inst, const OpenMPT_SoundDevice_TimeInfo * timeInfo );
 	void (OPENMPT_WINESUPPORT_CALL * SoundSourceUnlockFunc)( void * inst );
 } OpenMPT_SoundDevice_ISource;
Index: mptrack/wine/WineWrapper.c
===================================================================
--- mptrack/wine/WineWrapper.c	(revision 14171)
+++ mptrack/wine/WineWrapper.c	(working copy)
@@ -69,7 +69,13 @@
 	void (OPENMPT_WINESUPPORT_WRAPPER_CALL * SoundSourceLockFunc)( void * inst );
 	void (OPENMPT_WINESUPPORT_WRAPPER_CALL * SoundSourceLockedGetReferenceClockNowNanosecondsFunc)( void * inst, uint64_t * result );
 	void (OPENMPT_WINESUPPORT_WRAPPER_CALL * SoundSourceLockedReadPrepareFunc)( void * inst, const OpenMPT_SoundDevice_TimeInfo * timeInfo );
-	void (OPENMPT_WINESUPPORT_WRAPPER_CALL * SoundSourceLockedReadFunc)( void * inst, const OpenMPT_SoundDevice_BufferFormat * bufferFormat, uintptr_t numFrames, void * buffer, const void * inputBuffer );
+	void (OPENMPT_WINESUPPORT_WRAPPER_CALL * SoundSourceLockedReadUint8Func)( void * inst, const OpenMPT_SoundDevice_BufferFormat * bufferFormat, uintptr_t numFrames, uint8_t * buffer, const uint8_t * inputBuffer );
+	void (OPENMPT_WINESUPPORT_WRAPPER_CALL * SoundSourceLockedReadInt8Func)( void * inst, const OpenMPT_SoundDevice_BufferFormat * bufferFormat, uintptr_t numFrames, int8_t * buffer, const int8_t * inputBuffer );
+	void (OPENMPT_WINESUPPORT_WRAPPER_CALL * SoundSourceLockedReadInt16Func)( void * inst, const OpenMPT_SoundDevice_BufferFormat * bufferFormat, uintptr_t numFrames, int16_t * buffer, const int16_t * inputBuffer );
+	void (OPENMPT_WINESUPPORT_WRAPPER_CALL * SoundSourceLockedReadInt24Func)( void * inst, const OpenMPT_SoundDevice_BufferFormat * bufferFormat, uintptr_t numFrames, OpenMPT_int24 * buffer, const OpenMPT_int24 * inputBuffer );
+	void (OPENMPT_WINESUPPORT_WRAPPER_CALL * SoundSourceLockedReadInt32Func)( void * inst, const OpenMPT_SoundDevice_BufferFormat * bufferFormat, uintptr_t numFrames, int32_t * buffer, const int32_t * inputBuffer );
+	void (OPENMPT_WINESUPPORT_WRAPPER_CALL * SoundSourceLockedReadFloatFunc)( void * inst, const OpenMPT_SoundDevice_BufferFormat * bufferFormat, uintptr_t numFrames, float * buffer, const float * inputBuffer );
+	void (OPENMPT_WINESUPPORT_WRAPPER_CALL * SoundSourceLockedReadDoubleFunc)( void * inst, const OpenMPT_SoundDevice_BufferFormat * bufferFormat, uintptr_t numFrames, double * buffer, const double * inputBuffer );
 	void (OPENMPT_WINESUPPORT_WRAPPER_CALL * SoundSourceLockedReadDoneFunc)( void * inst, const OpenMPT_SoundDevice_TimeInfo * timeInfo );
 	void (OPENMPT_WINESUPPORT_WRAPPER_CALL * SoundSourceUnlockFunc)( void * inst );
 } OpenMPT_Wine_Wrapper_SoundDevice_ISource;
@@ -81,9 +87,15 @@
 	, AudioThreadCommandLock        = 1
 	, AudioThreadCommandClock       = 2
 	, AudioThreadCommandReadPrepare = 3
-	, AudioThreadCommandRead        = 4
-	, AudioThreadCommandReadDone    = 5
-	, AudioThreadCommandUnlock      = 6
+	, AudioThreadCommandReadUint8   = 4
+	, AudioThreadCommandReadInt8    = 5
+	, AudioThreadCommandReadInt16   = 6
+	, AudioThreadCommandReadInt24   = 7
+	, AudioThreadCommandReadInt32   = 8
+	, AudioThreadCommandReadFloat   = 9
+	, AudioThreadCommandReadDouble  = 10
+	, AudioThreadCommandReadDone    = 11
+	, AudioThreadCommandUnlock      = 12
 } OpenMPT_Wine_Wrapper_AudioThreadCommand;
 #endif
 
@@ -102,8 +114,24 @@
 	const OpenMPT_SoundDevice_BufferFormat * audiothread_command_bufferFormat;
 	const OpenMPT_SoundDevice_BufferAttributes * audiothread_command_bufferAttributes;
 	uintptr_t audiothread_command_numFrames;
-	void * audiothread_command_buffer;
-	const void * audiothread_command_inputBuffer;
+	union {
+		uint8_t * buf_uint8;
+		int8_t * buf_int8;
+		int16_t * buf_int16;
+		OpenMPT_int24 * buf_int24;
+		int32_t * buf_int32;
+		float * buf_float;
+		double * buf_double;
+	} audiothread_command_buffer;
+	union {
+		const uint8_t * buf_uint8;
+		const int8_t * buf_int8;
+		const int16_t * buf_int16;
+		const OpenMPT_int24 * buf_int24;
+		const int32_t * buf_int32;
+		const float * buf_float;
+		const double * buf_double;
+	} audiothread_command_inputBuffer;
 	uint64_t * audiothread_command_result;
 	HANDLE audiothread;
 	OpenMPT_PriorityBooster * priority_booster;
@@ -187,23 +215,125 @@
 	return sd->wine_source.SoundSourceLockedReadPrepareFunc( sd->wine_source.inst, timeInfo );
 #endif
 }
-static void OPENMPT_WINESUPPORT_CALL SoundSourceLockedReadFunc( void * inst, const OpenMPT_SoundDevice_BufferFormat * bufferFormat, uintptr_t numFrames, void * buffer, const void * inputBuffer ) {
+static void OPENMPT_WINESUPPORT_CALL SoundSourceLockedReadUint8Func( void * inst, const OpenMPT_SoundDevice_BufferFormat * bufferFormat, uintptr_t numFrames, uint8_t * buffer, const uint8_t * inputBuffer ) {
 	OpenMPT_Wine_Wrapper_SoundDevice * sd = (OpenMPT_Wine_Wrapper_SoundDevice*)inst;
 	if ( !sd ) {
 		return;
 	}
 #ifdef WINE_THREAD
-	sd->audiothread_command = AudioThreadCommandRead;
+	sd->audiothread_command = AudioThreadCommandReadUint8;
 	sd->audiothread_command_bufferFormat = bufferFormat;
 	sd->audiothread_command_numFrames = numFrames;
-	sd->audiothread_command_buffer = buffer;
-	sd->audiothread_command_inputBuffer = inputBuffer;
+	sd->audiothread_command_buffer.buf_uint8 = buffer;
+	sd->audiothread_command_inputBuffer.buf_uint8 = inputBuffer;
 	OpenMPT_Semaphore_Post( sd->audiothread_sem_request );
 	OpenMPT_Semaphore_Wait( sd->audiothread_sem_done );
 #else
-	return sd->wine_source.SoundSourceLockedReadFunc( sd->wine_source.inst, bufferFormat, bufferAttributes, numFrames, buffer, inputBuffer );
+	return sd->wine_source.SoundSourceLockedReadUint8Func( sd->wine_source.inst, bufferFormat, bufferAttributes, numFrames, buffer, inputBuffer );
 #endif
 }
+static void OPENMPT_WINESUPPORT_CALL SoundSourceLockedReadInt8Func( void * inst, const OpenMPT_SoundDevice_BufferFormat * bufferFormat, uintptr_t numFrames, int8_t * buffer, const int8_t * inputBuffer ) {
+	OpenMPT_Wine_Wrapper_SoundDevice * sd = (OpenMPT_Wine_Wrapper_SoundDevice*)inst;
+	if ( !sd ) {
+		return;
+	}
+#ifdef WINE_THREAD
+	sd->audiothread_command = AudioThreadCommandReadInt8;
+	sd->audiothread_command_bufferFormat = bufferFormat;
+	sd->audiothread_command_numFrames = numFrames;
+	sd->audiothread_command_buffer.buf_int8 = buffer;
+	sd->audiothread_command_inputBuffer.buf_int8 = inputBuffer;
+	OpenMPT_Semaphore_Post( sd->audiothread_sem_request );
+	OpenMPT_Semaphore_Wait( sd->audiothread_sem_done );
+#else
+	return sd->wine_source.SoundSourceLockedReadInt8Func( sd->wine_source.inst, bufferFormat, bufferAttributes, numFrames, buffer, inputBuffer );
+#endif
+}
+static void OPENMPT_WINESUPPORT_CALL SoundSourceLockedReadInt16Func( void * inst, const OpenMPT_SoundDevice_BufferFormat * bufferFormat, uintptr_t numFrames, int16_t * buffer, const int16_t * inputBuffer ) {
+	OpenMPT_Wine_Wrapper_SoundDevice * sd = (OpenMPT_Wine_Wrapper_SoundDevice*)inst;
+	if ( !sd ) {
+		return;
+	}
+#ifdef WINE_THREAD
+	sd->audiothread_command = AudioThreadCommandReadInt16;
+	sd->audiothread_command_bufferFormat = bufferFormat;
+	sd->audiothread_command_numFrames = numFrames;
+	sd->audiothread_command_buffer.buf_int16 = buffer;
+	sd->audiothread_command_inputBuffer.buf_int16 = inputBuffer;
+	OpenMPT_Semaphore_Post( sd->audiothread_sem_request );
+	OpenMPT_Semaphore_Wait( sd->audiothread_sem_done );
+#else
+	return sd->wine_source.SoundSourceLockedReadInt16Func( sd->wine_source.inst, bufferFormat, bufferAttributes, numFrames, buffer, inputBuffer );
+#endif
+}
+static void OPENMPT_WINESUPPORT_CALL SoundSourceLockedReadInt24Func( void * inst, const OpenMPT_SoundDevice_BufferFormat * bufferFormat, uintptr_t numFrames, OpenMPT_int24 * buffer, const OpenMPT_int24 * inputBuffer ) {
+	OpenMPT_Wine_Wrapper_SoundDevice * sd = (OpenMPT_Wine_Wrapper_SoundDevice*)inst;
+	if ( !sd ) {
+		return;
+	}
+#ifdef WINE_THREAD
+	sd->audiothread_command = AudioThreadCommandReadInt24;
+	sd->audiothread_command_bufferFormat = bufferFormat;
+	sd->audiothread_command_numFrames = numFrames;
+	sd->audiothread_command_buffer.buf_int24 = buffer;
+	sd->audiothread_command_inputBuffer.buf_int24 = inputBuffer;
+	OpenMPT_Semaphore_Post( sd->audiothread_sem_request );
+	OpenMPT_Semaphore_Wait( sd->audiothread_sem_done );
+#else
+	return sd->wine_source.SoundSourceLockedReadInt24Func( sd->wine_source.inst, bufferFormat, bufferAttributes, numFrames, buffer, inputBuffer );
+#endif
+}
+static void OPENMPT_WINESUPPORT_CALL SoundSourceLockedReadInt32Func( void * inst, const OpenMPT_SoundDevice_BufferFormat * bufferFormat, uintptr_t numFrames, int32_t * buffer, const int32_t * inputBuffer ) {
+	OpenMPT_Wine_Wrapper_SoundDevice * sd = (OpenMPT_Wine_Wrapper_SoundDevice*)inst;
+	if ( !sd ) {
+		return;
+	}
+#ifdef WINE_THREAD
+	sd->audiothread_command = AudioThreadCommandReadInt32;
+	sd->audiothread_command_bufferFormat = bufferFormat;
+	sd->audiothread_command_numFrames = numFrames;
+	sd->audiothread_command_buffer.buf_int32 = buffer;
+	sd->audiothread_command_inputBuffer.buf_int32 = inputBuffer;
+	OpenMPT_Semaphore_Post( sd->audiothread_sem_request );
+	OpenMPT_Semaphore_Wait( sd->audiothread_sem_done );
+#else
+	return sd->wine_source.SoundSourceLockedReadInt32Func( sd->wine_source.inst, bufferFormat, bufferAttributes, numFrames, buffer, inputBuffer );
+#endif
+}
+static void OPENMPT_WINESUPPORT_CALL SoundSourceLockedReadFloatFunc( void * inst, const OpenMPT_SoundDevice_BufferFormat * bufferFormat, uintptr_t numFrames, float * buffer, const float * inputBuffer ) {
+	OpenMPT_Wine_Wrapper_SoundDevice * sd = (OpenMPT_Wine_Wrapper_SoundDevice*)inst;
+	if ( !sd ) {
+		return;
+	}
+#ifdef WINE_THREAD
+	sd->audiothread_command = AudioThreadCommandReadFloat;
+	sd->audiothread_command_bufferFormat = bufferFormat;
+	sd->audiothread_command_numFrames = numFrames;
+	sd->audiothread_command_buffer.buf_float = buffer;
+	sd->audiothread_command_inputBuffer.buf_float = inputBuffer;
+	OpenMPT_Semaphore_Post( sd->audiothread_sem_request );
+	OpenMPT_Semaphore_Wait( sd->audiothread_sem_done );
+#else
+	return sd->wine_source.SoundSourceLockedReadFloatFunc( sd->wine_source.inst, bufferFormat, bufferAttributes, numFrames, buffer, inputBuffer );
+#endif
+}
+static void OPENMPT_WINESUPPORT_CALL SoundSourceLockedReadDoubleFunc( void * inst, const OpenMPT_SoundDevice_BufferFormat * bufferFormat, uintptr_t numFrames, double * buffer, const double * inputBuffer ) {
+	OpenMPT_Wine_Wrapper_SoundDevice * sd = (OpenMPT_Wine_Wrapper_SoundDevice*)inst;
+	if ( !sd ) {
+		return;
+	}
+#ifdef WINE_THREAD
+	sd->audiothread_command = AudioThreadCommandReadDouble;
+	sd->audiothread_command_bufferFormat = bufferFormat;
+	sd->audiothread_command_numFrames = numFrames;
+	sd->audiothread_command_buffer.buf_double = buffer;
+	sd->audiothread_command_inputBuffer.buf_double = inputBuffer;
+	OpenMPT_Semaphore_Post( sd->audiothread_sem_request );
+	OpenMPT_Semaphore_Wait( sd->audiothread_sem_done );
+#else
+	return sd->wine_source.SoundSourceLockedReadDoubleFunc( sd->wine_source.inst, bufferFormat, bufferAttributes, numFrames, buffer, inputBuffer );
+#endif
+}
 static void OPENMPT_WINESUPPORT_CALL SoundSourceLockedReadDoneFunc( void * inst, const OpenMPT_SoundDevice_TimeInfo * timeInfo ) {
 	OpenMPT_Wine_Wrapper_SoundDevice * sd = (OpenMPT_Wine_Wrapper_SoundDevice*)inst;
 	if ( !sd ) {
@@ -261,16 +391,76 @@
 						, sd->audiothread_command_timeInfo
 						);
 				break;
-			case AudioThreadCommandRead:
-				if(sd->wine_source.SoundSourceLockedReadFunc)
-					sd->wine_source.SoundSourceLockedReadFunc
+			case AudioThreadCommandReadUint8:
+				if(sd->wine_source.SoundSourceLockedReadUint8Func)
+					sd->wine_source.SoundSourceLockedReadUint8Func
 						( sd->wine_source.inst
 						, sd->audiothread_command_bufferFormat
 						, sd->audiothread_command_numFrames
-						, sd->audiothread_command_buffer
-						, sd->audiothread_command_inputBuffer
+						, sd->audiothread_command_buffer.buf_uint8
+						, sd->audiothread_command_inputBuffer.buf_uint8
 						);
 				break;
+			case AudioThreadCommandReadInt8:
+				if(sd->wine_source.SoundSourceLockedReadInt8Func)
+					sd->wine_source.SoundSourceLockedReadInt8Func
+						( sd->wine_source.inst
+						, sd->audiothread_command_bufferFormat
+						, sd->audiothread_command_numFrames
+						, sd->audiothread_command_buffer.buf_int8
+						, sd->audiothread_command_inputBuffer.buf_int8
+						);
+				break;
+			case AudioThreadCommandReadInt16:
+				if(sd->wine_source.SoundSourceLockedReadInt16Func)
+					sd->wine_source.SoundSourceLockedReadInt16Func
+						( sd->wine_source.inst
+						, sd->audiothread_command_bufferFormat
+						, sd->audiothread_command_numFrames
+						, sd->audiothread_command_buffer.buf_int16
+						, sd->audiothread_command_inputBuffer.buf_int16
+						);
+				break;
+			case AudioThreadCommandReadInt24:
+				if(sd->wine_source.SoundSourceLockedReadInt24Func)
+					sd->wine_source.SoundSourceLockedReadInt24Func
+						( sd->wine_source.inst
+						, sd->audiothread_command_bufferFormat
+						, sd->audiothread_command_numFrames
+						, sd->audiothread_command_buffer.buf_int24
+						, sd->audiothread_command_inputBuffer.buf_int24
+						);
+				break;
+			case AudioThreadCommandReadInt32:
+				if(sd->wine_source.SoundSourceLockedReadInt32Func)
+					sd->wine_source.SoundSourceLockedReadInt32Func
+						( sd->wine_source.inst
+						, sd->audiothread_command_bufferFormat
+						, sd->audiothread_command_numFrames
+						, sd->audiothread_command_buffer.buf_int32
+						, sd->audiothread_command_inputBuffer.buf_int32
+						);
+				break;
+			case AudioThreadCommandReadFloat:
+				if(sd->wine_source.SoundSourceLockedReadFloatFunc)
+					sd->wine_source.SoundSourceLockedReadFloatFunc
+						( sd->wine_source.inst
+						, sd->audiothread_command_bufferFormat
+						, sd->audiothread_command_numFrames
+						, sd->audiothread_command_buffer.buf_float
+						, sd->audiothread_command_inputBuffer.buf_float
+						);
+				break;
+			case AudioThreadCommandReadDouble:
+				if(sd->wine_source.SoundSourceLockedReadDoubleFunc)
+					sd->wine_source.SoundSourceLockedReadDoubleFunc
+						( sd->wine_source.inst
+						, sd->audiothread_command_bufferFormat
+						, sd->audiothread_command_numFrames
+						, sd->audiothread_command_buffer.buf_double
+						, sd->audiothread_command_inputBuffer.buf_double
+						);
+				break;
 			case AudioThreadCommandReadDone:
 				if(sd->wine_source.SoundSourceLockedReadDoneFunc)
 					sd->wine_source.SoundSourceLockedReadDoneFunc
@@ -333,7 +523,13 @@
 	sd->native_source.SoundSourceLockFunc = &SoundSourceLockFunc;
 	sd->native_source.SoundSourceLockedGetReferenceClockNowNanosecondsFunc = &SoundSourceLockedGetReferenceClockNowNanosecondsFunc;
 	sd->native_source.SoundSourceLockedReadPrepareFunc = &SoundSourceLockedReadPrepareFunc;
-	sd->native_source.SoundSourceLockedReadFunc = &SoundSourceLockedReadFunc;
+	sd->native_source.SoundSourceLockedReadUint8Func = &SoundSourceLockedReadUint8Func;
+	sd->native_source.SoundSourceLockedReadInt8Func = &SoundSourceLockedReadInt8Func;
+	sd->native_source.SoundSourceLockedReadInt16Func = &SoundSourceLockedReadInt16Func;
+	sd->native_source.SoundSourceLockedReadInt24Func = &SoundSourceLockedReadInt24Func;
+	sd->native_source.SoundSourceLockedReadInt32Func = &SoundSourceLockedReadInt32Func;
+	sd->native_source.SoundSourceLockedReadFloatFunc = &SoundSourceLockedReadFloatFunc;
+	sd->native_source.SoundSourceLockedReadDoubleFunc = &SoundSourceLockedReadDoubleFunc;
 	sd->native_source.SoundSourceLockedReadDoneFunc = &SoundSourceLockedReadDoneFunc;
 	sd->native_source.SoundSourceUnlockFunc = &SoundSourceUnlockFunc;
 	OpenMPT_SoundDevice_SetSource( sd->impl, &sd->native_source );
Index: sounddev/SoundDevice.h
===================================================================
--- sounddev/SoundDevice.h	(revision 14171)
+++ sounddev/SoundDevice.h	(working copy)
@@ -92,7 +92,13 @@
 	virtual void SoundSourceLock() = 0;
 	virtual uint64 SoundSourceLockedGetReferenceClockNowNanoseconds() const = 0; // timeGetTime()*1000000 on Windows
 	virtual void SoundSourceLockedReadPrepare(SoundDevice::TimeInfo timeInfo) = 0;
-	virtual void SoundSourceLockedRead(SoundDevice::BufferFormat bufferFormat, std::size_t numFrames, void *buffer, const void *inputBuffer) = 0;
+	virtual void SoundSourceLockedRead(SoundDevice::BufferFormat bufferFormat, std::size_t numFrames, uint8 *buffer, const uint8 *inputBuffer) = 0;
+	virtual void SoundSourceLockedRead(SoundDevice::BufferFormat bufferFormat, std::size_t numFrames, int8 *buffer, const int8 *inputBuffer) = 0;
+	virtual void SoundSourceLockedRead(SoundDevice::BufferFormat bufferFormat, std::size_t numFrames, int16 *buffer, const int16 *inputBuffer) = 0;
+	virtual void SoundSourceLockedRead(SoundDevice::BufferFormat bufferFormat, std::size_t numFrames, int24 *buffer, const int24 *inputBuffer) = 0;
+	virtual void SoundSourceLockedRead(SoundDevice::BufferFormat bufferFormat, std::size_t numFrames, int32 *buffer, const int32 *inputBuffer) = 0;
+	virtual void SoundSourceLockedRead(SoundDevice::BufferFormat bufferFormat, std::size_t numFrames, float *buffer, const float *inputBuffer) = 0;
+	virtual void SoundSourceLockedRead(SoundDevice::BufferFormat bufferFormat, std::size_t numFrames, double *buffer, const double *inputBuffer) = 0;
 	virtual void SoundSourceLockedReadDone(SoundDevice::TimeInfo timeInfo) = 0;
 	virtual void SoundSourceUnlock() = 0;
 };
Index: sounddev/SoundDeviceBase.cpp
===================================================================
--- sounddev/SoundDeviceBase.cpp	(revision 14171)
+++ sounddev/SoundDeviceBase.cpp	(working copy)
@@ -208,7 +208,8 @@
 }
 
 
-void Base::SourceLockedAudioRead(void *buffer, const void *inputBuffer, std::size_t numFrames)
+template <typename Tsample>
+void Base::SourceLockedAudioReadImpl(Tsample *buffer, const Tsample *inputBuffer, std::size_t numFrames)
 {
 	MPT_TRACE_SCOPE();
 	if(numFrames <= 0)
@@ -221,7 +222,73 @@
 	}
 }
 
+void Base::SourceLockedAudioRead(uint8 *buffer, const uint8 *inputBuffer, std::size_t numFrames)
+{
+	SourceLockedAudioReadImpl(buffer, inputBuffer, numFrames);
+}
 
+void Base::SourceLockedAudioRead(int8 *buffer, const int8 *inputBuffer, std::size_t numFrames)
+{
+	SourceLockedAudioReadImpl(buffer, inputBuffer, numFrames);
+}
+
+void Base::SourceLockedAudioRead(int16 *buffer, const int16 *inputBuffer, std::size_t numFrames)
+{
+	SourceLockedAudioReadImpl(buffer, inputBuffer, numFrames);
+}
+
+void Base::SourceLockedAudioRead(int24 *buffer, const int24 *inputBuffer, std::size_t numFrames)
+{
+	SourceLockedAudioReadImpl(buffer, inputBuffer, numFrames);
+}
+
+void Base::SourceLockedAudioRead(int32 *buffer, const int32 *inputBuffer, std::size_t numFrames)
+{
+	SourceLockedAudioReadImpl(buffer, inputBuffer, numFrames);
+}
+
+void Base::SourceLockedAudioRead(float *buffer, const float *inputBuffer, std::size_t numFrames)
+{
+	SourceLockedAudioReadImpl(buffer, inputBuffer, numFrames);
+}
+
+void Base::SourceLockedAudioRead(double *buffer, const double *inputBuffer, std::size_t numFrames)
+{
+	SourceLockedAudioReadImpl(buffer, inputBuffer, numFrames);
+}
+
+void Base::SourceLockedAudioReadVoid(void *buffer, const void *inputBuffer, std::size_t numFrames)
+{
+	switch(GetBufferFormat().sampleFormat)
+	{
+	case SampleFormatUnsigned8:
+		SourceLockedAudioRead(static_cast<uint8*>(buffer), static_cast<const uint8*>(inputBuffer), numFrames);
+		break;
+	case SampleFormatInt8:
+		SourceLockedAudioRead(static_cast<int8*>(buffer), static_cast<const int8*>(inputBuffer), numFrames);
+		break;
+	case SampleFormatInt16:
+		SourceLockedAudioRead(static_cast<int16*>(buffer), static_cast<const int16*>(inputBuffer), numFrames);
+		break;
+	case SampleFormatInt24:
+		SourceLockedAudioRead(static_cast<int24*>(buffer), static_cast<const int24*>(inputBuffer), numFrames);
+		break;
+	case SampleFormatInt32:
+		SourceLockedAudioRead(static_cast<int32*>(buffer), static_cast<const int32*>(inputBuffer), numFrames);
+		break;
+	case SampleFormatFloat32:
+		SourceLockedAudioRead(static_cast<float*>(buffer), static_cast<const float*>(inputBuffer), numFrames);
+		break;
+	case SampleFormatFloat64:
+		SourceLockedAudioRead(static_cast<double*>(buffer), static_cast<const double*>(inputBuffer), numFrames);
+		break;
+	case SampleFormatInvalid:
+		// nothing
+		break;
+	}
+}
+
+
 void Base::SourceLockedAudioReadDone()
 {
 	MPT_TRACE_SCOPE();
Index: sounddev/SoundDeviceBase.h
===================================================================
--- sounddev/SoundDeviceBase.h	(revision 14171)
+++ sounddev/SoundDeviceBase.h	(working copy)
@@ -101,7 +101,16 @@
 	void SourceFillAudioBufferLocked();
 	uint64 SourceLockedGetReferenceClockNowNanoseconds() const;
 	void SourceLockedAudioReadPrepare(std::size_t numFrames, std::size_t framesLatency);
-	void SourceLockedAudioRead(void *buffer, const void *inputBuffer, std::size_t numFrames);
+	template <typename Tsample>
+	void SourceLockedAudioReadImpl(Tsample *buffer, const Tsample *inputBuffer, std::size_t numFrames);
+	void SourceLockedAudioRead(uint8 *buffer, const uint8 *inputBuffer, std::size_t numFrames);
+	void SourceLockedAudioRead(int8 *buffer, const int8 *inputBuffer, std::size_t numFrames);
+	void SourceLockedAudioRead(int16 *buffer, const int16 *inputBuffer, std::size_t numFrames);
+	void SourceLockedAudioRead(int24 *buffer, const int24 *inputBuffer, std::size_t numFrames);
+	void SourceLockedAudioRead(int32 *buffer, const int32 *inputBuffer, std::size_t numFrames);
+	void SourceLockedAudioRead(float *buffer, const float *inputBuffer, std::size_t numFrames);
+	void SourceLockedAudioRead(double *buffer, const double *inputBuffer, std::size_t numFrames);
+	void SourceLockedAudioReadVoid(void *buffer, const void *inputBuffer, std::size_t numFrames);
 	void SourceLockedAudioReadDone();
 
 	void RequestClose() { m_RequestFlags.fetch_or(RequestFlagClose); }
Index: sounddev/SoundDeviceBuffer.h
===================================================================
--- sounddev/SoundDeviceBuffer.h	(revision 14175)
+++ sounddev/SoundDeviceBuffer.h	(working copy)
@@ -14,12 +14,13 @@
 
 #include "SoundDevice.h"
 
-
 #include "../soundbase/SampleBuffer.h"
 #include "../soundbase/SampleFormatCopy.h"
 #include "../soundbase/Dither.h"
 
+#include <type_traits>
 
+
 OPENMPT_NAMESPACE_BEGIN
 
 
@@ -27,258 +28,95 @@
 
 
 
-template <int fractionalBits, typename Tbuffer>
-void BufferReadTemplateFixed(Tbuffer & dst, const void * src, std::size_t srcTotal, std::size_t srcPos, std::size_t numFrames, std::size_t numChannels, SampleFormat sampleFormat)
+template <int fractionalBits, typename Tbuffer, typename Tsample>
+inline void BufferReadTemplateFixed(Tbuffer & dst, const Tsample * src, std::size_t srcTotal, std::size_t srcPos, std::size_t numFrames, std::size_t numChannels)
 {
-	switch(sampleFormat)
-	{
-	case SampleFormatUnsigned8:
-		ConvertBufferToBufferMixFixed<fractionalBits>(dst, advance_audio_buffer(audio_buffer_interleaved<const uint8>(static_cast<const uint8*>(src), numChannels, srcTotal), srcPos), numChannels, numFrames);
-		break;
-	case SampleFormatInt8:
-		ConvertBufferToBufferMixFixed<fractionalBits>(dst, advance_audio_buffer(audio_buffer_interleaved<const int8>(static_cast<const int8*>(src), numChannels, srcTotal), srcPos), numChannels, numFrames);
-		break;
-	case SampleFormatInt16:
-		ConvertBufferToBufferMixFixed<fractionalBits>(dst, advance_audio_buffer(audio_buffer_interleaved<const int16>(static_cast<const int16*>(src), numChannels, srcTotal), srcPos), numChannels, numFrames);
-		break;
-	case SampleFormatInt24:
-		ConvertBufferToBufferMixFixed<fractionalBits>(dst, advance_audio_buffer(audio_buffer_interleaved<const int24>(static_cast<const int24*>(src), numChannels, srcTotal), srcPos), numChannels, numFrames);
-		break;
-	case SampleFormatInt32:
-		ConvertBufferToBufferMixFixed<fractionalBits>(dst, advance_audio_buffer(audio_buffer_interleaved<const int32>(static_cast<const int32*>(src), numChannels, srcTotal), srcPos), numChannels, numFrames);
-		break;
-	case SampleFormatFloat32:
-		ConvertBufferToBufferMixFixed<fractionalBits>(dst, advance_audio_buffer(audio_buffer_interleaved<const float>(static_cast<const float*>(src), numChannels, srcTotal), srcPos), numChannels, numFrames);
-		break;
-	case SampleFormatFloat64:
-		ConvertBufferToBufferMixFixed<fractionalBits>(dst, advance_audio_buffer(audio_buffer_interleaved<const double>(static_cast<const double*>(src), numChannels, srcTotal), srcPos), numChannels, numFrames);
-		break;
-	case SampleFormatInvalid:
-		// nothing
-		break;
-	}
+	ConvertBufferToBufferMixFixed<fractionalBits>(dst, advance_audio_buffer(audio_buffer_interleaved<const Tsample>(src, numChannels, srcTotal), srcPos), numChannels, numFrames);
 }
 
 
-template <typename Tbuffer>
-void BufferReadTemplateFloat(Tbuffer & dst, const void * src, std::size_t srcTotal, std::size_t srcPos, std::size_t numFrames, std::size_t numChannels, SampleFormat sampleFormat)
+template <typename Tbuffer, typename Tsample>
+inline void BufferReadTemplateFloat(Tbuffer & dst, const Tsample * src, std::size_t srcTotal, std::size_t srcPos, std::size_t numFrames, std::size_t numChannels)
 {
-	switch(sampleFormat)
-	{
-	case SampleFormatUnsigned8:
-		ConvertBufferToBufferMixFloat(dst, advance_audio_buffer(audio_buffer_interleaved<const uint8>(static_cast<const uint8*>(src), numChannels, srcTotal), srcPos), numChannels, numFrames);
-		break;
-	case SampleFormatInt8:
-		ConvertBufferToBufferMixFloat(dst, advance_audio_buffer(audio_buffer_interleaved<const int8>(static_cast<const int8*>(src), numChannels, srcTotal), srcPos), numChannels, numFrames);
-		break;
-	case SampleFormatInt16:
-		ConvertBufferToBufferMixFloat(dst, advance_audio_buffer(audio_buffer_interleaved<const int16>(static_cast<const int16*>(src), numChannels, srcTotal), srcPos), numChannels, numFrames);
-		break;
-	case SampleFormatInt24:
-		ConvertBufferToBufferMixFloat(dst, advance_audio_buffer(audio_buffer_interleaved<const int24>(static_cast<const int24*>(src), numChannels, srcTotal), srcPos), numChannels, numFrames);
-		break;
-	case SampleFormatInt32:
-		ConvertBufferToBufferMixFloat(dst, advance_audio_buffer(audio_buffer_interleaved<const int32>(static_cast<const int32*>(src), numChannels, srcTotal), srcPos), numChannels, numFrames);
-		break;
-	case SampleFormatFloat32:
-		ConvertBufferToBufferMixFloat(dst, advance_audio_buffer(audio_buffer_interleaved<const float>(static_cast<const float*>(src), numChannels, srcTotal), srcPos), numChannels, numFrames);
-		break;
-	case SampleFormatFloat64:
-		ConvertBufferToBufferMixFloat(dst, advance_audio_buffer(audio_buffer_interleaved<const double>(static_cast<const double*>(src), numChannels, srcTotal), srcPos), numChannels, numFrames);
-		break;
-	case SampleFormatInvalid:
-		// nothing
-		break;
-	}
+	ConvertBufferToBufferMixFloat(dst, advance_audio_buffer(audio_buffer_interleaved<const Tsample>(src, numChannels, srcTotal), srcPos), numChannels, numFrames);
 }
 
 
-template <int fractionalBits, typename Tbuffer>
-void BufferWriteTemplateFixed(void * dst, std::size_t dstTotal, std::size_t dstPos, Tbuffer & src, std::size_t numFrames, std::size_t numChannels, Dither &dither, SampleFormat sampleFormat, bool clipFloat)
+template <int fractionalBits, typename Tsample, typename Tbuffer, std::enable_if_t<!std::is_floating_point<Tsample>::value, bool> = true>
+inline void BufferWriteTemplateFixed(Tsample * dst, std::size_t dstTotal, std::size_t dstPos, Tbuffer & src, std::size_t numFrames, std::size_t numChannels, Dither &dither, bool clipFloat)
 {
-	switch(sampleFormat)
-	{
-		case SampleFormatUnsigned8:
-			dither.WithDither(
-				[&](auto &ditherInstance)
-				{
-					ConvertBufferMixFixedToBuffer<fractionalBits, false>(advance_audio_buffer(audio_buffer_interleaved<uint8>(static_cast<uint8*>(dst), numChannels, dstTotal), dstPos), src, ditherInstance, numChannels, numFrames);
-				}
-			);
-			break;
-		case SampleFormatInt8:
-			dither.WithDither(
-				[&](auto &ditherInstance)
-				{
-					ConvertBufferMixFixedToBuffer<fractionalBits, false>(advance_audio_buffer(audio_buffer_interleaved<int8>(static_cast<int8*>(dst), numChannels, dstTotal), dstPos), src, ditherInstance, numChannels, numFrames);
-				}
-			);
-			break;
-		case SampleFormatInt16:
-			dither.WithDither(
-				[&](auto &ditherInstance)
-				{
-					ConvertBufferMixFixedToBuffer<fractionalBits, false>(advance_audio_buffer(audio_buffer_interleaved<int16>(static_cast<int16*>(dst), numChannels, dstTotal), dstPos), src, ditherInstance, numChannels, numFrames);
-				}
-			);
-			break;
-		case SampleFormatInt24:
-			dither.WithDither(
-				[&](auto &ditherInstance)
-				{
-					ConvertBufferMixFixedToBuffer<fractionalBits, false>(advance_audio_buffer(audio_buffer_interleaved<int24>(static_cast<int24*>(dst), numChannels, dstTotal), dstPos), src, ditherInstance, numChannels, numFrames);
-				}
-			);
-			break;
-		case SampleFormatInt32:
-			dither.WithDither(
-				[&](auto &ditherInstance)
-				{
-					ConvertBufferMixFixedToBuffer<fractionalBits, false>(advance_audio_buffer(audio_buffer_interleaved<int32>(static_cast<int32*>(dst), numChannels, dstTotal), dstPos), src, ditherInstance, numChannels, numFrames);
-				}
-			);
-			break;
-		case SampleFormatFloat32:
-			if(clipFloat)
-			{
-				dither.WithDither(
-					[&](auto &ditherInstance)
-					{
-						ConvertBufferMixFixedToBuffer<fractionalBits, true>(advance_audio_buffer(audio_buffer_interleaved<float>(static_cast<float*>(dst), numChannels, dstTotal), dstPos), src, ditherInstance, numChannels, numFrames);
-					}
-				);
-			} else
-			{
-				dither.WithDither(
-					[&](auto &ditherInstance)
-					{
-						ConvertBufferMixFixedToBuffer<fractionalBits, false>(advance_audio_buffer(audio_buffer_interleaved<float>(static_cast<float*>(dst), numChannels, dstTotal), dstPos), src, ditherInstance, numChannels, numFrames);
-					}
-				);
-			}
-			break;
-		case SampleFormatFloat64:
-			if(clipFloat)
-			{
-				dither.WithDither(
-					[&](auto &ditherInstance)
-					{
-						ConvertBufferMixFixedToBuffer<fractionalBits, true>(advance_audio_buffer(audio_buffer_interleaved<double>(static_cast<double*>(dst), numChannels, dstTotal), dstPos), src, ditherInstance, numChannels, numFrames);
-					}
-				);
-			} else
-			{
-				dither.WithDither(
-					[&](auto &ditherInstance)
-					{
-						ConvertBufferMixFixedToBuffer<fractionalBits, false>(advance_audio_buffer(audio_buffer_interleaved<double>(static_cast<double*>(dst), numChannels, dstTotal), dstPos), src, ditherInstance, numChannels, numFrames);
-					}
-				);
-			}
-			break;
-		case SampleFormatInvalid:
-			// nothing
-			break;
-	}
+	MPT_UNUSED_VARIABLE(clipFloat);
+	dither.WithDither(
+		[&](auto &ditherInstance)
+		{
+			ConvertBufferMixFixedToBuffer<fractionalBits, false>(advance_audio_buffer(audio_buffer_interleaved<Tsample>(dst, numChannels, dstTotal), dstPos), src, ditherInstance, numChannels, numFrames);
+		}
+	);
 }
-
-
-template <typename Tbuffer>
-void BufferWriteTemplateFloat(void * dst, std::size_t dstTotal, std::size_t dstPos, Tbuffer & src, std::size_t numFrames, std::size_t numChannels, Dither &dither, SampleFormat sampleFormat, bool clipFloat)
+template <int fractionalBits, typename Tsample, typename Tbuffer, std::enable_if_t<std::is_floating_point<Tsample>::value, bool> = true>
+inline void BufferWriteTemplateFixed(Tsample * dst, std::size_t dstTotal, std::size_t dstPos, Tbuffer & src, std::size_t numFrames, std::size_t numChannels, Dither &dither, bool clipFloat)
 {
-	switch(sampleFormat)
+	if(clipFloat)
 	{
-	case SampleFormatUnsigned8:
 		dither.WithDither(
 			[&](auto &ditherInstance)
 			{
-				ConvertBufferMixFloatToBuffer<false>(advance_audio_buffer(audio_buffer_interleaved<uint8>(static_cast<uint8*>(dst), numChannels, dstTotal), dstPos), src, ditherInstance, numChannels, numFrames);
+				ConvertBufferMixFixedToBuffer<fractionalBits, true>(advance_audio_buffer(audio_buffer_interleaved<Tsample>(dst, numChannels, dstTotal), dstPos), src, ditherInstance, numChannels, numFrames);
 			}
 		);
-		break;
-	case SampleFormatInt8:
+	} else
+	{
 		dither.WithDither(
 			[&](auto &ditherInstance)
 			{
-				ConvertBufferMixFloatToBuffer<false>(advance_audio_buffer(audio_buffer_interleaved<int8>(static_cast<int8*>(dst), numChannels, dstTotal), dstPos), src, ditherInstance, numChannels, numFrames);
+				ConvertBufferMixFixedToBuffer<fractionalBits, false>(advance_audio_buffer(audio_buffer_interleaved<Tsample>(dst, numChannels, dstTotal), dstPos), src, ditherInstance, numChannels, numFrames);
 			}
 		);
-		break;
-	case SampleFormatInt16:
+	}
+}
+
+
+template <typename Tsample, typename Tbuffer, std::enable_if_t<!std::is_floating_point<Tsample>::value, bool> = true>
+void BufferWriteTemplateFloat(Tsample * dst, std::size_t dstTotal, std::size_t dstPos, Tbuffer & src, std::size_t numFrames, std::size_t numChannels, Dither &dither, bool clipFloat)
+{
+	MPT_UNUSED_VARIABLE(clipFloat);
+	dither.WithDither(
+		[&](auto &ditherInstance)
+		{
+			ConvertBufferMixFloatToBuffer<false>(advance_audio_buffer(audio_buffer_interleaved<Tsample>(dst, numChannels, dstTotal), dstPos), src, ditherInstance, numChannels, numFrames);
+		}
+	);
+}
+template <typename Tsample, typename Tbuffer, std::enable_if_t<std::is_floating_point<Tsample>::value, bool> = true>
+void BufferWriteTemplateFloat(Tsample * dst, std::size_t dstTotal, std::size_t dstPos, Tbuffer & src, std::size_t numFrames, std::size_t numChannels, Dither &dither, bool clipFloat)
+{
+	if(clipFloat)
+	{
 		dither.WithDither(
 			[&](auto &ditherInstance)
 			{
-				ConvertBufferMixFloatToBuffer<false>(advance_audio_buffer(audio_buffer_interleaved<int16>(static_cast<int16*>(dst), numChannels, dstTotal), dstPos), src, ditherInstance, numChannels, numFrames);
+				ConvertBufferMixFloatToBuffer<true>(advance_audio_buffer(audio_buffer_interleaved<Tsample>(dst, numChannels, dstTotal), dstPos), src, ditherInstance, numChannels, numFrames);
 			}
 		);
-		break;
-	case SampleFormatInt24:
+	} else
+	{
 		dither.WithDither(
 			[&](auto &ditherInstance)
 			{
-				ConvertBufferMixFloatToBuffer<false>(advance_audio_buffer(audio_buffer_interleaved<int24>(static_cast<int24*>(dst), numChannels, dstTotal), dstPos), src, ditherInstance, numChannels, numFrames);
+				ConvertBufferMixFloatToBuffer<false>(advance_audio_buffer(audio_buffer_interleaved<Tsample>(dst, numChannels, dstTotal), dstPos), src, ditherInstance, numChannels, numFrames);
 			}
 		);
-		break;
-	case SampleFormatInt32:
-		dither.WithDither(
-			[&](auto &ditherInstance)
-			{
-				ConvertBufferMixFloatToBuffer<false>(advance_audio_buffer(audio_buffer_interleaved<int32>(static_cast<int32*>(dst), numChannels, dstTotal), dstPos), src, ditherInstance, numChannels, numFrames);
-			}
-		);
-		break;
-	case SampleFormatFloat32:
-		if(clipFloat)
-		{
-			dither.WithDither(
-				[&](auto &ditherInstance)
-				{
-					ConvertBufferMixFloatToBuffer<true>(advance_audio_buffer(audio_buffer_interleaved<float>(static_cast<float*>(dst), numChannels, dstTotal), dstPos), src, ditherInstance, numChannels, numFrames);
-				}
-			);
-		} else
-		{
-			dither.WithDither(
-				[&](auto &ditherInstance)
-				{
-					ConvertBufferMixFloatToBuffer<false>(advance_audio_buffer(audio_buffer_interleaved<float>(static_cast<float*>(dst), numChannels, dstTotal), dstPos), src, ditherInstance, numChannels, numFrames);
-				}
-			);
-		}
-		break;
-	case SampleFormatFloat64:
-		if(clipFloat)
-		{
-			dither.WithDither(
-				[&](auto &ditherInstance)
-				{
-					ConvertBufferMixFloatToBuffer<true>(advance_audio_buffer(audio_buffer_interleaved<double>(static_cast<double*>(dst), numChannels, dstTotal), dstPos), src, ditherInstance, numChannels, numFrames);
-				}
-			);
-		} else
-		{
-			dither.WithDither(
-				[&](auto &ditherInstance)
-				{
-					ConvertBufferMixFloatToBuffer<false>(advance_audio_buffer(audio_buffer_interleaved<double>(static_cast<double*>(dst), numChannels, dstTotal), dstPos), src, ditherInstance, numChannels, numFrames);
-				}
-			);
-		}
-		break;
-	case SampleFormatInvalid:
-		// nothing
-		break;
 	}
 }
 
 
 
+template <typename Tsample>
 class BufferIO
 {
 private:
-	const void * const m_src;
-	void * const m_dst;
+	const Tsample * const m_src;
+	Tsample * const m_dst;
 	std::size_t m_countFramesReadProcessed;
 	std::size_t m_countFramesWriteProcessed;
 	Dither & m_dither;
@@ -285,7 +123,7 @@
 	const BufferFormat m_bufferFormat;
 	const std::size_t m_countFramesTotal;
 public:
-	inline BufferIO(void * dst, const void * src, std::size_t numFrames, Dither & dither, BufferFormat bufferFormat)
+	inline BufferIO(Tsample * dst, const Tsample * src, std::size_t numFrames, Dither & dither, BufferFormat bufferFormat)
 		: m_src(src)
 		, m_dst(dst)
 		, m_countFramesReadProcessed(0)
@@ -300,7 +138,7 @@
 	inline void Read(Tbuffer & dst, std::size_t countChunk)
 	{
 		MPT_ASSERT(m_countFramesReadProcessed + countChunk <= m_countFramesTotal);
-		SoundDevice::BufferReadTemplateFloat(dst, m_src, m_countFramesTotal, m_countFramesReadProcessed, countChunk, m_bufferFormat.InputChannels, m_bufferFormat.sampleFormat);
+		SoundDevice::BufferReadTemplateFloat(dst, m_src, m_countFramesTotal, m_countFramesReadProcessed, countChunk, m_bufferFormat.InputChannels);
 		m_countFramesReadProcessed += countChunk;
 	}
 	template <int fractionalBits, typename Tbuffer>
@@ -307,7 +145,7 @@
 	inline void ReadFixedPoint(Tbuffer & dst, std::size_t countChunk)
 	{
 		MPT_ASSERT(m_countFramesReadProcessed + countChunk <= m_countFramesTotal);
-		SoundDevice::BufferReadTemplateFixed<fractionalBits>(dst, m_src, m_countFramesTotal, m_countFramesReadProcessed, countChunk, m_bufferFormat.InputChannels, m_bufferFormat.sampleFormat);
+		SoundDevice::BufferReadTemplateFixed<fractionalBits>(dst, m_src, m_countFramesTotal, m_countFramesReadProcessed, countChunk, m_bufferFormat.InputChannels);
 		m_countFramesReadProcessed += countChunk;
 	}
 	template <typename Tbuffer>
@@ -314,7 +152,7 @@
 	inline void Write(Tbuffer & src, std::size_t countChunk)
 	{
 		MPT_ASSERT(m_countFramesWriteProcessed + countChunk <= m_countFramesTotal);
-		SoundDevice::BufferWriteTemplateFloat(m_dst, m_countFramesTotal, m_countFramesWriteProcessed, src, countChunk, m_bufferFormat.Channels, m_dither, m_bufferFormat.sampleFormat, m_bufferFormat.NeedsClippedFloat);
+		SoundDevice::BufferWriteTemplateFloat(m_dst, m_countFramesTotal, m_countFramesWriteProcessed, src, countChunk, m_bufferFormat.Channels, m_dither, m_bufferFormat.NeedsClippedFloat);
 		m_countFramesWriteProcessed += countChunk;
 	}
 	template <int fractionalBits, typename Tbuffer>
@@ -321,7 +159,7 @@
 	inline void WriteFixedPoint(Tbuffer & src, std::size_t countChunk)
 	{
 		MPT_ASSERT(m_countFramesWriteProcessed + countChunk <= m_countFramesTotal);
-		SoundDevice::BufferWriteTemplateFixed<fractionalBits>(m_dst, m_countFramesTotal, m_countFramesWriteProcessed, src, countChunk, m_bufferFormat.Channels, m_dither, m_bufferFormat.sampleFormat, m_bufferFormat.NeedsClippedFloat);
+		SoundDevice::BufferWriteTemplateFixed<fractionalBits>(m_dst, m_countFramesTotal, m_countFramesWriteProcessed, src, countChunk, m_bufferFormat.Channels, m_dither, m_bufferFormat.NeedsClippedFloat);
 		m_countFramesWriteProcessed += countChunk;
 	}
 };
Index: sounddev/SoundDevicePortAudio.cpp
===================================================================
--- sounddev/SoundDevicePortAudio.cpp	(revision 14171)
+++ sounddev/SoundDevicePortAudio.cpp	(working copy)
@@ -285,7 +285,7 @@
 		return;
 	}
 	SourceLockedAudioReadPrepare(m_CurrentFrameCount, mpt::saturate_cast<std::size_t>(mpt::saturate_round<int64>(m_CurrentRealLatency * m_StreamInfo->sampleRate)));
-	SourceLockedAudioRead(m_CurrentFrameBuffer, m_CurrentFrameBufferInput, m_CurrentFrameCount);
+	SourceLockedAudioReadVoid(m_CurrentFrameBuffer, m_CurrentFrameBufferInput, m_CurrentFrameCount);
 	m_StatisticPeriodFrames.store(m_CurrentFrameCount);
 	SourceLockedAudioReadDone();
 }
Index: sounddev/SoundDevicePulseaudio.cpp
===================================================================
--- sounddev/SoundDevicePulseaudio.cpp	(revision 14171)
+++ sounddev/SoundDevicePulseaudio.cpp	(working copy)
@@ -358,7 +358,7 @@
 	latencyFrames += (latency_usec * m_Settings.Samplerate) / 1000000;
 	latencyFrames += 1 * (m_OutputBuffer.size() / m_Settings.Channels);
 	SourceLockedAudioReadPrepare(m_OutputBuffer.size() / m_Settings.Channels, latencyFrames);
-	SourceLockedAudioRead(&(m_OutputBuffer[0]), nullptr, m_OutputBuffer.size() / m_Settings.Channels);
+	SourceLockedAudioRead(m_OutputBuffer.data(), nullptr, m_OutputBuffer.size() / m_Settings.Channels);
 	error = 0;
 	if(pa_simple_write(m_PA_SimpleOutput, &(m_OutputBuffer[0]), m_OutputBuffer.size() * sizeof(float32), &error) < 0)
 	{
Index: sounddev/SoundDevicePulseSimple.cpp
===================================================================
--- sounddev/SoundDevicePulseSimple.cpp	(revision 14171)
+++ sounddev/SoundDevicePulseSimple.cpp	(working copy)
@@ -383,7 +383,7 @@
 	latencyFrames += (latency_usec * m_Settings.Samplerate) / 1000000;
 	latencyFrames += 1 * (m_OutputBuffer.size() / m_Settings.Channels);
 	SourceLockedAudioReadPrepare(m_OutputBuffer.size() / m_Settings.Channels, latencyFrames);
-	SourceLockedAudioRead(&(m_OutputBuffer[0]), nullptr, m_OutputBuffer.size() / m_Settings.Channels);
+	SourceLockedAudioRead(m_OutputBuffer.data(), nullptr, m_OutputBuffer.size() / m_Settings.Channels);
 	error = 0;
 	if(pa_simple_write(m_PA_SimpleOutput, &(m_OutputBuffer[0]), m_OutputBuffer.size() * sizeof(float32), &error) < 0)
 	{
Index: sounddev/SoundDeviceRtAudio.cpp
===================================================================
--- sounddev/SoundDeviceRtAudio.cpp	(revision 14171)
+++ sounddev/SoundDeviceRtAudio.cpp	(working copy)
@@ -177,7 +177,7 @@
 		return;
 	}
 	SourceLockedAudioReadPrepare(m_CurrentFrameBufferCount, m_FramesPerChunk * m_StreamOptions.numberOfBuffers);
-	SourceLockedAudioRead(m_CurrentFrameBufferOutput, m_CurrentFrameBufferInput, m_CurrentFrameBufferCount);
+	SourceLockedAudioReadVoid(m_CurrentFrameBufferOutput, m_CurrentFrameBufferInput, m_CurrentFrameBufferCount);
 	m_StatisticLatencyFrames.store(m_CurrentFrameBufferCount * m_StreamOptions.numberOfBuffers);
 	m_StatisticPeriodFrames.store(m_CurrentFrameBufferCount);
 	SourceLockedAudioReadDone();
Index: sounddev/SoundDeviceStub.cpp
===================================================================
--- sounddev/SoundDeviceStub.cpp	(revision 14171)
+++ sounddev/SoundDeviceStub.cpp	(working copy)
@@ -168,7 +168,7 @@
 	}
 	source->SoundSourceLockedReadPrepare(ti);
 }
-static void __cdecl SoundSourceLockedReadFunc( void * inst, const OpenMPT_SoundDevice_BufferFormat * bufferFormat, uintptr_t numFrames, void * buffer, const void * inputBuffer ) {
+static void __cdecl SoundSourceLockedReadUint8Func( void * inst, const OpenMPT_SoundDevice_BufferFormat * bufferFormat, uintptr_t numFrames, uint8_t * buffer, const uint8_t * inputBuffer ) {
 	SoundDevice::ISource * source = ((SoundDevice::ISource*)inst);
 	SoundDevice::BufferFormat bf = C::decode(*bufferFormat);
 	if(!source)
@@ -177,6 +177,60 @@
 	}
 	source->SoundSourceLockedRead(bf, numFrames, buffer, inputBuffer);
 }
+static void __cdecl SoundSourceLockedReadInt8Func( void * inst, const OpenMPT_SoundDevice_BufferFormat * bufferFormat, uintptr_t numFrames, int8_t  * buffer, const int8_t * inputBuffer ) {
+	SoundDevice::ISource * source = ((SoundDevice::ISource*)inst);
+	SoundDevice::BufferFormat bf = C::decode(*bufferFormat);
+	if(!source)
+	{
+		return;
+	}
+	source->SoundSourceLockedRead(bf, numFrames, buffer, inputBuffer);
+}
+static void __cdecl SoundSourceLockedReadInt16Func( void * inst, const OpenMPT_SoundDevice_BufferFormat * bufferFormat, uintptr_t numFrames, int16_t * buffer, const int16_t * inputBuffer ) {
+	SoundDevice::ISource * source = ((SoundDevice::ISource*)inst);
+	SoundDevice::BufferFormat bf = C::decode(*bufferFormat);
+	if(!source)
+	{
+		return;
+	}
+	source->SoundSourceLockedRead(bf, numFrames, buffer, inputBuffer);
+}
+static void __cdecl SoundSourceLockedReadInt24Func( void * inst, const OpenMPT_SoundDevice_BufferFormat * bufferFormat, uintptr_t numFrames, OpenMPT_int24 * buffer, const OpenMPT_int24 * inputBuffer ) {
+	SoundDevice::ISource * source = ((SoundDevice::ISource*)inst);
+	SoundDevice::BufferFormat bf = C::decode(*bufferFormat);
+	if(!source)
+	{
+		return;
+	}
+	source->SoundSourceLockedRead(bf, numFrames, static_cast<int24*>(buffer), static_cast<const int24*>(inputBuffer));
+}
+static void __cdecl SoundSourceLockedReadInt32Func( void * inst, const OpenMPT_SoundDevice_BufferFormat * bufferFormat, uintptr_t numFrames, int32_t * buffer, const int32_t * inputBuffer ) {
+	SoundDevice::ISource * source = ((SoundDevice::ISource*)inst);
+	SoundDevice::BufferFormat bf = C::decode(*bufferFormat);
+	if(!source)
+	{
+		return;
+	}
+	source->SoundSourceLockedRead(bf, numFrames, buffer, inputBuffer);
+}
+static void __cdecl SoundSourceLockedReadFloatFunc( void * inst, const OpenMPT_SoundDevice_BufferFormat * bufferFormat, uintptr_t numFrames, float * buffer, const float * inputBuffer ) {
+	SoundDevice::ISource * source = ((SoundDevice::ISource*)inst);
+	SoundDevice::BufferFormat bf = C::decode(*bufferFormat);
+	if(!source)
+	{
+		return;
+	}
+	source->SoundSourceLockedRead(bf, numFrames, buffer, inputBuffer);
+}
+static void __cdecl SoundSourceLockedReadDoubleFunc( void * inst, const OpenMPT_SoundDevice_BufferFormat * bufferFormat, uintptr_t numFrames, double * buffer, const double * inputBuffer ) {
+	SoundDevice::ISource * source = ((SoundDevice::ISource*)inst);
+	SoundDevice::BufferFormat bf = C::decode(*bufferFormat);
+	if(!source)
+	{
+		return;
+	}
+	source->SoundSourceLockedRead(bf, numFrames, buffer, inputBuffer);
+}
 static void __cdecl SoundSourceLockedReadDoneFunc( void * inst, const OpenMPT_SoundDevice_TimeInfo * timeInfo ) {
 	SoundDevice::ISource * source = ((SoundDevice::ISource*)inst);
 	SoundDevice::TimeInfo ti = C::decode(*timeInfo);
@@ -206,7 +260,13 @@
 	source.SoundSourceLockFunc = &SoundSourceLockFunc;
 	source.SoundSourceLockedGetReferenceClockNowNanosecondsFunc = &SoundSourceLockedGetReferenceClockNowNanosecondsFunc;
 	source.SoundSourceLockedReadPrepareFunc = &SoundSourceLockedReadPrepareFunc;
-	source.SoundSourceLockedReadFunc = &SoundSourceLockedReadFunc;
+	source.SoundSourceLockedReadUint8Func = &SoundSourceLockedReadUint8Func;
+	source.SoundSourceLockedReadInt8Func = &SoundSourceLockedReadInt8Func;
+	source.SoundSourceLockedReadInt16Func = &SoundSourceLockedReadInt16Func;
+	source.SoundSourceLockedReadInt24Func = &SoundSourceLockedReadInt24Func;
+	source.SoundSourceLockedReadInt32Func = &SoundSourceLockedReadInt32Func;
+	source.SoundSourceLockedReadFloatFunc = &SoundSourceLockedReadFloatFunc;
+	source.SoundSourceLockedReadDoubleFunc = &SoundSourceLockedReadDoubleFunc;
 	source.SoundSourceLockedReadDoneFunc = &SoundSourceLockedReadDoneFunc;
 	source.SoundSourceUnlockFunc = &SoundSourceUnlockFunc;
 	return w->OpenMPT_Wine_Wrapper_SoundDevice_SetSource(impl, &source);
Index: sounddev/SoundDeviceWaveout.cpp
===================================================================
--- sounddev/SoundDeviceWaveout.cpp	(revision 14171)
+++ sounddev/SoundDeviceWaveout.cpp	(working copy)
@@ -403,7 +403,7 @@
 		}
 		nLatency += m_nWaveBufferSize;
 		SourceLockedAudioReadPrepare(m_nWaveBufferSize / bytesPerFrame, nLatency / bytesPerFrame);
-		SourceLockedAudioRead(m_WaveBuffers[m_nWriteBuffer].lpData, nullptr, m_nWaveBufferSize / bytesPerFrame);
+		SourceLockedAudioReadVoid(m_WaveBuffers[m_nWriteBuffer].lpData, nullptr, m_nWaveBufferSize / bytesPerFrame);
 		nBytesWritten += m_nWaveBufferSize;
 		InterlockedAnd(interlocked_access(&m_WaveBuffers[m_nWriteBuffer].dwFlags), ~static_cast<DWORD>(WHDR_INQUEUE|WHDR_DONE));
 		InterlockedExchange(interlocked_access(&m_WaveBuffers[m_nWriteBuffer].dwBufferLength), m_nWaveBufferSize);
