I denne opplæringen vil vi pakke inn Web Audio i en enkel API som fokuserer på spillelyder innenfor et 3D-koordinatrom, og kan brukes til omfattende interaktive applikasjoner, inkludert, men ikke begrenset til, 3D-spill.
Denne opplæringen er den andre i en todelt serie. Hvis du ikke har lest den første opplæringen i serien, bør du gjøre det før du leser denne opplæringen fordi den introduserer deg til de ulike Web Audio-elementene vi skal bruke her.
Før vi kommer i gang, er det en liten demonstrasjon som bruker den forenklede API som vi skal dekke i denne opplæringen. Lyder (representert ved de hvite torgene) er tilfeldig plassert og spilt i et 3D-koordinatrom ved hjelp av den overordnede overføringsfunksjonen (HRTF) som Web Audio gir oss.
Kildefilene for demonstrasjonen er vedlagt denne opplæringen.
Fordi den forenklede API (AudioPlayer) allerede er opprettet for denne opplæringen og tilgjengelig for nedlasting, er det vi skal gjøre her, en bred titt på AudioPlayer API og koden som driver den.
Før du fortsetter denne opplæringen, vennligst les den forrige opplæringen i denne serien hvis du ikke har gjort det allerede, og er nytt for verden av Web Audio.
De Audioplayer
klassen inneholder vår forenklede API og er eksponert på vindu
objekt sammen med standard Web Audio klasser hvis, og bare hvis, Web Audio støttes av nettleseren. Dette betyr at vi bør sjekke eksistensen av klassen før vi prøver å bruke den.
hvis (window.AudioPlayer! == undefined) audioPlayer = new AudioPlayer ()
(Vi kunne ha forsøkt å skape en ny Audioplayer
objekt innen a prøv ... fange
uttalelse, men en enkel betinget sjekk fungerer perfekt.)
Bak kulissene, den Audioplayer
skaper en ny AudioContext
objekt og en ny AudioGainNode
objekt for oss, og kobler til GainNode
protestere mot mål
node eksponert av AudioContext
gjenstand.
var m_context = ny AudioContext () var m_gain = m_context.createGain () ... m_gain.connect (m_context.destination)
Når lyder opprettes og spilles, blir de koblet til m_gain
node, dette tillater oss å kontrollere volumet (amplitude) av alle lydene enkelt.
De Audioplayer
Konfigurerer også lyden lytteren
, eksponert av m_context
, så det samsvarer med det vanlige 3D-koordinatsystemet som brukes med WebGL. Den positive z
aksepunkter på betrakteren (med andre ord, det peker ut av 2D-skjermen), den positive y
akse peker opp, og den positive x
akse peker til høyre.
m_context.listener.setOrientation (0, 0, -1, 0, 1, 0)
Stillingen av lytteren
er alltid null; den sitter i midten av lydkoordinatsystemet.
Før vi kan lage eller spille noen lyder, må vi laste lydfilene; heldigvis nok Audioplayer
tar vare på alt det harde arbeidet for oss. Det avslører a last (...)
funksjon som vi kan bruke til å laste inn lydene, og tre hendelseshåndterere som tillater oss å holde oversikt over lastprogresjonen.
audioPlayer.onloadstart = funksjon () ... audioPlayer.onloaderror = funksjon () ... audioPlayer.onloadcomplete = funksjon () ... audioPlayer.load ("sound-01.ogg") audioPlayer.load ("sound-02 .ogg ") audioPlayer.load (" sound-03.ogg ")
Sett med lydformater som støttes, er nettleseravhengig. For eksempel støtter Chrome og Firefox OGG Vorbis, men ikke Internet Explorer. Alle tre nettleserne støtter MP3, noe som er praktisk, men problemet med MP3 er mangelen på sømløs lydsløyfe. MP3-formatet er ganske enkelt ikke designet for det. OGG Vorbis er imidlertid, og kan loop lykke perfekt.
Når du ringer til last (...)
funksjon flere ganger, Audioplayer
vil presse forespørslene inn i en kø og laste dem i rekkefølge. Når alle lydene i kø er lastet inn (og dekodet) onloadcomplete
Event Handler vil bli kalt.
Bak scenen, Audioplayer
bruker en enkelt XMLHttpRequest
motsette seg å laste lydene. De responseType
av forespørselen er satt til "Arraybuffer"
, og når filen har lastet matrisbufferen, sendes den til m_context
for dekoding.
// forenklet eksempel m_loader = ny XMLHttpRequest () m_queue = [] funksjonsbelastning () m_loader.open ("GET", m_queue [0]) m_loader.responseType = "arraybuffer" m_loader.onload = onLad m_loader.send () funksjon onLoad (event) var data = m_loader.response var status = m_loader.status m_loader.abort () // tilbakestiller lasteren hvis (status < 400) m_context.decodeAudioData(data, onDecode)
Hvis lasting og dekoding av en fil er vellykket, Audioplayer
vil enten laste inn den neste filen i køen (hvis køen ikke er tom) eller la oss få vite at alle filene er lastet inn.
Nå som vi har lastet inn noen lydfiler, kan vi lage og spille av våre lyder. Vi må først fortelle Audioplayer
å lage lydene, og dette gjøres ved å bruke skape(… )
funksjon eksponert av Audioplayer
.
var sound1 = audioPlayer.create ("sound-01.ogg") var sound2 = audioPlayer.create ("sound-02.ogg") var sound3 = audioPlayer.create ("sound-03.ogg")
Vi er fri til å lage så mange lyder som vi trenger, selv om vi bare har lastet inn en enkelt lydfil.
var a = audioPlayer.create ("beep.ogg") var b = audioPlayer.create ("beep.ogg") var c = audioPlayer.create ("beep.ogg")
Lydfilbanen passerte til skape(… )
funksjon forteller bare Audioplayer
hvilken fil den opprettede lyden skal bruke. Hvis den angitte lydfilen ikke er lastet inn når skape(… )
funksjon kalles, vil en runtime feil bli kastet.
Når vi har opprettet en eller flere lyder, er vi fri til å spille disse lydene når vi trenger det. For å spille en lyd bruker vi den passende navnet spille(… )
funksjon eksponert av Audioplayer
.
audioPlayer.play (SOUND1)
For å avgjøre om du skal spille en loopet lyd, vi kan også passere en boolsk til spille(… )
funksjon. Hvis den boolske er ekte
, lyden løper kontinuerlig til den stoppes.
audioPlayer.play (sound1, true)
For å stoppe en lyd kan vi bruke Stoppe(… )
funksjon.
audioPlayer.stop (SOUND1)
De spiller(… )
funksjonen lar oss vite om en lyd spiller for øyeblikket.
hvis (audioPlayer.isPlaying (lyd1)) ...
Bak kulissene, den Audioplayer
må gjøre en overraskende mengde arbeid for å få lyd til å spille, på grunn av den modulære naturen til Web Audio. Når en lyd må spilles,Audioplayer
må skape nye AudioSourceBufferNode
og PannerNode
objekter, konfigurere og koble dem til, og koble deretter lyden til m_gain
node. Heldigvis, Web Audio er svært optimalisert, slik at opprettelsen og konfigurasjonen av nye lydnoder gir sjelden noen merkbare overhead.
sound.source = m_context.createBufferSource () sound.panner = m_context.createPanner () sound.source.buffer = sound.buffer sound.source.loop = loop sound.source.onended = onSoundEnded // Dette er litt av et hack men vi må referere til lyd // objektet i hendelseshåndtereren onSoundEnded, og gjøre ting // denne måten er mer optimal enn å binde handleren. sound.source.sound = lyd sound.panner.panningModel = "HRTF" sound.panner.distanceModel = "lineær" sound.panner.setPosition (lyd.x, sound.y, sound.z) sound.source.connect (lyd .panner) sound.panner.connect (m_gain) sound.source.start ()
Å spille lyd er åpenbart nyttig, men hensikten med Audioplayer
er å spille lyder i et 3D-koordinatsystem, så vi bør sannsynligvis stille lydposisjonene før du spiller dem. Audioplayer
utsetter noen få funksjoner som tillater oss å gjøre nettopp det.
setX (...)
og getX (...)
funksjoner eksponert av Audioplayer
kan brukes til å sette og få posisjonen til en lyd langs koordinatsystemet x
akser.setY (...)
og getY (...)
Funksjoner kan brukes til å sette og få posisjonen til en lyd langs koordinatsystemet y
akser.setZ (...)
og getZ (...)
Funksjoner kan brukes til å sette og få posisjonen til en lyd langs koordinatsystemet z
akser.setPosition (...)
funksjonen kan brukes til å angi posisjonen til en lyd langs koordinatsystemet x
, y
, og z
akser henholdsvis.audioPlayer.setX (lyd1, 100) audioPlayer.setZ (lyd1, 200) console.log (audioPlayer.getX (lyd1)) // 100 console.log (audioPlayer.getZ (lyd1)) // 200 audioPlayer.setPosisjon (lyd1, 300, 0, 400) console.log (audioPlayer.getX (lyd1)) // 300 console.log (audioPlayer.getZ (lyd1)) // 400
Jo lenger en lyd er fra sentrum av koordinatsystemet, desto roligere blir lyden. På en avstand av 10000
(Web Audio Standard) En lyd blir helt stille.
Vi kan kontrollere det globale (master) volumet av lydene ved å bruke setVolume (...)
og getVolume (...)
funksjoner eksponert av Audioplayer
.
audioPlayer.setVolume (0.5) // 50% console.log (audioPlayer.getVolume ()) // 0.5
De setVolume (...)
funksjonen har også en andre parameter som kan brukes til å fade volumet over en tidsperiode. For eksempel å fade volumet til null over en to sekunders periode, kan vi gjøre følgende:
audioPlayer.setVolume (0.0, 2.0)
Tutorial-demoen utnytter dette for å fade inn lydene jevnt.
Bak kulissene, den Audioplayer
forteller bare m_gain
knutepunktet for å endre gevinstverdien lineært når volumet må endres.
var currentTime = m_context.currentTime var currentVolume = m_gain.gain.value m_gain.gain.cancelScheduledValues (0.0) m_gain.gain.setValueAtTime (currentVolume, currentTime) m_gain.gain.linearRampToValueAtTime (volum, nåværende tid + tid)
Audioplayer
håndhever en minimumsfadingstid på 0.01
sekunder, for å sikre at bratte volumendringer ikke forårsaker noen hørbare klikk eller dukker opp.
I denne veiledningen tok vi en titt på en måte å pakke inn Web Audio i en enkel API som fokuserer på spillelyder innenfor et 3D-koordinatrom for bruk i (blant andre programmer) 3D-spill.
På grunn av den modulære naturen til Web Audio, kan programmer som bruker Web Audio, bli komplekse ganske raskt, så jeg håper denne opplæringen har vært til nytte for deg. Når du forstår hvordan Web Audio fungerer, og hvor kraftig det er, er jeg sikker på at du vil ha det mye moro med det.
Ikke glem lydspilleren og demonstrasjonskildefilene er tilgjengelige på GitHub og klar for nedlasting. Kildekoden kommenteres ganske bra, så det er verdt å ta deg tid til å se på det raskt.
Hvis du har tilbakemelding eller spørsmål, vær så snill å poste en kommentar nedenfor.