2016-10-29 02:02:21 +03:00
|
|
|
//--------------------------------------------------------------------------------------
|
|
|
|
// File: SoundEffectInstance.cpp
|
|
|
|
//
|
2021-02-27 10:01:15 +03:00
|
|
|
// Copyright (c) Microsoft Corporation.
|
2018-02-24 09:08:23 +03:00
|
|
|
// Licensed under the MIT License.
|
2016-10-29 02:02:21 +03:00
|
|
|
//
|
|
|
|
// http://go.microsoft.com/fwlink/?LinkId=248929
|
2018-02-24 09:08:23 +03:00
|
|
|
// http://go.microsoft.com/fwlink/?LinkID=615561
|
2016-10-29 02:02:21 +03:00
|
|
|
//--------------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
#include "pch.h"
|
|
|
|
#include "SoundCommon.h"
|
|
|
|
|
|
|
|
using namespace DirectX;
|
|
|
|
|
|
|
|
|
|
|
|
//======================================================================================
|
|
|
|
// SoundEffectInstance
|
|
|
|
//======================================================================================
|
|
|
|
|
|
|
|
// Internal object implementation class.
|
|
|
|
class SoundEffectInstance::Impl : public IVoiceNotify
|
|
|
|
{
|
|
|
|
public:
|
2018-03-16 22:03:02 +03:00
|
|
|
Impl(_In_ AudioEngine* engine, _In_ SoundEffect* effect, SOUND_EFFECT_INSTANCE_FLAGS flags) :
|
2016-10-29 02:02:21 +03:00
|
|
|
mBase(),
|
2018-03-16 22:03:02 +03:00
|
|
|
mEffect(effect),
|
|
|
|
mWaveBank(nullptr),
|
|
|
|
mIndex(0),
|
|
|
|
mLooped(false)
|
2016-10-29 02:02:21 +03:00
|
|
|
{
|
2018-06-12 01:42:45 +03:00
|
|
|
assert(engine != nullptr);
|
2018-03-16 22:03:02 +03:00
|
|
|
engine->RegisterNotify(this, false);
|
2016-10-29 02:02:21 +03:00
|
|
|
|
2018-06-12 01:42:45 +03:00
|
|
|
assert(mEffect != nullptr);
|
2018-03-16 22:03:02 +03:00
|
|
|
mBase.Initialize(engine, effect->GetFormat(), flags);
|
2016-10-29 02:02:21 +03:00
|
|
|
}
|
|
|
|
|
2018-03-16 22:03:02 +03:00
|
|
|
Impl(_In_ AudioEngine* engine, _In_ WaveBank* waveBank, uint32_t index, SOUND_EFFECT_INSTANCE_FLAGS flags) :
|
2016-10-29 02:02:21 +03:00
|
|
|
mBase(),
|
2018-03-16 22:03:02 +03:00
|
|
|
mEffect(nullptr),
|
|
|
|
mWaveBank(waveBank),
|
|
|
|
mIndex(index),
|
|
|
|
mLooped(false)
|
2016-10-29 02:02:21 +03:00
|
|
|
{
|
2018-06-12 01:42:45 +03:00
|
|
|
assert(engine != nullptr);
|
2018-03-16 22:03:02 +03:00
|
|
|
engine->RegisterNotify(this, false);
|
2016-10-29 02:02:21 +03:00
|
|
|
|
2017-12-08 01:15:18 +03:00
|
|
|
char buff[64] = {};
|
2018-03-16 22:03:02 +03:00
|
|
|
auto wfx = reinterpret_cast<WAVEFORMATEX*>(buff);
|
2018-06-12 01:42:45 +03:00
|
|
|
assert(mWaveBank != nullptr);
|
2018-03-16 22:03:02 +03:00
|
|
|
mBase.Initialize(engine, mWaveBank->GetFormat(index, wfx, sizeof(buff)), flags);
|
2016-10-29 02:02:21 +03:00
|
|
|
}
|
|
|
|
|
2020-03-17 09:19:38 +03:00
|
|
|
Impl(Impl&&) = default;
|
|
|
|
Impl& operator= (Impl&&) = default;
|
|
|
|
|
|
|
|
Impl(Impl const&) = delete;
|
|
|
|
Impl& operator= (Impl const&) = delete;
|
|
|
|
|
2020-03-03 23:52:40 +03:00
|
|
|
~Impl() override
|
2016-10-29 02:02:21 +03:00
|
|
|
{
|
|
|
|
mBase.DestroyVoice();
|
|
|
|
|
2018-03-16 22:03:02 +03:00
|
|
|
if (mBase.engine)
|
2016-10-29 02:02:21 +03:00
|
|
|
{
|
2018-03-16 22:03:02 +03:00
|
|
|
mBase.engine->UnregisterNotify(this, false, false);
|
2016-10-29 02:02:21 +03:00
|
|
|
mBase.engine = nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-16 22:03:02 +03:00
|
|
|
void Play(bool loop);
|
2016-10-29 02:02:21 +03:00
|
|
|
|
|
|
|
// IVoiceNotify
|
2020-03-03 23:52:40 +03:00
|
|
|
void __cdecl OnBufferEnd() override
|
2016-10-29 02:02:21 +03:00
|
|
|
{
|
|
|
|
// We don't register for this notification for SoundEffectInstances, so this should not be invoked
|
2018-03-16 22:03:02 +03:00
|
|
|
assert(false);
|
2016-10-29 02:02:21 +03:00
|
|
|
}
|
|
|
|
|
2020-03-03 23:52:40 +03:00
|
|
|
void __cdecl OnCriticalError() override
|
2016-10-29 02:02:21 +03:00
|
|
|
{
|
|
|
|
mBase.OnCriticalError();
|
|
|
|
}
|
|
|
|
|
2020-03-03 23:52:40 +03:00
|
|
|
void __cdecl OnReset() override
|
2016-10-29 02:02:21 +03:00
|
|
|
{
|
|
|
|
mBase.OnReset();
|
|
|
|
}
|
|
|
|
|
2020-03-03 23:52:40 +03:00
|
|
|
void __cdecl OnUpdate() override
|
2016-10-29 02:02:21 +03:00
|
|
|
{
|
|
|
|
// We do not register for update notification
|
|
|
|
assert(false);
|
|
|
|
}
|
|
|
|
|
2020-03-03 23:52:40 +03:00
|
|
|
void __cdecl OnDestroyEngine() noexcept override
|
2016-10-29 02:02:21 +03:00
|
|
|
{
|
|
|
|
mBase.OnDestroy();
|
|
|
|
}
|
|
|
|
|
2020-03-03 23:52:40 +03:00
|
|
|
void __cdecl OnTrim() override
|
2016-10-29 02:02:21 +03:00
|
|
|
{
|
|
|
|
mBase.OnTrim();
|
|
|
|
}
|
|
|
|
|
2020-03-03 23:52:40 +03:00
|
|
|
void __cdecl GatherStatistics(AudioStatistics& stats) const noexcept override
|
2016-10-29 02:02:21 +03:00
|
|
|
{
|
|
|
|
mBase.GatherStatistics(stats);
|
|
|
|
}
|
|
|
|
|
2020-03-03 23:52:40 +03:00
|
|
|
void __cdecl OnDestroyParent() noexcept override
|
2020-01-20 09:42:00 +03:00
|
|
|
{
|
|
|
|
mBase.OnDestroy();
|
|
|
|
mWaveBank = nullptr;
|
|
|
|
mEffect = nullptr;
|
|
|
|
}
|
|
|
|
|
2016-10-29 02:02:21 +03:00
|
|
|
SoundEffectInstanceBase mBase;
|
|
|
|
SoundEffect* mEffect;
|
|
|
|
WaveBank* mWaveBank;
|
|
|
|
uint32_t mIndex;
|
|
|
|
bool mLooped;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2018-03-16 22:03:02 +03:00
|
|
|
void SoundEffectInstance::Impl::Play(bool loop)
|
2016-10-29 02:02:21 +03:00
|
|
|
{
|
2018-03-16 22:03:02 +03:00
|
|
|
if (!mBase.voice)
|
2016-10-29 02:02:21 +03:00
|
|
|
{
|
2018-03-16 22:03:02 +03:00
|
|
|
if (mWaveBank)
|
2016-10-29 02:02:21 +03:00
|
|
|
{
|
2017-12-08 01:15:18 +03:00
|
|
|
char buff[64] = {};
|
2018-03-16 22:03:02 +03:00
|
|
|
auto wfx = reinterpret_cast<WAVEFORMATEX*>(buff);
|
|
|
|
mBase.AllocateVoice(mWaveBank->GetFormat(mIndex, wfx, sizeof(buff)));
|
2016-10-29 02:02:21 +03:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-06-12 01:42:45 +03:00
|
|
|
assert(mEffect != nullptr);
|
2018-03-16 22:03:02 +03:00
|
|
|
mBase.AllocateVoice(mEffect->GetFormat());
|
2016-10-29 02:02:21 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-16 22:03:02 +03:00
|
|
|
if (!mBase.Play())
|
2016-10-29 02:02:21 +03:00
|
|
|
return;
|
|
|
|
|
|
|
|
// Submit audio data for STOPPED -> PLAYING state transition
|
2020-02-02 01:42:43 +03:00
|
|
|
XAUDIO2_BUFFER buffer = {};
|
2016-10-29 02:02:21 +03:00
|
|
|
|
2020-04-27 00:11:44 +03:00
|
|
|
#ifdef DIRECTX_ENABLE_XWMA
|
2016-10-29 02:02:21 +03:00
|
|
|
|
|
|
|
bool iswma = false;
|
2020-02-02 01:42:43 +03:00
|
|
|
XAUDIO2_BUFFER_WMA wmaBuffer = {};
|
2018-03-16 22:03:02 +03:00
|
|
|
if (mWaveBank)
|
2016-10-29 02:02:21 +03:00
|
|
|
{
|
2018-03-16 22:03:02 +03:00
|
|
|
iswma = mWaveBank->FillSubmitBuffer(mIndex, buffer, wmaBuffer);
|
2016-10-29 02:02:21 +03:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-06-12 01:42:45 +03:00
|
|
|
assert(mEffect != nullptr);
|
2018-03-16 22:03:02 +03:00
|
|
|
iswma = mEffect->FillSubmitBuffer(buffer, wmaBuffer);
|
2016-10-29 02:02:21 +03:00
|
|
|
}
|
|
|
|
|
2020-02-02 01:42:43 +03:00
|
|
|
#else // !xWMA
|
2016-10-29 02:02:21 +03:00
|
|
|
|
2018-03-16 22:03:02 +03:00
|
|
|
if (mWaveBank)
|
2016-10-29 02:02:21 +03:00
|
|
|
{
|
2018-03-16 22:03:02 +03:00
|
|
|
mWaveBank->FillSubmitBuffer(mIndex, buffer);
|
2016-10-29 02:02:21 +03:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-05-25 02:36:18 +03:00
|
|
|
assert(mEffect != nullptr);
|
2018-03-16 22:03:02 +03:00
|
|
|
mEffect->FillSubmitBuffer(buffer);
|
2016-10-29 02:02:21 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
2018-03-16 22:03:02 +03:00
|
|
|
|
2016-10-29 02:02:21 +03:00
|
|
|
buffer.Flags = XAUDIO2_END_OF_STREAM;
|
2018-03-16 22:03:02 +03:00
|
|
|
if (loop)
|
2016-10-29 02:02:21 +03:00
|
|
|
{
|
|
|
|
mLooped = true;
|
|
|
|
buffer.LoopCount = XAUDIO2_LOOP_INFINITE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
mLooped = false;
|
|
|
|
buffer.LoopCount = buffer.LoopBegin = buffer.LoopLength = 0;
|
|
|
|
}
|
|
|
|
buffer.pContext = nullptr;
|
|
|
|
|
|
|
|
HRESULT hr;
|
2022-04-05 01:02:22 +03:00
|
|
|
#ifdef DIRECTX_ENABLE_XWMA
|
2018-03-16 22:03:02 +03:00
|
|
|
if (iswma)
|
2016-10-29 02:02:21 +03:00
|
|
|
{
|
2018-03-16 22:03:02 +03:00
|
|
|
hr = mBase.voice->SubmitSourceBuffer(&buffer, &wmaBuffer);
|
2016-10-29 02:02:21 +03:00
|
|
|
}
|
|
|
|
else
|
2018-03-16 22:03:02 +03:00
|
|
|
#endif
|
2016-10-29 02:02:21 +03:00
|
|
|
{
|
2018-03-16 22:03:02 +03:00
|
|
|
hr = mBase.voice->SubmitSourceBuffer(&buffer, nullptr);
|
2016-10-29 02:02:21 +03:00
|
|
|
}
|
|
|
|
|
2018-03-16 22:03:02 +03:00
|
|
|
if (FAILED(hr))
|
2016-10-29 02:02:21 +03:00
|
|
|
{
|
2018-03-16 22:03:02 +03:00
|
|
|
#ifdef _DEBUG
|
2020-01-20 02:24:50 +03:00
|
|
|
DebugTrace("ERROR: SoundEffectInstance failed (%08X) when submitting buffer:\n", static_cast<unsigned int>(hr));
|
2016-10-29 02:02:21 +03:00
|
|
|
|
2017-12-08 01:15:18 +03:00
|
|
|
char buff[64] = {};
|
2018-03-16 22:03:02 +03:00
|
|
|
auto wfx = (mWaveBank) ? mWaveBank->GetFormat(mIndex, reinterpret_cast<WAVEFORMATEX*>(buff), sizeof(buff))
|
|
|
|
: mEffect->GetFormat();
|
2016-10-29 02:02:21 +03:00
|
|
|
|
2022-02-21 21:11:54 +03:00
|
|
|
const size_t length = (mWaveBank) ? mWaveBank->GetSampleSizeInBytes(mIndex) : mEffect->GetSampleSizeInBytes();
|
2016-10-29 02:02:21 +03:00
|
|
|
|
2020-01-20 02:24:50 +03:00
|
|
|
DebugTrace("\tFormat Tag %u, %u channels, %u-bit, %u Hz, %zu bytes\n",
|
|
|
|
wfx->wFormatTag, wfx->nChannels, wfx->wBitsPerSample, wfx->nSamplesPerSec, length);
|
2018-03-16 22:03:02 +03:00
|
|
|
#endif
|
|
|
|
mBase.Stop(true, mLooped);
|
2021-01-06 00:31:14 +03:00
|
|
|
throw std::runtime_error("SubmitSourceBuffer");
|
2016-10-29 02:02:21 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
|
|
// SoundEffectInstance
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
// Private constructors
|
|
|
|
_Use_decl_annotations_
|
2018-03-16 22:03:02 +03:00
|
|
|
SoundEffectInstance::SoundEffectInstance(AudioEngine* engine, SoundEffect* effect, SOUND_EFFECT_INSTANCE_FLAGS flags) :
|
2018-04-13 21:36:00 +03:00
|
|
|
pImpl(std::make_unique<Impl>(engine, effect, flags))
|
2016-10-29 02:02:21 +03:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
_Use_decl_annotations_
|
2019-05-25 02:36:18 +03:00
|
|
|
SoundEffectInstance::SoundEffectInstance(AudioEngine* engine, WaveBank* waveBank, unsigned int index, SOUND_EFFECT_INSTANCE_FLAGS flags) :
|
2018-04-13 21:36:00 +03:00
|
|
|
pImpl(std::make_unique<Impl>(engine, waveBank, index, flags))
|
2016-10-29 02:02:21 +03:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-10-01 02:55:37 +03:00
|
|
|
// Move ctor/operator.
|
|
|
|
SoundEffectInstance::SoundEffectInstance(SoundEffectInstance&&) noexcept = default;
|
|
|
|
SoundEffectInstance& SoundEffectInstance::operator= (SoundEffectInstance&&) noexcept = default;
|
2016-10-29 02:02:21 +03:00
|
|
|
|
|
|
|
|
|
|
|
// Public destructor.
|
|
|
|
SoundEffectInstance::~SoundEffectInstance()
|
|
|
|
{
|
2018-03-16 22:03:02 +03:00
|
|
|
if (pImpl)
|
2016-10-29 02:02:21 +03:00
|
|
|
{
|
2018-03-16 22:03:02 +03:00
|
|
|
if (pImpl->mWaveBank)
|
2016-10-29 02:02:21 +03:00
|
|
|
{
|
2020-01-20 09:42:00 +03:00
|
|
|
pImpl->mWaveBank->UnregisterInstance(pImpl.get());
|
2016-10-29 02:02:21 +03:00
|
|
|
pImpl->mWaveBank = nullptr;
|
|
|
|
}
|
|
|
|
|
2018-03-16 22:03:02 +03:00
|
|
|
if (pImpl->mEffect)
|
2016-10-29 02:02:21 +03:00
|
|
|
{
|
2020-01-20 09:42:00 +03:00
|
|
|
pImpl->mEffect->UnregisterInstance(pImpl.get());
|
2016-10-29 02:02:21 +03:00
|
|
|
pImpl->mEffect = nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Public methods.
|
2018-03-16 22:03:02 +03:00
|
|
|
void SoundEffectInstance::Play(bool loop)
|
2016-10-29 02:02:21 +03:00
|
|
|
{
|
2018-03-16 22:03:02 +03:00
|
|
|
pImpl->Play(loop);
|
2016-10-29 02:02:21 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-12-13 10:02:12 +03:00
|
|
|
void SoundEffectInstance::Stop(bool immediate) noexcept
|
2016-10-29 02:02:21 +03:00
|
|
|
{
|
2018-03-16 22:03:02 +03:00
|
|
|
pImpl->mBase.Stop(immediate, pImpl->mLooped);
|
2016-10-29 02:02:21 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-12-13 10:02:12 +03:00
|
|
|
void SoundEffectInstance::Pause() noexcept
|
2016-10-29 02:02:21 +03:00
|
|
|
{
|
|
|
|
pImpl->mBase.Pause();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void SoundEffectInstance::Resume()
|
|
|
|
{
|
|
|
|
pImpl->mBase.Resume();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-03-16 22:03:02 +03:00
|
|
|
void SoundEffectInstance::SetVolume(float volume)
|
2016-10-29 02:02:21 +03:00
|
|
|
{
|
2018-03-16 22:03:02 +03:00
|
|
|
pImpl->mBase.SetVolume(volume);
|
2016-10-29 02:02:21 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-03-16 22:03:02 +03:00
|
|
|
void SoundEffectInstance::SetPitch(float pitch)
|
2016-10-29 02:02:21 +03:00
|
|
|
{
|
2018-03-16 22:03:02 +03:00
|
|
|
pImpl->mBase.SetPitch(pitch);
|
2016-10-29 02:02:21 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-03-16 22:03:02 +03:00
|
|
|
void SoundEffectInstance::SetPan(float pan)
|
2016-10-29 02:02:21 +03:00
|
|
|
{
|
2018-03-16 22:03:02 +03:00
|
|
|
pImpl->mBase.SetPan(pan);
|
2016-10-29 02:02:21 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-04-12 23:18:45 +03:00
|
|
|
void SoundEffectInstance::Apply3D(const X3DAUDIO_LISTENER& listener, const X3DAUDIO_EMITTER& emitter, bool rhcoords)
|
2016-10-29 02:02:21 +03:00
|
|
|
{
|
2018-03-16 22:03:02 +03:00
|
|
|
pImpl->mBase.Apply3D(listener, emitter, rhcoords);
|
2016-10-29 02:02:21 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Public accessors.
|
2019-12-13 10:02:12 +03:00
|
|
|
bool SoundEffectInstance::IsLooped() const noexcept
|
2016-10-29 02:02:21 +03:00
|
|
|
{
|
|
|
|
return pImpl->mLooped;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-12-13 10:02:12 +03:00
|
|
|
SoundState SoundEffectInstance::GetState() noexcept
|
2016-10-29 02:02:21 +03:00
|
|
|
{
|
2018-03-16 22:03:02 +03:00
|
|
|
return pImpl->mBase.GetState(true);
|
2016-10-29 02:02:21 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-04-12 23:18:45 +03:00
|
|
|
unsigned int SoundEffectInstance::GetChannelCount() const noexcept
|
|
|
|
{
|
|
|
|
return pImpl->mBase.GetChannelCount();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-01-20 09:42:00 +03:00
|
|
|
IVoiceNotify* SoundEffectInstance::GetVoiceNotify() const noexcept
|
2016-10-29 02:02:21 +03:00
|
|
|
{
|
2020-01-20 09:42:00 +03:00
|
|
|
return pImpl.get();
|
2018-06-07 04:37:54 +03:00
|
|
|
}
|