Jeu audio simplifié

L'API Web Audio est un puissant allié pour tous ceux qui créent des jeux JavaScript, mais avec ce pouvoir vient la complexité. Web Audio est un système modulaire. Les nœuds audio peuvent être reliés entre eux pour former des graphiques complexes permettant de tout gérer, de la lecture d'un seul son à une application de séquencement de musique complète. C'est impressionnant, c'est le moins qu'on puisse dire.

Cependant, quand il s'agit de programmer des jeux, la plupart des développeurs veulent une API de base qui charge et joue les sons, et fournit des options pour changer le volume, la hauteur et le panoramique (position stéréo) de ces sons. Ce tutoriel fournit une solution élégante en encapsulant l’API Web Audio dans un environnement rapide et léger. Du son classe qui gère tout pour vous.

Remarque: Ce tutoriel est principalement destiné aux programmeurs JavaScript, mais les techniques utilisées pour mélanger et manipuler l'audio dans le code peuvent être appliquées à presque tous les environnements de programmation donnant accès à une API son de bas niveau..

Démo en direct

Avant de commencer, jetez un œil à la démonstration en direct du Du son classe en action. Vous pouvez cliquer sur les boutons de la démo pour jouer des sons:

  • SFX 01 est un son simple avec les paramètres par défaut. 
  • SFX 02 est un son simple qui a son panoramique (position stéréo) et son volume aléatoires à chaque lecture. 
  • SFX 03 est un son en boucle; cliquer sur le bouton permet d'activer ou de désactiver le son, et la position du pointeur de la souris dans le bouton ajuste la hauteur du son..

Remarque: Si vous n'entendez aucun son, le navigateur Web que vous utilisez ne prend pas en charge les flux audio Web Audio API ou OGG Vorbis. Utiliser Chrome ou Firefox devrait résoudre le problème.

La vie peut être plus simple

L'image suivante visualise un graphe de nœud Web Audio de base:

Exemple visuel d'un graphe de noeud Web Audio.

Comme vous pouvez le constater, le graphique contient assez de nœuds audio pour gérer la lecture de quatre sons de manière appropriée pour les jeux. Les nœuds de panoramique et de gain traitent du panoramique et du volume. Deux nœuds de compresseur dynamique permettent d'éviter tout artefact audible (clips, clips, etc.) si le graphe finissait par être surchargé par un son puissant..

Il est génial de pouvoir créer des graphes de nœuds audio comme celui-ci en JavaScript, mais devoir constamment créer, connecter et déconnecter ces nœuds peut devenir un véritable fardeau. Nous allons simplifier les choses en gérant le mixage et la manipulation audio par programmation, en utilisant un seul noeud de processeur de script..

Exemple visuel d'un graphe de nœud Web Audio simplifié.

Oui, c'est beaucoup plus simple et cela évite également le temps système nécessaire à la création, à la connexion et à la déconnexion d'une charge de nœuds audio chaque fois qu'un son doit être joué.. 

