Comment créer un oscillateur audio avec l'API Web Audio

Ce que vous allez créer

L’API Web Audio est un modèle complètement distinct de la

Ce que nous construisons

Voir l'API Pen WebAudio avec Oscilloscope de Dennis Gaebel (@dennisgaebel) sur CodePen.

Notre démo ci-dessus contient trois entrées radio qui, une fois sélectionnées, liront l’audio correspondant auquel chacune fait référence. Quand un canal est sélectionné, notre audio sera joué et le graphique de fréquence sera affiché. 

Je ne vais pas expliquer chaque ligne du code de la démo; Cependant, je vais expliquer les bits principaux qui aident à afficher la source audio et son graphe de fréquence. Pour commencer, nous aurons besoin d'un peu de balisage.

Le balisage

La partie la plus importante du balisage est le Toile, qui sera l'élément qui affiche notre oscilloscope. Si vous n'êtes pas familier avec Toile, Je suggère de lire cet article intitulé "Une introduction à l'utilisation de Canvas".

Avec la scène pour l'affichage du graphique, nous devons créer l'audio.

Créer l'audio

Nous allons commencer par définir quelques variables importantes pour le contexte audio et le gain. Ces variables seront utilisées pour référencer ultérieurement dans le code.

laissez audioContext, masterGain;

le audioContext représente un graphe de traitement audio (description complète d'un réseau de traitement de signal audio) construit à partir de modules audio reliés entre eux. Chacun est représenté par un AudioNode, et lorsqu'ils sont connectés ensemble, ils créent un graphe de routage audio. Ce contexte audio contrôle à la fois la création du ou des nœuds qu’il contient et l’exécution du traitement et du décodage audio.. 

le AudioContext doit être créé avant tout, car tout se passe dans un contexte.

Notre masterGain accepte une entrée d'une ou de plusieurs sources audio et génère le volume de l'audio, dont le gain a été réglé à un niveau spécifié par le nœud GainNode.gain paramètre a-rate. Vous pouvez considérer le gain principal comme le volume. Nous allons maintenant créer une fonction pour permettre la lecture par le navigateur.

function audioSetup () let source = 'http://ice1.somafm.com/seventies-128-aac'; audioContext = new (window.AudioContext || window.webkitAudioContext) (); 

Je commence par définir un la source variable qui sera utilisée pour référencer le fichier audio. Dans ce cas, j'utilise une URL vers un service de streaming, mais il pourrait aussi s'agir d'un fichier audio. le audioContext line définit un objet audio et constitue le contexte dont nous avons discuté auparavant. Je vérifie également la compatibilité en utilisant le WebKit préfixe, mais le support est largement adopté à l'heure actuelle à l'exception de IE11 et Opera Mini.

fonction audioSetup () masterGain = audioContext.createGain (); masterGain.connect (audioContext.destination); 

Une fois notre configuration initiale terminée, nous devrons créer et connecter le masterGain à la destination audio. Pour ce travail, nous utiliserons le relier() méthode, qui vous permet de connecter l'une des sorties du nœud à une cible.

function audioSetup () let song = new Audio (source), songSource = audioContext.createMediaElementSource (song); songSource.connect (masterGain); song.play (); 

le chanson variable crée un nouvel objet audio en utilisant le L'audio() constructeur. Vous aurez besoin d'un objet audio pour que le contexte ait une source à lire pour les auditeurs..

le songSource variable est la sauce magique qui joue l’audio et c’est là que nous allons passer à notre source audio. En utilisant createMediaElementSource (), l'audio peut être joué et manipulé comme vous le souhaitez. La dernière variable connecte notre source audio au gain principal (volume). La ligne finale song.play () est l'appel à donner réellement la permission de lire l'audio.

laissez audioContext, masterGain; function audioSetup () let source = 'http://ice1.somafm.com/seventies-128-aac'; audioContext = new (window.AudioContext || window.webkitAudioContext) (); masterGain = audioContext.createGain (); masterGain.connect (audioContext.destination); let song = new Audio (source), songSource = audioContext.createMediaElementSource (song); songSource.connect (masterGain); song.play ();  Configuration audio();

Voici notre résultat final contenant toutes les lignes de code dont nous avons parlé jusqu'à présent. Je m'assure également de faire l'appel à cette fonction écrite sur la dernière ligne. Ensuite, nous allons créer la forme d'onde audio.

Créer la vague audio

Afin d’afficher l’onde de fréquence de la source audio choisie, nous devons créer la forme d’onde..

analyseur const = audioContext.createAnalyser (); masterGain.connect (analyseur);

La première référence à createAnalyser () expose les données de temps et de fréquence audio afin de générer des visualisations de données. Cette méthode génère un AnalyserNode qui transmet le flux audio de l’entrée à la sortie, mais vous permet d’acquérir les données générées, de les traiter et de créer des visualisations audio qui ont exactement une entrée et une sortie. Le nœud d’analyseur sera connecté au gain principal qui est la sortie de notre chemin de signal et donne la possibilité d’analyser une source..

forme d'onde const = new Float32Array (analyser.frequencyBinCount); analyser.getFloatTimeDomainData (forme d'onde);

