📄 snd_win.c
字号:
return SIS_SUCCESS;
}
/*
==================
SNDDM_InitWav
Crappy windows multimedia base
==================
*/
qboolean SNDDMA_InitWav (void)
{
WAVEFORMATEX format;
int i;
HRESULT hr;
Com_Printf( "Initializing wave sound\n" );
snd_sent = 0;
snd_completed = 0;
dma.channels = 2;
dma.samplebits = 16;
if (s_khz->value == 44)
dma.speed = 44100;
if (s_khz->value == 22)
dma.speed = 22050;
else
dma.speed = 11025;
memset (&format, 0, sizeof(format));
format.wFormatTag = WAVE_FORMAT_PCM;
format.nChannels = dma.channels;
format.wBitsPerSample = dma.samplebits;
format.nSamplesPerSec = dma.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. */
Com_DPrintf ("...opening waveform device: ");
while ((hr = waveOutOpen((LPHWAVEOUT)&hWaveOut, WAVE_MAPPER,
&format,
0, 0L, CALLBACK_NULL)) != MMSYSERR_NOERROR)
{
if (hr != MMSYSERR_ALLOCATED)
{
Com_Printf ("failed\n");
return false;
}
if (MessageBox (NULL,
"The sound hardware is in use by another app.\n\n"
"Select Retry to try to start sound again or Cancel to run Quake 2 with no sound.",
"Sound not available",
MB_RETRYCANCEL | MB_SETFOREGROUND | MB_ICONEXCLAMATION) != IDRETRY)
{
Com_Printf ("hw in use\n" );
return false;
}
}
Com_DPrintf( "ok\n" );
/*
* Allocate and lock memory for the waveform data. The memory
* for waveform data must be globally allocated with
* GMEM_MOVEABLE and GMEM_SHARE flags.
*/
Com_DPrintf ("...allocating waveform buffer: ");
gSndBufSize = WAV_BUFFERS*WAV_BUFFER_SIZE;
hData = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, gSndBufSize);
if (!hData)
{
Com_Printf( " failed\n" );
FreeSound ();
return false;
}
Com_DPrintf( "ok\n" );
Com_DPrintf ("...locking waveform buffer: ");
lpData = GlobalLock(hData);
if (!lpData)
{
Com_Printf( " failed\n" );
FreeSound ();
return false;
}
memset (lpData, 0, gSndBufSize);
Com_DPrintf( "ok\n" );
/*
* Allocate and lock memory for the header. This memory must
* also be globally allocated with GMEM_MOVEABLE and
* GMEM_SHARE flags.
*/
Com_DPrintf ("...allocating waveform header: ");
hWaveHdr = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE,
(DWORD) sizeof(WAVEHDR) * WAV_BUFFERS);
if (hWaveHdr == NULL)
{
Com_Printf( "failed\n" );
FreeSound ();
return false;
}
Com_DPrintf( "ok\n" );
Com_DPrintf ("...locking waveform header: ");
lpWaveHdr = (LPWAVEHDR) GlobalLock(hWaveHdr);
if (lpWaveHdr == NULL)
{
Com_Printf( "failed\n" );
FreeSound ();
return false;
}
memset (lpWaveHdr, 0, sizeof(WAVEHDR) * WAV_BUFFERS);
Com_DPrintf( "ok\n" );
/* After allocation, set up and prepare headers. */
Com_DPrintf ("...preparing headers: ");
for (i=0 ; i<WAV_BUFFERS ; i++)
{
lpWaveHdr[i].dwBufferLength = WAV_BUFFER_SIZE;
lpWaveHdr[i].lpData = lpData + i*WAV_BUFFER_SIZE;
if (waveOutPrepareHeader(hWaveOut, lpWaveHdr+i, sizeof(WAVEHDR)) !=
MMSYSERR_NOERROR)
{
Com_Printf ("failed\n");
FreeSound ();
return false;
}
}
Com_DPrintf ("ok\n");
dma.samples = gSndBufSize/(dma.samplebits/8);
dma.samplepos = 0;
dma.submission_chunk = 512;
dma.buffer = (unsigned char *) lpData;
sample16 = (dma.samplebits/8) - 1;
wav_init = true;
return true;
}
/*
==================
SNDDMA_Init
Try to find a sound device to mix for.
Returns false if nothing is found.
==================
*/
int SNDDMA_Init(void)
{
sndinitstat stat;
memset ((void *)&dma, 0, sizeof (dma));
s_wavonly = Cvar_Get ("s_wavonly", "0", 0);
dsound_init = wav_init = 0;
stat = SIS_FAILURE; // assume DirectSound won't initialize
/* Init DirectSound */
if (!s_wavonly->value)
{
if (snd_firsttime || snd_isdirect)
{
stat = SNDDMA_InitDirect ();
if (stat == SIS_SUCCESS)
{
snd_isdirect = true;
if (snd_firsttime)
Com_Printf ("dsound init succeeded\n" );
}
else
{
snd_isdirect = false;
Com_Printf ("*** dsound init failed ***\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 (!dsound_init && (stat != SIS_NOTAVAIL))
{
if (snd_firsttime || snd_iswave)
{
snd_iswave = SNDDMA_InitWav ();
if (snd_iswave)
{
if (snd_firsttime)
Com_Printf ("Wave sound init succeeded\n");
}
else
{
Com_Printf ("Wave sound init failed\n");
}
}
}
snd_firsttime = false;
snd_buffer_count = 1;
if (!dsound_init && !wav_init)
{
if (snd_firsttime)
Com_Printf ("*** No sound device initialized ***\n");
return 0;
}
return 1;
}
/*
==============
SNDDMA_GetDMAPos
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.
===============
*/
int SNDDMA_GetDMAPos(void)
{
MMTIME mmtime;
int s;
DWORD dwWrite;
if (dsound_init)
{
mmtime.wType = TIME_SAMPLES;
pDSBuf->lpVtbl->GetCurrentPosition(pDSBuf, &mmtime.u.sample, &dwWrite);
s = mmtime.u.sample - mmstarttime.u.sample;
}
else if (wav_init)
{
s = snd_sent * WAV_BUFFER_SIZE;
}
s >>= sample16;
s &= (dma.samples-1);
return s;
}
/*
==============
SNDDMA_BeginPainting
Makes sure dma.buffer is valid
===============
*/
DWORD locksize;
void SNDDMA_BeginPainting (void)
{
int reps;
DWORD dwSize2;
DWORD *pbuf, *pbuf2;
HRESULT hresult;
DWORD dwStatus;
if (!pDSBuf)
return;
// if the buffer was lost or stopped, restore it and/or restart it
if (pDSBuf->lpVtbl->GetStatus (pDSBuf, &dwStatus) != DS_OK)
Com_Printf ("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);
// lock the dsound buffer
reps = 0;
dma.buffer = NULL;
while ((hresult = pDSBuf->lpVtbl->Lock(pDSBuf, 0, gSndBufSize, &pbuf, &locksize,
&pbuf2, &dwSize2, 0)) != DS_OK)
{
if (hresult != DSERR_BUFFERLOST)
{
Com_Printf( "S_TransferStereo16: Lock failed with error '%s'\n", DSoundError( hresult ) );
S_Shutdown ();
return;
}
else
{
pDSBuf->lpVtbl->Restore( pDSBuf );
}
if (++reps > 2)
return;
}
dma.buffer = (unsigned char *)pbuf;
}
/*
==============
SNDDMA_Submit
Send sound to device if buffer isn't really the dma buffer
Also unlocks the dsound buffer
===============
*/
void SNDDMA_Submit(void)
{
LPWAVEHDR h;
int wResult;
if (!dma.buffer)
return;
// unlock the dsound buffer
if (pDSBuf)
pDSBuf->lpVtbl->Unlock(pDSBuf, dma.buffer, locksize, NULL, 0);
if (!wav_init)
return;
//
// find which sound blocks have completed
//
while (1)
{
if ( snd_completed == snd_sent )
{
Com_DPrintf ("Sound overrun\n");
break;
}
if ( ! (lpWaveHdr[ snd_completed & WAV_MASK].dwFlags & WHDR_DONE) )
{
break;
}
snd_completed++; // this buffer has been played
}
//Com_Printf ("completed %i\n", snd_completed);
//
// submit a few new sound blocks
//
while (((snd_sent - snd_completed) >> sample16) < 8)
{
h = lpWaveHdr + ( snd_sent&WAV_MASK );
if (paintedtime/256 <= snd_sent)
break; // Com_Printf ("submit overrun\n");
//Com_Printf ("send %i\n", snd_sent);
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)
{
Com_Printf ("Failed to write block to device\n");
FreeSound ();
return;
}
}
}
/*
==============
SNDDMA_Shutdown
Reset the sound device for exiting
===============
*/
void SNDDMA_Shutdown(void)
{
FreeSound ();
}
/*
===========
S_Activate
Called when the main window gains or loses focus.
The window have been destroyed and recreated
between a deactivate and an activate.
===========
*/
void S_Activate (qboolean active)
{
if ( active )
{
if ( pDS && cl_hwnd && snd_isdirect )
{
DS_CreateBuffers();
}
}
else
{
if ( pDS && cl_hwnd && snd_isdirect )
{
DS_DestroyBuffers();
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -