📄 core_sound.cpp
字号:
/**************************************************
WinMain.cpp
GameCore Component
Programming Role-Playing Games with DirectX
by Jim Adams (01 Jan 2002)
**************************************************/
#include "Core_Global.h"
//////////////////////////////////////////////////////////////////////
//
// cSound Functions
//
//////////////////////////////////////////////////////////////////////
cSound::cSound()
{
short i;
// Initialize COM
CoInitialize(NULL);
m_hWnd = NULL;
m_Volume = 0;
m_hThread = NULL;
m_ThreadID = NULL;
m_ThreadActive = FALSE;
m_pDMPerformance = NULL;
m_pDMLoader = NULL;
m_pDS = NULL;
m_pDSBPrimary = NULL;
for(i=0;i<32;i++)
m_EventChannel[i] = NULL;
for(i=0;i<33;i++)
m_Events[i] = NULL;
}
cSound::~cSound()
{
Shutdown();
// Uninitialize COM
CoUninitialize();
}
BOOL cSound::Init(HWND hWnd, long Frequency, short Channels, short BitsPerSample, long CooperativeLevel)
{
CHAR strPath[MAX_PATH];
WCHAR wstrSearchPath[MAX_PATH];
DSBUFFERDESC dsbd;
WAVEFORMATEX wfex;
long VolumeLevel;
short i;
// Shutdown system in case of prior install
Shutdown();
// Save parent window handle
if((m_hWnd = hWnd) == NULL)
return FALSE;
///////////////////////////////////////////////////////////////////
// Initialize DirectSound
///////////////////////////////////////////////////////////////////
// Save settings of sound setup
if(CooperativeLevel == DSSCL_NORMAL)
CooperativeLevel = DSSCL_PRIORITY;
m_CooperativeLevel = CooperativeLevel;
m_Frequency = Frequency;
m_Channels = Channels;
m_BitsPerSample = BitsPerSample;
// create an IDirectSound8 object
if(FAILED(DirectSoundCreate8(NULL, &m_pDS, NULL)))
return FALSE;
// Set cooperative mode
if(FAILED(m_pDS->SetCooperativeLevel(m_hWnd, m_CooperativeLevel)))
return FALSE;
// Get primary buffer control
ZeroMemory(&dsbd, sizeof(DSBUFFERDESC));
dsbd.dwSize = sizeof(DSBUFFERDESC);
dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER | DSBCAPS_CTRLVOLUME;
dsbd.dwBufferBytes = 0;
dsbd.lpwfxFormat = NULL;
if(FAILED(m_pDS->CreateSoundBuffer(&dsbd, &m_pDSBPrimary, NULL)))
return FALSE;
// Set the primary buffer format
ZeroMemory(&wfex, sizeof(WAVEFORMATEX));
wfex.wFormatTag = WAVE_FORMAT_PCM;
wfex.nChannels = (WORD)m_Channels;
wfex.nSamplesPerSec = m_Frequency;
wfex.wBitsPerSample = (WORD)m_BitsPerSample;
wfex.nBlockAlign = wfex.wBitsPerSample / 8 * wfex.nChannels;
wfex.nAvgBytesPerSec = wfex.nSamplesPerSec * wfex.nBlockAlign;
if(FAILED(m_pDSBPrimary->SetFormat(&wfex)))
return FALSE;
// Create the events, plus
// an extra one for thread termination
for(i=0;i<33;i++) {
if((m_Events[i] = CreateEvent(NULL,FALSE,FALSE,NULL)) == NULL)
return FALSE;
}
// Create a thread for handling notifications
if((m_hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)HandleNotifications, (LPVOID)this, 0, &m_ThreadID)) == NULL)
return FALSE;
// Start main buffer playing
if(FAILED(m_pDSBPrimary->Play(0, 0, DSBPLAY_LOOPING)))
return FALSE;
///////////////////////////////////////////////////////////////////
// Initialize DirectMusic
///////////////////////////////////////////////////////////////////
// Create the DirectMusic loader object
CoCreateInstance(CLSID_DirectMusicLoader, NULL, CLSCTX_INPROC,
IID_IDirectMusicLoader8, (void**)&m_pDMLoader);
// Create the DirectMusic performance object
CoCreateInstance(CLSID_DirectMusicPerformance, NULL, CLSCTX_INPROC,
IID_IDirectMusicPerformance8, (void**)&m_pDMPerformance);
// Initialize the performance with the standard audio path.
// This initializes both DirectMusic and DirectSound and
// sets up the synthesizer.
m_pDMPerformance->InitAudio(NULL, NULL, m_hWnd,
DMUS_APATH_SHARED_STEREOPLUSREVERB, 128,
DMUS_AUDIOF_ALL, NULL);
// set the performance global volume to +10 decibels
VolumeLevel = 1000;
if(FAILED(m_pDMPerformance->SetGlobalParam(GUID_PerfMasterVolume, &VolumeLevel, sizeof(long))))
return FALSE;
// Tell DirectMusic where the default search path is
GetCurrentDirectory(MAX_PATH, strPath);
MultiByteToWideChar(CP_ACP, 0, strPath, -1, wstrSearchPath, MAX_PATH);
m_pDMLoader->SetSearchDirectory(GUID_DirectMusicAllTypes, wstrSearchPath, FALSE);
// Set default volume to full
SetVolume(100);
return TRUE;
}
BOOL cSound::Shutdown()
{
short i;
// Stop the music, and close down
if(m_pDMPerformance != NULL) {
m_pDMPerformance->Stop(NULL, NULL, 0, 0);
m_pDMPerformance->CloseDown();
}
// Release the DirectMusic objects
ReleaseCOM(m_pDMPerformance);
ReleaseCOM(m_pDMLoader);
// Go through all used sound channels and free them
for(i=0;i<32;i++) {
if(m_EventChannel[i] != NULL) {
m_EventChannel[i]->Free();
m_EventChannel[i] = NULL;
}
// Clear the event status
if(m_Events[i] != NULL)
ResetEvent(m_Events[i]);
}
// Stop the primary channel from playing
if(m_pDSBPrimary != NULL)
m_pDSBPrimary->Stop();
// Release the DirectSound objects
ReleaseCOM(m_pDSBPrimary);
ReleaseCOM(m_pDS);
// Force a closure of the thread by triggering the last event
// and waiting for it to terminate
if(m_hThread != NULL) {
if(m_Events[32] != NULL) {
while(m_ThreadActive == TRUE)
SetEvent(m_Events[32]);
} else {
// getting here means no event assigned on thread
// and need to terminate it - not desirable
TerminateThread(m_hThread, 0);
}
}
// Close all event handles
for(i=0;i<33;i++) {
if(m_Events[i] != NULL) {
CloseHandle(m_Events[i]);
m_Events[i] = NULL;
}
}
// Free the thread handle
if(m_hThread != NULL) {
CloseHandle(m_hThread);
m_hThread = NULL;
}
m_ThreadID = NULL;
return TRUE;
}
IDirectSound8 *cSound::GetDirectSoundCOM()
{
return m_pDS;
}
IDirectSoundBuffer *cSound::GetPrimaryBufferCOM()
{
return m_pDSBPrimary;
}
IDirectMusicPerformance8 *cSound::GetPerformanceCOM()
{
return m_pDMPerformance;
}
IDirectMusicLoader8 *cSound::GetLoaderCOM()
{
return m_pDMLoader;
}
BOOL cSound::AssignEvent(cSoundChannel *Channel, short *EventNum, HANDLE *EventHandle)
{
short i;
for(i=0;i<32;i++) {
if(m_Events[i] != NULL && m_EventChannel[i] == NULL) {
ResetEvent(m_Events[i]);
m_EventChannel[i] = Channel;
*EventNum = i;
*EventHandle = m_Events[i];
return TRUE;
}
}
return FALSE;
}
BOOL cSound::ReleaseEvent(cSoundChannel *Channel, short *EventNum)
{
if((unsigned short)*EventNum < 33 && m_EventChannel[*EventNum] == Channel) {
ResetEvent(m_Events[*EventNum]);
m_EventChannel[*EventNum] = NULL;
*EventNum = -1;
return TRUE;
}
return FALSE;
}
long cSound::GetVolume()
{
return m_Volume;
}
BOOL cSound::SetVolume(long Percent)
{
long Volume;
// Set the sound main volume
if(m_pDSBPrimary == NULL)
return FALSE;
// calculate a usable volume level
if(!Percent)
Volume = DSBVOLUME_MIN;
else
Volume = -20 * (100 - (Percent % 101));
if(FAILED(m_pDSBPrimary->SetVolume(Volume)))
return FALSE;
m_Volume = Percent % 101;
return TRUE;
}
DWORD cSound::HandleNotifications(LPVOID lpvoid)
{
DWORD dwResult, Channel;
cSound *SoundPtr;
BOOL Complete;
MSG Msg;
SoundPtr = (cSound*)lpvoid;
SoundPtr->m_ThreadActive = TRUE;
Complete = FALSE;
while(Complete == FALSE) {
// Wait for a message
dwResult = MsgWaitForMultipleObjects(33, SoundPtr->m_Events,
FALSE, INFINITE,
QS_ALLEVENTS);
// Get channel # to update
Channel = dwResult - WAIT_OBJECT_0;
// Check for channel update
if(Channel >=0 && Channel < 32) {
if(SoundPtr->m_EventChannel[Channel] != NULL)
SoundPtr->m_EventChannel[Channel]->Update();
} else
// Check for thread closure
if(Channel == 32) {
Complete = TRUE;
} else
// Check for waiting messages
if(Channel > 32) {
while(PeekMessage(&Msg, NULL, 0, 0, PM_REMOVE)) {
if(Msg.message == WM_QUIT) {
Complete = TRUE;
break;
}
}
}
}
SoundPtr->m_ThreadActive = FALSE;
return 0L;
}
BOOL cSound::Restore()
{
short i;
// Handle primary
if(m_pDSBPrimary != NULL)
m_pDSBPrimary->Restore();
// Handle all used sound channels
for(i=0;i<32;i++) {
if(m_EventChannel[i] != NULL)
m_EventChannel[i]->m_pDSBuffer->Restore();
}
return TRUE;
}
//////////////////////////////////////////////////////////////////////
//
// cSoundData Functions
//
//////////////////////////////////////////////////////////////////////
cSoundData::cSoundData()
{
m_Frequency = 22050;
m_Channels = 1;
m_BitsPerSample = 16;
m_fp = NULL;
m_Ptr = m_Buf = NULL;
m_StartPos = m_Pos = 0;
m_Size = m_Left = 0;
}
cSoundData::~cSoundData()
{
Free();
}
BOOL cSoundData::Create()
{
return Create(m_Size);
}
BOOL cSoundData::Create(long Size)
{
// Free prior allocated data
Free();
// Check for valid size
if((m_Size = Size) == 0)
return FALSE;
// Create a new buffer
m_Buf = new char[m_Size];
if(m_Buf == NULL)
return FALSE;
// Point to new buffer
m_Ptr = m_Buf;
m_fp = NULL;
// Clear out new buffer
ZeroMemory(m_Buf, m_Size);
return TRUE;
}
BOOL cSoundData::Free()
{
if(m_Buf != NULL) {
delete[] m_Buf;
m_Buf = NULL;
}
m_Ptr = NULL;
m_Size = 0;
return TRUE;
}
char *cSoundData::GetPtr()
{
return m_Buf;
}
long cSoundData::GetSize()
{
return m_Size;
}
BOOL cSoundData::SetFormat(long Frequency, short Channels, short BitsPerSample)
{
m_Frequency = Frequency;
m_Channels = Channels;
m_BitsPerSample = BitsPerSample;
return TRUE;
}
BOOL cSoundData::SetSource(FILE *fp, long Pos, long Size)
{
m_fp = fp;
m_Ptr = NULL;
if(Pos != -1)
m_StartPos = m_Pos = Pos;
if(Size != -1)
m_Size = m_Left = Size;
return TRUE;
}
BOOL cSoundData::SetSource(void *Ptr, long Pos, long Size)
{
m_fp = NULL;
m_Ptr = (char*)Ptr;
if(Pos != -1)
m_StartPos = m_Pos = Pos;
if(Size != -1)
m_Size = m_Left = Size;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -