mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-07 08:08:50 +00:00
Create() rework; comments tweaks; +hrtfapoapi
This commit is contained in:
Vendored
+60
-97
@@ -1,75 +1,45 @@
|
||||
#+build windows
|
||||
/* NOTES:
|
||||
1. Definition of terms:
|
||||
DSP: Digital Signal Processing.
|
||||
DSP: Digital Signal Processing.
|
||||
|
||||
CBR: Constant BitRate -- DSP that consumes a constant number of input samples to produce an output sample.
|
||||
input samples to produce an output sample.
|
||||
For example, a 22kHz to 44kHz resampler is CBR DSP.
|
||||
Even though the number of input to output samples differ,
|
||||
the ratio between input to output rate remains constant.
|
||||
All user-defined XAPOs are assumed to be CBR as
|
||||
XAudio2 only allows CBR DSP to be added to an effect chain.
|
||||
|
||||
For example, a 22kHz to 44kHz resampler is CBR DSP. Even though the number of input to output samples differ, the ratio between input to output rate remains constant.
|
||||
All user-defined XAPOs are assumed to be CBR as XAudio2 only allows CBR DSP to be added to an effect chain.
|
||||
|
||||
XAPO: Cross-platform Audio Processing Object --
|
||||
a thin wrapper that manages DSP code, allowing it to be easily plugged into an XAudio2 effect chain.
|
||||
to be easily plugged into an XAudio2 effect chain.
|
||||
|
||||
|
||||
Frame: A block of samples, one per channel, to be played simultaneously.
|
||||
to be played simultaneously.
|
||||
E.g. a mono stream has one sample per frame.
|
||||
E.g. a mono stream has one sample per frame.
|
||||
|
||||
In-Place: Processing such that the input buffer equals the output buffer (i.e. input data modified directly).
|
||||
output buffer (i.e. input data modified directly).
|
||||
This form of processing is generally more efficient
|
||||
than using separate memory for input and output.
|
||||
However, an XAPO may not perform format conversion
|
||||
when processing in-place.
|
||||
|
||||
This form of processing is generally more efficient than using separate memory for input and output.
|
||||
However, an XAPO may not perform format conversion when processing in-place.
|
||||
|
||||
2. XAPO member variables are divided into three classifications:
|
||||
Immutable: Set once via IXAPO.Initialize and remain
|
||||
constant during the lifespan of the XAPO.
|
||||
|
||||
Immutable: Set once via IXAPO.Initialize and remain constant during the lifespan of the XAPO.
|
||||
|
||||
Locked: May change before the XAPO is locked via
|
||||
IXAPO.LockForProcess but remain constant until IXAPO.UnlockForProcess is called.
|
||||
until IXAPO.UnlockForProcess is called.
|
||||
|
||||
|
||||
Dynamic: May change from one processing pass to the next, usually via IXAPOParameters.SetParameters.
|
||||
usually via IXAPOParameters.SetParameters.
|
||||
XAPOs should assign reasonable defaults to their dynamic
|
||||
variables during IXAPO.Initialize/LockForProcess so
|
||||
that calling IXAPOParameters.SetParameters is not
|
||||
required before processing begins.
|
||||
|
||||
XAPOs should assign reasonable defaults to their dynamic variables during IXAPO.Initialize/LockForProcess so that calling IXAPOParameters.SetParameters is not required before processing begins.
|
||||
|
||||
When implementing an XAPO, determine the type of each variable and initialize them in the appropriate method. Immutable variables are generally preferable over locked which are preferable over dynamic.
|
||||
initialize them in the appropriate method. Immutable variables are
|
||||
generally preferable over locked which are preferable over dynamic.
|
||||
That is, one should strive to minimize XAPO state changes for
|
||||
best performance, maintainability, and ease of use.
|
||||
|
||||
That is, one should strive to minimize XAPO state changes for best performance, maintainability, and ease of use.
|
||||
|
||||
3. To minimize glitches, the realtime audio processing thread must not block. XAPO methods called by the realtime thread are commented as non-blocking and therefore should not use blocking synchronization, allocate memory, access the disk, etc.
|
||||
not block. XAPO methods called by the realtime thread are commented
|
||||
as non-blocking and therefore should not use blocking synchronization,
|
||||
allocate memory, access the disk, etc. The XAPO interfaces were
|
||||
designed to allow an effect implementer to move such operations
|
||||
into other methods called on an application controlled thread.
|
||||
|
||||
The XAPO interfaces were designed to allow an effect implementer to move such operations into other methods called on an application controlled thread.
|
||||
|
||||
4. Extending functionality is accomplished through the addition of new COM interfaces. For example, if a new member is added to a parameter structure, a new interface using the new structure should be added, leaving the original interface unchanged.
|
||||
COM interfaces. For example, if a new member is added to a parameter
|
||||
structure, a new interface using the new structure should be added,
|
||||
leaving the original interface unchanged.
|
||||
This ensures consistent communication between future versions of
|
||||
XAudio2 and various versions of XAPOs that may exist in an application.
|
||||
|
||||
This ensures consistent communication between future versions of XAudio2 and various versions of XAPOs that may exist in an application.
|
||||
|
||||
5. All audio data is interleaved in XAudio2.
|
||||
The default audio format for an effect chain is WAVE_FORMAT_IEEE_FLOAT.
|
||||
The default audio format for an effect chain is WAVE_FORMAT_IEEE_FLOAT.
|
||||
|
||||
6. User-defined XAPOs should assume all input and output buffers are 16-byte aligned. */
|
||||
16-byte aligned.
|
||||
|
||||
7. See XAPOBase.odin for an XAPO base class which provides a default
|
||||
implementation for most of the interface methods defined below. */
|
||||
|
||||
|
||||
package windows_xaudio2
|
||||
|
||||
import win "core:sys/windows"
|
||||
@@ -77,8 +47,7 @@ import win "core:sys/windows"
|
||||
//--------------<D-E-F-I-N-I-T-I-O-N-S>-------------------------------------//
|
||||
|
||||
FORMAT_UNSUPPORTED := win.MAKE_HRESULT(win.SEVERITY.ERROR, win.FACILITY.XAPO, 0x01) // requested audio format unsupported
|
||||
FORMAT_UNSUPPORTED := win.MAKE_HRESULT(win.SEVERITY.ERROR, 0x897, 0x01) // requested audio format unsupported
|
||||
|
||||
|
||||
// supported number of channels (samples per frame) range
|
||||
XAPO_MIN_CHANNELS :: 1
|
||||
XAPO_MAX_CHANNELS :: 64
|
||||
@@ -111,11 +80,11 @@ XAPO_FLAG :: enum u32 {
|
||||
// XAPO must be run in-place. Use this flag only if your DSP implementation cannot process separate input and output buffers.
|
||||
// If set, the following flags must also be set:
|
||||
// CHANNELS_MUST_MATCH
|
||||
// XAPO_FLAG_FRAMERATE_MUST_MATCH
|
||||
// XAPO_FLAG_BITSPERSAMPLE_MUST_MATCH
|
||||
// XAPO_FLAG_BUFFERCOUNT_MUST_MATCH
|
||||
// XAPO_FLAG_INPLACE_SUPPORTED
|
||||
// Multiple input and output buffers may be used with in-place XAPOs, though the input buffer count must equal the output buffer count.
|
||||
// FRAMERATE_MUST_MATCH
|
||||
// BITSPERSAMPLE_MUST_MATCH
|
||||
// BUFFERCOUNT_MUST_MATCH
|
||||
// INPLACE_SUPPORTED
|
||||
// Multiple input and output buffers may be used with in-place XAPOs, though the input buffer count must equal the output buffer count.
|
||||
// When multiple input/output buffers are used, the XAPO may assume input buffer [N] equals output buffer [N] for in-place processing.
|
||||
INPLACE_REQUIRED = 5,
|
||||
|
||||
@@ -139,18 +108,18 @@ XAPO_REGISTRATION_PROPERTIES :: struct #packed {
|
||||
MinInputBufferCount: u32, // minimum number of input buffers required for processing, can be 0
|
||||
MaxInputBufferCount: u32, // maximum number of input buffers supported for processing, must be >= MinInputBufferCount
|
||||
MinOutputBufferCount: u32, // minimum number of output buffers required for processing, can be 0, must match MinInputBufferCount when XAPO_FLAG.BUFFERCOUNT_MUST_MATCH used
|
||||
MaxOutputBufferCount: u32, // maximum number of output buffers supported for processing, must be >= MinOutputBufferCount, must match MaxInputBufferCount when XAPO_FLAG_BUFFERCOUNT_MUST_MATCH used
|
||||
}
|
||||
MaxOutputBufferCount: u32, // maximum number of output buffers supported for processing, must be >= MinOutputBufferCount, must match MaxInputBufferCount when XAPO_FLAG.BUFFERCOUNT_MUST_MATCH used
|
||||
}
|
||||
|
||||
// LockForProcess buffer parameters:
|
||||
// Defines buffer parameters that remain constant while an XAPO is locked.
|
||||
// Used with IXAPO.LockForProcess.
|
||||
// For CBR XAPOs, MaxFrameCount is the only number of frames
|
||||
// For CBR XAPOs, MaxFrameCount is the only number of frames
|
||||
// IXAPO.Process would have to handle for the respective buffer.
|
||||
XAPO_LOCKFORPROCESS_BUFFER_PARAMETERS :: struct #packed {
|
||||
XAPO_LOCKFORPROCESS_BUFFER_PARAMETERS :: struct #packed {
|
||||
pFormat: ^WAVEFORMATEX, // buffer audio format
|
||||
MaxFrameCount: u32, // maximum number of frames in respective buffer that IXAPO.Process would have to handle, irrespective of dynamic variable settings, can be 0
|
||||
}
|
||||
}
|
||||
|
||||
// Buffer flags:
|
||||
// Describes assumed content of the respective buffer.
|
||||
@@ -161,31 +130,25 @@ XAPO_LOCKFORPROCESS_BUFFER_PARAMETERS :: struct #packed {
|
||||
// The flags represent what should be assumed is in the respective buffer. The flags may not reflect what is actually stored in memory.
|
||||
XAPO_BUFFER_FLAGS :: enum i32 {
|
||||
SILENT, // silent data should be assumed, respective memory may be uninitialized
|
||||
XAPO_BUFFER_VALID, // arbitrary data should be assumed (may or may not be silent frames), respective memory initialized
|
||||
}
|
||||
VALID, // arbitrary data should be assumed (may or may not be silent frames), respective memory initialized
|
||||
}
|
||||
|
||||
// Process buffer parameters:
|
||||
// Defines buffer parameters that may change from one processing pass to the next. Used with IXAPO.Process.
|
||||
// processing pass to the next. Used with IXAPO::Process.
|
||||
//
|
||||
// Note the byte size of the respective buffer must be at least:
|
||||
// Note the byte size of the respective buffer must be at least:
|
||||
// XAPO_LOCKFORPROCESS_BUFFER_PARAMETERS.MaxFrameCount * XAPO_LOCKFORPROCESS_BUFFER_PARAMETERS.pFormat.nBlockAlign
|
||||
//
|
||||
// Although the audio format and maximum size of the respective
|
||||
// buffer is locked (defined by XAPO_LOCKFORPROCESS_BUFFER_PARAMETERS),
|
||||
// the actual memory address of the buffer given is permitted to change
|
||||
// from one processing pass to the next.
|
||||
//
|
||||
// For CBR XAPOs, ValidFrameCount is constant while locked and equals
|
||||
// the respective XAPO_LOCKFORPROCESS_BUFFER_PARAMETERS.MaxFrameCount.
|
||||
XAPO_PROCESS_BUFFER_PARAMETERS :: struct #packed {
|
||||
// Although the audio format and maximum size of the respective buffer is locked (defined by XAPO_LOCKFORPROCESS_BUFFER_PARAMETERS), the actual memory address of the buffer given is permitted to change from one processing pass to the next.
|
||||
// For CBR XAPOs, ValidFrameCount is constant while locked and equals the respective XAPO_LOCKFORPROCESS_BUFFER_PARAMETERS.MaxFrameCount.
|
||||
XAPO_PROCESS_BUFFER_PARAMETERS :: struct #packed {
|
||||
pBuffer: rawptr, // audio data buffer, must be non-nil
|
||||
BufferFlags: XAPO_BUFFER_FLAGS, // describes assumed content of pBuffer, does not affect ValidFrameCount
|
||||
BufferFlags: XAPO_BUFFER_FLAGS, // describes assumed content of pBuffer, does not affect ValidFrameCount
|
||||
ValidFrameCount: u32, // number of frames of valid data, must be within respective [0, XAPO_LOCKFORPROCESS_BUFFER_PARAMETERS.MaxFrameCount], always XAPO_LOCKFORPROCESS_BUFFER_PARAMETERS.MaxFrameCount for CBR/user-defined XAPOs, does not affect BufferFlags
|
||||
}
|
||||
|
||||
// Used by IXAPO methods that must allocate arbitrary sized structures such as WAVEFORMATEX that are subsequently returned to the application.
|
||||
|
||||
XAPOAlloc :: win.CoTaskMemAlloc
|
||||
XAPOFree :: win.CoTaskMemFree
|
||||
|
||||
IXAPO_UUID_STRING :: "A410B984-9839-4819-A0BE-2856AE6B3ADB"
|
||||
IXAPO_UUID := &win.IID{0xA410B984, 0x9839, 0x4819, {0xA0, 0xBE, 0x28, 0x56, 0xAE, 0x6B, 0x3A, 0xDB}}
|
||||
IXAPO :: struct #raw_union {
|
||||
@@ -214,11 +177,11 @@ IXAPO_VTable :: struct {
|
||||
// pOutputFormat - [in] output format known to be supported
|
||||
// pRequestedInputFormat - [in] input format to examine
|
||||
// ppSupportedInputFormat - [out] receives pointer to nearest input format supported if not nil and input/output configuration unsupported, use XAPOFree to free structure, left untouched on any failure except FORMAT_UNSUPPORTED
|
||||
// RETURN VALUE:
|
||||
// RETURN VALUE:
|
||||
// COM error code, including:
|
||||
// S_OK - input/output configuration supported, ppSupportedInputFormat left untouched
|
||||
// FORMAT_UNSUPPORTED - input/output configuration unsupported, ppSupportedInputFormat receives pointer to nearest input format supported if not nil
|
||||
// E_INVALIDARG - either audio format invalid, ppSupportedInputFormat left untouched
|
||||
// E_INVALIDARG - either audio format invalid, ppSupportedInputFormat left untouched
|
||||
IsInputFormatSupported: proc "system" (this: ^IXAPO, pOutputFormat: ^WAVEFORMATEX, pRequestedInputFormat: ^WAVEFORMATEX, ppSupportedInputFormat: ^^WAVEFORMATEX) -> HRESULT,
|
||||
|
||||
// DESCRIPTION:
|
||||
@@ -232,11 +195,11 @@ IXAPO_VTable :: struct {
|
||||
// pInputFormat - [in] input format known to be supported
|
||||
// pRequestedOutputFormat - [in] output format to examine
|
||||
// ppSupportedOutputFormat - [out] receives pointer to nearest output format supported if not nil and input/output configuration unsupported, use XAPOFree to free structure, left untouched on any failure except FORMAT_UNSUPPORTED
|
||||
// RETURN VALUE:
|
||||
// RETURN VALUE:
|
||||
// COM error code, including:
|
||||
// S_OK - input/output configuration supported, ppSupportedOutputFormat left untouched
|
||||
// FORMAT_UNSUPPORTED - input/output configuration unsupported, ppSupportedOutputFormat receives pointer to nearest output format supported if not nil
|
||||
// E_INVALIDARG - either audio format invalid, ppSupportedOutputFormat left untouched
|
||||
// E_INVALIDARG - either audio format invalid, ppSupportedOutputFormat left untouched
|
||||
IsOutputFormatSupported: proc "system" (this: ^IXAPO, pInputFormat: ^WAVEFORMATEX, pRequestedOutputFormat: ^WAVEFORMATEX, ppSupportedOutputFormat: ^^WAVEFORMATEX) -> HRESULT,
|
||||
|
||||
// DESCRIPTION:
|
||||
@@ -246,10 +209,10 @@ IXAPO_VTable :: struct {
|
||||
// Immutable variables (constant during the lifespan of the XAPO) should be set once via this method.
|
||||
// Once initialized, an XAPO cannot be initialized again.
|
||||
// An XAPO should be initialized before passing it to XAudio2 as part of an effect chain. XAudio2 will not call this method; it exists for future content-driven initialization.
|
||||
// PARAMETERS:
|
||||
// PARAMETERS:
|
||||
// pData - [in] effect-specific initialization parameters, may be nil if DataByteSize == 0
|
||||
// DataByteSize - [in] size of pData in bytes, may be 0 if pData is NULL
|
||||
// RETURN VALUE:
|
||||
// DataByteSize - [in] size of pData in bytes, may be 0 if pData is nil
|
||||
// RETURN VALUE:
|
||||
// COM error code
|
||||
Initialize: proc "system" (this: ^IXAPO, pData: rawptr, DataByteSize: u32) -> HRESULT,
|
||||
|
||||
@@ -279,9 +242,9 @@ IXAPO_VTable :: struct {
|
||||
// PARAMETERS:
|
||||
// InputLockedParameterCount - [in] number of input buffers, must be within [XAPO_REGISTRATION_PROPERTIES.MinInputBufferCount, XAPO_REGISTRATION_PROPERTIES.MaxInputBufferCount]
|
||||
// pInputLockedParameters - [in] array of input locked buffer parameter structures, may be nil if InputLockedParameterCount == 0, otherwise must have InputLockedParameterCount elements
|
||||
// OutputLockedParameterCount - [in] number of output buffers, must be within [XAPO_REGISTRATION_PROPERTIES.MinOutputBufferCount, XAPO_REGISTRATION_PROPERTIES.MaxOutputBufferCount], must match InputLockedParameterCount when XAPO_FLAG_BUFFERCOUNT_MUST_MATCH used
|
||||
// pOutputLockedParameters - [in] array of output locked buffer parameter structures, may be NULL if OutputLockedParameterCount == 0, otherwise must have OutputLockedParameterCount elements
|
||||
// RETURN VALUE:
|
||||
// OutputLockedParameterCount - [in] number of output buffers, must be within [XAPO_REGISTRATION_PROPERTIES.MinOutputBufferCount, XAPO_REGISTRATION_PROPERTIES.MaxOutputBufferCount], must match InputLockedParameterCount when XAPO_FLAG.BUFFERCOUNT_MUST_MATCH used
|
||||
// pOutputLockedParameters - [in] array of output locked buffer parameter structures, may be nil if OutputLockedParameterCount == 0, otherwise must have OutputLockedParameterCount elements
|
||||
// RETURN VALUE:
|
||||
// COM error code
|
||||
LockForProcess: proc "system" (this: ^IXAPO, InputLockedParameterCount: u32, pInputLockedParameters: [^]XAPO_LOCKFORPROCESS_BUFFER_PARAMETERS, OutputLockedParameterCount: u32, pOutputLockedParameters: [^]XAPO_LOCKFORPROCESS_BUFFER_PARAMETERS) -> HRESULT,
|
||||
|
||||
@@ -303,16 +266,16 @@ IXAPO_VTable :: struct {
|
||||
// Multiple input/output buffers may be used with in-place XAPOs, though the input buffer count must equal the output buffer count.
|
||||
// When multiple input/output buffers are used with in-place XAPOs, the XAPO may assume input buffer [N] equals output buffer [N].
|
||||
// When IsEnabled is false, the XAPO should process thru. Thru processing means an XAPO should not apply its normal processing to the given input/output buffers during Process.
|
||||
// It should instead pass data from input to output with as little modification possible. Effects that perform format conversion should continue to do so.
|
||||
// The effect must ensure transitions between normal and thru processing do not introduce discontinuities into the signal.
|
||||
// It should instead pass data from input to output with as little modification possible. Effects that perform format conversion should continue to do so.
|
||||
// The effect must ensure transitions between normal and thru processing do not introduce discontinuities into the signal.
|
||||
// XAudio2 calls this method only if the XAPO is locked. This method should not block as it is called from the realtime thread.
|
||||
// PARAMETERS:
|
||||
// InputProcessParameterCount - [in] number of input buffers, matches respective InputLockedParameterCount parameter given to LockForProcess
|
||||
// pInputProcessParameters - [in] array of input process buffer parameter structures, may be nil if InputProcessParameterCount == 0, otherwise must have InputProcessParameterCount elements
|
||||
// OutputProcessParameterCount - [in] number of output buffers, matches respective OutputLockedParameterCount parameter given to LockForProcess
|
||||
// OutputProcessParameterCount - [in] number of output buffers, matches respective OutputLockedParameterCount parameter given to LockForProcess
|
||||
// pOutputProcessParameters - [in/out] array of output process buffer parameter structures, may be nil if OutputProcessParameterCount == 0, otherwise must have OutputProcessParameterCount elements
|
||||
// IsEnabled - [in] TRUE to process normally, FALSE to process thru
|
||||
// RETURN VALUE:
|
||||
// IsEnabled - [in] true to process normally, false to process thru
|
||||
// RETURN VALUE:
|
||||
// void
|
||||
Process: proc "system" (this: ^IXAPO, InputProcessParameterCount: u32, pInputProcessParameters: [^]XAPO_PROCESS_BUFFER_PARAMETERS, OutputProcessParameterCount: u32, pOutputProcessParameters: [^]XAPO_PROCESS_BUFFER_PARAMETERS, IsEnabled: b32),
|
||||
|
||||
@@ -358,7 +321,7 @@ IXAPOParameters_VTable :: struct {
|
||||
// This method should not block as it is called from the realtime thread.
|
||||
// PARAMETERS:
|
||||
// pParameters - [in] effect-specific parameter block, must be != nil
|
||||
// ParameterByteSize - [in] size of pParameters in bytes, must be > 0
|
||||
// ParameterByteSize - [in] size of pParameters in bytes, must be > 0
|
||||
// RETURN VALUE:
|
||||
// void
|
||||
SetParameters: proc "system" (this: ^IXAPOParameters, pParameters: rawptr, ParameterByteSize: u32),
|
||||
@@ -369,7 +332,7 @@ IXAPOParameters_VTable :: struct {
|
||||
// Unlike SetParameters, XAudio2 does not call this method on the realtime thread. Thus, the XAPO must protect variables shared with SetParameters/Process using appropriate synchronization.
|
||||
// PARAMETERS:
|
||||
// pParameters - [out] receives effect-specific parameter block, must be != nil
|
||||
// ParameterByteSize - [in] size of pParameters in bytes, must be > 0
|
||||
// ParameterByteSize - [in] size of pParameters in bytes, must be > 0
|
||||
// RETURN VALUE:
|
||||
// void
|
||||
GetParameters: proc "system" (this: ^IXAPOParameters, pParameters: rawptr, ParameterByteSize: u32),
|
||||
|
||||
Reference in New Issue
Block a user