⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 audiomanager.cpp

📁 游戏音频程序设计-Beginning.Game.Audio.Programming
💻 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,&current_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 + -