[DirectX]Programming.Role.Playing.Games:04_Sound

        Sound,在Programming.Role.Playing.Games书上,有介绍到使用DirectMusic和DirectSound,但dx9实在是太老了,DirectMusic也已经不支持了,而且现在还有个XAudio2组件,所以书上这一章节其实没有大多价值。

       大致流程跟之前的DirectInput类似,创建设备(CreateDevice),设置协作级(SetCooperativeLevel),创建一个主缓冲对象(CreateSoundBuffer),创建副缓冲对象(QueryInterface(IID_IDirectSoundBuffer8,..),可以多个,用于混音),创建通知对象(QueryInterface(IID_IDirectSoundNotify,..)),设置通知位置(SetNotificationPositions),数据填充到副缓冲区(Lock,Unlock),开始播放(Play),其实也可以不设置通知的。详细的可以看下这篇,写的还是挺详细的https://www.cnblogs.com/lidabo/p/4160057.html

         没有用书上的代码,用的是之前学习DX11的DirectSound代码,没有设置通知,所以相对简单点。加了混音,用的是这两首歌さくら - あなたに出会えてよかった和百恋歌,使用千千静听转的wav格式。

#include "SoundClass.h"

SoundClass::SoundClass()
{
	m_sound = nullptr;
	m_primaryBuffer = nullptr;
	m_secondaryBuffer = nullptr;
}

SoundClass::SoundClass(const SoundClass& other)
{
}

SoundClass::~SoundClass()
{
}

bool SoundClass::Initialize(HWND hwnd)
{
	bool result;

	result = InitializeDirectSound(hwnd);
	if (!result)
		return false;

	result = LoadWaveFile("Sound/Test.wav", &m_secondaryBuffer);
	if (!result)
		return false;

	result = LoadWaveFile("Sound/Test2.wav", &m_thirdBuffer);
	if (!result)
		return false;

	result = PlayWaveFile(&m_secondaryBuffer);
	if (!result)
		return false;

	result = PlayWaveFile(&m_thirdBuffer);
	if (!result)
		return false;

	return true;
}

void SoundClass::Shutdown()
{
	ShutdownWaveFile(&m_secondaryBuffer);

	ShutdownDirectSound();
}

void SoundClass::Play()
{
	bool result;

	result = PlayWaveFile(&m_secondaryBuffer);
	if (!result)
		return;

	result = PlayWaveFile(&m_thirdBuffer);
	if (!result)
		return;
}

void SoundClass::Stop()
{
	m_secondaryBuffer->Stop();
	m_thirdBuffer->Stop();
}

bool SoundClass::InitializeDirectSound(HWND hwnd)
{
	HRESULT result;
	DSBUFFERDESC bufferDesc;
	WAVEFORMATEX waveFormat;

	result = ::DirectSoundCreate8(nullptr, &m_sound, nullptr);
	if (FAILED(result))
		return false;

	result = m_sound->SetCooperativeLevel(hwnd, DSSCL_PRIORITY);
	if (FAILED(result))
		return false;

	// Setup the primary buffer description
	::memset(&bufferDesc, 0, sizeof(DSBUFFERDESC));
	bufferDesc.dwSize = sizeof(DSBUFFERDESC);
	bufferDesc.dwFlags = DSBCAPS_PRIMARYBUFFER | DSBCAPS_CTRLVOLUME;
	bufferDesc.dwBufferBytes = 0;
	bufferDesc.dwReserved = 0;
	bufferDesc.lpwfxFormat = nullptr;
	bufferDesc.guid3DAlgorithm = GUID_NULL;

	result = m_sound->CreateSoundBuffer(&bufferDesc, &m_primaryBuffer, nullptr);
	if (FAILED(result))
		return false;

	// Setup the format of the primary sound buffer
	::memset(&waveFormat, 0, sizeof(WAVEFORMATEX));
	waveFormat.wFormatTag = WAVE_FORMAT_PCM;
	waveFormat.nSamplesPerSec = 44100;
	waveFormat.wBitsPerSample = 16;
	waveFormat.nChannels = 2;
	waveFormat.nBlockAlign = (waveFormat.wBitsPerSample / 8) * waveFormat.nChannels;
	waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec * waveFormat.nBlockAlign;
	waveFormat.cbSize = 0;

	result = m_primaryBuffer->SetFormat(&waveFormat);
	if (FAILED(result))
		return false;

	return true;
}

void SoundClass::ShutdownDirectSound()
{
	if (m_primaryBuffer)
	{
		m_primaryBuffer->Release();
		m_primaryBuffer = nullptr;
	}

	if (m_sound)
	{
		m_sound->Release();
		m_sound = nullptr;
	}
}

