1 /*-========================================================================-_ 2 | - XAPO - | 3 | Copyright (c) Microsoft Corporation. All rights reserved. | 4 |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| 5 |PROJECT: XAPO MODEL: Unmanaged User-mode | 6 |VERSION: 1.0 EXCEPT: No Exceptions | 7 |CLASS: N / A MINREQ: WinXP, Xbox360 | 8 |BASE: N / A DIALECT: MSC++ 14.00 | 9 |>------------------------------------------------------------------------<| 10 | DUTY: XAPO base classes | 11 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^ 12 NOTES: 13 1. See XAPO.h for the rules governing XAPO interface behaviour. */ 14 15 #ifdef _MSC_VER 16 #pragma once 17 #endif 18 19 //--------------<D-E-F-I-N-I-T-I-O-N-S>-------------------------------------// 20 #include "XAPO.h" 21 22 // default audio format ranges supported, applies to XAPO_LOCKFORPROCESS_BUFFER_PARAMETERS.pFormat 23 #define XAPOBASE_DEFAULT_FORMAT_TAG WAVE_FORMAT_IEEE_FLOAT // 32-bit float only, applies to WAVEFORMATEX.wFormatTag or WAVEFORMATEXTENSIBLE.SubFormat when used 24 #define XAPOBASE_DEFAULT_FORMAT_MIN_CHANNELS XAPO_MIN_CHANNELS // minimum channel count, applies to WAVEFORMATEX.nChannels 25 #define XAPOBASE_DEFAULT_FORMAT_MAX_CHANNELS XAPO_MAX_CHANNELS // maximum channel count, applies to WAVEFORMATEX.nChannels 26 #define XAPOBASE_DEFAULT_FORMAT_MIN_FRAMERATE XAPO_MIN_FRAMERATE // minimum framerate, applies to WAVEFORMATEX.nSamplesPerSec 27 #define XAPOBASE_DEFAULT_FORMAT_MAX_FRAMERATE XAPO_MAX_FRAMERATE // maximum framerate, applies to WAVEFORMATEX.nSamplesPerSec 28 #define XAPOBASE_DEFAULT_FORMAT_BITSPERSAMPLE 32 // 32-bit float only, applies to WAVEFORMATEX.wBitsPerSample and WAVEFORMATEXTENSIBLE.wValidBitsPerSample when used 29 30 // default XAPO property flags supported, applies to XAPO_LOCKFORPROCESS_BUFFER_PARAMETERS 31 #define XAPOBASE_DEFAULT_FLAG (XAPO_FLAG_CHANNELS_MUST_MATCH | XAPO_FLAG_FRAMERATE_MUST_MATCH | XAPO_FLAG_BITSPERSAMPLE_MUST_MATCH | XAPO_FLAG_BUFFERCOUNT_MUST_MATCH | XAPO_FLAG_INPLACE_SUPPORTED) 32 33 // default number of input and output buffers supported, applies to XAPO_LOCKFORPROCESS_BUFFER_PARAMETERS 34 #define XAPOBASE_DEFAULT_BUFFER_COUNT 1 35 36 //--------------<M-A-C-R-O-S>-----------------------------------------------// 37 // assertion 38 #if !defined(XAPOASSERT) 39 #if XAPODEBUG 40 #define XAPOASSERT(exp) if (!(exp)) { OutputDebugStringA("XAPO ASSERT: " #exp ", {" __FUNCTION__ "}\n"); __debugbreak(); } 41 #else 42 #define XAPOASSERT(exp) __assume(exp) 43 #endif 44 #endif 45 #if !defined(XAPOASSERT_NO_OUTPUT) 46 #if XAPODEBUG 47 #define XAPOASSERT_NO_OUTPUT(exp) if (!(exp)) { __debugbreak(); } 48 #else 49 #define XAPOASSERT_NO_OUTPUT(exp) __assume(exp) 50 #endif 51 #endif 52 53 //--------------<D-A-T-A---T-Y-P-E-S>---------------------------------------// 54 #pragma pack(push, 8) // set packing alignment to ensure consistency across arbitrary build environments, and ensure synchronization variables used by Interlocked functionality are correctly aligned 55 56 // primitive types 57 typedef float FLOAT32; // 32-bit IEEE float 58 59 //// 60 // DESCRIPTION: 61 // Default implementation of the IXAPO and IUnknown interfaces. 62 // Provides overridable implementations for all methods save IXAPO::Process. 63 //// 64 class __declspec(novtable) CXAPOBase: public IXAPO { 65 private: 66 const XAPO_REGISTRATION_PROPERTIES* m_pRegistrationProperties; // pointer to registration properties of the XAPO, set via constructor 67 68 void* m_pfnMatrixMixFunction; // optimal matrix function pointer, used for thru processing 69 FLOAT32* m_pfl32MatrixCoefficients; // matrix coefficient table, used for thru processing 70 UINT32 m_nSrcFormatType; // input format type, used for thru processing 71 BOOL m_fIsScalarMatrix; // TRUE if m_pfl32MatrixCoefficients is diagonal matrix with all main diagonal entries equal, i.e. m_pfnMatrixMixFunction only used for type conversion (no channel conversion), used for thru processing 72 BOOL m_fIsLocked; // TRUE if XAPO locked via CXAPOBase.LockForProcess 73 74 protected: 75 LONG m_lReferenceCount; // COM reference count, must be aligned for atomic operations 76 77 //// 78 // DESCRIPTION: 79 // Verifies an audio format falls within the default ranges supported. 80 // 81 // REMARKS: 82 // If pFormat is unsupported, and fOverwrite is TRUE, 83 // pFormat is overwritten with the nearest format supported. 84 // Nearest meaning closest bit depth, framerate, and channel count, 85 // in that order of importance. 86 // 87 // PARAMETERS: 88 // pFormat - [in/out] audio format to examine 89 // fOverwrite - [in] TRUE to overwrite pFormat if audio format unsupported 90 // 91 // RETURN VALUE: 92 // COM error code, including: 93 // S_OK - audio format supported, pFormat left untouched 94 // XAPO_E_FORMAT_UNSUPPORTED - audio format unsupported, pFormat overwritten with nearest audio format supported if fOverwrite TRUE 95 // E_INVALIDARG - audio format invalid, pFormat left untouched 96 //// 97 virtual HRESULT ValidateFormatDefault (_Inout_ WAVEFORMATEX* pFormat, BOOL fOverwrite); 98 99 //// 100 // DESCRIPTION: 101 // Verifies that an input/output format pair configuration is supported 102 // with respect to the XAPO property flags. 103 // 104 // REMARKS: 105 // If pRequestedFormat is unsupported, and fOverwrite is TRUE, 106 // pRequestedFormat is overwritten with the nearest format supported. 107 // Nearest meaning closest bit depth, framerate, and channel count, 108 // in that order of importance. 109 // 110 // PARAMETERS: 111 // pSupportedFormat - [in] audio format known to be supported 112 // pRequestedFormat - [in/out] audio format to examine, must be WAVEFORMATEXTENSIBLE if fOverwrite TRUE 113 // fOverwrite - [in] TRUE to overwrite pRequestedFormat if input/output configuration unsupported 114 // 115 // RETURN VALUE: 116 // COM error code, including: 117 // S_OK - input/output configuration supported, pRequestedFormat left untouched 118 // XAPO_E_FORMAT_UNSUPPORTED - input/output configuration unsupported, pRequestedFormat overwritten with nearest audio format supported if fOverwrite TRUE 119 // E_INVALIDARG - either audio format invalid, pRequestedFormat left untouched 120 //// 121 HRESULT ValidateFormatPair (const WAVEFORMATEX* pSupportedFormat, _Inout_ WAVEFORMATEX* pRequestedFormat, BOOL fOverwrite); 122 123 //// 124 // DESCRIPTION: 125 // This method may be called by an IXAPO::Process implementation 126 // for thru processing. It copies/mixes data from source to 127 // destination, making as few changes as possible to the audio data. 128 // 129 // REMARKS: 130 // However, this method is capable of channel upmix/downmix and uses 131 // the same matrix coefficient table used by windows Vista to do so. 132 // 133 // For in-place processing (input buffer == output buffer) 134 // this method does nothing. 135 // 136 // This method should be called only if the XAPO is locked and 137 // XAPO_FLAG_FRAMERATE_MUST_MATCH is used. 138 // 139 // PARAMETERS: 140 // pInputBuffer - [in] input buffer, format may be INT8, INT16, INT20 (contained in 24 or 32 bits), INT24 (contained in 24 or 32 bits), INT32, or FLOAT32 141 // pOutputBuffer - [out] output buffer, format must be FLOAT32 142 // FrameCount - [in] number of frames to process 143 // InputChannelCount - [in] number of input channels 144 // OutputChannelCount - [in] number of output channels 145 // MixWithOutput - [in] TRUE to mix with output, FALSE to overwrite output 146 // 147 // RETURN VALUE: 148 // void 149 //// 150 void ProcessThru (const void* pInputBuffer, _Inout_updates_(FrameCount*OutputChannelCount) FLOAT32* pOutputBuffer, UINT32 FrameCount, UINT32 InputChannelCount, UINT32 OutputChannelCount, BOOL MixWithOutput); 151 152 // accessors GetRegistrationPropertiesInternal()153 const XAPO_REGISTRATION_PROPERTIES* GetRegistrationPropertiesInternal () { return m_pRegistrationProperties; } IsLocked()154 BOOL IsLocked () { return m_fIsLocked; } 155 156 public: 157 CXAPOBase (const XAPO_REGISTRATION_PROPERTIES* pRegistrationProperties); 158 virtual ~CXAPOBase (); 159 160 // IUnknown methods: 161 // retrieves the requested interface pointer if supported STDMETHOD(QueryInterface)162 STDMETHOD(QueryInterface) (REFIID riid, _Outptr_ void** ppInterface) 163 { 164 XAPOASSERT(ppInterface != NULL); 165 HRESULT hr = S_OK; 166 167 if (riid == __uuidof(IXAPO)) { 168 *ppInterface = static_cast<IXAPO*>(this); 169 AddRef(); 170 } else if (riid == __uuidof(IUnknown)) { 171 *ppInterface = static_cast<IUnknown*>(this); 172 AddRef(); 173 } else { 174 *ppInterface = NULL; 175 hr = E_NOINTERFACE; 176 } 177 178 return hr; 179 } 180 181 // increments reference count STDMETHOD_(ULONG,AddRef)182 STDMETHOD_(ULONG, AddRef) () 183 { 184 return (ULONG)InterlockedIncrement(&m_lReferenceCount); 185 } 186 187 // decrements reference count and deletes the object if the reference count falls to zero STDMETHOD_(ULONG,Release)188 STDMETHOD_(ULONG, Release) () 189 { 190 ULONG uTmpReferenceCount = (ULONG)InterlockedDecrement(&m_lReferenceCount); 191 if (uTmpReferenceCount == 0) { 192 delete this; 193 } 194 return uTmpReferenceCount; 195 } 196 197 // IXAPO methods: 198 // Allocates a copy of the registration properties of the XAPO. 199 // This default implementation returns a copy of the registration 200 // properties given to the constructor, allocated via XAPOAlloc. 201 STDMETHOD(GetRegistrationProperties) (_Outptr_ XAPO_REGISTRATION_PROPERTIES** ppRegistrationProperties); 202 203 // Queries if a specific input format is supported for a given output format. 204 // This default implementation assumes only the format described by the 205 // XAPOBASE_DEFAULT_FORMAT values are supported for both input and output. 206 STDMETHOD(IsInputFormatSupported) (const WAVEFORMATEX* pOutputFormat, const WAVEFORMATEX* pRequestedInputFormat, _Outptr_opt_ WAVEFORMATEX** ppSupportedInputFormat); 207 208 // Queries if a specific output format is supported for a given input format. 209 // This default implementation assumes only the format described by the 210 // XAPOBASE_DEFAULT_FORMAT values are supported for both input and output. 211 STDMETHOD(IsOutputFormatSupported) (const WAVEFORMATEX* pInputFormat, const WAVEFORMATEX* pRequestedOutputFormat, _Outptr_opt_ WAVEFORMATEX** ppSupportedOutputFormat); 212 213 // Performs any effect-specific initialization. 214 // This default implementation is a no-op and only returns S_OK. STDMETHOD(Initialize)215 STDMETHOD(Initialize) (_In_reads_bytes_opt_(DataByteSize) const void*, UINT32 DataByteSize) 216 { 217 UNREFERENCED_PARAMETER(DataByteSize); 218 return S_OK; 219 } 220 221 // Resets variables dependent on frame history. 222 // This default implementation is a no-op: this base class contains no 223 // relevant state to reset. STDMETHOD_(void,Reset)224 STDMETHOD_(void, Reset) () { return; } 225 226 // Notifies XAPO of buffer formats Process() will be given. 227 // This default implementation performs basic input/output format 228 // validation against the XAPO's registration properties. 229 // Derived XAPOs should call the base implementation first. 230 STDMETHOD(LockForProcess) (_Pre_equal_to_(OutputLockedParameterCount) UINT32 InputLockedParameterCount, _In_reads_opt_(InputLockedParameterCount) const XAPO_LOCKFORPROCESS_BUFFER_PARAMETERS* pInputLockedParameters, _Pre_equal_to_(InputLockedParameterCount) UINT32 OutputLockedParameterCount, _In_reads_opt_(OutputLockedParameterCount) const XAPO_LOCKFORPROCESS_BUFFER_PARAMETERS* pOutputLockedParameters); 231 232 // Opposite of LockForProcess. 233 // Derived XAPOs should call the base implementation first. 234 STDMETHOD_(void, UnlockForProcess) (); 235 236 // Returns the number of input frames required to generate the requested number of output frames. 237 // By default, this method returns the same number of frames it was passed. STDMETHOD_(UINT32,CalcInputFrames)238 STDMETHOD_(UINT32, CalcInputFrames) (UINT32 OutputFrameCount) { return OutputFrameCount; } 239 240 // Returns the number of output frames generated for the requested number of input frames. 241 // By default, this method returns the same number of frames it was passed. STDMETHOD_(UINT32,CalcOutputFrames)242 STDMETHOD_(UINT32, CalcOutputFrames) (UINT32 InputFrameCount) { return InputFrameCount; } 243 }; 244 245 //--------------------------------------------------------------------------// 246 //// 247 // DESCRIPTION: 248 // Extends CXAPOBase, providing a default implementation of the 249 // IXAPOParameters interface with appropriate synchronization to 250 // protect variables shared between IXAPOParameters::GetParameters 251 // and IXAPOParameters::SetParameters/IXAPO::Process. 252 // 253 // This class is for parameter blocks whose size is larger than 4 bytes. 254 // For smaller parameter blocks, use atomic operations directly 255 // on the parameters for synchronization. 256 //// 257 class __declspec(novtable) CXAPOParametersBase: public CXAPOBase, public IXAPOParameters { 258 private: 259 BYTE* m_pParameterBlocks; // three contiguous process parameter blocks used for synchronization, user responsible for initialization of parameter blocks before IXAPO::Process/SetParameters/GetParameters called 260 BYTE* m_pCurrentParameters; // pointer to current process parameters, must be aligned for atomic operations 261 BYTE* m_pCurrentParametersInternal; // pointer to current process parameters (temp pointer read by SetParameters/BeginProcess/EndProcess) 262 UINT32 m_uCurrentParametersIndex; // index of current process parameters 263 UINT32 m_uParameterBlockByteSize; // size of a single parameter block in bytes, must be > 0 264 BOOL m_fNewerResultsReady; // TRUE if there exists new processing results not yet picked up by GetParameters(), must be aligned for atomic operations 265 BOOL m_fProducer; // TRUE if IXAPO::Process produces data to be returned by GetParameters(), SetParameters() and ParametersChanged() disallowed 266 267 public: 268 //// 269 // PARAMETERS: 270 // pRegistrationProperties - [in] registration properties of the XAPO 271 // pParameterBlocks - [in] three contiguous process parameter blocks used for synchronization 272 // uParameterBlockByteSize - [in] size of one of the parameter blocks, must be > 0, should be > 4 273 // fProducer - [in] TRUE if IXAPO::Process produces data to be returned by GetParameters() (SetParameters() and ParametersChanged() disallowed) 274 //// 275 CXAPOParametersBase (const XAPO_REGISTRATION_PROPERTIES* pRegistrationProperties, _In_reads_bytes_opt_(3*uParameterBlockByteSize) BYTE* pParameterBlocks, UINT32 uParameterBlockByteSize, BOOL fProducer); 276 virtual ~CXAPOParametersBase (); 277 278 // IUnknown methods: 279 // retrieves the requested interface pointer if supported STDMETHOD(QueryInterface)280 STDMETHOD(QueryInterface) (REFIID riid, _Outptr_result_maybenull_ void** ppInterface) 281 { 282 XAPOASSERT(ppInterface != NULL); 283 HRESULT hr = S_OK; 284 285 if (riid == __uuidof(IXAPOParameters)) { 286 *ppInterface = static_cast<IXAPOParameters*>(this); 287 CXAPOBase::AddRef(); 288 } else { 289 hr = CXAPOBase::QueryInterface(riid, ppInterface); 290 } 291 292 return hr; 293 } 294 295 // increments reference count STDMETHOD_(ULONG,AddRef)296 STDMETHOD_(ULONG, AddRef)() { return CXAPOBase::AddRef(); } 297 298 // decrements reference count and deletes the object if the reference count falls to zero STDMETHOD_(ULONG,Release)299 STDMETHOD_(ULONG, Release)() { return CXAPOBase::Release(); } 300 301 // IXAPOParameters methods: 302 // Sets effect-specific parameters. 303 // This method may only be called on the realtime audio processing thread. 304 STDMETHOD_(void, SetParameters) (_In_reads_bytes_(ParameterByteSize) const void* pParameters, UINT32 ParameterByteSize); 305 306 // Gets effect-specific parameters. 307 // This method may block and should not be called from the realtime thread. 308 // Get the current parameters via BeginProcess. 309 STDMETHOD_(void, GetParameters) (_Out_writes_bytes_(ParameterByteSize) void* pParameters, UINT32 ParameterByteSize); 310 311 // Called by SetParameters() to allow for user-defined parameter validation. 312 // SetParameters validates that ParameterByteSize == m_uParameterBlockByteSize 313 // so the user may assume/assert ParameterByteSize == m_uParameterBlockByteSize. 314 // This method should not block as it is called from the realtime thread. OnSetParameters(_In_reads_bytes_ (ParameterByteSize)const void * pParameters,UINT32 ParameterByteSize)315 virtual void OnSetParameters (_In_reads_bytes_(ParameterByteSize) const void* pParameters, UINT32 ParameterByteSize) 316 { 317 XAPOASSERT(m_uParameterBlockByteSize > 0); 318 XAPOASSERT(pParameters != NULL); 319 XAPOASSERT(ParameterByteSize == m_uParameterBlockByteSize); 320 } 321 322 // Returns TRUE if SetParameters() has been called since the last processing pass. 323 // May only be used within the XAPO's IXAPO::Process implementation, 324 // before BeginProcess is called. 325 BOOL ParametersChanged (); 326 327 // Returns latest process parameters. 328 // XAPOs must call this method within their IXAPO::Process 329 // implementation to access latest process parameters in threadsafe manner. 330 BYTE* BeginProcess (); 331 332 // Notifies CXAPOParametersBase that the XAPO has finished accessing 333 // the latest process parameters. 334 // XAPOs must call this method within their IXAPO::Process 335 // implementation to access latest process parameters in threadsafe manner. 336 void EndProcess (); 337 }; 338 339 #pragma pack(pop) // revert packing alignment 340 //---------------------------------<-EOF->----------------------------------// 341