> ## 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 包络概述

> XDSP 包络概述

在本主题中，我们将逐步介绍在 XBOX Series X|S 设备上使用 XDSP 执行卷积时的包络 (enveloping) 用法。这一机制是作为一种灵活手段而设计的，让开发者可以在现有流上动态改变脉冲响应滤波器的一部分，而无需重新激活一个新的流。为此提供了 [XDspSubmitCommandWithEnvelope](/reference/audio/xdspaudio/functions/xdspsubmitcommandwithenvelope) API，它在 [XDspSubmitCommand](/reference/audio/xdspaudio/functions/xdspsubmitcommand) API 参数的基础上，还额外接收一个包含脉冲响应滤波器每个块增益值的 *envelopeBuffer*。这些增益值会在卷积过程中与脉冲响应滤波器对应的块相乘，从而产生期望的效果。此过程中原始脉冲响应滤波器不会被修改。

为了更好地理解包络机制，我们在频域中定义以下变量：

* 令块 ***m*** 中频率区间 ***n*** 处的脉冲响应滤波器信号为 ***f\[n,m] = f\_Real\[n,m] + if\_Imag\[n,m]***。
* 令块 ***m*** 中频率区间 ***n*** 处的输入信号为 ***s\[n,m] = s\_Real\[n,m] + is\_Imag\[n,m]***。
* 令滤波器块 ***m*** 的增益值表示为 ***K\[m]***（块 ***m*** 的包络增益）。

那么包络的数学表达如下：

***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])***

其中 ***r\[n,m]*** 是每个频率区间和块都被相应包络增益缩放后的卷积输出。如果没有指定包络增益，则对所有块 ***m*** 有 ***K\[m] = 1.0f***。

## 包络缓冲区

包络缓冲区包含以浮点表示的每个脉冲响应滤波器块在卷积中应用的增益值。对于单声道脉冲响应滤波器，此缓冲区最小应为 8 个浮点值；对于立体声脉冲响应滤波器，最小应为 16 个浮点值。对于立体声脉冲响应，包络缓冲区包含两个声道的增益值：先是整个左声道的增益值，然后是整个右声道的增益值。每个声道的包络长度必须是 16 字节的倍数，否则输出可能不正确。任何因为向上取整到最近的 16 字节倍数而多出的值都会被忽略。所有缓冲区指针都应按 16 字节对齐。
该缓冲区必须属于通过 [XDspConnect](/reference/audio/xdspaudio/functions/xdspconnect) 或 [XDspConnectWithMaximumStreamLimit](/reference/audio/xdspaudio/functions/xdspconnectwithmaximumstreamlimit) 注册的内存，并按 16 字节对齐。该缓冲区由硬件使用，在使用它的所有命令完成并领取到响应之前不能被修改或释放。
包络缓冲区中的增益值数量应为脉冲响应滤波器的块数，并向上取整到最近的 16 字节倍数，计算方式如下。

```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;
}
```

该缓冲区在结构上与脉冲响应滤波器一致。对于立体声脉冲响应，整个左声道的增益值之后紧跟着整个右声道的增益值，正如脉冲响应中左声道之后紧跟着右声道一样。
对于单声道脉冲响应，同一组增益值会应用到立体声输入信号的左右两个声道上。

## API 用法

以下是一个示例 API 用法模式。更多细节请参见下方备注。

```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;  
:::::::::::::::::::::::
```

## 备注

卷积按多阶段方式实现，每个输入数据包都会经过其中一个阶段。为保证输出平滑，包络的开启或关闭只能在第一个阶段完成。这意味着提交命令后，包络效果的开启/关闭并不会立即生效，可能需要几次调用后才会实际生效。

## 参考 API 文档

* [XDspAudio (API 内容)](/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)

## 另请参阅

[XDSP 概述](/build/console-features/audio/overviews/xdsp-overview)
[XDspSubmitCommandWithEnvelope](/reference/audio/xdspaudio/functions/xdspsubmitcommandwithenvelope)
[使用 XDSP API 进行带包络的单流卷积概述](/build/console-features/audio/overviews/xdsp-overview-single-stream-convolution-with-envelope)


## Related topics

- [XDSP 概述](/zh-CN/build/console-features/audio/overviews/xdsp-overview.md)
- [使用 XDSP API 进行带包络的单流卷积](/zh-CN/build/console-features/audio/overviews/xdsp-overview-single-stream-convolution-with-envelope.md)
- [XDSP audio](/zh-CN/reference/audio/xdspaudio/xdspaudio_members.md)
- [概述](/zh-CN/build/console-features/audio/overviews/index.md)
- [XDspConnect](/zh-CN/reference/audio/xdspaudio/functions/xdspconnect.md)
