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

📄 sound.c

📁 著名物理引擎Hawk的源代码
💻 C
字号:
/* sound.c, HAWK game engine
*
* Copyright 1997-1998 by Phil Frisbie, Jr.
* for Hawk Software
*
*/

#include <windows.h>
#include <fcntl.h>
#include "wave.h"
#include "internal.h"
#include "sound.h"

LPDIRECTSOUND	lpDS = NULL;

#define MAX_STATIC_SOUNDS	32
#define MAX_TEMP_SOUNDS		8
#define MAX_SOUNDS	(MAX_STATIC_SOUNDS+MAX_TEMP_SOUNDS)
#define FOURCC_PAK      mmioFOURCC('P', 'A', 'K', ' ')

SNDWAVEFILE		sounds[MAX_STATIC_SOUNDS+MAX_TEMP_SOUNDS];

LRESULT (CALLBACK sndMMIOProc)(LPSTR lpmmioinfo, UINT uMsg,
							   LONG lParam1, LONG lParam2);

/* Sound functions */
int soundLoad(char *name)
{
	return(sndLoadWave(name, TRUE));
}

void playSoundi(int sound, float pan, float volume, BOOL looped)
{
	int s;

	s = sndPlay3D(sound, looped, NULL);
	pan = MAX(1.0f, pan);
	pan = MAX(-1.0f, pan);
	sndSetBalance(s, 10000 * pan);
	volume = MAX(1.0f, volume);
	volume = MIN(0.0f, volume);
	if(volume != 1.0f)
		sndSetVolume(s, (int)((1.0f - volume) * -10000));
}

void playSound3Di(int sound, OBJECT *obj, float volume, BOOL looped)
{
	int s;

	s = sndPlay3D(sound, looped, obj);
	volume = MAX(1.0f, volume);
	volume = MIN(0.0f, volume);
}

void playSound(char *name, float pan, float volume)
{
	int sound;

	sound = sndLoadWave(name, FALSE);
	if(!sound)
		return;
	playSoundi(sound, pan, volume, FALSE);
}

/* Helper function */

void    stripExtension (char *path)
{
	int             length;
	
	length = strlen(path)-1;
	while (length > 0 && path[length] != '.')
	{
		length--;
		if (path[length] == '/')
			return;		/* no extension */
	}
	if (length)
		path[length] = 0;
}


BOOL sndEnable(HWND	hwnd)
{
	DSBUFFERDESC		dsbd;
	HRESULT				dsrval;
	LPDIRECTSOUNDBUFFER primary;
	
	atexit(sndDisable);
	
	dsrval = DirectSoundCreate(NULL, &lpDS, NULL);
	if(dsrval != DS_OK)
	{
		MessageBox(NULL, "DirectSoundCreate FAILED", "Error", MB_OK);
		return FALSE;
	}
	
	dsrval = IDirectSound_SetCooperativeLevel(lpDS, hwnd, DSSCL_NORMAL);
	if(dsrval != DS_OK)
	{
        IDirectSound_Release(lpDS);
		MessageBox(NULL, "SetCooperativeLevel FAILED", "Error", MB_OK);
		return FALSE;
    }
	memset(&sounds, 0, sizeof(sounds[0]) * (MAX_STATIC_SOUNDS+MAX_TEMP_SOUNDS));
	
	/* start the primary sound buffer playing */
	memset(&dsbd, 0, sizeof(DSBUFFERDESC));
	dsbd.dwSize = sizeof(DSBUFFERDESC);
	dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER;
	dsrval = IDirectSound_CreateSoundBuffer(lpDS, &dsbd, &primary, NULL);
	if(dsrval != DS_OK)
	{
		MessageBox(NULL, "CreateSoundBuffer FAILED", "Error", MB_OK);
	}
	IDirectSoundBuffer_Play(primary, 0, 0, DSBPLAY_LOOPING);
	IDirectSoundBuffer_Release(primary);
	
	/* set up the custom MMIO function */
	if(!mmioInstallIOProc(FOURCC_PAK, sndMMIOProc, MMIO_INSTALLPROC));
	
	return TRUE;
}

