Выбрать главу

  return false;

 } else {

  LogInfo("<li>Search directory '%s' set OK.", strSoundPath);

 }

 return true;

}

So, what does this code do? Well, we use CoCreateInstance to create our performance and loader objects. Once we have done this, we need to initialise the performance object by calling the InitAudio method. The parameters used above for InitAudio are fairly typical, so you will probably just want to use the same. Take a look in the SDK for a full description of the InitAudio method and it's parameters. Finally, we set the search directory for our loader object. The search directory is the folder that the loader object will look in to find the files that you want to load. In the code above, we will set the search directory to the "Sounds" folder which is inside our project folder. Now we are ready to load and play sounds.

A new class — CSound

Now that we have created and initialised DirectX Audio, we can load and play sounds and music. To help us with this, I have created a new class called CSound which is shown below. Take a quick look at the methods, and I'll explain how it works.

CSound::CSound() {

 m_pDirectAudioPerformance = NULL;

 m_pDirectAudioLoader = NULL;

 m_pSegment = NULL;

 m_pGraph = NULL;

 m_pMediaControl = NULL;

 m_pMediaPosition = NULL;

 m_enumFormat = Unknown;

 LogInfo("<li>Sound created OK");

}

void CSound::InitialiseForWavMidi(IDirectMusicPerformance8* pDirectAudioPerformance, IDirectMusicLoader8* pDirectAudioLoader) {

 m_pDirectAudioPerformance = pDirectAudioPerformance;

 m_pDirectAudioLoader = pDirectAudioLoader;

 m_enumFormat = WavMidi;

}

void CSound::InitialiseForMP3() {

 CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC, IID_IGraphBuilder, (void**)&m_pGraph);

 m_pGraph->QueryInterface(IID_IMediaControl, (void**)&m_pMediaControl);

 m_pGraph->QueryInterface(IID_IMediaPosition, (void**)&m_pMediaPosition);

 m_enumFormat = MP3;

}

CSound::~CSound() {

 Stop();

 SafeRelease(m_pSegment);

 SafeRelease(m_pGraph);

 SafeRelease(m_pMediaControl);

 SafeRelease(m_pMediaPosition);

 LogInfo("<li>Sound destroyed OK");

}

bool CSound::LoadSound(const char* szSoundFileName) {

 WCHAR wstrSoundPath[MAX_PATH];

 CHAR strSoundPath[MAX_PATH];

 switch(m_enumFormat) {

 case MP3:

  //Get the our applications "sounds" directory.

  GetCurrentDirectory(MAX_PATH, strSoundPath);

  strcat(strSoundPath, "\\Sounds\\");

  strcat(strSoundPath, szSoundFileName);

  //Convert the path to unicode.

  MultiByteToWideChar(CP_ACP, 0, strSoundPath, –1, wstrSoundPath, MAX_PATH);

  m_pGraph->RenderFile(wstrSoundPath, NULL);

  break;

 case WavMidi:

  //Convert the filename to unicode.

  MultiByteToWideChar(CP_ACP, 0, szSoundFileName, –1, wstrSoundPath, MAX_PATH);

  //Load a sound

  m_pDirectAudioLoader->LoadObjectFromFile(CLSID_DirectMusicSegment, IID_IDirectMusicSegment8, wstrSoundPath, (void**) &m_pSegment);

  m_pSegment->Download(m_pDirectAudioPerformance);

  break;

 default:

  return false;

 }

 return true;

}

bool CSound::Play(DWORD dwNumOfRepeats) {

 switch(m_enumFormat) {

 case MP3:

  //Make sure that we are at the start of the stream

  m_pMediaPosition->put_CurrentPosition(0);

  //Play mp3

  m_pMediaControl->Run();

  break;

 case WavMidi:

  //Set the number of times the sound repeats

  m_pSegment->SetRepeats(dwNumOfRepeats); //To loop the sound forever, pass in DMUS_SEG_REPEAT_INFINITE

  //Play the loaded sound

  m_pDirectAudioPerformance->PlaySegmentEx(m_pSegment, NULL, NULL, 0, 0, NULL, NULL, NULL);

  break;

 default:

  return false;

 }

 return true;

}

bool CSound::Stop() {

 switch(m_enumFormat) {

 case MP3:

  m_pMediaControl->Stop();

  break;

 case WavMidi:

  //Stop the loaded sound

  m_pDirectAudioPerformance->StopEx(m_pSegment, 0, 0);

  break;

 default:

  return false;

 }

 return true;

}

bool CSound::IsPlaying() {

 switch(m_enumFormat) {

 case MP3:

  REFTIME refPosition;

  REFTIME refDuration;

  m_pMediaPosition->get_CurrentPosition(&refPosition);

  m_pMediaPosition->get_Duration(&refDuration);

  if (refPosition < refDuration) {

   return true;

  } else {

   return false;

  }

  break;

 case WavMidi:

  if (m_pDirectAudioPerformance->IsPlaying(m_pSegment, NULL) == S_OK) {

   return true;

  } else {

   return false;

  }

  break;

 default:

  return false;

 }

}

So, how can I play a sound with CSound? Simple really, first create a new CSound object, then call either InitialiseForWavMidi or InitialiseForMP3 depending on what type of sound you want to play. Next, call LoadSound which is where you specify which file to play. Finally, call Play to play the sound that you have loaded. That's it! There are also two other methods: Stop which will stop the sound from playing and IsPlaying which tells you if a sound is playing or not. Below is a brief explanation of how each function works.

InitialiseForWavMidi

InitialiseForWavMidi initialises the CSound object for playing wav or midi files. The two parameters are the performance and loader pointers that we created earlier in CGame. These pointers are then saved as member variables for later use. We also set the format of this CSound object to WavMidi.

InitialiseForMP3

InitialiseForMP3 initialises the CSound object for playing mp3 files. There are no parameters. InitialiseForMP3 uses CoCreateInstance to create a DirectShow filter graph manager object. We can use CoCreateInstance here because CoInitialize has already been called from our CGame constructor. From the filter graph manager object we use the QueryInterface method to create two other objects: a media control object and a media position object. These three pointers are saved as member variables for later use. We also set the format of this CSound object to MP3.