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

# Convolução de fluxo único com envelope usando a API XDSP

> Visão geral de uma convolução de fluxo único com envelope usando a API XDSP

Neste tópico, vamos explicar o fluxo de código esperado sobre como usar o reverb de convolução por hardware em dispositivos XBOX Series X usando um dos exemplos incluídos no Microsoft Game Development Kit (GDK).

## Conexão e inicialização do hardware

É necessário estabelecer uma conexão com a unidade de aceleração de hardware por meio de [XDspConnect](/pt-BR/reference/audio/xdspaudio/functions/xdspconnect) ou [XDspConnectWithMaximumStreamLimit](/pt-BR/reference/audio/xdspaudio/functions/xdspconnectwithmaximumstreamlimit). O chamador define os requisitos da conexão usando os seguintes parâmetros:

1. *baseBuffer* - Um ponteiro para a memória alocada pelo usuário, suficiente para armazenar os buffers de entrada, de saída, de envelope e/ou de multiplicador de bloco que serão passados ao hardware. Essa memória deve ser alocada por meio de XMemAlloc com estes atributos: *XALLOC\_MEMTYPE\_PHYSICAL\_CACHEABLE*, *XALLOC\_PAGESIZE\_64KB*, *XALLOC\_ALIGNMENT\_64K*. Esses atributos devem ser definidos usando `MAKE_XALLOC_ATTRIBUTES()`, conforme mostrado no exemplo abaixo. Essa memória não deve ser liberada até que a chamada de [XDspDisconnect](/pt-BR/reference/audio/xdspaudio/functions/xdspdisconnect) seja bem-sucedida. Esse buffer deve ter pelo menos 64KB de tamanho.

2. *baseBufferLength* - O comprimento do *baseBuffer* em bytes. Esse buffer deve ter pelo menos 64KB e no máximo 500 MB.

3. *aggregateImpulseResponseInSeconds* - Representa a duração total de todas as respostas ao impulso individuais que serão ativadas simultaneamente usando [XDspActivate](/pt-BR/reference/audio/xdspaudio/functions/xdspactivate) com [XDspProcessType::Convolution](/pt-BR/reference/audio/xdspaudio/enums/xdspprocesstype). Se esse valor for 0, nenhum fluxo com [XDspProcessType::Convolution](/pt-BR/reference/audio/xdspaudio/enums/xdspprocesstype) poderá ser ativado.

4. handle - um ponteiro para o [XDspClientHandle](/pt-BR/reference/audio/xdspaudio/handles/xdspclienthandle) que armazenará o identificador retornado por esta chamada.

Se a chamada for bem-sucedida, o *baseBuffer* poderá ser usado pelo chamador para passar dados de entrada e recuperar os dados de saída dos fluxos por meio dos parâmetros de [XDspCommand](/pt-BR/reference/audio/xdspaudio/structs/xdspcommand). Qualquer buffer passado no [XDspCommand](/pt-BR/reference/audio/xdspaudio/structs/xdspcommand) deve estar alinhado em 16 bytes. O exemplo a seguir de um gerenciador de buffers simples pode ser usado para gerenciar os buffers de entrada e saída.

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

};
```

Os buffers de envelope de cada fluxo devem fazer parte do baseBuffer passado para **XDspConnect** ou **XDspConnectWithMaximumStreamLimit**, assim como os buffers de entrada e saída. O comprimento de cada buffer de envelope pode ser calculado da seguinte forma.

```cpp theme={null}
#define ROUND_UP_TO_16BYTE_ALIGNED(x) (((x) + (15)) & ~(0xF))
uint32_t blockSize = 1024; // can be 512 or 1024
uint32_t irLengthInComplexes = impulseResponseLengthInFloats/2;
uint32_t numFilterBlocks = irLengthInComplexes/blockSize;

// In case of a stereo impulse response filter, the envelope buffer length will be 2 * envelopeLengthInBytes assuming impulseResponseLengthInFloats is the impule response length of a single channel.
uint32_t envelopeLengthInBytes = ROUND_UP_TO_16BYTE_ALIGNED(numFilterBlocks * sizeof(float));
uint32_t envelopeGainCount = envelopeLengthInBytes/sizeof(float);
```

Veja a seguir o exemplo de código da primeira etapa para alocar memória e estabelecer uma conexão. Observe que **XDspConnectWithMaximumStreamLimit** pode ser usado no lugar de **XDspConnect** para reduzir o uso de memória interna se o número de fluxos que podem estar ativos for inferior a 256.

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

Em que XMemAllocAttributes representa os atributos mencionados acima. O código a seguir define *aggregateImpulseResponse* como 32 segundos.

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

## Ativação e desativação de fluxos

Depois que a conexão com o dispositivo for estabelecida, o chamador deverá enviar um comando de ativação de fluxo para iniciar uma convolução, FFT ou IFFT. O chamador deve especificar o [XDspProcessType](/pt-BR/reference/audio/xdspaudio/enums/xdspprocesstype), a contagem de quadros do bloco, a contagem de canais, o comprimento da resposta ao impulso em floats e um ponteiro para os dados da resposta ao impulso no domínio da frequência em [XDspActivationParameters](/pt-BR/reference/audio/xdspaudio/structs/xdspactivationparameters). Somente fluxos mono ou estéreo são permitidos. Para [XDspProcessType::ForwardFourierTransform](/pt-BR/reference/audio/xdspaudio/enums/xdspprocesstype) e [XDspProcessType::inverseFourierTransform](/pt-BR/reference/audio/xdspaudio/enums/xdspprocesstype), [XDspActivationParameters::impulseResponse](/pt-BR/reference/audio/xdspaudio/structs/xdspactivationparameters) deve ser nullptr e [XDspActivationParameters::impulseResponseLengthInFloats](/pt-BR/reference/audio/xdspaudio/structs/xdspactivationparameters) = 0. [XDspActivationOptions](/pt-BR/reference/audio/xdspaudio/enums/xdspactivationoptions) deve ser definido adequadamente.

Veja a seguir o código para ativar um fluxo para convolução.

```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](/pt-BR/reference/audio/xdspaudio/functions/xdspactivate) retorna um buffer [XDspStatus](/pt-BR/reference/audio/xdspaudio/structs/xdspstatus) como um de seus parâmetros. Esse buffer [XDspStatus](/pt-BR/reference/audio/xdspaudio/structs/xdspstatus) deve ser usado para obter o status dos comandos processados pelo hardware para esse fluxo. Depois que o resultado da ativação for recebido, o chamador poderá começar a enviar dados para convolução/FFT/IFFT. Isso deve ser feito usando a API [XDspSubmitCommand](/pt-BR/reference/audio/xdspaudio/functions/xdspsubmitcommand) ou [XDspSubmitCommandWithEnvelope](/pt-BR/reference/audio/xdspaudio/functions/xdspsubmitcommandwithenvelope). Em cada chamada, o chamador deve fazer o seguinte:

1. Preencha o buffer de entrada com exatamente *blockFrameCount* de dados.
2. Preencha o [XDspCommand](/pt-BR/reference/audio/xdspaudio/structs/xdspcommand) com os valores apropriados e com buffers de entrada e saída alinhados em 16 bytes.
3. Chame [XDspSubmitCommand](/pt-BR/reference/audio/xdspaudio/functions/xdspsubmitcommand) para enviar o comando ao hardware. Essa função retorna um número de sequência de comando que pode ser usado para acompanhar o número de comandos enviados ao hardware.
4. Para aplicar um envelope, preencha o buffer de envelope com valores de ganho para cada bloco do filtro de resposta ao impulso, chame [XDspSubmitCommandWithEnvelope](/pt-BR/reference/audio/xdspaudio/functions/xdspsubmitcommandwithenvelope) e continue fazendo essa chamada com o mesmo buffer de envelope até que o envelopamento não seja mais necessário ou o envelope precise ser alterado.
5. Quando o envelopamento não for mais necessário, chame [XDspSubmitCommand](/pt-BR/reference/audio/xdspaudio/functions/xdspsubmitcommand) ou [XDspSubmitCommandWithEnvelope](/pt-BR/reference/audio/xdspaudio/functions/xdspsubmitcommandwithenvelope) com nullptr para *envelopeBuffer*. Observe que **XDspSubmitCommandWithEnvelope** com nullptr para *envelopeBuffer* é equivalente a **XDspSubmitCommand**.
6. Ao trocar o envelope, o *envelopeBuffer* atual só poderá ser atualizado para o próximo envelope se o hardware tiver processado todos os comandos que usam esse envelope e os resultados tiverem sido coletados. Caso contrário, use um buffer de envelope diferente.

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

O trecho de código a seguir mostra um exemplo de preenchimento do buffer de envelope com valores de ganho para cada bloco do filtro de resposta ao impulso. Ele mostra como usar apenas a primeira metade do filtro de resposta ao impulso, com os valores de ganho da primeira metade dos blocos de resposta ao impulso começando em 1.0f e diminuindo linearmente, e a segunda metade preenchida com um valor de ganho de 0.0f. Para um filtro de resposta ao impulso estéreo, o filtro inteiro do canal esquerdo é seguido pelo do canal direito; o buffer de envelope do filtro de resposta ao impulso estéreo segue o mesmo padrão, com os valores de ganho de todo o canal esquerdo seguidos pelos valores de ganho de todo o canal direito. Consulte [Visão geral do envelopamento usando a API XDSP](/pt-BR/build/console-features/audio/overviews/xdsp-overview-enveloping) para obter informações sobre como calcular o tamanho do buffer de envelope.

```cpp theme={null}
// Please see the code snippet at the beginning of this example for information on the envelope buffer size and envelope gain counts.
void CreateEnvelopeParams(
    float* envelopeBuffer, 
    uint32_t envelopeGainCount, 
    uint32_t numFilterBlocks,
    bool stereoImpulseResponse)
{
    const uint32_t envelopeRatio = 0.5f; // Use only half of the impulse response filter
    uint32_t numGains = (uint32_t)(envelopeRatio * numFilterBlocks);
    float gainDecrement = 1.0f/numGains;

    envelopeBuffer[0] = 1.0f;
        
    for (uint32_t i = 1; i < envelopeGainCount; i++)
    {
        if (i < numGains)
        {
            envelopeBuffer[i] = envelopeBuffer[i-1] - gainDecrement;
        }
        else
        {
            envelopeBuffer[i] = 0.0f;
        }
    }

    if (stereoImpulseResponse)
    {
        // Populate gain values for the right channel envelope
        memcpy((void*)&envelopeBuffer[envelopeGainCount], (void*)&envelopeBuffer[0], envelopeGainCount * sizeof(float));
    }
}
```

O trecho de código a seguir mostra a aplicação do envelope chamando **XDspSubmitCommandWithEnvelope** com um *envelopeBuffer* válido. Ele é igual ao trecho que mostra como enviar um comando usando **XDspSubmitCommand**, exceto pela passagem do parâmetro adicional *envelopeBuffer*. Isso deve ser repetido até que o envelope não seja mais necessário; nesse momento, deve-se chamar **XDspSubmitCommand** ou **XDspSubmitCommandWithEnvelope** com nullptr para *envelopeBuffer*.

```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 = XDspSubmitCommandWithEnvelope(streamHandle, &command, envelopeBuffer, &sequence);

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

Em seguida, [XDspStatus](/pt-BR/reference/audio/xdspaudio/structs/xdspstatus) pode ser verificado para obter o status dos comandos enviados ao hardware, da seguinte forma:

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

Quando os pacotes do fluxo forem processados ou o hardware retornar um erro no resultado de [XDspStatus](/pt-BR/reference/audio/xdspaudio/structs/xdspstatus), [XDspDeactivate](/pt-BR/reference/audio/xdspaudio/functions/xdspdeactivate) deverá ser chamado.

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

[XDspDeactivate](/pt-BR/reference/audio/xdspaudio/functions/xdspdeactivate) retornará *XDSP\_E\_PENDING\_RESULTS* se o hardware não tiver terminado de processar todos os comandos enviados para esse fluxo.

## Encerramento

Depois que [XDspDeactivate](/pt-BR/reference/audio/xdspaudio/functions/xdspdeactivate) for bem-sucedido, o chamador deverá chamar [XDspDisconnect](/pt-BR/reference/audio/xdspaudio/functions/xdspdisconnect) para se desconectar da unidade de aceleração de hardware de áudio e liberar todos os recursos alocados. Se nem todos os fluxos forem desativados, [XDspDisconnect](/pt-BR/reference/audio/xdspaudio/functions/xdspdisconnect) retornará o erro *XDSP\_E\_NOT\_ALL\_HANDLES\_DEACTIVATED*.

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

## Documentação de referência da API

* [XDspAudio (conteúdo da API)](/pt-BR/reference/audio/xdspaudio/xdspaudio_members)
  * Funções
    * [XDspConnect](/pt-BR/reference/audio/xdspaudio/functions/xdspconnect)
    * [XDspConnectWithMaximumStreamLimit](/pt-BR/reference/audio/xdspaudio/functions/xdspconnectwithmaximumstreamlimit)
    * [XDspDisconnect](/pt-BR/reference/audio/xdspaudio/functions/xdspdisconnect)
    * [XDspActivate](/pt-BR/reference/audio/xdspaudio/functions/xdspactivate)
    * [XDspSubmitCommand](/pt-BR/reference/audio/xdspaudio/functions/xdspsubmitcommand)
    * [XDspSubmitCommandWithEnvelope](/pt-BR/reference/audio/xdspaudio/functions/xdspsubmitcommandwithenvelope)
    * [XDspDeactivate](/pt-BR/reference/audio/xdspaudio/functions/xdspdeactivate)
  * Estruturas
    * [XDspCommand](/pt-BR/reference/audio/xdspaudio/structs/xdspcommand)
    * [XDspActivationParameters](/pt-BR/reference/audio/xdspaudio/structs/xdspactivationparameters)
    * [XDspStatus](/pt-BR/reference/audio/xdspaudio/structs/xdspstatus)

## Confira também

[Visão geral do XDSP](/pt-BR/build/console-features/audio/overviews/xdsp-overview)
[Visão geral do envelopamento usando a API XDSP](/pt-BR/build/console-features/audio/overviews/xdsp-overview-enveloping)


## Related topics

- [XDspSubmitCommandWithEnvelope](/es/reference/audio/xdspaudio/functions/xdspsubmitcommandwithenvelope.md)
- [Información general de XDSP](/es/build/console-features/audio/overviews/xdsp-overview.md)
- [XDspSubmitCommand](/es/reference/audio/xdspaudio/functions/xdspsubmitcommand.md)
- [Single-stream convolution with envelope using the XDSP API](/build/console-features/audio/overviews/xdsp-overview-single-stream-convolution-with-envelope.md)
- [Certificação (Certify)](/pt-BR/publishing/game-publishing/concepts/certification/certification-overview.md)
