📄 snd_win.pas
字号:
begin
Com_Printf ('failed, hardware already in use'#10, [] );
Result := SIS_NOTAVAIL;
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
exit;
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 + -