📄 audiomanager.cpp
字号:
// AudioManager.cpp: implementation of the CAudioManager class.
//
//////////////////////////////////////////////////////////////////////
#include "AudioManager.h"
#include <io.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <vorbis/codec.h>
#include <vorbis/vorbisfile.h>
namespace AudioEngine {
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CAudioManager::CAudioManager()
{
m_InitGood = false;
m_Performance = NULL;
m_Loader = NULL;
m_NotificationHandler = NULL;
}
CAudioManager::~CAudioManager()
{
}
void CAudioManager::Init(HWND hwnd, bool stereo, int perfchannels)
{
HRESULT hr;
// initialize COM
hr = CoInitialize(NULL);
ThrowIfFailed(hr, "CAudioManager::Init: CoInitialize failed.");
// Create the loader
hr = CoCreateInstance(CLSID_DirectMusicLoader, NULL, CLSCTX_INPROC,
IID_IDirectMusicLoader8, (void**)&m_Loader);
ThrowIfFailed(hr, "CAudioManager::Init: CoCreateInstance for loader failed.");
// Create performance object
hr = CoCreateInstance( CLSID_DirectMusicPerformance, NULL, CLSCTX_INPROC,
IID_IDirectMusicPerformance8, (void**)&m_Performance);
ThrowIfFailed(hr, "CAudioManager::Init: CoCreateInstance for performance failed.");
hr = m_Performance->InitAudio(NULL, NULL, hwnd, stereo ? DMUS_APATH_DYNAMIC_STEREO : DMUS_APATH_DYNAMIC_MONO,
perfchannels, DMUS_AUDIOF_ALL, NULL);
if (hr == DSERR_NODRIVER) {
// output a warning message, then continue as usual
MessageBox(hwnd, "The program could not locate your audio hardware. Make sure your driver supports DirectX 8.", "Audio Engine", MB_ICONSTOP);
return; // notice we didn't set m_InitGood true
}
else ThrowIfFailed(hr, "CAudioManager::Init: m_Performance->InitAudio failed.");
// initialize mixer
m_Mixer.Init();
// add ALL notification messages (even though we may not do anything with some of them)
GUID guid;
/*
guid = GUID_NOTIFICATION_CHORD;
ThrowIfFailed(m_Performance->AddNotificationType(guid), "CAudioManager::Init: couldn't add CHORD notification type!");
guid = GUID_NOTIFICATION_COMMAND;
ThrowIfFailed(m_Performance->AddNotificationType(guid), "CAudioManager::Init: couldn't add COMMAND notification type!");
*/
guid = GUID_NOTIFICATION_MEASUREANDBEAT;
ThrowIfFailed(m_Performance->AddNotificationType(guid), "CAudioManager::Init: couldn't add MEASUREANDBEAT notification type!");
/*
guid = GUID_NOTIFICATION_PERFORMANCE;
ThrowIfFailed(m_Performance->AddNotificationType(guid), "CAudioManager::Init: couldn't add PERFORMANCE notification type!");
guid = GUID_NOTIFICATION_RECOMPOSE;
ThrowIfFailed(m_Performance->AddNotificationType(guid), "CAudioManager::Init: couldn't add RECOMPOSE notification type!");
guid = GUID_NOTIFICATION_SEGMENT;
ThrowIfFailed(m_Performance->AddNotificationType(guid), "CAudioManager::Init: couldn't add SEGMENT notification type!");
*/
// create event and tell DirectMusic about it
m_NotificationEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
m_Performance->SetNotificationHandle(m_NotificationEvent, 0); // hold messages for default of 2 seconds
m_InitGood = true;
}
void CAudioManager::UnInit()
{
// close notification handle and tell DirectMusic it's closed
CloseHandle(m_NotificationEvent);
m_Performance->SetNotificationHandle(NULL, 0);
// release performance
if(m_Performance != NULL) {
m_Performance->Stop( NULL, NULL, 0, 0 );
m_Performance->CloseDown();
SAFE_RELEASE( m_Performance );
}
SAFE_RELEASE( m_Loader );
// uninitialize mixer
m_Mixer.UnInit();
m_InitGood = false;
}
CSoundPtr CAudioManager::LoadSound(const CWAVFile &wavfile)
{
unsigned char *savedata = wavfile.Save();
// when you load a wave from memory, DirectMusic owns the memory pointer...
// do NOT delete!
return(LoadSound(savedata, wavfile.GetTotalSize()));
}
CSoundPtr CAudioManager::LoadSound(unsigned char *data, int datalen)
{
CSoundEffect *snd = new CSoundEffect(this);
LoadSegmentFromMemory(snd, data, datalen);
return(CSoundPtr(snd));
}
CSoundPtr CAudioManager::LoadSound(HMODULE hmod, char *type, WORD resID)
{
CSoundEffect *snd = new CSoundEffect(this);
LoadSegmentFromResource(snd, hmod, type, resID);
return(CSoundPtr(snd));
}
CSoundPtr CAudioManager::LoadSound(std::string filename)
{
CSoundEffect *snd = new CSoundEffect(this);
LoadSegmentFromDisk(snd, filename);
return(CSoundPtr(snd));
}
CSoundPtr CAudioManager::LoadMIDI(std::string filename)
{
CMIDIMusic *music = new CMIDIMusic(this);
LoadSegmentFromDisk(music, filename);
return(CSoundPtr(music));
}
CSoundPtr CAudioManager::LoadMIDI(unsigned char *data, int datalen)
{
CMIDIMusic *music = new CMIDIMusic(this);
LoadSegmentFromMemory(music, data, datalen);
return(CSoundPtr(music));
}
CSoundPtr CAudioManager::LoadMIDI(HMODULE hmod, char *type, WORD resID)
{
CMIDIMusic *music = new CMIDIMusic(this);
LoadSegmentFromResource(music, hmod, type, resID);
return(CSoundPtr(music));
}
CSoundPtr CAudioManager::LoadMP3(std::string filename)
{
CMP3 *mp3 = new CMP3(this);
mp3->m_Tag = GetMP3AudioTag(filename);
CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
IID_IGraphBuilder, (void **)&mp3->m_GraphBuilder);
mp3->m_GraphBuilder->QueryInterface(IID_IMediaControl, (void **)&mp3->m_MediaControl);
mp3->m_GraphBuilder->QueryInterface(IID_IMediaEventEx, (void **)&mp3->m_MediaEventEx);
WCHAR widefilename[MAX_PATH];
DXUtil_ConvertGenericStringToWideCch( widefilename, filename.c_str(), MAX_PATH);
mp3->m_GraphBuilder->RenderFile(widefilename, NULL);
return(CSoundPtr(mp3));
}
CMP3AudioTag CAudioManager::GetMP3AudioTag(std::string filename)
{
CMP3AudioTag tag;
tag.Read(filename);
return(tag);
}
CSoundPtr CAudioManager::LoadOggVorbis(std::string filename)
{
std::vector<unsigned char> pcmdata;
// this code is based on vorbisfile_example.c, included in the ogg distribution.
char pcmout[4096]; // ogg decoding buffer
OggVorbis_File vf;
int eof=0;
int current_section=0;
FILE *f = fopen(filename.c_str(), "rb");
if (f == NULL) { Throw("CAudioManager::LoadOggVorbis: could not open file."); }
if(ov_open(f, &vf, NULL, 0) < 0) {
Throw("CAudioManager::LoadOggVorbis: Input does not appear to be an Ogg bitstream.");
}
/* Throw the comments plus a few lines about the bitstream we're
decoding */
vorbis_info *vi=ov_info(&vf,-1);
// resize the pcmdata vector to the size of the ogg file
// two bytes per channel per sample
int samples = ov_pcm_total(&vf,-1);
int channels = vi->channels;
int samplerate = vi->rate;
if (samples > 0) {
pcmdata.reserve(channels*2*samples);
}
while(!eof){
long ret=ov_read(&vf,pcmout,sizeof(pcmout),0,2,1,¤t_section);
if (ret == 0) {
/* EOF */
eof=1;
} else if (ret < 0) {
/* error in the stream. Not a problem, just reporting it in
case we (the app) cares. In this case, we don't. */
} else {
/* we don't bother dealing with sample rate changes, etc, but
you'll have to*/
// transfer the data out of the ogg buffer and into ours.
for (int q=0; q < ret; q++) {
pcmdata.push_back(pcmout[q]);
}
}
}
/* cleanup */
ov_clear(&vf);
// now that we have the PCM data in memory, convert it to a WAV file
// and handoff to DirectMusic for loading into a segment.
CWAVFile wavfile;
wavfile.m_AudioFormat = WAVE_FORMAT_PCM;
wavfile.m_BitsPerSample = 16;
wavfile.m_BlockAlign = 2*channels; // 16 bits / 8 (to bytes) * numchannels (2)
wavfile.m_ByteRate = samplerate*channels*2;
wavfile.m_NumberOfChannels = channels;
wavfile.m_SampleRate = samplerate;
wavfile.SetData(pcmdata.begin(), pcmdata.size());
return(LoadSound(wavfile));
}
void CAudioManager::LoadSegmentFromDisk(CDirectMusicSegment *dest, std::string filename)
{
HRESULT hr;
// convert filename to wide-string
WCHAR widefilename[MAX_PATH];
DXUtil_ConvertGenericStringToWideCch( widefilename, filename.c_str(), MAX_PATH);
// tell loader to load this file
hr = m_Loader->LoadObjectFromFile(
CLSID_DirectMusicSegment,
IID_IDirectMusicSegment8,
widefilename,
(void**) &dest->m_Segment);
ThrowIfFailed(hr, "CAudioManager::LoadSound(std::string filename): LoadObjectFromFile failed.");
}
void CAudioManager::LoadSegmentFromMemory(CDirectMusicSegment *dest, unsigned char *data, int datalen)
{
HRESULT hr;
DMUS_OBJECTDESC desc;
memset(&desc, 0, sizeof(DMUS_OBJECTDESC));
desc.dwSize = sizeof(DMUS_OBJECTDESC);
desc.dwValidData = DMUS_OBJ_MEMORY | DMUS_OBJ_CLASS;
desc.guidClass = CLSID_DirectMusicSegment;
desc.llMemLength = datalen;
desc.pbMemData = data;
hr = m_Loader->GetObject(&desc, IID_IDirectMusicSegment8, (void **)&dest->m_Segment);
ThrowIfFailed(hr, "CAudioManager::LoadSound(unsigned char *data): GetObject failed.");
dest->m_OriginalData = data;
}
void CAudioManager::LoadSegmentFromResource(CDirectMusicSegment *dest, HMODULE hmod, char *type, WORD resID)
{
HRESULT hr;
DMUS_OBJECTDESC ObjDesc;
HRSRC hFound = FindResource(hmod, MAKEINTRESOURCE(resID), type);
if (NULL == hFound) {
Throw("CAudioManager::LoadSegmentFromResource: couldn't find resource!");
}
HGLOBAL hRes = LoadResource(hmod, hFound);
ObjDesc.dwSize = sizeof(DMUS_OBJECTDESC);
ObjDesc.guidClass = CLSID_DirectMusicSegment;
ObjDesc.dwValidData = DMUS_OBJ_CLASS | DMUS_OBJ_MEMORY;
ObjDesc.pbMemData = (BYTE *) LockResource(hRes);
ObjDesc.llMemLength = SizeofResource(hmod, hFound);
hr = m_Loader->GetObject(&ObjDesc, IID_IDirectMusicSegment8,
(void**) &dest->m_Segment);
ThrowIfFailed(hr, "CAudioManager::LoadSegmentFromResource(HMODULE hmod, WORD resID): GetObject failed.");
}
void CAudioManager::SetSearchDirectory(std::string dirname)
{
// convert dirname to wide-string
WCHAR widedirname[MAX_PATH];
DXUtil_ConvertGenericStringToWideCch( widedirname, dirname.c_str(), MAX_PATH);
HRESULT hr = m_Loader->SetSearchDirectory(CLSID_DirectMusicSegment, widedirname, true);
ThrowIfFailed(hr, "CAudioManager::SetSearchDirectory: SetSearchDirectory() failed.");
}
void CAudioManager::SetVolume(const CVolume &vol)
{
if (NULL == m_Performance) return;
long dmvol = vol.ToDirectMusic();
ThrowIfFailed(m_Performance->SetGlobalParam(GUID_PerfMasterVolume, &dmvol, sizeof(dmvol)),
"CAudioManager::SetVolume: SetGlobalParam failed.");
}
CVolume CAudioManager::GetVolume()
{
if (NULL == m_Performance) return(0);
long dmvol=0;
ThrowIfFailed(m_Performance->GetGlobalParam(GUID_PerfMasterVolume, &dmvol, sizeof(dmvol)),
"CAudioManager::GetVolume: GetGlobalParam failed.");
CVolume vol;
vol.FromDirectMusic(dmvol);
return(vol);
}
void CAudioManager::DispatchNotificationMessages()
{
if (NULL == m_Performance) return;
DMUS_NOTIFICATION_PMSG* pPmsg;
while (m_NotificationHandler && m_Performance->GetNotificationPMsg(&pPmsg) == S_OK) {
if (pPmsg->guidNotificationType == GUID_NOTIFICATION_MEASUREANDBEAT) {
// if it's a beat, call OnBeat... otherwise call OnMeasure.
if (pPmsg->dwField1 == 0) { m_NotificationHandler->OnMeasure(*pPmsg); }
else { m_NotificationHandler->OnBeat(*pPmsg); }
}
m_Performance->FreePMsg((DMUS_PMSG*)pPmsg);
} // while
// look for and process DirectShow notifications
CDirectShowMusic::DispatchDirectShowNotifications();
}
void CAudioManager::SetMasterTempoScaleFactor(float value)
{
if (NULL == m_Performance) return;
ThrowIfFailed(m_Performance->SetGlobalParam(GUID_PerfMasterTempo, &value, sizeof(value)),
"CAudioManager::SetMasterTempo: SetGlobalParam failed.");
}
float CAudioManager::GetMasterTempoScaleFactor()
{
if (NULL == m_Performance) return(0.0f);
float tempo=0.0f;
ThrowIfFailed(m_Performance->GetGlobalParam(GUID_PerfMasterTempo, &tempo, sizeof(tempo)),
"CAudioManager::GetMasterTempo: GetGlobalParam failed.");
return(tempo);
}
}; // namespace
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -