Replace XAudio2 implementation with an unified Xaudio2Redist

This removes dual implementation for 2.7 and 2.8/2.9 interfaces
and also removes reliance on DirectX End User Runtimes for Windows 7.
This commit is contained in:
Silent 2020-02-17 22:31:49 +01:00 committed by Ivan
parent 0dd417e5f2
commit 312fc94daa
17 changed files with 473 additions and 3051 deletions

View File

@ -7,11 +7,31 @@
*
**************************************************************************/
#ifdef _MSC_VER
#pragma once
#endif
#ifndef __XAUDIO2_INCLUDED__
#define __XAUDIO2_INCLUDED__
#include <sdkddkver.h>
// Current name of the DLL shipped in the same SDK as this header.
// The name reflects the current version
#define XAUDIO2_DLL_A "xaudio2redist.dll"
#define XAUDIO2_DLL_W L"xaudio2redist.dll"
#define XAUDIO2D_DLL_A "xaudio2redist.dll"
#define XAUDIO2D_DLL_W L"xaudio2redist.dll"
#ifdef UNICODE
#define XAUDIO2_DLL XAUDIO2_DLL_W
#define XAUDIO2D_DLL XAUDIO2D_DLL_W
#else
#define XAUDIO2_DLL XAUDIO2_DLL_A
#define XAUDIO2D_DLL XAUDIO2D_DLL_A
#endif
/**************************************************************************
*
* XAudio2 COM object class and interface IDs.
@ -20,8 +40,19 @@
#include <basetyps.h>
// XAudio 2.8
interface __declspec(uuid("60d8dac8-5aa1-4e8e-b597-2f5e2883d484")) IXAudio2;
#ifdef __cplusplus
// XAudio 2.9
interface __declspec(uuid("2B02E3CF-2E0B-4ec3-BE45-1B2A3FE7210D")) IXAudio2;
interface __declspec(uuid("84ac29bb-d619-44d2-b197-e4acf7df3ed6")) IXAudio2Extension;
EXTERN_C const GUID DECLSPEC_SELECTANY IID_IXAudio2Extension = __uuidof(IXAudio2Extension);
EXTERN_C const GUID DECLSPEC_SELECTANY IID_IXAudio2 = __uuidof(IXAudio2);
#else // #ifdef __cplusplus
// Compiling with C for Windows 10 and later
DEFINE_GUID(IID_IXAudio2, 0x2B02E3CF, 0x2E0B, 0x4ec3, 0xBE, 0x45, 0x1B, 0x2A, 0x3F, 0xE7, 0x21, 0x0D);
DEFINE_GUID(IID_IXAudio2Extension, 0x84ac29bb, 0xd619, 0x44d2, 0xb1, 0x97, 0xe4, 0xac, 0xf7, 0xdf, 0x3e, 0xd6);
#endif // #ifdef __cplusplus
// Ignore the rest of this header if only the GUID definitions were requested
#ifndef GUID_DEFS_ONLY
@ -31,6 +62,31 @@ interface __declspec(uuid("60d8dac8-5aa1-4e8e-b597-2f5e2883d484")) IXAudio2;
#include <mmreg.h> // Basic data types and constants for audio work
#include <audiosessiontypes.h> // For AUDIO_STREAM_CATEGORY
// The Windows 7 version of audiosessiontypes.h does not define AUDIO_STREAM_CATEGORY, so if we are targeting
// Windows 7 we might have to define it here, depending on which SDK is used.
#if _WIN32_WINNT < _WIN32_WINNT_WIN8
// If we are compiling for Windows 7, we might be using the Windows 7 Platform SDK, which does not have AUDIO_STREAM_CATEGORY.
// But we might be using a newer SDK (such as the Win8 Platform SDK), which has AUDIO_STREAM_CATEGORY.
// Determine if we are using the Windows 7 Platform SDK by checking if WAVE_FORMAT_WM9_SPECTRUM_ANALYZER is defined.
#ifndef WAVE_FORMAT_WM9_SPECTRUM_ANALYZER
typedef enum _AUDIO_STREAM_CATEGORY
{
AudioCategory_Other = 0,
AudioCategory_ForegroundOnlyMedia = 1,
AudioCategory_Communications = 3,
AudioCategory_Alerts = 4,
AudioCategory_SoundEffects = 5,
AudioCategory_GameEffects = 6,
AudioCategory_GameMedia = 7,
AudioCategory_GameChat = 8,
AudioCategory_Speech = 9,
AudioCategory_Movie = 10,
AudioCategory_Media = 11,
} AUDIO_STREAM_CATEGORY;
#endif /* WAVE_FORMAT_WM9_SPECTRUM_ANALYZER */
#endif /* NTDDI_VERSION < NTDDI_WIN8 */
// All structures defined in this file use tight field packing
#pragma pack(push, 1)
@ -99,10 +155,10 @@ interface __declspec(uuid("60d8dac8-5aa1-4e8e-b597-2f5e2883d484")) IXAudio2;
// XAudio2 error codes
#define FACILITY_XAUDIO2 0x896
#define XAUDIO2_E_INVALID_CALL 0x88960001 // An API call or one of its arguments was illegal
#define XAUDIO2_E_XMA_DECODER_ERROR 0x88960002 // The XMA hardware suffered an unrecoverable error
#define XAUDIO2_E_XAPO_CREATION_FAILED 0x88960003 // XAudio2 failed to initialize an XAPO effect
#define XAUDIO2_E_DEVICE_INVALIDATED 0x88960004 // An audio device became unusable (unplugged, etc)
#define XAUDIO2_E_INVALID_CALL ((HRESULT)0x88960001) // An API call or one of its arguments was illegal
#define XAUDIO2_E_XMA_DECODER_ERROR ((HRESULT)0x88960002) // The XMA hardware suffered an unrecoverable error
#define XAUDIO2_E_XAPO_CREATION_FAILED ((HRESULT)0x88960003) // XAudio2 failed to initialize an XAPO effect
#define XAUDIO2_E_DEVICE_INVALIDATED ((HRESULT)0x88960004) // An audio device became unusable (unplugged, etc)
/**************************************************************************
*
@ -166,6 +222,13 @@ typedef UINT32 XAUDIO2_PROCESSOR;
#define Processor31 0x40000000
#define Processor32 0x80000000
#define XAUDIO2_ANY_PROCESSOR 0xffffffff
// This value indicates that XAudio2 will choose the default processor by itself. The actual value chosen
// may vary depending on the hardware platform.
#define XAUDIO2_USE_DEFAULT_PROCESSOR 0x00000000
// This definition is included for backwards compatibilty. New implementations should use
// XAUDIO2_USE_DEFAULT_PROCESSOR instead to let XAudio2 select the appropriate default processor for the hardware platform.
#define XAUDIO2_DEFAULT_PROCESSOR Processor1
// Returned by IXAudio2Voice::GetVoiceDetails
@ -359,13 +422,13 @@ DECLARE_INTERFACE_(IXAudio2, IUnknown)
{
// NAME: IXAudio2::QueryInterface
// DESCRIPTION: Queries for a given COM interface on the XAudio2 object.
// Only IID_IUnknown and IID_IXAudio2 are supported.
// Only IID_IUnknown, IID_IXAudio2 and IID_IXaudio2Extension are supported.
//
// ARGUMENTS:
// riid - IID of the interface to be obtained.
// ppvInterface - Returns a pointer to the requested interface.
//
STDMETHOD(QueryInterface) (THIS_ REFIID riid, _Outptr_ void** ppvInterface) PURE;
STDMETHOD(QueryInterface) (THIS_ REFIID riid, _COM_Outptr_ void** ppvInterface) PURE;
// NAME: IXAudio2::AddRef
// DESCRIPTION: Adds a reference to the XAudio2 object.
@ -489,6 +552,50 @@ DECLARE_INTERFACE_(IXAudio2, IUnknown)
_Reserved_ void* pReserved X2DEFAULT(NULL)) PURE;
};
// This interface extends IXAudio2 with additional functionality.
// Use IXAudio2::QueryInterface to obtain a pointer to this interface.
#undef INTERFACE
#define INTERFACE IXAudio2Extension
DECLARE_INTERFACE_(IXAudio2Extension, IUnknown)
{
// NAME: IXAudio2Extension::QueryInterface
// DESCRIPTION: Queries for a given COM interface on the XAudio2 object.
// Only IID_IUnknown, IID_IXAudio2 and IID_IXaudio2Extension are supported.
//
// ARGUMENTS:
// riid - IID of the interface to be obtained.
// ppvInterface - Returns a pointer to the requested interface.
//
STDMETHOD(QueryInterface) (THIS_ REFIID riid, _COM_Outptr_ void** ppvInterface) PURE;
// NAME: IXAudio2Extension::AddRef
// DESCRIPTION: Adds a reference to the XAudio2 object.
//
STDMETHOD_(ULONG, AddRef) (THIS) PURE;
// NAME: IXAudio2Extension::Release
// DESCRIPTION: Releases a reference to the XAudio2 object.
//
STDMETHOD_(ULONG, Release) (THIS) PURE;
// NAME: IXAudio2Extension::GetProcessingQuantum
// DESCRIPTION: Returns the processing quantum
// quantumMilliseconds = (1000.0f * quantumNumerator / quantumDenominator)
//
// ARGUMENTS:
// quantumNumerator - Quantum numerator
// quantumDenominator - Quantum denominator
//
STDMETHOD_(void, GetProcessingQuantum)(THIS_ _Out_ UINT32* quantumNumerator, _Out_range_(!= , 0) UINT32* quantumDenominator);
// NAME: IXAudio2Extension::GetProcessor
// DESCRIPTION: Returns the number of the processor used by XAudio2
//
// ARGUMENTS:
// processor - Non-zero Processor number
//
STDMETHOD_(void, GetProcessor)(THIS_ _Out_range_(!= , 0) XAUDIO2_PROCESSOR* processor);
};
/**************************************************************************
*
@ -949,6 +1056,10 @@ DECLARE_INTERFACE(IXAudio2VoiceCallback)
#define IXAudio2_GetPerformanceData(This,pPerfData) ((This)->lpVtbl->GetPerformanceData(This,pPerfData))
#define IXAudio2_SetDebugConfiguration(This,pDebugConfiguration,pReserved) ((This)->lpVtbl->SetDebugConfiguration(This,pDebugConfiguration,pReserved))
// IXAudio2Extension
#define IXAudio2Extension_GetProcessingQuantum(This,quantumNumerator,quantumDenominator) ((This)->lpVtbl->GetProcessingQuantum(This,quantumNumerator,quantumDenominator))
#define IXAudio2Extension_GetProcessor(This,processor) ((This)->lpVtbl->GetProcessor(This,processor))
// IXAudio2Voice
#define IXAudio2Voice_GetVoiceDetails(This,pVoiceDetails) ((This)->lpVtbl->GetVoiceDetails(This,pVoiceDetails))
#define IXAudio2Voice_SetOutputVoices(This,pSendList) ((This)->lpVtbl->SetOutputVoices(This,pSendList))
@ -1143,12 +1254,16 @@ __inline float XAudio2CutoffFrequencyToOnePoleCoefficient(float CutoffFrequency,
* will use. Note that XAudio2 supports concurrent processing on
* multiple threads, using any combination of XAUDIO2_PROCESSOR
* flags. The values are platform-specific; platform-independent
* code can use XAUDIO2_DEFAULT_PROCESSOR to use the default on
* code can use XAUDIO2_USE_DEFAULT_PROCESSOR to use the default on
* each platform.
*
**************************************************************************/
typedef HRESULT(*XAudio2Create)(_Outptr_ IXAudio2** ppXAudio2, UINT32 Flags, XAUDIO2_PROCESSOR XAudio2Processor);
// We're an xaudio2 client
#define XAUDIO2_STDAPI EXTERN_C DECLSPEC_IMPORT HRESULT STDAPICALLTYPE
XAUDIO2_STDAPI XAudio2Create(_Outptr_ IXAudio2** ppXAudio2, UINT32 Flags X2DEFAULT(0),
XAUDIO2_PROCESSOR XAudio2Processor X2DEFAULT(XAUDIO2_USE_DEFAULT_PROCESSOR));
// Undo the #pragma pack(push, 1) directive at the top of this file
#pragma pack(pop)
@ -1156,3 +1271,4 @@ typedef HRESULT(*XAudio2Create)(_Outptr_ IXAudio2** ppXAudio2, UINT32 Flags, XAU
#endif // #ifndef GUID_DEFS_ONLY
#endif // #ifndef __XAUDIO2_INCLUDED__

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@ -1,263 +0,0 @@
/***************************************************************************
*
* Copyright (c) Microsoft Corporation. All rights reserved.
*
* File: audiodefs.h
* Content: Basic constants and data types for audio work.
*
* Remarks: This header file defines all of the audio format constants and
* structures required for XAudio2 and XACT work. Providing these
* in a single location avoids certain dependency problems in the
* legacy audio headers (mmreg.h, mmsystem.h, ksmedia.h).
*
* NOTE: Including the legacy headers after this one may cause a
* compilation error, because they define some of the same types
* defined here without preprocessor guards to avoid multiple
* definitions. If a source file needs one of the old headers,
* it must include it before including audiodefs.h.
*
***************************************************************************/
#ifndef __AUDIODEFS_INCLUDED__
#define __AUDIODEFS_INCLUDED__
#include <windef.h> // For WORD, DWORD, etc.
#pragma pack(push, 1) // Pack structures to 1-byte boundaries
/**************************************************************************
*
* WAVEFORMATEX: Base structure for many audio formats. Format-specific
* extensions can be defined for particular formats by using a non-zero
* cbSize value and adding extra fields to the end of this structure.
*
***************************************************************************/
#ifndef _WAVEFORMATEX_
#define _WAVEFORMATEX_
typedef struct tWAVEFORMATEX
{
WORD wFormatTag; // Integer identifier of the format
WORD nChannels; // Number of audio channels
DWORD nSamplesPerSec; // Audio sample rate
DWORD nAvgBytesPerSec; // Bytes per second (possibly approximate)
WORD nBlockAlign; // Size in bytes of a sample block (all channels)
WORD wBitsPerSample; // Size in bits of a single per-channel sample
WORD cbSize; // Bytes of extra data appended to this struct
} WAVEFORMATEX;
#endif
// Defining pointer types outside of the #if block to make sure they are
// defined even if mmreg.h or mmsystem.h is #included before this file
typedef WAVEFORMATEX *PWAVEFORMATEX, *NPWAVEFORMATEX, *LPWAVEFORMATEX;
typedef const WAVEFORMATEX *PCWAVEFORMATEX, *LPCWAVEFORMATEX;
/**************************************************************************
*
* WAVEFORMATEXTENSIBLE: Extended version of WAVEFORMATEX that should be
* used as a basis for all new audio formats. The format tag is replaced
* with a GUID, allowing new formats to be defined without registering a
* format tag with Microsoft. There are also new fields that can be used
* to specify the spatial positions for each channel and the bit packing
* used for wide samples (e.g. 24-bit PCM samples in 32-bit containers).
*
***************************************************************************/
#ifndef _WAVEFORMATEXTENSIBLE_
#define _WAVEFORMATEXTENSIBLE_
typedef struct
{
WAVEFORMATEX Format; // Base WAVEFORMATEX data
union
{
WORD wValidBitsPerSample; // Valid bits in each sample container
WORD wSamplesPerBlock; // Samples per block of audio data; valid
// if wBitsPerSample=0 (but rarely used).
WORD wReserved; // Zero if neither case above applies.
} Samples;
DWORD dwChannelMask; // Positions of the audio channels
GUID SubFormat; // Format identifier GUID
} WAVEFORMATEXTENSIBLE;
#endif
typedef WAVEFORMATEXTENSIBLE *PWAVEFORMATEXTENSIBLE, *LPWAVEFORMATEXTENSIBLE;
typedef const WAVEFORMATEXTENSIBLE *PCWAVEFORMATEXTENSIBLE, *LPCWAVEFORMATEXTENSIBLE;
/**************************************************************************
*
* Define the most common wave format tags used in WAVEFORMATEX formats.
*
***************************************************************************/
#ifndef WAVE_FORMAT_PCM // Pulse Code Modulation
// If WAVE_FORMAT_PCM is not defined, we need to define some legacy types
// for compatibility with the Windows mmreg.h / mmsystem.h header files.
// Old general format structure (information common to all formats)
typedef struct waveformat_tag
{
WORD wFormatTag;
WORD nChannels;
DWORD nSamplesPerSec;
DWORD nAvgBytesPerSec;
WORD nBlockAlign;
} WAVEFORMAT, *PWAVEFORMAT, NEAR *NPWAVEFORMAT, FAR *LPWAVEFORMAT;
// Specific format structure for PCM data
typedef struct pcmwaveformat_tag
{
WAVEFORMAT wf;
WORD wBitsPerSample;
} PCMWAVEFORMAT, *PPCMWAVEFORMAT, NEAR *NPPCMWAVEFORMAT, FAR *LPPCMWAVEFORMAT;
#define WAVE_FORMAT_PCM 0x0001
#endif
#ifndef WAVE_FORMAT_ADPCM // Microsoft Adaptive Differental PCM
// Replicate the Microsoft ADPCM type definitions from mmreg.h.
typedef struct adpcmcoef_tag
{
short iCoef1;
short iCoef2;
} ADPCMCOEFSET;
#pragma warning(push)
#pragma warning(disable:4200) // Disable zero-sized array warnings
typedef struct adpcmwaveformat_tag {
WAVEFORMATEX wfx;
WORD wSamplesPerBlock;
WORD wNumCoef;
ADPCMCOEFSET aCoef[]; // Always 7 coefficient pairs for MS ADPCM
} ADPCMWAVEFORMAT;
#pragma warning(pop)
#define WAVE_FORMAT_ADPCM 0x0002
#endif
// Other frequently used format tags
#ifndef WAVE_FORMAT_UNKNOWN
#define WAVE_FORMAT_UNKNOWN 0x0000 // Unknown or invalid format tag
#endif
#ifndef WAVE_FORMAT_IEEE_FLOAT
#define WAVE_FORMAT_IEEE_FLOAT 0x0003 // 32-bit floating-point
#endif
#ifndef WAVE_FORMAT_MPEGLAYER3
#define WAVE_FORMAT_MPEGLAYER3 0x0055 // ISO/MPEG Layer3
#endif
#ifndef WAVE_FORMAT_DOLBY_AC3_SPDIF
#define WAVE_FORMAT_DOLBY_AC3_SPDIF 0x0092 // Dolby Audio Codec 3 over S/PDIF
#endif
#ifndef WAVE_FORMAT_WMAUDIO2
#define WAVE_FORMAT_WMAUDIO2 0x0161 // Windows Media Audio
#endif
#ifndef WAVE_FORMAT_WMAUDIO3
#define WAVE_FORMAT_WMAUDIO3 0x0162 // Windows Media Audio Pro
#endif
#ifndef WAVE_FORMAT_WMASPDIF
#define WAVE_FORMAT_WMASPDIF 0x0164 // Windows Media Audio over S/PDIF
#endif
#ifndef WAVE_FORMAT_EXTENSIBLE
#define WAVE_FORMAT_EXTENSIBLE 0xFFFE // All WAVEFORMATEXTENSIBLE formats
#endif
/**************************************************************************
*
* Define the most common wave format GUIDs used in WAVEFORMATEXTENSIBLE
* formats. Note that including the Windows ksmedia.h header after this
* one will cause build problems; this cannot be avoided, since ksmedia.h
* defines these macros without preprocessor guards.
*
***************************************************************************/
#ifdef __cplusplus // uuid() and __uuidof() are only available in C++
#ifndef KSDATAFORMAT_SUBTYPE_PCM
struct __declspec(uuid("00000001-0000-0010-8000-00aa00389b71")) KSDATAFORMAT_SUBTYPE_PCM_STRUCT;
#define KSDATAFORMAT_SUBTYPE_PCM __uuidof(KSDATAFORMAT_SUBTYPE_PCM_STRUCT)
#endif
#ifndef KSDATAFORMAT_SUBTYPE_ADPCM
struct __declspec(uuid("00000002-0000-0010-8000-00aa00389b71")) KSDATAFORMAT_SUBTYPE_ADPCM_STRUCT;
#define KSDATAFORMAT_SUBTYPE_ADPCM __uuidof(KSDATAFORMAT_SUBTYPE_ADPCM_STRUCT)
#endif
#ifndef KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
struct __declspec(uuid("00000003-0000-0010-8000-00aa00389b71")) KSDATAFORMAT_SUBTYPE_IEEE_FLOAT_STRUCT;
#define KSDATAFORMAT_SUBTYPE_IEEE_FLOAT __uuidof(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT_STRUCT)
#endif
#endif
/**************************************************************************
*
* Speaker positions used in the WAVEFORMATEXTENSIBLE dwChannelMask field.
*
***************************************************************************/
#ifndef SPEAKER_FRONT_LEFT
#define SPEAKER_FRONT_LEFT 0x00000001
#define SPEAKER_FRONT_RIGHT 0x00000002
#define SPEAKER_FRONT_CENTER 0x00000004
#define SPEAKER_LOW_FREQUENCY 0x00000008
#define SPEAKER_BACK_LEFT 0x00000010
#define SPEAKER_BACK_RIGHT 0x00000020
#define SPEAKER_FRONT_LEFT_OF_CENTER 0x00000040
#define SPEAKER_FRONT_RIGHT_OF_CENTER 0x00000080
#define SPEAKER_BACK_CENTER 0x00000100
#define SPEAKER_SIDE_LEFT 0x00000200
#define SPEAKER_SIDE_RIGHT 0x00000400
#define SPEAKER_TOP_CENTER 0x00000800
#define SPEAKER_TOP_FRONT_LEFT 0x00001000
#define SPEAKER_TOP_FRONT_CENTER 0x00002000
#define SPEAKER_TOP_FRONT_RIGHT 0x00004000
#define SPEAKER_TOP_BACK_LEFT 0x00008000
#define SPEAKER_TOP_BACK_CENTER 0x00010000
#define SPEAKER_TOP_BACK_RIGHT 0x00020000
#define SPEAKER_RESERVED 0x7FFC0000
#define SPEAKER_ALL 0x80000000
#define _SPEAKER_POSITIONS_
#endif
#ifndef SPEAKER_STEREO
#define SPEAKER_MONO (SPEAKER_FRONT_CENTER)
#define SPEAKER_STEREO (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT)
#define SPEAKER_2POINT1 (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_LOW_FREQUENCY)
#define SPEAKER_SURROUND (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_BACK_CENTER)
#define SPEAKER_QUAD (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT)
#define SPEAKER_4POINT1 (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT)
#define SPEAKER_5POINT1 (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT)
#define SPEAKER_7POINT1 (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT | SPEAKER_FRONT_LEFT_OF_CENTER | SPEAKER_FRONT_RIGHT_OF_CENTER)
#define SPEAKER_5POINT1_SURROUND (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_SIDE_LEFT | SPEAKER_SIDE_RIGHT)
#define SPEAKER_7POINT1_SURROUND (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT | SPEAKER_SIDE_LEFT | SPEAKER_SIDE_RIGHT)
#endif
#pragma pack(pop)
#endif // #ifndef __AUDIODEFS_INCLUDED__

View File

@ -1,65 +0,0 @@
// comdecl.h: Macros to facilitate COM interface and GUID declarations.
// Copyright (c) Microsoft Corporation. All rights reserved.
#ifndef _COMDECL_H_
#define _COMDECL_H_
#ifndef _XBOX
#include <basetyps.h> // For standard COM interface macros
#else
#pragma warning(push)
#pragma warning(disable:4061)
#include <xtl.h> // Required by xobjbase.h
#include <xobjbase.h> // Special definitions for Xbox build
#pragma warning(pop)
#endif
// The DEFINE_CLSID() and DEFINE_IID() macros defined below allow COM GUIDs to
// be declared and defined in such a way that clients can obtain the GUIDs using
// either the __uuidof() extension or the old-style CLSID_Foo / IID_IFoo names.
// If using the latter approach, the client can also choose whether to get the
// GUID definitions by defining the INITGUID preprocessor constant or by linking
// to a GUID library. This works in either C or C++.
#ifndef _MSC_VER
#define DEFINE_UUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) __CRT_UUID_DECL(name, 0x##l, 0x##w1, 0x##w2, 0x##b1, 0x##b2, 0x##b3, 0x##b4, 0x##b5, 0x##b6, 0x##b7, 0x##b8)
#define DEFINE_CLSID(className, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) class className; DEFINE_UUID(className, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8)
#define DEFINE_IID(interfaceName, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) struct interfaceName; DEFINE_UUID(interfaceName, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8)
#elif __cplusplus
#define DECLSPEC_UUID_WRAPPER(x) __declspec(uuid(#x))
#ifdef INITGUID
#define DEFINE_CLSID(className, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
class DECLSPEC_UUID_WRAPPER(l##-##w1##-##w2##-##b1##b2##-##b3##b4##b5##b6##b7##b8) className; \
EXTERN_C const GUID DECLSPEC_SELECTANY CLSID_##className = __uuidof(className)
#define DEFINE_IID(interfaceName, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
interface DECLSPEC_UUID_WRAPPER(l##-##w1##-##w2##-##b1##b2##-##b3##b4##b5##b6##b7##b8) interfaceName; \
EXTERN_C const GUID DECLSPEC_SELECTANY IID_##interfaceName = __uuidof(interfaceName)
#else // INITGUID
#define DEFINE_CLSID(className, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
class DECLSPEC_UUID_WRAPPER(l##-##w1##-##w2##-##b1##b2##-##b3##b4##b5##b6##b7##b8) className; \
EXTERN_C const GUID CLSID_##className
#define DEFINE_IID(interfaceName, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
interface DECLSPEC_UUID_WRAPPER(l##-##w1##-##w2##-##b1##b2##-##b3##b4##b5##b6##b7##b8) interfaceName; \
EXTERN_C const GUID IID_##interfaceName
#endif // INITGUID
#else // __cplusplus
#define DEFINE_CLSID(className, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
DEFINE_GUID(CLSID_##className, 0x##l, 0x##w1, 0x##w2, 0x##b1, 0x##b2, 0x##b3, 0x##b4, 0x##b5, 0x##b6, 0x##b7, 0x##b8)
#define DEFINE_IID(interfaceName, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
DEFINE_GUID(IID_##interfaceName, 0x##l, 0x##w1, 0x##w2, 0x##b1, 0x##b2, 0x##b3, 0x##b4, 0x##b5, 0x##b6, 0x##b7, 0x##b8)
#endif // __cplusplus
#endif // #ifndef _COMDECL_H_

View File

@ -1,18 +0,0 @@
/*==========================================================================;
*
*
* File: dxsdkver.h
* Content: DirectX SDK Version Include File
*
****************************************************************************/
#ifndef _DXSDKVER_H_
#define _DXSDKVER_H_
#define _DXSDK_PRODUCT_MAJOR 9
#define _DXSDK_PRODUCT_MINOR 29
#define _DXSDK_BUILD_MAJOR 1962
#define _DXSDK_BUILD_MINOR 0
#endif // _DXSDKVER_H_

View File

@ -1,718 +0,0 @@
/***************************************************************************
*
* Copyright (c) Microsoft Corporation. All rights reserved.
*
* File: xma2defs.h
* Content: Constants, data types and functions for XMA2 compressed audio.
*
***************************************************************************/
#ifndef __XMA2DEFS_INCLUDED__
#define __XMA2DEFS_INCLUDED__
#include <sal.h> // Markers for documenting API semantics
#include <winerror.h> // For S_OK, E_FAIL
#include <audiodefs.h> // Basic data types and constants for audio work
/***************************************************************************
* Overview
***************************************************************************/
// A typical XMA2 file contains these RIFF chunks:
//
// 'fmt' or 'XMA2' chunk (or both): A description of the XMA data's structure
// and characteristics (length, channels, sample rate, loops, block size, etc).
//
// 'seek' chunk: A seek table to help navigate the XMA data.
//
// 'data' chunk: The encoded XMA2 data.
//
// The encoded XMA2 data is structured as a set of BLOCKS, which contain PACKETS,
// which contain FRAMES, which contain SUBFRAMES (roughly speaking). The frames
// in a file may also be divided into several subsets, called STREAMS.
//
// FRAME: A variable-sized segment of XMA data that decodes to exactly 512 mono
// or stereo PCM samples. This is the smallest unit of XMA data that can
// be decoded in isolation. Frames are an arbitrary number of bits in
// length, and need not be byte-aligned. See "XMA frame structure" below.
//
// SUBFRAME: A region of bits in an XMA frame that decodes to 128 mono or stereo
// samples. The XMA decoder cannot decode a subframe in isolation; it needs
// a whole frame to work with. However, it can begin emitting the frame's
// decoded samples at any one of the four subframe boundaries. Subframes
// can be addressed for seeking and looping purposes.
//
// PACKET: A 2Kb region containing a 32-bit header and some XMA frames. Frames
// can (and usually do) span packets. A packet's header includes the offset
// in bits of the first frame that begins within that packet. All of the
// frames that begin in a given packet belong to the same "stream" (see the
// Multichannel Audio section below).
//
// STREAM: A set of packets within an XMA file that all contain data for the
// same mono or stereo component of a PCM file with more than two channels.
// The packets comprising a given stream may be interleaved with each other
// more or less arbitrarily; see Multichannel Audio.
//
// BLOCK: An array of XMA packets; or, to break it down differently, a series of
// consecutive XMA frames, padded at the end with reserved data. A block
// must contain at least one 2Kb packet per stream, and it can hold up to
// 4095 packets (8190Kb), but its size is typically in the 32Kb-128Kb range.
// (The size chosen involves a trade-off between memory use and efficiency
// of reading from permanent storage.)
//
// XMA frames do not span blocks, so a block is guaranteed to begin with a
// set of complete frames, one per stream. Also, a block in a multi-stream
// XMA2 file always contains the same number of samples for each stream;
// see Multichannel Audio.
//
// The 'data' chunk in an XMA2 file is an array of XMA2WAVEFORMAT.BlockCount XMA
// blocks, all the same size (as specified in XMA2WAVEFORMAT.BlockSizeInBytes)
// except for the last one, which may be shorter.
// MULTICHANNEL AUDIO: the XMA decoder can only decode raw XMA data into either
// mono or stereo PCM data. In order to encode a 6-channel file (say), the file
// must be deinterleaved into 3 stereo streams that are encoded independently,
// producing 3 encoded XMA data streams. Then the packets in these 3 streams
// are interleaved to produce a single XMA2 file, and some information is added
// to the file so that the original 6-channel audio can be reconstructed at
// decode time. This works using the concept of an XMA stream (see above).
//
// The frames for all the streams in an XMA file are interleaved in an arbitrary
// order. To locate a frame that belongs to a given stream in a given XMA block,
// you must examine the first few packets in the block. Here (and only here) the
// packets are guaranteed to be presented in stream order, so that all frames
// beginning in packet 0 belong to stream 0 (the first stereo pair), etc.
//
// (This means that when decoding multi-stream XMA files, only entire XMA blocks
// should be submitted to the decoder; otherwise it cannot know which frames
// belong to which stream.)
//
// Once you have one frame that belongs to a given stream, you can find the next
// one by looking at the frame's 'NextFrameOffsetBits' value (which is stored in
// its first 15 bits; see XMAFRAME below). The GetXmaFrameBitPosition function
// uses this technique.
// SEEKING IN XMA2 FILES: Here is some pseudocode to find the byte position and
// subframe in an XMA2 file which will contain sample S when decoded.
//
// 1. Traverse the seek table to find the XMA2 block containing sample S. The
// seek table is an array of big-endian DWORDs, one per block in the file.
// The Nth DWORD is the total number of PCM samples that would be obtained
// by decoding the entire XMA file up to the end of block N. Hence, the
// block we want is the first one whose seek table entry is greater than S.
// (See the GetXmaBlockContainingSample helper function.)
//
// 2. Calculate which frame F within the block found above contains sample S.
// Since each frame decodes to 512 samples, this is straightforward. The
// first frame in the block produces samples X to X + 512, where X is the
// seek table entry for the prior block. So F is (S - X) / 512.
//
// 3. Find the bit offset within the block where frame F starts. Since frames
// are variable-sized, this can only be done by traversing all the frames in
// the block until we reach frame F. (See GetXmaFrameBitPosition.)
//
// 4. Frame F has four 128-sample subframes. To find the subframe containing S,
// we can use the formula (S % 512) / 128.
//
// In the case of multi-stream XMA files, sample S is a multichannel sample with
// parts coming from several frames, one per stream. To find all these frames,
// steps 2-4 need to be repeated for each stream N, using the knowledge that the
// first packets in a block are presented in stream order. The frame traversal
// in step 3 must be started at the first frame in the Nth packet of the block,
// which will be the first frame for stream N. (And the packet header will tell
// you the first frame's start position within the packet.)
//
// Step 1 can be performed using the GetXmaBlockContainingSample function below,
// and steps 2-4 by calling GetXmaDecodePositionForSample once for each stream.
/***************************************************************************
* XMA constants
***************************************************************************/
// Size of the PCM samples produced by the XMA decoder
#define XMA_OUTPUT_SAMPLE_BYTES 2u
#define XMA_OUTPUT_SAMPLE_BITS (XMA_OUTPUT_SAMPLE_BYTES * 8u)
// Size of an XMA packet
#define XMA_BYTES_PER_PACKET 2048u
#define XMA_BITS_PER_PACKET (XMA_BYTES_PER_PACKET * 8u)
// Size of an XMA packet header
#define XMA_PACKET_HEADER_BYTES 4u
#define XMA_PACKET_HEADER_BITS (XMA_PACKET_HEADER_BYTES * 8u)
// Sample blocks in a decoded XMA frame
#define XMA_SAMPLES_PER_FRAME 512u
// Sample blocks in a decoded XMA subframe
#define XMA_SAMPLES_PER_SUBFRAME 128u
// Maximum encoded data that can be submitted to the XMA decoder at a time
#define XMA_READBUFFER_MAX_PACKETS 4095u
#define XMA_READBUFFER_MAX_BYTES (XMA_READBUFFER_MAX_PACKETS * XMA_BYTES_PER_PACKET)
// Maximum size allowed for the XMA decoder's output buffers
#define XMA_WRITEBUFFER_MAX_BYTES (31u * 256u)
// Required byte alignment of the XMA decoder's output buffers
#define XMA_WRITEBUFFER_BYTE_ALIGNMENT 256u
// Decode chunk sizes for the XMA_PLAYBACK_INIT.subframesToDecode field
#define XMA_MIN_SUBFRAMES_TO_DECODE 1u
#define XMA_MAX_SUBFRAMES_TO_DECODE 8u
#define XMA_OPTIMAL_SUBFRAMES_TO_DECODE 4u
// LoopCount<255 means finite repetitions; LoopCount=255 means infinite looping
#define XMA_MAX_LOOPCOUNT 254u
#define XMA_INFINITE_LOOP 255u
/***************************************************************************
* XMA format structures
***************************************************************************/
// The currently recommended way to express format information for XMA2 files
// is the XMA2WAVEFORMATEX structure. This structure is fully compliant with
// the WAVEFORMATEX standard and contains all the information needed to parse
// and manage XMA2 files in a compact way.
#define WAVE_FORMAT_XMA2 0x166
typedef struct XMA2WAVEFORMATEX
{
WAVEFORMATEX wfx;
// Meaning of the WAVEFORMATEX fields here:
// wFormatTag; // Audio format type; always WAVE_FORMAT_XMA2
// nChannels; // Channel count of the decoded audio
// nSamplesPerSec; // Sample rate of the decoded audio
// nAvgBytesPerSec; // Used internally by the XMA encoder
// nBlockAlign; // Decoded sample size; channels * wBitsPerSample / 8
// wBitsPerSample; // Bits per decoded mono sample; always 16 for XMA
// cbSize; // Size in bytes of the rest of this structure (34)
WORD NumStreams; // Number of audio streams (1 or 2 channels each)
DWORD ChannelMask; // Spatial positions of the channels in this file,
// stored as SPEAKER_xxx values (see audiodefs.h)
DWORD SamplesEncoded; // Total number of PCM samples the file decodes to
DWORD BytesPerBlock; // XMA block size (but the last one may be shorter)
DWORD PlayBegin; // First valid sample in the decoded audio
DWORD PlayLength; // Length of the valid part of the decoded audio
DWORD LoopBegin; // Beginning of the loop region in decoded sample terms
DWORD LoopLength; // Length of the loop region in decoded sample terms
BYTE LoopCount; // Number of loop repetitions; 255 = infinite
BYTE EncoderVersion; // Version of XMA encoder that generated the file
WORD BlockCount; // XMA blocks in file (and entries in its seek table)
} XMA2WAVEFORMATEX, *PXMA2WAVEFORMATEX;
// The legacy XMA format structures are described here for reference, but they
// should not be used in new content. XMAWAVEFORMAT was the structure used in
// XMA version 1 files. XMA2WAVEFORMAT was used in early XMA2 files; it is not
// placed in the usual 'fmt' RIFF chunk but in its own 'XMA2' chunk.
#ifndef WAVE_FORMAT_XMA
#define WAVE_FORMAT_XMA 0x0165
// Values used in the ChannelMask fields below. Similar to the SPEAKER_xxx
// values defined in audiodefs.h, but modified to fit in a single byte.
#ifndef XMA_SPEAKER_LEFT
#define XMA_SPEAKER_LEFT 0x01
#define XMA_SPEAKER_RIGHT 0x02
#define XMA_SPEAKER_CENTER 0x04
#define XMA_SPEAKER_LFE 0x08
#define XMA_SPEAKER_LEFT_SURROUND 0x10
#define XMA_SPEAKER_RIGHT_SURROUND 0x20
#define XMA_SPEAKER_LEFT_BACK 0x40
#define XMA_SPEAKER_RIGHT_BACK 0x80
#endif
// Used in XMAWAVEFORMAT for per-stream data
typedef struct XMASTREAMFORMAT
{
DWORD PsuedoBytesPerSec; // Used by the XMA encoder (typo preserved for legacy reasons)
DWORD SampleRate; // The stream's decoded sample rate (in XMA2 files,
// this is the same for all streams in the file).
DWORD LoopStart; // Bit offset of the frame containing the loop start
// point, relative to the beginning of the stream.
DWORD LoopEnd; // Bit offset of the frame containing the loop end.
BYTE SubframeData; // Two 4-bit numbers specifying the exact location of
// the loop points within the frames that contain them.
// SubframeEnd: Subframe of the loop end frame where
// the loop ends. Ranges from 0 to 3.
// SubframeSkip: Subframes to skip in the start frame to
// reach the loop. Ranges from 0 to 4.
BYTE Channels; // Number of channels in the stream (1 or 2)
WORD ChannelMask; // Spatial positions of the channels in the stream
} XMASTREAMFORMAT;
// Legacy XMA1 format structure
typedef struct XMAWAVEFORMAT
{
WORD FormatTag; // Audio format type (always WAVE_FORMAT_XMA)
WORD BitsPerSample; // Bit depth (currently required to be 16)
WORD EncodeOptions; // Options for XMA encoder/decoder
WORD LargestSkip; // Largest skip used in interleaving streams
WORD NumStreams; // Number of interleaved audio streams
BYTE LoopCount; // Number of loop repetitions; 255 = infinite
BYTE Version; // XMA encoder version that generated the file.
// Always 3 or higher for XMA2 files.
XMASTREAMFORMAT XmaStreams[1]; // Per-stream format information; the actual
// array length is in the NumStreams field.
} XMAWAVEFORMAT;
// Used in XMA2WAVEFORMAT for per-stream data
typedef struct XMA2STREAMFORMAT
{
BYTE Channels; // Number of channels in the stream (1 or 2)
BYTE RESERVED; // Reserved for future use
WORD ChannelMask; // Spatial positions of the channels in the stream
} XMA2STREAMFORMAT;
// Legacy XMA2 format structure (big-endian byte ordering)
typedef struct XMA2WAVEFORMAT
{
BYTE Version; // XMA encoder version that generated the file.
// Always 3 or higher for XMA2 files.
BYTE NumStreams; // Number of interleaved audio streams
BYTE RESERVED; // Reserved for future use
BYTE LoopCount; // Number of loop repetitions; 255 = infinite
DWORD LoopBegin; // Loop begin point, in samples
DWORD LoopEnd; // Loop end point, in samples
DWORD SampleRate; // The file's decoded sample rate
DWORD EncodeOptions; // Options for the XMA encoder/decoder
DWORD PsuedoBytesPerSec; // Used internally by the XMA encoder
DWORD BlockSizeInBytes; // Size in bytes of this file's XMA blocks (except
// possibly the last one). Always a multiple of
// 2Kb, since XMA blocks are arrays of 2Kb packets.
DWORD SamplesEncoded; // Total number of PCM samples encoded in this file
DWORD SamplesInSource; // Actual number of PCM samples in the source
// material used to generate this file
DWORD BlockCount; // Number of XMA blocks in this file (and hence
// also the number of entries in its seek table)
XMA2STREAMFORMAT Streams[1]; // Per-stream format information; the actual
// array length is in the NumStreams field.
} XMA2WAVEFORMAT;
#endif // #ifndef WAVE_FORMAT_XMA
/***************************************************************************
* XMA packet structure (in big-endian form)
***************************************************************************/
typedef struct XMA2PACKET
{
int FrameCount : 6; // Number of XMA frames that begin in this packet
int FrameOffsetInBits : 15; // Bit of XmaData where the first complete frame begins
int PacketMetaData : 3; // Metadata stored in the packet (always 1 for XMA2)
int PacketSkipCount : 8; // How many packets belonging to other streams must be
// skipped to find the next packet belonging to this one
BYTE XmaData[XMA_BYTES_PER_PACKET - sizeof(DWORD)]; // XMA encoded data
} XMA2PACKET;
// E.g. if the first DWORD of a packet is 0x30107902:
//
// 001100 000001000001111 001 00000010
// | | | |____ Skip 2 packets to find the next one for this stream
// | | |___________ XMA2 signature (always 001)
// | |_____________________ First frame starts 527 bits into packet
// |________________________________ Packet contains 12 frames
// Helper functions to extract the fields above from an XMA packet. (Note that
// the bitfields cannot be read directly on little-endian architectures such as
// the Intel x86, as they are laid out in big-endian form.)
__inline DWORD GetXmaPacketFrameCount(__in_bcount(1) const BYTE* pPacket)
{
return (DWORD)(pPacket[0] >> 2);
}
__inline DWORD GetXmaPacketFirstFrameOffsetInBits(__in_bcount(3) const BYTE* pPacket)
{
return ((DWORD)(pPacket[0] & 0x3) << 13) |
((DWORD)(pPacket[1]) << 5) |
((DWORD)(pPacket[2]) >> 3);
}
__inline DWORD GetXmaPacketMetadata(__in_bcount(3) const BYTE* pPacket)
{
return (DWORD)(pPacket[2] & 0x7);
}
__inline DWORD GetXmaPacketSkipCount(__in_bcount(4) const BYTE* pPacket)
{
return (DWORD)(pPacket[3]);
}
/***************************************************************************
* XMA frame structure
***************************************************************************/
// There is no way to represent the XMA frame as a C struct, since it is a
// variable-sized string of bits that need not be stored at a byte-aligned
// position in memory. This is the layout:
//
// XMAFRAME
// {
// LengthInBits: A 15-bit number representing the length of this frame.
// XmaData: Encoded XMA data; its size in bits is (LengthInBits - 15).
// }
// Size in bits of the frame's initial LengthInBits field
#define XMA_BITS_IN_FRAME_LENGTH_FIELD 15
// Special LengthInBits value that marks an invalid final frame
#define XMA_FINAL_FRAME_MARKER 0x7FFF
/***************************************************************************
* XMA helper functions
***************************************************************************/
// We define a local ASSERT macro to equal the global one if it exists.
// You can define XMA2DEFS_ASSERT in advance to override this default.
#ifndef XMA2DEFS_ASSERT
#ifdef ASSERT
#define XMA2DEFS_ASSERT ASSERT
#else
#define XMA2DEFS_ASSERT(a) /* No-op by default */
#endif
#endif
// GetXmaBlockContainingSample: Use a given seek table to find the XMA block
// containing a given decoded sample. Note that the seek table entries in an
// XMA file are stored in big-endian form and may need to be converted prior
// to calling this function.
__inline HRESULT GetXmaBlockContainingSample
(
DWORD nBlockCount, // Blocks in the file (= seek table entries)
__in_ecount(nBlockCount) const DWORD* pSeekTable, // Pointer to the seek table data
DWORD nDesiredSample, // Decoded sample to locate
__out DWORD* pnBlockContainingSample, // Index of the block containing the sample
__out DWORD* pnSampleOffsetWithinBlock // Position of the sample in this block
)
{
DWORD nPreviousTotalSamples = 0;
DWORD nBlock;
DWORD nTotalSamplesSoFar;
XMA2DEFS_ASSERT(pSeekTable);
XMA2DEFS_ASSERT(pnBlockContainingSample);
XMA2DEFS_ASSERT(pnSampleOffsetWithinBlock);
for (nBlock = 0; nBlock < nBlockCount; ++nBlock)
{
nTotalSamplesSoFar = pSeekTable[nBlock];
if (nTotalSamplesSoFar > nDesiredSample)
{
*pnBlockContainingSample = nBlock;
*pnSampleOffsetWithinBlock = nDesiredSample - nPreviousTotalSamples;
return S_OK;
}
nPreviousTotalSamples = nTotalSamplesSoFar;
}
return E_FAIL;
}
// GetXmaFrameLengthInBits: Reads a given frame's LengthInBits field.
__inline DWORD GetXmaFrameLengthInBits
(
__in_bcount(nBitPosition / 8 + 3)
__in const BYTE* pPacket, // Pointer to XMA packet[s] containing the frame
DWORD nBitPosition // Bit offset of the frame within this packet
)
{
DWORD nRegion;
DWORD nBytePosition = nBitPosition / 8;
DWORD nBitOffset = nBitPosition % 8;
if (nBitOffset < 2) // Only need to read 2 bytes (and might not be safe to read more)
{
nRegion = (DWORD)(pPacket[nBytePosition+0]) << 8 |
(DWORD)(pPacket[nBytePosition+1]);
return (nRegion >> (1 - nBitOffset)) & 0x7FFF; // Last 15 bits
}
else // Need to read 3 bytes
{
nRegion = (DWORD)(pPacket[nBytePosition+0]) << 16 |
(DWORD)(pPacket[nBytePosition+1]) << 8 |
(DWORD)(pPacket[nBytePosition+2]);
return (nRegion >> (9 - nBitOffset)) & 0x7FFF; // Last 15 bits
}
}
// GetXmaFrameBitPosition: Calculates the bit offset of a given frame within
// an XMA block or set of blocks. Returns 0 on failure.
__inline DWORD GetXmaFrameBitPosition
(
__in_bcount(nXmaDataBytes) const BYTE* pXmaData, // Pointer to XMA block[s]
DWORD nXmaDataBytes, // Size of pXmaData in bytes
DWORD nStreamIndex, // Stream within which to seek
DWORD nDesiredFrame // Frame sought
)
{
const BYTE* pCurrentPacket;
DWORD nPacketsExamined = 0;
DWORD nFrameCountSoFar = 0;
DWORD nFramesToSkip;
DWORD nFrameBitOffset;
XMA2DEFS_ASSERT(pXmaData);
XMA2DEFS_ASSERT(nXmaDataBytes % XMA_BYTES_PER_PACKET == 0);
// Get the first XMA packet belonging to the desired stream, relying on the
// fact that the first packets for each stream are in consecutive order at
// the beginning of an XMA block.
pCurrentPacket = pXmaData + nStreamIndex * XMA_BYTES_PER_PACKET;
for (;;)
{
// If we have exceeded the size of the XMA data, return failure
if (pCurrentPacket + XMA_BYTES_PER_PACKET > pXmaData + nXmaDataBytes)
{
return 0;
}
// If the current packet contains the frame we are looking for...
if (nFrameCountSoFar + GetXmaPacketFrameCount(pCurrentPacket) > nDesiredFrame)
{
// See how many frames in this packet we need to skip to get to it
XMA2DEFS_ASSERT(nDesiredFrame >= nFrameCountSoFar);
nFramesToSkip = nDesiredFrame - nFrameCountSoFar;
// Get the bit offset of the first frame in this packet
nFrameBitOffset = XMA_PACKET_HEADER_BITS + GetXmaPacketFirstFrameOffsetInBits(pCurrentPacket);
// Advance nFrameBitOffset to the frame of interest
while (nFramesToSkip--)
{
nFrameBitOffset += GetXmaFrameLengthInBits(pCurrentPacket, nFrameBitOffset);
}
// The bit offset to return is the number of bits from pXmaData to
// pCurrentPacket plus the bit offset of the frame of interest
return (DWORD)(pCurrentPacket - pXmaData) * 8 + nFrameBitOffset;
}
// If we haven't found the right packet yet, advance our counters
++nPacketsExamined;
nFrameCountSoFar += GetXmaPacketFrameCount(pCurrentPacket);
// And skip to the next packet belonging to the same stream
pCurrentPacket += XMA_BYTES_PER_PACKET * (GetXmaPacketSkipCount(pCurrentPacket) + 1);
}
}
// GetLastXmaFrameBitPosition: Calculates the bit offset of the last complete
// frame in an XMA block or set of blocks.
__inline DWORD GetLastXmaFrameBitPosition
(
__in_bcount(nXmaDataBytes) const BYTE* pXmaData, // Pointer to XMA block[s]
DWORD nXmaDataBytes, // Size of pXmaData in bytes
DWORD nStreamIndex // Stream within which to seek
)
{
const BYTE* pLastPacket;
DWORD nBytesToNextPacket;
DWORD nFrameBitOffset;
DWORD nFramesInLastPacket;
XMA2DEFS_ASSERT(pXmaData);
XMA2DEFS_ASSERT(nXmaDataBytes % XMA_BYTES_PER_PACKET == 0);
XMA2DEFS_ASSERT(nXmaDataBytes >= XMA_BYTES_PER_PACKET * (nStreamIndex + 1));
// Get the first XMA packet belonging to the desired stream, relying on the
// fact that the first packets for each stream are in consecutive order at
// the beginning of an XMA block.
pLastPacket = pXmaData + nStreamIndex * XMA_BYTES_PER_PACKET;
// Search for the last packet belonging to the desired stream
for (;;)
{
nBytesToNextPacket = XMA_BYTES_PER_PACKET * (GetXmaPacketSkipCount(pLastPacket) + 1);
XMA2DEFS_ASSERT(nBytesToNextPacket);
if (pLastPacket + nBytesToNextPacket + XMA_BYTES_PER_PACKET > pXmaData + nXmaDataBytes)
{
break; // The next packet would extend beyond the end of pXmaData
}
pLastPacket += nBytesToNextPacket;
}
// The last packet can sometimes have no seekable frames, in which case we
// have to use the previous one
if (GetXmaPacketFrameCount(pLastPacket) == 0)
{
pLastPacket -= nBytesToNextPacket;
}
// Found the last packet. Get the bit offset of its first frame.
nFrameBitOffset = XMA_PACKET_HEADER_BITS + GetXmaPacketFirstFrameOffsetInBits(pLastPacket);
// Traverse frames until we reach the last one
nFramesInLastPacket = GetXmaPacketFrameCount(pLastPacket);
while (--nFramesInLastPacket)
{
nFrameBitOffset += GetXmaFrameLengthInBits(pLastPacket, nFrameBitOffset);
}
// The bit offset to return is the number of bits from pXmaData to
// pLastPacket plus the offset of the last frame in this packet.
return (DWORD)(pLastPacket - pXmaData) * 8 + nFrameBitOffset;
}
// GetXmaDecodePositionForSample: Obtains the information needed to make the
// decoder generate audio starting at a given sample position relative to the
// beginning of the given XMA block: the bit offset of the appropriate frame,
// and the right subframe within that frame. This data can be passed directly
// to the XMAPlaybackSetDecodePosition function.
__inline HRESULT GetXmaDecodePositionForSample
(
__in_bcount(nXmaDataBytes) const BYTE* pXmaData, // Pointer to XMA block[s]
DWORD nXmaDataBytes, // Size of pXmaData in bytes
DWORD nStreamIndex, // Stream within which to seek
DWORD nDesiredSample, // Sample sought
__out DWORD* pnBitOffset, // Returns the bit offset within pXmaData of
// the frame containing the sample sought
__out DWORD* pnSubFrame // Returns the subframe containing the sample
)
{
DWORD nDesiredFrame = nDesiredSample / XMA_SAMPLES_PER_FRAME;
DWORD nSubFrame = (nDesiredSample % XMA_SAMPLES_PER_FRAME) / XMA_SAMPLES_PER_SUBFRAME;
DWORD nBitOffset = GetXmaFrameBitPosition(pXmaData, nXmaDataBytes, nStreamIndex, nDesiredFrame);
XMA2DEFS_ASSERT(pnBitOffset);
XMA2DEFS_ASSERT(pnSubFrame);
if (nBitOffset)
{
*pnBitOffset = nBitOffset;
*pnSubFrame = nSubFrame;
return S_OK;
}
else
{
return E_FAIL;
}
}
// GetXmaSampleRate: Obtains the legal XMA sample rate (24, 32, 44.1 or 48Khz)
// corresponding to a generic sample rate.
__inline DWORD GetXmaSampleRate(DWORD dwGeneralRate)
{
DWORD dwXmaRate = 48000; // Default XMA rate for all rates above 44100Hz
if (dwGeneralRate <= 24000) dwXmaRate = 24000;
else if (dwGeneralRate <= 32000) dwXmaRate = 32000;
else if (dwGeneralRate <= 44100) dwXmaRate = 44100;
return dwXmaRate;
}
// Functions to convert between WAVEFORMATEXTENSIBLE channel masks (combinations
// of the SPEAKER_xxx flags defined in audiodefs.h) and XMA channel masks (which
// are limited to eight possible speaker positions: left, right, center, low
// frequency, side left, side right, back left and back right).
__inline DWORD GetStandardChannelMaskFromXmaMask(BYTE bXmaMask)
{
DWORD dwStandardMask = 0;
if (bXmaMask & XMA_SPEAKER_LEFT) dwStandardMask |= SPEAKER_FRONT_LEFT;
if (bXmaMask & XMA_SPEAKER_RIGHT) dwStandardMask |= SPEAKER_FRONT_RIGHT;
if (bXmaMask & XMA_SPEAKER_CENTER) dwStandardMask |= SPEAKER_FRONT_CENTER;
if (bXmaMask & XMA_SPEAKER_LFE) dwStandardMask |= SPEAKER_LOW_FREQUENCY;
if (bXmaMask & XMA_SPEAKER_LEFT_SURROUND) dwStandardMask |= SPEAKER_SIDE_LEFT;
if (bXmaMask & XMA_SPEAKER_RIGHT_SURROUND) dwStandardMask |= SPEAKER_SIDE_RIGHT;
if (bXmaMask & XMA_SPEAKER_LEFT_BACK) dwStandardMask |= SPEAKER_BACK_LEFT;
if (bXmaMask & XMA_SPEAKER_RIGHT_BACK) dwStandardMask |= SPEAKER_BACK_RIGHT;
return dwStandardMask;
}
__inline BYTE GetXmaChannelMaskFromStandardMask(DWORD dwStandardMask)
{
BYTE bXmaMask = 0;
if (dwStandardMask & SPEAKER_FRONT_LEFT) bXmaMask |= XMA_SPEAKER_LEFT;
if (dwStandardMask & SPEAKER_FRONT_RIGHT) bXmaMask |= XMA_SPEAKER_RIGHT;
if (dwStandardMask & SPEAKER_FRONT_CENTER) bXmaMask |= XMA_SPEAKER_CENTER;
if (dwStandardMask & SPEAKER_LOW_FREQUENCY) bXmaMask |= XMA_SPEAKER_LFE;
if (dwStandardMask & SPEAKER_SIDE_LEFT) bXmaMask |= XMA_SPEAKER_LEFT_SURROUND;
if (dwStandardMask & SPEAKER_SIDE_RIGHT) bXmaMask |= XMA_SPEAKER_RIGHT_SURROUND;
if (dwStandardMask & SPEAKER_BACK_LEFT) bXmaMask |= XMA_SPEAKER_LEFT_BACK;
if (dwStandardMask & SPEAKER_BACK_RIGHT) bXmaMask |= XMA_SPEAKER_RIGHT_BACK;
return bXmaMask;
}
// LocalizeXma2Format: Modifies a XMA2WAVEFORMATEX structure in place to comply
// with the current platform's byte-ordering rules (little- or big-endian).
__inline HRESULT LocalizeXma2Format(__inout XMA2WAVEFORMATEX* pXma2Format)
{
#define XMASWAP2BYTES(n) ((WORD)(((n) >> 8) | (((n) & 0xff) << 8)))
#define XMASWAP4BYTES(n) ((DWORD)((n) >> 24 | (n) << 24 | ((n) & 0xff00) << 8 | ((n) & 0xff0000) >> 8))
if (pXma2Format->wfx.wFormatTag == WAVE_FORMAT_XMA2)
{
return S_OK;
}
else if (XMASWAP2BYTES(pXma2Format->wfx.wFormatTag) == WAVE_FORMAT_XMA2)
{
pXma2Format->wfx.wFormatTag = XMASWAP2BYTES(pXma2Format->wfx.wFormatTag);
pXma2Format->wfx.nChannels = XMASWAP2BYTES(pXma2Format->wfx.nChannels);
pXma2Format->wfx.nSamplesPerSec = XMASWAP4BYTES(pXma2Format->wfx.nSamplesPerSec);
pXma2Format->wfx.nAvgBytesPerSec = XMASWAP4BYTES(pXma2Format->wfx.nAvgBytesPerSec);
pXma2Format->wfx.nBlockAlign = XMASWAP2BYTES(pXma2Format->wfx.nBlockAlign);
pXma2Format->wfx.wBitsPerSample = XMASWAP2BYTES(pXma2Format->wfx.wBitsPerSample);
pXma2Format->wfx.cbSize = XMASWAP2BYTES(pXma2Format->wfx.cbSize);
pXma2Format->NumStreams = XMASWAP2BYTES(pXma2Format->NumStreams);
pXma2Format->ChannelMask = XMASWAP4BYTES(pXma2Format->ChannelMask);
pXma2Format->SamplesEncoded = XMASWAP4BYTES(pXma2Format->SamplesEncoded);
pXma2Format->BytesPerBlock = XMASWAP4BYTES(pXma2Format->BytesPerBlock);
pXma2Format->PlayBegin = XMASWAP4BYTES(pXma2Format->PlayBegin);
pXma2Format->PlayLength = XMASWAP4BYTES(pXma2Format->PlayLength);
pXma2Format->LoopBegin = XMASWAP4BYTES(pXma2Format->LoopBegin);
pXma2Format->LoopLength = XMASWAP4BYTES(pXma2Format->LoopLength);
pXma2Format->BlockCount = XMASWAP2BYTES(pXma2Format->BlockCount);
return S_OK;
}
else
{
return E_FAIL; // Not a recognizable XMA2 format
}
#undef XMASWAP2BYTES
#undef XMASWAP4BYTES
}
#endif // #ifndef __XMA2DEFS_INCLUDED__

BIN
bin/xaudio2_9redist.dll Normal file

Binary file not shown.

View File

@ -1,206 +0,0 @@
#ifndef _WIN32
#error "XAudio27 can only be built on Windows."
#endif
#include "Utilities/Log.h"
#include "Utilities/StrFmt.h"
#include "Emu/System.h"
#include "Emu/system_config.h"
#include "XAudio2Backend.h"
#include "3rdparty/XAudio2_7/XAudio2.h"
LOG_CHANNEL(XAudio);
class XAudio27Library : public XAudio2Backend::XAudio2Library
{
const HMODULE tls_xaudio2_lib;
IXAudio2* tls_xaudio2_instance{};
IXAudio2MasteringVoice* tls_master_voice{};
IXAudio2SourceVoice* tls_source_voice{};
public:
XAudio27Library(void* lib2_7)
: tls_xaudio2_lib(static_cast<HMODULE>(lib2_7))
{
HRESULT hr = S_OK;
hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
if (FAILED(hr))
{
XAudio.error("CoInitializeEx() failed(0x%08x)", (u32)hr);
Emu.Pause();
return;
}
hr = XAudio2Create(&tls_xaudio2_instance, 0, XAUDIO2_DEFAULT_PROCESSOR);
if (FAILED(hr))
{
XAudio.error("XAudio2Create() failed(0x%08x)", (u32)hr);
Emu.Pause();
return;
}
hr = tls_xaudio2_instance->CreateMasteringVoice(&tls_master_voice, g_cfg.audio.downmix_to_2ch ? 2 : 8, 48000);
if (FAILED(hr))
{
XAudio.error("CreateMasteringVoice() failed(0x%08x)", (u32)hr);
tls_xaudio2_instance->Release();
Emu.Pause();
}
}
~XAudio27Library()
{
if (tls_source_voice != nullptr)
{
tls_source_voice->Stop();
tls_source_voice->DestroyVoice();
}
if (tls_master_voice != nullptr)
{
tls_master_voice->DestroyVoice();
}
if (tls_xaudio2_instance != nullptr)
{
tls_xaudio2_instance->StopEngine();
tls_xaudio2_instance->Release();
}
CoUninitialize();
FreeLibrary(tls_xaudio2_lib);
}
virtual void play() override
{
HRESULT hr = tls_source_voice->Start();
if (FAILED(hr))
{
XAudio.error("Start() failed(0x%08x)", (u32)hr);
Emu.Pause();
}
}
virtual void flush() override
{
HRESULT hr = tls_source_voice->FlushSourceBuffers();
if (FAILED(hr))
{
XAudio.error("FlushSourceBuffers() failed(0x%08x)", (u32)hr);
Emu.Pause();
}
}
virtual void stop() override
{
HRESULT hr = tls_source_voice->Stop();
if (FAILED(hr))
{
XAudio.error("Stop() failed(0x%08x)", (u32)hr);
Emu.Pause();
}
}
virtual bool is_playing() override
{
XAUDIO2_VOICE_STATE state;
tls_source_voice->GetState(&state);
return state.BuffersQueued > 0 || state.pCurrentBufferContext != nullptr;
}
virtual void open() override
{
HRESULT hr;
const u32 sample_size = AudioBackend::get_sample_size();
const u32 channels = AudioBackend::get_channels();
const u32 sampling_rate = AudioBackend::get_sampling_rate();
WAVEFORMATEX waveformatex;
waveformatex.wFormatTag = g_cfg.audio.convert_to_u16 ? WAVE_FORMAT_PCM : WAVE_FORMAT_IEEE_FLOAT;
waveformatex.nChannels = channels;
waveformatex.nSamplesPerSec = sampling_rate;
waveformatex.nAvgBytesPerSec = static_cast<DWORD>(sampling_rate * channels * sample_size);
waveformatex.nBlockAlign = channels * sample_size;
waveformatex.wBitsPerSample = sample_size * 8;
waveformatex.cbSize = 0;
hr = tls_xaudio2_instance->CreateSourceVoice(&tls_source_voice, &waveformatex, 0, XAUDIO2_DEFAULT_FREQ_RATIO);
if (FAILED(hr))
{
XAudio.error("CreateSourceVoice() failed(0x%08x)", (u32)hr);
Emu.Pause();
return;
}
tls_source_voice->SetVolume(channels == 2 ? 1.0f : 4.0f);
}
virtual bool add(const void* src, u32 num_samples) override
{
XAUDIO2_VOICE_STATE state;
tls_source_voice->GetState(&state);
// XAudio 2.7 bug workaround, when it says "SimpList: non-growable list ran out of room for new elements" and hits int 3
if (state.BuffersQueued >= MAX_AUDIO_BUFFERS)
{
XAudio.warning("Too many buffers enqueued (%d, pos=%u)", state.BuffersQueued, state.SamplesPlayed);
return false;
}
XAUDIO2_BUFFER buffer;
buffer.AudioBytes = num_samples * AudioBackend::get_sample_size();
buffer.Flags = 0;
buffer.LoopBegin = XAUDIO2_NO_LOOP_REGION;
buffer.LoopCount = 0;
buffer.LoopLength = 0;
buffer.pAudioData = (const BYTE*)src;
buffer.pContext = 0;
buffer.PlayBegin = 0;
buffer.PlayLength = AUDIO_BUFFER_SAMPLES;
HRESULT hr = tls_source_voice->SubmitSourceBuffer(&buffer);
if (FAILED(hr))
{
XAudio.error("AddData() failed(0x%08x)", (u32)hr);
Emu.Pause();
return false;
}
return true;
}
virtual u64 enqueued_samples() override
{
XAUDIO2_VOICE_STATE state;
tls_source_voice->GetState(&state);
// all buffers contain AUDIO_BUFFER_SAMPLES, so we can easily calculate how many samples there are remaining
return (AUDIO_BUFFER_SAMPLES - state.SamplesPlayed % AUDIO_BUFFER_SAMPLES) + (state.BuffersQueued * AUDIO_BUFFER_SAMPLES);
}
virtual f32 set_freq_ratio(f32 new_ratio) override
{
new_ratio = std::clamp(new_ratio, XAUDIO2_MIN_FREQ_RATIO, XAUDIO2_DEFAULT_FREQ_RATIO);
HRESULT hr = tls_source_voice->SetFrequencyRatio(new_ratio);
if (FAILED(hr))
{
XAudio.error("SetFrequencyRatio() failed(0x%08x)", (u32)hr);
Emu.Pause();
return 1.0f;
}
return new_ratio;
}
};
XAudio2Backend::XAudio2Library* XAudio2Backend::xa27_init(void* lib2_7)
{
return new XAudio27Library(lib2_7);
}

View File

@ -1,218 +0,0 @@
#ifndef _WIN32
#error "XAudio28 can only be built on Windows."
#endif
#include "Utilities/Log.h"
#include "Utilities/StrFmt.h"
#include "Emu/System.h"
#include "Emu/system_config.h"
#include "XAudio2Backend.h"
#include "3rdparty/minidx12/Include/xaudio2.h"
LOG_CHANNEL(XAudio);
class XAudio28Library : public XAudio2Backend::XAudio2Library
{
const HMODULE tls_xaudio2_lib;
IXAudio2* tls_xaudio2_instance{};
IXAudio2MasteringVoice* tls_master_voice{};
IXAudio2SourceVoice* tls_source_voice{};
public:
XAudio28Library(void* lib2_8)
: tls_xaudio2_lib(static_cast<HMODULE>(lib2_8))
{
const auto create = (XAudio2Create)GetProcAddress(tls_xaudio2_lib, "XAudio2Create");
HRESULT hr = S_OK;
hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
if (FAILED(hr))
{
XAudio.error("CoInitializeEx() failed(0x%08x)", (u32)hr);
Emu.Pause();
return;
}
hr = create(&tls_xaudio2_instance, 0, XAUDIO2_DEFAULT_PROCESSOR);
if (FAILED(hr))
{
XAudio.error("XAudio2Create() failed(0x%08x)", (u32)hr);
Emu.Pause();
return;
}
hr = tls_xaudio2_instance->CreateMasteringVoice(&tls_master_voice, g_cfg.audio.downmix_to_2ch ? 2 : 8, 48000);
if (FAILED(hr))
{
XAudio.error("CreateMasteringVoice() failed(0x%08x)", (u32)hr);
tls_xaudio2_instance->Release();
Emu.Pause();
}
}
~XAudio28Library()
{
if (tls_source_voice != nullptr)
{
tls_source_voice->Stop();
tls_source_voice->DestroyVoice();
}
if (tls_master_voice != nullptr)
{
tls_master_voice->DestroyVoice();
}
if (tls_xaudio2_instance != nullptr)
{
tls_xaudio2_instance->StopEngine();
tls_xaudio2_instance->Release();
}
CoUninitialize();
FreeLibrary(tls_xaudio2_lib);
}
virtual void play() override
{
AUDIT(tls_source_voice != nullptr);
HRESULT hr = tls_source_voice->Start();
if (FAILED(hr))
{
XAudio.error("Start() failed(0x%08x)", (u32)hr);
Emu.Pause();
}
}
virtual void flush() override
{
AUDIT(tls_source_voice != nullptr);
HRESULT hr = tls_source_voice->FlushSourceBuffers();
if (FAILED(hr))
{
XAudio.error("FlushSourceBuffers() failed(0x%08x)", (u32)hr);
Emu.Pause();
}
}
virtual void stop() override
{
AUDIT(tls_source_voice != nullptr);
HRESULT hr = tls_source_voice->Stop();
if (FAILED(hr))
{
XAudio.error("Stop() failed(0x%08x)", (u32)hr);
Emu.Pause();
}
}
virtual bool is_playing() override
{
AUDIT(tls_source_voice != nullptr);
XAUDIO2_VOICE_STATE state;
tls_source_voice->GetState(&state, XAUDIO2_VOICE_NOSAMPLESPLAYED);
return state.BuffersQueued > 0 || state.pCurrentBufferContext != nullptr;
}
virtual void open() override
{
HRESULT hr;
const u32 sample_size = AudioBackend::get_sample_size();
const u32 channels = AudioBackend::get_channels();
const u32 sampling_rate = AudioBackend::get_sampling_rate();
WAVEFORMATEX waveformatex;
waveformatex.wFormatTag = g_cfg.audio.convert_to_u16 ? WAVE_FORMAT_PCM : WAVE_FORMAT_IEEE_FLOAT;
waveformatex.nChannels = channels;
waveformatex.nSamplesPerSec = sampling_rate;
waveformatex.nAvgBytesPerSec = static_cast<DWORD>(sampling_rate * channels * sample_size);
waveformatex.nBlockAlign = channels * sample_size;
waveformatex.wBitsPerSample = sample_size * 8;
waveformatex.cbSize = 0;
hr = tls_xaudio2_instance->CreateSourceVoice(&tls_source_voice, &waveformatex, 0, XAUDIO2_DEFAULT_FREQ_RATIO);
if (FAILED(hr))
{
XAudio.error("CreateSourceVoice() failed(0x%08x)", (u32)hr);
Emu.Pause();
return;
}
AUDIT(tls_source_voice != nullptr);
tls_source_voice->SetVolume(channels == 2 ? 1.0f : 4.0f);
}
virtual bool add(const void* src, u32 num_samples) override
{
AUDIT(tls_source_voice != nullptr);
XAUDIO2_VOICE_STATE state;
tls_source_voice->GetState(&state, XAUDIO2_VOICE_NOSAMPLESPLAYED);
if (state.BuffersQueued >= MAX_AUDIO_BUFFERS)
{
XAudio.warning("Too many buffers enqueued (%d)", state.BuffersQueued);
return false;
}
XAUDIO2_BUFFER buffer;
buffer.AudioBytes = num_samples * AudioBackend::get_sample_size();
buffer.Flags = 0;
buffer.LoopBegin = XAUDIO2_NO_LOOP_REGION;
buffer.LoopCount = 0;
buffer.LoopLength = 0;
buffer.pAudioData = (const BYTE*)src;
buffer.pContext = 0;
buffer.PlayBegin = 0;
buffer.PlayLength = AUDIO_BUFFER_SAMPLES;
HRESULT hr = tls_source_voice->SubmitSourceBuffer(&buffer);
if (FAILED(hr))
{
XAudio.error("AddData() failed(0x%08x)", (u32)hr);
Emu.Pause();
return false;
}
return true;
}
virtual u64 enqueued_samples() override
{
XAUDIO2_VOICE_STATE state;
tls_source_voice->GetState(&state);
// all buffers contain AUDIO_BUFFER_SAMPLES, so we can easily calculate how many samples there are remaining
return (AUDIO_BUFFER_SAMPLES - state.SamplesPlayed % AUDIO_BUFFER_SAMPLES) + (state.BuffersQueued * AUDIO_BUFFER_SAMPLES);
}
virtual f32 set_freq_ratio(f32 new_ratio) override
{
new_ratio = std::clamp(new_ratio, XAUDIO2_MIN_FREQ_RATIO, XAUDIO2_DEFAULT_FREQ_RATIO);
HRESULT hr = tls_source_voice->SetFrequencyRatio(new_ratio);
if (FAILED(hr))
{
XAudio.error("SetFrequencyRatio() failed(0x%08x)", (u32)hr);
Emu.Pause();
return 1.0f;
}
return new_ratio;
}
};
XAudio2Backend::XAudio2Library* XAudio2Backend::xa28_init(void* lib2_8)
{
return new XAudio28Library(lib2_8);
}

View File

@ -4,91 +4,197 @@
#include "Utilities/Log.h"
#include "Utilities/StrFmt.h"
#include "Emu/System.h"
#include "Emu/system_config.h"
#include "XAudio2Backend.h"
#include <Windows.h>
#pragma comment(lib, "xaudio2_9redist.lib")
LOG_CHANNEL(XAudio);
XAudio2Backend::XAudio2Backend()
{
Microsoft::WRL::ComPtr<IXAudio2> instance;
HRESULT hr = XAudio2Create(instance.GetAddressOf(), 0, XAUDIO2_DEFAULT_PROCESSOR);
if (FAILED(hr))
{
XAudio.error("XAudio2Create() failed(0x%08x)", (u32)hr);
Emu.Pause();
return;
}
hr = instance->CreateMasteringVoice(&m_master_voice, g_cfg.audio.downmix_to_2ch ? 2 : 8, 48000);
if (FAILED(hr))
{
XAudio.error("CreateMasteringVoice() failed(0x%08x)", (u32)hr);
Emu.Pause();
}
// All succeeded, "commit"
m_xaudio2_instance = std::move(instance);
}
XAudio2Backend::~XAudio2Backend()
{
if (m_source_voice != nullptr)
{
m_source_voice->Stop();
m_source_voice->DestroyVoice();
}
if (m_master_voice != nullptr)
{
m_master_voice->DestroyVoice();
}
if (m_xaudio2_instance != nullptr)
{
m_xaudio2_instance->StopEngine();
}
}
void XAudio2Backend::Play()
{
lib->play();
AUDIT(m_source_voice != nullptr);
HRESULT hr = m_source_voice->Start();
if (FAILED(hr))
{
XAudio.error("Start() failed(0x%08x)", (u32)hr);
Emu.Pause();
}
}
void XAudio2Backend::Close()
{
lib->stop();
lib->flush();
Pause();
Flush();
}
void XAudio2Backend::Pause()
{
lib->stop();
AUDIT(m_source_voice != nullptr);
HRESULT hr = m_source_voice->Stop();
if (FAILED(hr))
{
XAudio.error("Stop() failed(0x%08x)", (u32)hr);
Emu.Pause();
}
}
void XAudio2Backend::Open(u32 /* num_buffers */)
{
if (!lib)
{
void* hmodule;
HRESULT hr;
if (hmodule = LoadLibraryExW(L"XAudio2_9.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32))
{
// XAudio 2.9 uses the same code as XAudio 2.8
lib.reset(xa28_init(hmodule));
const u32 sample_size = AudioBackend::get_sample_size();
const u32 channels = AudioBackend::get_channels();
const u32 sampling_rate = AudioBackend::get_sampling_rate();
XAudio.success("XAudio 2.9 initialized");
}
else if (hmodule = LoadLibraryExW(L"XAudio2_8.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32))
{
lib.reset(xa28_init(hmodule));
WAVEFORMATEX waveformatex;
waveformatex.wFormatTag = g_cfg.audio.convert_to_u16 ? WAVE_FORMAT_PCM : WAVE_FORMAT_IEEE_FLOAT;
waveformatex.nChannels = channels;
waveformatex.nSamplesPerSec = sampling_rate;
waveformatex.nAvgBytesPerSec = static_cast<DWORD>(sampling_rate * channels * sample_size);
waveformatex.nBlockAlign = channels * sample_size;
waveformatex.wBitsPerSample = sample_size * 8;
waveformatex.cbSize = 0;
XAudio.success("XAudio 2.8 initialized");
}
else if (hmodule = LoadLibraryExW(L"XAudio2_7.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32))
hr = m_xaudio2_instance->CreateSourceVoice(&m_source_voice, &waveformatex, 0, XAUDIO2_DEFAULT_FREQ_RATIO);
if (FAILED(hr))
{
lib.reset(xa27_init(hmodule));
XAudio.success("XAudio 2.7 initialized");
}
else
{
fmt::throw_exception("No supported XAudio2 library found");
}
XAudio.error("CreateSourceVoice() failed(0x%08x)", (u32)hr);
Emu.Pause();
return;
}
lib->open();
AUDIT(m_source_voice != nullptr);
m_source_voice->SetVolume(channels == 2 ? 1.0f : 4.0f);
}
bool XAudio2Backend::IsPlaying()
{
return lib->is_playing();
AUDIT(m_source_voice != nullptr);
XAUDIO2_VOICE_STATE state;
m_source_voice->GetState(&state, XAUDIO2_VOICE_NOSAMPLESPLAYED);
return state.BuffersQueued > 0 || state.pCurrentBufferContext != nullptr;
}
bool XAudio2Backend::AddData(const void* src, u32 num_samples)
{
return lib->add(src, num_samples);
AUDIT(m_source_voice != nullptr);
XAUDIO2_VOICE_STATE state;
m_source_voice->GetState(&state, XAUDIO2_VOICE_NOSAMPLESPLAYED);
if (state.BuffersQueued >= MAX_AUDIO_BUFFERS)
{
XAudio.warning("Too many buffers enqueued (%d)", state.BuffersQueued);
return false;
}
XAUDIO2_BUFFER buffer;
buffer.AudioBytes = num_samples * AudioBackend::get_sample_size();
buffer.Flags = 0;
buffer.LoopBegin = XAUDIO2_NO_LOOP_REGION;
buffer.LoopCount = 0;
buffer.LoopLength = 0;
buffer.pAudioData = static_cast<const BYTE*>(src);
buffer.pContext = nullptr;
buffer.PlayBegin = 0;
buffer.PlayLength = AUDIO_BUFFER_SAMPLES;
HRESULT hr = m_source_voice->SubmitSourceBuffer(&buffer);
if (FAILED(hr))
{
XAudio.error("AddData() failed(0x%08x)", (u32)hr);
Emu.Pause();
return false;
}
return true;
}
void XAudio2Backend::Flush()
{
lib->flush();
AUDIT(m_source_voice != nullptr);
HRESULT hr = m_source_voice->FlushSourceBuffers();
if (FAILED(hr))
{
XAudio.error("FlushSourceBuffers() failed(0x%08x)", (u32)hr);
Emu.Pause();
}
}
u64 XAudio2Backend::GetNumEnqueuedSamples()
{
return lib->enqueued_samples();
AUDIT(m_source_voice != nullptr);
XAUDIO2_VOICE_STATE state;
m_source_voice->GetState(&state);
// all buffers contain AUDIO_BUFFER_SAMPLES, so we can easily calculate how many samples there are remaining
return static_cast<u64>(AUDIO_BUFFER_SAMPLES - state.SamplesPlayed % AUDIO_BUFFER_SAMPLES) + (state.BuffersQueued * AUDIO_BUFFER_SAMPLES);
}
f32 XAudio2Backend::SetFrequencyRatio(f32 new_ratio)
{
return lib->set_freq_ratio(new_ratio);
new_ratio = std::clamp(new_ratio, XAUDIO2_MIN_FREQ_RATIO, XAUDIO2_DEFAULT_FREQ_RATIO);
HRESULT hr = m_source_voice->SetFrequencyRatio(new_ratio);
if (FAILED(hr))
{
XAudio.error("SetFrequencyRatio() failed(0x%08x)", (u32)hr);
Emu.Pause();
return 1.0f;
}
return new_ratio;
}

View File

@ -6,28 +6,16 @@
#include "Emu/Audio/AudioBackend.h"
#include <xaudio2redist.h>
#include <wrl/client.h>
class XAudio2Backend : public AudioBackend
{
public:
class XAudio2Library
{
public:
virtual void play() = 0;
virtual void flush() = 0;
virtual void stop() = 0;
virtual void open() = 0;
virtual bool is_playing() = 0;
virtual bool add(const void*, u32) = 0;
virtual u64 enqueued_samples() = 0;
virtual f32 set_freq_ratio(f32) = 0;
};
class XAudio2Backend final : public AudioBackend
{
private:
static XAudio2Library* xa27_init(void*);
static XAudio2Library* xa28_init(void*);
std::unique_ptr<XAudio2Library> lib = nullptr;
Microsoft::WRL::ComPtr<IXAudio2> m_xaudio2_instance;
IXAudio2MasteringVoice* m_master_voice{};
IXAudio2SourceVoice* m_source_voice{};
public:
XAudio2Backend();

View File

@ -115,13 +115,12 @@ if(USE_FAUDIO AND SDL2_FOUND AND NOT SDL2_VERSION VERSION_LESS 2.0.9)
endif()
if(WIN32)
target_include_directories(rpcs3_emu PUBLIC "${RPCS3_SRC_DIR}/../3rdparty/XAudio2Redist/include")
target_link_libraries(rpcs3_emu PRIVATE "${RPCS3_SRC_DIR}/../3rdparty/XAudio2Redist/libs/xaudio2_9redist.lib")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /DELAYLOAD:xaudio2_9redist.dll")
target_sources(rpcs3_emu PRIVATE
Audio/XAudio2/XAudio27Backend.cpp
Audio/XAudio2/XAudio28Backend.cpp
Audio/XAudio2/XAudio2Backend.cpp
)
# Slimmed down version of minidx9 for XAudio2_7 only
include_directories(BEFORE "${RPCS3_SRC_DIR}/../3rdparty/XAudio2_7")
endif()
target_link_libraries(rpcs3_emu

View File

@ -63,7 +63,7 @@
<PropertyGroup Label="UserMacros" />
<ItemDefinitionGroup>
<ClCompile>
<AdditionalIncludeDirectories>..\3rdparty\XAudio2_7;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>..\3rdparty\XAudio2Redist\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
</ItemDefinitionGroup>
<ItemGroup>
@ -76,8 +76,6 @@
</ItemGroup>
<ItemGroup>
<ClCompile Include="Emu\Audio\XAudio2\XAudio2Backend.cpp" />
<ClCompile Include="Emu\Audio\XAudio2\XAudio27Backend.cpp" />
<ClCompile Include="Emu\Audio\XAudio2\XAudio28Backend.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">

View File

@ -10,12 +10,6 @@
<ClCompile Include="Emu\Audio\XAudio2\XAudio2Backend.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Emu\Audio\XAudio2\XAudio27Backend.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Emu\Audio\XAudio2\XAudio28Backend.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Emu\Audio\XAudio2\XAudio2Backend.h">

File diff suppressed because it is too large Load Diff

View File

@ -3,7 +3,7 @@
<ImportGroup Label="PropertySheets" />
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<IncludePath>.\;..\;..\asmjit\src;..\3rdparty\yaml-cpp\include;..\3rdparty\ffmpeg\include;..\3rdparty\cereal\include;$(VC_IncludePath);$(WindowsSDK_IncludePath);$(UniversalCRT_IncludePath);..\3rdparty\minidx12\Include;..\3rdparty\span\include;..\3rdparty\libpng;..\3rdparty\GL;..\3rdparty\stblib;..\3rdparty\OpenAL\include;..\3rdparty\pugixml\src;..\3rdparty\hidapi\hidapi;..\3rdparty\Optional;..\3rdparty\xxhash</IncludePath>
<IncludePath>.\;..\;..\asmjit\src;..\3rdparty\yaml-cpp\include;..\3rdparty\ffmpeg\include;..\3rdparty\cereal\include;$(VC_IncludePath);$(WindowsSDK_IncludePath);$(UniversalCRT_IncludePath);..\3rdparty\span\include;..\3rdparty\libpng;..\3rdparty\GL;..\3rdparty\stblib;..\3rdparty\OpenAL\include;..\3rdparty\pugixml\src;..\3rdparty\hidapi\hidapi;..\3rdparty\Optional;..\3rdparty\xxhash</IncludePath>
<OutDir>$(SolutionDir)lib\$(Configuration)-$(Platform)\</OutDir>
<LibraryPath>$(SolutionDir)lib\$(Configuration)-$(Platform)\;$(UniversalCRT_LibraryPath_x64);$(LibraryPath)</LibraryPath>
<IntDir>$(SolutionDir)tmp\$(ProjectName)-$(Configuration)-$(Platform)\</IntDir>