Signatur
Beschreibung
Die schreibgeschützte Eigenschaft listener einer BaseAudioContext-Instanz (also eines AudioContext oder OfflineAudioContext) liefert ein AudioListener-Objekt. Es steht für die Person, die in der virtuellen Szene zuhört: Man kann sich den Listener als ihren Kopf mit zwei Ohren vorstellen.
Jeder Kontext hat genau einen Listener. Alle PannerNode-Knoten dieses Kontexts berechnen ihre Räumlichkeit relativ zu ihm, also Lautstärke nach Entfernung, Links-Rechts-Verteilung und Richtungswirkung. Der Listener hat eine Position (positionX/Y/Z) und eine Ausrichtung. Die Ausrichtung besteht aus einem Vektor für die Blickrichtung (forwardX/Y/Z) und einem Vektor für „oben“ (upX/Y/Z).
Diese Werte sind AudioParam-Objekte. Du kannst sie also direkt über .value setzen oder mit Methoden wie setValueAtTime() und linearRampToValueAtTime() sample-genau und ohne Knackser verändern. Das eignet sich für Spiele, VR/WebXR, Audio-Visualisierungen oder interaktive Klanginstallationen, bei denen sich der Hörer durch den Raum bewegt.
Das Koordinatensystem ist rechtshändig. Standardmäßig steht der Listener im Ursprung (0, 0, 0), schaut in Richtung -Z (forward = (0, 0, -1)), und „oben“ ist +Y (up = (0, 1, 0)).
Rückgabewert
AudioListener-Objekt des Kontexts. Bei jedem Zugriff wird dasselbe Objekt zurückgegeben. Die Eigenschaft selbst kann man nicht neu zuweisen, die enthaltenen AudioParam-Werte aber schon.Beispiele
Listener abrufen und Standardwerte auslesen
const ctx = new AudioContext();
const { listener } = ctx;
console.log(listener.positionX.value, listener.positionY.value, listener.positionZ.value);
console.log(listener.forwardZ.value, listener.upY.value);
console.log(listener === ctx.listener);
Hörer positionieren und ausrichten (mit Fallback für ältere Browser)
const ctx = new AudioContext();
const listener = ctx.listener;
const placeListener = (x, y, z) => {
if (listener.positionX) {
listener.positionX.value = x;
listener.positionY.value = y;
listener.positionZ.value = z;
listener.forwardX.value = 0;
listener.forwardY.value = 0;
listener.forwardZ.value = -1;
listener.upX.value = 0;
listener.upY.value = 1;
listener.upZ.value = 0;
} else {
// Veraltete API für ältere Browser
listener.setPosition(x, y, z);
listener.setOrientation(0, 0, -1, 0, 1, 0);
}
};
placeListener(0, 1.7, 5); // Augenhöhe, 5 m vor dem Ursprung
console.log('Listener platziert');
Hörer an einer Schallquelle vorbeibewegen
const ctx = new AudioContext();
const osc = new OscillatorNode(ctx, { frequency: 440 });
const panner = new PannerNode(ctx, {
panningModel: 'HRTF',
distanceModel: 'inverse',
positionX: 0,
positionY: 0,
positionZ: -2
});
osc.connect(panner).connect(ctx.destination);
document.querySelector('#play').addEventListener('click', async () => {
await ctx.resume(); // Autoplay-Richtlinie: erst nach Nutzerinteraktion
const now = ctx.currentTime;
const { positionX } = ctx.listener;
// Der Hörer läuft in 4 Sekunden von links nach rechts
positionX.setValueAtTime(-10, now);
positionX.linearRampToValueAtTime(10, now + 4);
osc.start(now);
osc.stop(now + 4);
});
// Wichtig · Fallstricke
- Einer pro Kontext: Es gibt keinen Konstruktor für
AudioListener. Wer mehrere Hörer braucht, etwa für Splitscreen, muss mehrereAudioContext-Instanzen anlegen. - Veraltete Methoden:
setPosition()undsetOrientation()gelten als veraltet, bleiben für ältere Browser aber als Rückfallebene nützlich. Firefox unterstützt dieAudioParam-Eigenschaften (positionX,forwardXusw.) erst ab Version 138. Prüfe deshalb vorher, ob sie vorhanden sind, zum Beispiel mitif (listener.positionX). - Wirkt nur auf
PannerNode: EinStereoPannerNodeoder direkt verbundene Quellen berücksichtigen den Listener nicht. - Ausrichtungsvektoren: Der Vorwärts- und der Oben-Vektor dürfen nicht parallel sein, sonst ist die Ausrichtung nicht definiert. Sie müssen nicht normiert sein, sollten aber möglichst senkrecht zueinander stehen.
- Performance: Wenn du
.valuein jedem Frame setzt, zum Beispiel inrequestAnimationFrame, kann es knacken. Für flüssige Bewegungen sindsetTargetAtTime()oder Rampen besser. - Autoplay: Ein
AudioContextstartet oft im Zustand"suspended". Ruferesume()nach einer Nutzerinteraktion auf.