> ## 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 passerons en revue le déroulement prévu du code pour utiliser la réverbération par convolution matérielle sur les appareils XBOX Series X, à l'aide de l'un des exemples inclus avec 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 au moyen de [XDspConnect](/fr-CA/reference/audio/xdspaudio/functions/xdspconnect) ou de [XDspConnectWithMaximumStreamLimit](/fr-CA/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 transmises au matériel. Cette mémoire doit être allouée au moyen de 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 le montre l'exemple ci-dessous. Cette mémoire ne doit pas être libérée tant que l'appel à [XDspDisconnect](/fr-CA/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 globale de toutes les réponses impulsionnelles individuelles qui seront activées simultanément à l'aide de [XDspActivate](/fr-CA/reference/audio/xdspaudio/functions/xdspactivate) avec [XDspProcessType::Convolution](/fr-CA/reference/audio/xdspaudio/enums/xdspprocesstype). Si cette valeur est 0, aucun flux avec [XDspProcessType::Convolution](/fr-CA/reference/audio/xdspaudio/enums/xdspprocesstype) ne peut être activé.

4. handle : pointeur vers le [XDspClientHandle](/fr-CA/reference/audio/xdspaudio/handles/xdspclienthandle) qui contiendra le handle retourné par cet appel.

Si l'appel réussit, l'appelant peut utiliser *baseBuffer* pour transmettre les données d'entrée et récupérer les données de sortie des flux au moyen des paramètres de [XDspCommand](/fr-CA/reference/audio/xdspaudio/structs/xdspcommand). Toute mémoire tampon transmise dans [XDspCommand](/fr-CA/reference/audio/xdspaudio/structs/xdspcommand) doit être alignée sur 16 octets. L'exemple suivant d'un gestionnaire de mémoires tampons simple peut servir à 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 transmis à **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 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* à 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 le [XDspProcessType](/fr-CA/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 la réponse impulsionnelle dans le domaine fréquentiel dans [XDspActivationParameters](/fr-CA/reference/audio/xdspaudio/structs/xdspactivationparameters). Seuls les flux mono ou stéréo sont autorisés. Pour [XDspProcessType::ForwardFourierTransform](/fr-CA/reference/audio/xdspaudio/enums/xdspprocesstype) et [XDspProcessType::inverseFourierTransform](/fr-CA/reference/audio/xdspaudio/enums/xdspprocesstype), [XDspActivationParameters::impulseResponse](/fr-CA/reference/audio/xdspaudio/structs/xdspactivationparameters) doit être nullptr et [XDspActivationParameters::impulseResponseLengthInFloats](/fr-CA/reference/audio/xdspaudio/structs/xdspactivationparameters) = 0. [XDspActivationOptions](/fr-CA/reference/audio/xdspaudio/enums/xdspactivationoptions) doit être défini de façon 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-CA/reference/audio/xdspaudio/functions/xdspactivate) retourne une mémoire tampon [XDspStatus](/fr-CA/reference/audio/xdspaudio/structs/xdspstatus) dans l'un de ses paramètres. Cette mémoire tampon [XDspStatus](/fr-CA/reference/audio/xdspaudio/structs/xdspstatus) doit servir à 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, la FFT ou l'IFFT. Cela doit se faire à l'aide de l'API [XDspSubmitCommand](/fr-CA/reference/audio/xdspaudio/functions/xdspsubmitcommand) ou [XDspSubmitCommandWithEnvelope](/fr-CA/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* données.
2. Remplir [XDspCommand](/fr-CA/reference/audio/xdspaudio/structs/xdspcommand) avec les valeurs appropriées ainsi que des mémoires tampons d'entrée et de sortie alignées sur 16 octets.
3. Appeler [XDspSubmitCommand](/fr-CA/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 servir à 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-CA/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-CA/reference/audio/xdspaudio/functions/xdspsubmitcommand) ou [XDspSubmitCommandWithEnvelope](/fr-CA/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 la prochaine enveloppe 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 seulement la première moitié du filtre de réponse impulsionnelle : les valeurs de gain de la première moitié des blocs de la réponse impulsionnelle commencent à 1.0f et diminuent de façon linéaire, tandis que la seconde moitié est remplie avec une valeur de gain de 0.0f. Pour un filtre de réponse impulsionnelle stéréo, le filtre complet du canal gauche est suivi de celui du canal droit; la mémoire tampon d'enveloppe du filtre de réponse impulsionnelle stéréo suit le même modèle, les valeurs de gain de tout le canal gauche étant suivies des valeurs de gain de tout le canal droit. Consultez [Vue d'ensemble de l'enveloppe à l'aide de l'API XDSP](/fr-CA/build/console-features/audio/overviews/xdsp-overview-enveloping) pour savoir comment calculer 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**, sauf qu'il transmet le paramètre supplémentaire *envelopeBuffer*. 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-CA/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-CA/reference/audio/xdspaudio/structs/xdspstatus), [XDspDeactivate](/fr-CA/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-CA/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-CA/reference/audio/xdspaudio/functions/xdspdeactivate) a réussi, l'appelant doit appeler [XDspDisconnect](/fr-CA/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-CA/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-CA/reference/audio/xdspaudio/xdspaudio_members)
  * Fonctions
    * [XDspConnect](/fr-CA/reference/audio/xdspaudio/functions/xdspconnect)
    * [XDspConnectWithMaximumStreamLimit](/fr-CA/reference/audio/xdspaudio/functions/xdspconnectwithmaximumstreamlimit)
    * [XDspDisconnect](/fr-CA/reference/audio/xdspaudio/functions/xdspdisconnect)
    * [XDspActivate](/fr-CA/reference/audio/xdspaudio/functions/xdspactivate)
    * [XDspSubmitCommand](/fr-CA/reference/audio/xdspaudio/functions/xdspsubmitcommand)
    * [XDspSubmitCommandWithEnvelope](/fr-CA/reference/audio/xdspaudio/functions/xdspsubmitcommandwithenvelope)
    * [XDspDeactivate](/fr-CA/reference/audio/xdspaudio/functions/xdspdeactivate)
  * Structures
    * [XDspCommand](/fr-CA/reference/audio/xdspaudio/structs/xdspcommand)
    * [XDspActivationParameters](/fr-CA/reference/audio/xdspaudio/structs/xdspactivationparameters)
    * [XDspStatus](/fr-CA/reference/audio/xdspaudio/structs/xdspstatus)

## Voir aussi

[Vue d'ensemble de XDSP](/fr-CA/build/console-features/audio/overviews/xdsp-overview)
[Vue d'ensemble de l'enveloppe à l'aide de l'API XDSP](/fr-CA/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)
