📄 dsound.cpp
字号:
#include "graphics.h"
LPDIRECTSOUND lpDS; // DirectSound对象
LPDIRECTSOUNDBUFFER lpDSBPrimary; // 主声音缓冲区
WAVEFORMATEX wf;
BOOL sound_init = FALSE;
BOOL sound_on = TRUE, music_on = TRUE; // 音效和音乐开关
long sample_pan, sample_volume; // 音效的均衡和音量
long music_pan, music_volume; // 音乐的均衡和音量
STATICSOUND static_buffer[MAXSAMPLE]; // 音效缓冲区
STREAMSOUND stream_buffer; // 音乐缓冲区
HANDLE sound_event[MAXSAMPLE * 2 + 2]; // 声音缓冲区事件数组
HANDLE DS_Thread = NULL; // DirectSound线程
DWORD DirectSoundThreadID; // DirectSound线程ID
// 初始化DirectSound
BOOL init_directsound()
{
// 创建DirectSound对象
if (DirectSoundCreate(NULL, &lpDS, NULL) != DS_OK)
{
// 创建DirectSound对象失败
sound_on = music_on = FALSE;
return FALSE;
}
// 设置DirectSound协作层
if (lpDS->SetCooperativeLevel(hWnd, DSSCL_PRIORITY) != DD_OK)
{
// 设置DirectSound协作层失败
free_directsound();
return FALSE;
}
DSBUFFERDESC dsbdesc;
ZeroMemory(&dsbdesc, sizeof(dsbdesc));
dsbdesc.dwSize = sizeof(dsbdesc);
dsbdesc.dwFlags = DSBCAPS_PRIMARYBUFFER;
// 建立主声音缓冲区
if(lpDS->CreateSoundBuffer(&dsbdesc, &lpDSBPrimary,NULL) != DS_OK)
{
free_directsound();
return FALSE;
}
// 设置主声音缓冲区格式
wf.wFormatTag = WAVE_FORMAT_PCM;
wf.nChannels = 2;
wf.wBitsPerSample = SOUNDBPS;
wf.nSamplesPerSec = SOUNDSPS;
wf.nBlockAlign = (SOUNDBPS * 2) >> 3;
wf.nAvgBytesPerSec = SOUNDSPS * wf.nBlockAlign;
wf.cbSize = 0;
if (lpDSBPrimary->SetFormat(&wf) != DS_OK)
{
// 设置主声音缓冲区格式失败
free_directsound();
return FALSE;
}
lpDSBPrimary->Play(0, 0, DSBPLAY_LOOPING);
// 建立声音流缓冲区
dsbdesc.dwSize = sizeof(dsbdesc);
dsbdesc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 |
DSBCAPS_CTRLPOSITIONNOTIFY | DSBCAPS_CTRLPAN |
DSBCAPS_CTRLVOLUME;
dsbdesc.dwBufferBytes = MUSIC_BUFFER_SIZE;
dsbdesc.lpwfxFormat = &wf;
dsbdesc.dwReserved = 0;
if (lpDS->CreateSoundBuffer(&dsbdesc, &stream_buffer.lpDSB, NULL) != DS_OK)
{
// 建立声音流缓冲区失败
free_directsound();
return FALSE;
}
if (stream_buffer.lpDSB->QueryInterface(IID_IDirectSoundNotify, (void **)&stream_buffer.lpDSN) != DS_OK)
{
// 设置声音流缓冲区事件设置失败
free_directsound();
return FALSE;
}
HANDLE event;
event = CreateEvent(NULL, FALSE, FALSE, NULL);
sound_event[MAXSAMPLE*2] = event;
stream_buffer.dsbpn[0].hEventNotify = event;
stream_buffer.dsbpn[0].dwOffset = 0;
event = CreateEvent(NULL, FALSE, FALSE, NULL);
sound_event[MAXSAMPLE * 2 + 1] = event;
stream_buffer.dsbpn[1].hEventNotify = event;
stream_buffer.dsbpn[1].dwOffset = MUSIC_BUFFER_SIZE >> 1;
stream_buffer.pan = music_pan;
stream_buffer.volume = music_volume;
if (stream_buffer.lpDSN->SetNotificationPositions(2, stream_buffer.dsbpn) != DS_OK)
{
// 设置声音流缓冲区事件设置失败
free_directsound();
return FALSE;
}
stream_buffer.music = NULL;
// 设置缓冲区
STATICSOUND *ss;
dsbdesc.dwSize = sizeof(dsbdesc);
dsbdesc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 |
DSBCAPS_CTRLPOSITIONNOTIFY | DSBCAPS_CTRLPAN |
DSBCAPS_CTRLVOLUME;
dsbdesc.dwBufferBytes = SAMPLE_BUFFER_SIZE;
dsbdesc.lpwfxFormat = &wf;
dsbdesc.dwReserved = 0;
ss = &static_buffer[0];
for (int i = 0; i < MAXSAMPLE; i++, ss++)
{
// 创建缓冲区
if (lpDS->CreateSoundBuffer(&dsbdesc, &(ss->lpDSB), NULL) != DS_OK)
{
// 创建静态声音缓冲区失败
free_directsound();
return FALSE;
}
if (ss->lpDSB->QueryInterface(IID_IDirectSoundNotify, (void **)&ss->lpDSN) != DS_OK)
{
// 设置声音缓冲区失败
free_directsound();
return FALSE;
}
ss->status = -1;
event = CreateEvent(NULL, FALSE, FALSE, NULL);
sound_event[i << 1] = event;
ss->dsbpn[0].hEventNotify = event;
ss->dsbpn[0].dwOffset = 0;
event = CreateEvent(NULL, FALSE, FALSE, NULL);
sound_event[(i << 1) + 1] = event;
ss->dsbpn[1].hEventNotify = event;
ss->dsbpn[1].dwOffset = SAMPLE_BUFFER_SIZE >> 1;
ss->pan = sample_pan;
ss->volume = sample_volume;
if (ss->lpDSN->SetNotificationPositions(2, ss->dsbpn) != DS_OK)
{
// 设置声音缓冲区失败
free_directsound();
return FALSE;
}
}
// 创建多线程
if(!(DS_Thread = CreateThread(NULL, 0, DirectSoundThread, NULL, 0, &DirectSoundThreadID)))
{
free_directsound();
put_message(TRUE, "错误,创建声音管理线程失败。");
}
return TRUE;
}
// 读取音效文件
SAMPLE *load_sample(char *filename)
{
FILE *fp;
SAMPLE *sample;
sample = new SAMPLE;
put_message(sample == NULL, "错误,没有足够的内存。");
sample->number = -1;
fp = fopen(filename, "rb");
put_message(fp == NULL, "错误,读取文件%s失败。", filename);
DWORD riff = 0, size = 0, type = 0, entry = 0, filesize = 0, data_size = 0;
fseek(fp, 0, SEEK_END);
filesize = ftell(fp);
fseek(fp, 0, SEEK_SET);
fread(&riff, sizeof(DWORD), 1, fp);
fread(&size, sizeof(DWORD), 1, fp);
fread(&type, sizeof(DWORD), 1, fp);
BOOL format_read = FALSE, data_read = FALSE;
if (riff != mmioFOURCC('R', 'I', 'F', 'F') ||
type != mmioFOURCC('W', 'A', 'V', 'E'))
{
fclose(fp);
return NULL;
}
entry += 12;
while(entry < filesize)
{
fread(&type, sizeof(DWORD), 1, fp);
fread(&size, sizeof(DWORD), 1, fp);
entry += 8;
switch(type)
{
case mmioFOURCC('f', 'm', 't', ' '):
if (size < sizeof(WAVEFORMAT))
{
fclose(fp);
return FALSE;
}
fseek(fp, sizeof(WAVEFORMAT), SEEK_CUR);
entry += sizeof(WAVEFORMAT);
if (format_read && data_read)
return sample;
format_read = TRUE;
break;
case mmioFOURCC('d', 'a', 't', 'a'):
sample->bit = new char [size];
put_message(sample->bit == NULL, "错误,没有足够的内存。");
fread(sample->bit, size, 1, fp);
entry += size;
sample->size = size;
data_read = TRUE;
if (format_read)
return sample;
break;
}
}
fclose(fp);
return sample;
}
// 读取音乐文件
MUSIC *load_music(char *filename)
{
MUSIC *music;
music = new MUSIC;
put_message(music == NULL, "错误,没有足够的内存。");
music->source = MUSIC_IN_FILE;
music->fp = fopen(filename, "rb");
put_message(music->fp == NULL, "错误,读取文件%s失败。", filename);
DWORD riff = 0, size = 0, type = 0, entry = 0, filesize = 0, data_size = 0;
fseek(music->fp, 0, SEEK_END);
filesize = ftell(music->fp);
fseek(music->fp, 0, SEEK_SET);
fread(&riff, sizeof(DWORD), 1, music->fp);
fread(&size, sizeof(DWORD), 1, music->fp);
fread(&type, sizeof(DWORD), 1, music->fp);
BOOL format_read = FALSE, data_read = FALSE;
if (riff != mmioFOURCC('R', 'I', 'F', 'F') ||
type != mmioFOURCC('W', 'A', 'V', 'E'))
{
fclose(music->fp);
return NULL;
}
entry += 12;
while(entry < filesize)
{
fread(&type, sizeof(DWORD), 1, music->fp);
fread(&size, sizeof(DWORD), 1, music->fp);
entry += 8;
switch(type)
{
case mmioFOURCC('f', 'm', 't', ' '):
if (size < sizeof(WAVEFORMAT))
{
fclose(music->fp);
return FALSE;
}
fseek(music->fp, sizeof(WAVEFORMAT), SEEK_CUR);
entry += sizeof(WAVEFORMAT);
if (format_read && data_read)
return music;
format_read = TRUE;
break;
case mmioFOURCC('d', 'a', 't', 'a'):
music->size = size;
music->pos = ftell(music->fp);
data_read = TRUE;
if (format_read)
return music;
break;
}
}
fclose(music->fp);
return music;
}
// 释放音效文件所占的内存
void free_sample(SAMPLE **sample)
{
SAMPLE *s = *sample;
if (s == NULL)
return;
if (s->bit != NULL)
free(s->bit);
free(s);
*sample = NULL;
}
// 释放音效文件所占的内存
void free_music(MUSIC **music)
{
MUSIC *m = *music;
free(m);
*music = NULL;
}
// 释放DirectSound对象
void free_directsound()
{
// 关闭声音管理线程
if (DS_Thread)
{
TerminateThread(DS_Thread, 0);
Sleep(200);
}
// 释放静态缓冲区
for (int i = 0; i < MAXSAMPLE; i++)
{
if (static_buffer[i].lpDSB != NULL)
{
static_buffer[i].lpDSB->Release();
static_buffer[i].lpDSB = NULL;
static_buffer[i].lpDSN->Release();
static_buffer[i].lpDSN = NULL;
CloseHandle(sound_event[i << 1]);
CloseHandle(sound_event[i << 1 + 1]);
}
}
// 释放流缓冲区
if (stream_buffer.lpDSN != NULL)
{
stream_buffer.lpDSN->Release();
stream_buffer.lpDSN = NULL;
}
if (stream_buffer.lpDSB != NULL)
{
stream_buffer.lpDSB->Release();
stream_buffer.lpDSB = NULL;
}
CloseHandle(sound_event[MAXSAMPLE * 2]);
CloseHandle(sound_event[MAXSAMPLE * 2 + 1]);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -