I denna handledning tar vi en närmare titt på de grundläggande Web Audio-elementen som används för att konstruera 3D-ljudbilder för immersiva interaktiva applikationer inklusive, men inte begränsat till, 3D-spel.
Web Audio API och den terminologi som den använder kan ibland vara förvirrande men den här handledningen syftar till att ta bort komplexiteten och ge en enklare förklaring av Web Audio-elementen och hur de fungerar tillsammans för att bilda en 3D-ljudbild.
Denna demonstration innehåller tre ljud som roterar runt en lyssnare, Lyttarens riktning indikeras av pilen. Om du kan tänka dig att titta på ett speltecken (lyssnaren), kan de roterande ljuden enkelt representera vänner eller fiender som cirklar karaktären.
Demonstrationskällkoden och resurserna bifogas denna handledning.
De AudioContext
gränssnittet är hjärtan och själen i Web Audio, det ger de funktioner som krävs för att skapa olika Web Audio-element samt tillhandahålla ett sätt att skicka allt ljud till hårdvara och framåt till någons högtalare eller hörlurar.
var audioContext = null om (window.AudioContext! == undefined) audioContext = new AudioContext ()
Det är viktigt att se till att AudioContext
gränssnittet är tillgängligt eftersom webbljudet fortfarande är ganska nytt och det kanske inte är tillgängligt i vissa webbläsare.
Förutom att de funktioner som krävs för att skapa olika Web Audio-element, ska AudioContext
gränssnittet har två viktiga egenskaper; destination
och lyssnare
vilka båda är skrivskyddade. De destination
egendom kan ses som en anslutning till ljudhårdvara, det är där allt det genererade ljudet kommer att hamna i slutändan. De lyssnare
egendom (vi kommer att se ut så här mer i detalj senare) representerar sak som lyssnar på allt ljud, t.ex. ett tecken, eller mer exakt en kamera, i ett spel.
De AudioBuffer
och AudioBufferSourceNode
gränssnitt tillåter oss att spela ljud. AudioBuffer
Objekt innehåller de råa ljuden (ljudprover) som är tweaked, crunched och krossade när de går igenom Web Audio innan de når någons högtalare eller hörlurar. AudioBufferSourceNode
objekt används för att starta och stoppa ljudet som finns i AudioBuffer
objekt.
Det vanliga sättet att ladda ljud till en AudioBuffer
objektet är att använda a XMLHttpRequest
objekt med dess responseType
satt till arraybuffer
. När ljudfilen har laddats skickas matrisbufferten sedan till AudioContext
objekt för avkodning och, om avkodningen är framgångsrik, kommer vi att förses med en AudioBuffer
objekt.
var loader.onload = närladdad loader.send () funktion whenLoaded (händelse) var data = loader.windows (open) (varas = loader.open ("GET", "massive-explosion.ogg") loader.responseType = "arraybuffer" .response if (data === null) // Det gick inte att ladda filen. returnera // Avkod data. audioContext.decodeAudioData (data, whenDecoded) funktion närDecoded (audioBuffer) // "audioBuffer" är ett AudioBuffer-objekt.
De decodeAudioData ()
funktionen har också en tredje parameter som accepterar en andra återuppringning, den återkallas kallas när den laddade ljudfilen inte kan avkodas.
decodeAudioData (data, närDecoded, whenFailed)
Inte alla webbläsare stöder samma ljudformat. Ett bra tablett med stödformat finns här, så du kanske vill använda den andra återuppringningen till fallback till ett alternativt ljudformat om det behövs. Till exempel stöder Internet Explorer inte OGG Vorbis men det stöder MP3. Det enda verkliga problemet med MP3 är att det inte tillåter sömlöst loopat ljud som OGG Vorbis gör.
När du har en AudioBuffer
objekt tillgängligt du kan spela det med en AudioBufferSourceNode
objekt.
var source = audioContext.createBufferSource () // Bifoga ett AudioBuffer-objekt. source.buffer = audioBuffer // Anslut "source" -objektet till "destination" -objektet. source.connect (audioContext.destination) // Optionellt, berätta "source" för att slingra ljudet kontinuerligt. source.loop = false // Starta ljudet. source.start ()
Det är viktigt att komma ihåg AudioBufferSourceNode
Objekt är enstaka ljudspelare, med andra ord kan du bara använda Start()
funktion en gång. Du måste skapa en AudioBufferSourceNode
objekt och anslut det (direkt eller indirekt) till destination
föremål utsatt av AudioContext
objekt när du vill spela ljud från en AudioBuffer
objekt.
Du kan göra livet lite enklare genom att skapa en liten verktygsfunktion som skapar, ansluter och startar en AudioBufferSourceNode
föremål för dig.
funktionsspel (audioBuffer01, audioContext) var source = audioContext.createSourceBuffer () source.buffer = audioBuffer source.connect (audioContext.destination) source.start () spela (audioBuffer01, audioContext) spela (audioBuffer02, audioContext) spela (audioBuffer03 , audioContext)
När en AudioBufferSourceCode
objekt slutar spelas och om du inte har några referenser till objektet någonstans (t.ex. du inte har dem lagrade i en array), kopplar Web Audio automatiskt objektet till dig. Det här är väldigt användbart när du bara behöver elda och glömma korta ljudeffekter mm.
Om du bestämmer dig för att slinga ljudet med hjälp av AudioBufferSourceNode
slinga
egendom, måste du hänvisa till AudioBufferSourceNode
objekt någonstans så du kan sluta()
ljudspelet.
source.stop ()
Så vid denna tidpunkt använder vi buffertar för att spela ljud, men ljudet spelas direkt utan att panning eller spatialisering appliceras på den. Det är här PannerNode
objekt kommer till spel.
PannerNode
objekt tillåter oss att placera ljud i 3D-rymden, inom ett kartesiskt koordinatsystem. Det här är där de flesta 3D-magikerna händer.
en PannerNode
objektet har en hel del egenskaper som gör att vi kan finjustera ljudets beteende men för denna handledning är vi bara intresserade av två av dem; maxDistance
och panningModel
. De maxDistance
egendom är avståndet från lyssnare vid vilken tidpunkt kommer ljudvolymen att vara noll. Detta är ett godtyckligt värde och kommer bara att innebära betydelse inom din ansökan men det är normalt 10000. Den panningModel
berättar Web Audio hur man behandlar ljudet som passerar genom a PannerNode
objekt. För 3D-ljudbilder kommer du förmodligen att ange värdet till HRTF
(huvudrelaterad överföringsfunktion).
För att ange positionen för en AudioBufferSourceNode
vi använder setPosition ()
funktion utsatt av a PannerNode
objekt.
var panner = audioContext.createPanner () panner.panningModel = "HRTF" // Ställ in 3D-positionen (x, y, z). panner.setPosition (1, 2, 3) // Anslut "source" -objektet till "panner" -objektet. source.connect (panner) // Anslut "panner" -objektet till "destination" -objektet. panner.connect (audioContext.destination) // Starta ljudet. source.start ()
För att göra sakerna lite tydligare, låt oss uppdatera den funktion som vi skapade tidigare.
funktionen spel (audioBuffer, x, y, z, audioContext) var source = audioContext.createSourceBuffer () source.buffer = audioBuffer var panner = audioContext.createPanner () panner.panningModel = "HRTF" panner.setPosition (x, y, z) source.connect (panner) panner.connect (audioContext.destination) source.start () spela (audioBuffer01, 1, 2, 3, audioContext) spela (audioBuffer02, 4, 5, 6, audioContext) spela (audioBuffer03, 7, 8, 9, audioContext)
Vid denna tidpunkt spelar vi ljud och placerar det i 3D-utrymme, men det finns ytterligare ett viktigt element som vi behöver titta på; ljudlyssnaren.
Varje AudioContext
objektet avslöjar a lyssnare
objekt som representerar positionen och orienteringen av sak det lyssnar på ljudet. Vanligtvis sak skulle vara en virtuell kamera som är kopplad till ett spel karaktärs huvud, bilens stötfångare, flygplanets svans eller något annat som är vettigt för betraktaren från deras perspektiv.
De lyssnare
objektet har a setPosition ()
funktion och a setOrientation ()
fungera. De setPosition ()
funktion placerar lyssnaren någonstans inom 3D-rymden och setOrientation ()
roterar lyssnaren (föreställ dig en kamera panorering och lutning).
De setPosition ()
funktion fungerar på exakt samma sätt som PannerNode
setPosition ()
funktion och accepterar tre koordinater.
audioContext.listener.setPosition (x, y, z)
De setOrientation ()
funktionen är lite mer komplex, det accepterar två enhetsvektorer. Den första vektorn representerar lyssnarens rotation (den riktning som kameran pekar), och den andra vektorn representerar lyssnarens upp riktning (den pekar ut över kamerans topp).
audioContext.listener.setOrientation (x1, y1, z1, x2, y2, z2)
Om du bara behöver rotera lyssnaren runt en axel är vektorkalkylerna relativt enkla. Till exempel, om du använder samma koordinatsystem som WebGL använder var positiv x
pekar till höger om skärmen, positiv y
pekar på toppen av skärmen och positivt z
pekar ut på skärmen, så kan du rotera lyssnaren runt y
axel (panorera kameran) med en cos ()
funktionssamtal och en synd()
funktionssamtal.
// Lyssnarens position (kan vara någonting). var x = 50 var y = 100 var z = 0 audioContext.listener.setPosition (x, y, z) // Beräkna rotationsvektorn. // rad = rotation, i radianer var rad = 0.10 var v1 = Math.cos (rad) // x var v2 = 0 // y var v3 = Math.sin (rad) // z // Den "upp" vektorn var v4 = 0 // x var v5 = 1 // y var v6 = 0 // z audioContext.listener.setOrientation (v1, v2, v3, v4, v5, v6)
Demonstrationen för denna handledning (källkod är bifogad) gör en liknande sak och roterar PannerNode
objekt runt en enda axel.
I denna handledning tog vi en titt på de grundläggande Web Audio-elementen som används för att konstruera 3D-ljudbilder för immersiva interaktiva applikationer, inklusive, men inte begränsat till, 3D-spel. Förhoppningsvis har denna handledning varit till nytta för dig och har gett tillräckligt med information för att du ska kunna förstå hur ljudbuffertar, pannrar och lyssnare arbetar tillsammans för att producera 3D-ljudbilder.
Om du har några kommentarer eller frågor, var god och skriv en kommentar nedan.
I nästa handledning, Web Audio och 3D Soundscapes: Implementation, kommer vi att ta alla ovanstående (och mer) och lägga in det i ett förenklat API. Huvudfokus för nästa handledning kommer att vara 3D-spel, men API: n kommer att vara generisk nog för användning i olika immersiva interaktiva applikationer.