L'API Web Audio présente d'autres particularités qui peuvent rendre les choses difficiles. Le nœud de panoramique, par exemple, est spécialement conçu pour les sons positionnés dans un espace 3D, et non dans un espace 2D, et les nœuds sources de la mémoire tampon audio (étiquetés "son" dans l'image précédente) ne peuvent être lus qu'une seule fois, d'où la nécessité de créer en permanence et connectez ces types de nœuds.

Le noeud de processeur à script unique utilisé par le Du son class demande périodiquement que des échantillons sonores lui soient transmis à partir de JavaScript, ce qui nous facilite grandement les choses. Nous pouvons mélanger et manipuler des échantillons sonores très rapidement et facilement en JavaScript afin de produire le volume, la hauteur et les fonctionnalités de panoramique dont nous avons besoin pour les jeux en 2D..

La classe sonore

Au lieu de passer à travers la création de la Du son classe, nous allons examiner les parties principales du code qui sont directement liées à l’API Web Audio et à la manipulation des échantillons sonores. Les fichiers sources de la démo incluent le fichier entièrement fonctionnel. Du son classe, que vous pouvez librement étudier et utiliser dans vos propres projets.

Chargement de fichiers son

le Du son classe charge les fichiers son sur un réseau sous forme de mémoires tampon à l'aide de XMLHttpRequest objets. Les tampons de matrice sont ensuite décodés en échantillons sonores bruts par un objet de contexte audio..

request.open ("GET", "sound.ogg"); request.onload = decode; request.responseType = "arraybuffer"; request.open (); function decode () if (request.response! == null) audioContext.decodeAudioData (request.response, done);  function done (audioBuffer) …

Évidemment, ce code ne traite pas les erreurs, mais cela montre comment les fichiers audio sont chargés et décodés. le audioBuffer passé au terminé() fonction contient les échantillons sonores bruts du fichier son chargé.

Mélange et manipulation d'échantillons sonores

Pour mélanger et manipuler les échantillons sonores chargés, le Du son class attache un écouteur à un noeud de processeur de script. Cet auditeur sera appelé périodiquement pour demander plus d'échantillons sonores..

// Calcule une taille de tampon. // Ceci produira une valeur raisonnable qui équilibre la latence audio // et l'utilisation du processeur pour les jeux fonctionnant à 60 Hz. var v = audioContext.sampleRate / 60; var n = 0; tandis que (v> 0) v >> = 1; n ++;  v = Math.pow (2, n); // taille du tampon // Crée le processeur de script. processeur = audioContext.createScriptProcessor (v); // attache le listener. processor.onaudioprocess = processSamples; fonction processSamples (event) …

La fréquence à laquelle le processSamples () La fonction appelée varie selon les configurations matérielles, mais elle est généralement environ 45 fois par seconde. Cela peut sembler beaucoup, mais il est nécessaire de maintenir la latence audio suffisamment faible pour pouvoir être utilisée dans les jeux modernes qui tournent généralement à 60 images par seconde. Si la latence audio est trop élevée, les sons seront entendus trop tard pour pouvoir être synchronisés avec ce qui se passe à l'écran, et ce serait une expérience bouleversante pour quiconque joue à un jeu.

Malgré la fréquence à laquelle le processSamples () fonction est appelée, l’utilisation du processeur reste faible, ne vous inquiétez donc pas du temps trop long pris par la logique de jeu et le rendu. Sur mon matériel (Intel Core i3, 3 GHz), l'utilisation du processeur dépasse rarement les 2%, même lorsque beaucoup de sons sont lus simultanément.

le processSamples () la fonction contient en fait la viande du Du son classe; c'est à cet endroit que les échantillons sonores sont mélangés et manipulés avant d'être transférés via le Web Audio vers le matériel. Le code suivant montre ce qui se passe dans la fonction:

// Prend l'échantillon sonore. sampleL = samplesL [soundPosition >> 0]; sampleR = samplesR [soundPosition >> 0]; // Augmente la position de la tête de lecture du son. soundPosition + = soundScale; // Appliquer le volume global (affecte tous les sons). sampleL * = globalVolume; sampleR * = globalVolume; // Appliquer le volume du son. sampleL * = soundVolume; sampleR * = soundVolume; // Applique le panoramique du son (position stéréo). sampleL * = 1.0 - soundPan; sampleR * = 1.0 + soundPan;

C'est plus ou moins tout ce qu'il y a à faire. C'est la magie: une poignée d'opérations simples modifient le volume, la hauteur et la position stéréo d'un son.

Si vous êtes un programmeur et que vous êtes familiarisé avec ce type de traitement du son, vous pensez peut-être que "cela ne peut pas être tout ce qu'il y a à faire", et vous auriez raison: la classe Sound doit garder une trace des instances sonores, des tampons d'échantillon et faire quelques autres choses, mais tout cela est banal!

Utilisation de la classe sonore

Le code suivant montre comment utiliser la classe Sound. Vous pouvez également télécharger les fichiers source de la démonstration en direct accompagnant ce didacticiel..

// Crée quelques objets Sound. var boom = new Sound ("boom.ogg"); var tick = new Sound ("tick.ogg"); // Passons éventuellement un auditeur à la classe Sound. Sound.setListener (auditeur); // Ceci chargera tous les objets Sound nouvellement créés. Sound.load (); // L'auditeur. fonction écouteur (son, état) if (état === Sound.State.LOADED) if (son === tick) setInterval (playTick, 1000);  else if (son === boom) setInterval (playBoom, 4000);  else if (state === Sound.State.ERROR) console.warn ("Erreur sonore:% s", sound.getPath ());  // Lit le son de tick. fonction playTick () tick.play ();  // Lit le son de la flèche. fonction playBoom ​​() boom.play (); // Randomise la hauteur et le volume du son. boom.setScale (0,8 + 0,4 * Math.random ()); boom.setVolume (0,2 + 0,8 * Math.random ()); 

Gentil et facile.

Une chose à noter: peu importe si l'API Web Audio n'est pas disponible dans un navigateur et peu importe si le navigateur ne peut pas lire un format de son spécifique. Vous pouvez toujours appeler le jouer() et Arrêtez() fonctionne sur un Du son objet sans erreurs étant jeté. C'est intentionnel. cela vous permet de faire fonctionner votre code de jeu comme d'habitude sans vous soucier des problèmes de compatibilité de navigateur ou de créer une branche pour le code afin de résoudre ces problèmes. Le pire qui puisse arriver est le silence.

L'API Sound Class

  • jouer()
  • Arrêtez()
  • getPath (): Obtient le chemin du fichier du son.
  • getState ()
  • getPan ()
  • setPan (valeur): Définit le panoramique du son (position stéréo).
  • getScale ()
  • setScale (valeur): Définit l'échelle du son (pitch).
  • getVolume ()
  • setVolume (valeur): Règle le volume du son.
  • isPending ()
  • est en cours de chargement()
  • est chargé()
  • isLooped ()

La classe Sound contient également les fonctions statiques suivantes.

  • charge(): Charge les sons nouvellement créés.
  • Arrêtez(): Arrête tous les sons.
  • getVolume ()
  • setVolume (valeur): Définit le volume global (maître).
  • getListener ()
  • setListener (valeur): Garde la trace de la progression du chargement du son, etc..
  • canPlay (format): Vérifie si différents formats de son peuvent être lus.

La documentation peut être trouvée dans le code source de la démo.

Conclusion

La lecture d’effets sonores dans un jeu JavaScript doit être simple. Ce tutoriel le permet également en encapsulant la puissante API Web Audio dans une classe Sound légère et rapide qui gère tout pour vous..

Ressources associées

Si vous souhaitez en savoir plus sur les échantillons sonores et comment les manipuler, j'ai écrit une série pour Tuts + qui devrait vous occuper un bon moment…

  1. Créer un synthétiseur - Introduction
  2. Création d'un synthétiseur - Core Engine
  3. Création d'un synthétiseur - Processeurs audio

Les liens suivants concernent les spécifications normalisées du W3C et de Khronos directement liées à l'API Web Audio:

  • API Web Audio
  • Tableaux typés