⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 snd_win.pas

📁 雷神之锤2(Quake2)Delphi源码
💻 PAS
📖 第 1 页 / 共 2 页
字号:
      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 + -