| /* DirectSound |
| * |
| * Copyright 1998 Marcus Meissner |
| * Copyright 1998 Rob Riggs |
| */ |
| /* |
| * Note: This file requires multithread ability. It is not possible to |
| * implement the stuff in a single thread anyway. And most DirectX apps |
| * require threading themselves. |
| * |
| * Most thread locking is complete. There may be a few race |
| * conditions still lurking. |
| * |
| * Tested with a Soundblaster clone, a Gravis UltraSound Classic, |
| * and a Turtle Beach Tropez+. |
| * |
| * TODO: |
| * Implement DirectSoundCapture API |
| * Implement SetCooperativeLevel properly (need to address focus issues) |
| * Use wavetable synth for static buffers if available |
| * Implement DirectSound3DBuffers (stubs in place) |
| * Use hardware 3D support if available (OSS support may be needed first) |
| * Add support for APIs other than OSS: ALSA (http://alsa.jcu.cz/) |
| * and esound (http://www.gnome.org), for instance |
| * |
| * FIXME: Status needs updating. |
| * |
| * Status: |
| * - Wing Commander 4/W95: |
| * The intromovie plays without problems. Nearly lipsynchron. |
| * - DiscWorld 2 |
| * The sound works, but noticeable chunks are left out (from the sound and |
| * the animation). Don't know why yet. |
| * - Diablo: |
| * Sound works, but slows down the movieplayer. |
| * - XvT: |
| * Doesn't sound yet. |
| * - Monkey Island 3: |
| * The background sound of the startscreen works ;) |
| * - WingCommander Prophecy Demo: |
| * Sound works for the intromovie. |
| * - Total Annihilation (1998/12/04): |
| * Sound plays perfectly in the game, but the Smacker movies |
| * (http://www.smacker.com/) play silently. |
| * - A-10 Cuba! Demo (1998/12/04): |
| * Sound works properly (for some people). |
| * - dsstream.exe, from DirectX 5.2 SDK (1998/12/04): |
| * Works properly, but requires "-dll -winmm". |
| * - dsshow.exe, from DirectX 5.2 SDK (1998/12/04): |
| * Initializes the DLL properly with CoCreateInstance(), but the |
| * FileOpen dialog box is broken - could not test properly |
| */ |
| |
| #include "config.h" |
| #include <assert.h> |
| #include <errno.h> |
| #include <sys/types.h> |
| #include <sys/time.h> |
| #include <sys/fcntl.h> |
| #include <unistd.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <math.h> /* Insomnia - pow() function */ |
| #include "dsound.h" |
| #include "winuser.h" |
| #include "winerror.h" |
| #include "wine/obj_base.h" |
| #include "thread.h" |
| #include "debugtools.h" |
| |
| DEFAULT_DEBUG_CHANNEL(dsound) |
| |
| |
| /***************************************************************************** |
| * Predeclare the interface implementation structures |
| */ |
| typedef struct IDirectSoundImpl IDirectSoundImpl; |
| typedef struct IDirectSoundBufferImpl IDirectSoundBufferImpl; |
| typedef struct IDirectSoundNotifyImpl IDirectSoundNotifyImpl; |
| typedef struct IDirectSound3DListenerImpl IDirectSound3DListenerImpl; |
| typedef struct IDirectSound3DBufferImpl IDirectSound3DBufferImpl; |
| |
| /***************************************************************************** |
| * IDirectSound implementation structure |
| */ |
| struct IDirectSoundImpl |
| { |
| /* IUnknown fields */ |
| ICOM_VTABLE(IDirectSound)* lpvtbl; |
| DWORD ref; |
| /* IDirectSoundImpl fields */ |
| DWORD priolevel; |
| int nrofbuffers; |
| IDirectSoundBufferImpl** buffers; |
| IDirectSoundBufferImpl* primary; |
| IDirectSound3DListenerImpl* listener; |
| WAVEFORMATEX wfx; /* current main waveformat */ |
| }; |
| |
| /***************************************************************************** |
| * IDirectSoundBuffer implementation structure |
| */ |
| struct IDirectSoundBufferImpl |
| { |
| /* IUnknown fields */ |
| ICOM_VTABLE(IDirectSoundBuffer)* lpvtbl; |
| DWORD ref; |
| /* IDirectSoundBufferImpl fields */ |
| WAVEFORMATEX wfx; |
| LPBYTE buffer; |
| IDirectSound3DBufferImpl* ds3db; |
| DWORD playflags,playing; |
| DWORD playpos,writepos,buflen; |
| DWORD nAvgBytesPerSec; |
| DWORD freq; |
| ULONG freqAdjust; |
| LONG volume,pan; |
| LONG lVolAdjust,rVolAdjust; |
| IDirectSoundBufferImpl* parent; /* for duplicates */ |
| IDirectSoundImpl* dsound; |
| DSBUFFERDESC dsbd; |
| LPDSBPOSITIONNOTIFY notifies; |
| int nrofnotifies; |
| CRITICAL_SECTION lock; |
| }; |
| |
| /***************************************************************************** |
| * IDirectSoundNotify implementation structure |
| */ |
| struct IDirectSoundNotifyImpl |
| { |
| /* IUnknown fields */ |
| ICOM_VTABLE(IDirectSoundNotify)* lpvtbl; |
| DWORD ref; |
| /* IDirectSoundNotifyImpl fields */ |
| IDirectSoundBufferImpl* dsb; |
| }; |
| |
| /***************************************************************************** |
| * IDirectSound3DListener implementation structure |
| */ |
| struct IDirectSound3DListenerImpl |
| { |
| /* IUnknown fields */ |
| ICOM_VTABLE(IDirectSound3DListener)* lpvtbl; |
| DWORD ref; |
| /* IDirectSound3DListenerImpl fields */ |
| IDirectSoundBufferImpl* dsb; |
| DS3DLISTENER ds3dl; |
| CRITICAL_SECTION lock; |
| }; |
| |
| /***************************************************************************** |
| * IDirectSound3DBuffer implementation structure |
| */ |
| struct IDirectSound3DBufferImpl |
| { |
| /* IUnknown fields */ |
| ICOM_VTABLE(IDirectSound3DBuffer)* lpvtbl; |
| DWORD ref; |
| /* IDirectSound3DBufferImpl fields */ |
| IDirectSoundBufferImpl* dsb; |
| DS3DBUFFER ds3db; |
| LPBYTE buffer; |
| DWORD buflen; |
| CRITICAL_SECTION lock; |
| }; |
| |
| |
| #ifdef HAVE_OSS |
| # include <sys/ioctl.h> |
| # ifdef HAVE_MACHINE_SOUNDCARD_H |
| # include <machine/soundcard.h> |
| # endif |
| # ifdef HAVE_SYS_SOUNDCARD_H |
| # include <sys/soundcard.h> |
| # endif |
| |
| /* #define USE_DSOUND3D 1 */ |
| |
| #define DSOUND_FRAGLEN (primarybuf->wfx.nAvgBytesPerSec >> 4) |
| #define DSOUND_FREQSHIFT (14) |
| |
| static int audiofd = -1; |
| static int audioOK = 0; |
| |
| static IDirectSoundImpl* dsound = NULL; |
| |
| static IDirectSoundBufferImpl* primarybuf = NULL; |
| |
| static int DSOUND_setformat(LPWAVEFORMATEX wfex); |
| static void DSOUND_CheckEvent(IDirectSoundBufferImpl *dsb, int len); |
| static void DSOUND_CloseAudio(void); |
| |
| #endif |
| |
| |
| HRESULT WINAPI DirectSoundEnumerateA( |
| LPDSENUMCALLBACKA enumcb, |
| LPVOID context) |
| { |
| TRACE("enumcb = %p, context = %p\n", enumcb, context); |
| |
| #ifdef HAVE_OSS |
| if (enumcb != NULL) |
| enumcb(NULL,"WINE DirectSound using Open Sound System", |
| "sound",context); |
| #endif |
| |
| return DS_OK; |
| } |
| |
| #ifdef HAVE_OSS |
| static void _dump_DSBCAPS(DWORD xmask) { |
| struct { |
| DWORD mask; |
| char *name; |
| } flags[] = { |
| #define FE(x) { x, #x }, |
| FE(DSBCAPS_PRIMARYBUFFER) |
| FE(DSBCAPS_STATIC) |
| FE(DSBCAPS_LOCHARDWARE) |
| FE(DSBCAPS_LOCSOFTWARE) |
| FE(DSBCAPS_CTRLFREQUENCY) |
| FE(DSBCAPS_CTRLPAN) |
| FE(DSBCAPS_CTRLVOLUME) |
| FE(DSBCAPS_CTRLDEFAULT) |
| FE(DSBCAPS_CTRLALL) |
| FE(DSBCAPS_STICKYFOCUS) |
| FE(DSBCAPS_GETCURRENTPOSITION2) |
| }; |
| int i; |
| |
| for (i=0;i<sizeof(flags)/sizeof(flags[0]);i++) |
| if (flags[i].mask & xmask) |
| fprintf(stderr,"%s ",flags[i].name); |
| } |
| |
| /******************************************************************************* |
| * IDirectSound3DBuffer |
| */ |
| |
| /* IUnknown methods */ |
| static HRESULT WINAPI IDirectSound3DBufferImpl_QueryInterface( |
| LPDIRECTSOUND3DBUFFER iface, REFIID riid, LPVOID *ppobj) |
| { |
| ICOM_THIS(IDirectSound3DBufferImpl,iface); |
| char xbuf[50]; |
| |
| WINE_StringFromCLSID(riid,xbuf); |
| TRACE("(%p,%s,%p)\n",This,xbuf,ppobj); |
| return E_FAIL; |
| } |
| |
| static ULONG WINAPI IDirectSound3DBufferImpl_AddRef(LPDIRECTSOUND3DBUFFER iface) |
| { |
| ICOM_THIS(IDirectSound3DBufferImpl,iface); |
| This->ref++; |
| return This->ref; |
| } |
| |
| static ULONG WINAPI IDirectSound3DBufferImpl_Release(LPDIRECTSOUND3DBUFFER iface) |
| { |
| ICOM_THIS(IDirectSound3DBufferImpl,iface); |
| if(--This->ref) |
| return This->ref; |
| |
| HeapFree(GetProcessHeap(),0,This->buffer); |
| HeapFree(GetProcessHeap(),0,This); |
| |
| return S_OK; |
| } |
| |
| /* IDirectSound3DBuffer methods */ |
| static HRESULT WINAPI IDirectSound3DBufferImpl_GetAllParameters( |
| LPDIRECTSOUND3DBUFFER iface, |
| LPDS3DBUFFER lpDs3dBuffer) |
| { |
| FIXME("stub\n"); |
| return DS_OK; |
| } |
| |
| static HRESULT WINAPI IDirectSound3DBufferImpl_GetConeAngles( |
| LPDIRECTSOUND3DBUFFER iface, |
| LPDWORD lpdwInsideConeAngle, |
| LPDWORD lpdwOutsideConeAngle) |
| { |
| FIXME("stub\n"); |
| return DS_OK; |
| } |
| |
| static HRESULT WINAPI IDirectSound3DBufferImpl_GetConeOrientation( |
| LPDIRECTSOUND3DBUFFER iface, |
| LPD3DVECTOR lpvConeOrientation) |
| { |
| FIXME("stub\n"); |
| return DS_OK; |
| } |
| |
| static HRESULT WINAPI IDirectSound3DBufferImpl_GetConeOutsideVolume( |
| LPDIRECTSOUND3DBUFFER iface, |
| LPLONG lplConeOutsideVolume) |
| { |
| FIXME("stub\n"); |
| return DS_OK; |
| } |
| |
| static HRESULT WINAPI IDirectSound3DBufferImpl_GetMaxDistance( |
| LPDIRECTSOUND3DBUFFER iface, |
| LPD3DVALUE lpfMaxDistance) |
| { |
| FIXME("stub\n"); |
| return DS_OK; |
| } |
| |
| static HRESULT WINAPI IDirectSound3DBufferImpl_GetMinDistance( |
| LPDIRECTSOUND3DBUFFER iface, |
| LPD3DVALUE lpfMinDistance) |
| { |
| FIXME("stub\n"); |
| return DS_OK; |
| } |
| |
| static HRESULT WINAPI IDirectSound3DBufferImpl_GetMode( |
| LPDIRECTSOUND3DBUFFER iface, |
| LPDWORD lpdwMode) |
| { |
| FIXME("stub\n"); |
| return DS_OK; |
| } |
| |
| static HRESULT WINAPI IDirectSound3DBufferImpl_GetPosition( |
| LPDIRECTSOUND3DBUFFER iface, |
| LPD3DVECTOR lpvPosition) |
| { |
| FIXME("stub\n"); |
| return DS_OK; |
| } |
| |
| static HRESULT WINAPI IDirectSound3DBufferImpl_GetVelocity( |
| LPDIRECTSOUND3DBUFFER iface, |
| LPD3DVECTOR lpvVelocity) |
| { |
| FIXME("stub\n"); |
| return DS_OK; |
| } |
| |
| static HRESULT WINAPI IDirectSound3DBufferImpl_SetAllParameters( |
| LPDIRECTSOUND3DBUFFER iface, |
| LPCDS3DBUFFER lpcDs3dBuffer, |
| DWORD dwApply) |
| { |
| FIXME("stub\n"); |
| return DS_OK; |
| } |
| |
| static HRESULT WINAPI IDirectSound3DBufferImpl_SetConeAngles( |
| LPDIRECTSOUND3DBUFFER iface, |
| DWORD dwInsideConeAngle, |
| DWORD dwOutsideConeAngle, |
| DWORD dwApply) |
| { |
| FIXME("stub\n"); |
| return DS_OK; |
| } |
| |
| static HRESULT WINAPI IDirectSound3DBufferImpl_SetConeOrientation( |
| LPDIRECTSOUND3DBUFFER iface, |
| D3DVALUE x, D3DVALUE y, D3DVALUE z, |
| DWORD dwApply) |
| { |
| FIXME("stub\n"); |
| return DS_OK; |
| } |
| |
| static HRESULT WINAPI IDirectSound3DBufferImpl_SetConeOutsideVolume( |
| LPDIRECTSOUND3DBUFFER iface, |
| LONG lConeOutsideVolume, |
| DWORD dwApply) |
| { |
| FIXME("stub\n"); |
| return DS_OK; |
| } |
| |
| static HRESULT WINAPI IDirectSound3DBufferImpl_SetMaxDistance( |
| LPDIRECTSOUND3DBUFFER iface, |
| D3DVALUE fMaxDistance, |
| DWORD dwApply) |
| { |
| FIXME("stub\n"); |
| return DS_OK; |
| } |
| |
| static HRESULT WINAPI IDirectSound3DBufferImpl_SetMinDistance( |
| LPDIRECTSOUND3DBUFFER iface, |
| D3DVALUE fMinDistance, |
| DWORD dwApply) |
| { |
| FIXME("stub\n"); |
| return DS_OK; |
| } |
| |
| static HRESULT WINAPI IDirectSound3DBufferImpl_SetMode( |
| LPDIRECTSOUND3DBUFFER iface, |
| DWORD dwMode, |
| DWORD dwApply) |
| { |
| ICOM_THIS(IDirectSound3DBufferImpl,iface); |
| TRACE("mode = %lx\n", dwMode); |
| This->ds3db.dwMode = dwMode; |
| return DS_OK; |
| } |
| |
| static HRESULT WINAPI IDirectSound3DBufferImpl_SetPosition( |
| LPDIRECTSOUND3DBUFFER iface, |
| D3DVALUE x, D3DVALUE y, D3DVALUE z, |
| DWORD dwApply) |
| { |
| FIXME("stub\n"); |
| return DS_OK; |
| } |
| |
| static HRESULT WINAPI IDirectSound3DBufferImpl_SetVelocity( |
| LPDIRECTSOUND3DBUFFER iface, |
| D3DVALUE x, D3DVALUE y, D3DVALUE z, |
| DWORD dwApply) |
| { |
| FIXME("stub\n"); |
| return DS_OK; |
| } |
| |
| ICOM_VTABLE(IDirectSound3DBuffer) ds3dbvt = |
| { |
| ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE |
| /* IUnknown methods */ |
| IDirectSound3DBufferImpl_QueryInterface, |
| IDirectSound3DBufferImpl_AddRef, |
| IDirectSound3DBufferImpl_Release, |
| /* IDirectSound3DBuffer methods */ |
| IDirectSound3DBufferImpl_GetAllParameters, |
| IDirectSound3DBufferImpl_GetConeAngles, |
| IDirectSound3DBufferImpl_GetConeOrientation, |
| IDirectSound3DBufferImpl_GetConeOutsideVolume, |
| IDirectSound3DBufferImpl_GetMaxDistance, |
| IDirectSound3DBufferImpl_GetMinDistance, |
| IDirectSound3DBufferImpl_GetMode, |
| IDirectSound3DBufferImpl_GetPosition, |
| IDirectSound3DBufferImpl_GetVelocity, |
| IDirectSound3DBufferImpl_SetAllParameters, |
| IDirectSound3DBufferImpl_SetConeAngles, |
| IDirectSound3DBufferImpl_SetConeOrientation, |
| IDirectSound3DBufferImpl_SetConeOutsideVolume, |
| IDirectSound3DBufferImpl_SetMaxDistance, |
| IDirectSound3DBufferImpl_SetMinDistance, |
| IDirectSound3DBufferImpl_SetMode, |
| IDirectSound3DBufferImpl_SetPosition, |
| IDirectSound3DBufferImpl_SetVelocity, |
| }; |
| |
| #ifdef USE_DSOUND3D |
| static int DSOUND_Create3DBuffer(IDirectSoundBufferImpl* dsb) |
| { |
| DWORD i, temp, iSize, oSize, offset; |
| LPBYTE bIbuf, bObuf, bTbuf = NULL; |
| LPWORD wIbuf, wObuf, wTbuf = NULL; |
| |
| /* Inside DirectX says it's stupid but allowed */ |
| if (dsb->wfx.nChannels == 2) { |
| /* Convert to mono */ |
| if (dsb->wfx.wBitsPerSample == 16) { |
| iSize = dsb->buflen / 4; |
| wTbuf = malloc(dsb->buflen / 2); |
| if (wTbuf == NULL) |
| return DSERR_OUTOFMEMORY; |
| for (i = 0; i < iSize; i++) |
| wTbuf[i] = (dsb->buffer[i] + dsb->buffer[(i * 2) + 1]) / 2; |
| wIbuf = wTbuf; |
| } else { |
| iSize = dsb->buflen / 2; |
| bTbuf = malloc(dsb->buflen / 2); |
| if (bTbuf == NULL) |
| return DSERR_OUTOFMEMORY; |
| for (i = 0; i < iSize; i++) |
| bTbuf[i] = (dsb->buffer[i] + dsb->buffer[(i * 2) + 1]) / 2; |
| bIbuf = bTbuf; |
| } |
| } else { |
| if (dsb->wfx.wBitsPerSample == 16) { |
| iSize = dsb->buflen / 2; |
| wIbuf = (LPWORD) dsb->buffer; |
| } else { |
| bIbuf = (LPBYTE) dsb->buffer; |
| iSize = dsb->buflen; |
| } |
| } |
| |
| if (primarybuf->wfx.wBitsPerSample == 16) { |
| wObuf = (LPWORD) dsb->ds3db->buffer; |
| oSize = dsb->ds3db->buflen / 2; |
| } else { |
| bObuf = (LPBYTE) dsb->ds3db->buffer; |
| oSize = dsb->ds3db->buflen; |
| } |
| |
| offset = primarybuf->wfx.nSamplesPerSec / 100; /* 10ms */ |
| if (primarybuf->wfx.wBitsPerSample == 16 && dsb->wfx.wBitsPerSample == 16) |
| for (i = 0; i < iSize; i++) { |
| temp = wIbuf[i]; |
| if (i >= offset) |
| temp += wIbuf[i - offset] >> 9; |
| else |
| temp += wIbuf[i + iSize - offset] >> 9; |
| wObuf[i * 2] = temp; |
| wObuf[(i * 2) + 1] = temp; |
| } |
| else if (primarybuf->wfx.wBitsPerSample == 8 && dsb->wfx.wBitsPerSample == 8) |
| for (i = 0; i < iSize; i++) { |
| temp = bIbuf[i]; |
| if (i >= offset) |
| temp += bIbuf[i - offset] >> 5; |
| else |
| temp += bIbuf[i + iSize - offset] >> 5; |
| bObuf[i * 2] = temp; |
| bObuf[(i * 2) + 1] = temp; |
| } |
| |
| if (wTbuf) |
| free(wTbuf); |
| if (bTbuf) |
| free(bTbuf); |
| |
| return DS_OK; |
| } |
| #endif |
| /******************************************************************************* |
| * IDirectSound3DListener |
| */ |
| |
| /* IUnknown methods */ |
| static HRESULT WINAPI IDirectSound3DListenerImpl_QueryInterface( |
| LPDIRECTSOUND3DLISTENER iface, REFIID riid, LPVOID *ppobj) |
| { |
| ICOM_THIS(IDirectSound3DListenerImpl,iface); |
| char xbuf[50]; |
| |
| WINE_StringFromCLSID(riid,xbuf); |
| TRACE("(%p,%s,%p)\n",This,xbuf,ppobj); |
| return E_FAIL; |
| } |
| |
| static ULONG WINAPI IDirectSound3DListenerImpl_AddRef(LPDIRECTSOUND3DLISTENER iface) |
| { |
| ICOM_THIS(IDirectSound3DListenerImpl,iface); |
| This->ref++; |
| return This->ref; |
| } |
| |
| static ULONG WINAPI IDirectSound3DListenerImpl_Release(LPDIRECTSOUND3DLISTENER iface) |
| { |
| ICOM_THIS(IDirectSound3DListenerImpl,iface); |
| This->ref--; |
| return This->ref; |
| } |
| |
| /* IDirectSound3DListener methods */ |
| static HRESULT WINAPI IDirectSound3DListenerImpl_GetAllParameter( |
| LPDIRECTSOUND3DLISTENER iface, |
| LPDS3DLISTENER lpDS3DL) |
| { |
| FIXME("stub\n"); |
| return DS_OK; |
| } |
| |
| static HRESULT WINAPI IDirectSound3DListenerImpl_GetDistanceFactor( |
| LPDIRECTSOUND3DLISTENER iface, |
| LPD3DVALUE lpfDistanceFactor) |
| { |
| FIXME("stub\n"); |
| return DS_OK; |
| } |
| |
| static HRESULT WINAPI IDirectSound3DListenerImpl_GetDopplerFactor( |
| LPDIRECTSOUND3DLISTENER iface, |
| LPD3DVALUE lpfDopplerFactor) |
| { |
| FIXME("stub\n"); |
| return DS_OK; |
| } |
| |
| static HRESULT WINAPI IDirectSound3DListenerImpl_GetOrientation( |
| LPDIRECTSOUND3DLISTENER iface, |
| LPD3DVECTOR lpvOrientFront, |
| LPD3DVECTOR lpvOrientTop) |
| { |
| FIXME("stub\n"); |
| return DS_OK; |
| } |
| |
| static HRESULT WINAPI IDirectSound3DListenerImpl_GetPosition( |
| LPDIRECTSOUND3DLISTENER iface, |
| LPD3DVECTOR lpvPosition) |
| { |
| FIXME("stub\n"); |
| return DS_OK; |
| } |
| |
| static HRESULT WINAPI IDirectSound3DListenerImpl_GetRolloffFactor( |
| LPDIRECTSOUND3DLISTENER iface, |
| LPD3DVALUE lpfRolloffFactor) |
| { |
| FIXME("stub\n"); |
| return DS_OK; |
| } |
| |
| static HRESULT WINAPI IDirectSound3DListenerImpl_GetVelocity( |
| LPDIRECTSOUND3DLISTENER iface, |
| LPD3DVECTOR lpvVelocity) |
| { |
| FIXME("stub\n"); |
| return DS_OK; |
| } |
| |
| static HRESULT WINAPI IDirectSound3DListenerImpl_SetAllParameters( |
| LPDIRECTSOUND3DLISTENER iface, |
| LPCDS3DLISTENER lpcDS3DL, |
| DWORD dwApply) |
| { |
| FIXME("stub\n"); |
| return DS_OK; |
| } |
| |
| static HRESULT WINAPI IDirectSound3DListenerImpl_SetDistanceFactor( |
| LPDIRECTSOUND3DLISTENER iface, |
| D3DVALUE fDistanceFactor, |
| DWORD dwApply) |
| { |
| FIXME("stub\n"); |
| return DS_OK; |
| } |
| |
| static HRESULT WINAPI IDirectSound3DListenerImpl_SetDopplerFactor( |
| LPDIRECTSOUND3DLISTENER iface, |
| D3DVALUE fDopplerFactor, |
| DWORD dwApply) |
| { |
| FIXME("stub\n"); |
| return DS_OK; |
| } |
| |
| static HRESULT WINAPI IDirectSound3DListenerImpl_SetOrientation( |
| LPDIRECTSOUND3DLISTENER iface, |
| D3DVALUE xFront, D3DVALUE yFront, D3DVALUE zFront, |
| D3DVALUE xTop, D3DVALUE yTop, D3DVALUE zTop, |
| DWORD dwApply) |
| { |
| FIXME("stub\n"); |
| return DS_OK; |
| } |
| |
| static HRESULT WINAPI IDirectSound3DListenerImpl_SetPosition( |
| LPDIRECTSOUND3DLISTENER iface, |
| D3DVALUE x, D3DVALUE y, D3DVALUE z, |
| DWORD dwApply) |
| { |
| FIXME("stub\n"); |
| return DS_OK; |
| } |
| |
| static HRESULT WINAPI IDirectSound3DListenerImpl_SetRolloffFactor( |
| LPDIRECTSOUND3DLISTENER iface, |
| D3DVALUE fRolloffFactor, |
| DWORD dwApply) |
| { |
| FIXME("stub\n"); |
| return DS_OK; |
| } |
| |
| static HRESULT WINAPI IDirectSound3DListenerImpl_SetVelocity( |
| LPDIRECTSOUND3DLISTENER iface, |
| D3DVALUE x, D3DVALUE y, D3DVALUE z, |
| DWORD dwApply) |
| { |
| FIXME("stub\n"); |
| return DS_OK; |
| } |
| |
| static HRESULT WINAPI IDirectSound3DListenerImpl_CommitDeferredSettings( |
| LPDIRECTSOUND3DLISTENER iface) |
| |
| { |
| FIXME("stub\n"); |
| return DS_OK; |
| } |
| |
| ICOM_VTABLE(IDirectSound3DListener) ds3dlvt = |
| { |
| ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE |
| /* IUnknown methods */ |
| IDirectSound3DListenerImpl_QueryInterface, |
| IDirectSound3DListenerImpl_AddRef, |
| IDirectSound3DListenerImpl_Release, |
| /* IDirectSound3DListener methods */ |
| IDirectSound3DListenerImpl_GetAllParameter, |
| IDirectSound3DListenerImpl_GetDistanceFactor, |
| IDirectSound3DListenerImpl_GetDopplerFactor, |
| IDirectSound3DListenerImpl_GetOrientation, |
| IDirectSound3DListenerImpl_GetPosition, |
| IDirectSound3DListenerImpl_GetRolloffFactor, |
| IDirectSound3DListenerImpl_GetVelocity, |
| IDirectSound3DListenerImpl_SetAllParameters, |
| IDirectSound3DListenerImpl_SetDistanceFactor, |
| IDirectSound3DListenerImpl_SetDopplerFactor, |
| IDirectSound3DListenerImpl_SetOrientation, |
| IDirectSound3DListenerImpl_SetPosition, |
| IDirectSound3DListenerImpl_SetRolloffFactor, |
| IDirectSound3DListenerImpl_SetVelocity, |
| IDirectSound3DListenerImpl_CommitDeferredSettings, |
| }; |
| |
| /******************************************************************************* |
| * IDirectSoundNotify |
| */ |
| static HRESULT WINAPI IDirectSoundNotifyImpl_QueryInterface( |
| LPDIRECTSOUNDNOTIFY iface,REFIID riid,LPVOID *ppobj |
| ) { |
| ICOM_THIS(IDirectSoundNotifyImpl,iface); |
| char xbuf[50]; |
| |
| WINE_StringFromCLSID(riid,xbuf); |
| TRACE("(%p,%s,%p)\n",This,xbuf,ppobj); |
| return E_FAIL; |
| } |
| |
| static ULONG WINAPI IDirectSoundNotifyImpl_AddRef(LPDIRECTSOUNDNOTIFY iface) { |
| ICOM_THIS(IDirectSoundNotifyImpl,iface); |
| return ++(This->ref); |
| } |
| |
| static ULONG WINAPI IDirectSoundNotifyImpl_Release(LPDIRECTSOUNDNOTIFY iface) { |
| ICOM_THIS(IDirectSoundNotifyImpl,iface); |
| This->ref--; |
| if (!This->ref) { |
| IDirectSoundNotify_Release((LPDIRECTSOUNDBUFFER)This->dsb); |
| HeapFree(GetProcessHeap(),0,This); |
| return S_OK; |
| } |
| return This->ref; |
| } |
| |
| static HRESULT WINAPI IDirectSoundNotifyImpl_SetNotificationPositions( |
| LPDIRECTSOUNDNOTIFY iface,DWORD howmuch,LPCDSBPOSITIONNOTIFY notify |
| ) { |
| ICOM_THIS(IDirectSoundNotifyImpl,iface); |
| int i; |
| |
| if (TRACE_ON(dsound)) { |
| TRACE("(%p,0x%08lx,%p)\n",This,howmuch,notify); |
| for (i=0;i<howmuch;i++) |
| TRACE("notify at %ld to 0x%08lx\n", |
| notify[i].dwOffset,(DWORD)notify[i].hEventNotify); |
| } |
| This->dsb->notifies = HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,This->dsb->notifies,(This->dsb->nrofnotifies+howmuch)*sizeof(DSBPOSITIONNOTIFY)); |
| memcpy( This->dsb->notifies+This->dsb->nrofnotifies, |
| notify, |
| howmuch*sizeof(DSBPOSITIONNOTIFY) |
| ); |
| This->dsb->nrofnotifies+=howmuch; |
| |
| return S_OK; |
| } |
| |
| ICOM_VTABLE(IDirectSoundNotify) dsnvt = |
| { |
| ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE |
| IDirectSoundNotifyImpl_QueryInterface, |
| IDirectSoundNotifyImpl_AddRef, |
| IDirectSoundNotifyImpl_Release, |
| IDirectSoundNotifyImpl_SetNotificationPositions, |
| }; |
| |
| /******************************************************************************* |
| * IDirectSoundBuffer |
| */ |
| |
| /* This sets this format for the <em>Primary Buffer Only</em> */ |
| /* See file:///cdrom/sdk52/docs/worddoc/dsound.doc page 120 */ |
| static HRESULT WINAPI IDirectSoundBufferImpl_SetFormat( |
| LPDIRECTSOUNDBUFFER iface,LPWAVEFORMATEX wfex |
| ) { |
| ICOM_THIS(IDirectSoundBufferImpl,iface); |
| IDirectSoundBufferImpl** dsb; |
| int i; |
| |
| /* Let's be pedantic! */ |
| if ((wfex == NULL) || |
| (wfex->wFormatTag != WAVE_FORMAT_PCM) || |
| (wfex->nChannels < 1) || (wfex->nChannels > 2) || |
| (wfex->nSamplesPerSec < 1) || |
| (wfex->nBlockAlign < 1) || (wfex->nChannels > 4) || |
| ((wfex->wBitsPerSample != 8) && (wfex->wBitsPerSample != 16))) { |
| TRACE("failed pedantic check!\n"); |
| return DSERR_INVALIDPARAM; |
| } |
| |
| /* **** */ |
| EnterCriticalSection(&(primarybuf->lock)); |
| |
| if (primarybuf->wfx.nSamplesPerSec != wfex->nSamplesPerSec) { |
| dsb = dsound->buffers; |
| for (i = 0; i < dsound->nrofbuffers; i++, dsb++) { |
| /* **** */ |
| EnterCriticalSection(&((*dsb)->lock)); |
| |
| (*dsb)->freqAdjust = ((*dsb)->freq << DSOUND_FREQSHIFT) / |
| wfex->nSamplesPerSec; |
| |
| LeaveCriticalSection(&((*dsb)->lock)); |
| /* **** */ |
| } |
| } |
| |
| memcpy(&(primarybuf->wfx), wfex, sizeof(primarybuf->wfx)); |
| |
| TRACE("(formattag=0x%04x,chans=%d,samplerate=%ld" |
| "bytespersec=%ld,blockalign=%d,bitspersamp=%d,cbSize=%d)\n", |
| wfex->wFormatTag, wfex->nChannels, wfex->nSamplesPerSec, |
| wfex->nAvgBytesPerSec, wfex->nBlockAlign, |
| wfex->wBitsPerSample, wfex->cbSize); |
| |
| primarybuf->wfx.nAvgBytesPerSec = |
| This->wfx.nSamplesPerSec * This->wfx.nBlockAlign; |
| |
| DSOUND_CloseAudio(); |
| |
| LeaveCriticalSection(&(primarybuf->lock)); |
| /* **** */ |
| |
| return DS_OK; |
| } |
| |
| static HRESULT WINAPI IDirectSoundBufferImpl_SetVolume( |
| LPDIRECTSOUNDBUFFER iface,LONG vol |
| ) { |
| ICOM_THIS(IDirectSoundBufferImpl,iface); |
| double temp; |
| |
| TRACE("(%p,%ld)\n",This,vol); |
| |
| /* I'm not sure if we need this for primary buffer */ |
| if (!(This->dsbd.dwFlags & DSBCAPS_CTRLVOLUME)) |
| return DSERR_CONTROLUNAVAIL; |
| |
| if ((vol > DSBVOLUME_MAX) || (vol < DSBVOLUME_MIN)) |
| return DSERR_INVALIDPARAM; |
| |
| /* This needs to adjust the soundcard volume when */ |
| /* called for the primary buffer */ |
| if (This->dsbd.dwFlags & DSBCAPS_PRIMARYBUFFER) { |
| FIXME("Volume control of primary unimplemented.\n"); |
| This->volume = vol; |
| return DS_OK; |
| } |
| |
| /* **** */ |
| EnterCriticalSection(&(This->lock)); |
| |
| This->volume = vol; |
| |
| temp = (double) (This->volume - (This->pan > 0 ? This->pan : 0)); |
| This->lVolAdjust = (ULONG) (pow(2.0, temp / 600.0) * 32768.0); |
| temp = (double) (This->volume + (This->pan < 0 ? This->pan : 0)); |
| This->rVolAdjust = (ULONG) (pow(2.0, temp / 600.0) * 32768.0); |
| |
| LeaveCriticalSection(&(This->lock)); |
| /* **** */ |
| |
| TRACE("left = %lx, right = %lx\n", This->lVolAdjust, This->rVolAdjust); |
| |
| return DS_OK; |
| } |
| |
| static HRESULT WINAPI IDirectSoundBufferImpl_GetVolume( |
| LPDIRECTSOUNDBUFFER iface,LPLONG vol |
| ) { |
| ICOM_THIS(IDirectSoundBufferImpl,iface); |
| TRACE("(%p,%p)\n",This,vol); |
| |
| if (vol == NULL) |
| return DSERR_INVALIDPARAM; |
| |
| *vol = This->volume; |
| return DS_OK; |
| } |
| |
| static HRESULT WINAPI IDirectSoundBufferImpl_SetFrequency( |
| LPDIRECTSOUNDBUFFER iface,DWORD freq |
| ) { |
| ICOM_THIS(IDirectSoundBufferImpl,iface); |
| TRACE("(%p,%ld)\n",This,freq); |
| |
| /* You cannot set the frequency of the primary buffer */ |
| if (!(This->dsbd.dwFlags & DSBCAPS_CTRLFREQUENCY) || |
| (This->dsbd.dwFlags & DSBCAPS_PRIMARYBUFFER)) |
| return DSERR_CONTROLUNAVAIL; |
| |
| if ((freq < DSBFREQUENCY_MIN) || (freq > DSBFREQUENCY_MAX)) |
| return DSERR_INVALIDPARAM; |
| |
| /* **** */ |
| EnterCriticalSection(&(This->lock)); |
| |
| This->freq = freq; |
| This->freqAdjust = (freq << DSOUND_FREQSHIFT) / primarybuf->wfx.nSamplesPerSec; |
| This->nAvgBytesPerSec = freq * This->wfx.nBlockAlign; |
| |
| LeaveCriticalSection(&(This->lock)); |
| /* **** */ |
| |
| return DS_OK; |
| } |
| |
| static HRESULT WINAPI IDirectSoundBufferImpl_Play( |
| LPDIRECTSOUNDBUFFER iface,DWORD reserved1,DWORD reserved2,DWORD flags |
| ) { |
| ICOM_THIS(IDirectSoundBufferImpl,iface); |
| TRACE("(%p,%08lx,%08lx,%08lx)\n", |
| This,reserved1,reserved2,flags |
| ); |
| This->playflags = flags; |
| This->playing = 1; |
| return DS_OK; |
| } |
| |
| static HRESULT WINAPI IDirectSoundBufferImpl_Stop(LPDIRECTSOUNDBUFFER iface) |
| { |
| ICOM_THIS(IDirectSoundBufferImpl,iface); |
| TRACE("(%p)\n",This); |
| |
| /* **** */ |
| EnterCriticalSection(&(This->lock)); |
| |
| This->playing = 0; |
| DSOUND_CheckEvent(This, 0); |
| |
| LeaveCriticalSection(&(This->lock)); |
| /* **** */ |
| |
| return DS_OK; |
| } |
| |
| static DWORD WINAPI IDirectSoundBufferImpl_AddRef(LPDIRECTSOUNDBUFFER iface) { |
| ICOM_THIS(IDirectSoundBufferImpl,iface); |
| /* TRACE(dsound,"(%p) ref was %ld\n",This, This->ref); */ |
| |
| return ++(This->ref); |
| } |
| static DWORD WINAPI IDirectSoundBufferImpl_Release(LPDIRECTSOUNDBUFFER iface) { |
| ICOM_THIS(IDirectSoundBufferImpl,iface); |
| int i; |
| |
| /* TRACE(dsound,"(%p) ref was %ld\n",This, This->ref); */ |
| |
| if (--This->ref) |
| return This->ref; |
| |
| for (i=0;i<This->dsound->nrofbuffers;i++) |
| if (This->dsound->buffers[i] == This) |
| break; |
| if (i < This->dsound->nrofbuffers) { |
| /* Put the last buffer of the list in the (now empty) position */ |
| This->dsound->buffers[i] = This->dsound->buffers[This->dsound->nrofbuffers - 1]; |
| This->dsound->buffers = HeapReAlloc(GetProcessHeap(),0,This->dsound->buffers,sizeof(LPDIRECTSOUNDBUFFER)*This->dsound->nrofbuffers); |
| This->dsound->nrofbuffers--; |
| IDirectSound_Release((LPDIRECTSOUND)This->dsound); |
| } |
| |
| DeleteCriticalSection(&(This->lock)); |
| |
| if (This->ds3db && This->ds3db->lpvtbl) |
| IDirectSound3DBuffer_Release((LPDIRECTSOUND3DBUFFER)This->ds3db); |
| |
| if (This->parent) |
| /* this is a duplicate buffer */ |
| IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER)This->parent); |
| else |
| /* this is a toplevel buffer */ |
| HeapFree(GetProcessHeap(),0,This->buffer); |
| |
| HeapFree(GetProcessHeap(),0,This); |
| |
| if (This == primarybuf) |
| primarybuf = NULL; |
| |
| return DS_OK; |
| } |
| |
| static HRESULT WINAPI IDirectSoundBufferImpl_GetCurrentPosition( |
| LPDIRECTSOUNDBUFFER iface,LPDWORD playpos,LPDWORD writepos |
| ) { |
| ICOM_THIS(IDirectSoundBufferImpl,iface); |
| TRACE("(%p,%p,%p)\n",This,playpos,writepos); |
| if (playpos) *playpos = This->playpos; |
| if (writepos) *writepos = This->writepos; |
| TRACE("playpos = %ld, writepos = %ld\n", playpos?*playpos:0, writepos?*writepos:0); |
| return DS_OK; |
| } |
| |
| static HRESULT WINAPI IDirectSoundBufferImpl_GetStatus( |
| LPDIRECTSOUNDBUFFER iface,LPDWORD status |
| ) { |
| ICOM_THIS(IDirectSoundBufferImpl,iface); |
| TRACE("(%p,%p)\n",This,status); |
| |
| if (status == NULL) |
| return DSERR_INVALIDPARAM; |
| |
| *status = 0; |
| if (This->playing) |
| *status |= DSBSTATUS_PLAYING; |
| if (This->playflags & DSBPLAY_LOOPING) |
| *status |= DSBSTATUS_LOOPING; |
| |
| return DS_OK; |
| } |
| |
| |
| static HRESULT WINAPI IDirectSoundBufferImpl_GetFormat( |
| LPDIRECTSOUNDBUFFER iface,LPWAVEFORMATEX lpwf,DWORD wfsize,LPDWORD wfwritten |
| ) { |
| ICOM_THIS(IDirectSoundBufferImpl,iface); |
| TRACE("(%p,%p,%ld,%p)\n",This,lpwf,wfsize,wfwritten); |
| |
| if (wfsize>sizeof(This->wfx)) |
| wfsize = sizeof(This->wfx); |
| if (lpwf) { /* NULL is valid */ |
| memcpy(lpwf,&(This->wfx),wfsize); |
| if (wfwritten) |
| *wfwritten = wfsize; |
| } else |
| if (wfwritten) |
| *wfwritten = sizeof(This->wfx); |
| else |
| return DSERR_INVALIDPARAM; |
| |
| return DS_OK; |
| } |
| |
| static HRESULT WINAPI IDirectSoundBufferImpl_Lock( |
| LPDIRECTSOUNDBUFFER iface,DWORD writecursor,DWORD writebytes,LPVOID lplpaudioptr1,LPDWORD audiobytes1,LPVOID lplpaudioptr2,LPDWORD audiobytes2,DWORD flags |
| ) { |
| ICOM_THIS(IDirectSoundBufferImpl,iface); |
| |
| TRACE("(%p,%ld,%ld,%p,%p,%p,%p,0x%08lx)\n", |
| This, |
| writecursor, |
| writebytes, |
| lplpaudioptr1, |
| audiobytes1, |
| lplpaudioptr2, |
| audiobytes2, |
| flags |
| ); |
| if (flags & DSBLOCK_FROMWRITECURSOR) |
| writecursor += This->writepos; |
| if (flags & DSBLOCK_ENTIREBUFFER) |
| writebytes = This->buflen; |
| if (writebytes > This->buflen) |
| writebytes = This->buflen; |
| |
| assert(audiobytes1!=audiobytes2); |
| assert(lplpaudioptr1!=lplpaudioptr2); |
| if (writecursor+writebytes <= This->buflen) { |
| *(LPBYTE*)lplpaudioptr1 = This->buffer+writecursor; |
| *audiobytes1 = writebytes; |
| if (lplpaudioptr2) |
| *(LPBYTE*)lplpaudioptr2 = NULL; |
| if (audiobytes2) |
| *audiobytes2 = 0; |
| TRACE("->%ld.0\n",writebytes); |
| } else { |
| *(LPBYTE*)lplpaudioptr1 = This->buffer+writecursor; |
| *audiobytes1 = This->buflen-writecursor; |
| if (lplpaudioptr2) |
| *(LPBYTE*)lplpaudioptr2 = This->buffer; |
| if (audiobytes2) |
| *audiobytes2 = writebytes-(This->buflen-writecursor); |
| TRACE("->%ld.%ld\n",*audiobytes1,audiobytes2?*audiobytes2:0); |
| } |
| /* No. See file:///cdrom/sdk52/docs/worddoc/dsound.doc page 21 */ |
| /* This->writepos=(writecursor+writebytes)%This->buflen; */ |
| return DS_OK; |
| } |
| |
| static HRESULT WINAPI IDirectSoundBufferImpl_SetCurrentPosition( |
| LPDIRECTSOUNDBUFFER iface,DWORD newpos |
| ) { |
| ICOM_THIS(IDirectSoundBufferImpl,iface); |
| TRACE("(%p,%ld)\n",This,newpos); |
| |
| /* **** */ |
| EnterCriticalSection(&(This->lock)); |
| |
| This->playpos = newpos; |
| |
| LeaveCriticalSection(&(This->lock)); |
| /* **** */ |
| |
| return DS_OK; |
| } |
| |
| static HRESULT WINAPI IDirectSoundBufferImpl_SetPan( |
| LPDIRECTSOUNDBUFFER iface,LONG pan |
| ) { |
| ICOM_THIS(IDirectSoundBufferImpl,iface); |
| double temp; |
| |
| TRACE("(%p,%ld)\n",This,pan); |
| |
| if ((pan > DSBPAN_RIGHT) || (pan < DSBPAN_LEFT)) |
| return DSERR_INVALIDPARAM; |
| |
| /* You cannot set the pan of the primary buffer */ |
| /* and you cannot use both pan and 3D controls */ |
| if (!(This->dsbd.dwFlags & DSBCAPS_CTRLPAN) || |
| (This->dsbd.dwFlags & DSBCAPS_CTRL3D) || |
| (This->dsbd.dwFlags & DSBCAPS_PRIMARYBUFFER)) |
| return DSERR_CONTROLUNAVAIL; |
| |
| /* **** */ |
| EnterCriticalSection(&(This->lock)); |
| |
| This->pan = pan; |
| |
| temp = (double) (This->volume - (This->pan > 0 ? This->pan : 0)); |
| This->lVolAdjust = (ULONG) (pow(2.0, temp / 600.0) * 32768.0); |
| temp = (double) (This->volume + (This->pan < 0 ? This->pan : 0)); |
| This->rVolAdjust = (ULONG) (pow(2.0, temp / 600.0) * 32768.0); |
| |
| LeaveCriticalSection(&(This->lock)); |
| /* **** */ |
| |
| return DS_OK; |
| } |
| |
| static HRESULT WINAPI IDirectSoundBufferImpl_GetPan( |
| LPDIRECTSOUNDBUFFER iface,LPLONG pan |
| ) { |
| ICOM_THIS(IDirectSoundBufferImpl,iface); |
| TRACE("(%p,%p)\n",This,pan); |
| |
| if (pan == NULL) |
| return DSERR_INVALIDPARAM; |
| |
| *pan = This->pan; |
| |
| return DS_OK; |
| } |
| |
| static HRESULT WINAPI IDirectSoundBufferImpl_Unlock( |
| LPDIRECTSOUNDBUFFER iface,LPVOID p1,DWORD x1,LPVOID p2,DWORD x2 |
| ) { |
| ICOM_THIS(IDirectSoundBufferImpl,iface); |
| TRACE("(%p,%p,%ld,%p,%ld):stub\n", This,p1,x1,p2,x2); |
| |
| /* There is really nothing to do here. Should someone */ |
| /* choose to implement static buffers in hardware (by */ |
| /* using a wave table synth, for example) this is where */ |
| /* you'd want to do the loading. For software buffers, */ |
| /* which is what we currently use, we need do nothing. */ |
| |
| #if 0 |
| /* It's also the place to pre-process 3D buffers... */ |
| |
| /* This is highly experimental and liable to break things */ |
| if (This->dsbd.dwFlags & DSBCAPS_CTRL3D) |
| DSOUND_Create3DBuffer(This); |
| #endif |
| |
| return DS_OK; |
| } |
| |
| static HRESULT WINAPI IDirectSoundBufferImpl_GetFrequency( |
| LPDIRECTSOUNDBUFFER iface,LPDWORD freq |
| ) { |
| ICOM_THIS(IDirectSoundBufferImpl,iface); |
| TRACE("(%p,%p)\n",This,freq); |
| |
| if (freq == NULL) |
| return DSERR_INVALIDPARAM; |
| |
| *freq = This->freq; |
| |
| return DS_OK; |
| } |
| |
| static HRESULT WINAPI IDirectSoundBufferImpl_Initialize( |
| LPDIRECTSOUNDBUFFER iface,LPDIRECTSOUND dsound,LPDSBUFFERDESC dbsd |
| ) { |
| ICOM_THIS(IDirectSoundBufferImpl,iface); |
| FIXME("(%p,%p,%p):stub\n",This,dsound,dbsd); |
| printf("Re-Init!!!\n"); |
| return DSERR_ALREADYINITIALIZED; |
| } |
| |
| static HRESULT WINAPI IDirectSoundBufferImpl_GetCaps( |
| LPDIRECTSOUNDBUFFER iface,LPDSBCAPS caps |
| ) { |
| ICOM_THIS(IDirectSoundBufferImpl,iface); |
| TRACE("(%p)->(%p)\n",This,caps); |
| |
| if (caps == NULL) |
| return DSERR_INVALIDPARAM; |
| |
| /* I think we should check this value, not set it. See */ |
| /* Inside DirectX, p215. That should apply here, too. */ |
| caps->dwSize = sizeof(*caps); |
| |
| caps->dwFlags = This->dsbd.dwFlags | DSBCAPS_LOCSOFTWARE; |
| caps->dwBufferBytes = This->dsbd.dwBufferBytes; |
| /* This value represents the speed of the "unlock" command. |
| As unlock is quite fast (it does not do anything), I put |
| 4096 ko/s = 4 Mo / s */ |
| caps->dwUnlockTransferRate = 4096; |
| caps->dwPlayCpuOverhead = 0; |
| |
| return DS_OK; |
| } |
| |
| static HRESULT WINAPI IDirectSoundBufferImpl_QueryInterface( |
| LPDIRECTSOUNDBUFFER iface,REFIID riid,LPVOID *ppobj |
| ) { |
| ICOM_THIS(IDirectSoundBufferImpl,iface); |
| char xbuf[50]; |
| |
| WINE_StringFromCLSID(riid,xbuf); |
| TRACE("(%p,%s,%p)\n",This,xbuf,ppobj); |
| |
| if ( IsEqualGUID( &IID_IDirectSoundNotify, riid ) ) { |
| IDirectSoundNotifyImpl *dsn; |
| |
| dsn = (IDirectSoundNotifyImpl*)HeapAlloc(GetProcessHeap(),0,sizeof(*dsn)); |
| dsn->ref = 1; |
| dsn->dsb = This; |
| IDirectSoundBuffer_AddRef(iface); |
| dsn->lpvtbl = &dsnvt; |
| *ppobj = (LPVOID)dsn; |
| return S_OK; |
| } |
| |
| if ( IsEqualGUID( &IID_IDirectSound3DBuffer, riid ) ) { |
| *ppobj = This->ds3db; |
| if (*ppobj) |
| return DS_OK; |
| } |
| |
| return E_FAIL; |
| } |
| |
| static ICOM_VTABLE(IDirectSoundBuffer) dsbvt = |
| { |
| ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE |
| IDirectSoundBufferImpl_QueryInterface, |
| IDirectSoundBufferImpl_AddRef, |
| IDirectSoundBufferImpl_Release, |
| IDirectSoundBufferImpl_GetCaps, |
| IDirectSoundBufferImpl_GetCurrentPosition, |
| IDirectSoundBufferImpl_GetFormat, |
| IDirectSoundBufferImpl_GetVolume, |
| IDirectSoundBufferImpl_GetPan, |
| IDirectSoundBufferImpl_GetFrequency, |
| IDirectSoundBufferImpl_GetStatus, |
| IDirectSoundBufferImpl_Initialize, |
| IDirectSoundBufferImpl_Lock, |
| IDirectSoundBufferImpl_Play, |
| IDirectSoundBufferImpl_SetCurrentPosition, |
| IDirectSoundBufferImpl_SetFormat, |
| IDirectSoundBufferImpl_SetVolume, |
| IDirectSoundBufferImpl_SetPan, |
| IDirectSoundBufferImpl_SetFrequency, |
| IDirectSoundBufferImpl_Stop, |
| IDirectSoundBufferImpl_Unlock |
| }; |
| |
| /******************************************************************************* |
| * IDirectSound |
| */ |
| |
| static HRESULT WINAPI IDirectSoundImpl_SetCooperativeLevel( |
| LPDIRECTSOUND iface,HWND hwnd,DWORD level |
| ) { |
| ICOM_THIS(IDirectSoundImpl,iface); |
| FIXME("(%p,%08lx,%ld):stub\n",This,(DWORD)hwnd,level); |
| return DS_OK; |
| } |
| |
| static HRESULT WINAPI IDirectSoundImpl_CreateSoundBuffer( |
| LPDIRECTSOUND iface,LPDSBUFFERDESC dsbd,LPLPDIRECTSOUNDBUFFER ppdsb,LPUNKNOWN lpunk |
| ) { |
| ICOM_THIS(IDirectSoundImpl,iface); |
| IDirectSoundBufferImpl** ippdsb=(IDirectSoundBufferImpl**)ppdsb; |
| LPWAVEFORMATEX wfex; |
| |
| TRACE("(%p,%p,%p,%p)\n",This,dsbd,ippdsb,lpunk); |
| |
| if ((This == NULL) || (dsbd == NULL) || (ippdsb == NULL)) |
| return DSERR_INVALIDPARAM; |
| |
| if (TRACE_ON(dsound)) { |
| TRACE("(size=%ld)\n",dsbd->dwSize); |
| TRACE("(flags=0x%08lx\n",dsbd->dwFlags); |
| _dump_DSBCAPS(dsbd->dwFlags); |
| TRACE("(bufferbytes=%ld)\n",dsbd->dwBufferBytes); |
| TRACE("(lpwfxFormat=%p)\n",dsbd->lpwfxFormat); |
| } |
| |
| wfex = dsbd->lpwfxFormat; |
| |
| if (wfex) |
| TRACE("(formattag=0x%04x,chans=%d,samplerate=%ld" |
| "bytespersec=%ld,blockalign=%d,bitspersamp=%d,cbSize=%d)\n", |
| wfex->wFormatTag, wfex->nChannels, wfex->nSamplesPerSec, |
| wfex->nAvgBytesPerSec, wfex->nBlockAlign, |
| wfex->wBitsPerSample, wfex->cbSize); |
| |
| if (dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER) { |
| if (primarybuf) { |
| IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER)primarybuf); |
| *ippdsb = primarybuf; |
| primarybuf->dsbd.dwFlags = dsbd->dwFlags; |
| return DS_OK; |
| } /* Else create primarybuf */ |
| } |
| |
| *ippdsb = (IDirectSoundBufferImpl*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDirectSoundBufferImpl)); |
| if (*ippdsb == NULL) |
| return DSERR_OUTOFMEMORY; |
| (*ippdsb)->ref = 1; |
| |
| TRACE("Created buffer at %p\n", *ippdsb); |
| |
| if (dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER) { |
| (*ippdsb)->buflen = dsound->wfx.nAvgBytesPerSec; |
| (*ippdsb)->freq = dsound->wfx.nSamplesPerSec; |
| } else { |
| (*ippdsb)->buflen = dsbd->dwBufferBytes; |
| (*ippdsb)->freq = dsbd->lpwfxFormat->nSamplesPerSec; |
| } |
| (*ippdsb)->buffer = (LPBYTE)HeapAlloc(GetProcessHeap(),0,(*ippdsb)->buflen); |
| if ((*ippdsb)->buffer == NULL) { |
| HeapFree(GetProcessHeap(),0,(*ippdsb)); |
| *ippdsb = NULL; |
| return DSERR_OUTOFMEMORY; |
| } |
| /* It's not necessary to initialize values to zero since */ |
| /* we allocated this structure with HEAP_ZERO_MEMORY... */ |
| (*ippdsb)->playpos = 0; |
| (*ippdsb)->writepos = 0; |
| (*ippdsb)->parent = NULL; |
| (*ippdsb)->lpvtbl = &dsbvt; |
| (*ippdsb)->dsound = This; |
| (*ippdsb)->playing = 0; |
| (*ippdsb)->lVolAdjust = (1 << 15); |
| (*ippdsb)->rVolAdjust = (1 << 15); |
| |
| if (!(dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER)) { |
| (*ippdsb)->freqAdjust = ((*ippdsb)->freq << DSOUND_FREQSHIFT) / |
| primarybuf->wfx.nSamplesPerSec; |
| (*ippdsb)->nAvgBytesPerSec = (*ippdsb)->freq * |
| dsbd->lpwfxFormat->nBlockAlign; |
| } |
| |
| memcpy(&((*ippdsb)->dsbd),dsbd,sizeof(*dsbd)); |
| |
| /* register buffer */ |
| if (!(dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER)) { |
| This->buffers = (IDirectSoundBufferImpl**)HeapReAlloc(GetProcessHeap(),0,This->buffers,sizeof(IDirectSoundBufferImpl*)*(This->nrofbuffers+1)); |
| This->buffers[This->nrofbuffers] = *ippdsb; |
| This->nrofbuffers++; |
| } |
| IDirectSound_AddRef(iface); |
| |
| if (dsbd->lpwfxFormat) |
| memcpy(&((*ippdsb)->wfx), dsbd->lpwfxFormat, sizeof((*ippdsb)->wfx)); |
| |
| InitializeCriticalSection(&((*ippdsb)->lock)); |
| |
| #if USE_DSOUND3D |
| if (dsbd->dwFlags & DSBCAPS_CTRL3D) { |
| IDirectSound3DBufferImpl *ds3db; |
| |
| ds3db = (IDirectSound3DBufferImpl*)HeapAlloc(GetProcessHeap(), |
| 0,sizeof(*ds3db)); |
| ds3db->ref = 1; |
| ds3db->dsb = (*ippdsb); |
| ds3db->lpvtbl = &ds3dbvt; |
| (*ippdsb)->ds3db = ds3db; |
| ds3db->ds3db.dwSize = sizeof(DS3DBUFFER); |
| ds3db->ds3db.vPosition.x.x = 0.0; |
| ds3db->ds3db.vPosition.y.y = 0.0; |
| ds3db->ds3db.vPosition.z.z = 0.0; |
| ds3db->ds3db.vVelocity.x.x = 0.0; |
| ds3db->ds3db.vVelocity.y.y = 0.0; |
| ds3db->ds3db.vVelocity.z.z = 0.0; |
| ds3db->ds3db.dwInsideConeAngle = DS3D_DEFAULTCONEANGLE; |
| ds3db->ds3db.dwOutsideConeAngle = DS3D_DEFAULTCONEANGLE; |
| ds3db->ds3db.vConeOrientation.x.x = 0.0; |
| ds3db->ds3db.vConeOrientation.y.y = 0.0; |
| ds3db->ds3db.vConeOrientation.z.z = 0.0; |
| ds3db->ds3db.lConeOutsideVolume = DS3D_DEFAULTCONEOUTSIDEVOLUME; |
| ds3db->ds3db.flMinDistance = DS3D_DEFAULTMINDISTANCE; |
| ds3db->ds3db.flMaxDistance = DS3D_DEFAULTMAXDISTANCE; |
| ds3db->ds3db.dwMode = DS3DMODE_NORMAL; |
| ds3db->buflen = ((*ippdsb)->buflen * primarybuf->wfx.nBlockAlign) / |
| (*ippdsb)->wfx.nBlockAlign; |
| ds3db->buffer = HeapAlloc(GetProcessHeap(), 0, ds3db->buflen); |
| if (ds3db->buffer == NULL) { |
| ds3db->buflen = 0; |
| ds3db->ds3db.dwMode = DS3DMODE_DISABLE; |
| } |
| } |
| #endif |
| return DS_OK; |
| } |
| |
| static HRESULT WINAPI IDirectSoundImpl_DuplicateSoundBuffer( |
| LPDIRECTSOUND iface,LPDIRECTSOUNDBUFFER pdsb,LPLPDIRECTSOUNDBUFFER ppdsb |
| ) { |
| ICOM_THIS(IDirectSoundImpl,iface); |
| IDirectSoundBufferImpl* ipdsb=(IDirectSoundBufferImpl*)pdsb; |
| IDirectSoundBufferImpl** ippdsb=(IDirectSoundBufferImpl**)ppdsb; |
| TRACE("(%p,%p,%p)\n",This,ipdsb,ippdsb); |
| |
| *ippdsb = (IDirectSoundBufferImpl*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDirectSoundBufferImpl)); |
| |
| IDirectSoundBuffer_AddRef(pdsb); |
| memcpy(*ippdsb, ipdsb, sizeof(IDirectSoundBufferImpl)); |
| (*ippdsb)->ref = 1; |
| (*ippdsb)->playpos = 0; |
| (*ippdsb)->writepos = 0; |
| (*ippdsb)->dsound = This; |
| (*ippdsb)->parent = ipdsb; |
| memcpy(&((*ippdsb)->wfx), &(ipdsb->wfx), sizeof((*ippdsb)->wfx)); |
| /* register buffer */ |
| This->buffers = (IDirectSoundBufferImpl**)HeapReAlloc(GetProcessHeap(),0,This->buffers,sizeof(IDirectSoundBufferImpl**)*(This->nrofbuffers+1)); |
| This->buffers[This->nrofbuffers] = *ippdsb; |
| This->nrofbuffers++; |
| IDirectSound_AddRef(iface); |
| return DS_OK; |
| } |
| |
| |
| static HRESULT WINAPI IDirectSoundImpl_GetCaps(LPDIRECTSOUND iface,LPDSCAPS caps) { |
| ICOM_THIS(IDirectSoundImpl,iface); |
| TRACE("(%p,%p)\n",This,caps); |
| TRACE("(flags=0x%08lx)\n",caps->dwFlags); |
| |
| if (caps == NULL) |
| return DSERR_INVALIDPARAM; |
| |
| /* We should check this value, not set it. See Inside DirectX, p215. */ |
| caps->dwSize = sizeof(*caps); |
| |
| caps->dwFlags = |
| DSCAPS_PRIMARYSTEREO | |
| DSCAPS_PRIMARY16BIT | |
| DSCAPS_SECONDARYSTEREO | |
| DSCAPS_SECONDARY16BIT | |
| DSCAPS_CONTINUOUSRATE; |
| /* FIXME: query OSS */ |
| caps->dwMinSecondarySampleRate = DSBFREQUENCY_MIN; |
| caps->dwMaxSecondarySampleRate = DSBFREQUENCY_MAX; |
| |
| caps->dwPrimaryBuffers = 1; |
| |
| caps->dwMaxHwMixingAllBuffers = 0; |
| caps->dwMaxHwMixingStaticBuffers = 0; |
| caps->dwMaxHwMixingStreamingBuffers = 0; |
| |
| caps->dwFreeHwMixingAllBuffers = 0; |
| caps->dwFreeHwMixingStaticBuffers = 0; |
| caps->dwFreeHwMixingStreamingBuffers = 0; |
| |
| caps->dwMaxHw3DAllBuffers = 0; |
| caps->dwMaxHw3DStaticBuffers = 0; |
| caps->dwMaxHw3DStreamingBuffers = 0; |
| |
| caps->dwFreeHw3DAllBuffers = 0; |
| caps->dwFreeHw3DStaticBuffers = 0; |
| caps->dwFreeHw3DStreamingBuffers = 0; |
| |
| caps->dwTotalHwMemBytes = 0; |
| |
| caps->dwFreeHwMemBytes = 0; |
| |
| caps->dwMaxContigFreeHwMemBytes = 0; |
| |
| caps->dwUnlockTransferRateHwBuffers = 4096; /* But we have none... */ |
| |
| caps->dwPlayCpuOverheadSwBuffers = 1; /* 1% */ |
| |
| return DS_OK; |
| } |
| |
| static ULONG WINAPI IDirectSoundImpl_AddRef(LPDIRECTSOUND iface) { |
| ICOM_THIS(IDirectSoundImpl,iface); |
| return ++(This->ref); |
| } |
| |
| static ULONG WINAPI IDirectSoundImpl_Release(LPDIRECTSOUND iface) { |
| ICOM_THIS(IDirectSoundImpl,iface); |
| TRACE("(%p), ref was %ld\n",This,This->ref); |
| if (!--(This->ref)) { |
| DSOUND_CloseAudio(); |
| while(IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER)primarybuf)); /* Deallocate */ |
| FIXME("need to release all buffers!\n"); |
| HeapFree(GetProcessHeap(),0,This); |
| dsound = NULL; |
| return S_OK; |
| } |
| return This->ref; |
| } |
| |
| static HRESULT WINAPI IDirectSoundImpl_SetSpeakerConfig( |
| LPDIRECTSOUND iface,DWORD config |
| ) { |
| ICOM_THIS(IDirectSoundImpl,iface); |
| FIXME("(%p,0x%08lx):stub\n",This,config); |
| return DS_OK; |
| } |
| |
| static HRESULT WINAPI IDirectSoundImpl_QueryInterface( |
| LPDIRECTSOUND iface,REFIID riid,LPVOID *ppobj |
| ) { |
| ICOM_THIS(IDirectSoundImpl,iface); |
| char xbuf[50]; |
| |
| if ( IsEqualGUID( &IID_IDirectSound3DListener, riid ) ) { |
| |
| if (This->listener) { |
| *ppobj = This->listener; |
| return DS_OK; |
| } |
| This->listener = (IDirectSound3DListenerImpl*)HeapAlloc( |
| GetProcessHeap(), 0, sizeof(*(This->listener))); |
| This->listener->ref = 1; |
| This->listener->lpvtbl = &ds3dlvt; |
| IDirectSound_AddRef(iface); |
| This->listener->ds3dl.dwSize = sizeof(DS3DLISTENER); |
| This->listener->ds3dl.vPosition.x.x = 0.0; |
| This->listener->ds3dl.vPosition.y.y = 0.0; |
| This->listener->ds3dl.vPosition.z.z = 0.0; |
| This->listener->ds3dl.vVelocity.x.x = 0.0; |
| This->listener->ds3dl.vVelocity.y.y = 0.0; |
| This->listener->ds3dl.vVelocity.z.z = 0.0; |
| This->listener->ds3dl.vOrientFront.x.x = 0.0; |
| This->listener->ds3dl.vOrientFront.y.y = 0.0; |
| This->listener->ds3dl.vOrientFront.z.z = 1.0; |
| This->listener->ds3dl.vOrientTop.x.x = 0.0; |
| This->listener->ds3dl.vOrientTop.y.y = 1.0; |
| This->listener->ds3dl.vOrientTop.z.z = 0.0; |
| This->listener->ds3dl.flDistanceFactor = DS3D_DEFAULTDISTANCEFACTOR; |
| This->listener->ds3dl.flRolloffFactor = DS3D_DEFAULTROLLOFFFACTOR; |
| This->listener->ds3dl.flDopplerFactor = DS3D_DEFAULTDOPPLERFACTOR; |
| *ppobj = (LPVOID)This->listener; |
| return DS_OK; |
| } |
| |
| WINE_StringFromCLSID(riid,xbuf); |
| TRACE("(%p,%s,%p)\n",This,xbuf,ppobj); |
| return E_FAIL; |
| } |
| |
| static HRESULT WINAPI IDirectSoundImpl_Compact( |
| LPDIRECTSOUND iface) |
| { |
| ICOM_THIS(IDirectSoundImpl,iface); |
| TRACE("(%p)\n", This); |
| return DS_OK; |
| } |
| |
| static HRESULT WINAPI IDirectSoundImpl_GetSpeakerConfig( |
| LPDIRECTSOUND iface, |
| LPDWORD lpdwSpeakerConfig) |
| { |
| ICOM_THIS(IDirectSoundImpl,iface); |
| TRACE("(%p, %p)\n", This, lpdwSpeakerConfig); |
| *lpdwSpeakerConfig = DSSPEAKER_STEREO | (DSSPEAKER_GEOMETRY_NARROW << 16); |
| return DS_OK; |
| } |
| |
| static HRESULT WINAPI IDirectSoundImpl_Initialize( |
| LPDIRECTSOUND iface, |
| LPGUID lpGuid) |
| { |
| ICOM_THIS(IDirectSoundImpl,iface); |
| TRACE("(%p, %p)\n", This, lpGuid); |
| return DS_OK; |
| } |
| |
| static ICOM_VTABLE(IDirectSound) dsvt = |
| { |
| ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE |
| IDirectSoundImpl_QueryInterface, |
| IDirectSoundImpl_AddRef, |
| IDirectSoundImpl_Release, |
| IDirectSoundImpl_CreateSoundBuffer, |
| IDirectSoundImpl_GetCaps, |
| IDirectSoundImpl_DuplicateSoundBuffer, |
| IDirectSoundImpl_SetCooperativeLevel, |
| IDirectSoundImpl_Compact, |
| IDirectSoundImpl_GetSpeakerConfig, |
| IDirectSoundImpl_SetSpeakerConfig, |
| IDirectSoundImpl_Initialize |
| }; |
| |
| |
| /* See http://www.opensound.com/pguide/audio.html for more details */ |
| |
| static int |
| DSOUND_setformat(LPWAVEFORMATEX wfex) { |
| int xx,channels,speed,format,nformat; |
| |
| if (!audioOK) { |
| TRACE("(%p) deferred\n", wfex); |
| return 0; |
| } |
| switch (wfex->wFormatTag) { |
| default: |
| WARN("unknown WAVE_FORMAT tag %d\n",wfex->wFormatTag); |
| return DSERR_BADFORMAT; |
| case WAVE_FORMAT_PCM: |
| break; |
| } |
| if (wfex->wBitsPerSample==8) |
| format = AFMT_U8; |
| else |
| format = AFMT_S16_LE; |
| |
| if (-1==ioctl(audiofd,SNDCTL_DSP_GETFMTS,&xx)) { |
| perror("ioctl SNDCTL_DSP_GETFMTS"); |
| return -1; |
| } |
| if ((xx&format)!=format) {/* format unsupported */ |
| FIXME("SNDCTL_DSP_GETFMTS: format not supported\n"); |
| return -1; |
| } |
| nformat = format; |
| if (-1==ioctl(audiofd,SNDCTL_DSP_SETFMT,&nformat)) { |
| perror("ioctl SNDCTL_DSP_SETFMT"); |
| return -1; |
| } |
| if (nformat!=format) {/* didn't work */ |
| FIXME("SNDCTL_DSP_GETFMTS: format not set\n"); |
| return -1; |
| } |
| |
| channels = wfex->nChannels-1; |
| if (-1==ioctl(audiofd,SNDCTL_DSP_STEREO,&channels)) { |
| perror("ioctl SNDCTL_DSP_STEREO"); |
| return -1; |
| } |
| speed = wfex->nSamplesPerSec; |
| if (-1==ioctl(audiofd,SNDCTL_DSP_SPEED,&speed)) { |
| perror("ioctl SNDCTL_DSP_SPEED"); |
| return -1; |
| } |
| TRACE("(freq=%ld,channels=%d,bits=%d)\n", |
| wfex->nSamplesPerSec,wfex->nChannels,wfex->wBitsPerSample |
| ); |
| return 0; |
| } |
| |
| static void DSOUND_CheckEvent(IDirectSoundBufferImpl *dsb, int len) |
| { |
| int i; |
| DWORD offset; |
| LPDSBPOSITIONNOTIFY event; |
| |
| if (dsb->nrofnotifies == 0) |
| return; |
| |
| TRACE("(%p) buflen = %ld, playpos = %ld, len = %d\n", |
| dsb, dsb->buflen, dsb->playpos, len); |
| for (i = 0; i < dsb->nrofnotifies ; i++) { |
| event = dsb->notifies + i; |
| offset = event->dwOffset; |
| TRACE("checking %d, position %ld, event = %d\n", |
| i, offset, event->hEventNotify); |
| /* DSBPN_OFFSETSTOP has to be the last element. So this is */ |
| /* OK. [Inside DirectX, p274] */ |
| /* */ |
| /* This also means we can't sort the entries by offset, */ |
| /* because DSBPN_OFFSETSTOP == -1 */ |
| if (offset == DSBPN_OFFSETSTOP) { |
| if (dsb->playing == 0) { |
| SetEvent(event->hEventNotify); |
| TRACE("signalled event %d (%d)\n", event->hEventNotify, i); |
| return; |
| } else |
| return; |
| } |
| if ((dsb->playpos + len) >= dsb->buflen) { |
| if ((offset < ((dsb->playpos + len) % dsb->buflen)) || |
| (offset >= dsb->playpos)) { |
| TRACE("signalled event %d (%d)\n", event->hEventNotify, i); |
| SetEvent(event->hEventNotify); |
| } |
| } else { |
| if ((offset >= dsb->playpos) && (offset < (dsb->playpos + len))) { |
| TRACE("signalled event %d (%d)\n", event->hEventNotify, i); |
| SetEvent(event->hEventNotify); |
| } |
| } |
| } |
| } |
| |
| /* WAV format info can be found at: */ |
| /* */ |
| /* http://www.cwi.nl/ftp/audio/AudioFormats.part2 */ |
| /* ftp://ftp.cwi.nl/pub/audio/RIFF-format */ |
| /* */ |
| /* Import points to remember: */ |
| /* */ |
| /* 8-bit WAV is unsigned */ |
| /* 16-bit WAV is signed */ |
| |
| static inline INT16 cvtU8toS16(BYTE byte) |
| { |
| INT16 s = (byte - 128) << 8; |
| |
| return s; |
| } |
| |
| static inline BYTE cvtS16toU8(INT16 word) |
| { |
| BYTE b = (word + 32768) >> 8; |
| |
| return b; |
| } |
| |
| |
| /* We should be able to optimize these two inline functions */ |
| /* so that we aren't doing 8->16->8 conversions when it is */ |
| /* not necessary. But this is still a WIP. Optimize later. */ |
| static inline void get_fields(const IDirectSoundBufferImpl *dsb, BYTE *buf, INT *fl, INT *fr) |
| { |
| INT16 *bufs = (INT16 *) buf; |
| |
| /* TRACE(dsound, "(%p)", buf); */ |
| if ((dsb->wfx.wBitsPerSample == 8) && dsb->wfx.nChannels == 2) { |
| *fl = cvtU8toS16(*buf); |
| *fr = cvtU8toS16(*(buf + 1)); |
| return; |
| } |
| |
| if ((dsb->wfx.wBitsPerSample == 16) && dsb->wfx.nChannels == 2) { |
| *fl = *bufs; |
| *fr = *(bufs + 1); |
| return; |
| } |
| |
| if ((dsb->wfx.wBitsPerSample == 8) && dsb->wfx.nChannels == 1) { |
| *fl = cvtU8toS16(*buf); |
| *fr = *fl; |
| return; |
| } |
| |
| if ((dsb->wfx.wBitsPerSample == 16) && dsb->wfx.nChannels == 1) { |
| *fl = *bufs; |
| *fr = *bufs; |
| return; |
| } |
| |
| FIXME("get_fields found an unsupported configuration\n"); |
| return; |
| } |
| |
| static inline void set_fields(BYTE *buf, INT fl, INT fr) |
| { |
| INT16 *bufs = (INT16 *) buf; |
| |
| if ((primarybuf->wfx.wBitsPerSample == 8) && (primarybuf->wfx.nChannels == 2)) { |
| *buf = cvtS16toU8(fl); |
| *(buf + 1) = cvtS16toU8(fr); |
| return; |
| } |
| |
| if ((primarybuf->wfx.wBitsPerSample == 16) && (primarybuf->wfx.nChannels == 2)) { |
| *bufs = fl; |
| *(bufs + 1) = fr; |
| return; |
| } |
| |
| if ((primarybuf->wfx.wBitsPerSample == 8) && (primarybuf->wfx.nChannels == 1)) { |
| *buf = cvtS16toU8((fl + fr) >> 1); |
| return; |
| } |
| |
| if ((primarybuf->wfx.wBitsPerSample == 16) && (primarybuf->wfx.nChannels == 1)) { |
| *bufs = (fl + fr) >> 1; |
| return; |
| } |
| FIXME("set_fields found an unsupported configuration\n"); |
| return; |
| } |
| |
| /* Now with PerfectPitch (tm) technology */ |
| static INT DSOUND_MixerNorm(IDirectSoundBufferImpl *dsb, BYTE *buf, INT len) |
| { |
| INT i, size, ipos, ilen, fieldL, fieldR; |
| BYTE *ibp, *obp; |
| INT iAdvance = dsb->wfx.nBlockAlign; |
| INT oAdvance = primarybuf->wfx.nBlockAlign; |
| |
| ibp = dsb->buffer + dsb->playpos; |
| obp = buf; |
| |
| TRACE("(%p, %p, %p), playpos=%8.8lx\n", dsb, ibp, obp, dsb->playpos); |
| /* Check for the best case */ |
| if ((dsb->freq == primarybuf->wfx.nSamplesPerSec) && |
| (dsb->wfx.wBitsPerSample == primarybuf->wfx.wBitsPerSample) && |
| (dsb->wfx.nChannels == primarybuf->wfx.nChannels)) { |
| TRACE("(%p) Best case\n", dsb); |
| if ((ibp + len) < (BYTE *)(dsb->buffer + dsb->buflen)) |
| memcpy(obp, ibp, len); |
| else { /* wrap */ |
| memcpy(obp, ibp, dsb->buflen - dsb->playpos); |
| memcpy(obp + (dsb->buflen - dsb->playpos), |
| dsb->buffer, |
| len - (dsb->buflen - dsb->playpos)); |
| } |
| return len; |
| } |
| |
| /* Check for same sample rate */ |
| if (dsb->freq == primarybuf->wfx.nSamplesPerSec) { |
| TRACE("(%p) Same sample rate %ld = primary %ld\n", dsb, |
| dsb->freq, primarybuf->wfx.nSamplesPerSec); |
| ilen = 0; |
| for (i = 0; i < len; i += oAdvance) { |
| get_fields(dsb, ibp, &fieldL, &fieldR); |
| ibp += iAdvance; |
| ilen += iAdvance; |
| set_fields(obp, fieldL, fieldR); |
| obp += oAdvance; |
| if (ibp >= (BYTE *)(dsb->buffer + dsb->buflen)) |
| ibp = dsb->buffer; /* wrap */ |
| } |
| return (ilen); |
| } |
| |
| /* Mix in different sample rates */ |
| /* */ |
| /* New PerfectPitch(tm) Technology (c) 1998 Rob Riggs */ |
| /* Patent Pending :-] */ |
| |
| TRACE("(%p) Adjusting frequency: %ld -> %ld\n", |
| dsb, dsb->freq, primarybuf->wfx.nSamplesPerSec); |
| |
| size = len / oAdvance; |
| ilen = ((size * dsb->freqAdjust) >> DSOUND_FREQSHIFT) * iAdvance; |
| for (i = 0; i < size; i++) { |
| |
| ipos = (((i * dsb->freqAdjust) >> DSOUND_FREQSHIFT) * iAdvance) + dsb->playpos; |
| |
| if (ipos >= dsb->buflen) |
| ipos %= dsb->buflen; /* wrap */ |
| |
| get_fields(dsb, (dsb->buffer + ipos), &fieldL, &fieldR); |
| set_fields(obp, fieldL, fieldR); |
| obp += oAdvance; |
| } |
| return ilen; |
| } |
| |
| static void DSOUND_MixerVol(IDirectSoundBufferImpl *dsb, BYTE *buf, INT len) |
| { |
| INT i, inc = primarybuf->wfx.wBitsPerSample >> 3; |
| BYTE *bpc = buf; |
| INT16 *bps = (INT16 *) buf; |
| |
| TRACE("(%p) left = %lx, right = %lx\n", dsb, |
| dsb->lVolAdjust, dsb->rVolAdjust); |
| if ((!(dsb->dsbd.dwFlags & DSBCAPS_CTRLPAN) || (dsb->pan == 0)) && |
| (!(dsb->dsbd.dwFlags & DSBCAPS_CTRLVOLUME) || (dsb->volume == 0)) && |
| !(dsb->dsbd.dwFlags & DSBCAPS_CTRL3D)) |
| return; /* Nothing to do */ |
| |
| /* If we end up with some bozo coder using panning or 3D sound */ |
| /* with a mono primary buffer, it could sound very weird using */ |
| /* this method. Oh well, tough patooties. */ |
| |
| for (i = 0; i < len; i += inc) { |
| INT val; |
| |
| switch (inc) { |
| |
| case 1: |
| /* 8-bit WAV is unsigned, but we need to operate */ |
| /* on signed data for this to work properly */ |
| val = *bpc - 128; |
| val = ((val * (i & inc ? dsb->rVolAdjust : dsb->lVolAdjust)) >> 15); |
| *bpc = val + 128; |
| bpc++; |
| break; |
| case 2: |
| /* 16-bit WAV is signed -- much better */ |
| val = *bps; |
| val = ((val * ((i & inc) ? dsb->rVolAdjust : dsb->lVolAdjust)) >> 15); |
| *bps = val; |
| bps++; |
| break; |
| default: |
| /* Very ugly! */ |
| FIXME("MixerVol had a nasty error\n"); |
| } |
| } |
| } |
| |
| #ifdef USE_DSOUND3D |
| static void DSOUND_Mixer3D(IDirectSoundBufferImpl *dsb, BYTE *buf, INT len) |
| { |
| BYTE *ibp, *obp; |
| DWORD buflen, playpos; |
| |
| buflen = dsb->ds3db->buflen; |
| playpos = (dsb->playpos * primarybuf->wfx.nBlockAlign) / dsb->wfx.nBlockAlign; |
| ibp = dsb->ds3db->buffer + playpos; |
| obp = buf; |
| |
| if (playpos > buflen) { |
| FIXME("Major breakage"); |
| return; |
| } |
| |
| if (len <= (playpos + buflen)) |
| memcpy(obp, ibp, len); |
| else { /* wrap */ |
| memcpy(obp, ibp, buflen - playpos); |
| memcpy(obp + (buflen - playpos), |
| dsb->buffer, |
| len - (buflen - playpos)); |
| } |
| return; |
| } |
| #endif |
| |
| static void *tmp_buffer; |
| static size_t tmp_buffer_len = 0; |
| |
| static void *DSOUND_tmpbuffer(size_t len) |
| { |
| if (len>tmp_buffer_len) { |
| void *new_buffer = realloc(tmp_buffer, len); |
| if (new_buffer) { |
| tmp_buffer = new_buffer; |
| tmp_buffer_len = len; |
| } |
| return new_buffer; |
| } |
| return tmp_buffer; |
| } |
| |
| static DWORD DSOUND_MixInBuffer(IDirectSoundBufferImpl *dsb) |
| { |
| INT i, len, ilen, temp, field; |
| INT advance = primarybuf->wfx.wBitsPerSample >> 3; |
| BYTE *buf, *ibuf, *obuf; |
| INT16 *ibufs, *obufs; |
| |
| len = DSOUND_FRAGLEN; /* The most we will use */ |
| if (!(dsb->playflags & DSBPLAY_LOOPING)) { |
| temp = MulDiv(primarybuf->wfx.nAvgBytesPerSec, dsb->buflen, |
| dsb->nAvgBytesPerSec) - |
| MulDiv(primarybuf->wfx.nAvgBytesPerSec, dsb->playpos, |
| dsb->nAvgBytesPerSec); |
| len = (len > temp) ? temp : len; |
| } |
| len &= ~3; /* 4 byte alignment */ |
| |
| if (len == 0) { |
| /* This should only happen if we aren't looping and temp < 4 */ |
| |
| /* We skip the remainder, so check for possible events */ |
| DSOUND_CheckEvent(dsb, dsb->buflen - dsb->playpos); |
| /* Stop */ |
| dsb->playing = 0; |
| dsb->writepos = 0; |
| dsb->playpos = 0; |
| /* Check for DSBPN_OFFSETSTOP */ |
| DSOUND_CheckEvent(dsb, 0); |
| return 0; |
| } |
| |
| /* Been seeing segfaults in malloc() for some reason... */ |
| TRACE("allocating buffer (size = %d)\n", len); |
| if ((buf = ibuf = (BYTE *) DSOUND_tmpbuffer(len)) == NULL) |
| return 0; |
| |
| TRACE("MixInBuffer (%p) len = %d\n", dsb, len); |
| |
| ilen = DSOUND_MixerNorm(dsb, ibuf, len); |
| if ((dsb->dsbd.dwFlags & DSBCAPS_CTRLPAN) || |
| (dsb->dsbd.dwFlags & DSBCAPS_CTRLVOLUME)) |
| DSOUND_MixerVol(dsb, ibuf, len); |
| |
| obuf = primarybuf->buffer + primarybuf->playpos; |
| for (i = 0; i < len; i += advance) { |
| obufs = (INT16 *) obuf; |
| ibufs = (INT16 *) ibuf; |
| if (primarybuf->wfx.wBitsPerSample == 8) { |
| /* 8-bit WAV is unsigned */ |
| field = (*ibuf - 128); |
| field += (*obuf - 128); |
| field = field > 127 ? 127 : field; |
| field = field < -128 ? -128 : field; |
| *obuf = field + 128; |
| } else { |
| /* 16-bit WAV is signed */ |
| field = *ibufs; |
| field += *obufs; |
| field = field > 32767 ? 32767 : field; |
| field = field < -32768 ? -32768 : field; |
| *obufs = field; |
| } |
| ibuf += advance; |
| obuf += advance; |
| if (obuf >= (BYTE *)(primarybuf->buffer + primarybuf->buflen)) |
| obuf = primarybuf->buffer; |
| } |
| /* free(buf); */ |
| |
| if (dsb->dsbd.dwFlags & DSBCAPS_CTRLPOSITIONNOTIFY) |
| DSOUND_CheckEvent(dsb, ilen); |
| |
| dsb->playpos += ilen; |
| dsb->writepos = dsb->playpos + ilen; |
| |
| if (dsb->playpos >= dsb->buflen) { |
| if (!(dsb->playflags & DSBPLAY_LOOPING)) { |
| dsb->playing = 0; |
| dsb->writepos = 0; |
| dsb->playpos = 0; |
| DSOUND_CheckEvent(dsb, 0); /* For DSBPN_OFFSETSTOP */ |
| } else |
| dsb->playpos %= dsb->buflen; /* wrap */ |
| } |
| |
| if (dsb->writepos >= dsb->buflen) |
| dsb->writepos %= dsb->buflen; |
| |
| return len; |
| } |
| |
| static DWORD WINAPI DSOUND_MixPrimary(void) |
| { |
| INT i, len, maxlen = 0; |
| IDirectSoundBufferImpl *dsb; |
| |
| for (i = dsound->nrofbuffers - 1; i >= 0; i--) { |
| dsb = dsound->buffers[i]; |
| |
| if (!dsb || !(dsb->lpvtbl)) |
| continue; |
| IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER)dsb); |
| if (dsb->buflen && dsb->playing) { |
| EnterCriticalSection(&(dsb->lock)); |
| len = DSOUND_MixInBuffer(dsb); |
| maxlen = len > maxlen ? len : maxlen; |
| LeaveCriticalSection(&(dsb->lock)); |
| } |
| IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER)dsb); |
| } |
| |
| return maxlen; |
| } |
| |
| static int DSOUND_OpenAudio(void) |
| { |
| int audioFragment; |
| |
| if (primarybuf == NULL) |
| return DSERR_OUTOFMEMORY; |
| |
| while (audiofd >= 0) |
| |
| sleep(5); |
| /* we will most likely not get one, avoid excessive opens ... */ |
| if (audiofd == -ENODEV) |
| return -1; |
| audiofd = open("/dev/audio",O_WRONLY); |
| if (audiofd==-1) { |
| /* Don't worry if sound is busy at the moment */ |
| if ((errno != EBUSY) && (errno != ENODEV)) |
| perror("open /dev/audio"); |
| audiofd = -errno; |
| return -1; /* -1 */ |
| } |
| |
| /* We should probably do something here if SETFRAGMENT fails... */ |
| audioFragment=0x0002000c; |
| if (-1==ioctl(audiofd,SNDCTL_DSP_SETFRAGMENT,&audioFragment)) |
| perror("ioctl SETFRAGMENT"); |
| |
| audioOK = 1; |
| DSOUND_setformat(&(primarybuf->wfx)); |
| |
| return 0; |
| } |
| |
| static void DSOUND_CloseAudio(void) |
| { |
| int neutral; |
| |
| neutral = primarybuf->wfx.wBitsPerSample == 8 ? 128 : 0; |
| audioOK = 0; /* race condition */ |
| Sleep(5); |
| /* It's possible we've been called with audio closed */ |
| /* from SetFormat()... this is just to force a call */ |
| /* to OpenAudio() to reset the hardware properly */ |
| if (audiofd >= 0) |
| close(audiofd); |
| primarybuf->playpos = 0; |
| primarybuf->writepos = DSOUND_FRAGLEN; |
| memset(primarybuf->buffer, neutral, primarybuf->buflen); |
| audiofd = -1; |
| TRACE("Audio stopped\n"); |
| } |
| |
| static int DSOUND_WriteAudio(char *buf, int len) |
| { |
| int result, left = 0; |
| |
| while (left < len) { |
| result = write(audiofd, buf + left, len - left); |
| if (result == -1) { |
| if (errno == EINTR) |
| continue; |
| else |
| return result; |
| } |
| left += result; |
| } |
| return 0; |
| } |
| |
| static void DSOUND_OutputPrimary(int len) |
| { |
| int neutral, flen1, flen2; |
| char *frag1, *frag2; |
| |
| /* This is a bad place for this. We need to clear the */ |
| /* buffer with a neutral value, for unsigned 8-bit WAVE */ |
| /* that's 128, for signed 16-bit it's 0 */ |
| neutral = primarybuf->wfx.wBitsPerSample == 8 ? 128 : 0; |
| |
| /* **** */ |
| EnterCriticalSection(&(primarybuf->lock)); |
| |
| /* Write out the */ |
| if ((audioOK == 1) || (DSOUND_OpenAudio() == 0)) { |
| if (primarybuf->playpos + len >= primarybuf->buflen) { |
| frag1 = primarybuf->buffer + primarybuf->playpos; |
| flen1 = primarybuf->buflen - primarybuf->playpos; |
| frag2 = primarybuf->buffer; |
| flen2 = len - (primarybuf->buflen - primarybuf->playpos); |
| if (DSOUND_WriteAudio(frag1, flen1) != 0) { |
| perror("DSOUND_WriteAudio"); |
| LeaveCriticalSection(&(primarybuf->lock)); |
| ExitThread(0); |
| } |
| memset(frag1, neutral, flen1); |
| if (DSOUND_WriteAudio(frag2, flen2) != 0) { |
| perror("DSOUND_WriteAudio"); |
| LeaveCriticalSection(&(primarybuf->lock)); |
| ExitThread(0); |
| } |
| memset(frag2, neutral, flen2); |
| } else { |
| frag1 = primarybuf->buffer + primarybuf->playpos; |
| flen1 = len; |
| if (DSOUND_WriteAudio(frag1, flen1) != 0) { |
| perror("DSOUND_WriteAudio"); |
| LeaveCriticalSection(&(primarybuf->lock)); |
| ExitThread(0); |
| } |
| memset(frag1, neutral, flen1); |
| } |
| } else { |
| /* Can't play audio at the moment -- we need to sleep */ |
| /* to make up for the time we'd be blocked in write() */ |
| /* to /dev/audio */ |
| Sleep(60); |
| } |
| primarybuf->playpos += len; |
| if (primarybuf->playpos >= primarybuf->buflen) |
| primarybuf->playpos %= primarybuf->buflen; |
| primarybuf->writepos = primarybuf->playpos + DSOUND_FRAGLEN; |
| if (primarybuf->writepos >= primarybuf->buflen) |
| primarybuf->writepos %= primarybuf->buflen; |
| |
| LeaveCriticalSection(&(primarybuf->lock)); |
| /* **** */ |
| } |
| |
| static DWORD WINAPI DSOUND_thread(LPVOID arg) |
| { |
| int len; |
| |
| TRACE("dsound is at pid %d\n",getpid()); |
| while (1) { |
| if (!dsound) { |
| WARN("DSOUND thread giving up.\n"); |
| ExitThread(0); |
| } |
| if (getppid()==1) { |
| WARN("DSOUND father died? Giving up.\n"); |
| ExitThread(0); |
| } |
| /* RACE: dsound could be deleted */ |
| IDirectSound_AddRef((LPDIRECTSOUND)dsound); |
| if (primarybuf == NULL) { |
| /* Should never happen */ |
| WARN("Lost the primary buffer!\n"); |
| IDirectSound_Release((LPDIRECTSOUND)dsound); |
| ExitThread(0); |
| } |
| |
| /* **** */ |
| EnterCriticalSection(&(primarybuf->lock)); |
| len = DSOUND_MixPrimary(); |
| LeaveCriticalSection(&(primarybuf->lock)); |
| /* **** */ |
| |
| if (primarybuf->playing) |
| len = DSOUND_FRAGLEN > len ? DSOUND_FRAGLEN : len; |
| if (len) { |
| /* This does all the work */ |
| DSOUND_OutputPrimary(len); |
| } else { |
| /* no buffers playing -- close and wait */ |
| if (audioOK) |
| DSOUND_CloseAudio(); |
| Sleep(100); |
| } |
| IDirectSound_Release((LPDIRECTSOUND)dsound); |
| } |
| ExitThread(0); |
| } |
| |
| #endif /* HAVE_OSS */ |
| |
| HRESULT WINAPI DirectSoundCreate(REFGUID lpGUID,LPDIRECTSOUND *ppDS,IUnknown *pUnkOuter ) |
| { |
| IDirectSoundImpl** ippDS=(IDirectSoundImpl**)ppDS; |
| if (lpGUID) |
| TRACE("(%p,%p,%p)\n",lpGUID,ippDS,pUnkOuter); |
| else |
| TRACE("DirectSoundCreate (%p)\n", ippDS); |
| |
| #ifdef HAVE_OSS |
| |
| if (ippDS == NULL) |
| return DSERR_INVALIDPARAM; |
| |
| if (primarybuf) { |
| IDirectSound_AddRef((LPDIRECTSOUND)dsound); |
| *ippDS = dsound; |
| return DS_OK; |
| } |
| |
| /* Check that we actually have audio capabilities */ |
| /* If we do, whether it's busy or not, we continue */ |
| /* otherwise we return with DSERR_NODRIVER */ |
| |
| audiofd = open("/dev/audio",O_WRONLY); |
| if (audiofd == -1) { |
| audiofd = -errno; |
| if (errno == ENODEV) { |
| MESSAGE("No sound hardware found, but continuing anyway.\n"); |
| } else if (errno == EBUSY) { |
| MESSAGE("Sound device busy, will keep trying.\n"); |
| } else { |
| MESSAGE("Unexpected error (%d) while checking for sound support.\n",errno); |
| return DSERR_GENERIC; |
| } |
| } else { |
| close(audiofd); |
| audiofd = -1; |
| } |
| |
| *ippDS = (IDirectSoundImpl*)HeapAlloc(GetProcessHeap(),0,sizeof(IDirectSoundImpl)); |
| if (*ippDS == NULL) |
| return DSERR_OUTOFMEMORY; |
| |
| (*ippDS)->ref = 1; |
| (*ippDS)->lpvtbl = &dsvt; |
| (*ippDS)->buffers = NULL; |
| (*ippDS)->nrofbuffers = 0; |
| |
| (*ippDS)->wfx.wFormatTag = 1; |
| (*ippDS)->wfx.nChannels = 2; |
| (*ippDS)->wfx.nSamplesPerSec = 22050; |
| (*ippDS)->wfx.nAvgBytesPerSec = 44100; |
| (*ippDS)->wfx.nBlockAlign = 2; |
| (*ippDS)->wfx.wBitsPerSample = 8; |
| |
| if (!dsound) { |
| HANDLE hnd; |
| DWORD xid; |
| |
| dsound = (*ippDS); |
| if (primarybuf == NULL) { |
| DSBUFFERDESC dsbd; |
| HRESULT hr; |
| |
| dsbd.dwSize = sizeof(DSBUFFERDESC); |
| dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER; |
| dsbd.dwBufferBytes = 0; |
| dsbd.lpwfxFormat = &(dsound->wfx); |
| hr = IDirectSound_CreateSoundBuffer(*ppDS, &dsbd, (LPDIRECTSOUNDBUFFER*)&primarybuf, NULL); |
| if (hr != DS_OK) |
| return hr; |
| dsound->primary = primarybuf; |
| } |
| memset(primarybuf->buffer, 128, primarybuf->buflen); |
| hnd = CreateThread(NULL,0,DSOUND_thread,0,0,&xid); |
| } |
| return DS_OK; |
| #else |
| MessageBoxA(0,"DirectSound needs the Open Sound System Driver, which has not been found by ./configure.","WINE DirectSound",MB_OK|MB_ICONSTOP); |
| return DSERR_NODRIVER; |
| #endif |
| } |
| |
| /******************************************************************************* |
| * DirectSound ClassFactory |
| */ |
| typedef struct |
| { |
| /* IUnknown fields */ |
| ICOM_VTABLE(IClassFactory)* lpvtbl; |
| DWORD ref; |
| } IClassFactoryImpl; |
| |
| static HRESULT WINAPI |
| DSCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) { |
| ICOM_THIS(IClassFactoryImpl,iface); |
| char buf[80]; |
| |
| if (HIWORD(riid)) |
| WINE_StringFromCLSID(riid,buf); |
| else |
| sprintf(buf,"<guid-0x%04x>",LOWORD(riid)); |
| FIXME("(%p)->(%s,%p),stub!\n",This,buf,ppobj); |
| return E_NOINTERFACE; |
| } |
| |
| static ULONG WINAPI |
| DSCF_AddRef(LPCLASSFACTORY iface) { |
| ICOM_THIS(IClassFactoryImpl,iface); |
| return ++(This->ref); |
| } |
| |
| static ULONG WINAPI DSCF_Release(LPCLASSFACTORY iface) { |
| ICOM_THIS(IClassFactoryImpl,iface); |
| /* static class, won't be freed */ |
| return --(This->ref); |
| } |
| |
| static HRESULT WINAPI DSCF_CreateInstance( |
| LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj |
| ) { |
| ICOM_THIS(IClassFactoryImpl,iface); |
| char buf[80]; |
| |
| WINE_StringFromCLSID(riid,buf); |
| TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,buf,ppobj); |
| if ( IsEqualGUID( &IID_IDirectSound, riid ) ) { |
| /* FIXME: reuse already created dsound if present? */ |
| return DirectSoundCreate(riid,(LPDIRECTSOUND*)ppobj,pOuter); |
| } |
| return E_NOINTERFACE; |
| } |
| |
| static HRESULT WINAPI DSCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) { |
| ICOM_THIS(IClassFactoryImpl,iface); |
| FIXME("(%p)->(%d),stub!\n",This,dolock); |
| return S_OK; |
| } |
| |
| static ICOM_VTABLE(IClassFactory) DSCF_Vtbl = { |
| DSCF_QueryInterface, |
| DSCF_AddRef, |
| DSCF_Release, |
| DSCF_CreateInstance, |
| DSCF_LockServer |
| }; |
| static IClassFactoryImpl DSOUND_CF = {&DSCF_Vtbl, 1 }; |
| |
| /******************************************************************************* |
| * DllGetClassObject [DSOUND.4] |
| * Retrieves class object from a DLL object |
| * |
| * NOTES |
| * Docs say returns STDAPI |
| * |
| * PARAMS |
| * rclsid [I] CLSID for the class object |
| * riid [I] Reference to identifier of interface for class object |
| * ppv [O] Address of variable to receive interface pointer for riid |
| * |
| * RETURNS |
| * Success: S_OK |
| * Failure: CLASS_E_CLASSNOTAVAILABLE, E_OUTOFMEMORY, E_INVALIDARG, |
| * E_UNEXPECTED |
| */ |
| DWORD WINAPI DSOUND_DllGetClassObject(REFCLSID rclsid,REFIID riid,LPVOID *ppv) |
| { |
| char buf[80],xbuf[80]; |
| |
| if (HIWORD(rclsid)) |
| WINE_StringFromCLSID(rclsid,xbuf); |
| else |
| sprintf(xbuf,"<guid-0x%04x>",LOWORD(rclsid)); |
| if (HIWORD(riid)) |
| WINE_StringFromCLSID(riid,buf); |
| else |
| sprintf(buf,"<guid-0x%04x>",LOWORD(riid)); |
| WINE_StringFromCLSID(riid,xbuf); |
| TRACE("(%p,%p,%p)\n", xbuf, buf, ppv); |
| if ( IsEqualCLSID( &IID_IClassFactory, riid ) ) { |
| *ppv = (LPVOID)&DSOUND_CF; |
| IClassFactory_AddRef((IClassFactory*)*ppv); |
| return S_OK; |
| } |
| |
| FIXME("(%p,%p,%p): no interface found.\n", xbuf, buf, ppv); |
| return CLASS_E_CLASSNOTAVAILABLE; |
| } |
| |
| |
| /******************************************************************************* |
| * DllCanUnloadNow [DSOUND.3] Determines whether the DLL is in use. |
| * |
| * RETURNS |
| * Success: S_OK |
| * Failure: S_FALSE |
| */ |
| DWORD WINAPI DSOUND_DllCanUnloadNow(void) |
| { |
| FIXME("(void): stub\n"); |
| return S_FALSE; |
| } |