Creëer dynamisch geluid met de Web Audio API

Vóór de Web Audio API gaf HTML5 ons de element. Het lijkt misschien moeilijk om het nu te onthouden, maar voorafgaand aan de element, onze beste optie voor geluid in een browser was een plug-in! 

De element was inderdaad opwindend, maar het had een vrij unieke focus. Het was in wezen een videospeler zonder de video, goed voor lange audio zoals muziek of een podcast, maar niet geschikt voor de eisen van gaming. We verdragen (of hebben oplossingen gevonden voor) problemen met lussen, gelijktijdige geluidslimieten, glitches en totaal gebrek aan toegang tot de geluidsgegevens zelf.

Gelukkig heeft ons geduld zijn vruchten afgeworpen. Waar de element ontbrak, de Web Audio API levert. Het geeft ons een ongekende controle over geluid en het is perfect voor alles, van gaming tot geavanceerde geluidsbewerking. Dit alles met een opgeruimde API die erg leuk is om te gebruiken en goed wordt ondersteund.

Laten we iets specifieker zijn: Web Audio geeft u toegang tot de onbewerkte golfvormgegevens van een geluid en kunt u het manipuleren, analyseren, vervormen of anderszins wijzigen. Het is voor audio wat de canvas-API is voor pixels. U hebt diepe en veelal onbelemmerde toegang tot de geluidsgegevens. Het is echt krachtig!

Deze tutorial is de tweede in een serie over Flight Arcade-gebouwd om te laten zien wat er mogelijk is op het webplatform en in de nieuwe Microsoft Edge-browser en EdgeHTML-renderingengine. Interactieve code en voorbeelden voor dit artikel bevinden zich ook in Flight Arcade / Learn.

Vluchtgeluiden

Zelfs de vroegste versies van Flight Simulator deden hun best om het gevoel van vliegen opnieuw te creëren met geluid. Een van de belangrijkste geluiden is de dynamische toonhoogte van de motor die van toonhoogte verandert met het gaspedaal. We wisten dat, toen we de game voor het web opnieuw bedachten, een statisch motorgeluid echt plat leek, dus de dynamische toonhoogte van het motorgeluid was een voor de hand liggende kandidaat voor Web Audio.

Minder voor de hand liggend (maar mogelijk interessanter) was de stem van onze vlieginstructeur. In vroege iteraties van Flight Arcade speelden we de stem van de instructeur zoals die was opgenomen, en het klonk alsof het uit een geluidscabine kwam! We merkten dat we de stem als de "verteller" noemden in plaats van de "instructeur". 

Op de een of andere manier brak dat onberispelijke geluid de illusie van het spel. Het leek niet goed om zo'n perfect geluid over de lawaaierige geluiden van de cockpit te laten komen. In dit geval hebben we Web Audio gebruikt om enkele eenvoudige vervormingen toe te passen op de spraakinstructie en het realisme van leren vliegen te verbeteren!

In de onderstaande secties geef ik u een vrij gedetailleerd beeld van hoe we de Web Audio API hebben gebruikt om deze geluiden te maken.

De API gebruiken: AudioContext en audiobronnen

De eerste stap in elk Web Audio-project is het maken van een AudioContext voorwerp. Sommige browsers (inclusief Chrome) vereisen nog steeds dat deze API wordt voorafgegaan, zodat de code er als volgt uitziet:

var AudioContext = window.AudioContext || window.webkitAudioContext; var audioCtx = nieuwe AudioContext ();

Dan heb je een geluid nodig. Je kunt eigenlijk helemaal vanuit het niets geluiden genereren met de Web Audio API, maar voor onze doeleinden wilden we een vooraf opgenomen audiobron laden. Als je al een HTML had element, je zou dat kunnen gebruiken, maar vaak doe je dat niet. Immers, wie heeft er een nodig element als je webaudio hebt? Meestal download je de audio gewoon rechtstreeks in een buffer met een HTTP-verzoek:

var request = new XMLHttpRequest (); request.open ("GET", url, true); request.responseType = "arraybuffer"; var loader = this; request.onload = function () loader.context.decodeAudioData (request.response, function (buffer) if (! buffer) console.log ('error decoding file data:' + url); return; loader.bufferList [index] = buffer; if (++ loader.loadCount === loader.urlList.length) loader.onload (loader.bufferList);, function (error) console.error ('decodeAudioData error', error );); ;

Nu hebben we een AudioContext en enkele audiogegevens. De volgende stap is om deze dingen samen te laten werken. Daarvoor hebben we ...

AudioNodes