void sndDisable(void)
{
	int		i;
	
	for(i=0;i<MAX_STATIC_SOUNDS+MAX_TEMP_SOUNDS;i++)
		sndUnload(i);
	if(lpDS != NULL)
	{
		IDirectSound_Release(lpDS);
	}
}

int sndLoadWave(char *name, BOOL is_static)
{
	SNDWAVEFILE		*sound = NULL;
	DSBUFFERDESC	dsbd;
	DWORD			*samples = NULL;
	HRESULT			dsrval;
	BYTE			*data = NULL;
	BYTE			*data2 = NULL;
	DWORD			length;
	DWORD			length2;
	int				i;
	
	if(is_static)
	{
		/* find a free static sound structure */
		for(i=0; i<MAX_STATIC_SOUNDS; i++)
		{
			if(!sounds[i].DSB)/* found one */
			{
				sound = &sounds[i];
				break;
			}
		}
		if(!sound)
			return -1;
	}
	else
	{
		/* find a free temp sound structure */
		for(i=MAX_STATIC_SOUNDS; i<MAX_SOUNDS; i++)
		{
			if(!sounds[i].DSB)/* found one */
			{
				sound = &sounds[i];
				break;
			}
		}
		if(!sound)
			return -1;
	}
	
	/* load the wave file */
	stripExtension(name);		/* remove the .wav extension */
	strcat(name, ".PAK+wav");	/* add our extension */
	if(WaveLoadFile(name, &sound->waveFile.size,
		samples, &sound->waveFile.wfxInfo,
		&sound->waveFile.data))
	{
		return -1;
	}
	
	/* create the sound buffer */
	memset(&dsbd, 0, sizeof(DSBUFFERDESC));
	dsbd.dwSize = sizeof(DSBUFFERDESC);
	dsbd.dwFlags = DSBCAPS_CTRLDEFAULT | DSBCAPS_STATIC;
	dsbd.dwBufferBytes = sound->waveFile.size;
	dsbd.lpwfxFormat = sound->waveFile.wfxInfo;
	
	dsrval = IDirectSound_CreateSoundBuffer(lpDS, &dsbd, &sound->DSB, NULL);
	if(dsrval != DS_OK)
	{
		MessageBox(NULL, "CreateSoundBuffer FAILED", "Error", MB_OK);
	}
	
	/* copy the sound bytes */
	dsrval = IDirectSoundBuffer_Lock(sound->DSB,
		0,
		sound->waveFile.size,
		&data,
		&length,
		&data2,
		&length2,
		0L);
	if(dsrval == DS_OK)
	{
		memcpy(data, sound->waveFile.data, length);
		if(length2)
			memcpy(data2, sound->waveFile.data+length, length2);
		GlobalFree(sound->waveFile.data);
		dsrval = IDirectSoundBuffer_Unlock(sound->DSB,
				data,
				length,
				data2,
				length2);
		if(dsrval != DS_OK)
		{
			/*			MessageBox(NULL, "Unlock FAILED", "Error", MB_OK); */
			return -1;
		}
	}
	else
	{
		/*		MessageBox(NULL, "Lock FAILED", "Error", MB_OK); */
		return -1;
	}
	
	IDirectSoundBuffer_GetFrequency(sound->DSB, &sound->freq);
	return i;
}

void sndUnload(int wave)
{
	SNDWAVEFILE		*sound = &sounds[wave];
	
	if(wave < 0)
		return;
	if(sound->DSB)
	{
		IDirectSoundBuffer_Release(sound->DSB);
		memset(sound, 0, sizeof(SNDWAVEFILE));
	}
}

