📄 win_snd.c
字号:
/* Digger Remastered
Copyright (c) Andrew Jenner 1998-2004 */
#include "def.h"
#include <stdlib.h>
#include "newsnd.h"
#include "win_dig.h"
#include "win_snd.h"
#include "sound.h"
#define WAVE_OUT_DEVICE 2
#define DIRECT_SOUND_DEVICE 1
LPDIRECTSOUND lpds; /* the DirectSound object */
LPDIRECTSOUNDBUFFER lpdsb; /* the DirectSoundBuffer that all sound is written to */
int sound_output_device=0; /* 0=sound disabled;1=directsound;2=standard windows waveOut*/
samp* sound_buffer=(samp*) NULL;
extern bool sndflag;
int sound_card_capture_flag=0;
BOOL sound_buffer_playing=FALSE; /* DirectSound only: has playback been started */
LONG dx_sound_volume; /* current volume (percentage from 0 to 100) */
bool wave_device_available; /* is there a DirectSound device or any other wave device that can be used? */
HWAVEOUT wave_output_device = (HWAVEOUT) NULL; /* handle to wave output device (when not using DirectSound) */
#define NUM_SOUND_BUFFERS 2
samp far* waveout_buffer[NUM_SOUND_BUFFERS] = {NULL, NULL}; /* Non DirectSound only */
WAVEHDR waveheader[NUM_SOUND_BUFFERS]; /* Non DirectSound only */
bool fill_sound_buffer=FALSE;
Uint4 waveout_sample_rate; /* Non DirectSound only: just stores the waveout_sample_rate that was in the INI file */
/* DIRECTSOUND */
/* If using DirectSound, a circular buffer is used similar to the DOS/Soundblaster version. */
/* s1fillbuffer() operates more or less the same as the DOS version. */
/* NON-DIRECTSOUND */
/* If using the standard Windows waveOut functions, things are a little strange... */
/* There are two WAVEHDR structures, each with an asoociated sound buffer. When the playback */
/* is first started, both of these buffers are 'prepared' (locked) and written out. When the */
/* first buffer is finished playing, the second starts playing automatically, and the */
/* waveOutProc function is called to notify the program that the first buffer is finished */
/* playing. In the waveOutProc function, the first header/buffer is 'unprepared', then */
/* filled with new sound data (this is obtained from 'buffer' which is filled in */
/* 's1fillbuffer'), 'prepared', and finally written out with 'waveOutWrite'. Then, when the */
/* second buffer is finished being played, waveOutProc is again called, and the second buffer */
/* is unprepared, filled, prepared, and written out also. Playback continues to alternate */
/* between these two headers/buffers for the entire game. */
/* Currently, s1fillbuffer() fills the 'buffer' variable, similar to the Soundblaster version,*/
/* except that it doesn't automatically wrap around to the beginning of 'buffer'. */
/* Also, this function must call 'waveOutGetPosition' to try to control the rate at which */
/* 'buffer' is filled (otherwise the sound is really messed up, especially the music at the */
/* end of a level). */
/* waveOut_fillbuffer() copies the sound data from 'buffer' to one of the waveheader/buffers */
/* and resets the 'last' variable to indicate that s1fillbuffer should start filling 'buffer' */
/* up again with new sound data. */
void destroy_sound_buffers()
{
MMRESULT mmresult;
int i;
for (i=0;i<NUM_SOUND_BUFFERS;i++)
if (waveout_buffer[i])
{
farfree (waveout_buffer[i]);
waveout_buffer[i]=NULL;
}
if (sound_buffer)
{
farfree (sound_buffer);
sound_buffer=NULL;
}
}
void CALLBACK waveOutProc(HWAVEOUT hwo, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2)
{
switch (uMsg)
{
case MM_WOM_DONE:
unprepare_sound_data((WAVEHDR*) dwParam1); /* unlock the sound buffer, so we can fill it with new data */
if (!shutting_down)
{
play_sound_data((WAVEHDR*) dwParam1);
}
break;
}
}
bool setsounddevice(int base,int irq,int dma,Uint4 samprate,Uint4 bufsize)
{
HRESULT hr;
samp* lpvAudioPtr1;
DWORD dwAudioBytes1;
samp* lpvAudioPtr2;
DWORD dwAudioBytes2;
bufsize<<=1;
size=bufsize;
if (sound_output_device==DIRECT_SOUND_DEVICE && !lpDirectSoundCreate)
{
sound_output_device=WAVE_OUT_DEVICE;
}
switch (sound_output_device)
{
case DIRECT_SOUND_DEVICE:
hr = DirectSoundCreate(NULL, &lpds, NULL);
if (!hr == DS_OK)
{
wave_device_available=FALSE;
return FALSE;
}
wave_device_available=TRUE;
// hr = IDirectSound_SetCooperativeLevel(lpds, hWnd, DSSCL_PRIORITY);
if (!hr == DS_OK)
fatal_error(hr, "DirectSound_SetCooperativeLevel: FAILED");
if (!create_windows_sound_buffer(samprate, bufsize))
fatal_error(0, "create_windows_sound_buffer FAILED");
// hr=IDirectSoundBuffer_Lock(lpdsb,0,bufsize,(void **)&lpvAudioPtr1,
// &dwAudioBytes1,(void **)&lpvAudioPtr2,
// &dwAudioBytes2,(DWORD)NULL);
switch (hr)
{
case DSERR_BUFFERLOST:
fatal_error(hr, "DirectSoundBuffer: lock FAILED (BufferLost)");
case DSERR_INVALIDCALL:
fatal_error(hr, "DirectSoundBuffer: lock FAILED (InvalidCall)");
case DSERR_INVALIDPARAM:
fatal_error(hr, "DirectSoundBuffer: lock FAILED (InvalidParam)");
case DSERR_PRIOLEVELNEEDED:
fatal_error(hr, "DirectSoundBuffer: lock FAILED (PrioLevelNeeded)");
}
if (hr==DS_OK) {
memset(lpvAudioPtr1, (MIN_SAMP+MAX_SAMP)>>1, dwAudioBytes1);
IDirectSoundBuffer_Unlock(lpdsb,lpvAudioPtr1,dwAudioBytes1,lpvAudioPtr2,
dwAudioBytes2);
}
s1fillbuffer();
sound_buffer_playing=TRUE;
// hr = IDirectSoundBuffer_Play(lpdsb, 0, 0, DSBPLAY_LOOPING);
if (hr!=DS_OK)
fatal_error(hr, "DirectSoundBuffer_Play FAILED");
return TRUE;
case WAVE_OUT_DEVICE:
wave_device_available=waveOutGetNumDevs();
if (wave_device_available)
create_windows_sound_buffer(samprate, bufsize);
waveout_sample_rate=samprate;
return TRUE;
case 0: // disabled
wave_device_available=FALSE;
return TRUE;
}
return FALSE;
}
bool initsounddevice(void)
{
return TRUE;
}
void killsounddevice(void)
{
}
BOOL create_windows_sound_buffer(Uint4 samprate, Uint4 bufsize)
{
PCMWAVEFORMAT pcmwf;
int i;
HRESULT hr;
DSBUFFERDESC dsbdesc;
MMRESULT mmresult;
if (!wave_device_available)
return FALSE;
memset(&pcmwf, 0, sizeof(PCMWAVEFORMAT));
pcmwf.wf.wFormatTag = WAVE_FORMAT_PCM;
pcmwf.wf.nChannels = 1;
pcmwf.wf.nSamplesPerSec = samprate;
pcmwf.wf.nBlockAlign = 1;
pcmwf.wf.nAvgBytesPerSec = pcmwf.wf.nSamplesPerSec * pcmwf.wf.nBlockAlign;
pcmwf.wBitsPerSample = 8;
/* Using Directsound */
if (sound_output_device==DIRECT_SOUND_DEVICE)
{
memset(&dsbdesc, 0, sizeof(DSBUFFERDESC)); // Zero it out.
dsbdesc.dwSize = sizeof(DSBUFFERDESC);
dsbdesc.dwFlags = DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLFREQUENCY;
dsbdesc.dwBufferBytes = bufsize;
dsbdesc.lpwfxFormat = (LPWAVEFORMATEX)&pcmwf;
// hr = IDirectSound_CreateSoundBuffer(lpds, &dsbdesc, &lpdsb, NULL);
if SUCCEEDED(hr)
{
return TRUE;
}
else
{
lpdsb = NULL;
return FALSE;
}
}
if (sound_output_device==WAVE_OUT_DEVICE)
{
/* Not using DirectSound */
mmresult=waveOutOpen(&wave_output_device, WAVE_MAPPER, (LPWAVEFORMATEX) &pcmwf, (DWORD) waveOutProc, 0, CALLBACK_FUNCTION);
if (mmresult!=MMSYSERR_NOERROR)
{
wave_device_available=FALSE;
return FALSE;
}
else
{
sound_buffer=(samp*) malloc(bufsize*sizeof(samp));
if (!sound_buffer)
fatal_error(0, "create_windows_sound_buffer: FAILED to allocate memory for 'sound_buffer'");
for (i=0;i<NUM_SOUND_BUFFERS;i++)
{
/* create sound buffers and WAVEHEADERs */
waveout_buffer[i]=(samp*) malloc(bufsize*sizeof(samp));
if (waveout_buffer[i]==NULL)
{
wave_device_available=FALSE;
return FALSE;
}
farmemset(waveout_buffer[i], (MIN_SAMP+MAX_SAMP)>>1, bufsize*sizeof(samp));
waveheader[i].lpData=waveout_buffer[i];
waveheader[i].dwBufferLength=bufsize*sizeof(samp);
waveheader[i].dwBytesRecorded=0;
waveheader[i].dwUser=0;
waveheader[i].dwFlags=0;
waveheader[i].dwLoops=0;
waveheader[i].lpNext=0;
waveheader[i].reserved=0;
}
for (i=0;i<NUM_SOUND_BUFFERS;i++)
{
/* start playing the wavedata */
play_sound_data(&waveheader[i]);
}
return TRUE;
}
}
return FALSE;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -