X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fdarkplaces.git;a=blobdiff_plain;f=snd_win.c;h=fff1e3aaf3c8a7326d9ef37eec78d51405892ce3;hp=5434e5dbd29fc180697e71e279c3757fa052623b;hb=f9efec5d9bd92a5b614aab549f8b0a009051fbbc;hpb=4bae3a8c37a3a08174d6a7b3bf095d408572fdd6 diff --git a/snd_win.c b/snd_win.c index 5434e5db..fff1e3aa 100644 --- a/snd_win.c +++ b/snd_win.c @@ -18,29 +18,102 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "quakedef.h" -#include "winquake.h" +#include "snd_main.h" + +#ifdef SUPPORTDIRECTX +#ifndef DIRECTSOUND_VERSION +# define DIRECTSOUND_VERSION 0x0500 /* Version 5.0 */ +#endif +#endif +#include +#include +#ifdef SUPPORTDIRECTX +#include +#endif + +// ============================================================================== + +#ifndef _WAVEFORMATEXTENSIBLE_ +#define _WAVEFORMATEXTENSIBLE_ +typedef struct +{ + WAVEFORMATEX Format; + union + { + WORD wValidBitsPerSample; // bits of precision + WORD wSamplesPerBlock; // valid if wBitsPerSample==0 + WORD wReserved; // If neither applies, set to zero + } Samples; + DWORD dwChannelMask; // which channels are present in stream + GUID SubFormat; +} WAVEFORMATEXTENSIBLE, *PWAVEFORMATEXTENSIBLE; +#endif + +#if !defined(WAVE_FORMAT_EXTENSIBLE) +# define WAVE_FORMAT_EXTENSIBLE 0xFFFE +#endif + +// Some speaker positions +#ifndef SPEAKER_FRONT_LEFT +# define SPEAKER_FRONT_LEFT 0x1 +# define SPEAKER_FRONT_RIGHT 0x2 +# define SPEAKER_FRONT_CENTER 0x4 +# define SPEAKER_LOW_FREQUENCY 0x8 +# define SPEAKER_BACK_LEFT 0x10 +# define SPEAKER_BACK_RIGHT 0x20 +# define SPEAKER_FRONT_LEFT_OF_CENTER 0x40 +# define SPEAKER_FRONT_RIGHT_OF_CENTER 0x80 +// ... we never use the other values +#endif + +// KSDATAFORMAT_SUBTYPE_PCM = GUID "00000001-0000-0010-8000-00aa00389b71" +static const GUID MY_KSDATAFORMAT_SUBTYPE_PCM = +{ + 0x00000001, + 0x0000, + 0x0010, + { + 0x80, 0x00, + 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 + } +}; + -#define iDirectSoundCreate(a,b,c) pDirectSoundCreate(a,b,c) +// ============================================================================== +extern HWND mainwindow; + +#ifdef SUPPORTDIRECTX HRESULT (WINAPI *pDirectSoundCreate)(GUID FAR *lpGUID, LPDIRECTSOUND FAR *lplpDS, IUnknown FAR *pUnkOuter); +#endif + +// Wave output: how much buffer time, and how many partitions in that time +#define WAV_BUFFERTIME 0.125 +#define WAV_BUFFERS 16 +#define WAV_MASK (WAV_BUFFERS - 1) +static unsigned int wav_buffer_size; -// 64K is > 1 second at 16-bit, 22050 Hz -#define WAV_BUFFERS 64 -#define WAV_MASK 0x3F -#define WAV_BUFFER_SIZE 0x0400 -#define SECONDARY_BUFFER_SIZE 0x10000 +// DirectSound output: 64KB in 1 buffer +//#define SECONDARY_BUFFER_SIZE(fmt_ptr) ((fmt_ptr)->width * (fmt_ptr)->channels * (fmt_ptr)->speed / 2) +// LordHavoc: changed this to be a multiple of 32768 +#define SECONDARY_BUFFER_SIZE(fmt_ptr) ((fmt_ptr)->channels * 32768) -typedef enum {SIS_SUCCESS, SIS_FAILURE, SIS_NOTAVAIL} sndinitstat; +typedef enum sndinitstat_e {SIS_SUCCESS, SIS_FAILURE, SIS_NOTAVAIL} sndinitstat; -static qboolean wavonly; +#ifdef SUPPORTDIRECTX static qboolean dsound_init; -static qboolean wav_init; -static qboolean snd_firsttime = true, snd_isdirect, snd_iswave; +static unsigned int dsound_time; static qboolean primary_format_set; +#endif + +static qboolean wav_init; -static int sample16; static int snd_sent, snd_completed; +static int prev_painted; +static unsigned int paintpot; + + /* * Global variables. Must be visible to window-procedure function @@ -59,154 +132,100 @@ WAVEOUTCAPS wavecaps; DWORD gSndBufSize; -MMTIME mmstarttime; +DWORD dwStartTime; +#ifdef SUPPORTDIRECTX LPDIRECTSOUND pDS; LPDIRECTSOUNDBUFFER pDSBuf, pDSPBuf; HINSTANCE hInstDS; +#endif qboolean SNDDMA_InitWav (void); +#ifdef SUPPORTDIRECTX sndinitstat SNDDMA_InitDirect (void); - -/* -================== -S_BlockSound -================== -*/ -void S_BlockSound (void) -{ - -// DirectSound takes care of blocking itself - if (snd_iswave) - { - snd_blocked++; - - if (snd_blocked == 1) - { - waveOutReset (hWaveOut); - } - } -} +#endif /* ================== -S_UnblockSound +SndSys_BuildWaveFormat ================== */ -void S_UnblockSound (void) +static qboolean SndSys_BuildWaveFormat (const snd_format_t* requested, WAVEFORMATEXTENSIBLE* fmt_ptr) { + WAVEFORMATEX* pfmtex; -// DirectSound takes care of blocking itself - if (snd_iswave) - { - snd_blocked--; - } -} + memset (fmt_ptr, 0, sizeof(*fmt_ptr)); + pfmtex = &fmt_ptr->Format; + pfmtex->nChannels = requested->channels; + pfmtex->wBitsPerSample = requested->width * 8; + pfmtex->nSamplesPerSec = requested->speed; + pfmtex->nBlockAlign = pfmtex->nChannels * pfmtex->wBitsPerSample / 8; + pfmtex->nAvgBytesPerSec = pfmtex->nSamplesPerSec * pfmtex->nBlockAlign; -/* -================== -FreeSound -================== -*/ -void FreeSound (void) -{ - int i; - - if (pDSBuf) - { - pDSBuf->lpVtbl->Stop(pDSBuf); - pDSBuf->lpVtbl->Release(pDSBuf); - } - -// only release primary buffer if it's not also the mixing buffer we just released - if (pDSPBuf && (pDSBuf != pDSPBuf)) - { - pDSPBuf->lpVtbl->Release(pDSPBuf); - } - - if (pDS) + // LordHavoc: disabled this WAVE_FORMAT_EXTENSIBLE support because it does not seem to be working +#if 0 + if (requested->channels <= 2) { - pDS->lpVtbl->SetCooperativeLevel (pDS, mainwindow, DSSCL_NORMAL); - pDS->lpVtbl->Release(pDS); +#endif + pfmtex->wFormatTag = WAVE_FORMAT_PCM; + pfmtex->cbSize = 0; +#if 0 } - - if (hWaveOut) + else { - waveOutReset (hWaveOut); - - if (lpWaveHdr) + pfmtex->wFormatTag = WAVE_FORMAT_EXTENSIBLE; + pfmtex->cbSize = sizeof(*fmt_ptr) - sizeof(fmt_ptr->Format); + fmt_ptr->Samples.wValidBitsPerSample = fmt_ptr->Format.wBitsPerSample; + fmt_ptr->SubFormat = MY_KSDATAFORMAT_SUBTYPE_PCM; + + // Build the channel mask + fmt_ptr->dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT; + switch (requested->channels) { - for (i=0 ; i< WAV_BUFFERS ; i++) - waveOutUnprepareHeader (hWaveOut, lpWaveHdr+i, sizeof(WAVEHDR)); + case 8: + fmt_ptr->dwChannelMask |= SPEAKER_FRONT_LEFT_OF_CENTER | SPEAKER_FRONT_RIGHT_OF_CENTER; + // no break + case 6: + fmt_ptr->dwChannelMask |= SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY; + // no break + case 4: + fmt_ptr->dwChannelMask |= SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT; + break; + + default: + Con_Printf("SndSys_BuildWaveFormat: invalid number of channels (%hu)\n", requested->channels); + return false; } - - waveOutClose (hWaveOut); - - if (hWaveHdr) - { - GlobalUnlock(hWaveHdr); - GlobalFree(hWaveHdr); - } - - if (hData) - { - GlobalUnlock(hData); - GlobalFree(hData); - } - } +#endif - pDS = NULL; - pDSBuf = NULL; - pDSPBuf = NULL; - hWaveOut = 0; - hData = 0; - hWaveHdr = 0; - lpData = NULL; - lpWaveHdr = NULL; - dsound_init = false; - wav_init = false; + return true; } +#ifdef SUPPORTDIRECTX /* ================== -SNDDMA_InitDirect +SndSys_InitDirectSound -Direct-Sound support +DirectSound 5 support ================== */ -sndinitstat SNDDMA_InitDirect (void) +static sndinitstat SndSys_InitDirectSound (const snd_format_t* requested) { - DSBUFFERDESC dsbuf; - DSBCAPS dsbcaps; - DWORD dwSize, dwWrite; - DSCAPS dscaps; - WAVEFORMATEX format, pformat; - HRESULT hresult; - int reps; - int i; - - memset((void *)shm, 0, sizeof(*shm)); - shm->channels = 2; - shm->samplebits = 16; - i = COM_CheckParm ("-sndspeed"); // LordHavoc: -sndspeed option - if (i && i != (com_argc - 1)) - shm->speed = atoi(com_argv[i+1]); - else - shm->speed = 44100; - - memset (&format, 0, sizeof(format)); - format.wFormatTag = WAVE_FORMAT_PCM; - format.nChannels = shm->channels; - format.wBitsPerSample = shm->samplebits; - format.nSamplesPerSec = shm->speed; - format.nBlockAlign = format.nChannels * format.wBitsPerSample / 8; - format.cbSize = 0; - format.nAvgBytesPerSec = format.nSamplesPerSec * format.nBlockAlign; + DSBUFFERDESC dsbuf; + DSBCAPS dsbcaps; + DWORD dwSize; + DSCAPS dscaps; + WAVEFORMATEXTENSIBLE format, pformat; + HRESULT hresult; + int reps; + + if (! SndSys_BuildWaveFormat(requested, &format)) + return SIS_FAILURE; if (!hInstDS) { @@ -214,7 +233,7 @@ sndinitstat SNDDMA_InitDirect (void) if (hInstDS == NULL) { - Con_SafePrintf ("Couldn't load dsound.dll\n"); + Con_Print("Couldn't load dsound.dll\n"); return SIS_FAILURE; } @@ -222,16 +241,16 @@ sndinitstat SNDDMA_InitDirect (void) if (!pDirectSoundCreate) { - Con_SafePrintf ("Couldn't get DS proc addr\n"); + Con_Print("Couldn't get DS proc addr\n"); return SIS_FAILURE; } } - while ((hresult = iDirectSoundCreate(NULL, &pDS, NULL)) != DS_OK) + while ((hresult = pDirectSoundCreate(NULL, &pDS, NULL)) != DS_OK) { if (hresult != DSERR_ALLOCATED) { - Con_SafePrintf ("DirectSound create failed\n"); + Con_Print("DirectSound create failed\n"); return SIS_FAILURE; } @@ -241,35 +260,34 @@ sndinitstat SNDDMA_InitDirect (void) "Sound not available", MB_RETRYCANCEL | MB_SETFOREGROUND | MB_ICONEXCLAMATION) != IDRETRY) { - Con_SafePrintf ("DirectSoundCreate failure\n" - " hardware already in use\n"); + Con_Print("DirectSoundCreate failure\n hardware already in use\n"); return SIS_NOTAVAIL; } } dscaps.dwSize = sizeof(dscaps); - if (DS_OK != pDS->lpVtbl->GetCaps (pDS, &dscaps)) + if (DS_OK != IDirectSound_GetCaps (pDS, &dscaps)) { - Con_SafePrintf ("Couldn't get DS caps\n"); + Con_Print("Couldn't get DS caps\n"); } if (dscaps.dwFlags & DSCAPS_EMULDRIVER) { - Con_SafePrintf ("No DirectSound driver installed\n"); - FreeSound (); + Con_Print("No DirectSound driver installed\n"); + SndSys_Shutdown (); return SIS_FAILURE; } - if (DS_OK != pDS->lpVtbl->SetCooperativeLevel (pDS, mainwindow, DSSCL_EXCLUSIVE)) + if (DS_OK != IDirectSound_SetCooperativeLevel (pDS, mainwindow, DSSCL_EXCLUSIVE)) { - Con_SafePrintf ("Set coop level failed\n"); - FreeSound (); + Con_Print("Set coop level failed\n"); + SndSys_Shutdown (); return SIS_FAILURE; } -// get access to the primary buffer, if possible, so we can set the -// sound hardware format + // get access to the primary buffer, if possible, so we can set the + // sound hardware format memset (&dsbuf, 0, sizeof(dsbuf)); dsbuf.dwSize = sizeof(DSBUFFERDESC); dsbuf.dwFlags = DSBCAPS_PRIMARYBUFFER; @@ -280,177 +298,152 @@ sndinitstat SNDDMA_InitDirect (void) dsbcaps.dwSize = sizeof(dsbcaps); primary_format_set = false; +// COMMANDLINEOPTION: Windows DirectSound: -snoforceformat uses the format that DirectSound returns, rather than forcing it if (!COM_CheckParm ("-snoforceformat")) { - if (DS_OK == pDS->lpVtbl->CreateSoundBuffer(pDS, &dsbuf, &pDSPBuf, NULL)) + if (DS_OK == IDirectSound_CreateSoundBuffer(pDS, &dsbuf, &pDSPBuf, NULL)) { pformat = format; - if (DS_OK != pDSPBuf->lpVtbl->SetFormat (pDSPBuf, &pformat)) + if (DS_OK != IDirectSoundBuffer_SetFormat (pDSPBuf, (WAVEFORMATEX*)&pformat)) { - if (snd_firsttime) - Con_SafePrintf ("Set primary sound buffer format: no\n"); + Con_Print("Set primary sound buffer format: no\n"); } else { - if (snd_firsttime) - Con_SafePrintf ("Set primary sound buffer format: yes\n"); + Con_Print("Set primary sound buffer format: yes\n"); primary_format_set = true; } } } +// COMMANDLINEOPTION: Windows DirectSound: -primarysound locks the sound hardware for exclusive use if (!primary_format_set || !COM_CheckParm ("-primarysound")) { - // create the secondary buffer we'll actually work with + HRESULT result; + + // create the secondary buffer we'll actually work with memset (&dsbuf, 0, sizeof(dsbuf)); dsbuf.dwSize = sizeof(DSBUFFERDESC); dsbuf.dwFlags = DSBCAPS_CTRLFREQUENCY | DSBCAPS_LOCSOFTWARE; - dsbuf.dwBufferBytes = SECONDARY_BUFFER_SIZE; - dsbuf.lpwfxFormat = &format; + dsbuf.dwBufferBytes = SECONDARY_BUFFER_SIZE(requested); + dsbuf.lpwfxFormat = (WAVEFORMATEX*)&format; memset(&dsbcaps, 0, sizeof(dsbcaps)); dsbcaps.dwSize = sizeof(dsbcaps); - if (DS_OK != pDS->lpVtbl->CreateSoundBuffer(pDS, &dsbuf, &pDSBuf, NULL)) + result = IDirectSound_CreateSoundBuffer(pDS, &dsbuf, &pDSBuf, NULL); + if (result != DS_OK || + requested->channels != format.Format.nChannels || + requested->width != format.Format.wBitsPerSample / 8 || + requested->speed != format.Format.nSamplesPerSec) { - Con_SafePrintf ("DS:CreateSoundBuffer Failed"); - FreeSound (); + Con_Printf("DS:CreateSoundBuffer Failed (%d): channels=%u, width=%u, speed=%u\n", + (int)result, (unsigned)format.Format.nChannels, (unsigned)format.Format.wBitsPerSample / 8, (unsigned)format.Format.nSamplesPerSec); + SndSys_Shutdown (); return SIS_FAILURE; } - shm->channels = format.nChannels; - shm->samplebits = format.wBitsPerSample; - shm->speed = format.nSamplesPerSec; - - if (DS_OK != pDSBuf->lpVtbl->GetCaps (pDSBuf, &dsbcaps)) + if (DS_OK != IDirectSoundBuffer_GetCaps (pDSBuf, &dsbcaps)) { - Con_SafePrintf ("DS:GetCaps failed\n"); - FreeSound (); + Con_Print("DS:GetCaps failed\n"); + SndSys_Shutdown (); return SIS_FAILURE; } - if (snd_firsttime) - Con_SafePrintf ("Using secondary sound buffer\n"); + Con_Print("Using secondary sound buffer\n"); } else { - if (DS_OK != pDS->lpVtbl->SetCooperativeLevel (pDS, mainwindow, DSSCL_WRITEPRIMARY)) + if (DS_OK != IDirectSound_SetCooperativeLevel (pDS, mainwindow, DSSCL_WRITEPRIMARY)) { - Con_SafePrintf ("Set coop level failed\n"); - FreeSound (); + Con_Print("Set coop level failed\n"); + SndSys_Shutdown (); return SIS_FAILURE; } - if (DS_OK != pDSPBuf->lpVtbl->GetCaps (pDSPBuf, &dsbcaps)) + if (DS_OK != IDirectSoundBuffer_GetCaps (pDSPBuf, &dsbcaps)) { - Con_Printf ("DS:GetCaps failed\n"); + Con_Print("DS:GetCaps failed\n"); return SIS_FAILURE; } pDSBuf = pDSPBuf; - Con_SafePrintf ("Using primary sound buffer\n"); + Con_Print("Using primary sound buffer\n"); } // Make sure mixer is active - pDSBuf->lpVtbl->Play(pDSBuf, 0, 0, DSBPLAY_LOOPING); + IDirectSoundBuffer_Play(pDSBuf, 0, 0, DSBPLAY_LOOPING); - if (snd_firsttime) - Con_SafePrintf(" %d channel(s)\n" - " %d bits/sample\n" - " %d samples/sec\n", - shm->channels, shm->samplebits, shm->speed); + Con_Printf(" %d channel(s)\n" + " %d bits/sample\n" + " %d samples/sec\n", + requested->channels, requested->width * 8, requested->speed); gSndBufSize = dsbcaps.dwBufferBytes; -// initialize the buffer + // initialize the buffer reps = 0; - while ((hresult = pDSBuf->lpVtbl->Lock(pDSBuf, 0, gSndBufSize, (LPVOID*)&lpData, &dwSize, NULL, NULL, 0)) != DS_OK) + while ((hresult = IDirectSoundBuffer_Lock(pDSBuf, 0, gSndBufSize, (LPVOID*)&lpData, &dwSize, NULL, NULL, 0)) != DS_OK) { if (hresult != DSERR_BUFFERLOST) { - Con_SafePrintf ("SNDDMA_InitDirect: DS::Lock Sound Buffer Failed\n"); - FreeSound (); + Con_Print("SNDDMA_InitDirect: DS::Lock Sound Buffer Failed\n"); + SndSys_Shutdown (); return SIS_FAILURE; } if (++reps > 10000) { - Con_SafePrintf ("SNDDMA_InitDirect: DS: couldn't restore buffer\n"); - FreeSound (); + Con_Print("SNDDMA_InitDirect: DS: couldn't restore buffer\n"); + SndSys_Shutdown (); return SIS_FAILURE; } } memset(lpData, 0, dwSize); + IDirectSoundBuffer_Unlock(pDSBuf, lpData, dwSize, NULL, 0); - pDSBuf->lpVtbl->Unlock(pDSBuf, lpData, dwSize, NULL, 0); - - /* we don't want anyone to access the buffer directly w/o locking it first. */ - lpData = NULL; - - pDSBuf->lpVtbl->Stop(pDSBuf); - pDSBuf->lpVtbl->GetCurrentPosition(pDSBuf, &mmstarttime.u.sample, &dwWrite); - pDSBuf->lpVtbl->Play(pDSBuf, 0, 0, DSBPLAY_LOOPING); + IDirectSoundBuffer_Stop(pDSBuf); + IDirectSoundBuffer_Play(pDSBuf, 0, 0, DSBPLAY_LOOPING); - shm->samples = gSndBufSize/(shm->samplebits/8); - shm->samplepos = 0; - shm->buffer = (unsigned char *) lpData; - sample16 = (shm->samplebits/8) - 1; + dwStartTime = 0; + dsound_time = 0; + snd_renderbuffer = Snd_CreateRingBuffer(requested, gSndBufSize / (requested->width * requested->channels), lpData); dsound_init = true; return SIS_SUCCESS; } +#endif /* ================== -SNDDM_InitWav +SndSys_InitMmsystem Crappy windows multimedia base ================== */ -qboolean SNDDMA_InitWav (void) +static qboolean SndSys_InitMmsystem (const snd_format_t* requested) { - WAVEFORMATEX format; + WAVEFORMATEXTENSIBLE format; int i; HRESULT hr; - snd_sent = 0; - snd_completed = 0; + if (! SndSys_BuildWaveFormat(requested, &format)) + return false; - memset((void *)shm, 0, sizeof(*shm)); - shm->channels = 2; - shm->samplebits = 16; - i = COM_CheckParm ("-sndspeed"); // LordHavoc: -sndspeed option - if (i && i != (com_argc - 1)) - shm->speed = atoi(com_argv[i+1]); - else - shm->speed = 44100; - - memset (&format, 0, sizeof(format)); - format.wFormatTag = WAVE_FORMAT_PCM; - format.nChannels = shm->channels; - format.wBitsPerSample = shm->samplebits; - format.nSamplesPerSec = shm->speed; - format.nBlockAlign = format.nChannels - *format.wBitsPerSample / 8; - format.cbSize = 0; - format.nAvgBytesPerSec = format.nSamplesPerSec - *format.nBlockAlign; - - /* Open a waveform device for output using window callback. */ - while ((hr = waveOutOpen((LPHWAVEOUT)&hWaveOut, WAVE_MAPPER, - &format, + // Open a waveform device for output using window callback + while ((hr = waveOutOpen((LPHWAVEOUT)&hWaveOut, WAVE_MAPPER, (WAVEFORMATEX*)&format, 0, 0L, CALLBACK_NULL)) != MMSYSERR_NOERROR) { if (hr != MMSYSERR_ALLOCATED) { - Con_SafePrintf ("waveOutOpen failed\n"); + Con_Print("waveOutOpen failed\n"); return false; } @@ -460,31 +453,31 @@ qboolean SNDDMA_InitWav (void) "Sound not available", MB_RETRYCANCEL | MB_SETFOREGROUND | MB_ICONEXCLAMATION) != IDRETRY) { - Con_SafePrintf ("waveOutOpen failure;\n" - " hardware already in use\n"); + Con_Print("waveOutOpen failure;\n hardware already in use\n"); return false; } } + wav_buffer_size = ((int)(requested->speed * WAV_BUFFERTIME) / WAV_BUFFERS) * requested->channels * requested->width; + /* * Allocate and lock memory for the waveform data. The memory * for waveform data must be globally allocated with * GMEM_MOVEABLE and GMEM_SHARE flags. - - */ - gSndBufSize = WAV_BUFFERS*WAV_BUFFER_SIZE; + */ + gSndBufSize = WAV_BUFFERS * wav_buffer_size; hData = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, gSndBufSize); if (!hData) { - Con_SafePrintf ("Sound: Out of memory.\n"); - FreeSound (); + Con_Print("Sound: Out of memory.\n"); + SndSys_Shutdown (); return false; } lpData = GlobalLock(hData); if (!lpData) { - Con_SafePrintf ("Sound: Failed to lock.\n"); - FreeSound (); + Con_Print("Sound: Failed to lock.\n"); + SndSys_Shutdown (); return false; } memset (lpData, 0, gSndBufSize); @@ -494,13 +487,12 @@ qboolean SNDDMA_InitWav (void) * also be globally allocated with GMEM_MOVEABLE and * GMEM_SHARE flags. */ - hWaveHdr = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, - (DWORD) sizeof(WAVEHDR) * WAV_BUFFERS); + hWaveHdr = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, (DWORD) sizeof(WAVEHDR) * WAV_BUFFERS); if (hWaveHdr == NULL) { - Con_SafePrintf ("Sound: Failed to Alloc header.\n"); - FreeSound (); + Con_Print("Sound: Failed to Alloc header.\n"); + SndSys_Shutdown (); return false; } @@ -508,257 +500,377 @@ qboolean SNDDMA_InitWav (void) if (lpWaveHdr == NULL) { - Con_SafePrintf ("Sound: Failed to lock header.\n"); - FreeSound (); + Con_Print("Sound: Failed to lock header.\n"); + SndSys_Shutdown (); return false; } memset (lpWaveHdr, 0, sizeof(WAVEHDR) * WAV_BUFFERS); - /* After allocation, set up and prepare headers. */ + // After allocation, set up and prepare headers for (i=0 ; isamples = gSndBufSize/(shm->samplebits/8); - shm->samplepos = 0; - shm->buffer = (unsigned char *) lpData; - sample16 = (shm->samplebits/8) - 1; + snd_renderbuffer = Snd_CreateRingBuffer(requested, gSndBufSize / (requested->width * requested->channels), lpData); + + prev_painted = 0; + paintpot = 0; + + snd_sent = 0; + snd_completed = 0; wav_init = true; return true; } + /* -================== -SNDDMA_Init +==================== +SndSys_Init -Try to find a sound device to mix for. -Returns false if nothing is found. -================== +Create "snd_renderbuffer" with the proper sound format if the call is successful +May return a suggested format if the requested format isn't available +==================== */ - -qboolean SNDDMA_Init(void) +qboolean SndSys_Init (const snd_format_t* requested, snd_format_t* suggested) { +#ifdef SUPPORTDIRECTX + qboolean wavonly; +#endif sndinitstat stat; - if (COM_CheckParm ("-wavonly")) - wavonly = true; + Con_Print ("SndSys_Init: using the Win32 module\n"); - dsound_init = wav_init = 0; +#ifdef SUPPORTDIRECTX +// COMMANDLINEOPTION: Windows Sound: -wavonly uses wave sound instead of DirectSound + wavonly = (COM_CheckParm ("-wavonly") != 0); + dsound_init = false; +#endif + wav_init = false; stat = SIS_FAILURE; // assume DirectSound won't initialize - /* Init DirectSound */ +#ifdef SUPPORTDIRECTX + // Init DirectSound if (!wavonly) { - if (snd_firsttime || snd_isdirect) - { - stat = SNDDMA_InitDirect ();; - - if (stat == SIS_SUCCESS) - { - snd_isdirect = true; + stat = SndSys_InitDirectSound (requested); - if (snd_firsttime) - Con_SafePrintf ("DirectSound initialized\n"); - } - else - { - snd_isdirect = false; - Con_SafePrintf ("DirectSound failed to init\n"); - } - } + if (stat == SIS_SUCCESS) + Con_Print("DirectSound initialized\n"); + else + Con_Print("DirectSound failed to init\n"); } +#endif -// if DirectSound didn't succeed in initializing, try to initialize -// waveOut sound, unless DirectSound failed because the hardware is -// already allocated (in which case the user has already chosen not -// to have sound) + // if DirectSound didn't succeed in initializing, try to initialize + // waveOut sound, unless DirectSound failed because the hardware is + // already allocated (in which case the user has already chosen not + // to have sound) +#ifdef SUPPORTDIRECTX if (!dsound_init && (stat != SIS_NOTAVAIL)) +#endif { - if (snd_firsttime || snd_iswave) - { - - snd_iswave = SNDDMA_InitWav (); - - if (snd_iswave) - { - if (snd_firsttime) - Con_SafePrintf ("Wave sound initialized\n"); - } - else - { - Con_SafePrintf ("Wave sound failed to init\n"); - } - } + if (SndSys_InitMmsystem (requested)) + Con_Print("Wave sound (MMSYSTEM) initialized\n"); + else + Con_Print("Wave sound failed to init\n"); } - snd_firsttime = false; - - if (!dsound_init && !wav_init) - return 0; - - return 1; +#ifdef SUPPORTDIRECTX + return (dsound_init || wav_init); +#else + return wav_init; +#endif } + /* -============== -SNDDMA_GetDMAPos +==================== +SndSys_Shutdown -return the current sample position (in mono samples read) -inside the recirculating dma buffer, so the mixing code will know -how many sample are required to fill it up. -=============== +Stop the sound card, delete "snd_renderbuffer" and free its other resources +==================== */ -int SNDDMA_GetDMAPos(void) +void SndSys_Shutdown (void) { - MMTIME mmtime; - int s; - DWORD dwWrite; +#ifdef SUPPORTDIRECTX + if (pDSBuf) + { + IDirectSoundBuffer_Stop(pDSBuf); + IDirectSoundBuffer_Release(pDSBuf); + } - if (dsound_init) + // only release primary buffer if it's not also the mixing buffer we just released + if (pDSPBuf && (pDSBuf != pDSPBuf)) { - mmtime.wType = TIME_SAMPLES; - pDSBuf->lpVtbl->GetCurrentPosition(pDSBuf, &mmtime.u.sample, &dwWrite); - s = mmtime.u.sample - mmstarttime.u.sample; + IDirectSoundBuffer_Release(pDSPBuf); } - else if (wav_init) + + if (pDS) { - s = snd_sent * WAV_BUFFER_SIZE; + IDirectSound_SetCooperativeLevel (pDS, mainwindow, DSSCL_NORMAL); + IDirectSound_Release(pDS); } - else - s = 0; +#endif + + if (hWaveOut) + { + waveOutReset (hWaveOut); + + if (lpWaveHdr) + { + unsigned int i; + + for (i=0 ; i< WAV_BUFFERS ; i++) + waveOutUnprepareHeader (hWaveOut, lpWaveHdr+i, sizeof(WAVEHDR)); + } + + waveOutClose (hWaveOut); + if (hWaveHdr) + { + GlobalUnlock(hWaveHdr); + GlobalFree(hWaveHdr); + } - s >>= sample16; + if (hData) + { + GlobalUnlock(hData); + GlobalFree(hData); + } + } - s &= (shm->samples-1); + if (snd_renderbuffer != NULL) + { + Mem_Free(snd_renderbuffer); + snd_renderbuffer = NULL; + } - return s; +#ifdef SUPPORTDIRECTX + pDS = NULL; + pDSBuf = NULL; + pDSPBuf = NULL; + dsound_init = false; +#endif + hWaveOut = 0; + hData = 0; + hWaveHdr = 0; + lpData = NULL; + lpWaveHdr = NULL; + wav_init = false; } + /* -============== -SNDDMA_Submit +==================== +SndSys_Submit -Send sound to device if buffer isn't really the dma buffer -=============== +Submit the contents of "snd_renderbuffer" to the sound card +==================== */ -void SNDDMA_Submit(void) +void SndSys_Submit (void) { LPWAVEHDR h; int wResult; + // DirectSound doesn't need this if (!wav_init) return; - // - // find which sound blocks have completed - // - while (1) - { - if ( snd_completed == snd_sent ) - { - Con_DPrintf ("Sound overrun\n"); - break; - } - - if ( ! (lpWaveHdr[ snd_completed & WAV_MASK].dwFlags & WHDR_DONE) ) - { - break; - } - - snd_completed++; // this buffer has been played - } + paintpot += (snd_renderbuffer->endframe - prev_painted) * snd_renderbuffer->format.channels * snd_renderbuffer->format.width; + if (paintpot > WAV_BUFFERS * wav_buffer_size) + paintpot = WAV_BUFFERS * wav_buffer_size; + prev_painted = snd_renderbuffer->endframe; - // - // submit two new sound blocks - // - while (((snd_sent - snd_completed) >> sample16) < 4) + // submit new sound blocks + while (paintpot > wav_buffer_size) { - h = lpWaveHdr + ( snd_sent&WAV_MASK ); + h = lpWaveHdr + (snd_sent & WAV_MASK); - snd_sent++; /* * Now the data block can be sent to the output device. The * waveOutWrite function returns immediately and waveform * data is sent to the output device in the background. */ wResult = waveOutWrite(hWaveOut, h, sizeof(WAVEHDR)); - - if (wResult != MMSYSERR_NOERROR) + if (wResult == MMSYSERR_NOERROR) + snd_sent++; + else if (wResult == WAVERR_STILLPLAYING) + { + if(developer.integer >= 1000) + Con_Print("waveOutWrite failed (too much sound data)\n"); + //h->dwFlags |= WHDR_DONE; + //snd_sent++; + } + else { - Con_SafePrintf ("Failed to write block to device\n"); - FreeSound (); + Con_Printf("waveOutWrite failed, error code %d\n", (int) wResult); + SndSys_Shutdown (); return; } + + paintpot -= wav_buffer_size; } + } + /* -============== -SNDDMA_Shutdown +==================== +SndSys_GetSoundTime -Reset the sound device for exiting -=============== +Returns the number of sample frames consumed since the sound started +==================== */ -void SNDDMA_Shutdown(void) +unsigned int SndSys_GetSoundTime (void) { - FreeSound (); + unsigned int factor; + + factor = snd_renderbuffer->format.width * snd_renderbuffer->format.channels; + +#ifdef SUPPORTDIRECTX + if (dsound_init) + { + DWORD dwTime; + unsigned int diff; + + IDirectSoundBuffer_GetCurrentPosition(pDSBuf, &dwTime, NULL); + diff = (unsigned int)(dwTime - dwStartTime) % (unsigned int)gSndBufSize; + dwStartTime = dwTime; + + dsound_time += diff / factor; + return dsound_time; + } +#endif + + if (wav_init) + { + // Find which sound blocks have completed + for (;;) + { + if (snd_completed == snd_sent) + { + Con_DPrint("Sound overrun\n"); + break; + } + + if (!(lpWaveHdr[snd_completed & WAV_MASK].dwFlags & WHDR_DONE)) + break; + + snd_completed++; // this buffer has been played + } + + return (snd_completed * wav_buffer_size) / factor; + + /* + * S_PaintAndSubmit: WARNING: newsoundtime (soundtime (275 < 134217707) + * apparently this sound time wraps quite early? + { + MMRESULT res; + MMTIME mmtime; + + mmtime.wType = TIME_SAMPLES; + res = waveOutGetPosition(hWaveOut, &mmtime, sizeof(mmtime)); + if(res == MMSYSERR_NOERROR) + return mmtime.u.sample; + } + */ + } + + return 0; } -DWORD dsound_dwSize; -DWORD dsound_dwSize2; -DWORD *dsound_pbuf; -DWORD *dsound_pbuf2; -void *S_LockBuffer(void) + +#ifdef SUPPORTDIRECTX +static DWORD dsound_dwSize; +static DWORD dsound_dwSize2; +static DWORD *dsound_pbuf; +static DWORD *dsound_pbuf2; +#endif + +/* +==================== +SndSys_LockRenderBuffer + +Get the exclusive lock on "snd_renderbuffer" +==================== +*/ +qboolean SndSys_LockRenderBuffer (void) { +#ifdef SUPPORTDIRECTX int reps; HRESULT hresult; + DWORD dwStatus; if (pDSBuf) { + // if the buffer was lost or stopped, restore it and/or restart it + if (IDirectSoundBuffer_GetStatus (pDSBuf, &dwStatus) != DS_OK) + Con_Print("Couldn't get sound buffer status\n"); + + if (dwStatus & DSBSTATUS_BUFFERLOST) + { + Con_Print("DSound buffer is lost!!\n"); + IDirectSoundBuffer_Restore (pDSBuf); + } + + if (!(dwStatus & DSBSTATUS_PLAYING)) + IDirectSoundBuffer_Play(pDSBuf, 0, 0, DSBPLAY_LOOPING); + reps = 0; - while ((hresult = pDSBuf->lpVtbl->Lock(pDSBuf, 0, gSndBufSize, (LPVOID*)&dsound_pbuf, &dsound_dwSize, (LPVOID*)&dsound_pbuf2, &dsound_dwSize2, 0)) != DS_OK) + while ((hresult = IDirectSoundBuffer_Lock(pDSBuf, 0, gSndBufSize, (LPVOID*)&dsound_pbuf, &dsound_dwSize, (LPVOID*)&dsound_pbuf2, &dsound_dwSize2, 0)) != DS_OK) { if (hresult != DSERR_BUFFERLOST) { - Con_Printf ("S_LockBuffer: DS::Lock Sound Buffer Failed\n"); + Con_Print("S_LockBuffer: DS: Lock Sound Buffer Failed\n"); S_Shutdown (); S_Startup (); - return NULL; + return false; } if (++reps > 10000) { - Con_Printf ("S_LockBuffer: DS: couldn't restore buffer\n"); + Con_Print("S_LockBuffer: DS: couldn't restore buffer\n"); S_Shutdown (); S_Startup (); - return NULL; + return false; } } - return dsound_pbuf; + + if ((void*)dsound_pbuf != snd_renderbuffer->ring) + Sys_Error("SndSys_LockRenderBuffer: the ring address has changed!!!\n"); + return true; } - else - return shm->buffer; +#endif + + return wav_init; } -void S_UnlockBuffer(void) + +/* +==================== +SndSys_UnlockRenderBuffer + +Release the exclusive lock on "snd_renderbuffer" +==================== +*/ +void SndSys_UnlockRenderBuffer (void) { +#ifdef SUPPORTDIRECTX if (pDSBuf) - pDSBuf->lpVtbl->Unlock(pDSBuf, dsound_pbuf, dsound_dwSize, dsound_pbuf2, dsound_dwSize2); + IDirectSoundBuffer_Unlock(pDSBuf, dsound_pbuf, dsound_dwSize, dsound_pbuf2, dsound_dwSize2); +#endif } -