bool SoundClass::LoadWaveFile(char* filePath, IDirectSoundBuffer8** secondaryBuffer)
{
	int error;
	FILE* filePtr;
	UINT count;
	WaveHeaderType waveFileHeader;
	WAVEFORMATEX waveFormat;
	DSBUFFERDESC bufferDesc;
	HRESULT result;
	IDirectSoundBuffer* tempBuffer;
	UCHAR* waveData;
	UCHAR* bufferPtr;
	ULONG bufferSize;

	error = fopen_s(&filePtr, filePath, "rb");
	if (error != 0)
		return false;

	count = (UINT)fread(&waveFileHeader, (size_t)sizeof(WaveHeaderType), 1, filePtr);
	if (count != 1)
		return false;

	if (memcmp(waveFileHeader.chunkID, "RIFF", 4) || memcmp(waveFileHeader.format, "WAVE", 4) ||
		memcmp(waveFileHeader.subChunkID, "fmt ", 4) || memcmp(waveFileHeader.dataChunkID, "data", 4))
		return false;

	if (waveFileHeader.audioFormat != WAVE_FORMAT_PCM)
		return false;

	if (waveFileHeader.numChannels != 2)
		return false;

	//if (waveFileHeader.sampleRate != 44100)
	//	return false;

	if (waveFileHeader.bitsPerSample != 16)
		return false;

	::memset(&waveFormat, 0, sizeof(WAVEFORMATEX));
	waveFormat.wFormatTag = WAVE_FORMAT_PCM;
	waveFormat.nSamplesPerSec = 44100;
	waveFormat.wBitsPerSample = 16;
	waveFormat.nChannels = 2;
	waveFormat.nBlockAlign = (waveFormat.wBitsPerSample / 8) * waveFormat.nChannels;
	waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec * waveFormat.nBlockAlign;
	waveFormat.cbSize = 0;

	::memset(&bufferDesc, 0, sizeof(DSBUFFERDESC));
	bufferDesc.dwSize = sizeof(DSBUFFERDESC);
	bufferDesc.dwFlags = DSBCAPS_CTRLVOLUME | DSBCAPS_GLOBALFOCUS;
	bufferDesc.dwBufferBytes = waveFileHeader.dataSize;
	bufferDesc.dwReserved = 0;
	bufferDesc.lpwfxFormat = &waveFormat;
	bufferDesc.guid3DAlgorithm = GUID_NULL;

	// Create a temporary sound buffer with the specific buffer settings
	result = m_sound->CreateSoundBuffer(&bufferDesc, &tempBuffer, nullptr);
	if (FAILED(result))
		return false;

	result = tempBuffer->QueryInterface(IID_IDirectSoundBuffer8, (void**)&*secondaryBuffer);
	if (FAILED(result))
	{
		tempBuffer->Release();
		tempBuffer = nullptr;
		return false;
	}

	tempBuffer->Release();
	tempBuffer = nullptr;
	
	// Move th the begining of the wave data which starts at the end of the data chunk header
	fseek(filePtr, sizeof(WaveHeaderType), SEEK_SET);

	waveData = new UCHAR[waveFileHeader.dataSize];
	if (!waveData)
		return false;

	count = (UINT)fread(waveData, 1, (size_t)waveFileHeader.dataSize, filePtr);
	if (count != waveFileHeader.dataSize)
		return false;

	error = fclose(filePtr);
	if (error != 0)
		return false;

	// Lock the secondary buufer to write wave data into it
	result = (*secondaryBuffer)->Lock(0, waveFileHeader.dataSize, (void**)&bufferPtr, (LPDWORD)&bufferSize, nullptr, 0, 0);
	if (FAILED(result))
		return false;

	::memcpy(bufferPtr, waveData, waveFileHeader.dataSize);

	// Unlock the secondary buffer after the data has been written to it
	result = (*secondaryBuffer)->Unlock((LPVOID)bufferPtr, bufferSize, nullptr, 0);
	if (FAILED(result))
		return false;

	delete[] waveData;
	waveData = nullptr;

	return true;
}

void SoundClass::ShutdownWaveFile(IDirectSoundBuffer8** secondaryBuffer)
{
	if (*secondaryBuffer)
	{
		(*secondaryBuffer)->Release();
		*secondaryBuffer = nullptr;
	}
}

bool SoundClass::PlayWaveFile(IDirectSoundBuffer8** secondaryBuffer)
{
	HRESULT result;

	result = (*secondaryBuffer)->SetCurrentPosition(0);
	if (FAILED(result))
		return false;

	result = (*secondaryBuffer)->SetVolume(DSBVOLUME_MAX);
	if (FAILED(result))
		return false;

	result = (*secondaryBuffer)->Play(0, 0, 0);
	if (FAILED(result))
		return false;

	return true;
}

源码下载:下载地址

猜你喜欢

转载自blog.csdn.net/zp288105109a/article/details/81139105