Handmade Hero»Forums»Code
Joel Brage
4 posts
Im way behind but here comes XAudio2
Yeah.. due to kids, life and those bacterias that kids have in the kindergarden Im just hopelessly still in episode 8 coding along being a C/C++ newb.

So Casey sais direct sound: I code direct sound. But just out of curiosity I translated it the best I understood to XAudio2 which seems to be the windows8+ hottness.

Here be bad code:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
internal void
Win32InitXAudio2(int32 BufferSize, int32 SamplesPerSeconds,
                 XAUDIO2_BUFFER *AudioBuffer)
{
    bool32 GotError = 0;
    // NOTE Load Library
    HMODULE XAudio2Library = LoadLibraryA("xaudio2_8.dll");

    //must call this for COM, sais the Internetz ?!?!1
	//CoInitializeEx( NULL, COINIT_MULTITHREADED );
    
    if(XAudio2Library)
    {
        // NOTE Create XAudio2 object
        IXAudio2 *XAudio2 = NULL;
        HRESULT hr;
        x_audio2_create *XAudio2Create = (x_audio2_create *)GetProcAddress(XAudio2Library, "XAudio2Create");
        if (XAudio2Create && SUCCEEDED(XAudio2Create(&XAudio2, 0, XAUDIO2_DEFAULT_PROCESSOR)))
        {
        
            // NOTE Create the master voice
            IXAudio2MasteringVoice* MasterVoice = NULL;
            if (SUCCEEDED(XAudio2->CreateMasteringVoice(&MasterVoice)))
            {
                
                // NOTE Create the WAVEFORMAT
                WAVEFORMATEX WaveFormat = {};
                WaveFormat.wFormatTag = WAVE_FORMAT_PCM;
                WaveFormat.nChannels = 2;
                WaveFormat.nSamplesPerSec = SamplesPerSeconds;
                WaveFormat.wBitsPerSample = 16;
                WaveFormat.nBlockAlign = (WaveFormat.nChannels*WaveFormat.wBitsPerSample) / 8;
                WaveFormat.nAvgBytesPerSec = WaveFormat.nSamplesPerSec*WaveFormat.nBlockAlign;
                WaveFormat.cbSize = 0;
                
                // NOTE Create the Souce voice
                IXAudio2SourceVoice *SourceVoice;
                if(SUCCEEDED(XAudio2->CreateSourceVoice( &SourceVoice, &WaveFormat)))
                {
                    
                    // NOTE Allocate buffer. The buffer is owned by the program and not the XAudio2
                    //AudioBuffer = {}
                    AudioBuffer->Flags = 0;
                    AudioBuffer->AudioBytes = BufferSize;
                    AudioBuffer->pAudioData = (const BYTE*)VirtualAlloc(0, BufferSize, MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE);
                    AudioBuffer->PlayBegin = 0;
                    AudioBuffer->PlayLength = 0;
                    AudioBuffer->LoopBegin = 0;
                    AudioBuffer->LoopLength = 0;
                    AudioBuffer->LoopCount = XAUDIO2_LOOP_INFINITE;
                    AudioBuffer->pContext = 0;
                    
                    // NOTE Pass XAUDIO2_BUFFER to the source voice
                    if(SUCCEEDED(SourceVoice->SubmitSourceBuffer(AudioBuffer)))
                    {
                        
                        // NOTE Start playing
                        if (SUCCEEDED(SourceVoice->Start(0)))
                        {
                            //YEAH!
                        }
                        else
                        {
                            // TODO Diagnostics
                            GotError = 32;
                        }
                    }
                    else
                    {
                        // TODO Diagnostics
                        GotError = 16;
                    }
                }
                else
                {
                    // TODO Diagnostics
                    GotError = 8;
                }
            }
            else
            {
                // TODO Diagnostics
                GotError = 4;
            }
        }
        else
        {
            // TODO Diagnostics
            GotError = 2;
        }
    }
    else
    {
        // TODO Diagnostics
        GotError = 1;
    }
    
    if(GotError)
    {
        //CoUninitialize();
        // Free mem?
    }
}


So whats the verdict?
Mārtiņš Možeiko
2559 posts / 2 projects
Im way behind but here comes XAudio2
Not sure why you mention Windows 8. XAudio2 works fine even in Windows XP as long as it is installed (part of DirectX redist).

And your loading code to get XAudio2Create function from xaudio2_8.dll is not the best thing to do. This will work only in Windows 8. On Windows 7, Vista and XP, XAudio2Create is not exported function from dll file, it is inline function defined in xaudio.h header file. It basically uses COM CoCreateInstance function to create IXAudio2 object, so you need to call CoInitialize to initialize COM. You can check what it does from DirectX SDK headers. But if you are OK only supporting Windows 8, then there is no need to use COM at all (that includes no CoInitialize and CoUninitialize) - XAudio2Create function from dll file will do all that for you. Same way DirectSoundCreate function works.
Joel Brage
4 posts
Im way behind but here comes XAudio2
Thnx mmozeiko I will correct my code,

