📄 core_sound.cpp
字号:
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[4];
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();
// Create the notification interface
if(FAILED(m_pDSBuffer->QueryInterface(IID_IDirectSoundNotify8, (void**)&m_pDSNotify)))
//if(FAILED(m_pDSBuffer->QueryInterface(IID_IDirectSoundNotify, (void**)&m_pDSNotify)))
return FALSE;
// Get an event for this
if(m_Sound->AssignEvent(this, &m_Event, &hEvent) == FALSE)
return FALSE;
// Setup the 4 notification positions
dspn[0].dwOffset = g_SoundBufferChunk - 1;
dspn[0].hEventNotify = hEvent;
dspn[1].dwOffset = g_SoundBufferChunk * 2 - 1;
dspn[1].hEventNotify = hEvent;
dspn[2].dwOffset = g_SoundBufferChunk * 3 - 1;
dspn[2].hEventNotify = hEvent;
dspn[3].dwOffset = g_SoundBufferSize - 1;
dspn[3].hEventNotify = hEvent;
if(FAILED(m_pDSNotify->SetNotificationPositions(4, dspn)))
return FALSE;
// set the pan and default volume
SetVolume(100);
SetPan(0);
return TRUE;
}
BOOL cSoundChannel::Create(cSound *Sound, cSoundData *SoundDesc)
{
return Create(Sound, SoundDesc->m_Frequency, SoundDesc->m_Channels, SoundDesc->m_BitsPerSample);
}
BOOL cSoundChannel::Free()
{
// Stop any playback
Stop();
// Release the notification
ReleaseCOM(m_pDSNotify);
// Release the buffer
ReleaseCOM(m_pDSBuffer);
// Release event from parent cSound class
m_Sound->ReleaseEvent(this, &m_Event);
// Set to no parent sound
m_Sound = NULL;
return TRUE;
}
BOOL cSoundChannel::Play(cSoundData *Desc, long VolumePercent, long Loop)
{
if(Desc == NULL)
return FALSE;
if(m_pDSBuffer == NULL)
return FALSE;
if(m_pDSNotify == NULL)
return FALSE;
// Stop any playback
Stop();
// Restore a lost buffer just in case
m_pDSBuffer->Restore();
// Setup playing information
m_Desc.Copy(Desc);
// Set looping data
m_Loop = Loop;
// Calculate stop section position
if(!m_Loop)
m_StopSection = -1;
else
m_StopSection = (short)(((m_Desc.m_Size * m_Loop) % g_SoundBufferSize) / g_SoundBufferChunk);
// Buffer in data
m_LoadSection = 0;
BufferData();
BufferData();
BufferData();
BufferData();
// Set the volume
SetVolume(VolumePercent);
// Set position and begin play
m_NextNotify = 0;
if(FAILED(m_pDSBuffer->SetCurrentPosition(0)))
return FALSE;
if(FAILED(m_pDSBuffer->Play(0,0,DSBPLAY_LOOPING)))
return FALSE;
// Flag as playing
m_Playing = TRUE;
return TRUE;
}
BOOL cSoundChannel::Stop()
{
if(m_pDSBuffer)
m_pDSBuffer->Stop();
m_Playing = FALSE;
return TRUE;
}
long cSoundChannel::GetVolume()
{
return m_Volume;
}
BOOL cSoundChannel::SetVolume(long Percent)
{
long Volume;
if(m_pDSBuffer == NULL)
return FALSE;
// calculate a usable volume level
if(!Percent)
Volume = DSBVOLUME_MIN;
else
Volume = -20 * (100 - (Percent % 101));
if(FAILED(m_pDSBuffer->SetVolume(Volume)))
return FALSE;
m_Volume = Percent % 101;
return TRUE;
}
signed long cSoundChannel::GetPan()
{
return m_Pan;
}
BOOL cSoundChannel::SetPan(signed long Level)
{
signed long Pan;
if(m_pDSBuffer == NULL)
return FALSE;
// calculate a usable setting
if(Level < 0)
Pan = DSBPAN_LEFT / 100 * ((-Level) % 101);
else
Pan = DSBPAN_RIGHT / 100 * (Level % 101);
if(FAILED(m_pDSBuffer->SetPan(Pan)))
return FALSE;
m_Pan = Level % 101;
return TRUE;
}
long cSoundChannel::GetFrequency()
{
return m_Frequency;
}
BOOL cSoundChannel::SetFrequency(long Level)
{
if(m_pDSBuffer == NULL)
return FALSE;
if(FAILED(m_pDSBuffer->SetFrequency(Level)))
return FALSE;
m_Frequency = Level;
return TRUE;
}
BOOL cSoundChannel::IsPlaying()
{
if(m_Sound == NULL || m_pDSBuffer == NULL || m_pDSNotify == NULL)
return FALSE;
return m_Playing;
}
BOOL cSoundChannel::BufferData()
{
long Pos, Size;
long ToLoad, LoadPos;
char *Ptr;
if(m_pDSBuffer == NULL)
return FALSE;
// Setup position to load in
Pos = (m_LoadSection % 4) * g_SoundBufferChunk;
if(FAILED(m_pDSBuffer->Lock(Pos, g_SoundBufferChunk, (void**)&Ptr, (DWORD*)&Size, NULL, NULL, 0)))
return FALSE;
// Clear out buffer if nothing left to load
if(!m_Desc.m_Left)
ZeroMemory(Ptr, Size);
else {
// Load in the data - take looping into account
ToLoad = Size;
LoadPos = 0;
for(;;) {
if(m_Desc.m_Left > ToLoad) {
if(m_Desc.m_fp != NULL) {
fseek(m_Desc.m_fp, m_Desc.m_Pos, SEEK_SET);
fread(&Ptr[LoadPos], 1, ToLoad, m_Desc.m_fp);
} else
memcpy(&Ptr[LoadPos], &m_Desc.m_Ptr[m_Desc.m_Pos], ToLoad);
m_Desc.m_Left -= ToLoad;
m_Desc.m_Pos += ToLoad;
break;
} else {
if(m_Desc.m_fp != NULL) {
fseek(m_Desc.m_fp, m_Desc.m_Pos, SEEK_SET);
fread(&Ptr[LoadPos], 1, m_Desc.m_Left, m_Desc.m_fp);
} else
memcpy(&Ptr[LoadPos], &m_Desc.m_Ptr[m_Desc.m_Pos], m_Desc.m_Left);
ToLoad -= m_Desc.m_Left;
LoadPos += m_Desc.m_Left;
// Check if we need to stop loop
if(m_Loop >= 1) {
m_Loop--;
if(!m_Loop) {
// Clear out remaining buffer space
if(ToLoad)
ZeroMemory(&Ptr[LoadPos], ToLoad);
m_Desc.m_Left = 0L;
break;
}
}
m_Desc.m_Pos = m_Desc.m_StartPos;
m_Desc.m_Left = m_Desc.m_Size;
// See if we need to stop loading data
if(!ToLoad)
break;
}
}
}
// Unlock the buffer
m_pDSBuffer->Unlock(Ptr, Size, NULL, 0);
// Mark next section to load
if((m_LoadSection+=1) > 3)
m_LoadSection = 0;
return TRUE;
}
BOOL cSoundChannel::Update()
{
// Check for end of sound
if(m_NextNotify == m_StopSection && !m_Desc.m_Left) {
Stop();
} else {
// Buffer in more data
BufferData();
if((m_NextNotify+=1) > 3)
m_NextNotify = 0;
}
return TRUE;
}
//////////////////////////////////////////////////////////////////////
//
// cMusicChannel Functions
//
//////////////////////////////////////////////////////////////////////
cMusicChannel::cMusicChannel()
{
m_Sound = NULL;
m_pDMSegment = NULL;
m_Volume = 0;
}
cMusicChannel::~cMusicChannel()
{
Free();
}
IDirectMusicSegment8 *cMusicChannel::GetSegmentCOM()
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -