Chrome a constamment et discrètement amélioré sa compatibilité avec l'API Web Audio. Dans Chrome 49 (bêta depuis février 2016, et version stable attendue en mars 2016), nous avons mis à jour plusieurs fonctionnalités pour suivre les spécifications et ajouté un nouveau nœud.
decodeAudioData() renvoie désormais une promesse
La méthode decodeAudioData() sur AudioContext
renvoie désormais un Promise
, ce qui permet de gérer les modèles asynchrones basés sur des promesses. La méthode decodeAudioData()
a toujours accepté des fonctions de rappel de succès et d'erreur comme paramètres:
context.decodeAudioData( arraybufferData, onSuccess, onError);
Vous pouvez désormais utiliser la méthode Promise standard pour gérer la nature asynchrone du décodage des données audio:
context.decodeAudioData( arraybufferData ).then(
(buffer) => { /* store the buffer */ },
(reason) => { console.log("decode failed! " + reason) });
Bien que cela semble plus verbeux dans un seul exemple, les promesses rendent la programmation asynchrone plus facile et plus cohérente. Pour des raisons de compatibilité, les fonctions de rappel "Success" et "Error" sont toujours prises en charge, conformément à la spécification.
OfflineAudioContext est désormais compatible avec suspend() et resume()
À première vue, il peut sembler étrange d'utiliser suspend() sur un OfflineAudioContext.
Après tout, suspend()
a été ajouté à AudioContext
pour permettre de mettre le matériel audio en mode veille, ce qui semble inutile dans les scénarios où vous effectuez un rendu dans un tampon (ce qui est l'objectif de OfflineAudioContext
, bien sûr).
Toutefois, l'objectif de cette fonctionnalité est de ne pouvoir construire qu'une partie d'un "score" à la fois, afin de réduire au maximum l'utilisation de la mémoire. Vous pouvez créer d'autres nœuds pendant que vous êtes suspendu au milieu d'un rendu.
Par exemple, la Sonate au clair de lune de Beethoven contient environ 6 500 notes.
Chaque "note" se décompose probablement en au moins deux nœuds de graphique audio (par exemple, un AudioBuffer et un nœud Gain). Si vous souhaitez afficher l'intégralité des sept minutes et demie dans un tampon avec OfflineAudioContext
, vous ne souhaitez probablement pas créer tous ces nœuds en même temps. Vous pouvez les créer par blocs de temps:
var context = new OfflineAudioContext(2, length, sampleRate);
scheduleNextBlock();
context.startRendering().then( (buffer) => { /* store the buffer */ } );
function scheduleNextBlock() {
// create any notes for the next blockSize number of seconds here
// ...
// make sure to tell the context to suspend again after this block;
context.suspend(context.currentTime + blockSize).then( scheduleNextBlock );
context.resume();
}
Vous pourrez ainsi réduire le nombre de nœuds à précréer au début du rendu et réduire les exigences en termes de mémoire.
IIRFilterNode
La spécification a ajouté un nœud pour les audiophiles qui souhaitent créer leur propre réponse impulsionnelle infinie précisément spécifiée : le IIRFilterNode.
Ce filtre complète le BiquadFilterNode, mais permet de spécifier complètement les paramètres de réponse du filtre (plutôt que le AudioParams
facile à utiliser de BiquadFilterNode
pour le type, la fréquence, Q, etc.). IIRFilterNode
permet de spécifier précisément des filtres qui ne pouvaient pas être créés auparavant, comme les filtres à ordre unique. Toutefois, l'utilisation d'IIRFilterNode nécessite une connaissance approfondie du fonctionnement des filtres IIR. Ils ne sont pas non plus planifiables comme les BiquadFilterNodes.
Modifications précédentes
Je voudrais également mentionner quelques améliorations apportées précédemment: dans Chrome 48, l'automatisation des nœuds BiquadFilter
a commencé à s'exécuter à la fréquence audio. L'API n'a pas changé du tout pour ce faire, mais cela signifie que vos balayages de filtres seront encore plus fluides. Dans Chrome 48, nous avons également ajouté la méthode AudioNode.connect()
en renvoyant le nœud auquel nous nous connectons. Cela permet de créer plus facilement des chaînes de nœuds, comme dans cet exemple:
sourceNode.connect(gainNode).connect(filterNode).connect(context.destination);
C'est tout pour le moment. À bientôt !