> ## 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.

# XDSP Enveloping Overview

> XDSP Enveloping Overview

In this topic, we will walk through the usage of enveloping as part of performing convolution on XBOX Series X|S devices using XDSP. This mechanism was developed as a flexible method for developers to alter a portion of the impulse response filter dynamically on the existing stream without reactivating a new stream. [XDspSubmitCommandWithEnvelope](/reference/audio/xdspaudio/functions/xdspsubmitcommandwithenvelope) API is provided which takes an *envelopeBuffer* containing gain values for each block of the impulse response filter in addition to the parameters provided to the [XDspSubmitCommand](/reference/audio/xdspaudio/functions/xdspsubmitcommand) API. The gain values are multipled with the corresponding blocks in the impulse response filter during the convolution process to provide the desired effect. The original impulse response filter is not modified during this process.

To better understand the enveloping mechanism, let us define the following variables in the frequency domain:

* Let the impulse response filter signal for the frequency bin ***n*** of block ***m*** be ***f\[n,m] = f\_Real\[n,m] + if\_Imag\[n,m]***.
* Let the input signal for the frequency bin ***n*** of block ***m*** be ***s\[n,m] = s\_Real\[n,m] + is\_Imag\[n,m]***.
* Let the gain value for a filter block ***m*** be represented as ***K\[m]*** (the envelope gain for block ***m***).

Then the mathematical representation of enveloping is as follows:

***r\[n,m] = K\[m] \* f\[n,m] \* s\[n,m]***
***r\[n,m] = K\[m] \* (f\_Real\[n,m] + if\_Imag\[n,m]) \* (s\_Real\[n,m] + is\_Imag\[n,m])***

Whereby ***r\[n,m]*** is the convolutional output after each frequency bin and block has been scaled by the associated envelope gain. If no envelope gain is specified, then ***K\[m] = 1.0f*** for all block ***m***.

## Envelope buffer

The envelope buffer contains gain values in float for each block of impulse response filter to be applied during the convolution.  The minimum size of this buffer should be 8 float values in case of a mono impulse response filter and 16 float values for a stereo impulse response filter. In case of a stereo impulse response, the envelope buffer contains gain values for both the channels with gain values for entire left channel followed by the gain values for the entire right channel. The envelope length for each channel should be a multiple of 16 bytes, otherwise the output may not be correct. Any additional values as a result of rounding up to the nearest 16 byte multiple will be ignored. All buffer pointers should be 16 byte aligned.
This buffer must be part of the memory registered by [XDspConnect](/reference/audio/xdspaudio/functions/xdspconnect) or [XDspConnectWithMaximumStreamLimit](/reference/audio/xdspaudio/functions/xdspconnectwithmaximumstreamlimit) and should be 16 byte aligned. This buffer is used by the hardware and cannot be modified or freed until all the commands using this buffer are complete and responses have been picked up.
The count of gain values in envelope buffer should be the number of blocks in the impulse response filter rounded up to the nearest 16 byte multiple and is calculated as follows.

```cpp theme={null}
#define ROUND_UP_TO_16BYTE_ALIGNED(x) (((x) + (15)) & ~(0xF))

// XDspActivationParameters::impulseResponseLengthInFloats is the impulse response length of each channel in case of stereo IR
uint32_t irLengthInComplexes = XDspActivationParameters::impulseResponseLengthInFloats/2;  
uint32_t numFilterBlocks = irLengthInComplexes/XDspActivationParameters::blockFrameCount;

// Round up the envelope size to the nearest multiple of 16 bytes. Additional values resulting from the rounding will be ignored.
// envelopeGainCount represents the number of gain values an envelope buffer holds. In case of a stereo impulse response filter,
// this is the number of gain values per channel.
uint32_t envelopeLengthInBytes = ROUND_UP_TO_16BYTE_ALIGNED(numFilterBlocks * sizeof(float));
uint32_t envelopeGainCount = envelopeSize / sizeof(float)  

// Account for left and right channel envelopes in case of stereo impulse response
if (stereoImpulseRespone)
{
    envelopeLengthInBytes = envelopeLengthInBytes * 2;
}
```

This buffer follows the impulse response filter in nature. For stereo impulse response, the gain values for the entire left channel are followed by the gain values for the entire right channel in the same way as the left channel impulse response is followed by the right channel impulse response.
For a mono impulse response, the same gain values are applied to both the left and right channels of a stereo input signal.

## API usage

Here's a sample API usage pattern. Please see the notes below for additional details.

```cpp theme={null}
XDspSubmitCommand(...)/XDspSubmitCommandWithEnvelope(.., nullptr, ...);  // _envelopeState = Off;  
XDspSubmitCommand(...)/XDspSubmitCommandWithEnvelope(.., nullptr, ...);  // _envelopeState = Off;  
:::::::::::::::::::::::     
XDspSubmitCommandWithEnvelope(..., envelopeBuffer1, ...); // _envelopeState = Engaged with envelopeBuffer1  
XDspSubmitCommandWithEnvelope(..., envelopeBuffer1, ...); // _envelopeState = Engaged with envelopeBuffer1  
:::::::::::::::::::::: 
XDspSubmitCommandWithEnvelope(..., envelopeBuffer2, ...); // _envelopeState = Engaged with envelopeBuffer2  
XDspSubmitCommandWithEnvelope(..., envelopeBuffer2, ...); // _envelopeState = Engaged with envelopeBuffer2  
::::::::::::::::::::::  
XDspSubmitCommand(...)/XDspSubmitCommandWithEnvelope(.., nullptr, ...);  // _envelopeState = Off;  
XDspSubmitCommand(...)/XDspSubmitCommandWithEnvelope(.., nullptr, ...);  // _envelopeState = Off;  
:::::::::::::::::::::::
```

## Notes

Convolution is implemented as a multi-stage process and each input packet goes through one of these stages. To keep the output smooth, enveloping can be turned on or off only in the first stage. This means that enveloping effect may not be turned off/on immediately when the command is submitted. It may take a few calls for it to go into effect.

## Reference API documentation

* [XDspAudio (API contents)](/reference/audio/xdspaudio/xdspaudio_members)
  * Functions
    * [XDspSubmitCommandWithEnvelope](/reference/audio/xdspaudio/functions/xdspsubmitcommandwithenvelope)
    * [XDspSubmitCommand](/reference/audio/xdspaudio/functions/xdspsubmitcommand)
    * [XDspConnect](/reference/audio/xdspaudio/functions/xdspconnect)
    * [XDspConnectWithMaximumStreamLimit](/reference/audio/xdspaudio/functions/xdspconnectwithmaximumstreamlimit)

## See also

[XDSP Overview](/build/console-features/audio/overviews/xdsp-overview)
[XDspSubmitCommandWithEnvelope](/reference/audio/xdspaudio/functions/xdspsubmitcommandwithenvelope)
[Overview of a single stream Convolution with Envelope using the XDSP API](/build/console-features/audio/overviews/xdsp-overview-single-stream-convolution-with-envelope)


## Related topics

- [XDspSubmitCommandWithEnvelope](/reference/audio/xdspaudio/functions/xdspsubmitcommandwithenvelope.md)
- [XDspConnect](/reference/audio/xdspaudio/functions/xdspconnect.md)
- [XDspSubmitCommand](/reference/audio/xdspaudio/functions/xdspsubmitcommand.md)
- [XDspConnectWithMaximumStreamLimit](/reference/audio/xdspaudio/functions/xdspconnectwithmaximumstreamlimit.md)
- [XDSP overview](/build/console-features/audio/overviews/xdsp-overview.md)