Like I said, i am a c/C++ newb (havnt coded it for like 15 years) and really learning with this stream. I just thought that there might be others who also wondered about XAudio etc. By the time this or any game of mine is out, windows8, 10 etc might be to expect.

About working on windows 8, I just read the msdn page and assumed :)

One question: does the CoCreateInstance not do anything in windows 8+ or must I avoid it there?

//J
Mārtiņš Možeiko
2559 posts / 2 projects
Im way behind but here comes XAudio2
CoCreateInstance will work fine on Windows 8. You can use it instead just fine. Microsoft really likes to keep backwards compatibility, so any old code that uses XAudio2 by calling CoInitialize and CoCreateInstance will still work fine on Win8/10/etc.
Joel Brage
4 posts
Im way behind but here comes XAudio2
Edited by Joel Brage on
Right. But the directsound API and the XAudio2 api look very alike to me. Have you got experience with them both and know what benefits there are with the latter?

Why not stick with the old guns?

Edit: Also my xaudio2.h doesnt have that CoCreateInstance call in it (win 8.1). Dont I have to get it from the DLL the way I did it then, or link the dll and risk the program not running if the dll is missing which I thought was the problem CM was trying to work around with his technique.
Mārtiņš Možeiko
2559 posts / 2 projects
Im way behind but here comes XAudio2
Edited by Mārtiņš Možeiko on
If you are going to do your own sound mixing like Handmade Hero does, then it doesn't matter. Both API are fine. And if you are going Window Vista/7+ route then you might as well use Windows Core Audio API (aka WASAPI) - that would give you lowest possible latency. See here: http://msdn.microsoft.com/en-us/library/windows/desktop/dd370784.aspx Here's example how to use it: http://msdn.microsoft.com/en-us/library/windows/desktop/dd316756.aspx

On Windows Vista/7+ both DirectSound and XAudio2 (and WinMM) are simply libraries that uses Windows Core Audio. So you can reduce complexity of code running (and reduce latency) to directly use Core Audio.

But if you are not mixing your own audio then you would need to create separate buffers for DirectSound or voices for XAudio2 for individual sounds. Then XAudio2 advantage would be more choices how to start/group voices, afaik DirectSound doesn't allow that and require you to start/stop playback individually on buffers. Also XAudio2 doesn't allow recording sound (microphone input). And XAudio2 would allow porting to Xbox360 be easier - Xbox360 uses same XAudio2 API (no idea what XboxOne uses).
Mārtiņš Možeiko
2559 posts / 2 projects
Im way behind but here comes XAudio2
Edited by Mārtiņš Možeiko on
CoCreateInstance is in objbase.h.
You need to include windows.h to use it, and link to ole32.lib to link to ole32.dll file (that is standard windows dll file like user32.dll or gdi32.dll, no need to optionally load it with LoadLibrary).
Gavin Williams
26 posts
Im way behind but here comes XAudio2
I'm writing XAudio2 code now (Day20) and I have a different experience on Windows 8.1. I had to use CoInitialize(nullptr,0) && CoUninitialize() later, or else CreateMasteringVoice will fail.
Kasper Sauramo
19 posts
Im way behind but here comes XAudio2
If I recall correctly here, Windows7 requires Xaudio2.7 and 2.8 isn't supported. However for some reason, the headers included in Windows7 by default is actually 2.8 (the ones you get with a vanilla #include <xaudio2>) So in order to use the Windows7 compatible version you need the latest DirectX SDK (June 2010).

Now please correct me if I'm wrong, because to me it makes no sense to stop supporting the latest API for Windows7 yet.
Mārtiņš Možeiko
2559 posts / 2 projects
Im way behind but here comes XAudio2
Edited by Mārtiņš Možeiko on
Yes, this is true.

VS2013 ships with xaudio2.h header and import library from Windows SDK 8. And it links with xaudio_2_8.dll which is not available for Windows 7. Only XAudio2 v2.7 is available for Win7 as part DirectX redistributable. If you want to create application that uses XAudio2 on Windows7 you need to either dynamic load at runtime for XAudio2 dll, or use DirectX SDK headers to compile your code (that will use COM object instantiation instead of dll exported functions).

For more information about versions of XAudio2 read here: https://msdn.microsoft.com/en-us/...ary/windows/desktop/ee415802.aspx

It actually makes more sense instead of XAudio2 to use WASAPI (part of Windows Core Audio) API as audio API if supporting Windows Vista+ is OK with you. Then you will not care about any versions or any redistributables.