X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fdarkplaces.git;a=blobdiff_plain;f=snd_win.c;h=080122487a821d438a0e25eaad3070e4139294f0;hp=89b333d54b2c18b2e75baf6428e919eca4bea007;hb=445a1ceeb50d479a4799df83e6d653e9a4470b95;hpb=da29a8beeb35293e2fd38b51883c91b5cf4cf4ad diff --git a/snd_win.c b/snd_win.c index 89b333d5..08012248 100644 --- a/snd_win.c +++ b/snd_win.c @@ -17,41 +17,105 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#include "quakedef.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 + +#include "qtypes.h" +#include "quakedef.h" +#include "snd_main.h" + +// ============================================================================== + +#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 + } +}; + + +// ============================================================================== extern HWND mainwindow; +static cvar_t snd_wav_partitionsize = {CVAR_SAVE, "snd_wav_partitionsize", "1024", "controls sound delay in samples, values too low will cause crackling, too high will cause delayed sounds"}; +static qboolean sndsys_registeredcvars = false; +#ifdef SUPPORTDIRECTX HRESULT (WINAPI *pDirectSoundCreate)(GUID FAR *lpGUID, LPDIRECTSOUND FAR *lplpDS, IUnknown FAR *pUnkOuter); +#endif -// 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 (WAV_BUFFERS - 1) -#define WAV_BUFFER_SIZE 1024 +// Wave output: queue of this many sound buffers to play, reused cyclically +#define WAV_BUFFERS 16 +#define WAV_MASK (WAV_BUFFERS - 1) +static unsigned int wav_buffer_size; // DirectSound output: 64KB in 1 buffer -#define SECONDARY_BUFFER_SIZE (64 * 1024) +//#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 sndinitstat_e {SIS_SUCCESS, SIS_FAILURE, SIS_NOTAVAIL} sndinitstat; +#ifdef SUPPORTDIRECTX static qboolean dsound_init; -static qboolean wav_init; +static unsigned int dsound_time; static qboolean primary_format_set; +#endif + +static qboolean wav_init; static int snd_sent, snd_completed; static int prev_painted; static unsigned int paintpot; -static unsigned int dsound_time; /* @@ -73,15 +137,79 @@ DWORD gSndBufSize; DWORD dwStartTime; +#ifdef SUPPORTDIRECTX LPDIRECTSOUND pDS; LPDIRECTSOUNDBUFFER pDSBuf, pDSPBuf; HINSTANCE hInstDS; +#endif qboolean SNDDMA_InitWav (void); +#ifdef SUPPORTDIRECTX sndinitstat SNDDMA_InitDirect (void); +#endif + + +/* +================== +SndSys_BuildWaveFormat +================== +*/ +static qboolean SndSys_BuildWaveFormat (const snd_format_t* requested, WAVEFORMATEXTENSIBLE* fmt_ptr) +{ + WAVEFORMATEX* pfmtex; + + 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; + + // LordHavoc: disabled this WAVE_FORMAT_EXTENSIBLE support because it does not seem to be working +#if 0 + if (requested->channels <= 2) + { +#endif + pfmtex->wFormatTag = WAVE_FORMAT_PCM; + pfmtex->cbSize = 0; +#if 0 + } + else + { + 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) + { + 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; + } + } +#endif + + return true; +} +#ifdef SUPPORTDIRECTX /* ================== SndSys_InitDirectSound @@ -89,24 +217,18 @@ SndSys_InitDirectSound DirectSound 5 support ================== */ -static sndinitstat SndSys_InitDirectSound (const snd_format_t* requested, snd_format_t* suggested) +static sndinitstat SndSys_InitDirectSound (const snd_format_t* requested) { - DSBUFFERDESC dsbuf; - DSBCAPS dsbcaps; - DWORD dwSize; - DSCAPS dscaps; - WAVEFORMATEX format, pformat; - HRESULT hresult; - int reps; - - memset (&format, 0, sizeof(format)); - format.wFormatTag = WAVE_FORMAT_PCM; - format.nChannels = requested->channels; - format.wBitsPerSample = requested->width * 8; - format.nSamplesPerSec = requested->speed; - format.nBlockAlign = format.nChannels * format.wBitsPerSample / 8; - format.nAvgBytesPerSec = format.nSamplesPerSec * format.nBlockAlign; - format.cbSize = 0; + 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) { @@ -118,7 +240,7 @@ static sndinitstat SndSys_InitDirectSound (const snd_format_t* requested, snd_fo return SIS_FAILURE; } - pDirectSoundCreate = (void *)GetProcAddress(hInstDS,"DirectSoundCreate"); + pDirectSoundCreate = (HRESULT (__stdcall *)(GUID *, LPDIRECTSOUND *,IUnknown *))GetProcAddress(hInstDS,"DirectSoundCreate"); if (!pDirectSoundCreate) { @@ -186,7 +308,7 @@ static sndinitstat SndSys_InitDirectSound (const snd_format_t* requested, snd_fo { pformat = format; - if (DS_OK != IDirectSoundBuffer_SetFormat (pDSPBuf, &pformat)) + if (DS_OK != IDirectSoundBuffer_SetFormat (pDSPBuf, (WAVEFORMATEX*)&pformat)) { Con_Print("Set primary sound buffer format: no\n"); } @@ -208,20 +330,20 @@ static sndinitstat SndSys_InitDirectSound (const snd_format_t* requested, snd_fo 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); result = IDirectSound_CreateSoundBuffer(pDS, &dsbuf, &pDSBuf, NULL); if (result != DS_OK || - requested->channels != format.nChannels || - requested->width != format.wBitsPerSample / 8 || - requested->speed != format.nSamplesPerSec) + requested->channels != format.Format.nChannels || + requested->width != format.Format.wBitsPerSample / 8 || + requested->speed != format.Format.nSamplesPerSec) { Con_Printf("DS:CreateSoundBuffer Failed (%d): channels=%u, width=%u, speed=%u\n", - result, format.nChannels, format.wBitsPerSample / 8, format.nSamplesPerSec); + (int)result, (unsigned)format.Format.nChannels, (unsigned)format.Format.wBitsPerSample / 8, (unsigned)format.Format.nSamplesPerSec); SndSys_Shutdown (); return SIS_FAILURE; } @@ -257,7 +379,7 @@ static sndinitstat SndSys_InitDirectSound (const snd_format_t* requested, snd_fo // Make sure mixer is active IDirectSoundBuffer_Play(pDSBuf, 0, 0, DSBPLAY_LOOPING); - Con_DPrintf(" %d channel(s)\n" + Con_Printf(" %d channel(s)\n" " %d bits/sample\n" " %d samples/sec\n", requested->channels, requested->width * 8, requested->speed); @@ -299,6 +421,7 @@ static sndinitstat SndSys_InitDirectSound (const snd_format_t* requested, snd_fo return SIS_SUCCESS; } +#endif /* @@ -308,24 +431,17 @@ SndSys_InitMmsystem Crappy windows multimedia base ================== */ -static qboolean SndSys_InitMmsystem (const snd_format_t* requested, snd_format_t* suggested) +static qboolean SndSys_InitMmsystem (const snd_format_t* requested) { - WAVEFORMATEX format; + WAVEFORMATEXTENSIBLE format; int i; HRESULT hr; - memset (&format, 0, sizeof(format)); - format.wFormatTag = WAVE_FORMAT_PCM; - format.nChannels = requested->channels; - format.wBitsPerSample = requested->width * 8; - format.nSamplesPerSec = requested->speed; - format.nBlockAlign = format.nChannels * format.wBitsPerSample / 8; - format.nAvgBytesPerSec = format.nSamplesPerSec * format.nBlockAlign; - format.cbSize = 0; + if (! SndSys_BuildWaveFormat(requested, &format)) + return false; // Open a waveform device for output using window callback - while ((hr = waveOutOpen((LPHWAVEOUT)&hWaveOut, WAVE_MAPPER, - &format, + while ((hr = waveOutOpen((LPHWAVEOUT)&hWaveOut, WAVE_MAPPER, (WAVEFORMATEX*)&format, 0, 0L, CALLBACK_NULL)) != MMSYSERR_NOERROR) { if (hr != MMSYSERR_ALLOCATED) @@ -345,12 +461,14 @@ static qboolean SndSys_InitMmsystem (const snd_format_t* requested, snd_format_t } } + wav_buffer_size = bound(128, snd_wav_partitionsize.integer, 8192) * 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) { @@ -358,7 +476,7 @@ static qboolean SndSys_InitMmsystem (const snd_format_t* requested, snd_format_t SndSys_Shutdown (); return false; } - lpData = GlobalLock(hData); + lpData = (HPSTR)GlobalLock(hData); if (!lpData) { Con_Print("Sound: Failed to lock.\n"); @@ -372,8 +490,7 @@ static qboolean SndSys_InitMmsystem (const snd_format_t* requested, snd_format_t * 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) { @@ -396,11 +513,10 @@ static qboolean SndSys_InitMmsystem (const snd_format_t* requested, snd_format_t // After allocation, set up and prepare headers for (i=0 ; iendframe - prev_painted) * snd_renderbuffer->format.channels * snd_renderbuffer->format.width; - if (paintpot > WAV_BUFFERS * WAV_BUFFER_SIZE) - paintpot = WAV_BUFFERS * WAV_BUFFER_SIZE; + if (paintpot > WAV_BUFFERS * wav_buffer_size) + paintpot = WAV_BUFFERS * wav_buffer_size; prev_painted = snd_renderbuffer->endframe; // submit new sound blocks - while (paintpot > WAV_BUFFER_SIZE) + while (paintpot > wav_buffer_size) { 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_insane.integer) + Con_DPrint("waveOutWrite failed (too much sound data)\n"); + //h->dwFlags |= WHDR_DONE; + //snd_sent++; + } + else { - Con_Print("Failed to write block to device\n"); + Con_Printf("waveOutWrite failed, error code %d\n", (int) wResult); SndSys_Shutdown (); return; } - paintpot -= WAV_BUFFER_SIZE; + paintpot -= wav_buffer_size; } } @@ -600,19 +745,24 @@ Returns the number of sample frames consumed since the sound started */ unsigned int SndSys_GetSoundTime (void) { - unsigned int s; + 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); - s = (dwTime - dwStartTime) & (gSndBufSize - 1); + diff = (unsigned int)(dwTime - dwStartTime) % (unsigned int)gSndBufSize; dwStartTime = dwTime; - dsound_time += s / (snd_renderbuffer->format.width * snd_renderbuffer->format.channels); + dsound_time += diff / factor; return dsound_time; } +#endif if (wav_init) { @@ -621,7 +771,7 @@ unsigned int SndSys_GetSoundTime (void) { if (snd_completed == snd_sent) { - Con_DPrint("Sound overrun\n"); + // Con_DPrint("Sound overrun\n"); break; } @@ -631,19 +781,33 @@ unsigned int SndSys_GetSoundTime (void) snd_completed++; // this buffer has been played } - s = snd_completed * WAV_BUFFER_SIZE; + 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; - return s / (snd_renderbuffer->format.width * snd_renderbuffer->format.channels); + mmtime.wType = TIME_SAMPLES; + res = waveOutGetPosition(hWaveOut, &mmtime, sizeof(mmtime)); + if(res == MMSYSERR_NOERROR) + return mmtime.u.sample; + } + */ } return 0; } +#ifdef SUPPORTDIRECTX static DWORD dsound_dwSize; static DWORD dsound_dwSize2; static DWORD *dsound_pbuf; static DWORD *dsound_pbuf2; +#endif /* ==================== @@ -654,6 +818,7 @@ Get the exclusive lock on "snd_renderbuffer" */ qboolean SndSys_LockRenderBuffer (void) { +#ifdef SUPPORTDIRECTX int reps; HRESULT hresult; DWORD dwStatus; @@ -698,6 +863,7 @@ qboolean SndSys_LockRenderBuffer (void) Sys_Error("SndSys_LockRenderBuffer: the ring address has changed!!!\n"); return true; } +#endif return wav_init; } @@ -712,6 +878,20 @@ Release the exclusive lock on "snd_renderbuffer" */ void SndSys_UnlockRenderBuffer (void) { +#ifdef SUPPORTDIRECTX if (pDSBuf) IDirectSoundBuffer_Unlock(pDSBuf, dsound_pbuf, dsound_dwSize, dsound_pbuf2, dsound_dwSize2); +#endif +} + +/* +==================== +SndSys_SendKeyEvents + +Send keyboard events originating from the sound system (e.g. MIDI) +==================== +*/ +void SndSys_SendKeyEvents(void) +{ + // not supported }