UWP: Prise en charge des Graphiques Audio dans vos applications

In Mobile Development by Christian HissibiniLeave a Comment

Dans cette article, nous décrivons l’utilisation des API dans l’espace Windows.Media.Audio pour créer des graphiques pour le routage audio, le mixage et le traitement audio.

Un graphique audio est un ensemble de nœuds audio interconnectés par lequel passe le flux des données audio.

  • Les nœuds d’entrée audio transmettent au graphique les données en provenance des appareils d’entrée audio, des fichiers audio ou du code personnalisé.
  • L’audio traitée par le graphique se dirige vers les nœuds de sortie audio. L’audio peut être routée à la sortie du graphique vers des appareils de sortie audio, des fichiers audio ou du code personnalisé.
  • Les nœuds prémixés extraient l’audio à partir d’un ou plusieurs nœuds et la combine en une seule sortie pouvant être routée vers d’autres nœuds dans le graphique.

Une fois tous les nœuds créés et les connexions entre eux configurées, vous pouvez démarrer le graphique audio. Le flux de données audio est alors transmis des nœuds d’entrée aux nœuds de sortie, par le biais des nœuds prémixés. Ce modèle facilite et accélère l’implémentation de scénarios, tels que l’enregistrement sur un fichier audio à partir du microphone de l’appareil, la lecture audio à partir d’un fichier vers le haut-parleur de l’appareil ou le mixage audio à partir de plusieurs sources.

Des scénarios supplémentaires sont disponibles en ajoutant des effets audio au graphique audio. Chaque nœud d’un graphique audio peut contenir plusieurs effets audio qui effectuent le traitement sur l’audio traversant le nœud. Plusieurs effets intégrés comme l’écho, l’égaliseur, la limitation et la réverbération peuvent être attachés à un nœud audio simplement avec quelques lignes de code.Vous pouvez aussi créer vos propres effets audio pour produire les mêmes effets intégrés.

 Notes

L’exemple AudioGraph UWP implémente le code décrit dans cette vue d’ensemble. Vous pouvez télécharger l’exemple pour voir le code en contexte ou pour vous en servir comme point de départ pour votre propre application.

Choix de Windows Runtime AudioGraph ou XAudio2

Les API de graphique audio Windows Runtime offrent des fonctionnalités qui peuvent également être implémentées à l’aide d’API XAudio2 COM. Les fonctionnalités de l’infrastructure de graphique audio suivantes diffèrent entre Windows Runtime et XAudio2.

Les API de graphique audio Windows Runtime:

  • Sont bien plus simples d’utilisation que XAudio2.
  • Peuvent être utilisées à partir de C# , en plus de la prise en charge pour C++.
  • Peuvent utiliser directement des fichiers audio, notamment les formats de fichier compressé. XAudio2 fonctionne uniquement sur les mémoires tampons audio et n’offre pas de fonctionnalités d’E/S fichier.
  • Peuvent utiliser le pipeline audio à faible latence dans Windows 10.
  • Prennent en charge le changement de point de terminaison automatique lorsque les paramètres de point de terminaison par défaut sont utilisés. Par exemple, si l’utilisateur bascule du haut-parleur de l’appareil à un casque, l’audio est automatiquement redirigée vers la nouvelle entrée.

Classe AudioGraph

La classe AudioGraph est le parent de tous les nœuds qui composent le graphique. Utilisez cet objet pour créer des instances de tous les types de nœud audio. Créez une instance de la classe AudioGraph en initialisant un objet AudioGraphSettings contenant des paramètres de configuration pour le graphique, puis en appelant AudioGraph.CreateAsync. L’objet CreateAudioGraphResultrenvoyé donne accès au graphique audio créé ou fournit une valeur d’erreur en cas d’échec de création du graphique audio.C#Copier

AudioGraph audioGraph;

C#Copier

