2

I've followed the tutorial along Microsoft's website, and created my own SoundEngine and Sound class structure to have the code abstracted away in main, however whenever I make a call such as batmanWav->play(), it will only play the audio if I write std::cin.get() or system("PAUSE")

Why is this? I will be trying to port this to a game that's already been worked on, but I obviously don't want the game to stop every time a sound is played.

EDIT: I was asked to show some code which has the issues

int main() 
{
CoInitializeEx(nullptr, COINIT_MULTITHREADED);

Sound batman("batman.wav");
Sound alien("alien.wav");

alien.play();

batman.play();
system("PAUSE");
CoUninitialize();

}

Sound.cpp

HRESULT Sound::play()
{
HRESULT hr = S_OK;
if (FAILED(hr = pSourceVoice->Start(0)))
    return hr;

return hr;
}

For each Sound object I initialized a source voice, and each one refers to the same mastering voice and IXAudio2 *pXAudio2 object. The code I used to load wave file data was taken straight off MSDN docs.

  • Can you provide minimal example code that producs the effect you describe? – Galik Jun 02 '18 at 21:34
  • Sure I added a little bit, I can add the actual `SoundEngine` and `Sound` class code if needed. – Nicholas Hernandez Jun 02 '18 at 21:44
  • From your code it looks like if you don't put in the *pause* command it will shut down the sound before it has a chance to play. Remember many computer instructions execute millions of times a second. So `CoUninitialize()` will probably halt the sounds before they begin to play. And if that didn't the program would exit before the sounds begin playing. – Galik Jun 02 '18 at 21:50
  • So in the context of a game, how do you think one would get around this problem? I would want to have a background track playing as well as be able to have various sound effects, but I cant have the game pause everytime a sound is played – Nicholas Hernandez Jun 02 '18 at 21:54
  • 1
    In a game your program will not end immediately after starting the audio. It will keep going round in a loop drawing things and calculating stuff until the user quits. – Galik Jun 02 '18 at 21:56
  • Ah I think I understand. So since it computes everything millions of times per second, it reaches the end of main before it can even play the sound. So in a game since it wouldn't quit immediately after, the code should be fine and continue to play – Nicholas Hernandez Jun 02 '18 at 21:59
  • Yes, that's what I think. It doesn't wait to play the sound, it carries on and plays the sound in the background (on a different thread) – Galik Jun 02 '18 at 22:00
  • I'm just trying to prove that from the docs but I am having trouble finding stuff (never used this myself) – Galik Jun 02 '18 at 22:02
  • Got it I think I understand, yeah the docs are pretty sparse and for a fairly beginner c++ coder it's hard to wrap my mind around it – Nicholas Hernandez Jun 02 '18 at 22:18

1 Answers1

2

As someone already noted, the problem is that your application exits before the sound really starts playing. XAudio2 is a non-blocking API, which means that you have to keep the memory live and the audio graph active until the sounds complete playing.

In other words, when you called IXAudio2SourceVoice::Start, nothing happens except that it logs that you want to start the audio. Another thread which was created as part of your IXAudio2 object then sees the request and begins to process the playback request. By that point, your application has exited and the process terminated unless you 'pause'.

Try something like the following from XAudio2BasicSound:

hr = pSourceVoice->Start( 0 );

// Let the sound play
BOOL isRunning = TRUE;
while( SUCCEEDED( hr ) && isRunning )
{
    XAUDIO2_VOICE_STATE state;
    pSourceVoice->GetState( &state );
    isRunning = ( state.BuffersQueued > 0 ) != 0;

    Sleep( 10 );
}

You should look at these samples and at DirectX Tool Kit for Audio.

Chuck Walbourn
  • 38,259
  • 2
  • 58
  • 81
  • Thanks. I have 3 questions. 1. You used the number 10 because XAudio2 reads 10ms of chunks at a time? 2. Can I use XAudio2 without a DirectX environment? 3. Is there no way to get the duration of a sound? – KeyC0de Oct 21 '20 at 19:46
  • 1
    The number 10 is completely arbitrary. Normally you don't just sit in a loop waiting for the playback to be done and instead do other things. XAudio2 is packet-based, so you determine how much audio is queued up. The processing is done on another thread, so you need to not "spin-wait" or you'll get glitches. – Chuck Walbourn Oct 21 '20 at 20:25
  • 1
    XAudio2 is unrelated to "Direct3D" rendering. It's just a software library that submits work through WASAPI. On Windows XP it actually feed the final mix to DirectSound, but that's not true on any modern Windows version. – Chuck Walbourn Oct 21 '20 at 20:26
  • 1
    Look at [DirectX Tool Kit for Audio](https://github.com/microsoft/DirectXTK/tree/master/Audio). Specifically the [SoundEffect](https://github.com/microsoft/DirectXTK/blob/master/Audio/SoundEffect.cpp) implementation has code for computing duration from the .wav data in samples or seconds. For PCM data it's trivial, but for the various compressed formats it's trickier. – Chuck Walbourn Oct 21 '20 at 20:28