int sndCopy(int wave)
{
	SNDWAVEFILE		*sound = &sounds[wave];
	SNDWAVEFILE		*newsound = NULL;
	HRESULT			dsrval;
	int				i;
	
	/* find a free temp sound structure */
	if(wave < 0)
		return -1;
	for(i=MAX_STATIC_SOUNDS; i<MAX_SOUNDS; i++)
	{
		if(!sounds[i].DSB)/* found one */
		{
			newsound = &sounds[i];
			break;
		}
	}
	if(!newsound)
		return -1;
	dsrval = IDirectSound_DuplicateSoundBuffer(lpDS,
					sound->DSB, &newsound->DSB);
	if(dsrval == DS_OK)
		return i;
	else
		return -1;
}

#define SND_FALL_OFF 1000

void sndUpdate3D(int wave, OBJECT *obj)
{
	OBJECT	*player = GLevel.view[0]->object;
	vec3_t	v, look;
	float	dist, vol, pan, temp;
	
	VectorSubtract(obj->origin, player->origin, v);
	dist = VectorLength(v);
	vol = 1.0f - dist / SND_FALL_OFF;
	vol = MAX(0.1f, vol);
	/* set the volume */
	if(vol == 0.1f)
	{
		sndSetVolume(wave, -10000);
		return;
	}
	else
		sndSetVolume(wave, (int)((1.0f - vol) * -10000));
	/* set the panning */
	/* find the amount left/right */
	v[Z] = 0.0f;
	VectorNormalize(v, v);
	VectorCopy(GLevel.view[0]->look, look);
	pan = 1.0f - DotProduct(v, look);
	/* find if left or right */
	temp = v[X]; v[X] = v[Y]; v[Y] = (-1.0f) * temp;
	if(DotProduct(v, look) > 0.0f)
	{
		sndSetBalance(wave, (int)(-10000 * pan));
	}
	else
	{
		sndSetBalance(wave, (int)(10000 * pan));
	}
}

int sndPlay3D(int wave, BOOL looped, OBJECT *obj)
{
	SNDWAVEFILE		*sound = &sounds[wave];
	int				nwave;
	
	if(wave < 0)
		return wave;
	if(sndIsPlaying(wave))
	{
		if(sound->looped)
			return wave;			/* don't duplicate a looped sound */
		nwave = sndCopy(wave);
		if(nwave >=0)
		{
			sound = &sounds[nwave];
			IDirectSoundBuffer_Play(sound->DSB, 0, 0, 0);
			sound->looped = FALSE;	/* don't loop a temp sound buffer */
			sound->obj = obj;
		}
	}
	else
	{
		nwave = wave;
		if(looped)
		{
			IDirectSoundBuffer_Play(sound->DSB, 0, 0, DSBPLAY_LOOPING);
			sound->looped = TRUE;
		}
		else
		{
			IDirectSoundBuffer_Play(sound->DSB, 0, 0, 0);
			sound->looped = FALSE;
		}
		sound->obj = obj;
	}
	if(obj)
		sndUpdate3D(nwave, obj);
	
	return nwave;
}

void sndStop(int wave)
{
	SNDWAVEFILE		*sound = &sounds[wave];
	
	if(wave < 0)
		return;
	IDirectSoundBuffer_Stop(sound->DSB);
}

BOOL sndIsPlaying(int wave)
{
	SNDWAVEFILE		*sound = &sounds[wave];
	DWORD			status;
	
	if(wave < 0)
		return FALSE;
	IDirectSoundBuffer_GetStatus(sound->DSB, &status);
	return (status & DSBSTATUS_PLAYING);
}

int sndGetFrequency(int wave)
{
	SNDWAVEFILE		*sound = &sounds[wave];
	
	if(wave < 0)
		return -1;
	return sound->freq;
}

int sndGetBalance(int wave)
{
	SNDWAVEFILE		*sound = &sounds[wave];
	
	if(wave < 0)
		return 0;
	return sound->pan;
}

int sndGetVolume(int wave)
{
	SNDWAVEFILE		*sound = &sounds[wave];
	
	if(wave < 0)
		return 0;
	return sound->vol;
}