Ce Float32Array () constructeur représente un tableau d'un nombre à virgule flottante de 32 bits. le fréquenceBinCount propriété du AnalyserNode interface est une valeur longue non signée correspondant à la moitié de la taille de la transformée rapide de Fourier (FFT). Cela équivaut généralement au nombre de valeurs de données que vous aurez à utiliser avec la visualisation. Nous utilisons cette approche pour collecter nos données de fréquence à plusieurs reprises.

La méthode finale getFloatTimeDomainData copie la forme d'onde actuelle, ou les données de domaine temporel, dans une Float32Array tableau passé en elle.

function updateWaveform () requestAnimationFrame (updateWaveform); analyser.getFloatTimeDomainData (forme d'onde); 

Toute cette quantité de données et d’usages de traitement requestAnimationFrame () collecter des données de domaine temporel à plusieurs reprises et dessinez une sortie "style oscilloscope" de l'entrée audio actuelle. Je fais aussi un autre appel à getFloatTimeDomainData () puisque cela doit être mis à jour continuellement car la source audio est dynamique.

analyseur const = audioContext.createAnalyser (); masterGain.connect (analyseur); forme d'onde const = new Float32Array (analyser.frequencyBinCount); analyser.getFloatTimeDomainData (forme d'onde); function updateWaveform () requestAnimationFrame (updateWaveform); analyser.getFloatTimeDomainData (forme d'onde); 

La combinaison de tout le code discuté jusqu’à présent a pour résultat la fonction entière ci-dessus. L’appel à cette fonction sera placé dans notre Configuration audio fonction juste en dessous song.play (). Avec la forme d'onde en place, nous avons toujours besoin de dessiner cette information à l'écran en utilisant notre Toile élément, et ceci est la prochaine partie de notre discussion.

Dessiner la vague audio

Maintenant que nous avons créé notre forme d'onde et que nous possédons les données dont nous avons besoin, nous devons les dessiner à l'écran. c'est là que le Toile l'élément est introduit.

fonction drawOscilloscope () requestAnimationFrame (drawOscilloscope); const scopeCanvas = document.getElementById ('oscilloscope'); const scopeContext = scopeCanvas.getContext ('2d'); 

Le code ci-dessus saisit simplement le Toile élément afin que nous puissions le référencer dans notre fonction. L'appel à requestAnimationFrame en haut de cette fonction planifiera la prochaine image d'animation. Ceci est placé en premier afin que nous puissions être aussi proches que possible de 60 images par seconde.

function drawOscilloscope () scopeCanvas.width = waveform.length; scopeCanvas.height = 200; 

J'ai mis en place un style de base qui dessinera la largeur et la hauteur du Toile. La hauteur est définie sur une valeur absolue, tandis que la largeur correspond à la longueur de la forme d'onde produite par la source audio..

function drawOscilloscope () scopeContext.clearRect (0, 0, scopeCanvas.width, scopeCanvas.height); scopeContext.beginPath (); 

le clearRect (x, y, largeur, hauteur) Cette méthode effacera tout contenu précédemment dessiné afin que nous puissions dessiner continuellement le graphe de fréquence. Vous devrez également vous assurer d'appeler beginPath () avant de commencer à dessiner le nouveau cadre après avoir appelé clearRect (). Cette méthode commence un nouveau chemin en vidant la liste de tous les sous-chemins. La dernière pièce de ce puzzle est une boucle permettant de parcourir les données que nous avons obtenues afin que nous puissions continuellement dessiner ce graphique de fréquence à l'écran..

fonction drawOscilloscope () for (let i = 0; i < waveform.length; i++)  const x = i; const y = ( 0.5 + (waveform[i] / 2) ) * scopeCanvas.height; if(i == 0)  scopeContext.moveTo(x, y);  else  scopeContext.lineTo(x, y);   scopeContext.stroke(); 

Cette boucle ci-dessus attire notre forme d'onde vers le Toile élément. Si nous enregistrons la longueur de la forme d'onde sur la console (pendant la lecture de l'audio), 1024 signaleront à plusieurs reprises. Cela équivaut généralement au nombre de valeurs de données que vous devrez utiliser pour la visualisation. Si vous vous souvenez de la section précédente pour la création de la forme d'onde, nous obtenons cette valeur de Float32Array (analyser.frequencyBinCount). Voici comment nous pouvons référencer la valeur 1024 que nous allons parcourir en boucle.

le déménager à() Cette méthode déplacera littéralement le point de départ d’un nouveau sous-chemin vers la mise à jour. (x, y) coordonnées. le lineTo () méthode connecte le dernier point du sous-chemin à la x, y coordonne avec une ligne droite (mais ne la dessine pas réellement). La dernière pièce appelle accident vasculaire cérébral() fourni par Toile afin que nous puissions réellement tracer la ligne de fréquence. Je vais laisser la partie contenant le calcul en tant que défi de lecteur, alors assurez-vous de poster votre réponse dans les commentaires ci-dessous.

fonction drawOscilloscope () requestAnimationFrame (drawOscilloscope); const scopeCanvas = document.getElementById ('oscilloscope'); const scopeContext = scopeCanvas.getContext ('2d'); scopeCanvas.width = waveform.length; scopeCanvas.height = 200; scopeContext.clearRect (0, 0, scopeCanvas.width, scopeCanvas.height); scopeContext.beginPath (); pour (soit i = 0; i < waveform.length; i++)  const x = i; const y = ( 0.5 + (waveform[i] / 2) ) * scopeCanvas.height; if(i == 0)  scopeContext.moveTo(x, y);  else  scopeContext.lineTo(x, y);   scopeContext.stroke(); 

C’est toute la fonction que nous avons créée pour dessiner la forme d’onde que nous appellerons après song.play () placé dans notre Configuration audio fonction, qui comprend également notre updateWaveForm appel de fonction aussi bien.

Pensées Parting

J'ai seulement expliqué les éléments importants de la démo, mais assurez-vous de lire les autres parties de ma démo pour mieux comprendre le fonctionnement des boutons radio et du bouton Démarrer par rapport au code ci-dessus, y compris le style CSS..

L'API Web Audio est vraiment amusant pour quiconque s'intéresse à l'audio de toutes sortes, et je vous encourage à aller plus loin. J'ai également rassemblé des exemples très amusants de CodePen qui utilisent l'API Web Audio pour construire des exemples très intéressants. Prendre plaisir!

  • https://codepen.io/collection/XLYyWN
  • https://codepen.io/collection/nNqdoR
  • https://codepen.io/collection/XkNgkE
  • https://codepen.io/collection/ArxwaW

Références

  • http://webaudioapi.com
  • https://webaudio.github.io/web-audio-api
  • http://chimera.labs.oreilly.com/books/1234000001552/ch01.html