c++directxxaudio2

I cannot play a sound twice in xaudio2


I am trying to set up xaudio2 and have been following the documentation. I can play a sound just fine, until I try playing it again, at which point nothing happens. I have followed the documentation almost line for line, but can't figure out why this is happening. here is the code.

        #include <iostream>
    #include <vector>
    #include <algorithm>
    #include <xaudio2.h>
    #include <Windows.h>

    #ifdef _XBOX //Big-Endian
    #define fourccRIFF 'RIFF'
    #define fourccDATA 'data'
    #define fourccFMT 'fmt '
    #define fourccWAVE 'WAVE'
    #define fourccXWMA 'XWMA'
    #define fourccDPDS 'dpds'
    #endif

    #ifndef _XBOX //Little-Endian
    #define fourccRIFF 'FFIR'
    #define fourccDATA 'atad'
    #define fourccFMT ' tmf'
    #define fourccWAVE 'EVAW'
    #define fourccXWMA 'AMWX'
    #define fourccDPDS 'sdpd'
    #endif
    HRESULT FindChunk(HANDLE hFile, DWORD fourcc, DWORD& dwChunkSize, DWORD& dwChunkDataPosition)
    {
        HRESULT hr = S_OK;
        if (INVALID_SET_FILE_POINTER == SetFilePointer(hFile, 0, NULL, FILE_BEGIN))
            return HRESULT_FROM_WIN32(GetLastError());

        DWORD dwChunkType;
        DWORD dwChunkDataSize;
        DWORD dwRIFFDataSize = 0;
        DWORD dwFileType;
        DWORD bytesRead = 0;
        DWORD dwOffset = 0;

        while (hr == S_OK)
        {
            DWORD dwRead;
            if (0 == ReadFile(hFile, &dwChunkType, sizeof(DWORD), &dwRead, NULL))
                hr = HRESULT_FROM_WIN32(GetLastError());

            if (0 == ReadFile(hFile, &dwChunkDataSize, sizeof(DWORD), &dwRead, NULL))
                hr = HRESULT_FROM_WIN32(GetLastError());

            switch (dwChunkType)
            {
            case fourccRIFF:
                dwRIFFDataSize = dwChunkDataSize;
                dwChunkDataSize = 4;
                if (0 == ReadFile(hFile, &dwFileType, sizeof(DWORD), &dwRead, NULL))
                    hr = HRESULT_FROM_WIN32(GetLastError());
                break;

            default:
                if (INVALID_SET_FILE_POINTER == SetFilePointer(hFile, dwChunkDataSize, NULL, FILE_CURRENT))
                    return HRESULT_FROM_WIN32(GetLastError());
            }

            dwOffset += sizeof(DWORD) * 2;

            if (dwChunkType == fourcc)
            {
                dwChunkSize = dwChunkDataSize;
                dwChunkDataPosition = dwOffset;
                return S_OK;
            }

            dwOffset += dwChunkDataSize;

            if (bytesRead >= dwRIFFDataSize) return S_FALSE;

        }

        return S_OK;

    }
    HRESULT ReadChunkData(HANDLE hFile, void* buffer, DWORD buffersize, DWORD bufferoffset)
    {
        HRESULT hr = S_OK;
        if (INVALID_SET_FILE_POINTER == SetFilePointer(hFile, bufferoffset, NULL, FILE_BEGIN))
            return HRESULT_FROM_WIN32(GetLastError());
        DWORD dwRead;
        if (0 == ReadFile(hFile, buffer, buffersize, &dwRead, NULL))
            hr = HRESULT_FROM_WIN32(GetLastError());
        return hr;
    }


    class VoiceCallback : public IXAudio2VoiceCallback
    {
    public:
        void STDMETHODCALLTYPE OnStreamEnd() override
        {}
        void STDMETHODCALLTYPE OnVoiceProcessingPassEnd() override
        {}
        void STDMETHODCALLTYPE OnVoiceProcessingPassStart(UINT32 SamplesRequired) override
        {}
        void STDMETHODCALLTYPE OnBufferEnd(void* pBufferContext) override
        {
        
            std::cout << "buffer end" << std::endl;
        }
        void STDMETHODCALLTYPE OnBufferStart(void* pBufferContext) override
        {
            std::cout << "buffer start" << std::endl;
        }
        void STDMETHODCALLTYPE OnLoopEnd(void* pBufferContext) override
        {}
        void STDMETHODCALLTYPE OnVoiceError(void* pBufferContext, HRESULT Error) override
        {}
    };

    int main()
    {


        WAVEFORMATEXTENSIBLE wfx = { 0 };
        XAUDIO2_BUFFER buffer = { 0 };
        HANDLE hFile = CreateFileA(
            "meow.wav",
            GENERIC_READ,
            FILE_SHARE_READ,
            NULL,
            OPEN_EXISTING,
            0,
            NULL);

        if (INVALID_HANDLE_VALUE == hFile)
            return HRESULT_FROM_WIN32(GetLastError());

        if (INVALID_SET_FILE_POINTER == SetFilePointer(hFile, 0, NULL, FILE_BEGIN))
            return HRESULT_FROM_WIN32(GetLastError());

        DWORD dwChunkSize;
        DWORD dwChunkPosition;
        //check the file type, should be fourccWAVE or 'XWMA'
        FindChunk(hFile, fourccRIFF, dwChunkSize, dwChunkPosition);
        DWORD filetype;
        ReadChunkData(hFile, &filetype, sizeof(DWORD), dwChunkPosition);
        if (filetype != fourccWAVE)
            return S_FALSE;
        FindChunk(hFile, fourccFMT, dwChunkSize, dwChunkPosition);
        ReadChunkData(hFile, &wfx, dwChunkSize, dwChunkPosition);
        //fill out the audio data buffer with the contents of the fourccDATA chunk
        FindChunk(hFile, fourccDATA, dwChunkSize, dwChunkPosition);
        BYTE* pDataBuffer = new BYTE[dwChunkSize];
        ReadChunkData(hFile, pDataBuffer, dwChunkSize, dwChunkPosition);
        buffer.AudioBytes = dwChunkSize;  //size of the audio buffer in bytes
        buffer.pAudioData = pDataBuffer;  //buffer containing audio data
        buffer.Flags = XAUDIO2_END_OF_STREAM; // tell the source voice not to expect any data after this buffer



        HRESULT hr;
        VoiceCallback vcb;

        // initialize COM
        if (FAILED(hr = CoInitializeEx(nullptr, COINITBASE_MULTITHREADED)))
        {
            return hr;
        }

        // audio engine initialized to nullptr
        IXAudio2* audioEngine = nullptr;
        // initialize audio engine
        if ( FAILED(hr = XAudio2Create(&audioEngine, 0)))
        {
            return hr;
        }

        // create mastering voice
        IXAudio2MasteringVoice* masteringVoice = nullptr;
        // initialize masterVoice
        if (FAILED(hr = audioEngine->CreateMasteringVoice(&masteringVoice)))
        {
            return hr;
        }


        // create source voice
        IXAudio2SourceVoice* sourceVoice = nullptr;
        // init source voice
        if (FAILED(hr = audioEngine->CreateSourceVoice(&sourceVoice, (WAVEFORMATEX*)&wfx, 0u, 2.0f, &vcb)))
        {
            return hr;
        }
        // submit audio buffer to source voice
        if (FAILED(hr = sourceVoice->SubmitSourceBuffer(&buffer)))
        {
            return hr;
        }


        bool over = false;
        while (!over)
        {
            if (GetAsyncKeyState('S'))
            {
                over = true;
            }
            if (GetAsyncKeyState('M'))
            {


                if (FAILED(hr = sourceVoice->Start(0)))
                {
                    return hr;
                }
            

            }
            if (GetAsyncKeyState('A'))
            {
                sourceVoice->Stop();
            }
   
        }


        audioEngine->Release();
        audioEngine = nullptr;

        masteringVoice = nullptr;

        CoUninitialize();


    }

any help would be apreciated.


Solution

  • A single XAudio2 source voice can only be playing or not playing. It can't be playing 'twice'. If you want the same sound with overlapping playback, you need to have two XAudio2 source voices active. You can submit the same audio to as many different format-compatible voices as you want. Remember that your audio data remains in your applications' memory, and each source voice just reads it directly from there (i.e. there's no copying of all the source data like there was in DirectSound).

    XAudio2 is a 'real-time mixer' for complex sounds like you find in games. If you just want to play a WAV file, that's what the old Win32 PlaySound function did.

    If you want to play the same sound again, you have to submit the audio packet again. If you do it repeatedly, it will keep looping.

    Alternatively, you can set the loop-count when you play it to just reuse the same submitted packet over and over again.

    You should take a look at DirectX Tool Kit for Audio for a simple XAudio2-based audio library. It supports 'one-shot' sounds like you are trying to do here, as well as looping sounds, voice-management, positional audio, environmental effects, file-based streaming, etc.