BOOL sndGetLooping(int wave)
{
	SNDWAVEFILE		*sound = &sounds[wave];
	
	if(wave < 0)
		return FALSE;
	return sound->looped;
}

void sndSetFrequency(int wave, int frequency)
{
	SNDWAVEFILE		*sound = &sounds[wave];
	HRESULT			dsrval;
	
	if(wave < 0)
		return;
	dsrval = IDirectSoundBuffer_SetFrequency(sound->DSB, frequency);
	
	if(dsrval == DS_OK)
		sound->freq = frequency;
}

void sndSetBalance(int wave, int balance)
{
	SNDWAVEFILE		*sound = &sounds[wave];
	HRESULT			dsrval;
	
	if(wave < 0)
		return;
	dsrval = IDirectSoundBuffer_SetPan(sound->DSB, balance);
	
	if(dsrval == DS_OK)
		sound->pan = balance;
}

void sndSetVolume(int wave, int volume)
{
	SNDWAVEFILE		*sound = &sounds[wave];
	HRESULT			dsrval;
	
	if(wave < 0)
		return;
	dsrval = IDirectSoundBuffer_SetVolume(sound->DSB, volume);
	
	if(dsrval == DS_OK)
		sound->vol = volume;
}

void sndSetLooping(int wave, BOOL looping)
{
	SNDWAVEFILE		*sound = &sounds[wave];
	
	if(wave < 0)
		return;
	if(looping == sound->looped)
		return;
	if(looping)
	{
		IDirectSoundBuffer_Play(sound->DSB, 0, 0, DSBPLAY_LOOPING);
		sound->looped = TRUE;
	}
	else
	{
		IDirectSoundBuffer_Play(sound->DSB, 0, 0, 0);
		sound->looped = FALSE;
	}
}

void sndUpdate(void)
{
	/* delete temp sounds that are done playing */
	int				i;
	SNDWAVEFILE		*sound;
	
	for(i=MAX_STATIC_SOUNDS; i<MAX_SOUNDS; i++)
	{
		sound = &sounds[i];
		
		if(sound->DSB)
			if(!sndIsPlaying(i))
				sndUnload(i);
	}
	/* update 3D sounds */
	for(i=0; i<MAX_SOUNDS; i++)
	{
		sound = &sounds[i];
		
		if(sound->DSB && sndIsPlaying(i) && sound->obj)
			sndUpdate3D(i, sound->obj);
	}
}

/*
* Custom IO procedure for MMIO calls.
*
* Used to allow wave files to be accessed in PAK files.
*/

LRESULT (CALLBACK sndMMIOProc)(LPSTR lpmmioinfo, UINT uMsg,
							   LONG lParam1, LONG lParam2)
{
	char	*filename;
	int		f, count;
	MMIOINFO	*mmioinfo = (MMIOINFO *)lpmmioinfo;
	
	switch (uMsg)
	{
	case MMIOM_OPEN:
		filename = (char*)lParam1;
		stripExtension(filename);	/* remove the .wav extension */
		strcat(filename, ".wav");	/* add our extension */
		f = openFile(filename,O_RDONLY|O_BINARY);
		if(f >0)
		{
			mmioinfo->adwInfo[0] = f;
			seekFile(f, 0, SEEK_SET);
			return MMSYSERR_NOERROR;
		}
		else
		{
			return MMIOERR_CANNOTOPEN;
		}
		break;
	case MMIOM_CLOSE:
		f = mmioinfo->adwInfo[0];
		closeFile(f);
		return MMSYSERR_NOERROR;
		break;
	case MMIOM_READ:
		f = mmioinfo->adwInfo[0];
		count = readFile(f, (char *)lParam1, lParam2);
		if(count > 0)
			mmioinfo->lDiskOffset += count;
		return count;
		break;
	case MMIOM_SEEK:
		f = mmioinfo->adwInfo[0];
		count = seekFile(f, lParam1, lParam2);
		if(count > 0)
			mmioinfo->lDiskOffset += count;
		return count;
		break;
	default:
		return 0;
		break;
	}
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -