📄 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;
return TRUE;
}
BOOL cSoundData::LoadWAV(char *Filename, FILE *fp)
{
if(LoadWAVHeader(Filename, fp) == FALSE)
return FALSE;
if(Create() == FALSE)
return FALSE;
// open file, seek to position and read in data
if(Filename != NULL) {
if((fp=fopen(Filename, "rb"))==NULL)
return FALSE;
}
fseek(fp, m_StartPos, SEEK_SET);
fread(m_Buf, 1, m_Size, fp);
m_StartPos = m_Pos = 0;
// close up file
if(Filename != NULL)
fclose(fp);
return TRUE;
}
BOOL cSoundData::LoadWAVHeader(char *Filename, FILE *fp)
{
sWaveHeader Hdr;
BOOL ReturnVal;
long Pos;
if(Filename == NULL && fp == NULL)
return FALSE;
if(Filename != NULL) {
if((fp=fopen(Filename, "rb"))==NULL)
return FALSE;
}
// Save position in file
Pos = ftell(fp);
// Read in header and parse
ReturnVal = FALSE;
fread(&Hdr, 1, sizeof(sWaveHeader), fp);
if(!memcmp(Hdr.RiffSig, "RIFF", 4) && !memcmp(Hdr.WaveSig, "WAVE", 4) && !memcmp(Hdr.FormatSig, "fmt ", 4) && !memcmp(Hdr.DataSig, "data", 4)) {
m_Frequency = Hdr.SampleRate;
m_Channels = Hdr.Channels;
m_BitsPerSample = Hdr.BitsPerSample;
m_Size = m_Left = Hdr.DataSize;
m_StartPos = m_Pos = ftell(fp);
ReturnVal = TRUE;
}
// Close if we opened file
// otherwise return to original position
if(Filename != NULL)
fclose(fp);
else
fseek(fp, Pos, SEEK_SET);
return ReturnVal;
}
BOOL cSoundData::Copy(cSoundData *Source)
{
if(Source == NULL)
return FALSE;
m_Frequency = Source->m_Frequency;
m_Channels = Source->m_Channels;
m_BitsPerSample = Source->m_BitsPerSample;
m_fp = Source->m_fp;
m_Ptr = Source->m_Ptr;
m_Size = Source->m_Size;
m_Left = Source->m_Left;
m_Pos = Source->m_Pos;
m_StartPos = Source->m_StartPos;
return TRUE;
}
//////////////////////////////////////////////////////////////////////
//
// cSoundChannel Functions
//
//////////////////////////////////////////////////////////////////////
cSoundChannel::cSoundChannel()
{
m_Sound = NULL;
m_pDSBuffer = NULL;
m_pDSNotify = NULL;
m_Event = -1;
m_Volume = 0;
m_Pan = 0;
m_Frequency = 0;
m_Playing = FALSE;
}
cSoundChannel::~cSoundChannel()
{
Free();
}
IDirectSoundBuffer8 *cSoundChannel::GetSoundBufferCOM()
{
return m_pDSBuffer;
}
IDirectSoundNotify8 *cSoundChannel::GetNotifyCOM()
{
return m_pDSNotify;
}
BOOL cSoundChannel::Create(cSound *Sound, long Frequency, short Channels, short BitsPerSample)
{
DSBUFFERDESC dsbd;
WAVEFORMATEX wfex;
HANDLE hEvent;
DSBPOSITIONNOTIFY dspn[3];
IDirectSoundBuffer *pDSBuffer;
// Free a prior channel
Free();
if((m_Sound = Sound) == NULL)
return FALSE;
if(m_Sound->GetDirectSoundCOM() == NULL)
return FALSE;
// Save playback format
m_Frequency = Frequency;
m_BitsPerSample = BitsPerSample;
m_Channels = Channels;
// Create a new sound buffer for this channel
// Using specified 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;
ZeroMemory(&dsbd, sizeof(DSBUFFERDESC));
dsbd.dwSize = sizeof(DSBUFFERDESC);
dsbd.dwFlags = DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLPAN | DSBCAPS_CTRLFREQUENCY | DSBCAPS_CTRLPOSITIONNOTIFY | DSBCAPS_LOCSOFTWARE;
dsbd.dwBufferBytes = g_SoundBufferSize;
dsbd.lpwfxFormat = &wfex;
if(FAILED(m_Sound->GetDirectSoundCOM()->CreateSoundBuffer(&dsbd, &pDSBuffer, NULL)))
return FALSE;
// query for newer interface
if(FAILED(pDSBuffer->QueryInterface(IID_IDirectSoundBuffer8, (void**)&m_pDSBuffer))) {
pDSBuffer->Release();
return FALSE;
}
// Release old object - we have the newer one now
pDSBuffer->Release();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -