> ## Documentation Index
> Fetch the complete documentation index at: https://devdocs.xbox.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Overview of a single stream Convolution using the XDSP API

> Overview of a single stream Convolution using the XDSP API

In this topic, we will walk through the expected code flow about how to use hardware Convolution reverb on XBOX Series X devices by using one of the samples included with the Microsoft Game Development Kit (GDK).

## Hardware connection and startup

A connection has to be established with the hardware acceleration unit via [XDspConnect](/reference/audio/xdspaudio/functions/xdspconnect) or [XDspConnectWithMaximumStreamLimit](/reference/audio/xdspaudio/functions/xdspconnectwithmaximumstreamlimit). The caller sets the requirements for the connection by using the following parameters:

1. *baseBuffer* - A pointer to the user allocated memory enough to hold input, output, envelope buffer and/or block multiplier buffers that will be passed to the hardware. This memory should be allocated via XMemAlloc with these attributes: *XALLOC\_MEMTYPE\_PHYSICAL\_CACHEABLE*, *XALLOC\_PAGESIZE\_64KB*, *XALLOC\_ALIGNMENT\_64K*. These attributes should be set using `MAKE_XALLOC_ATTRIBUTES()`, as shown in the example below. This memory should not be freed until [XDspDisconnect](/reference/audio/xdspaudio/functions/xdspdisconnect) call succeeds. This buffer should be at least 64KB in size.

2. *baseBufferLength* - The length of the *baseBuffer* in bytes. This buffer should be at least 64KB and no more than 500 MB.

3. *aggregateImpulseResponseInSeconds* - It represents the overall duration of all the individual impulse responses that will be activated simultaneously using [XDspActivate](/reference/audio/xdspaudio/functions/xdspactivate) with [XDspProcessType::Convolution](/reference/audio/xdspaudio/enums/xdspprocesstype). If this value is 0, no streams with [XDspProcessType::Convolution](/reference/audio/xdspaudio/enums/xdspprocesstype) can be activated.

4. handle - a pointer to the [XDspClientHandle](/reference/audio/xdspaudio/handles/xdspclienthandle) to hold the handle returned by this call.

If the call succeeds, the *baseBuffer* can be used by the caller to pass input data and retrieve the output data of the streams via [XDspCommand](/reference/audio/xdspaudio/structs/xdspcommand) parameters. Any buffer that is passed in the [XDspCommand](/reference/audio/xdspaudio/structs/xdspcommand) should be 16 byte aligned. The following example of a simple buffer manager can be used for managing the input and output buffers.

```cpp theme={null}
class ConvolveOneBufferManager
{
private:
    float const* _outputBuffer = nullptr;
    uint32_t _maxBufferFrameCount = 0;
    uint32_t _bufferStride = 0;
    uint32_t _maxBufferCount = 0;
    uint32_t _acquiredBufferCount = 0;
    uint32_t _channelCount = 1;

public:
    void Reset(float const* outputBuffer, uint32_t maxBufferCount, uint32_t maxBufferFrameCount, uint32_t channelCount) {
        _outputBuffer = outputBuffer;
        _maxBufferCount = maxBufferCount;
        _maxBufferFrameCount = maxBufferFrameCount;
        _channelCount = channelCount;
    }

    uint32_t GetMaxBufferFrameCount() const {
        return _maxBufferFrameCount;
    }

    bool IsFull() const {
        return _acquiredBufferCount >= _maxBufferCount;
    }

    void Acquire() {
        if (_acquiredBufferCount < _maxBufferCount) {
            _acquiredBufferCount++;
        }
    }

    void Release() {
        if (_acquiredBufferCount > 0) {
            _acquiredBufferCount--;
        }
    }

    float* GetOutputBuffer(uint32_t index) {
        return const_cast<float*>(_outputBuffer) + (((index % _maxBufferCount) * _maxBufferFrameCount * _channelCount));
    }

};
```

Following is the code example for the first step to allocate memory and establish a connection.

