📄 core_sound.cpp
字号:
// Create the notification interface
if(FAILED(m_pDSBuffer->QueryInterface(IID_IDirectSoundNotify8, (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()
{
return m_pDMSegment;
}
BOOL cMusicChannel::Create(cSound *Sound)
{
Free();
// Make sure all objects there
if((m_Sound = Sound) == NULL)
return FALSE;
if(m_Sound->GetPerformanceCOM() == NULL)
return FALSE;
if(m_Sound->GetLoaderCOM() == NULL)
return FALSE;
return TRUE;
}
BOOL cMusicChannel::Load(char *Filename)
{
DMUS_OBJECTDESC dmod;
Free();
if(m_Sound == NULL)
return FALSE;
if(m_Sound->GetPerformanceCOM() == NULL)
return FALSE;
if(m_Sound->GetLoaderCOM() == NULL)
return FALSE;
// Get the object
ZeroMemory(&dmod, sizeof(DMUS_OBJECTDESC));
dmod.dwSize = sizeof(DMUS_OBJECTDESC);
dmod.guidClass = CLSID_DirectMusicSegment;
dmod.dwValidData = DMUS_OBJ_CLASS | DMUS_OBJ_FILENAME | DMUS_OBJ_FULLPATH;
mbstowcs(dmod.wszFileName, Filename, MAX_PATH);
if(FAILED(m_Sound->GetLoaderCOM()->GetObject(&dmod, IID_IDirectMusicSegment8, (LPVOID*)&m_pDMSegment)))
return FALSE;
// Setup MIDI playing
if(strstr(Filename, ".mid") != NULL) {
if(FAILED(m_pDMSegment->SetParam(GUID_StandardMIDIFile, 0xFFFFFFFF, 0, 0, NULL)))
return FALSE;
}
// Download the band
if(FAILED(m_pDMSegment->Download(m_Sound->GetPerformanceCOM())))
return FALSE;
return TRUE;
}
BOOL cMusicChannel::Free()
{
Stop();
if(m_Sound != NULL) {
// unload instrument data
if(m_pDMSegment != NULL) {
if(m_Sound->GetPerformanceCOM() != NULL) {
if(FAILED(m_pDMSegment->Unload(m_Sound->GetPerformanceCOM())))
return FALSE;
}
// free loader data
if(m_Sound->GetLoaderCOM() != NULL) {
if(FAILED(m_Sound->GetLoaderCOM()->ReleaseObjectByUnknown(m_pDMSegment)))
return FALSE;
}
}
}
// release the segment
ReleaseCOM(m_pDMSegment);
return TRUE;
}
BOOL cMusicChannel::SetDLS(cDLS *DLS)
{
if(DLS == NULL)
return FALSE;
if(DLS->GetCollectionCOM() == NULL)
return FALSE;
if(m_Sound == NULL)
return FALSE;
if(m_Sound->GetPerformanceCOM() == NULL)
return FALSE;
if(m_pDMSegment == NULL)
return FALSE;
// Connect to the collection
if(FAILED(m_pDMSegment->SetParam(GUID_ConnectToDLSCollection, 0xFFFFFFFF, 0, 0, (void*)DLS->GetCollectionCOM())))
return FALSE;
// unload and then re-download new instruments
if(FAILED(m_pDMSegment->Unload(m_Sound->GetPerformanceCOM())))
return FALSE;
if(FAILED(m_pDMSegment->Download(m_Sound->GetPerformanceCOM())))
return FALSE;
return TRUE;
}
BOOL cMusicChannel::Play(long VolumePercent, long Loop)
{
Stop();
// Return if not setup correctly
if(m_Sound == NULL)
return FALSE;
if(m_Sound->GetPerformanceCOM() == NULL)
return FALSE;
if(m_pDMSegment == NULL)
return FALSE;
// Set the number of loops
if(!Loop)
m_pDMSegment->SetRepeats(DMUS_SEG_REPEAT_INFINITE);
else
m_pDMSegment->SetRepeats(Loop-1);
// Set the playback volume
SetVolume(VolumePercent);
// Play on default audio path
if(FAILED(m_Sound->GetPerformanceCOM()->PlaySegmentEx(
m_pDMSegment, NULL, NULL,
0, 0, NULL, NULL, NULL)))
return FALSE;
return TRUE;
}
BOOL cMusicChannel::Stop()
{
// Return if not setup correctly
if(m_Sound == NULL)
return FALSE;
if(m_Sound->GetPerformanceCOM() == NULL)
return FALSE;
if(m_pDMSegment == NULL)
return FALSE;
// Stop playback
if(FAILED(m_Sound->GetPerformanceCOM()->Stop(m_pDMSegment, NULL, 0, 0)))
return FALSE;
return TRUE;
}
long cMusicChannel::GetVolume()
{
return m_Volume;
}
BOOL cMusicChannel::SetVolume(long Percent)
{
IDirectMusicAudioPath8 *pDMAudioPath;
long Volume;
if(m_Sound == NULL)
return FALSE;
if(m_Sound->GetPerformanceCOM() == NULL)
return FALSE;
if(FAILED(m_Sound->GetPerformanceCOM()->GetDefaultAudioPath(&pDMAudioPath)))
return FALSE;
// calculate a usable volume level
if(!Percent)
Volume = -9600;
else
Volume = (long)(-32.0 * (100.0 - (float)(Percent % 101)));
if(FAILED(pDMAudioPath->SetVolume(Volume,0))) {
pDMAudioPath->Release();
return FALSE;
}
pDMAudioPath->Release();
m_Volume = Percent % 101;
return TRUE;
}
BOOL cMusicChannel::SetTempo(long Percent)
{
float Tempo;
if(m_Sound == NULL)
return FALSE;
if(m_Sound->GetPerformanceCOM() == NULL)
return FALSE;
// calculate tempo setting based on percentage
Tempo = (float)Percent / 100.0f;
// set master performance tempo
if(FAILED(m_Sound->GetPerformanceCOM()->SetGlobalParam(GUID_PerfMasterTempo, (void*)&Tempo, sizeof(float))))
return FALSE;
return TRUE;
}
BOOL cMusicChannel::IsPlaying()
{
// Return if not setup correctly
if(m_Sound == NULL)
return FALSE;
if(m_Sound->GetPerformanceCOM() == NULL)
return FALSE;
if(m_pDMSegment == NULL)
return FALSE;
if(m_Sound->GetPerformanceCOM()->IsPlaying(m_pDMSegment, NULL) == S_OK)
return TRUE;
return FALSE;
}
cDLS::cDLS()
{
m_Sound = NULL;
m_pDMCollection = NULL;
}
cDLS::~cDLS()
{
Free();
}
BOOL cDLS::Create(cSound *Sound)
{
Free();
if((m_Sound = Sound) == NULL)
return FALSE;
if(m_Sound->GetLoaderCOM() == NULL)
return FALSE;
return TRUE;
}
BOOL cDLS::Load(char *Filename)
{
DMUS_OBJECTDESC dmod;
Free();
if(m_Sound == NULL)
return FALSE;
if(m_Sound->GetLoaderCOM() == NULL)
return FALSE;
ZeroMemory(&dmod, sizeof(DMUS_OBJECTDESC));
dmod.dwSize = sizeof(DMUS_OBJECTDESC);
dmod.guidClass = CLSID_DirectMusicCollection;
if(Filename == NULL) {
// Get the default collection
dmod.guidObject = GUID_DefaultGMCollection;
dmod.dwValidData = DMUS_OBJ_CLASS | DMUS_OBJ_OBJECT;
} else {
// Get the collection object
dmod.dwValidData = DMUS_OBJ_CLASS | DMUS_OBJ_FILENAME | DMUS_OBJ_FULLPATH;
mbstowcs(dmod.wszFileName, Filename, MAX_PATH);
}
if(FAILED(m_Sound->GetLoaderCOM()->GetObject(&dmod, IID_IDirectMusicCollection8, (LPVOID*)&m_pDMCollection)))
return FALSE;
return TRUE;
}
BOOL cDLS::Free()
{
if(m_Sound == NULL)
return FALSE;
if(m_Sound->GetLoaderCOM() == NULL)
return FALSE;
if(m_pDMCollection != NULL) {
if(FAILED(m_Sound->GetLoaderCOM()->ReleaseObjectByUnknown(m_pDMCollection)))
return FALSE;
}
ReleaseCOM(m_pDMCollection);
return TRUE;
}
IDirectMusicCollection8 *cDLS::GetCollectionCOM()
{
return m_pDMCollection;
}
long cDLS::GetNumPatches()
{
HRESULT hr;
DWORD dwPatch;
long i;
hr = S_OK;
for(i=0; hr == S_OK; i++) {
hr = m_pDMCollection->EnumInstrument(i, &dwPatch, NULL, 0);
if(hr != S_OK)
break;
}
return i;
}
long cDLS::GetPatch(long Index)
{
DWORD dwPatch;
if(m_pDMCollection == NULL)
return -1;
if(FAILED(m_pDMCollection->EnumInstrument(Index, &dwPatch, NULL, 0)))
return -1;
return (long)dwPatch;
}
BOOL cDLS::Exists(long Patch)
{
IDirectMusicInstrument8 *pDMInstrument;
if(m_pDMCollection == NULL)
return FALSE;
if(FAILED(m_pDMCollection->GetInstrument(Patch, &pDMInstrument)))
return FALSE;
pDMInstrument->Release();
return TRUE;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -