Disclaimer : Vous ne ferez pas un meilleur score à Flappy Bird grâce à cette nouvelle version ;)

Le but de cet article est de vous présenter l'API audio et getUserMedia afin d'enregistrer le son du micro et d'en avoir une représentation visuelle.

Vous serez ensuite capable de réaliser ce Flappy Bird contrôlable avec la voix ;)

getUserMedia()

C'est une API qui permet de demander l'accès au micro ou à la webcam de l'utilisateur et d'en récupérer un flux.

Compatibilité

Avant toute chose vous devez savoir que cette API est encore expérimentale , non disponible sur IE et Safari, et vient tout juste de faire son apparition sur les navigateurs mobiles.

Détection

Nous devons d'abord savoir si le navigateur peut supporter getUserMedia().

if (navigator.getUserMedia) {
    alert('Votre navigateur supporte getUserMedia()');
} else {
  alert('Votre navigateur ne supporte pas getUserMedia()');
}

Tip : Vous pouvez aussi utiliser Modernizr => if(Modernizr.getusermedia) {}

Compatibilité multi-navigateurs : getUserMedia est toujours préfixé par Chrome et Firefox. Pour rendre notre code compatible partout, nous devons ajouter les préfixes nécessaires.

Il faut donc ajouter ces lignes avant d'utiliser navigator.getUserMedia.

navigator.getUserMedia  = navigator.getUserMedia ||
                        navigator.webkitGetUserMedia ||
                        navigator.mozGetUserMedia ||
                        navigator.msGetUserMedia;

Accès au micro

Avant de pouvoir récupérer un flux audio, nous devons d'abord demander à l'utilisateur l'accès à son micro. Vous avez déjà sûrement vu cette petite barre en haut de votre navigateur. Accès micro

La fonction s'utilise ainsi:

navigator.getUserMedia(constraints, successCallback, errorCallback);
  • Le premier paramètre de getUserMedia est un objet contenant les détails des accès demandés. Ici nous voulons l'accès au micro : {audio: true}
  • Les deuxième et troisième paramètres sont des fonctions de callback en cas de succès / échec
if (navigator.getUserMedia) {
    navigator.getUserMedia(
        {audio: true}, // pour la vidéo: {video: true}
        successCallback,
        errorCallback // optionnel
    );
} else {
    alert('Votre navigateur ne supporte pas getUserMedia()');
}

function successCallback(stream) {
    alert ("L'utilisateur a accepté l'accès au micro");
    // On utilise le flux
}

function errorCallback() {
    alert ("L'utilisateur a refusé l'accès au micro");
}

Tip: Sur Chrome quand un vous avez donné l'accès à votre micro à un site, vous pouvez voir ce point rouge sur l'onglet. Onglet micro

Web Audio API

Comme vous vous en doutez, cette API permet d'effectuer tout un tas d'opérations sur les sons.

Compatibilité

L'API Audio est un peu mieux supportée mais toujours pas sur IE (même 11!)

AudioContext

L'AudioContext permet de gérer et de jouer des sons.

Le principe est assez simple : une source audio (ici notre micro) est connectée à une destination (nos écouteurs). Entre les deux, notre source peut passer à travers des AudioNodes qui vont nous permettre par exemple d'appliquer des filtres sur le signal.

Audio context : Source --> AudioNode(s) --> Destination

Nous allons commencer par créer un AudioContext.

var audioContext = new AudioContext();

Compatibilité multi-navigateurs : Comme pour getUserMedia, on préfixe AudioContext (il n'y a besoin que de webkit cette fois ci).

window.AudioContext = window.AudioContext || window.webkitAudioContext;
var audioContext = new AudioContext();

Connecter la source à la destination

C'est très simple, le code parle de lui même.

function successCallback(stream) {
    // Micro
    var source = audioContext.createMediaStreamSource(stream);
    // Ecouteurs
    var destination = audioContext.destination;

    // On connecte notre micro aux écouteurs
    source.connect(destination);
}

Ajouter un AudioNode

Un AudioNode se met entre la source et la destination et permet d'effectuer de nombreuses opérations sur le flux.

Il existe plusieurs types d'AudioNodes, qui vont nous permettre de modifier le flux audio (modifier le volume, appliquer des effets, etc.) ou d'en extraire des données.

Pour l'exemple nous allons utiliser l'AnalyserNode qui permet de récupérer la fréquence du flux et d'en faire une représentation visuelle.

Nous allons donc connecter notre micro à l'AnalyserNode.

function successCallback(stream) {
    var source = audioContext.createMediaStreamSource(stream);
    var destination = audioContext.destination;
    // AnalyserNode
    var analyserNode = audioContext.createAnalyser();

    // On fait passer la source dans l'AudioNode
    source.connect(analyserNode);
    // On connecte notre micro aux écouteurs
    analyserNode.connect(destination);
}

Maintenant il faut exploiter l'AnalyserNode. Pour cela, on va à chaque frame récupérer un tableau de fréquences et en calculer la moyenne. Libre à vous ensuite de représenter cela visuellement.

var frequencyData, analyserNode;

function successCallback(stream) {
    var source = audioContext.createMediaStreamSource(stream);
    var destination = audioContext.destination;
    // AnalyserNode
    analyserNode = audioContext.createAnalyser();

    // On fait passer la source dans l'AudioNode
    source.connect(analyserNode);
    // On connecte notre micro aux écouteurs
    analyserNode.connect(destination);

    // On récupère le frequencyBinCount
    frequencyData = new Uint8Array(analyserNode.frequencyBinCount);
    update();
}

function update() {
    // On programme le prochain update
    requestAnimationFrame(update);

    // On récupère les nouvelles fréquences
    analyserNode.getByteFrequencyData(frequencyData);

    var average = 0;
    var frequencyLength = frequencyData.length;

    // On boucle sur chaque fréquence pour calculer la moyenne
    for (var i = 0; i < frequencyLength; i++) {
        // Les valeurs vont de 0 à 256
        var value = frequencyData[i] / 256;
        average += value;
    }

    // Soyez créatifs ;)
    average = average / frequencyLength;
    console.log(average);
}

N'hésitez pas à jouer avec les différents AudioNodes, on peut assez simplement transformer sa voix.

Tip: Testez le BiquadFilterNode, vous aurez des résultats surprenants ;)

Pour réaliser Audio Flappy Bird, j'utilise le code ci-dessus en définissant la hauteur de Flappy en fonction de la valeur moyenne du tableau de fréquences.

Le code source d'Audio Flappy Bird est disponible sur github https://github.com/T1l3/AudioFlappyBird.