```cpp theme={null}
static const ULONGLONG XMemAllocAttributes = MAKE_XALLOC_ATTRIBUTES(allocatorId,
                      0,
                      XALLOC_MEMTYPE_PHYSICAL_CACHEABLE,
                      XALLOC_PAGESIZE_64KB,
                      XALLOC_ALIGNMENT_64K,
                      FALSE);

float* baseBuffer = (float *)XMemAlloc(baseBufferLength, XMemAllocAttributes);
```

Where XMemAllocAttributes represents the attributes mentioned above. The following code sets the *aggregateImpulseResponse* to 32 seconds.

```cpp theme={null}
hr = XDspConnect(baseBuffer, baseBufferLength, 32 /*aggregateImpulseResponseInSeconds*/, &clientHandle);
```

## Activation and deactivation of streams

After the connection is established with the device, the caller should send a stream activation command to engage a convolution, FFT or IFFT. The caller must specify the [XDspProcessType](/reference/audio/xdspaudio/enums/xdspprocesstype), block frame count, channel count, impulse response length in floats and a pointer to the impulse response data in frequency domain in the [XDspActivationParameters](/reference/audio/xdspaudio/structs/xdspactivationparameters). Only mono or stereo streams are allowed. For [XDspProcessType::ForwardFourierTransform](/reference/audio/xdspaudio/enums/xdspprocesstype) and [XDspProcessType::inverseFourierTransform](/reference/audio/xdspaudio/enums/xdspprocesstype), [XDspActivationParameters::impulseResponse](/reference/audio/xdspaudio/structs/xdspactivationparameters) should be nullptr and [XDspActivationParameters::impulseResponseLengthInFloats](/reference/audio/xdspaudio/structs/xdspactivationparameters) = 0. [XDspActivationOptions](/reference/audio/xdspaudio/enums/xdspactivationoptions) should be set appropriately.

Following is the code to activate one stream for convolution.

```cpp theme={null}
XDspActivationParameters params;
XDspStatus* status;
XDspStreamHandle* streamHandle;
params.type = XDspProcessType::Convolution;
params.blockFrameCount = maxBufferFrameCount;
params.channelCount = channelCount; // mono or stereo
params.impulseResponseLengthInFloats = filterFrameCount;
params.impulseResponse = filterBuffer;

if (channelCount == 2 && deinterleaved)
{
    params.options |= XDspActivationOptions::Deinterleaved;
}
if (stereoImpulseResponse)
{
    params.options |= XDspActivationOptions::StereoImpulseResponse;
}
hr = XDspActivate(clientHandle, &params, &status, &streamHandle); 
```

[XDspActivate](/reference/audio/xdspaudio/functions/xdspactivate) returns a [XDspStatus](/reference/audio/xdspaudio/structs/xdspstatus) buffer as one of its parameters. This [XDspStatus](/reference/audio/xdspaudio/structs/xdspstatus) buffer should be used to find the status of the commands processed by the hardware for this stream. After the activation result is received, the caller can start submitting data for Convolution/FFT/IFFT. This should be done by using the [XDspSubmitCommand](/reference/audio/xdspaudio/functions/xdspsubmitcommand) API. For each [XDspSubmitCommand](/reference/audio/xdspaudio/functions/xdspsubmitcommand), the caller must do the following:

1. Fill the input buffer with exactly *blockFrameCount* of data.
2. Fill in the [XDspCommand](/reference/audio/xdspaudio/structs/xdspcommand) with appropriate values and input and output buffers that are 16 byte aligned.
3. Call [XDspSubmitCommand](/reference/audio/xdspaudio/functions/xdspsubmitcommand) to submit the command to the hardware. This function returns a command sequence number that can be used to track the number of commands sent to the hardware.

```cpp theme={null}
XDspCommand command;

command.beginScale = 1.0f;
command.endScale = 1.0f;
command.inputBlockBuffer = inputDataBuffer;
command.outputBlockBuffer =  bufferManager.GetOutputBuffer(_totalCommandsSubmitted + 1);
command.blockBufferMultiplier = nullptr;

uint32_t sequence = 0;
hr = XDspSubmitCommand(streamHandle, &command, &sequence);

if (SUCCEEDED(hr))
{
    totalCommandsSubmitted++;
}
```