private async Task InitAudioGraph()
{

    AudioGraphSettings settings = new AudioGraphSettings(Windows.Media.Render.AudioRenderCategory.Media);

    CreateAudioGraphResult result = await AudioGraph.CreateAsync(settings);
    if (result.Status != AudioGraphCreationStatus.Success)
    {
        ShowErrorMessage("AudioGraph creation error: " + result.Status.ToString());
    }

    audioGraph = result.Graph;

}
  • Tous les types de nœud audio sont créés en utilisant les méthodes Create* de la classe AudioGraph.
  • La méthode AudioGraph.Start entraîne le graphique audio à traiter les données audio. La méthode AudioGraph.Stop arrête le traitement audio. Chaque nœud du graphique peut être démarré et arrêté de façon indépendante lorsque le graphique est en cours d’exécution, mais aucun nœud n’est actif lorsque le graphique est arrêté. ResetAllNodes entraîne tous les nœuds du graphique à ignorer toutes les données actuellement présentes dans leurs mémoires tampons audio.
  • L’événement QuantumStarted se produit lorsque le graphique commence le traitement d’un nouveau quantum de données audio. L’événement QuantumProcessed se produit lorsque le traitement d’un quantum est terminé.
  • La seule propriété AudioGraphSettings requise est AudioRenderCategory. Cette valeur permet au système d’optimiser le pipeline audio pour la catégorie spécifiée.
  • La taille du quantum du graphique audio détermine le nombre d’échantillons traités en une seule fois. Par défaut, la taille du quantum est de 10 ms, basée sur le taux d’échantillonnage par défaut. Si vous spécifiez une taille de quantum personnalisée en définissant la propriété DesiredSamplesPerQuantum, vous devez également définir la propriété QuantumSizeSelectionModesur ClosestToDesired, ou la valeur indiquée sera ignorée. Si cette valeur est utilisée, le système choisit une taille de quantum aussi proche que possible de celle que vous avez spécifiée. Pour déterminer la taille réelle du quantum, vérifiez la propriété SamplesPerQuantum du AudioGraph après sa création.
  • Si vous prévoyez seulement d’utiliser le graphique audio avec des fichiers et que vous n’envisagez pas de sortie vers un appareil audio, il est recommandé d’utiliser la taille de quantum par défaut en ne définissant pas la propriété DesiredSamplesPerQuantum.
  • La propriété DesiredRenderDeviceAudioProcessing détermine la quantité de traitement que l’appareil de rendu principal effectue sur la sortie du graphique audio. Le paramètre Default permet au système d’utiliser le traitement audio par défaut pour la catégorie de rendu audio spécifiée. Ce traitement peut considérablement améliorer le son sur certains appareils, en particulier les appareils mobiles équipés de petits haut-parleurs. Le paramètre Raw peut améliorer les performances en réduisant la quantité de traitement du signal, mais peut entraîner une qualité audio médiocre sur certains appareils.
  • Si QuantumSizeSelectionMode est défini sur LowestLatency, le graphique audio utilise automatiquement Raw pourDesiredRenderDeviceAudioProcessing.
  • À partir de Windows10, version1803, vous pouvez utiliser la propriété AudioGraphSettings.MaxPlaybackSpeedFactor pour définir une valeur maximale utilisée pour les propriétés AudioFileInputNode.PlaybackSpeedFactorAudioFrameInputNode.PlaybackSpeedFactor et MediaSourceInputNode.PlaybackSpeedFactor. Lorsqu’un graphique audio prend en charge un facteur de vitesse de lecture supérieur à 1, le système doit allouer plus de mémoire afin de maintenir une mémoire tampon suffisante de données audio. Pour cette raison, la définition de MaxPlaybackSpeedFactor sur la valeur la plus basse requise par votre application permet de réduire la consommation de mémoire de votre application. Si votre application lit uniquement le contenu à la vitesse normale, il est recommandé de définir MaxPlaybackSpeedFactor sur 1.
  • La EncodingProperties détermine le format audio utilisé par le graphique. Seuls les formats flottants 32 bits sont pris en charge.
  • La PrimaryRenderDevice configure l’appareil de rendu principal pour le graphique audio. Si vous ne définissez pas cette propriété, l’appareil système par défaut est utilisé. L’appareil de rendu principal est utilisé pour calculer les tailles de quantum pour les autres nœuds du graphique. S’il n’existe aucun appareil de rendu audio sur le système, la création de graphique audio échouera.

Vous pouvez laisser le graphique audio utiliser l’appareil de rendu audio par défaut ou utiliser la classe Windows.Devices.Enumeration.DeviceInformation pour obtenir la liste des appareils disponibles sur le système en appelant FindAllAsync et en utilisant le sélecteur d’appareil de rendu audio renvoyé par Windows.Media.Devices.MediaDevice.GetAudioRenderSelector. Vous pouvez choisir l’un des objets DeviceInformation renvoyés par programme ou afficher l’interface utilisateur pour permettre à l’utilisateur de sélectionner un appareil et de l’utiliser pour définir la propriété PrimaryRenderDevice.C#Copier

Windows.Devices.Enumeration.DeviceInformationCollection devices =
 await Windows.Devices.Enumeration.DeviceInformation.FindAllAsync(Windows.Media.Devices.MediaDevice.GetAudioRenderSelector());

// Show UI to allow the user to select a device
Windows.Devices.Enumeration.DeviceInformation selectedDevice = ShowMyDeviceSelectionUI(devices);


settings.PrimaryRenderDevice = selectedDevice;

Nœud d’entrée d’appareil

Un nœud d’entrée d’appareil transmet l’audio au graphique à partir d’un appareil de capture audio connecté au système, par exemple un microphone. Créez un objet DeviceInputNode qui utilise l’appareil de capture audio par défaut du système en appelant CreateDeviceInputNodeAsync. Indiquez un objet AudioRenderCategory pour permettre au système d’optimiser le pipeline audio pour la catégorie spécifiée.C#Copier

AudioDeviceInputNode deviceInputNode;

C#Copier

private async Task CreateDeviceInputNode()
{
    // Create a device output node
    CreateAudioDeviceInputNodeResult result = await audioGraph.CreateDeviceInputNodeAsync(Windows.Media.Capture.MediaCategory.Media);

    if (result.Status != AudioDeviceNodeCreationStatus.Success)
    {
        // Cannot create device output node
        ShowErrorMessage(result.Status.ToString());
        return;
    }

    deviceInputNode = result.DeviceInputNode;
}

Si vous souhaitez indiquer un appareil de capture audio spécifique pour le nœud d’entrée d’appareil, vous pouvez utiliser la classe Windows.Devices.Enumeration.DeviceInformation pour obtenir la liste des périphériques de capture audio disponibles du système en appelant la méthode FindAllAsync et passage de l’audio de rendu sélecteur d’appareil renvoyé par Windows.Media.Devices.MediaDevice.GetAudioCaptureSelector. Vous pouvez choisir l’un des objets DeviceInformation renvoyés par programme ou afficher l’interface utilisateur pour permettre à l’utilisateur de sélectionner un appareil pour le transmettre à CreateDeviceInputNodeAsync.C#Copier

Windows.Devices.Enumeration.DeviceInformationCollection devices =
 await Windows.Devices.Enumeration.DeviceInformation.FindAllAsync(Windows.Media.Devices.MediaDevice.GetAudioCaptureSelector());

// Show UI to allow the user to select a device
Windows.Devices.Enumeration.DeviceInformation selectedDevice = ShowMyDeviceSelectionUI(devices);

CreateAudioDeviceInputNodeResult result =
    await audioGraph.CreateDeviceInputNodeAsync(Windows.Media.Capture.MediaCategory.Media, audioGraph.EncodingProperties, selectedDevice);

Nœud de sortie d’appareil

Un nœud de sortie d’appareil transmet l’audio du graphique vers l’appareil de rendu audio, par exemple des haut-parleurs ou un casque. Créez un DeviceOutputNode en appelant CreateDeviceOutputNodeAsync. Le nœud de sortie utilise l’objet PrimaryRenderDevice du graphique audio.C#Copier

AudioDeviceOutputNode deviceOutputNode;

C#Copier

private async Task CreateDeviceOutputNode()
{
    // Create a device output node
    CreateAudioDeviceOutputNodeResult result = await audioGraph.CreateDeviceOutputNodeAsync();

    if (result.Status != AudioDeviceNodeCreationStatus.Success)
    {
        // Cannot create device output node
        ShowErrorMessage(result.Status.ToString());
        return;
    }

    deviceOutputNode = result.DeviceOutputNode;
}

Nœud d’entrée de fichier

Un nœud d’entrée de fichier permet de transmettre les données d’un fichier audio au graphique. Créez un objet AudioFileInputNodeen appelant CreateFileInputNodeAsync.C#Copier

AudioFileInputNode fileInputNode;

C#Copier

private async Task CreateFileInputNode()
{
    if (audioGraph == null)
        return;

    FileOpenPicker filePicker = new FileOpenPicker();
    filePicker.SuggestedStartLocation = PickerLocationId.MusicLibrary;
    filePicker.FileTypeFilter.Add(".mp3");
    filePicker.FileTypeFilter.Add(".wav");
    filePicker.FileTypeFilter.Add(".wma");
    filePicker.FileTypeFilter.Add(".m4a");
    filePicker.ViewMode = PickerViewMode.Thumbnail;
    StorageFile file = await filePicker.PickSingleFileAsync();

    // File can be null if cancel is hit in the file picker
    if (file == null)
    {
        return;
    }
    CreateAudioFileInputNodeResult result = await audioGraph.CreateFileInputNodeAsync(file);

    if (result.Status != AudioFileNodeCreationStatus.Success)
    {
        ShowErrorMessage(result.Status.ToString());
    }

    fileInputNode = result.FileInputNode;
}
  • Les nœuds d’entrée de fichier prennent en charge les formats suivants: mp3, wav, wma et m4a.
  • Définissez la propriété StartTime pour spécifier le décalage dans le fichier où la lecture doit commencer. Si cette propriété est null, le début du fichier est utilisé. Définissez la propriété EndTime pour spécifier le décalage dans le fichier où la lecture doit se terminer. Si cette propriété est null, la fin du fichier est utilisée. L’heure de début doit être antérieure à l’heure de fin, et l’heure de fin doit être inférieure ou égale à la durée du fichier audio, qui peut être déterminée en vérifiant la valeur de propriété Duration.
  • Recherchez une position dans le fichier audio en appelant Seek et en spécifiant le décalage dans le fichier vers lequel la position de lecture doit être déplacée. La valeur spécifiée doit être comprise entre StartTime et EndTime. Obtenez la position de lecture actuelle du nœud avec la propriété Position en lecture seule.
  • Activez la boucle du fichier audio en définissant la propriété LoopCount. Lorsqu’elle n’est pas null, cette valeur indique le nombre de fois que le fichier est lu après la lecture initiale. Par exemple, la définition de LoopCount sur 1 entraîne la lecture du fichier 2 fois en tout, la définition sur 5 entraîne la lecture du fichier 6 fois en tout. Si vous définissez LoopCount sur null, le fichier sera lu en boucle indéfiniment. Pour arrêter la lecture en boucle, définissez la valeur sur 0.
  • Réglez la vitesse à laquelle le fichier audio est lu en définissant la PlaybackSpeedFactor. Une valeur de 1 correspond à la vitesse d’origine du fichier, 0,5 correspond à la vitesse intermédiaire et 2 correspond à la vitesse double.

Nœud d’entrée MediaSource

La classe MediaSource offre une méthode courante de référencement de contenu multimédia à partir de différentes sources et présente un modèle commun d’accès aux données multimédias, quel que soit le format multimédia sous-jacent, qui peut être un fichier sur disque, un flux ou une source réseau de diffusion en continu adaptative. Un nœud **MediaSourceAudioInputNode vous permet de diriger les données audio d’un objet MediaSource dans le graphique audio. Créez un objet MediaSourceAudioInputNodeen appelant CreateMediaSourceAudioInputNodeAsync, qui transmet un objet MediaSource représentant le contenu que vous souhaitez lire. Un objet **CreateMediaSourceAudioInputNodeResult est retourné. Vous pouvez l’utiliser pour déterminer l’état de l’opération en vérifiant la propriété Status. Si l’état est Success, vous pouvez obtenir l’objet MediaSourceAudioInputNode créé en accédant à la propriété Node. L’exemple suivant illustre la création d’un nœud à partir d’un objet AdaptiveMediaSource représentant la diffusion du contenu sur le réseau. Pour plus d’informations sur l’utilisation de MediaSource, voir Éléments, playlists et pistes multimédias. Pour plus d’informations sur la diffusion de contenu multimédia sur Internet, voir Streaming adaptatif.C#Copier

MediaSourceAudioInputNode mediaSourceInputNode;

C#Copier

private async Task CreateMediaSourceInputNode(System.Uri contentUri)
{
    if (audioGraph == null)
        return;

    var adaptiveMediaSourceResult = await AdaptiveMediaSource.CreateFromUriAsync(contentUri);
    if(adaptiveMediaSourceResult.Status != AdaptiveMediaSourceCreationStatus.Success)
    {
        Debug.WriteLine("Failed to create AdaptiveMediaSource");
        return;
    }

    var mediaSource = MediaSource.CreateFromAdaptiveMediaSource(adaptiveMediaSourceResult.MediaSource);
    CreateMediaSourceAudioInputNodeResult mediaSourceAudioInputNodeResult =
        await audioGraph.CreateMediaSourceAudioInputNodeAsync(mediaSource);

    if (mediaSourceAudioInputNodeResult.Status != MediaSourceAudioInputNodeCreationStatus.Success)
    {
        switch (mediaSourceAudioInputNodeResult.Status)
        {
            case MediaSourceAudioInputNodeCreationStatus.FormatNotSupported:
                Debug.WriteLine("The MediaSource uses an unsupported format");
                break;
            case MediaSourceAudioInputNodeCreationStatus.NetworkError:
                Debug.WriteLine("The MediaSource requires a network connection and a network-related error occurred");
                break;
            case MediaSourceAudioInputNodeCreationStatus.UnknownFailure:
            default:
                Debug.WriteLine("An unknown error occurred while opening the MediaSource");
                break;
        }
        return;
    }

    mediaSourceInputNode = mediaSourceAudioInputNodeResult.Node;
}

Pour recevoir une notification lorsque la lecture a atteint la fin du contenu MediaSource, enregistrez un gestionnaire pour l’événement MediaSourceCompleted.C#Copier

mediaSourceInputNode.MediaSourceCompleted += MediaSourceInputNode_MediaSourceCompleted;

C#Copier

private void MediaSourceInputNode_MediaSourceCompleted(MediaSourceAudioInputNode sender, object args)
{
    audioGraph.Stop();
}

La lecture d’un fichier à partir d’un disque est toujours susceptible de se terminer avec succès, mais le contenu multimédia diffusé à partir d’une source réseau peut échouer pendant la lecture en raison d’une modification de la connexion réseau ou d’autres problèmes qui sont hors du contrôle du graphique audio. Si un objet MediaSource devient illisible pendant la lecture, le graphique audio déclenche l’événement UnrecoverableErrorOccurred. Vous pouvez utiliser le gestionnaire de cet événement pour arrêter et supprimer le graphique audio et réinitialiser votre graphique.C#Copier

audioGraph.UnrecoverableErrorOccurred += AudioGraph_UnrecoverableErrorOccurred;

C#Copier

private void AudioGraph_UnrecoverableErrorOccurred(AudioGraph sender, AudioGraphUnrecoverableErrorOccurredEventArgs args)
{
    if (sender == audioGraph && args.Error != AudioGraphUnrecoverableError.None)
    {
        Debug.WriteLine("The audio graph encountered and unrecoverable error.");
        audioGraph.Stop();
        audioGraph.Dispose();
        InitAudioGraph();
    }
}

Nœud de sortie de fichier

Un nœud de sortie de fichier vous permet de diriger les données audio du graphique vers un fichier audio. Créez un objet AudioFileOutputNode en appelant CreateFileOutputNodeAsync.C#Copier

AudioFileOutputNode fileOutputNode;

C#Copier

private async Task CreateFileOutputNode()
{
    FileSavePicker saveFilePicker = new FileSavePicker();
    saveFilePicker.FileTypeChoices.Add("Pulse Code Modulation", new List<string>() { ".wav" });
    saveFilePicker.FileTypeChoices.Add("Windows Media Audio", new List<string>() { ".wma" });
    saveFilePicker.FileTypeChoices.Add("MPEG Audio Layer-3", new List<string>() { ".mp3" });
    saveFilePicker.SuggestedFileName = "New Audio Track";
    StorageFile file = await saveFilePicker.PickSaveFileAsync();

    // File can be null if cancel is hit in the file picker
    if (file == null)
    {
        return;
    }

    Windows.Media.MediaProperties.MediaEncodingProfile mediaEncodingProfile;
    switch (file.FileType.ToString().ToLowerInvariant())
    {
        case ".wma":
            mediaEncodingProfile = MediaEncodingProfile.CreateWma(AudioEncodingQuality.High);
            break;
        case ".mp3":
            mediaEncodingProfile = MediaEncodingProfile.CreateMp3(AudioEncodingQuality.High);
            break;
        case ".wav":
            mediaEncodingProfile = MediaEncodingProfile.CreateWav(AudioEncodingQuality.High);
            break;
        default:
            throw new ArgumentException();
    }


    // Operate node at the graph format, but save file at the specified format
    CreateAudioFileOutputNodeResult result = await audioGraph.CreateFileOutputNodeAsync(file, mediaEncodingProfile);

    if (result.Status != AudioFileNodeCreationStatus.Success)
    {
        // FileOutputNode creation failed
        ShowErrorMessage(result.Status.ToString());
        return;
    }

    fileOutputNode = result.FileOutputNode;
}

