X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fdarkplaces.git;a=blobdiff_plain;f=snd_win.c;h=2752446fb9ba3c2e3c7373d22037ab1e36889733;hp=0fec464b841422c9ecb69ba0f3a222549aa5e985;hb=f9d8bc7ea04ff91fcbd90fe50a299b37724b349b;hpb=3e84ec7391c20263a18ee7784510bfc6a0a484d6 diff --git a/snd_win.c b/snd_win.c index 0fec464b..2752446f 100644 --- a/snd_win.c +++ b/snd_win.c @@ -18,6 +18,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "quakedef.h" +#include "snd_main.h" #include #include @@ -27,23 +28,27 @@ extern HWND mainwindow; HRESULT (WINAPI *pDirectSoundCreate)(GUID FAR *lpGUID, LPDIRECTSOUND FAR *lplpDS, IUnknown FAR *pUnkOuter); -// 64K is > 1 second at 16-bit, 22050 Hz +// Wave output: 64KB in 64 buffers of 1KB +// (64KB is > 1 sec at 16-bit 22050 Hz mono, and is 1/3 sec at 16-bit 44100 Hz stereo) #define WAV_BUFFERS 64 -#define WAV_MASK 0x3F -#define WAV_BUFFER_SIZE 0x0400 -#define SECONDARY_BUFFER_SIZE 0x10000 +#define WAV_MASK (WAV_BUFFERS - 1) +#define WAV_BUFFER_SIZE 1024 -typedef enum {SIS_SUCCESS, SIS_FAILURE, SIS_NOTAVAIL} sndinitstat; +// DirectSound output: 64KB in 1 buffer +#define SECONDARY_BUFFER_SIZE (64 * 1024) + +typedef enum sndinitstat_e {SIS_SUCCESS, SIS_FAILURE, SIS_NOTAVAIL} sndinitstat; static qboolean wavonly; static qboolean dsound_init; static qboolean wav_init; -static qboolean snd_firsttime = true, snd_isdirect, snd_iswave; static qboolean primary_format_set; -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 @@ -62,7 +67,7 @@ WAVEOUTCAPS wavecaps; DWORD gSndBufSize; -MMTIME mmstarttime; +DWORD dwStartTime; LPDIRECTSOUND pDS; LPDIRECTSOUNDBUFFER pDSBuf, pDSPBuf; @@ -79,16 +84,13 @@ S_BlockSound */ void S_BlockSound (void) { - -// DirectSound takes care of blocking itself - if (snd_iswave) + // DirectSound takes care of blocking itself + if (wav_init) { snd_blocked++; if (snd_blocked == 1) - { waveOutReset (hWaveOut); - } } } @@ -100,12 +102,9 @@ S_UnblockSound */ void S_UnblockSound (void) { - -// DirectSound takes care of blocking itself - if (snd_iswave) - { + // DirectSound takes care of blocking itself + if (wav_init) snd_blocked--; - } } @@ -124,7 +123,7 @@ void FreeSound (void) pDSBuf->lpVtbl->Release(pDSBuf); } -// only release primary buffer if it's not also the mixing buffer we just released + // only release primary buffer if it's not also the mixing buffer we just released if (pDSPBuf && (pDSBuf != pDSPBuf)) { pDSPBuf->lpVtbl->Release(pDSPBuf); @@ -186,7 +185,7 @@ sndinitstat SNDDMA_InitDirect (void) { DSBUFFERDESC dsbuf; DSBCAPS dsbcaps; - DWORD dwSize, dwWrite; + DWORD dwSize; DSCAPS dscaps; WAVEFORMATEX format, pformat; HRESULT hresult; @@ -196,7 +195,8 @@ sndinitstat SNDDMA_InitDirect (void) memset((void *)shm, 0, sizeof(*shm)); shm->format.channels = 2; shm->format.width = 2; - i = COM_CheckParm ("-sndspeed"); // LordHavoc: -sndspeed option +// COMMANDLINEOPTION: Windows Sound: -sndspeed chooses 44100 hz, 22100 hz, or 11025 hz sound output rate + i = COM_CheckParm ("-sndspeed"); if (i && i != (com_argc - 1)) shm->format.speed = atoi(com_argv[i+1]); else @@ -217,7 +217,7 @@ sndinitstat SNDDMA_InitDirect (void) if (hInstDS == NULL) { - Con_SafePrint("Couldn't load dsound.dll\n"); + Con_Print("Couldn't load dsound.dll\n"); return SIS_FAILURE; } @@ -225,7 +225,7 @@ sndinitstat SNDDMA_InitDirect (void) if (!pDirectSoundCreate) { - Con_SafePrint("Couldn't get DS proc addr\n"); + Con_Print("Couldn't get DS proc addr\n"); return SIS_FAILURE; } } @@ -234,7 +234,7 @@ sndinitstat SNDDMA_InitDirect (void) { if (hresult != DSERR_ALLOCATED) { - Con_SafePrint("DirectSound create failed\n"); + Con_Print("DirectSound create failed\n"); return SIS_FAILURE; } @@ -244,7 +244,7 @@ sndinitstat SNDDMA_InitDirect (void) "Sound not available", MB_RETRYCANCEL | MB_SETFOREGROUND | MB_ICONEXCLAMATION) != IDRETRY) { - Con_SafePrint("DirectSoundCreate failure\n hardware already in use\n"); + Con_Print("DirectSoundCreate failure\n hardware already in use\n"); return SIS_NOTAVAIL; } } @@ -253,25 +253,25 @@ sndinitstat SNDDMA_InitDirect (void) if (DS_OK != pDS->lpVtbl->GetCaps (pDS, &dscaps)) { - Con_SafePrint("Couldn't get DS caps\n"); + Con_Print("Couldn't get DS caps\n"); } if (dscaps.dwFlags & DSCAPS_EMULDRIVER) { - Con_SafePrint("No DirectSound driver installed\n"); + Con_Print("No DirectSound driver installed\n"); FreeSound (); return SIS_FAILURE; } if (DS_OK != pDS->lpVtbl->SetCooperativeLevel (pDS, mainwindow, DSSCL_EXCLUSIVE)) { - Con_SafePrint("Set coop level failed\n"); + Con_Print("Set coop level failed\n"); FreeSound (); 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; @@ -282,6 +282,7 @@ 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)) @@ -290,22 +291,21 @@ sndinitstat SNDDMA_InitDirect (void) if (DS_OK != pDSPBuf->lpVtbl->SetFormat (pDSPBuf, &pformat)) { - if (snd_firsttime) - Con_SafePrint("Set primary sound buffer format: no\n"); + Con_Print("Set primary sound buffer format: no\n"); } else { - if (snd_firsttime) - Con_SafePrint("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 + // create the secondary buffer we'll actually work with memset (&dsbuf, 0, sizeof(dsbuf)); dsbuf.dwSize = sizeof(DSBUFFERDESC); dsbuf.dwFlags = DSBCAPS_CTRLFREQUENCY | DSBCAPS_LOCSOFTWARE; @@ -317,7 +317,7 @@ sndinitstat SNDDMA_InitDirect (void) if (DS_OK != pDS->lpVtbl->CreateSoundBuffer(pDS, &dsbuf, &pDSBuf, NULL)) { - Con_SafePrint("DS:CreateSoundBuffer Failed\n"); + Con_Print("DS:CreateSoundBuffer Failed\n"); FreeSound (); return SIS_FAILURE; } @@ -328,19 +328,18 @@ sndinitstat SNDDMA_InitDirect (void) if (DS_OK != pDSBuf->lpVtbl->GetCaps (pDSBuf, &dsbcaps)) { - Con_SafePrint("DS:GetCaps failed\n"); + Con_Print("DS:GetCaps failed\n"); FreeSound (); return SIS_FAILURE; } - if (snd_firsttime) - Con_SafePrint("Using secondary sound buffer\n"); + Con_Print("Using secondary sound buffer\n"); } else { if (DS_OK != pDS->lpVtbl->SetCooperativeLevel (pDS, mainwindow, DSSCL_WRITEPRIMARY)) { - Con_SafePrint("Set coop level failed\n"); + Con_Print("Set coop level failed\n"); FreeSound (); return SIS_FAILURE; } @@ -352,35 +351,34 @@ sndinitstat SNDDMA_InitDirect (void) } pDSBuf = pDSPBuf; - Con_SafePrint("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); - if (snd_firsttime) - Con_SafePrintf(" %d channel(s)\n" - " %d bits/sample\n" - " %d samples/sec\n", - shm->format.channels, shm->format.width * 8, shm->format.speed); + Con_Printf(" %d channel(s)\n" + " %d bits/sample\n" + " %d samples/sec\n", + shm->format.channels, shm->format.width * 8, shm->format.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) { if (hresult != DSERR_BUFFERLOST) { - Con_SafePrint("SNDDMA_InitDirect: DS::Lock Sound Buffer Failed\n"); + Con_Print("SNDDMA_InitDirect: DS::Lock Sound Buffer Failed\n"); FreeSound (); return SIS_FAILURE; } if (++reps > 10000) { - Con_SafePrint("SNDDMA_InitDirect: DS: couldn't restore buffer\n"); + Con_Print("SNDDMA_InitDirect: DS: couldn't restore buffer\n"); FreeSound (); return SIS_FAILURE; } @@ -391,17 +389,16 @@ sndinitstat SNDDMA_InitDirect (void) pDSBuf->lpVtbl->Unlock(pDSBuf, lpData, dwSize, NULL, 0); - /* we don't want anyone to access the buffer directly w/o locking it first. */ + // 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->GetCurrentPosition(pDSBuf, &dwStartTime, NULL); pDSBuf->lpVtbl->Play(pDSBuf, 0, 0, DSBPLAY_LOOPING); shm->samples = gSndBufSize / shm->format.width; shm->samplepos = 0; shm->buffer = (unsigned char *) lpData; - sample16 = shm->format.width - 1; dsound_init = true; @@ -428,7 +425,8 @@ qboolean SNDDMA_InitWav (void) memset((void *)shm, 0, sizeof(*shm)); shm->format.channels = 2; shm->format.width = 2; - i = COM_CheckParm ("-sndspeed"); // LordHavoc: -sndspeed option +// COMMANDLINEOPTION: Windows Sound: -sndspeed chooses 44100 hz, 22100 hz, or 11025 hz sound output rate + i = COM_CheckParm ("-sndspeed"); if (i && i != (com_argc - 1)) shm->format.speed = atoi(com_argv[i+1]); else @@ -439,20 +437,18 @@ qboolean SNDDMA_InitWav (void) format.nChannels = shm->format.channels; format.wBitsPerSample = shm->format.width * 8; format.nSamplesPerSec = shm->format.speed; - format.nBlockAlign = format.nChannels - *format.wBitsPerSample / 8; + format.nBlockAlign = format.nChannels * format.wBitsPerSample / 8; format.cbSize = 0; - format.nAvgBytesPerSec = format.nSamplesPerSec - *format.nBlockAlign; + format.nAvgBytesPerSec = format.nSamplesPerSec * format.nBlockAlign; - /* Open a waveform device for output using window callback. */ + // Open a waveform device for output using window callback while ((hr = waveOutOpen((LPHWAVEOUT)&hWaveOut, WAVE_MAPPER, &format, 0, 0L, CALLBACK_NULL)) != MMSYSERR_NOERROR) { if (hr != MMSYSERR_ALLOCATED) { - Con_SafePrint("waveOutOpen failed\n"); + Con_Print("waveOutOpen failed\n"); return false; } @@ -462,7 +458,7 @@ qboolean SNDDMA_InitWav (void) "Sound not available", MB_RETRYCANCEL | MB_SETFOREGROUND | MB_ICONEXCLAMATION) != IDRETRY) { - Con_SafePrint("waveOutOpen failure;\n hardware already in use\n"); + Con_Print("waveOutOpen failure;\n hardware already in use\n"); return false; } } @@ -471,20 +467,19 @@ qboolean SNDDMA_InitWav (void) * 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; hData = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, gSndBufSize); if (!hData) { - Con_SafePrint("Sound: Out of memory.\n"); + Con_Print("Sound: Out of memory.\n"); FreeSound (); return false; } lpData = GlobalLock(hData); if (!lpData) { - Con_SafePrint("Sound: Failed to lock.\n"); + Con_Print("Sound: Failed to lock.\n"); FreeSound (); return false; } @@ -500,7 +495,7 @@ qboolean SNDDMA_InitWav (void) if (hWaveHdr == NULL) { - Con_SafePrint("Sound: Failed to Alloc header.\n"); + Con_Print("Sound: Failed to Alloc header.\n"); FreeSound (); return false; } @@ -509,14 +504,14 @@ qboolean SNDDMA_InitWav (void) if (lpWaveHdr == NULL) { - Con_SafePrint("Sound: Failed to lock header.\n"); + Con_Print("Sound: Failed to lock header.\n"); FreeSound (); 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->format.width; shm->samplepos = 0; shm->buffer = (unsigned char *) lpData; - sample16 = shm->format.width - 1; + + prev_painted = 0; + paintpot = 0; wav_init = true; @@ -549,69 +546,46 @@ Try to find a sound device to mix for. Returns false if nothing is found. ================== */ - qboolean SNDDMA_Init(void) { sndinitstat stat; +// COMMANDLINEOPTION: Windows Sound: -wavonly uses wave sound instead of DirectSound if (COM_CheckParm ("-wavonly")) wavonly = true; - dsound_init = wav_init = 0; + dsound_init = false; + wav_init = false; stat = SIS_FAILURE; // assume DirectSound won't initialize - /* Init DirectSound */ + // Init DirectSound if (!wavonly) { - if (snd_firsttime || snd_isdirect) - { - stat = SNDDMA_InitDirect (); + stat = SNDDMA_InitDirect (); - if (stat == SIS_SUCCESS) - { - snd_isdirect = true; - - if (snd_firsttime) - Con_SafePrint("DirectSound initialized\n"); - } - else - { - snd_isdirect = false; - Con_SafePrint("DirectSound failed to init\n"); - } - } + if (stat == SIS_SUCCESS) + Con_Print("DirectSound initialized\n"); + else + Con_Print("DirectSound failed to init\n"); } -// 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) if (!dsound_init && (stat != SIS_NOTAVAIL)) { - if (snd_firsttime || snd_iswave) - { - - snd_iswave = SNDDMA_InitWav (); - - if (snd_iswave) - { - if (snd_firsttime) - Con_SafePrint("Wave sound initialized\n"); - } - else - { - Con_SafePrint("Wave sound failed to init\n"); - } - } + if (SNDDMA_InitWav ()) + Con_Print("Wave sound initialized\n"); + else + Con_Print("Wave sound failed to init\n"); } - snd_firsttime = false; - if (!dsound_init && !wav_init) - return 0; + return false; - return 1; + return true; } /* @@ -625,29 +599,36 @@ how many sample are required to fill it up. */ int SNDDMA_GetDMAPos(void) { - MMTIME mmtime; - int s; - DWORD dwWrite; + DWORD dwTime, s; if (dsound_init) { - mmtime.wType = TIME_SAMPLES; - pDSBuf->lpVtbl->GetCurrentPosition(pDSBuf, &mmtime.u.sample, &dwWrite); - s = mmtime.u.sample - mmstarttime.u.sample; + pDSBuf->lpVtbl->GetCurrentPosition(pDSBuf, &dwTime, NULL); + s = dwTime - dwStartTime; } else if (wav_init) { - s = snd_sent * WAV_BUFFER_SIZE; - } - else - s = 0; + // 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; - s >>= sample16; + snd_completed++; // this buffer has been played + } - s &= (shm->samples-1); + s = snd_completed * WAV_BUFFER_SIZE; + } + else + return 0; - return s; + return (s >> (shm->format.width - 1)) & (shm->samples - 1); } /* @@ -662,34 +643,19 @@ void SNDDMA_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_DPrint("Sound overrun\n"); - break; - } - - if ( ! (lpWaveHdr[ snd_completed & WAV_MASK].dwFlags & WHDR_DONE) ) - { - break; - } + paintpot += (paintedtime - prev_painted) * shm->format.channels * shm->format.width; + if (paintpot > WAV_BUFFERS * WAV_BUFFER_SIZE) + paintpot = WAV_BUFFERS * WAV_BUFFER_SIZE; + prev_painted = paintedtime; - snd_completed++; // this buffer has been played - } - - // - // 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++; /* @@ -701,10 +667,12 @@ void SNDDMA_Submit(void) if (wResult != MMSYSERR_NOERROR) { - Con_SafePrint("Failed to write block to device\n"); + Con_Print("Failed to write block to device\n"); FreeSound (); return; } + + paintpot -= WAV_BUFFER_SIZE; } } @@ -720,24 +688,37 @@ void SNDDMA_Shutdown(void) FreeSound (); } -DWORD dsound_dwSize; -DWORD dsound_dwSize2; -DWORD *dsound_pbuf; -DWORD *dsound_pbuf2; + +static DWORD dsound_dwSize; +static DWORD dsound_dwSize2; +static DWORD *dsound_pbuf; +static DWORD *dsound_pbuf2; + void *S_LockBuffer(void) { int reps; HRESULT hresult; + DWORD dwStatus; if (pDSBuf) { + // if the buffer was lost or stopped, restore it and/or restart it + if (pDSBuf->lpVtbl->GetStatus (pDSBuf, &dwStatus) != DS_OK) + Con_Print("Couldn't get sound buffer status\n"); + + if (dwStatus & DSBSTATUS_BUFFERLOST) + pDSBuf->lpVtbl->Restore (pDSBuf); + + if (!(dwStatus & DSBSTATUS_PLAYING)) + pDSBuf->lpVtbl->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) { if (hresult != DSERR_BUFFERLOST) { - Con_Print("S_LockBuffer: DS::Lock Sound Buffer Failed\n"); + Con_Print("S_LockBuffer: DS: Lock Sound Buffer Failed\n"); S_Shutdown (); S_Startup (); return NULL; @@ -753,8 +734,10 @@ void *S_LockBuffer(void) } return dsound_pbuf; } - else + else if (wav_init) return shm->buffer; + else + return NULL; } void S_UnlockBuffer(void)