Zowat alles wat je doet met Web Audio gebeurt via een soort AudioNode, en ze komen in veel verschillende smaken: sommige knooppunten worden gebruikt als audiobronnen, sommige als audio-uitgangen, en sommige als audioprocessors of analysers. Je kunt ze samen ketenen om interessante dingen te doen.

Je zou de AudioContext kunnen zien als een soort geluidsfase. De verschillende instrumenten, versterkers en luidsprekers die het bevat, zijn allemaal verschillende soorten AudioNodes. Werken met de Web Audio API lijkt veel op het samenvoegen van al deze dingen (instrumenten in bijvoorbeeld effectpedalen en het pedaal in een versterker en vervolgens luidsprekers, etc.).

Om iets interessants te doen met onze nieuw verworven AudioContext-audiobronnen, moeten we eerst de audiogegevens inkapselen als een bron AudioNode.

var sourceNode = audioContext.createBufferSource ();

afspelen

Dat is het. We hebben een bron. Maar voordat we het kunnen spelen, moeten we het verbinden met een bestemmingsknooppunt. Voor het gemak stelt de AudioContext een standaard bestemmingsknooppunt voor (meestal uw hoofdtelefoon of luidsprekers). Eenmaal verbonden, is het gewoon een kwestie van bellen begin en hou op.

sourceNode.connect (audioContext.destination); sourceNode.start (0); sourceNode.stop ();

Het is vermeldenswaard dat je alleen kunt bellen begin() eenmaal op elk bronknooppunt. Dat betekent dat "pauze" niet direct wordt ondersteund. Zodra een bron is gestopt, is deze verlopen. Gelukkig zijn bronknooppunten goedkope objecten, ontworpen om eenvoudig te worden gemaakt (de audiogegevens zelf, onthoudt, bevindt zich in een afzonderlijke buffer). Dus, als u een gepauzeerd geluid wilt hervatten, kunt u eenvoudig een nieuw bronknooppunt en gesprek maken begin() met een tijdstempelparameter. AudioContext heeft een interne klok die u kunt gebruiken om tijdstempels te beheren. 

Het motorgeluid

Dat is het voor de basis, maar alles wat we tot nu toe gedaan hebben (eenvoudig afspelen van audio) had met het oude gedaan kunnen worden element. Voor Flight Arcade moesten we iets dynamischers doen. We wilden dat het veld zou veranderen met de snelheid van de motor.

Dat is eigenlijk vrij eenvoudig met Web Audio (en zou bijna onmogelijk zijn geweest zonder het)! Het bronknooppunt heeft een snelheidseigenschap die van invloed is op de afspeelsnelheid. Om de toonhoogte te verhogen, verhogen we gewoon de afspeelsnelheid:

throttleSlider.onMove = function (val) sourceNode.source.playbackRate.value = val; ;

Het motorgeluid moet ook worden herhaald. Dat is ook heel gemakkelijk (er is ook een eigenschap voor):

sourceNode.source.loop = true;

Maar er is een vangst. Veel audioformaten (vooral gecomprimeerde audio) slaan de audiogegevens op in frames met een vaste grootte en, vaker wel dan niet, zullen de audiogegevens zelf het laatste frame niet "vullen". Dit kan een klein gat achterlaten aan het einde van het audiobestand en resulteren in klikken of glitches wanneer die audiobestanden worden gelust. Standaard HTML-audio-elementen bieden geen enkele vorm van controle over deze kloof, en het kan een grote uitdaging zijn voor webgames die afhankelijk zijn van looping-audio.

Gelukkig is het afspelen van hiaten zonder geluid met de Web Audio API echt eenvoudig. Het is gewoon een kwestie van een tijdstempel instellen voor het begin en einde van het lusgedeelte van de audio (merk op dat deze waarden relatief zijn ten opzichte van de audiobron zelf en niet de AudioContext-klok).

engineAudioSource.source.loopStart = 0,5; engineAudioSource.source.loopEnd = 1.5;

De instructeursstem

Tot nu toe is alles wat we hebben gedaan met een bronknooppunt (ons audiobestand) en een uitgangsknooppunt (de geluidsbestemming die we eerder hebben ingesteld, waarschijnlijk je speakers), maar AudioNodes kan voor veel meer worden gebruikt, inclusief geluidsmanipulatie of analyse. In Flight Arcade hebben we twee knooppunttypen (een ConvolverNode en een WaveShaperNode) gebruikt om de stem van de instructeur te laten klinken alsof deze door een luidspreker komt.

kronkeling

Van de W3C-specificatie:

Convolution is een wiskundig proces dat op een audiosignaal kan worden toegepast om veel interessante, hoogwaardige lineaire effecten te bereiken. Heel vaak wordt het effect gebruikt om een ​​akoestische ruimte te simuleren, zoals een concertzaal, een kathedraal of een openluchtamfitheater. Het kan ook worden gebruikt voor complexe filtereffecten, zoals een gedempt geluid vanuit een kast, geluid onder water, geluid via een telefoon of via een vintage luidsprekerkast. Deze techniek wordt heel vaak gebruikt bij de productie van grote films en muziek en wordt beschouwd als extreem veelzijdig en van hoge kwaliteit.

Convolution combineert in principe twee geluiden: een geluid dat moet worden verwerkt (de stem van de instructeur) en een geluid dat een impulsrespons wordt genoemd. De impulsrespons is inderdaad een degelijk bestand, maar het is echt alleen nuttig voor dit soort convolutieproces. Je kunt het beschouwen als een soort geluidsfilter, ontworpen om een ​​specifiek effect te produceren wanneer het geconvolueerd is met een ander geluid. Het resultaat is meestal veel realistischer dan eenvoudige wiskundige manipulatie van de audio.

Om het te gebruiken, maken we een convolutiepunt, laden we de audio met de impulsrespons en verbinden we de knooppunten.

// create the convolver var convolverNode = audioContext.createConvolver (); // neem aan dat we het telefoongeluid al hebben gedownload in een bufferconvoliver.buffer = telephponeBuffer; // verbind de knooppunten sourceNode.connect (convolverNode); convolverNode.connect (audioContext.destination);

Wave Shaping

Om de vervorming te vergroten, gebruikten we ook een WaveShaper-knooppunt. Met dit type knooppunt kunt u wiskundige vervorming toepassen op het audiosignaal om een ​​aantal echt dramatische effecten te bereiken. De vervorming is gedefinieerd als een curvefunctie. Die functies kunnen wat ingewikkelde wiskunde vereisen. Voor het onderstaande voorbeeld hebben we een goede geleend van onze vrienden bij MDN.

// maak de waveshaper var waveShaper = audioContext.createWaveShaper (); // onze functie voor vervormingscurve makeDistortionCurve (aantal) var k = typeof amount === 'number'? aantal: 50, n_samples = 44100, curve = nieuwe Float32Array (n_samples), deg = Math.PI / 180, i = 0, x; voor (; < n_samples; ++i )  x = i * 2 / n_samples - 1; curve[i] = ( 3 + k ) * x * 20 * deg / (Math.PI + k * Math.abs(x));  return curve;  // connect the nodes sourceNode.connect(convolver); convolver.connectwaveShaper); waveShaper.connect(audioContext.destination); // vary the amount of distortion with the slider distortionSlider.onMove = function(val) waveShaper.curve = makeDistortionCurve(val); ;

Let op het grote verschil tussen de originele golfvorm en de golfvorm waarop de WaveShaper is toegepast.

Het bovenstaande voorbeeld is een dramatische weergave van hoeveel u kunt doen met de Web Audio API. We maken niet alleen een aantal heel dramatische veranderingen aan het geluid rechtstreeks vanuit de browser, maar we analyseren ook de golfvorm en maken deze in een canvas-element! De Web Audio API is ongelooflijk krachtig en veelzijdig en, eerlijk gezegd, erg leuk!

Meer hands-on met JavaScript

Microsoft heeft veel gratis leren over veel open-source JavaScript-onderwerpen en we zijn op een missie om nog veel meer met Microsoft Edge te maken. Hier zijn enkele om te bekijken:

  • Microsoft Edge Web Summit 2015 (een complete reeks van wat u kunt verwachten met de nieuwe browser, nieuwe webplatformfuncties en gastsprekers uit de community)
  • Het beste van // BUILD / en Windows 10 (inclusief de nieuwe JavaScript-engine voor sites en apps)
  • JavaScript vooruit helpen zonder het web te breken (de recente keynote van Christian Heilmann)
  • Gehoste webapps en webplatforminnovaties (een diepgaande duik over onderwerpen als manifold.JS)
  • Praktische prestatie-tips om uw HTML / JavaScript sneller te maken (een zevendelige serie van responsief ontwerp tot informele games tot prestatie-optimalisatie)
  • De Jump-start van het moderne webplatform (de fundamenten van HTML, CSS en JavaScript)

En enkele gratis tools om aan de slag te gaan: Visual Studio Code, Azure Trial en testtools voor meerdere browsers, allemaal beschikbaar voor Mac, Linux of Windows.

Dit artikel maakt deel uit van de web dev tech-serie van Microsoft. We zijn verheugd om te delen Microsoft Edge en het nieuwe EdgeHTML-renderingengine met jou. Download gratis virtuele machines of test op afstand op uw Mac, iOS, Android of Windows-apparaat @ http://dev.modern.ie/.