Next, [XDspStatus](/reference/audio/xdspaudio/structs/xdspstatus) can be checked to find the status of the commands submitted to the hardware as follows:

```cpp theme={null}
while (status->lastProcessedCommandSequence > totalResponsesReceived)
{
    totalResponsesReceived++;
 
    // Hardware status is only updated when there is a hardware fault and the
    // error is going to persist for the duration of the stream. But, all the
    // commands that have already been submitted will still be processed by
    // the hardware and we have to wait for these commands to be processed 
    // before calling XDspDeactivate.
    hr = status->result; 
     
    float* outBuffer = bufferManager.GetOutputBuffer(totalResponsesReceived);
    // The output will be in the outBuffer
    // Do something with the outBuffer
    bufferManager.Release();
}
```

The packets in the stream are processed or the hardware returns an error in [XDspStatus](/reference/audio/xdspaudio/structs/xdspstatus) result, [XDspDeactivate](/reference/audio/xdspaudio/functions/xdspdeactivate) should be called.

```cpp theme={null}
while (totalResponsesReceived < totalCommandsSubmitted)
{
    // run the above code in the while loop to obtain all the responses
}
hr = XDspDeactivate(streamHandle);
```

[XDspDeactivate](/reference/audio/xdspaudio/functions/xdspdeactivate) returns *XDSP\_E\_PENDING\_RESULTS* if the hardware is not done processing all commands submitted for this stream.

## Termination

After [XDspDeactivate](/reference/audio/xdspaudio/functions/xdspdeactivate) succeeds, the caller must call [XDspDisconnect](/reference/audio/xdspaudio/functions/xdspdisconnect) to disconnect from the audio hardware acceleration unit to free all the allocated resources. If all streams are not deactivated, [XDspDisconnect](/reference/audio/xdspaudio/functions/xdspdisconnect) will return *XDSP\_E\_NOT\_ALL\_HANDLES\_DEACTIVATED* error.

```cpp theme={null}
hr = XDspDisconnect(clientHandle);
XMemFree(baseBuffer, XMemAllocAttributes);
```

## Reference API documentation

* [XDspAudio (API contents)](/reference/audio/xdspaudio/xdspaudio_members)
  * Functions
    * [XDspConnect](/reference/audio/xdspaudio/functions/xdspconnect)
    * [XDspConnectWithMaximumStreamLimit](/reference/audio/xdspaudio/functions/xdspconnectwithmaximumstreamlimit)
    * [XDspDisconnect](/reference/audio/xdspaudio/functions/xdspdisconnect)
    * [XDspActivate](/reference/audio/xdspaudio/functions/xdspactivate)
    * [XDspSubmitCommand](/reference/audio/xdspaudio/functions/xdspsubmitcommand)
    * [XDspDeactivate](/reference/audio/xdspaudio/functions/xdspdeactivate)
  * Structures
    * [XDspCommand](/reference/audio/xdspaudio/structs/xdspcommand)
    * [XDspActivationParameters](/reference/audio/xdspaudio/structs/xdspactivationparameters)
    * [XDspStatus](/reference/audio/xdspaudio/structs/xdspstatus)

## See also

[XDSP Overview](/build/console-features/audio/overviews/xdsp-overview)


## Related topics

- [XDspConnectWithMaximumStreamLimit](/reference/audio/xdspaudio/functions/xdspconnectwithmaximumstreamlimit.md)
- [XDspActivate](/reference/audio/xdspaudio/functions/xdspactivate.md)
- [XDspDeactivate](/reference/audio/xdspaudio/functions/xdspdeactivate.md)
- [XDspDisconnect](/reference/audio/xdspaudio/functions/xdspdisconnect.md)
- [XDspSubmitCommandWithEnvelope](/reference/audio/xdspaudio/functions/xdspsubmitcommandwithenvelope.md)
