View Issue Details

IDProjectCategoryView StatusLast Update
0001418OpenMPTAudio I/Opublic2021-02-18 09:39
Reportermanx Assigned Tomanx  
PrioritynormalSeveritymajorReproducibilityalways
Status resolvedResolutionfixed 
Product VersionOpenMPT 1.30.00.* (old testing) 
Target VersionOpenMPT 1.30.01.00 / libopenmpt 0.6.0 (upgrade first)Fixed in VersionOpenMPT 1.29.08.00 / libopenmpt 0.5.6/0.5.7 (upgrade first) 
Summary0001418: Simplify output sample format
Description

SoundDevice currently (and historically) defines the sample format that client code has to use. This hinders refactoring because it requires client code to be able to generate any possible sample format. SoundDevice::BuferrIO somewhat solves this problem in a way rather specific to the OpenMPT MixSample type. However, this is still in particular problematic when trying to layer stream resampling on top of SoundDevice.

Although the current implementation allows for a zero-copy implementation by facilitating converting to output sample format in class BufferIO, it introduces significant maintenance overhead. In practice, our use of this zero-copy functionality is not even zero-copy because we fill the internal MixSampleBuffer first, and then output.

The way so simplify here, is to use 1 single defined sample format (i.e. float32) in the interface to SoundDevice, and just store it in an internal buffer, which the individual SoundDevice backends convert to the required output format as needed.

TagsNo tags attached.
Has the bug occurred in previous versions?
Tested code revision (in case you know it)

Relationships

child of 0001417 assignedmanx use OpenMPT sound devices in openmpt123 

Activities

manx

manx

2021-02-17 10:08

administrator   ~0004641

r14175 decouples sounddev from MixSampleInt

manx

manx

2021-02-17 17:55

administrator   ~0004642

This is a different approach compared to what I outlined in the issue. Instead of removing BufferIO completely and forcing any particular sample format throughout the entire SoundDevice interface, this extended BufferIO to accept any common sample format. Additionally, we can get rid of the void* buffers and use typed overloads for all sample formats supported by SoundDevice instead.

sounddev-typesafety-v3.patch (63,707 bytes)   
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);
sounddev-typesafety-v3.patch (63,707 bytes)   
manx

manx

2021-02-18 09:39

administrator   ~0004643

r14177 / 1.30.00.28

Issue History

Date Modified Username Field Change
2021-02-16 08:12 manx New Issue
2021-02-16 08:12 manx Status new => assigned
2021-02-16 08:12 manx Assigned To => manx
2021-02-16 08:13 manx Relationship added child of 0001417
2021-02-17 10:07 manx Description Updated
2021-02-17 10:08 manx Note Added: 0004641
2021-02-17 17:55 manx Note Added: 0004642
2021-02-17 17:55 manx File Added: sounddev-typesafety-v3.patch
2021-02-17 17:55 manx Target Version OpenMPT 1.31.01.00 / libopenmpt 0.7.0 (upgrade first) => OpenMPT 1.30.01.00 / libopenmpt 0.6.0 (upgrade first)
2021-02-18 09:39 manx Status assigned => resolved
2021-02-18 09:39 manx Resolution open => fixed
2021-02-18 09:39 manx Fixed in Version => OpenMPT 1.29.08.00 / libopenmpt 0.5.6/0.5.7 (upgrade first)
2021-02-18 09:39 manx Note Added: 0004643