From a12bfcf5d5db8c3579a47de09524c9bfa17e021e Mon Sep 17 00:00:00 2001 From: Johannes Anderwald Date: Tue, 9 Feb 2010 12:03:59 +0000 Subject: [PATCH] [DSOUND_NEW] - Implement starting / stopping primary sound buffer - Implement retrieving capabilities for secondary sound buffer - Import sound mixing routines from wine, not yet used svn path=/trunk/; revision=45527 --- .../dll/directx/dsound_new/dsound_convert.c | 435 ++++++++++++++++++ reactos/dll/directx/dsound_new/primary.c | 64 ++- reactos/dll/directx/dsound_new/secondary.c | 25 +- 3 files changed, 516 insertions(+), 8 deletions(-) create mode 100644 reactos/dll/directx/dsound_new/dsound_convert.c diff --git a/reactos/dll/directx/dsound_new/dsound_convert.c b/reactos/dll/directx/dsound_new/dsound_convert.c new file mode 100644 index 00000000000..0a6e474d09d --- /dev/null +++ b/reactos/dll/directx/dsound_new/dsound_convert.c @@ -0,0 +1,435 @@ +/* DirectSound format conversion and mixing routines + * + * Copyright 2007 Maarten Lankhorst + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +/* 8 bits is unsigned, the rest is signed. + * First I tried to reuse existing stuff from alsa-lib, after that + * didn't work, I gave up and just went for individual hacks. + * + * 24 bit is expensive to do, due to unaligned access. + * In dlls/winex11.drv/dib_convert.c convert_888_to_0888_asis there is a way + * around it, but I'm happy current code works, maybe something for later. + * + * The ^ 0x80 flips the signed bit, this is the conversion from + * signed (-128.. 0.. 127) to unsigned (0...255) + * This is only temporary: All 8 bit data should be converted to signed. + * then when fed to the sound card, it should be converted to unsigned again. + * + * Sound is LITTLE endian + */ + +#include "config.h" + +#include + +#define NONAMELESSSTRUCT +#define NONAMELESSUNION +#include "windef.h" +#include "winbase.h" +#include "mmsystem.h" +#include "winternl.h" +#include "wine/debug.h" +#include "dsound.h" +#include "dsdriver.h" +#include "dsound_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(dsound); + +#ifdef WORDS_BIGENDIAN +#define le16(x) RtlUshortByteSwap((x)) +#define le32(x) RtlUlongByteSwap((x)) +#else +#define le16(x) (x) +#define le32(x) (x) +#endif + +static inline void src_advance(const void **src, UINT stride, INT *count, UINT *freqAcc, UINT adj) +{ + *freqAcc += adj; + if (*freqAcc >= (1 << DSOUND_FREQSHIFT)) + { + ULONG adv = (*freqAcc >> DSOUND_FREQSHIFT); + *freqAcc &= (1 << DSOUND_FREQSHIFT) - 1; + *(const char **)src += adv * stride; + *count -= adv; + } +} + +static void convert_8_to_8 (const void *src, void *dst, UINT src_stride, + UINT dst_stride, INT count, UINT freqAcc, UINT adj) +{ + while (count > 0) + { + *(BYTE *)dst = *(const BYTE *)src; + + dst = (char *)dst + dst_stride; + src_advance(&src, src_stride, &count, &freqAcc, adj); + } +} + +static void convert_8_to_16 (const void *src, void *dst, UINT src_stride, + UINT dst_stride, INT count, UINT freqAcc, UINT adj) +{ + while (count > 0) + { + WORD dest = *(const BYTE *)src, *dest16 = dst; + *dest16 = le16(dest * 257 - 32768); + + dst = (char *)dst + dst_stride; + src_advance(&src, src_stride, &count, &freqAcc, adj); + } +} + +static void convert_8_to_24 (const void *src, void *dst, UINT src_stride, + UINT dst_stride, INT count, UINT freqAcc, UINT adj) +{ + while (count > 0) + { + BYTE dest = *(const BYTE *)src; + BYTE *dest24 = dst; + dest24[0] = dest; + dest24[1] = dest; + dest24[2] = dest - 0x80; + + dst = (char *)dst + dst_stride; + src_advance(&src, src_stride, &count, &freqAcc, adj); + } +} + +static void convert_8_to_32 (const void *src, void *dst, UINT src_stride, + UINT dst_stride, INT count, UINT freqAcc, UINT adj) +{ + while (count > 0) + { + DWORD dest = *(const BYTE *)src, *dest32 = dst; + *dest32 = le32(dest * 16843009 - 2147483648U); + + dst = (char *)dst + dst_stride; + src_advance(&src, src_stride, &count, &freqAcc, adj); + } +} + +static void convert_16_to_8 (const void *src, void *dst, UINT src_stride, + UINT dst_stride, INT count, UINT freqAcc, UINT adj) +{ + while (count > 0) + { + BYTE *dst8 = dst; + *dst8 = (le16(*(const WORD *)src)) / 256; + *dst8 -= 0x80; + + dst = (char *)dst + dst_stride; + src_advance(&src, src_stride, &count, &freqAcc, adj); + } +} + +static void convert_16_to_16 (const void *src, void *dst, UINT src_stride, + UINT dst_stride, INT count, UINT freqAcc, UINT adj) +{ + while (count > 0) + { + *(WORD *)dst = *(const WORD *)src; + + dst = (char *)dst + dst_stride; + src_advance(&src, src_stride, &count, &freqAcc, adj); + } +} + +static void convert_16_to_24 (const void *src, void *dst, UINT src_stride, + UINT dst_stride, INT count, UINT freqAcc, UINT adj) +{ + while (count > 0) + { + WORD dest = le16(*(const WORD *)src); + BYTE *dest24 = dst; + + dest24[0] = dest / 256; + dest24[1] = dest; + dest24[2] = dest / 256; + + dst = (char *)dst + dst_stride; + src_advance(&src, src_stride, &count, &freqAcc, adj); + } +} + +static void convert_16_to_32 (const void *src, void *dst, UINT src_stride, + UINT dst_stride, INT count, UINT freqAcc, UINT adj) +{ + while (count > 0) + { + DWORD dest = *(const WORD *)src, *dest32 = dst; + *dest32 = dest * 65537; + + dst = (char *)dst + dst_stride; + src_advance(&src, src_stride, &count, &freqAcc, adj); + } +} + +static void convert_24_to_8 (const void *src, void *dst, UINT src_stride, + UINT dst_stride, INT count, UINT freqAcc, UINT adj) +{ + while (count > 0) + { + BYTE *dst8 = dst; + *dst8 = ((const BYTE *)src)[2]; + + dst = (char *)dst + dst_stride; + src_advance(&src, src_stride, &count, &freqAcc, adj); + } +} + +static void convert_24_to_16 (const void *src, void *dst, UINT src_stride, + UINT dst_stride, INT count, UINT freqAcc, UINT adj) +{ + while (count > 0) + { + WORD *dest16 = dst; + const BYTE *source = src; + *dest16 = le16(source[2] * 256 + source[1]); + + dst = (char *)dst + dst_stride; + src_advance(&src, src_stride, &count, &freqAcc, adj); + } +} + +static void convert_24_to_24 (const void *src, void *dst, UINT src_stride, + UINT dst_stride, INT count, UINT freqAcc, UINT adj) +{ + while (count > 0) + { + BYTE *dest24 = dst; + const BYTE *src24 = src; + + dest24[0] = src24[0]; + dest24[1] = src24[1]; + dest24[2] = src24[2]; + + dst = (char *)dst + dst_stride; + src_advance(&src, src_stride, &count, &freqAcc, adj); + } +} + +static void convert_24_to_32 (const void *src, void *dst, UINT src_stride, + UINT dst_stride, INT count, UINT freqAcc, UINT adj) +{ + while (count > 0) + { + DWORD *dest32 = dst; + const BYTE *source = src; + *dest32 = le32(source[2] * 16777217 + source[1] * 65536 + source[0] * 256); + + dst = (char *)dst + dst_stride; + src_advance(&src, src_stride, &count, &freqAcc, adj); + } +} + +static void convert_32_to_8 (const void *src, void *dst, UINT src_stride, + UINT dst_stride, INT count, UINT freqAcc, UINT adj) +{ + while (count > 0) + { + BYTE *dst8 = dst; + *dst8 = (le32(*(const DWORD *)src) / 16777216); + *dst8 -= 0x80; + + dst = (char *)dst + dst_stride; + src_advance(&src, src_stride, &count, &freqAcc, adj); + } +} + +static void convert_32_to_16 (const void *src, void *dst, UINT src_stride, + UINT dst_stride, INT count, UINT freqAcc, UINT adj) +{ + while (count > 0) + { + WORD *dest16 = dst; + *dest16 = le16(le32(*(const DWORD *)src) / 65536); + + dst = (char *)dst + dst_stride; + src_advance(&src, src_stride, &count, &freqAcc, adj); + } +} + +static void convert_32_to_24 (const void *src, void *dst, UINT src_stride, + UINT dst_stride, INT count, UINT freqAcc, UINT adj) +{ + while (count > 0) + { + DWORD dest = le32(*(const DWORD *)src); + BYTE *dest24 = dst; + + dest24[0] = dest / 256; + dest24[1] = dest / 65536; + dest24[2] = dest / 16777216; + + dst = (char *)dst + dst_stride; + src_advance(&src, src_stride, &count, &freqAcc, adj); + } +} + +static void convert_32_to_32 (const void *src, void *dst, UINT src_stride, + UINT dst_stride, INT count, UINT freqAcc, UINT adj) +{ + while (count > 0) + { + DWORD *dest = dst; + *dest = *(const DWORD *)src; + + dst = (char *)dst + dst_stride; + src_advance(&src, src_stride, &count, &freqAcc, adj); + } +} + +const bitsconvertfunc convertbpp[4][4] = { + { convert_8_to_8, convert_8_to_16, convert_8_to_24, convert_8_to_32 }, + { convert_16_to_8, convert_16_to_16, convert_16_to_24, convert_16_to_32 }, + { convert_24_to_8, convert_24_to_16, convert_24_to_24, convert_24_to_32 }, + { convert_32_to_8, convert_32_to_16, convert_32_to_24, convert_32_to_32 }, +}; + +static void mix8(signed char *src, INT *dst, unsigned len) +{ + TRACE("%p - %p %d\n", src, dst, len); + while (len--) + /* 8-bit WAV is unsigned, it's here converted to signed, normalize function will convert it back again */ + *(dst++) += (signed char)((BYTE)*(src++) - (BYTE)0x80); +} + +static void mix16(SHORT *src, INT *dst, unsigned len) +{ + TRACE("%p - %p %d\n", src, dst, len); + len /= 2; + while (len--) + { + *dst += le16(*src); + ++dst; ++src; + } +} + +static void mix24(BYTE *src, INT *dst, unsigned len) +{ + TRACE("%p - %p %d\n", src, dst, len); + len /= 3; + while (len--) + { + DWORD field; + field = ((DWORD)src[2] << 16) + ((DWORD)src[1] << 8) + (DWORD)src[0]; + if (src[2] & 0x80) + field |= 0xFF000000U; + *(dst++) += field; + ++src; + } +} + +static void mix32(INT *src, LONGLONG *dst, unsigned len) +{ + TRACE("%p - %p %d\n", src, dst, len); + len /= 4; + while (len--) + *(dst++) += le32(*(src++)); +} + +const mixfunc mixfunctions[4] = { + (mixfunc)mix8, + (mixfunc)mix16, + (mixfunc)mix24, + (mixfunc)mix32 +}; + +static void norm8(INT *src, signed char *dst, unsigned len) +{ + TRACE("%p - %p %d\n", src, dst, len); + while (len--) + { + *dst = (*src) + 0x80; + if (*src < -0x80) + *dst = 0; + else if (*src > 0x7f) + *dst = 0xff; + ++dst; + ++src; + } +} + +static void norm16(INT *src, SHORT *dst, unsigned len) +{ + TRACE("%p - %p %d\n", src, dst, len); + len /= 2; + while (len--) + { + *dst = le16(*src); + if (*src <= -0x8000) + *dst = le16(0x8000); + else if (*src > 0x7fff) + *dst = le16(0x7fff); + ++dst; + ++src; + } +} + +static void norm24(INT *src, BYTE *dst, unsigned len) +{ + TRACE("%p - %p %d\n", src, dst, len); + len /= 3; + while (len--) + { + if (*src <= -0x800000) + { + dst[0] = 0; + dst[1] = 0; + dst[2] = 0x80; + } + else if (*src > 0x7fffff) + { + dst[0] = 0xff; + dst[1] = 0xff; + dst[2] = 0x7f; + } + else + { + dst[0] = *src; + dst[1] = *src >> 8; + dst[2] = *src >> 16; + } + ++dst; + ++src; + } +} + +static void norm32(LONGLONG *src, INT *dst, unsigned len) +{ + TRACE("%p - %p %d\n", src, dst, len); + len /= 4; + while (len--) + { + *dst = le32(*src); + if (*src <= -(LONGLONG)0x80000000) + *dst = le32(0x80000000); + else if (*src > 0x7fffffff) + *dst = le32(0x7fffffff); + ++dst; + ++src; + } +} + +const normfunc normfunctions[4] = { + (normfunc)norm8, + (normfunc)norm16, + (normfunc)norm24, + (normfunc)norm32, +}; diff --git a/reactos/dll/directx/dsound_new/primary.c b/reactos/dll/directx/dsound_new/primary.c index 9b5e822e8bc..ab57c706420 100644 --- a/reactos/dll/directx/dsound_new/primary.c +++ b/reactos/dll/directx/dsound_new/primary.c @@ -229,8 +229,37 @@ PrimaryDirectSoundBuffer8Impl_fnPlay( DWORD dwPriority, DWORD dwFlags) { - UNIMPLEMENTED - return DSERR_INVALIDPARAM; + LPCDirectSoundBuffer This = (LPCDirectSoundBuffer)CONTAINING_RECORD(iface, CDirectSoundBuffer, lpVtbl); + + if (dwReserved1 != 0 || !(dwFlags & DSBPLAY_LOOPING)) + { + /* invalid parameter */ + return DSERR_INVALIDPARAM; + } + + PrimaryDirectSoundBuffer_AcquireLock(iface); + + if (This->State == KSSTATE_STOP) + { + PrimaryDirectSoundBuffer_SetState(iface, KSSTATE_ACQUIRE); + ASSERT(This->State == KSSTATE_ACQUIRE); + } + + if (This->State == KSSTATE_ACQUIRE) + { + PrimaryDirectSoundBuffer_SetState(iface, KSSTATE_PAUSE); + ASSERT(This->State == KSSTATE_PAUSE); + } + + if (This->State == KSSTATE_PAUSE) + { + PrimaryDirectSoundBuffer_SetState(iface, KSSTATE_RUN); + ASSERT(This->State == KSSTATE_RUN); + } + + PrimaryDirectSoundBuffer_ReleaseLock(iface); + + return DS_OK; } HRESULT @@ -239,8 +268,8 @@ PrimaryDirectSoundBuffer8Impl_fnSetCurrentPosition( LPDIRECTSOUNDBUFFER8 iface, DWORD dwNewPosition) { - UNIMPLEMENTED - return DSERR_INVALIDPARAM; + /* The position of a primary buffer can't be set */ + return DSERR_INVALIDCALL; } HRESULT @@ -303,8 +332,31 @@ WINAPI PrimaryDirectSoundBuffer8Impl_fnStop( LPDIRECTSOUNDBUFFER8 iface) { - UNIMPLEMENTED - return DSERR_INVALIDPARAM; + LPCDirectSoundBuffer This = (LPCDirectSoundBuffer)CONTAINING_RECORD(iface, CDirectSoundBuffer, lpVtbl); + + PrimaryDirectSoundBuffer_AcquireLock(iface); + + if (This->State == KSSTATE_RUN) + { + PrimaryDirectSoundBuffer_SetState(iface, KSSTATE_PAUSE); + ASSERT(This->State == KSSTATE_PAUSE); + } + + if (This->State == KSSTATE_PAUSE) + { + PrimaryDirectSoundBuffer_SetState(iface, KSSTATE_ACQUIRE); + ASSERT(This->State == KSSTATE_ACQUIRE); + } + + if (This->State == KSSTATE_ACQUIRE) + { + PrimaryDirectSoundBuffer_SetState(iface, KSSTATE_STOP); + ASSERT(This->State == KSSTATE_STOP); + } + + PrimaryDirectSoundBuffer_ReleaseLock(iface); + + return DS_OK; } diff --git a/reactos/dll/directx/dsound_new/secondary.c b/reactos/dll/directx/dsound_new/secondary.c index 4474c2665ea..c2f29bf58a4 100644 --- a/reactos/dll/directx/dsound_new/secondary.c +++ b/reactos/dll/directx/dsound_new/secondary.c @@ -17,6 +17,7 @@ typedef struct LPFILTERINFO Filter; DWORD dwLevel; + DWORD dwFlags; LPWAVEFORMATEX Format; PUCHAR Buffer; DWORD BufferSize; @@ -97,8 +98,27 @@ SecondaryDirectSoundBuffer8Impl_fnGetCaps( LPDIRECTSOUNDBUFFER8 iface, LPDSBCAPS pDSBufferCaps) { - UNIMPLEMENTED - return DSERR_INVALIDPARAM; + LPCDirectSoundBuffer This = (LPCDirectSoundBuffer)CONTAINING_RECORD(iface, CDirectSoundBuffer, lpVtbl); + + if (!pDSBufferCaps) + { + /* invalid parameter */ + return DSERR_INVALIDPARAM; + } + + if (pDSBufferCaps->dwSize < sizeof(DSBCAPS)) + { + /* invalid buffer size */ + return DSERR_INVALIDPARAM; + } + + /* get buffer details */ + pDSBufferCaps->dwUnlockTransferRate = 0; + pDSBufferCaps->dwPlayCpuOverhead = 0; + pDSBufferCaps->dwSize = This->BufferSize; + pDSBufferCaps->dwFlags = This->dwFlags; + + return DS_OK; } HRESULT @@ -528,6 +548,7 @@ NewSecondarySoundBuffer( This->lpVtbl = &vt_DirectSoundBuffer8; This->Filter = Filter; This->dwLevel = dwLevel; + This->dwFlags = lpcDSBufferDesc->dwFlags; This->State = KSSTATE_STOP; This->Flags = 0; This->Position = 0; -- 2.17.1