📄 snd_win.pas
字号:
Exit;
end;
end;
Com_DPrintf('ok'#10, []);
dscaps.dwSize := sizeof(dscaps);
if DS_OK <> pDS.GetCaps(dscaps) then
Com_Printf('*** couldn''t get DS caps ***'#10, []);
if (dscaps.dwFlags and DSCAPS_EMULDRIVER <> 0) then
begin
Com_DPrintf('...no DSound driver found'#10, []);
FreeSound();
Result := SIS_FAILURE;
Exit;
end;
if not DS_CreateBuffers() then
begin
Result := SIS_FAILURE;
Exit;
end;
dsound_init := true;
Com_DPrintf('...completed successfully'#10, []);
Result := SIS_SUCCESS;
end;
{
=========
SNDDM_InitWav
Crappy windows multimedia base
=========
}
function SNDDMA_InitWav(): boolean;
var
format: TWAVEFORMATEX;
i: integer;
hr: HRESULT;
begin
Com_Printf('Initializing wave sound'#10, []);
snd_sent := 0;
snd_completed := 0;
dma.channels := 2;
dma.samplebits := 16;
if Trunc(s_khz^.value) = 44 then
dma.speed := 44100;
if Trunc(s_khz^.value) = 22 then
dma.speed := 22050
else
dma.speed := 11025;
FillChar(format, sizeof(format), 0);
format.wFormatTag := WAVE_FORMAT_PCM;
format.nChannels := dma.channels;
format.wBitsPerSample := dma.samplebits;
format.nSamplesPerSec := dma.speed;
format.nBlockAlign := format.nChannels * format.wBitsPerSample div 8;
format.cbSize := 0;
format.nAvgBytesPerSec := format.nSamplesPerSec * format.nBlockAlign;
{ Open a waveform device for output using window callback. }
Com_DPrintf('...opening waveform device: ', []);
hr := waveOutOpen(@hWaveOut_, WAVE_MAPPER,
@format, 0, 0, CALLBACK_NULL);
while hr <> MMSYSERR_NOERROR do
begin
if hr <> MMSYSERR_ALLOCATED then
begin
Com_Printf('failed'#10, []);
Result := false;
Exit;
end;
if MessageBox(0, 'The sound hardware is in use by another app.'#10#10 +
'Select Retry to try to start sound again or Cancel to run Quake 2 with no sound.',
'Sound not available', MB_RETRYCANCEL or MB_SETFOREGROUND or MB_ICONEXCLAMATION) <> IDRETRY then
begin
Com_Printf('hw in use'#10, []);
Result := false;
Exit;
end;
end;
Com_DPrintf('ok'#10, []);
{
* 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 or GMEM_SHARE, gSndBufSize);
if (hData = 0) then
begin
Com_Printf(' failed'#10, []);
FreeSound();
Result := false;
Exit;
end;
Com_DPrintf('ok'#10, []);
Com_DPrintf('...locking waveform buffer: ', []);
lpData := GlobalLock(hData);
if lpData = nil then
begin
Com_Printf(' failed'#10, []);
FreeSound();
Result := false;
Exit;
end;
FillChar(lpData^, gSndBufSize, 0);
Com_DPrintf('ok'#10, []);
{
* 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 or GMEM_SHARE,
DWORD(sizeof(WAVEHDR) * WAV_BUFFERS));
if hWaveHdr = 0 then
begin
Com_Printf('failed'#10, []);
FreeSound();
Result := false;
Exit;
end;
Com_DPrintf('ok'#10, []);
Com_DPrintf('...locking waveform header: ', []);
lpWaveHdr := GlobalLock(hWaveHdr);
if lpWaveHdr = nil then
begin
Com_Printf('failed'#10, []);
FreeSound();
Result := false;
Exit;
end;
FillChar(lpWaveHdr^, sizeof(WAVEHDR) * WAV_BUFFERS, 0);
Com_DPrintf('ok'#10, []);
{ After allocation, set up and prepare headers. }
Com_DPrintf('...preparing headers: ', []);
for i := 0 to WAV_BUFFERS - 1 do
begin
lpWaveHdr[i].dwBufferLength := WAV_BUFFER_SIZE;
lpWaveHdr[i].lpData := Pointer(Cardinal(lpData) + i * WAV_BUFFER_SIZE);
if waveOutPrepareHeader(hWaveOut_, @lpWaveHdr[i], sizeof(WAVEHDR)) <>
MMSYSERR_NOERROR then
begin
Com_Printf('failed'#10, []);
FreeSound();
Result := False;
Exit;
end;
end;
Com_DPrintf('ok'#10, []);
dma.samples := gSndBufSize div (dma.samplebits div 8);
dma.samplepos := 0;
dma.submission_chunk := 512;
dma.buffer := PByte(lpData);
sample16 := dma.samplebits div 8 - 1;
wav_init := True;
Result := True;
end;
{
=========
SNDDMA_Init
Try to find a sound device to mix for.
Returns false if nothing is found.
=========
}
function SNDDMA_Init(): boolean;
var
stat: sndinitstat;
begin
FillChar(dma, sizeof(dma), 0);
s_wavonly := Cvar_Get('s_wavonly', '0', 0);
dsound_init := false;
wav_init := false;
stat := SIS_FAILURE; // assume DirectSound won't initialize
{ Init DirectSound }
if s_wavonly^.value = 0 then
begin
if (snd_firsttime or snd_isdirect) then
begin
stat := SNDDMA_InitDirect();
if stat = SIS_SUCCESS then
begin
snd_isdirect := true;
if snd_firsttime then
Com_Printf('dsound init succeeded'#10, []);
end
else
begin
snd_isdirect := false;
Com_Printf('*** dsound init failed ***'#10, []);
end;
end;
end;
// 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 (not dsound_init) and (stat <> SIS_NOTAVAIL) then
begin
if snd_firsttime or snd_iswave then
begin
snd_iswave := SNDDMA_InitWav();
if snd_iswave then
begin
if (snd_firsttime) then
Com_Printf('Wave sound init succeeded'#10, []);
end
else
Com_Printf('Wave sound init failed'#10, []);
end;
end;
snd_firsttime := false;
snd_buffer_count := 1;
if (not dsound_init) and (not wav_init) then
begin
if snd_firsttime then
Com_Printf('*** No sound device initialized ***'#10, []);
Result := False;
Exit;
end;
Result := True;
end;
{
=======
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.
========
}
function SNDDMA_GetDMAPos(): integer;
var
mmtime_: MMTIME;
s: Integer;
dwWrite: DWORD;
begin
if dsound_init then
begin
mmtime_.wType := TIME_SAMPLES;
pDSBuf.GetCurrentPosition(@mmtime_.sample, @dwWrite);
s := Integer(mmtime_.sample) - mmstarttime.sample;
end
else if wav_init then
begin
s := snd_sent * WAV_BUFFER_SIZE;
end;
s := s shr sample16;
s := s and (dma.samples - 1);
Result := s;
end;
{
=======
SNDDMA_BeginPainting
Makes sure dma.buffer is valid
========
}
var
locksize: DWORD;
procedure SNDDMA_BeginPainting();
var
reps: integer;
dwSize2: DWORD;
pbuf, pbuf2: Pointer;
hresult_: HRESULT;
dwStatus: DWORD;
begin
if Assigned(pDSBuf) then
begin
// if the buffer was lost or stopped, restore it and/or restart it
if pDSBuf.GetStatus(dwStatus) <> DS_OK then
Com_Printf('Couldn''t get sound buffer status'#10, []);
if (dwStatus and DSBSTATUS_BUFFERLOST <> 0) then
pDSBuf.Restore();
if not (dwStatus and DSBSTATUS_PLAYING <> 0) then
pDSBuf.Play(0, 0, DSBPLAY_LOOPING);
// lock the dsound buffer
reps := 0;
dma.buffer := nil;
hresult_ := pDSBuf.Lock(0, gSndBufSize, pbuf,
locksize, pbuf2, dwSize2, 0);
while hresult_ <> DS_OK do
begin
if hresult_ <> DSERR_BUFFERLOST then
begin
Com_Printf('S_TransferStereo16: Lock failed with error "%s"'#10, [DSoundError(hresult_)]);
S_Shutdown();
Exit;
end
else
begin
pDSBuf.Restore();
end;
Inc(reps);
if (reps > 2) then
Exit;
hresult_ := pDSBuf.Lock(0, gSndBufSize, pbuf,
locksize, pbuf2, dwSize2, 0);
end;
dma.buffer := PByte(pbuf);
end;
end;
{
=======
SNDDMA_Submit
Send sound to device if buffer isn't really the dma buffer
Also unlocks the dsound buffer
========
}
procedure SNDDMA_Submit();
var
h: PWAVEHDR;
wResult: integer;
begin
if dma.buffer <> nil then
begin
// unlock the dsound buffer
if pDSBuf <> nil then
pDSBuf.Unlock(dma.buffer, locksize, nil, 0);
if wav_init then
begin
//
// find which sound blocks have completed
//
while 1 > 0 do
begin
if (snd_completed = snd_sent) then
begin
Com_DPrintf('Sound overrun'#10, []);
exit;
end;
if not (lpWaveHdr[snd_completed and WAV_MASK].dwFlags and WHDR_DONE <> 0) then
break;
snd_completed := snd_completed + 1; // this buffer has been played
end;
//Com_Printf ('completed %i'#10, snd_completed); break
//
// submit a few new sound blocks
//
while (((snd_sent - snd_completed) shr sample16) < 8) do
begin
h := @lpWaveHdr[(snd_sent and WAV_MASK)];
if (paintedtime / 256 <= snd_sent) then
break; // Com_Printf ('submit overrun'#10);
//Com_Printf ('send %i'#10, snd_sent);
snd_sent := snd_sent + 1;
{
* 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 then
begin
Com_Printf('Failed to write block to device'#10, []);
FreeSound();
exit;
end;
end;
end;
end;
end;
{
=======
SNDDMA_Shutdown
Reset the sound device for exiting
========
}
procedure SNDDMA_Shutdown();
begin
FreeSound();
end;
{
======
S_Activate
Called when the main window gains or loses focus.
The window have been destroyed and recreated
between a deactivate and an activate.
======
}
procedure S_Activate(active: qboolean);
begin
if active then
begin
if (pDS <> nil) and (cl_hwnd <> 0) and (snd_isdirect) then
DS_CreateBuffers();
end
else
begin
if (pDS <> nil) and (cl_hwnd <> 0) and (snd_isdirect) then
DS_DestroyBuffers();
end;
end;
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -