Audio Web et paysages sonores 3D mise en œuvre

Dans ce didacticiel, nous allons incorporer Web Audio dans une API simple, centrée sur la lecture de sons dans un espace de coordonnées 3D, et pouvant être utilisée pour des applications immersives et interactives, notamment les jeux 3D..

Ce tutoriel est le deuxième d'une série en deux parties. Si vous n'avez pas lu le premier tutoriel de la série, vous devriez le faire avant de lire ce tutoriel, car il vous présente les différents éléments Web Audio que nous allons utiliser ici..

Manifestation

Avant de commencer, voici une petite démonstration qui utilise l’API simplifiée que nous allons couvrir dans ce didacticiel. Les sons (représentés par les carrés blancs) sont positionnés de manière aléatoire et lus dans un espace de coordonnées 3D à l'aide de la fonction de transfert de tête (HRTF) fournie par Web Audio..

Les fichiers source de la démonstration sont joints à ce tutoriel..

Vue d'ensemble

Comme l'API simplifiée (AudioPlayer) a déjà été créée pour ce didacticiel et peut être téléchargée, nous allons examiner ici de manière générale l'API AudioPlayer et son code d'activation..

Avant de continuer ce tutoriel, veuillez lire le didacticiel précédent de cette série si vous ne l'avez pas déjà fait et que vous êtes nouveau dans le monde de Web Audio.

AudioPlayer

le AudioPlayer classe contient notre API simplifiée et est exposée sur le la fenêtre object aux côtés des classes Web Audio standard si, et seulement si, Web Audio est pris en charge par le navigateur Web. Cela signifie que nous devrions vérifier l'existence de la classe avant d'essayer de l'utiliser..

if (window.AudioPlayer! == non défini) audioPlayer = new AudioPlayer ()

(Nous aurions pu essayer de créer un nouveau AudioPlayer objet dans un essayer… attraper déclaration, mais une simple vérification conditionnelle fonctionne parfaitement bien.)

Dans les coulisses, le audioPlayer crée un nouveau AudioContext objet et un nouveau AudioGainNode objet pour nous, et relie le GainNode objecter à la destination noeud exposé par le AudioContext objet.

var m_context = new AudioContext () var m_gain = m_context.createGain ()… m_gain.connect (m_context.destination)

Lorsque les sons sont créés et joués, ils sont connectés au m_gain nœud, cela nous permet de contrôler facilement le volume (amplitude) de tous les sons.

le audioPlayer configure également l'audio auditeur, exposé par m_context, il correspond donc au système de coordonnées 3D commun utilisé avec WebGL. Le positif z points d’axe sur le spectateur (en d’autres termes, il pointe vers l’écran 2D), le positif y axe pointe vers le haut, et le positif X axe pointe vers la droite.

m_context.listener.setOrientation (0, 0, -1, 0, 1, 0)

La position de la auditeur est toujours nul; il se trouve au centre du système de coordonnées audio.

Chargement des sons

Avant de pouvoir créer ou jouer des sons, nous devons charger les fichiers audio. heureusement audioPlayer prend soin de tout le dur travail pour nous. Il expose un charge(… ) fonction que nous pouvons utiliser pour charger les sons et trois gestionnaires d'événements nous permettant de suivre l'évolution de la charge.

audioPlayer.onloadstart = function () … audioPlayer.onloaderror = function () … audioPlayer.onloadcomplete = fonction () … audioPlayer.load ("sound-01.ogg") audioPlayer.load ("sound-02 .ogg ") audioPlayer.load (" sound-03.ogg ")

L'ensemble des formats audio pris en charge dépend du navigateur. Par exemple, Chrome et Firefox prennent en charge OGG Vorbis mais pas Internet Explorer. Les trois navigateurs prennent en charge le format MP3, ce qui est pratique, mais le problème avec le format MP3 est l’absence de boucle de son continue, le format MP3 n’est tout simplement pas conçu pour cela. Cependant, OGG Vorbis est, et peut en boucle des sons parfaitement.

Lorsque vous appelez le charge(… ) fonctionner plusieurs fois, audioPlayer va mettre les demandes dans une file d'attente et les charger séquentiellement. Lorsque tous les sons en file d'attente ont été chargés (et décodés), le onloadcomplete gestionnaire d'événement sera appelé.

Dans les coulisses, audioPlayer utilise un seul XMLHttpRequest objet pour charger les sons. le responseType de la demande est défini sur "arraybuffer", et lorsque le fichier est chargé, le tampon de tableau est envoyé à m_context pour décoder.

// exemple simplifié m_loader = new XMLHttpRequest () m_queue = [] function load () m_loader.open ("GET", m_queue [0]) m_loader.responseType = "arraybuffer" m_loader.onload = onLoad m_loader.send () function onLoad (event) var data = m_loader.response var status = m_loader.status m_loader.abort () // réinitialise le chargeur si (status < 400)  m_context.decodeAudioData(data, onDecode)  

Si le chargement et le décodage d'un fichier sont réussis, audioPlayer chargera le fichier suivant dans la file d'attente (si la file n'est pas vide) ou nous informera que tous les fichiers ont été chargés.

Créer des sons

Maintenant que nous avons chargé des fichiers audio, nous pouvons créer et jouer nos sons. Nous devons d'abord dire audioPlayer pour créer les sons, et cela se fait en utilisant le créer(… ) fonction exposée par audioPlayer.

var sound1 = audioPlayer.create ("sound-01.ogg") var sound2 = audioPlayer.create ("sound-02.ogg") var sound3 = audioPlayer.create ("sound-03.ogg")

Nous sommes libres de créer autant de sons que nécessaire, même si nous n'avons chargé qu'un seul fichier son..

var a = audioPlayer.create ("beep.ogg") var b = audioPlayer.create ("beep.ogg") var c = audioPlayer.create ("beep.ogg")

Le chemin du fichier son transmis à la créer(… ) la fonction dit simplement audioPlayer quel fichier le son créé doit utiliser. Si le fichier son spécifié n’a pas été chargé lors de la créer(… ) la fonction est appelée, une erreur d'exécution sera levée.

Jouer des sons

Lorsque nous avons créé un ou plusieurs sons, nous sommes libres de les reproduire chaque fois que nous en avons besoin. Pour jouer un son, nous utilisons le bien nommé jouer(… ) fonction exposée par audioPlayer.

audioPlayer.play (sound1)

Pour déterminer s'il faut jouer un en boucle son, on peut aussi passer un booléen au jouer(… ) une fonction. Si le booléen est vrai, le son restera en boucle jusqu'à ce qu'il soit arrêté.

audioPlayer.play (sound1, true)

Pour arrêter un son, on peut utiliser le Arrêtez(… ) une fonction.

audioPlayer.stop (sound1)

le est en train de jouer(… ) fonction nous permet de savoir si un son est en cours de lecture.

if (audioPlayer.isPlaying (sound1)) …

Dans les coulisses, le audioPlayer En raison de la nature modulaire de Web Audio, il faut un travail surprenant pour obtenir un son. Chaque fois qu'un son doit être joué,audioPlayer doit créer de nouveaux AudioSourceBufferNode et PannerNode objets, configurez-les et connectez-les, puis connectez le son au m_gain nœud. Heureusement, Web Audio est hautement optimisé, de sorte que la création et la configuration de nouveaux nœuds audio entraînent rarement une surcharge visible..

sound.source = m_context.createBufferSource () sound.panner = m_context.createPanner () sound.source.buffer = sound.buffer sound.source.loop = boucle sound.source.onended = onSoundEnded // Ceci est un morceau de hack mais nous devons référencer l'objet sound // dans le gestionnaire d'événements onSoundEnded, et cette méthode est plus optimale que de lier le gestionnaire. sound.source.sound = sound sound.panner.panningModel = "HRTF" sound.panner.distanceModel = "linear" sound.panner.setPosition (sound.x, sound.y, sound.z) sound.source.connect (sound .panner) sound.panner.connect (m_gain) sound.source.start ()

Jouer des sons est évidemment utile, mais le but de audioPlayer est de jouer des sons dans un système de coordonnées 3D, donc nous devrions probablement définir les positions du son avant de les jouer. audioPlayer expose quelques fonctions qui nous permettent de faire exactement cela.

Sons de positionnement

  • le setX (…) et getX (…) fonctions exposées par audioPlayer peut être utilisé pour définir et obtenir la position d'un son le long du système de coordonnées X axe.
  • le setY (…) et getY (…) les fonctions peuvent être utilisées pour définir et obtenir la position d'un son le long du système de coordonnées y axe.
  • le setZ (…) et getZ (…) les fonctions peuvent être utilisées pour définir et obtenir la position d'un son le long du système de coordonnées z axe.
  • Enfin, l'utile setPosition (…) la fonction peut être utilisée pour définir la position d'un son le long du système de coordonnées X, y, et z axes respectivement.
audioPlayer.setX (sound1, 100) audioPlayer.setZ (sound1, 200) console.log (audioPlayer.getX (sound1)) // 100 console.log (audioPlayer.getZ (sound1)) // 200 audioPlayer.setPosition (sound1, 300, 0, 400) console.log (audioPlayer.getX (sound1)) // 300 console.log (audioPlayer.getZ (sound1)) // 400

Plus un son est éloigné du centre du système de coordonnées, plus le son sera silencieux. À une distance de 10000 (le Web Audio par défaut) un son sera complètement silencieux.

Le volume

Nous pouvons contrôler le volume global (maître) des sons en utilisant le setVolume (…) et getVolume (…) fonctions exposées par audioPlayer.

audioPlayer.setVolume (0.5) // 50% console.log (audioPlayer.getVolume ()) // 0.5

le setVolume (…) function possède également un second paramètre qui peut être utilisé pour atténuer le volume sur une période donnée. Par exemple, pour réduire le volume à zéro sur une période de deux secondes, nous pourrions procéder comme suit:

audioPlayer.setVolume (0.0, 2.0)

La démo du tutoriel en profite pour fondre les sons en douceur.

Dans les coulisses, le audioPlayer raconte simplement le m_gain noeud pour modifier linéairement la valeur de gain chaque fois que le volume doit être modifié.

var currentTime = m_context.currentTime var currentVolume = m_gain.gain.value m_gain.gain.cancelScheduledValues ​​(0.0) m_gain.gain.setValueAtTime (currentVolume, currentTime) m_gain.gain.

audioPlayer applique un temps minimum de fondu de 0,01 secondes, pour éviter que de forts changements de volume ne provoquent de clics ou de bruits audibles.

Conclusion

Dans ce didacticiel, nous avons examiné une méthode permettant d’envelopper Web Audio dans une API simple qui se concentre sur la lecture de sons dans un espace de coordonnées 3D pour une utilisation dans (parmi d’autres applications) des jeux 3D..

En raison de la nature modulaire de Web Audio, les programmes qui utilisent Web Audio peuvent devenir complexes assez rapidement. J'espère donc que ce tutoriel vous aura été utile. Lorsque vous comprendrez comment Web Audio fonctionne et à quel point il est puissant, je suis sûr que vous vous amuserez beaucoup avec ce logiciel..

N'oubliez pas qu'AudioPlayer et les fichiers sources de démonstration sont disponibles sur GitHub et prêts à être téléchargés. Le code source est assez bien commenté, il est donc utile de prendre le temps de le consulter rapidement..

Si vous avez des commentaires ou des questions, n'hésitez pas à poster un commentaire ci-dessous.

Ressources

  • Spécification Audio Web W3C
  • Documentation audio Web MDN