DirectXTK12/Audio/SoundEffectInstance.cpp

338 строки
7.9 KiB
C++
Исходник Постоянная ссылка Обычный вид История

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
{
assert(engine != nullptr);
2018-03-16 22:03:02 +03:00
engine->RegisterNotify(this, false);
2016-10-29 02:02:21 +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
{
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);
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
}
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
{
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
{
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
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;
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
{
assert(mEffect != nullptr);
2018-03-16 22:03:02 +03:00
iswma = mEffect->FillSubmitBuffer(buffer, wmaBuffer);
2016-10-29 02:02:21 +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
{
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;
#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_
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
{
}
// 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
{
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
{
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
}
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
}
unsigned int SoundEffectInstance::GetChannelCount() const noexcept
{
return pImpl->mBase.GetChannelCount();
}
IVoiceNotify* SoundEffectInstance::GetVoiceNotify() const noexcept
2016-10-29 02:02:21 +03:00
{
return pImpl.get();
2018-06-07 04:37:54 +03:00
}