HRESULT AudioEngine::Impl::Reset()

in Audio/AudioEngine.cpp [373:588]


HRESULT AudioEngine::Impl::Reset(const WAVEFORMATEX* wfx, const wchar_t* deviceId)
{
    if (wfx)
    {
        if (wfx->wFormatTag != WAVE_FORMAT_PCM)
            return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);

        if (!wfx->nChannels || wfx->nChannels > XAUDIO2_MAX_AUDIO_CHANNELS)
            return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);

        if (wfx->nSamplesPerSec < XAUDIO2_MIN_SAMPLE_RATE || wfx->nSamplesPerSec > XAUDIO2_MAX_SAMPLE_RATE)
            return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);

        // We don't use other data members of WAVEFORMATEX here to describe the device format, so no need to fully validate
    }

    assert(!xaudio2);
    assert(mMasterVoice == nullptr);
    assert(mReverbVoice == nullptr);

    masterChannelMask = masterChannels = masterRate = 0;

    memset(&mX3DAudio, 0, X3DAUDIO_HANDLE_BYTESIZE);

    mCriticalError = false;
    mReverbEnabled = false;

    //
    // Create XAudio2 engine
    //
    HRESULT hr = XAudio2Create(xaudio2.ReleaseAndGetAddressOf(), 0u);
    if (FAILED(hr))
        return hr;

    if (mEngineFlags & AudioEngine_Debug)
    {
        XAUDIO2_DEBUG_CONFIGURATION debug = {};
        debug.TraceMask = XAUDIO2_LOG_ERRORS | XAUDIO2_LOG_WARNINGS;
        debug.BreakMask = XAUDIO2_LOG_ERRORS;
        xaudio2->SetDebugConfiguration(&debug, nullptr);
    #ifdef USING_XAUDIO2_9
        DebugTrace("INFO: XAudio 2.9 debugging enabled\n");
    #else // USING_XAUDIO2_8
            // To see the trace output, you need to view ETW logs for this application:
            //    Go to Control Panel, Administrative Tools, Event Viewer.
            //    View->Show Analytic and Debug Logs.
            //    Applications and Services Logs / Microsoft / Windows / XAudio2.
            //    Right click on Microsoft Windows XAudio2 debug logging, Properties, then Enable Logging, and hit OK
        DebugTrace("INFO: XAudio 2.8 debugging enabled\n");
    #endif
    }

    if (mEngineFlags & AudioEngine_DisableVoiceReuse)
    {
        DebugTrace("INFO: Voice reuse is disabled\n");
    }

    hr = xaudio2->RegisterForCallbacks(&mEngineCallback);
    if (FAILED(hr))
    {
        xaudio2.Reset();
        return hr;
    }

    //
    // Create mastering voice for device
    //
    hr = xaudio2->CreateMasteringVoice(&mMasterVoice,
        (wfx) ? wfx->nChannels : 0u /*XAUDIO2_DEFAULT_CHANNELS */,
        (wfx) ? wfx->nSamplesPerSec : 0u /* XAUDIO2_DEFAULT_SAMPLERATE */,
        0u, deviceId, nullptr, mCategory);
    if (FAILED(hr))
    {
        xaudio2.Reset();
        return hr;
    }

    DWORD dwChannelMask;
    hr = mMasterVoice->GetChannelMask(&dwChannelMask);
    if (FAILED(hr))
    {
        SAFE_DESTROY_VOICE(mMasterVoice)
        xaudio2.Reset();
        return hr;
    }

    XAUDIO2_VOICE_DETAILS details;
    mMasterVoice->GetVoiceDetails(&details);

    masterChannelMask = dwChannelMask;
    masterChannels = details.InputChannels;
    masterRate = details.InputSampleRate;

    DebugTrace("INFO: mastering voice has %u channels, %u sample rate, %08X channel mask\n",
        masterChannels, masterRate, masterChannelMask);

    if (mMasterVolume != 1.f)
    {
        hr = mMasterVoice->SetVolume(mMasterVolume);
        if (FAILED(hr))
        {
            SAFE_DESTROY_VOICE(mMasterVoice)
            xaudio2.Reset();
            return hr;
        }
    }

    //
    // Setup mastering volume limiter (optional)
    //
    if (mEngineFlags & AudioEngine_UseMasteringLimiter)
    {
        FXMASTERINGLIMITER_PARAMETERS params = {};
        params.Release = FXMASTERINGLIMITER_DEFAULT_RELEASE;
        params.Loudness = FXMASTERINGLIMITER_DEFAULT_LOUDNESS;

        hr = CreateFX(__uuidof(FXMasteringLimiter), mVolumeLimiter.ReleaseAndGetAddressOf(), &params, sizeof(params));
        if (FAILED(hr))
        {
            SAFE_DESTROY_VOICE(mMasterVoice)
            xaudio2.Reset();
            return hr;
        }

        XAUDIO2_EFFECT_DESCRIPTOR desc = {};
        desc.InitialState = TRUE;
        desc.OutputChannels = masterChannels;
        desc.pEffect = mVolumeLimiter.Get();

        XAUDIO2_EFFECT_CHAIN chain = { 1, &desc };
        hr = mMasterVoice->SetEffectChain(&chain);
        if (FAILED(hr))
        {
            SAFE_DESTROY_VOICE(mMasterVoice)
            mVolumeLimiter.Reset();
            xaudio2.Reset();
            return hr;
        }

        DebugTrace("INFO: Mastering volume limiter enabled\n");
    }

    //
    // Setup environmental reverb for 3D audio (optional)
    //
    if (mEngineFlags & AudioEngine_EnvironmentalReverb)
    {
        hr = XAudio2CreateReverb(mReverbEffect.ReleaseAndGetAddressOf(), 0u);
        if (FAILED(hr))
        {
            SAFE_DESTROY_VOICE(mMasterVoice)
            mVolumeLimiter.Reset();
            xaudio2.Reset();
            return hr;
        }

        XAUDIO2_EFFECT_DESCRIPTOR effects[] = { { mReverbEffect.Get(), TRUE, 1 } };
        XAUDIO2_EFFECT_CHAIN effectChain = { 1, effects };

        mReverbEnabled = true;

        hr = xaudio2->CreateSubmixVoice(&mReverbVoice, 1, masterRate,
            (mEngineFlags & AudioEngine_ReverbUseFilters) ? XAUDIO2_VOICE_USEFILTER : 0u, 0u,
            nullptr, &effectChain);
        if (FAILED(hr))
        {
            SAFE_DESTROY_VOICE(mMasterVoice)
            mReverbEffect.Reset();
            mVolumeLimiter.Reset();
            xaudio2.Reset();
            return hr;
        }

        XAUDIO2FX_REVERB_PARAMETERS native;
        ReverbConvertI3DL2ToNative(&gReverbPresets[Reverb_Default], &native);
        hr = mReverbVoice->SetEffectParameters(0, &native, sizeof(XAUDIO2FX_REVERB_PARAMETERS));
        if (FAILED(hr))
        {
            SAFE_DESTROY_VOICE(mReverbVoice)
            SAFE_DESTROY_VOICE(mMasterVoice)
            mReverbEffect.Reset();
            mVolumeLimiter.Reset();
            xaudio2.Reset();
            return hr;
        }

        DebugTrace("INFO: I3DL2 reverb effect enabled for 3D positional audio\n");
    }

    //
    // Setup 3D audio
    //
    constexpr float SPEEDOFSOUND = X3DAUDIO_SPEED_OF_SOUND;

    hr = X3DAudioInitialize(masterChannelMask, SPEEDOFSOUND, mX3DAudio);
    if (FAILED(hr))
    {
        SAFE_DESTROY_VOICE(mReverbVoice)
        SAFE_DESTROY_VOICE(mMasterVoice)
        mReverbEffect.Reset();
        mVolumeLimiter.Reset();
        xaudio2.Reset();
        return hr;
    }

    //
    // Inform any notify objects we are ready to go again
    //
    for (auto it : mNotifyObjects)
    {
        assert(it != nullptr);
        it->OnReset();
    }

    return S_OK;
}