In deze tutorial wikkelen we Web Audio in een eenvoudige API die zich richt op het afspelen van geluiden binnen een 3D-coördinaatruimte en die kan worden gebruikt voor meeslepende interactieve toepassingen, inclusief maar niet beperkt tot, 3D-games.
Deze tutorial is de tweede in een tweedelige serie. Als u de eerste zelfstudie in de serie niet hebt gelezen, moet u dit doen voordat u deze zelfstudie leest, omdat deze u kennis laat maken met de verschillende Web Audio-elementen die we hier zullen gebruiken.
Voordat we aan de slag gaan, is hier een kleine demonstratie die de vereenvoudigde API gebruikt die we in deze zelfstudie bespreken. Geluiden (vertegenwoordigd door de witte vierkanten) worden willekeurig gepositioneerd en gespeeld in een 3D-coördinaatruimte met behulp van de aan het hoofd gerelateerde overdrachtfunctie (HRTF) die Web Audio ons biedt.
De bronbestanden voor de demonstratie zijn bij deze zelfstudie gevoegd.
Omdat de vereenvoudigde API (AudioPlayer) al is gemaakt voor deze zelfstudie en beschikbaar is om te downloaden, gaan we hier uitgebreid kijken naar de AudioPlayer-API en de code waarmee deze wordt aangedreven.
Lees voordat u verder gaat met deze tutorial de vorige tutorial in deze serie als je dat nog niet gedaan hebt en nieuw bent in de wereld van Web Audio.
De Geluids speler
klasse bevat onze vereenvoudigde API en wordt getoond op de venster
object naast de standaard Web Audio-klassen als, en alleen als, Web Audio wordt ondersteund door de webbrowser. Dit betekent dat we moeten controleren of er een klasse bestaat voordat we het proberen te gebruiken.
if (window.AudioPlayer! == undefined) audioPlayer = nieuwe AudioPlayer ()
(We hadden kunnen proberen om een nieuwe te maken Geluids speler
object binnen een proberen te vangen
verklaring, maar een eenvoudige voorwaardelijke controle werkt perfect.)
Achter de schermen, de geluids speler
maakt een nieuw AudioContext
object en een nieuw AudioGainNode
object voor ons, en verbindt de GainNode
bezwaar tegen de bestemming
knoop blootgesteld door de AudioContext
voorwerp.
var m_context = new AudioContext () var m_gain = m_context.createGain () ... m_gain.connect (m_context.destination)
Wanneer geluiden worden gemaakt en afgespeeld, worden ze verbonden met de m_gain
knooppunt, dit stelt ons in staat om het volume (amplitude) van alle geluiden gemakkelijk te regelen.
De geluids speler
configureert ook de audio luisteraar
, blootgesteld door m_context
, dus het komt overeen met het gemeenschappelijke 3D-coördinatensysteem dat wordt gebruikt met WebGL. Het positieve z
as wijst naar de kijker (met andere woorden, het wijst naar het 2D-scherm), het positieve Y
as wijst naar boven en het positieve X
as wijst naar rechts.
m_context.listener.setOrientation (0, 0, -1, 0, 1, 0)
De positie van de luisteraar
is altijd nul; het bevindt zich in het midden van het audio-coördinatensysteem.
Voordat we geluiden kunnen maken of afspelen, moeten we de geluidsbestanden laden. gelukkig genoeg geluids speler
zorgt voor al het harde werk voor ons. Het onthult een laden (...)
functie die we kunnen gebruiken om de geluiden te laden, en drie event handlers waarmee we de voortgang van de lading kunnen volgen.
audioPlayer.onloadstart = function () ... audioPlayer.onloaderror = function () ... audioPlayer.onloadcomplete = function () ... audioPlayer.load ("sound-01.ogg") audioPlayer.load ("sound-02 .ogg ") audioPlayer.load (" sound-03.ogg ")
De reeks geluidsindelingen die wordt ondersteund, is browserafhankelijk. Chrome en Firefox ondersteunen bijvoorbeeld OGG Vorbis, maar Internet Explorer doet dit niet. Alle drie de browsers ondersteunen MP3, wat handig is, maar het probleem met MP3 is het ontbreken van een naadloze looping van het geluid - het MP3-formaat is er gewoon niet voor ontworpen. Echter, OGG Vorbis is, en kan loop-geluiden perfect.
Bij het bellen van de laden (...)
meerdere keren functioneren, geluids speler
zal de aanvragen in een wachtrij duwen en ze sequentieel laden. Wanneer alle in de wachtrij geplaatste geluiden zijn geladen (en zijn gedecodeerd) de gebeurtenishandler onLoadComplete
gebeurtenishandler wordt gebeld.
Achter de schermen, geluids speler
gebruikt een single XMLHttpRequest
object om de geluiden te laden. De responseType
van het verzoek is ingesteld op "Arraybuffer"
, en wanneer het bestand is geladen waarnaar de arraybuffer is verzonden m_context
voor decodering.
// vereenvoudigd voorbeeld m_loader = nieuw XMLHttpRequest () m_queue = [] functie load () m_loader.open ("GET", m_queue [0]) m_loader.responseType = "arraybuffer" m_loader.onload = onLoad m_loader.send () function onLoad (event) var data = m_loader.response var status = m_loader.status m_loader.abort () // reset de loader als (status < 400) m_context.decodeAudioData(data, onDecode)
Als het laden en decoderen van een bestand succesvol is, geluids speler
laadt het volgende bestand in de wachtrij (als de wachtrij niet leeg is) of laat ons weten dat alle bestanden zijn geladen.
Nu we enkele geluidsbestanden hebben geladen, kunnen we onze geluiden maken en afspelen. We moeten het eerst vertellen geluids speler
om de geluiden te creëren, en dit wordt gedaan met behulp van de maak (...)
functie zichtbaar gemaakt door geluids speler
.
var sound1 = audioPlayer.create ("sound-01.ogg") var sound2 = audioPlayer.create ("sound-02.ogg") var sound3 = audioPlayer.create ("sound-03.ogg")
We zijn vrij om zoveel geluiden te maken als we nodig hebben, zelfs als we maar één geluidsbestand hebben geladen.
var a = audioPlayer.create ("beep.ogg") var b = audioPlayer.create ("beep.ogg") var c = audioPlayer.create ("beep.ogg")
Het geluidsbestandpad doorgegeven aan de maak (...)
functie vertelt gewoon geluids speler
welk bestand het gemaakte geluid zou moeten gebruiken. Als het opgegeven geluidsbestand niet is geladen wanneer het maak (...)
functie wordt aangeroepen, wordt een runtime-fout gegenereerd.
Wanneer we een of meer geluiden hebben gemaakt, zijn we vrij om die geluiden te spelen wanneer dat nodig is. Om een geluid te spelen, gebruiken we de toepasselijke naam spelen (...)
functie zichtbaar gemaakt door geluids speler
.
audioPlayer.play (Geluid1)
Om te bepalen of een a moet worden afgespeeld gelust geluid, we kunnen ook een Boolean doorgeven aan de spelen (...)
functie. Als de Boolean is waar
, het geluid loopt continu door totdat het wordt gestopt.
audioPlayer.play (sound1, true)
Om een geluid te stoppen, kunnen we de hou op(… )
functie.
audioPlayer.stop (Geluid1)
De speelt(… )
functie laat ons weten of een geluid speelt op dit moment.
if (audioPlayer.isPlaying (sound1)) ...
Achter de schermen, de geluids speler
moet een verrassende hoeveelheid werk doen om een geluid te krijgen, vanwege het modulaire karakter van Web Audio. Wanneer een geluid moet worden gespeeld,geluids speler
moet nieuw maken AudioSourceBufferNode
en PannerNode
objecten, configureer en verbind ze en verbind vervolgens het geluid met de m_gain
knooppunt. Gelukkig is Web Audio sterk geoptimaliseerd, dus het maken en configureren van nieuwe audioknooppunten veroorzaakt zelden merkbare overheadkosten.
sound.source = m_context.createBufferSource () sound.panner = m_context.createPanner () sound.source.buffer = sound.buffer sound.source.loop = loop sound.source.onended = onSoundEnded // Dit is een beetje een hack maar we moeten verwijzen naar het geluid // -object in de gebeurtenishandler onSoundEnded en dingen doen // op deze manier is optimaler dan het verbinden van de handler. sound.source.sound = geluid sound.panner.panningModel = "HRTF" sound.panner.distanceModel = "lineaire" sound.panner.setPosition (sound.x, sound.y, sound.z) sound.source.connect (geluid .panner) sound.panner.connect (m_gain) sound.source.start ()
Het spelen van geluiden is natuurlijk nuttig, maar het doel van geluids speler
is om geluiden in een 3D-coördinatensysteem te spelen, dus we moeten waarschijnlijk de geluidsposities instellen voordat ze worden afgespeeld. geluids speler
onthult een paar functies die ons in staat stellen om precies dat te doen.
setX (...)
en getX (...)
functies zichtbaar gemaakt door geluids speler
kan worden gebruikt om de positie van een geluid langs het coördinatensysteem in te stellen en te krijgen X
as.setY (...)
en getY (...)
functies kunnen worden gebruikt om de positie van een geluid langs het coördinatensysteem in te stellen en te krijgen Y
as.setZ (...)
en getZ (...)
functies kunnen worden gebruikt om de positie van een geluid langs het coördinatensysteem in te stellen en te krijgen z
as.setPosition (...)
functie kan worden gebruikt om de positie van een geluid langs de coördinatensystemen in te stellen X
, Y
, en z
assen.audioPlayer.setX (geluid1, 100) audioPlayer.setZ (geluid1, 200) console.log (audioPlayer.getX (geluid1)) // 100 console.log (audioPlayer.getZ (sound1)) // 200 audioPlayer.setPosition (sound1, 300, 0, 400) console.log (audioPlayer.getX (geluid1)) // 300 console.log (audioPlayer.getZ (sound1)) // 400
Hoe verder een geluid uit het midden van het coördinatensysteem komt, hoe rustiger het geluid zal zijn. Op een afstand van 10000
(de standaard Web Audio) klinkt een geluid volledig stil.
We kunnen het globale (master) volume van de geluiden regelen met behulp van de setVolume (...)
en getVolume (...)
functies zichtbaar gemaakt door geluids speler
.
audioPlayer.setVolume (0.5) // 50% console.log (audioPlayer.getVolume ()) // 0.5
De setVolume (...)
De functie heeft ook een tweede parameter die kan worden gebruikt om het volume over een bepaalde periode te vervagen. Om bijvoorbeeld het volume over een periode van twee seconden op nul te zetten, kunnen we het volgende doen:
audioPlayer.setVolume (0.0, 2.0)
De tutorial demo maakt hier gebruik van om de geluiden soepel in te voeren.
Achter de schermen, de geluids speler
vertelt gewoon het m_gain
knooppunt om de versterkingswaarde lineair te veranderen telkens wanneer het volume moet worden gewijzigd.
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 (volume, currentTime + tijd)
geluids speler
dwingt een minimale fade-tijd van 0.01
seconden, om te zorgen dat steile volumeveranderingen geen hoorbare klikken of ploffen veroorzaken.
In deze zelfstudie hebben we een manier bekeken om Web Audio in een eenvoudige API te verwerken die zich richt op het afspelen van geluiden in een 3D-coördinaatruimte voor gebruik in (onder andere toepassingen) 3D-games.
Vanwege het modulaire karakter van Web Audio, kunnen programma's die gebruikmaken van Web Audio behoorlijk snel ingewikkeld worden, dus ik hoop dat deze tutorial nuttig voor u is geweest. Als je begrijpt hoe Web Audio werkt en hoe krachtig het is, weet ik zeker dat je er veel plezier mee zult hebben.
Vergeet niet dat de AudioPlayer en demonstratie bronbestanden beschikbaar zijn op GitHub en klaar om te downloaden. De broncode wordt redelijk goed becommentarieerd, dus het is de moeite waard de tijd te nemen om er snel naar te kijken.
Als u feedback of vragen heeft, kunt u hieronder een reactie plaatsen.