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(), ¶ms, 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;
}