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

# Convolution à flux unique avec enveloppe à l'aide de l'API XDSP

> Vue d'ensemble d'une convolution à flux unique avec enveloppe à l'aide de l'API XDSP

Dans cette rubrique, nous allons examiner le flux de code attendu pour utiliser la réverbération par convolution matérielle sur les appareils XBOX Series X, à l'aide de l'un des exemples inclus dans le Microsoft Game Development Kit (GDK).

## Connexion au matériel et démarrage

Une connexion doit être établie avec l'unité d'accélération matérielle via [XDspConnect](/fr/reference/audio/xdspaudio/functions/xdspconnect) ou [XDspConnectWithMaximumStreamLimit](/fr/reference/audio/xdspaudio/functions/xdspconnectwithmaximumstreamlimit). L'appelant définit les exigences de la connexion à l'aide des paramètres suivants :

1. *baseBuffer* : pointeur vers la mémoire allouée par l'utilisateur, suffisante pour contenir les mémoires tampons d'entrée, de sortie, d'enveloppe et/ou de multiplicateur de bloc qui seront passées au matériel. Cette mémoire doit être allouée via XMemAlloc avec les attributs suivants : *XALLOC\_MEMTYPE\_PHYSICAL\_CACHEABLE*, *XALLOC\_PAGESIZE\_64KB*, *XALLOC\_ALIGNMENT\_64K*. Ces attributs doivent être définis à l'aide de `MAKE_XALLOC_ATTRIBUTES()`, comme illustré dans l'exemple ci-dessous. Cette mémoire ne doit pas être libérée tant que l'appel à [XDspDisconnect](/fr/reference/audio/xdspaudio/functions/xdspdisconnect) n'a pas réussi. Cette mémoire tampon doit avoir une taille d'au moins 64 Ko.

2. *baseBufferLength* : longueur de *baseBuffer* en octets. Cette mémoire tampon doit avoir une taille d'au moins 64 Ko et d'au plus 500 Mo.

3. *aggregateImpulseResponseInSeconds* : représente la durée totale de toutes les réponses impulsionnelles individuelles qui seront activées simultanément à l'aide de [XDspActivate](/fr/reference/audio/xdspaudio/functions/xdspactivate) avec [XDspProcessType::Convolution](/fr/reference/audio/xdspaudio/enums/xdspprocesstype). Si cette valeur est 0, aucun flux avec [XDspProcessType::Convolution](/fr/reference/audio/xdspaudio/enums/xdspprocesstype) ne peut être activé.

4. handle : pointeur vers le [XDspClientHandle](/fr/reference/audio/xdspaudio/handles/xdspclienthandle) destiné à contenir le handle retourné par cet appel.

Si l'appel réussit, l'appelant peut utiliser *baseBuffer* pour passer les données d'entrée et récupérer les données de sortie des flux via les paramètres de [XDspCommand](/fr/reference/audio/xdspaudio/structs/xdspcommand). Toute mémoire tampon passée dans [XDspCommand](/fr/reference/audio/xdspaudio/structs/xdspcommand) doit être alignée sur 16 octets. L'exemple suivant de gestionnaire de mémoire tampon simple peut être utilisé pour gérer les mémoires tampons d'entrée et de sortie.

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

};
```

Les mémoires tampons d'enveloppe de chaque flux doivent faire partie du baseBuffer passé à **XDspConnect** ou **XDspConnectWithMaximumStreamLimit**, comme les mémoires tampons d'entrée et de sortie. La longueur de chaque mémoire tampon d'enveloppe peut être calculée comme suit.

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

Voici l'exemple de code de la première étape, qui consiste à allouer de la mémoire et à établir une connexion. Notez que **XDspConnectWithMaximumStreamLimit** peut être utilisé à la place de **XDspConnect** pour réduire l'utilisation de la mémoire interne si le nombre de flux pouvant être actifs est inférieur à 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);
```

Où XMemAllocAttributes représente les attributs mentionnés ci-dessus. Le code suivant définit *aggregateImpulseResponse* sur 32 secondes.

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

## Activation et désactivation des flux

Une fois la connexion établie avec l'appareil, l'appelant doit envoyer une commande d'activation de flux pour lancer une convolution, une FFT ou une IFFT. L'appelant doit spécifier dans [XDspActivationParameters](/fr/reference/audio/xdspaudio/structs/xdspactivationparameters) le [XDspProcessType](/fr/reference/audio/xdspaudio/enums/xdspprocesstype), le nombre de trames par bloc, le nombre de canaux, la longueur de la réponse impulsionnelle en valeurs float et un pointeur vers les données de réponse impulsionnelle dans le domaine fréquentiel. Seuls les flux mono ou stéréo sont autorisés. Pour [XDspProcessType::ForwardFourierTransform](/fr/reference/audio/xdspaudio/enums/xdspprocesstype) et [XDspProcessType::inverseFourierTransform](/fr/reference/audio/xdspaudio/enums/xdspprocesstype), [XDspActivationParameters::impulseResponse](/fr/reference/audio/xdspaudio/structs/xdspactivationparameters) doit être nullptr et [XDspActivationParameters::impulseResponseLengthInFloats](/fr/reference/audio/xdspaudio/structs/xdspactivationparameters) = 0. [XDspActivationOptions](/fr/reference/audio/xdspaudio/enums/xdspactivationoptions) doit être défini de manière appropriée.

Voici le code permettant d'activer un flux pour la 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](/fr/reference/audio/xdspaudio/functions/xdspactivate) retourne une mémoire tampon [XDspStatus](/fr/reference/audio/xdspaudio/structs/xdspstatus) dans l'un de ses paramètres. Cette mémoire tampon [XDspStatus](/fr/reference/audio/xdspaudio/structs/xdspstatus) doit être utilisée pour connaître l'état des commandes traitées par le matériel pour ce flux. Une fois le résultat de l'activation reçu, l'appelant peut commencer à soumettre des données pour la convolution/FFT/IFFT. Cela doit se faire à l'aide de l'API [XDspSubmitCommand](/fr/reference/audio/xdspaudio/functions/xdspsubmitcommand) ou [XDspSubmitCommandWithEnvelope](/fr/reference/audio/xdspaudio/functions/xdspsubmitcommandwithenvelope). À chaque appel, l'appelant doit effectuer les opérations suivantes :

1. Remplir la mémoire tampon d'entrée avec exactement *blockFrameCount* de données.
2. Renseigner [XDspCommand](/fr/reference/audio/xdspaudio/structs/xdspcommand) avec les valeurs appropriées et des mémoires tampons d'entrée et de sortie alignées sur 16 octets.
3. Appeler [XDspSubmitCommand](/fr/reference/audio/xdspaudio/functions/xdspsubmitcommand) pour soumettre la commande au matériel. Cette fonction retourne un numéro de séquence de commande qui peut être utilisé pour suivre le nombre de commandes envoyées au matériel.
4. Pour appliquer une enveloppe, remplir la mémoire tampon d'enveloppe avec les valeurs de gain de chaque bloc du filtre de réponse impulsionnelle, appeler [XDspSubmitCommandWithEnvelope](/fr/reference/audio/xdspaudio/functions/xdspsubmitcommandwithenvelope), puis continuer à effectuer cet appel avec la même mémoire tampon d'enveloppe jusqu'à ce que l'enveloppe ne soit plus nécessaire ou qu'elle doive être modifiée.
5. Lorsque l'enveloppe n'est plus nécessaire, appeler [XDspSubmitCommand](/fr/reference/audio/xdspaudio/functions/xdspsubmitcommand) ou [XDspSubmitCommandWithEnvelope](/fr/reference/audio/xdspaudio/functions/xdspsubmitcommandwithenvelope) avec nullptr pour *envelopeBuffer*. Notez que **XDspSubmitCommandWithEnvelope** avec nullptr pour *envelopeBuffer* équivaut à **XDspSubmitCommand**.
6. Lors du changement d'enveloppe, le *envelopeBuffer* actuel ne peut être mis à jour pour l'enveloppe suivante que si le matériel a traité toutes les commandes utilisant cette enveloppe et que les résultats ont été récupérés. Sinon, utilisez une autre mémoire tampon d'enveloppe.

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

L'extrait de code suivant montre un exemple de remplissage de la mémoire tampon d'enveloppe avec les valeurs de gain de chaque bloc du filtre de réponse impulsionnelle. Il montre comment utiliser uniquement la première moitié du filtre de réponse impulsionnelle : les valeurs de gain de la première moitié des blocs de réponse impulsionnelle commencent à 1.0f et diminuent de façon linéaire, et la seconde moitié est remplie avec une valeur de gain de 0.0f. Pour un filtre de réponse impulsionnelle stéréo, l'intégralité du filtre du canal gauche est suivie de celle du canal droit ; la mémoire tampon d'enveloppe du filtre de réponse impulsionnelle stéréo suit le même modèle, avec les valeurs de gain de l'ensemble du canal gauche suivies des valeurs de gain de l'ensemble du canal droit. Consultez [Vue d'ensemble de l'enveloppe à l'aide de l'API XDSP](/fr/build/console-features/audio/overviews/xdsp-overview-enveloping) pour plus d'informations sur le calcul de la taille de la mémoire tampon d'enveloppe.

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

L'extrait de code suivant montre l'application de l'enveloppe en appelant **XDspSubmitCommandWithEnvelope** avec un *envelopeBuffer* valide. Il est identique à l'extrait qui montre comment soumettre une commande à l'aide de **XDspSubmitCommand**, à l'exception du paramètre supplémentaire *envelopeBuffer* qui est passé. Cette opération doit être répétée jusqu'à ce que l'enveloppe ne soit plus nécessaire ; il faut alors appeler **XDspSubmitCommand** ou **XDspSubmitCommandWithEnvelope** avec nullptr pour *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++;
}
```

Ensuite, vous pouvez vérifier [XDspStatus](/fr/reference/audio/xdspaudio/structs/xdspstatus) pour connaître l'état des commandes soumises au matériel, comme suit :

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

Lorsque les paquets du flux ont été traités ou que le matériel retourne une erreur dans le résultat de [XDspStatus](/fr/reference/audio/xdspaudio/structs/xdspstatus), [XDspDeactivate](/fr/reference/audio/xdspaudio/functions/xdspdeactivate) doit être appelé.

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

[XDspDeactivate](/fr/reference/audio/xdspaudio/functions/xdspdeactivate) retourne *XDSP\_E\_PENDING\_RESULTS* si le matériel n'a pas fini de traiter toutes les commandes soumises pour ce flux.

## Arrêt

Une fois que [XDspDeactivate](/fr/reference/audio/xdspaudio/functions/xdspdeactivate) a réussi, l'appelant doit appeler [XDspDisconnect](/fr/reference/audio/xdspaudio/functions/xdspdisconnect) pour se déconnecter de l'unité d'accélération matérielle audio et libérer toutes les ressources allouées. Si tous les flux ne sont pas désactivés, [XDspDisconnect](/fr/reference/audio/xdspaudio/functions/xdspdisconnect) retourne l'erreur *XDSP\_E\_NOT\_ALL\_HANDLES\_DEACTIVATED*.

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

## Documentation de référence de l'API

* [XDspAudio (contenu de l'API)](/fr/reference/audio/xdspaudio/xdspaudio_members)
  * Fonctions
    * [XDspConnect](/fr/reference/audio/xdspaudio/functions/xdspconnect)
    * [XDspConnectWithMaximumStreamLimit](/fr/reference/audio/xdspaudio/functions/xdspconnectwithmaximumstreamlimit)
    * [XDspDisconnect](/fr/reference/audio/xdspaudio/functions/xdspdisconnect)
    * [XDspActivate](/fr/reference/audio/xdspaudio/functions/xdspactivate)
    * [XDspSubmitCommand](/fr/reference/audio/xdspaudio/functions/xdspsubmitcommand)
    * [XDspSubmitCommandWithEnvelope](/fr/reference/audio/xdspaudio/functions/xdspsubmitcommandwithenvelope)
    * [XDspDeactivate](/fr/reference/audio/xdspaudio/functions/xdspdeactivate)
  * Structures
    * [XDspCommand](/fr/reference/audio/xdspaudio/structs/xdspcommand)
    * [XDspActivationParameters](/fr/reference/audio/xdspaudio/structs/xdspactivationparameters)
    * [XDspStatus](/fr/reference/audio/xdspaudio/structs/xdspstatus)

## Voir aussi

[Vue d'ensemble de XDSP](/fr/build/console-features/audio/overviews/xdsp-overview)
[Vue d'ensemble de l'enveloppe à l'aide de l'API XDSP](/fr/build/console-features/audio/overviews/xdsp-overview-enveloping)


## Related topics

- [Ajouter des services dorsaux avec PlayFab](/fr-CA/home/build-first-title/add-backend-services.md)
- [XR-013 Liaison des comptes Microsoft avec les comptes d'éditeur](/fr/publishing/certification/xr/xr-013.md)
- [Certification (Certify)](/fr-CA/publishing/game-publishing/concepts/certification/certification-overview.md)
- [XR-064 Sessions de jeu joignables et jeu en ligne](/fr-CA/publishing/certification/xr/xr-064.md)
- [Exigences XBOX testées lors de la certification pour les jeux sur console XBOX](/fr/publishing/certification/console-cert-tested-requirements.md)