Nœud d’entrée de trame audio

Un nœud d’entrée de trame audio vous permet de transmettre au graphique audio les données audio que vous générez dans votre propre code. Cela permet notamment la création d’un synthétiseur logiciel personnalisé. Créez un objet AudioFrameInputNode en appelant CreateFrameInputNode.C#Copier

AudioFrameInputNode frameInputNode;

C#Copier

private void CreateFrameInputNode()
{
    // Create the FrameInputNode at the same format as the graph, except explicitly set mono.
    AudioEncodingProperties nodeEncodingProperties = audioGraph.EncodingProperties;
    nodeEncodingProperties.ChannelCount = 1;
    frameInputNode = audioGraph.CreateFrameInputNode(nodeEncodingProperties);

    // Initialize the Frame Input Node in the stopped state
    frameInputNode.Stop();

    // Hook up an event handler so we can start generating samples when needed
    // This event is triggered when the node is required to provide data
    frameInputNode.QuantumStarted += node_QuantumStarted;
}

L’événement FrameInputNode.QuantumStarted est déclenché lorsque le graphique audio est prêt à commencer le traitement du prochain quantum de données audio. Vous fournissez à cet événement vos données audio personnalisées depuis le gestionnaire.C#Copier

private void node_QuantumStarted(AudioFrameInputNode sender, FrameInputNodeQuantumStartedEventArgs args)
{
    // GenerateAudioData can provide PCM audio data by directly synthesizing it or reading from a file.
    // Need to know how many samples are required. In this case, the node is running at the same rate as the rest of the graph
    // For minimum latency, only provide the required amount of samples. Extra samples will introduce additional latency.
    uint numSamplesNeeded = (uint)args.RequiredSamples;

    if (numSamplesNeeded != 0)
    {
        AudioFrame audioData = GenerateAudioData(numSamplesNeeded);
        frameInputNode.AddFrame(audioData);
    }
}
  • L’objet FrameInputNodeQuantumStartedEventArgs transmis au gestionnaire d’événements QuantumStarted expose la propriété RequiredSamples qui indique le nombre d’échantillons dont le graphique audio a besoin pour remplir le quantum à traiter.
  • Appelez AudioFrameInputNode.AddFrame pour transmettre un objet AudioFrame contenant les données audio au graphique.
  • Un nouvel ensemble d’API permettant d’utiliser MediaFrameReader avec des données audio a été introduit dans Windows10, version1803. Ces API permettent d’obtenir des objets AudioFrame à partir d’une source d’images multimédias, qui peuvent être transmis dans un objet FrameInputNode à l’aide de la méthode AddFrame. Pour plus d’informations, voir Traiter des trames audio avec MediaFrameReader.
  • Un exemple d’implémentation de la méthode d’assistance GenerateAudioData est indiqué ci-dessous.

Pour remplir un AudioFrame avec des données audio, vous devez accéder à la mémoire tampon sous-jacente de la trame audio. Pour ce faire, vous devez initialiser l’interface COM IMemoryBufferByteAccess en ajoutant le code suivant dans votre espace de noms.C#Copier

[ComImport]
[Guid("5B0D3235-4DBA-4D44-865E-8F1D0E4FD04D")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
unsafe interface IMemoryBufferByteAccess
{
    void GetBuffer(out byte* buffer, out uint capacity);
}

Le code suivant montre un exemple d’implémentation d’une méthode d’assistance GenerateAudioData qui crée un objet AudioFrame et le remplit avec des données audio.C#Copier

private double audioWaveTheta = 0;

unsafe private AudioFrame GenerateAudioData(uint samples)
{
    // Buffer size is (number of samples) * (size of each sample)
    // We choose to generate single channel (mono) audio. For multi-channel, multiply by number of channels
    uint bufferSize = samples * sizeof(float);
    AudioFrame frame = new Windows.Media.AudioFrame(bufferSize);

    using (AudioBuffer buffer = frame.LockBuffer(AudioBufferAccessMode.Write))
    using (IMemoryBufferReference reference = buffer.CreateReference())
    {
        byte* dataInBytes;
        uint capacityInBytes;
        float* dataInFloat;

        // Get the buffer from the AudioFrame
        ((IMemoryBufferByteAccess)reference).GetBuffer(out dataInBytes, out capacityInBytes);

        // Cast to float since the data we are generating is float
        dataInFloat = (float*)dataInBytes;

        float freq = 1000; // choosing to generate frequency of 1kHz
        float amplitude = 0.3f;
        int sampleRate = (int)audioGraph.EncodingProperties.SampleRate;
        double sampleIncrement = (freq * (Math.PI * 2)) / sampleRate;

        // Generate a 1kHz sine wave and populate the values in the memory buffer
        for (int i = 0; i < samples; i++)
        {
            double sinValue = amplitude * Math.Sin(audioWaveTheta);
            dataInFloat[i] = (float)sinValue;
            audioWaveTheta += sampleIncrement;
        }
    }

    return frame;
}
  • Étant donné que cette méthode accède à la mémoire tampon brute sous-jacente des types Windows Runtime, elle doit être déclarée à l’aide du mot clé unsafe. Vous devez également configurer votre projet dans Microsoft Visual Studio pour permettre la compilation du code non sécurisé en ouvrant la page Propriétés du projet, en cliquant sur la page de propriétés Créer, puis en sélectionnant la case à cocher Autoriser du code unsafe.
  • Initialisez une nouvelle instance de AudioFrame, dans l’espace de noms Windows.Media, en passant la taille de mémoire tampon souhaitée au constructeur. La taille de mémoire tampon est le nombre d’échantillons multiplié par la taille de chaque échantillon.
  • Obtenez la AudioBufferde la trame audio en appelant LockBuffer.
  • Obtenez une instance de l’interface COM IMemoryBufferByteAccess à partir de la mémoire tampon audio en appelant CreateReference.
  • Obtenez un pointeur vers les données de mémoire tampon audio brutes en appelant IMemoryBufferByteAccess.GetBuffer et en le diffusant vers le type d’exemple de données des données audio.
  • Remplissez la mémoire tampon avec les données et renvoyez la AudioFrame pour la soumettre au graphique audio.

Nœud de sortie de trame audio

Un nœud de sortie de trame audio vous permet de recevoir et de traiter la sortie de données audio à partir du graphique audio à l’aide du code personnalisé que vous créez. Cela permet d’effectuer par exemple une analyse de signal sur la sortie audio. Créez un objet AudioFrameOutputNode en appelant CreateFrameOutputNode.C#Copier

AudioFrameOutputNode frameOutputNode;

C#Copier

private void CreateFrameOutputNode()
{
    frameOutputNode = audioGraph.CreateFrameOutputNode();
    audioGraph.QuantumStarted += AudioGraph_QuantumStarted;
}

L’événement AudioGraph.QuantumStarted est déclenché lorsque le graphique audio a commencé le traitement d’un quantum de données audio. Vous pouvez accéder aux données audio à partir du gestionnaire pour cet événement.

 Notes

Si vous souhaitez récupérer des trames audio à une cadence régulière, avec synchronisation avec le graphique audio, appelez AudioFrameOutputNode.GetFrame à partir du gestionnaire d’événements QuantumStarted synchrone. L’événement QuantumProcessed est déclenché en mode asynchrone une fois que le moteur audio a terminé le traitement audio, ce qui signifie que sa cadence peut être irrégulière. Par conséquent, vous ne devez pas utiliser l’événement QuantumProcessed pour le traitement synchronisé des données de trame audio.C#Copier

private void AudioGraph_QuantumStarted(AudioGraph sender, object args)
{
    AudioFrame frame = frameOutputNode.GetFrame();
    ProcessFrameOutput(frame);

}
  • Appelez GetFrame pour obtenir un objet AudioFrame contenant les données audio du graphique.
  • Un exemple d’implémentation de la méthode d’assistance ProcessFrameOutput est indiqué ci-dessous.

C#Copier

unsafe private void ProcessFrameOutput(AudioFrame frame)
{
    using (AudioBuffer buffer = frame.LockBuffer(AudioBufferAccessMode.Write))
    using (IMemoryBufferReference reference = buffer.CreateReference())
    {
        byte* dataInBytes;
        uint capacityInBytes;
        float* dataInFloat;

        // Get the buffer from the AudioFrame
        ((IMemoryBufferByteAccess)reference).GetBuffer(out dataInBytes, out capacityInBytes);

        dataInFloat = (float*)dataInBytes;
    }
}
  • Comme dans l’exemple de nœud d’entrée de trame audio ci-dessus, vous devez déclarer l’interface COM IMemoryBufferByteAccess et configurer votre projet pour autoriser le code non sécurisé à accéder à la mémoire tampon audio sous-jacente.
  • Obtenez la AudioBufferde la trame audio en appelant LockBuffer.
  • Obtenez une instance de l’interface COM IMemoryBufferByteAccess à partir de la mémoire tampon audio en appelant CreateReference.
  • Obtenez un pointeur vers les données de mémoire tampon audio brutes en appelant IMemoryBufferByteAccess.GetBuffer et en le diffusant vers le type d’exemple de données des données audio.

Connexions de nœud et nœuds prémixés

Tous les types de nœud d’entrée exposent la méthode AddOutgoingConnection qui achemine les données audio produites par le nœud vers le nœud transmis dans la méthode. L’exemple suivant connecte un objet AudioFileInputNode à un objetAudioDeviceOutputNode qui est un programme d’installation simple pour la lecture d’un fichier audio sur les haut-parleurs de l’appareil.C#Copier

fileInputNode.AddOutgoingConnection(deviceOutputNode);

Vous pouvez créer plusieurs connexions à partir d’un nœud d’entrée vers d’autres nœuds. L’exemple suivant ajoute une autre connexion à partir du AudioFileInputNode vers un AudioFileOutputNode. À présent, le son du fichier audio est lu par le haut-parleur de l’appareil et est également écrit dans un fichier audio.C#Copier

fileInputNode.AddOutgoingConnection(fileOutputNode);

Les nœuds de sortie peuvent également recevoir plus d’une connexion à partir d’autres nœuds. Dans l’exemple suivant, une connexion est établie à partir d’un AudioDeviceInputNode vers le nœud AudioDeviceOutput. Étant donné que le nœud de sortie dispose de connexions issues du nœud d’entrée de fichier et du nœud d’entrée d’appareil, la sortie contient un mélange d’audio des deux sources. AddOutgoingConnection fournit une surcharge qui vous permet de spécifier une valeur gain pour le signal passant par la connexion.C#Copier

deviceInputNode.AddOutgoingConnection(deviceOutputNode, .5);

Bien que les nœuds de sortie puissent accepter des connexions de plusieurs nœuds, vous voudrez peut-être créer une combinaison intermédiaire de signaux à partir d’un ou plusieurs nœuds avant de transmettre la combinaison à une sortie. Par exemple, vous souhaitez peut-être définir le niveau ou appliquer des effets à un sous-ensemble de signaux audio dans un graphique. Pour cela, utilisez le AudioSubmixNode. Vous pouvez vous connecter à un nœud prémixé à partir d’un ou plusieurs nœuds d’entrée ou à partir d’autres nœuds prémixés. Dans l’exemple suivant, un nouveau nœud prémixé est créé avec AudioGraph.CreateSubmixNode. Ensuite, les connexions sont ajoutées à partir d’un nœud d’entrée de fichier et d’un nœud de sortie de trame dans le nœud prémixé. Enfin, le nœud prémixé est connecté à un nœud de sortie de fichier.C#Copier

private void CreateSubmixNode()
{
    AudioSubmixNode submixNode = audioGraph.CreateSubmixNode();
    fileInputNode.AddOutgoingConnection(submixNode);
    frameInputNode.AddOutgoingConnection(submixNode);
    submixNode.AddOutgoingConnection(fileOutputNode);
}

Démarrage et arrêt de nœuds de graphique audio

Lorsque AudioGraph.Start est appelée, le graphique audio commence à traiter les données audio. Chaque type de nœud fournit les méthodes Start et Stop qui entraînent le démarrage du nœud individuel ou l’arrêt du traitement des données. Lorsque AudioGraph.Stop est appelée, le traitement audio de tous les nœuds est arrêté indépendamment de l’état de chacun d’entre eux. L’état de chaque nœud peut être défini lorsque le graphique audio est arrêté. Par exemple, vous pouvez appeler Stop sur un nœud individuel pendant que le graphique est arrêt, puis appeler AudioGraph.Start, et le nœud individuel restera à l’arrêt.

Tous les types de nœud exposent la propriété ConsumeInput qui, lorsqu’elle est définie sur False, permet au nœud de poursuivre le traitement audio, mais l’empêche de consommer des données audio en cours d’entrée à partir d’autres nœuds.

Tous les types de nœud exposent la méthode Reset qui pousse le nœud à ignorer les données audio présentes actuellement dans sa mémoire tampon.

Leave a Comment