621 lines
19 KiB
C++
621 lines
19 KiB
C++
//--------------------------------------------------------------------------------------
|
|
// File: SoundEffect.cpp
|
|
//
|
|
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
|
|
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
|
|
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
|
|
// PARTICULAR PURPOSE.
|
|
//
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//
|
|
// http://go.microsoft.com/fwlink/?LinkId=248929
|
|
//--------------------------------------------------------------------------------------
|
|
|
|
#include "pch.h"
|
|
#include "WAVFileReader.h"
|
|
#include "SoundCommon.h"
|
|
|
|
#include <list>
|
|
|
|
#if defined(_XBOX_ONE) && defined(_TITLE)
|
|
#include <apu.h>
|
|
#endif
|
|
|
|
using namespace DirectX;
|
|
|
|
|
|
//======================================================================================
|
|
// SoundEffect
|
|
//======================================================================================
|
|
|
|
// Internal object implementation class.
|
|
class SoundEffect::Impl : public IVoiceNotify
|
|
{
|
|
public:
|
|
explicit Impl( _In_ AudioEngine* engine ) :
|
|
mWaveFormat( nullptr ),
|
|
mStartAudio( nullptr ),
|
|
mAudioBytes( 0 ),
|
|
mLoopStart( 0 ),
|
|
mLoopLength( 0 ),
|
|
mEngine( engine ),
|
|
mOneShots( 0 )
|
|
#if defined(_XBOX_ONE) || (_WIN32_WINNT < _WIN32_WINNT_WIN8) || (_WIN32_WINNT >= _WIN32_WINNT_WIN10)
|
|
, mSeekCount( 0 )
|
|
, mSeekTable( nullptr )
|
|
#endif
|
|
#if defined(_XBOX_ONE) && defined(_TITLE)
|
|
, mXMAMemory( nullptr )
|
|
#endif
|
|
{
|
|
assert( mEngine != 0 );
|
|
mEngine->RegisterNotify( this, false );
|
|
}
|
|
|
|
virtual ~Impl()
|
|
{
|
|
if ( !mInstances.empty() )
|
|
{
|
|
DebugTrace( "WARNING: Destroying SoundEffect with %Iu outstanding SoundEffectInstances\n", mInstances.size() );
|
|
|
|
for( auto it = mInstances.begin(); it != mInstances.end(); ++it )
|
|
{
|
|
assert( *it != 0 );
|
|
(*it)->OnDestroyParent();
|
|
}
|
|
|
|
mInstances.clear();
|
|
}
|
|
|
|
if ( mOneShots > 0 )
|
|
{
|
|
DebugTrace( "WARNING: Destroying SoundEffect with %u outstanding one shot effects\n", mOneShots );
|
|
}
|
|
|
|
if ( mEngine )
|
|
{
|
|
mEngine->UnregisterNotify( this, true, false );
|
|
mEngine = nullptr;
|
|
}
|
|
|
|
#if defined(_XBOX_ONE) && defined(_TITLE)
|
|
if ( mXMAMemory )
|
|
{
|
|
ApuFree( mXMAMemory );
|
|
mXMAMemory = nullptr;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
HRESULT Initialize( _In_ AudioEngine* engine, _Inout_ std::unique_ptr<uint8_t[]>& wavData,
|
|
_In_ const WAVEFORMATEX* wfx, _In_reads_bytes_(audioBytes) const uint8_t* startAudio, size_t audioBytes,
|
|
#if defined(_XBOX_ONE) || (_WIN32_WINNT < _WIN32_WINNT_WIN8) || (_WIN32_WINNT >= _WIN32_WINNT_WIN10)
|
|
_In_reads_opt_(seekCount) const uint32_t* seekTable, size_t seekCount,
|
|
#endif
|
|
uint32_t loopStart, uint32_t loopLength );
|
|
|
|
void Play( float volume, float pitch, float pan );
|
|
|
|
// IVoiceNotify
|
|
virtual void __cdecl OnBufferEnd() override
|
|
{
|
|
InterlockedDecrement( &mOneShots );
|
|
}
|
|
|
|
virtual void __cdecl OnCriticalError() override
|
|
{
|
|
mOneShots = 0;
|
|
}
|
|
|
|
virtual void __cdecl OnReset() override
|
|
{
|
|
// No action required
|
|
}
|
|
|
|
virtual void __cdecl OnUpdate() override
|
|
{
|
|
// We do not register for update notification
|
|
assert(false);
|
|
}
|
|
|
|
virtual void __cdecl OnDestroyEngine() override
|
|
{
|
|
mEngine = nullptr;
|
|
mOneShots = 0;
|
|
}
|
|
|
|
virtual void __cdecl OnTrim() override
|
|
{
|
|
// No action required
|
|
}
|
|
|
|
virtual void __cdecl GatherStatistics( AudioStatistics& stats ) const override
|
|
{
|
|
stats.playingOneShots += mOneShots;
|
|
stats.audioBytes += mAudioBytes;
|
|
|
|
#if defined(_XBOX_ONE) && defined(_TITLE)
|
|
if ( mXMAMemory )
|
|
stats.xmaAudioBytes += mAudioBytes;
|
|
#endif
|
|
}
|
|
|
|
const WAVEFORMATEX* mWaveFormat;
|
|
const uint8_t* mStartAudio;
|
|
uint32_t mAudioBytes;
|
|
uint32_t mLoopStart;
|
|
uint32_t mLoopLength;
|
|
AudioEngine* mEngine;
|
|
std::list<SoundEffectInstance*> mInstances;
|
|
uint32_t mOneShots;
|
|
|
|
#if defined(_XBOX_ONE) || (_WIN32_WINNT < _WIN32_WINNT_WIN8) || (_WIN32_WINNT >= _WIN32_WINNT_WIN10)
|
|
uint32_t mSeekCount;
|
|
const uint32_t* mSeekTable;
|
|
#endif
|
|
|
|
private:
|
|
std::unique_ptr<uint8_t[]> mWavData;
|
|
|
|
#if defined(_XBOX_ONE) && defined(_TITLE)
|
|
void* mXMAMemory;
|
|
#endif
|
|
};
|
|
|
|
|
|
_Use_decl_annotations_
|
|
HRESULT SoundEffect::Impl::Initialize( AudioEngine* engine, std::unique_ptr<uint8_t[]>& wavData,
|
|
const WAVEFORMATEX* wfx, const uint8_t* startAudio, size_t audioBytes,
|
|
#if defined(_XBOX_ONE) || (_WIN32_WINNT < _WIN32_WINNT_WIN8) || (_WIN32_WINNT >= _WIN32_WINNT_WIN10)
|
|
const uint32_t* seekTable, size_t seekCount,
|
|
#endif
|
|
uint32_t loopStart, uint32_t loopLength )
|
|
{
|
|
if ( !engine || !IsValid( wfx ) || !startAudio || !audioBytes || !wavData )
|
|
return E_INVALIDARG;
|
|
|
|
#ifdef _M_X64
|
|
if ( audioBytes > 0xFFFFFFFF )
|
|
return E_INVALIDARG;
|
|
#endif
|
|
|
|
switch( GetFormatTag( wfx ) )
|
|
{
|
|
case WAVE_FORMAT_PCM:
|
|
case WAVE_FORMAT_IEEE_FLOAT:
|
|
case WAVE_FORMAT_ADPCM:
|
|
// Take ownership of the buffer
|
|
mWavData.reset( wavData.release() );
|
|
|
|
// WARNING: We assume the wfx and startAudio parameters are pointers into the wavData memory buffer
|
|
mWaveFormat = wfx;
|
|
mStartAudio = startAudio;
|
|
break;
|
|
|
|
#if defined(_XBOX_ONE) || (_WIN32_WINNT < _WIN32_WINNT_WIN8) || (_WIN32_WINNT >= _WIN32_WINNT_WIN10)
|
|
|
|
case WAVE_FORMAT_WMAUDIO2:
|
|
case WAVE_FORMAT_WMAUDIO3:
|
|
if ( !seekCount || !seekTable )
|
|
{
|
|
DebugTrace( "ERROR: SoundEffect format xWMA requires seek table\n" );
|
|
return E_FAIL;
|
|
}
|
|
|
|
#ifdef _M_X64
|
|
if ( seekCount > 0xFFFFFFFF )
|
|
return E_INVALIDARG;
|
|
#endif
|
|
|
|
// Take ownership of the buffer
|
|
mWavData.reset( wavData.release() );
|
|
|
|
// WARNING: We assume the wfx, startAudio, and mSeekTable parameters are pointers into the wavData memory buffer
|
|
mWaveFormat = wfx;
|
|
mStartAudio = startAudio;
|
|
mSeekCount = static_cast<uint32_t>( seekCount );
|
|
mSeekTable = seekTable;
|
|
break;
|
|
|
|
#endif // _XBOX_ONE || _WIN32_WINNT < _WIN32_WINNT_WIN8 || _WIN32_WINNT >= _WIN32_WINNT_WIN10
|
|
|
|
#if defined(_XBOX_ONE) && defined(_TITLE)
|
|
|
|
case WAVE_FORMAT_XMA2:
|
|
if ( !seekCount || !seekTable )
|
|
{
|
|
DebugTrace( "ERROR: SoundEffect format XMA2 requires seek table\n" );
|
|
return E_FAIL;
|
|
}
|
|
|
|
#ifdef _M_X64
|
|
if ( seekCount > 0xFFFFFFFF )
|
|
return E_INVALIDARG;
|
|
#endif
|
|
|
|
{
|
|
HRESULT hr = ApuAlloc( &mXMAMemory, nullptr,
|
|
static_cast<UINT32>( audioBytes ), SHAPE_XMA_INPUT_BUFFER_ALIGNMENT );
|
|
if ( FAILED(hr) )
|
|
{
|
|
DebugTrace( "ERROR: ApuAlloc failed. Did you allocate a large enough heap with ApuCreateHeap for all your XMA wave data?\n" );
|
|
return hr;
|
|
}
|
|
}
|
|
|
|
memcpy( mXMAMemory, startAudio, audioBytes );
|
|
mStartAudio = reinterpret_cast<const uint8_t*>( mXMAMemory );
|
|
|
|
mWavData.reset( new uint8_t[ sizeof(XMA2WAVEFORMATEX) + ( seekCount * sizeof(uint32_t) ) ] );
|
|
|
|
memcpy( mWavData.get(), wfx, sizeof(XMA2WAVEFORMATEX) );
|
|
mWaveFormat = reinterpret_cast<WAVEFORMATEX*>( mWavData.get() );
|
|
|
|
// XMA seek table is Big-Endian
|
|
{
|
|
auto dest = reinterpret_cast<uint32_t*>( mWavData.get() + sizeof(XMA2WAVEFORMATEX) );
|
|
for( size_t k = 0; k < seekCount; ++k )
|
|
{
|
|
dest[ k ] = _byteswap_ulong( seekTable[ k ]) ;
|
|
}
|
|
}
|
|
|
|
mSeekCount = static_cast<uint32_t>( seekCount );
|
|
mSeekTable = reinterpret_cast<const uint32_t*>( mWavData.get() + sizeof(XMA2WAVEFORMATEX) );
|
|
|
|
wavData.reset();
|
|
break;
|
|
|
|
#endif // _XBOX_ONE && _TITLE
|
|
|
|
default:
|
|
{
|
|
DebugTrace( "ERROR: SoundEffect encountered an unsupported format tag (%u)\n", wfx->wFormatTag );
|
|
return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED );
|
|
}
|
|
}
|
|
|
|
mAudioBytes = static_cast<uint32_t>( audioBytes );
|
|
mLoopStart = loopStart;
|
|
mLoopLength = loopLength;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
void SoundEffect::Impl::Play( float volume, float pitch, float pan )
|
|
{
|
|
assert( volume >= -XAUDIO2_MAX_VOLUME_LEVEL && volume <= XAUDIO2_MAX_VOLUME_LEVEL );
|
|
assert( pitch >= -1.f && pitch <= 1.f );
|
|
assert( pan >= -1.f && pan <= 1.f );
|
|
|
|
IXAudio2SourceVoice* voice = nullptr;
|
|
mEngine->AllocateVoice( mWaveFormat, SoundEffectInstance_Default, true, &voice );
|
|
|
|
if ( !voice )
|
|
return;
|
|
|
|
if ( volume != 1.f )
|
|
{
|
|
HRESULT hr = voice->SetVolume( volume );
|
|
ThrowIfFailed( hr );
|
|
}
|
|
|
|
if ( pitch != 0.f )
|
|
{
|
|
float fr = XAudio2SemitonesToFrequencyRatio( pitch * 12.f );
|
|
|
|
HRESULT hr = voice->SetFrequencyRatio( fr );
|
|
ThrowIfFailed( hr );
|
|
}
|
|
|
|
if ( pan != 0.f )
|
|
{
|
|
float matrix[16];
|
|
if (ComputePan(pan, mWaveFormat->nChannels, matrix))
|
|
{
|
|
HRESULT hr = voice->SetOutputMatrix(nullptr, mWaveFormat->nChannels, mEngine->GetOutputChannels(), matrix);
|
|
ThrowIfFailed( hr );
|
|
}
|
|
}
|
|
|
|
HRESULT hr = voice->Start( 0 );
|
|
ThrowIfFailed( hr );
|
|
|
|
XAUDIO2_BUFFER buffer;
|
|
memset( &buffer, 0, sizeof(buffer) );
|
|
buffer.AudioBytes = mAudioBytes;
|
|
buffer.pAudioData = mStartAudio;
|
|
buffer.Flags = XAUDIO2_END_OF_STREAM;
|
|
buffer.pContext = this;
|
|
|
|
#if defined(_XBOX_ONE) || (_WIN32_WINNT < _WIN32_WINNT_WIN8) || (_WIN32_WINNT >= _WIN32_WINNT_WIN10)
|
|
|
|
uint32_t tag = GetFormatTag( mWaveFormat );
|
|
if ( tag == WAVE_FORMAT_WMAUDIO2 || tag == WAVE_FORMAT_WMAUDIO3 )
|
|
{
|
|
XAUDIO2_BUFFER_WMA wmaBuffer;
|
|
memset( &wmaBuffer, 0, sizeof(wmaBuffer) );
|
|
|
|
wmaBuffer.PacketCount = mSeekCount;
|
|
wmaBuffer.pDecodedPacketCumulativeBytes = mSeekTable;
|
|
|
|
hr = voice->SubmitSourceBuffer( &buffer, &wmaBuffer );
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
hr = voice->SubmitSourceBuffer( &buffer, nullptr );
|
|
}
|
|
if ( FAILED(hr) )
|
|
{
|
|
DebugTrace( "ERROR: SoundEffect failed (%08X) when submitting buffer:\n", hr );
|
|
DebugTrace( "\tFormat Tag %u, %u channels, %u-bit, %u Hz, %u bytes\n", mWaveFormat->wFormatTag,
|
|
mWaveFormat->nChannels, mWaveFormat->wBitsPerSample, mWaveFormat->nSamplesPerSec, mAudioBytes );
|
|
throw std::exception( "SubmitSourceBuffer" );
|
|
}
|
|
|
|
InterlockedIncrement( &mOneShots );
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
// SoundEffect
|
|
//--------------------------------------------------------------------------------------
|
|
|
|
// Public constructors.
|
|
_Use_decl_annotations_
|
|
SoundEffect::SoundEffect( AudioEngine* engine, const wchar_t* waveFileName )
|
|
: pImpl(new Impl(engine) )
|
|
{
|
|
WAVData wavInfo;
|
|
std::unique_ptr<uint8_t[]> wavData;
|
|
HRESULT hr = LoadWAVAudioFromFileEx( waveFileName, wavData, wavInfo );
|
|
if ( FAILED(hr) )
|
|
{
|
|
DebugTrace( "ERROR: SoundEffect failed (%08X) to load from .wav file \"%ls\"\n", hr, waveFileName );
|
|
throw std::exception( "SoundEffect" );
|
|
}
|
|
|
|
#if defined(_XBOX_ONE) || (_WIN32_WINNT < _WIN32_WINNT_WIN8) || (_WIN32_WINNT >= _WIN32_WINNT_WIN10)
|
|
hr = pImpl->Initialize( engine, wavData, wavInfo.wfx, wavInfo.startAudio, wavInfo.audioBytes,
|
|
wavInfo.seek, wavInfo.seekCount,
|
|
wavInfo.loopStart, wavInfo.loopLength );
|
|
#else
|
|
hr = pImpl->Initialize( engine, wavData, wavInfo.wfx, wavInfo.startAudio, wavInfo.audioBytes,
|
|
wavInfo.loopStart, wavInfo.loopLength );
|
|
#endif
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
DebugTrace( "ERROR: SoundEffect failed (%08X) to intialize from .wav file \"%ls\"\n", hr, waveFileName );
|
|
throw std::exception( "SoundEffect" );
|
|
}
|
|
}
|
|
|
|
|
|
_Use_decl_annotations_
|
|
SoundEffect::SoundEffect( AudioEngine* engine, std::unique_ptr<uint8_t[]>& wavData,
|
|
const WAVEFORMATEX* wfx, const uint8_t* startAudio, size_t audioBytes )
|
|
: pImpl(new Impl(engine) )
|
|
{
|
|
#if defined(_XBOX_ONE) || (_WIN32_WINNT < _WIN32_WINNT_WIN8) || (_WIN32_WINNT >= _WIN32_WINNT_WIN10)
|
|
HRESULT hr = pImpl->Initialize( engine, wavData, wfx, startAudio, audioBytes, nullptr, 0, 0, 0 );
|
|
#else
|
|
HRESULT hr = pImpl->Initialize( engine, wavData, wfx, startAudio, audioBytes, 0, 0 );
|
|
#endif
|
|
if ( FAILED(hr) )
|
|
{
|
|
DebugTrace( "ERROR: SoundEffect failed (%08X) to intialize\n", hr );
|
|
throw std::exception( "SoundEffect" );
|
|
}
|
|
}
|
|
|
|
|
|
_Use_decl_annotations_
|
|
SoundEffect::SoundEffect( AudioEngine* engine, std::unique_ptr<uint8_t[]>& wavData,
|
|
const WAVEFORMATEX* wfx, const uint8_t* startAudio, size_t audioBytes,
|
|
uint32_t loopStart, uint32_t loopLength )
|
|
: pImpl(new Impl(engine) )
|
|
{
|
|
#if defined(_XBOX_ONE) || (_WIN32_WINNT < _WIN32_WINNT_WIN8) || (_WIN32_WINNT >= _WIN32_WINNT_WIN10)
|
|
HRESULT hr = pImpl->Initialize( engine, wavData, wfx, startAudio, audioBytes, nullptr, 0, loopStart, loopLength );
|
|
#else
|
|
HRESULT hr = pImpl->Initialize( engine, wavData, wfx, startAudio, audioBytes, loopStart, loopLength );
|
|
#endif
|
|
if ( FAILED(hr) )
|
|
{
|
|
DebugTrace( "ERROR: SoundEffect failed (%08X) to intialize\n", hr );
|
|
throw std::exception( "SoundEffect" );
|
|
}
|
|
}
|
|
|
|
|
|
#if defined(_XBOX_ONE) || (_WIN32_WINNT < _WIN32_WINNT_WIN8) || (_WIN32_WINNT >= _WIN32_WINNT_WIN10)
|
|
|
|
_Use_decl_annotations_
|
|
SoundEffect::SoundEffect( AudioEngine* engine, std::unique_ptr<uint8_t[]>& wavData,
|
|
const WAVEFORMATEX* wfx, const uint8_t* startAudio, size_t audioBytes,
|
|
const uint32_t* seekTable, size_t seekCount )
|
|
{
|
|
HRESULT hr = pImpl->Initialize( engine, wavData, wfx, startAudio, audioBytes, seekTable, seekCount, 0, 0 );
|
|
if ( FAILED(hr) )
|
|
{
|
|
DebugTrace( "ERROR: SoundEffect failed (%08X) to intialize\n", hr );
|
|
throw std::exception( "SoundEffect" );
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
// Move constructor.
|
|
SoundEffect::SoundEffect(SoundEffect&& moveFrom)
|
|
: pImpl(std::move(moveFrom.pImpl))
|
|
{
|
|
}
|
|
|
|
|
|
// Move assignment.
|
|
SoundEffect& SoundEffect::operator= (SoundEffect&& moveFrom)
|
|
{
|
|
pImpl = std::move(moveFrom.pImpl);
|
|
return *this;
|
|
}
|
|
|
|
|
|
// Public destructor.
|
|
SoundEffect::~SoundEffect()
|
|
{
|
|
}
|
|
|
|
|
|
// Public methods.
|
|
void SoundEffect::Play()
|
|
{
|
|
pImpl->Play( 1.f, 0.f, 0.f );
|
|
}
|
|
|
|
|
|
void SoundEffect::Play( float volume, float pitch, float pan )
|
|
{
|
|
pImpl->Play( volume, pitch, pan );
|
|
}
|
|
|
|
|
|
std::unique_ptr<SoundEffectInstance> SoundEffect::CreateInstance( SOUND_EFFECT_INSTANCE_FLAGS flags )
|
|
{
|
|
auto effect = new SoundEffectInstance( pImpl->mEngine, this, flags );
|
|
assert( effect != 0 );
|
|
pImpl->mInstances.emplace_back( effect );
|
|
return std::unique_ptr<SoundEffectInstance>( effect );
|
|
}
|
|
|
|
|
|
void SoundEffect::UnregisterInstance( _In_ SoundEffectInstance* instance )
|
|
{
|
|
auto it = std::find( pImpl->mInstances.begin(), pImpl->mInstances.end(), instance );
|
|
if ( it == pImpl->mInstances.end() )
|
|
return;
|
|
|
|
pImpl->mInstances.erase( it );
|
|
}
|
|
|
|
|
|
// Public accessors.
|
|
bool SoundEffect::IsInUse() const
|
|
{
|
|
return ( pImpl->mOneShots > 0 ) || !pImpl->mInstances.empty();
|
|
}
|
|
|
|
|
|
size_t SoundEffect::GetSampleSizeInBytes() const
|
|
{
|
|
return pImpl->mAudioBytes;
|
|
}
|
|
|
|
|
|
size_t SoundEffect::GetSampleDuration() const
|
|
{
|
|
if ( !pImpl->mWaveFormat || !pImpl->mWaveFormat->nChannels )
|
|
return 0;
|
|
|
|
switch( GetFormatTag( pImpl->mWaveFormat ) )
|
|
{
|
|
case WAVE_FORMAT_ADPCM:
|
|
{
|
|
auto adpcmFmt = reinterpret_cast<const ADPCMWAVEFORMAT*>( pImpl->mWaveFormat );
|
|
|
|
uint64_t duration = uint64_t( pImpl->mAudioBytes / adpcmFmt->wfx.nBlockAlign ) * adpcmFmt->wSamplesPerBlock;
|
|
int partial = pImpl->mAudioBytes % adpcmFmt->wfx.nBlockAlign;
|
|
if ( partial )
|
|
{
|
|
if ( partial >= ( 7 * adpcmFmt->wfx.nChannels ) )
|
|
duration += ( partial * 2 / adpcmFmt->wfx.nChannels - 12 );
|
|
}
|
|
return static_cast<size_t>( duration );
|
|
}
|
|
|
|
#if defined(_XBOX_ONE) || (_WIN32_WINNT < _WIN32_WINNT_WIN8) || (_WIN32_WINNT >= _WIN32_WINNT_WIN10)
|
|
|
|
case WAVE_FORMAT_WMAUDIO2:
|
|
case WAVE_FORMAT_WMAUDIO3:
|
|
if ( pImpl->mSeekTable && pImpl->mSeekCount > 0 )
|
|
{
|
|
return pImpl->mSeekTable[ pImpl->mSeekCount - 1 ] / uint32_t( 2 * pImpl->mWaveFormat->nChannels );
|
|
}
|
|
break;
|
|
|
|
#endif
|
|
|
|
#if defined(_XBOX_ONE) && defined(_TITLE)
|
|
|
|
case WAVE_FORMAT_XMA2:
|
|
return reinterpret_cast<const XMA2WAVEFORMATEX*>( pImpl->mWaveFormat )->SamplesEncoded;
|
|
|
|
#endif
|
|
|
|
default:
|
|
if ( pImpl->mWaveFormat->wBitsPerSample > 0 )
|
|
{
|
|
return static_cast<size_t>( ( uint64_t( pImpl->mAudioBytes ) * 8 )
|
|
/ uint64_t( pImpl->mWaveFormat->wBitsPerSample * pImpl->mWaveFormat->nChannels ) );
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
size_t SoundEffect::GetSampleDurationMS() const
|
|
{
|
|
if ( !pImpl->mWaveFormat || !pImpl->mWaveFormat->nSamplesPerSec )
|
|
return 0;
|
|
|
|
uint64_t samples = GetSampleDuration();
|
|
return static_cast<size_t>( ( samples * 1000 ) / pImpl->mWaveFormat->nSamplesPerSec );
|
|
}
|
|
|
|
|
|
const WAVEFORMATEX* SoundEffect::GetFormat() const
|
|
{
|
|
return pImpl->mWaveFormat;
|
|
}
|
|
|
|
|
|
#if defined(_XBOX_ONE) || (_WIN32_WINNT < _WIN32_WINNT_WIN8) || (_WIN32_WINNT >= _WIN32_WINNT_WIN10)
|
|
|
|
bool SoundEffect::FillSubmitBuffer( _Out_ XAUDIO2_BUFFER& buffer, _Out_ XAUDIO2_BUFFER_WMA& wmaBuffer ) const
|
|
{
|
|
memset( &buffer, 0, sizeof(buffer) );
|
|
memset( &wmaBuffer, 0, sizeof(wmaBuffer) );
|
|
|
|
buffer.AudioBytes = pImpl->mAudioBytes;
|
|
buffer.pAudioData = pImpl->mStartAudio;
|
|
buffer.LoopBegin = pImpl->mLoopStart;
|
|
buffer.LoopLength = pImpl->mLoopLength;
|
|
|
|
uint32_t tag = GetFormatTag( pImpl->mWaveFormat );
|
|
if ( tag == WAVE_FORMAT_WMAUDIO2 || tag == WAVE_FORMAT_WMAUDIO3 )
|
|
{
|
|
wmaBuffer.PacketCount = pImpl->mSeekCount;
|
|
wmaBuffer.pDecodedPacketCumulativeBytes = pImpl->mSeekTable;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
#else
|
|
|
|
void SoundEffect::FillSubmitBuffer( _Out_ XAUDIO2_BUFFER& buffer ) const
|
|
{
|
|
memset( &buffer, 0, sizeof(buffer) );
|
|
buffer.AudioBytes = pImpl->mAudioBytes;
|
|
buffer.pAudioData = pImpl->mStartAudio;
|
|
buffer.LoopBegin = pImpl->mLoopStart;
|
|
buffer.LoopLength = pImpl->mLoopLength;
|
|
}
|
|
|
|
#endif
|