X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fdarkplaces.git;a=blobdiff_plain;f=snd_win.c;h=8197b256342316136c3ae4017d2eb8347bc279c8;hp=d031645b26f7b7feb3eb65c8bf4a76e6e3de01e3;hb=ac947d2fbb445473c266390a1fca26c8be8611c4;hpb=d50445e9045ddea0d49857346597c57c129029e0 diff --git a/snd_win.c b/snd_win.c index d031645b..8197b256 100644 --- a/snd_win.c +++ b/snd_win.c @@ -28,11 +28,14 @@ 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 + +// DirectSound output: 64KB in 1 buffer +#define SECONDARY_BUFFER_SIZE (64 * 1024) typedef enum {SIS_SUCCESS, SIS_FAILURE, SIS_NOTAVAIL} sndinitstat; @@ -42,9 +45,11 @@ 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 @@ -63,7 +68,7 @@ WAVEOUTCAPS wavecaps; DWORD gSndBufSize; -MMTIME mmstarttime; +DWORD dwStartTime; LPDIRECTSOUND pDS; LPDIRECTSOUNDBUFFER pDSBuf, pDSPBuf; @@ -80,16 +85,13 @@ S_BlockSound */ void S_BlockSound (void) { - -// DirectSound takes care of blocking itself + // DirectSound takes care of blocking itself if (snd_iswave) { snd_blocked++; if (snd_blocked == 1) - { waveOutReset (hWaveOut); - } } } @@ -101,12 +103,9 @@ S_UnblockSound */ void S_UnblockSound (void) { - -// DirectSound takes care of blocking itself + // DirectSound takes care of blocking itself if (snd_iswave) - { snd_blocked--; - } } @@ -125,7 +124,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); @@ -187,7 +186,7 @@ sndinitstat SNDDMA_InitDirect (void) { DSBUFFERDESC dsbuf; DSBCAPS dsbcaps; - DWORD dwSize, dwWrite; + DWORD dwSize; DSCAPS dscaps; WAVEFORMATEX format, pformat; HRESULT hresult; @@ -219,7 +218,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; } @@ -227,7 +226,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; } } @@ -236,7 +235,7 @@ sndinitstat SNDDMA_InitDirect (void) { if (hresult != DSERR_ALLOCATED) { - Con_SafePrint("DirectSound create failed\n"); + Con_Print("DirectSound create failed\n"); return SIS_FAILURE; } @@ -246,7 +245,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; } } @@ -255,25 +254,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; @@ -294,12 +293,12 @@ 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; } @@ -309,7 +308,7 @@ sndinitstat SNDDMA_InitDirect (void) // 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; @@ -321,7 +320,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; } @@ -332,19 +331,19 @@ 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; } @@ -356,35 +355,35 @@ 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" + 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; } @@ -395,17 +394,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; @@ -433,7 +431,7 @@ qboolean SNDDMA_InitWav (void) shm->format.channels = 2; shm->format.width = 2; // COMMANDLINEOPTION: Windows Sound: -sndspeed chooses 44100 hz, 22100 hz, or 11025 hz sound output rate - i = COM_CheckParm ("-sndspeed"); // LordHavoc: -sndspeed option + i = COM_CheckParm ("-sndspeed"); if (i && i != (com_argc - 1)) shm->format.speed = atoi(com_argv[i+1]); else @@ -444,20 +442,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; } @@ -467,7 +463,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; } } @@ -476,20 +472,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; } @@ -505,7 +500,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; } @@ -514,14 +509,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; @@ -554,7 +551,6 @@ Try to find a sound device to mix for. Returns false if nothing is found. ================== */ - qboolean SNDDMA_Init(void) { sndinitstat stat; @@ -567,7 +563,7 @@ qboolean SNDDMA_Init(void) stat = SIS_FAILURE; // assume DirectSound won't initialize - /* Init DirectSound */ + // Init DirectSound if (!wavonly) { if (snd_firsttime || snd_isdirect) @@ -579,20 +575,20 @@ qboolean SNDDMA_Init(void) snd_isdirect = true; if (snd_firsttime) - Con_SafePrint("DirectSound initialized\n"); + Con_Print("DirectSound initialized\n"); } else { snd_isdirect = false; - Con_SafePrint("DirectSound failed to init\n"); + 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) @@ -603,11 +599,11 @@ qboolean SNDDMA_Init(void) if (snd_iswave) { if (snd_firsttime) - Con_SafePrint("Wave sound initialized\n"); + Con_Print("Wave sound initialized\n"); } else { - Con_SafePrint("Wave sound failed to init\n"); + Con_Print("Wave sound failed to init\n"); } } } @@ -631,29 +627,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); } /* @@ -668,34 +671,17 @@ 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; - } + paintpot += (paintedtime - prev_painted) * shm->format.channels * shm->format.width; + prev_painted = paintedtime; - if ( ! (lpWaveHdr[ snd_completed & WAV_MASK].dwFlags & WHDR_DONE) ) - { - break; - } - - 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++; /* @@ -707,10 +693,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; } } @@ -734,16 +722,27 @@ 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;