Herzlich willkommen zum SELF-Treffen 2026
vom 24.04. – 26.04.2026
in Halle (Saale)
Web Audio
Inhaltsverzeichnis
Web Audio API
Mit der Web Audio API [1][2][3]können per JavaScript Töne im Browser generiert (synthetisiert) werden, damit sind keine externen Audio-Dateien erforderlich.
Sie erlaubt es, diese generierten und auch externe Audioquellen präzise zu steuern, zu manipulieren und mit Effekten zu versehen. Dadurch lassen sich komplexe Signalwege („Audiographen“) aufbauen, ähnlich wie in einem Tonstudio.
Für Spiele-Sound, Musik-Apps, Synthesizer, Visualisierungen, barrierefreie Benachrichtigungen oder überall dort, wo einfaches <audio> nicht ausreicht – ganz ohne zusätzliche Plugins.
Stärken:
- Echtzeit-Verarbeitung
- Sample-genaues Timing
- Modularer Aufbau mit Audio-Nodes
- Effekte, Filter und Dynamik
- Räumliches Audio
- Komplexe Signalketten
- Signal-Analyse
AudioContext
Alles in der Web Audio API dreht sich um den AudioContext, das Herzstück. Er ist die zentrale Instanz, die den Audio-Render-Thread verwaltet, die Samplerate definiert und als Fabrik für die Erzeugung von AudioNodes und die Steuerung der Wiedergabe dient.
Audiograph
Die Web Audio API basiert auf dem Konzept eines gerichteten Graphen, dem Audiograph. Darunter versteht man ein Netz aus sogenannten AudioNodes, von denen jeder eine bestimmte Aufgabe im Audiograph erfüllt. Ein Audiograph enthält eine oder mehrere Audioquellen und leitet deren Audiodaten über Effekt- und Analyse-Nodes weiter zu einem Audioausgang.
Die grundsätzliche Herangehensweise per JavaScript ähnelt der von HTML5 Canvas API .
AudioNodes
Jeder AudioNode hat eine connect()-Methode, die es ermöglicht, einen seiner Ausgänge mit einem der Eingänge eines anderen AudioNode zu verbinden, ganz so, als hättest du ein Regal voller Geräte und würdest Kabel von einem zum anderen ziehen. Und wie in der Wirklichkeit gibt es auch hier Geräte mit unterschiedlich vielen Kanälen: Das kann nur einer sein (Mono), zwei (Stereo), vier (Quadro) bis hin zu 7.1 8-Kanal Surround Sound. Wenn du versuchst, ein Mono-Gerät in einen 7.1-Verstärker zu stöpseln, kommt kein guter Klang heraus. Im Web Audio API ist es genauso, deshalb bietet es dir AudioNodes, um Kanäle zu mixen oder zu splitten.
const oscillator = ctx.createOscillator();
const gainNode = ctx.createGain();
// Verbindung: Oscillator → Gain → Lautsprecher
oscillator.connect(gainNode);
gainNode.connect(ctx.destination);
oscillator.start();
Die API bietet eine Vielzahl spezialisierter Knoten, einige der wichtigsten sind:
-
OscillatorNode: Erzeugt Töne direkt im Browser -
AudioBufferSourceNode: Spielt geladene Audiodaten ab -
GainNode: Steuert die Lautstärke -
BiquadFilterNode: Wendet Filter wie Lowpass oder Highpass an -
AnalyserNode: Liefert Daten für Visualisierungen -
DelayNode: Verzögert das Signal (Echo) -
ConvolverNode: Faltungshall (Raumklang) -
DynamicsCompressor: Komprimiert die Dynamik -
MediaStreamSource: Mikrofon-Eingabe direkt in den Audio-Graph -
AudioWorklet: Eigene DSP-Algorithmen direkt in JavaScript erstellen -
destination: Ausgabe an Lautsprecher oder Kopfhörer
Eingangsquellen
Am Anfang eines Signalwegs stehen die Eingangsquellen (Source Nodes). Sie liefern die Audiodaten, die anschließend durch verschiedene Verarbeitungsschritte geleitet werden können. Die Web Audio API bietet dafür unterschiedliche Typen von Quellen: von synthetisch erzeugten Tönen über geladene Audiodateien bis hin zu Medienströmen aus <audio>-/<video>-Elementen oder Mikrofoneingaben.
Beispiele
Einen Ton erzeugen
Standardwerte, müssen nicht explizit definiert werden:
-
state= "suspended" (pausiert, produziert keinen Ton) -
destination= Lautsprecher -
gain= Standardlautstärke -
osc.type= "sine" (Sinuswelle) -
osc.frequency.value= 440 (440 Hertz, Standard-Kammerton A) -
sampleRate= geräteabhängig, meist 44100 oder 48000 Hz -
detune= 0 Cent (Stimmung) - ohne
osc.stopin diesem Beispiel wäre der Ton endlos
const ctx = new AudioContext();
const osc = ctx.createOscillator();
osc.connect(ctx.destination);
osc.start();
osc.stop(ctx.currentTime + 1);
Einen bestimmten Ton erzeugen
Neu gegenüber obigem Beispiel:
-
osc.type = "sawtooth"– Sägezahnwelle (obertonreich, scharf) -
osc.frequency.value = 660– 660 Hz statt Standard 440 Hz -
GainNode– regelt die Lautstärke über die Zeit -
gain.gain.exponentialRampToValueAtTime– sanfter Übergang (kein harter Sprung) - Schneller Attack (Anschlag): 0.05 Sekunden
- Langsamer Release (Ausklang): 3 Sekunden
const gain = ctx.createGain();
osc.type = "sawtooth";
osc.frequency.value = 660;
gain.gain.setValueAtTime(0.001, ctx.currentTime);
gain.gain.exponentialRampToValueAtTime(0.5, ctx.currentTime + 0.05);
gain.gain.exponentialRampToValueAtTime(0.001, ctx.currentTime + 3);
osc.connect(gain);
gain.connect(ctx.destination);
Tongenerator
Neu gegenüber obigem Beispiel:
- Ton läuft dauerhaft bis Stop (kein
osc.stopmit Zeitangabe) -
osc.frequency.valueundgain.gain.valuekönnen live verändert werden -
osc.typekann während der Wiedergabe gewechselt werden
osc.type = document.getElementById('waveform').value;
osc.frequency.value = Number(document.getElementById('freqSlider').value);
gain.gain.value = document.getElementById('volSlider').value / 100;
Mini-Piano / Mehrstimmigkeit
Mini-Klaviatur, bedienbar per Maus, Touch und Tastatur. (Stand Anfang 2026: Der Browser Safari setzt den Fokus nicht automatisch auf die Klaviatur, deshalb muss zum Spielen per Computer-Tastatur zuerst ins Fenster geklickt werden)
- Einziger
AudioContextwird einmal erstellt und wiederverwendet (mehrere Kontexte könnten das Browser-Limit erreichen). - Alle Frequenzen werden mathematisch aus einem Referenzton berechnet.
- Bei Oktavwechsel wird
buildPiano()neu aufgebaut statt Frequenzen nachträglich zu ändern.
// Frequenzberechnung per Formel statt Tabelle
function midiToFreq(semitone) {
return 440 * 2 ** ((semitone - 9) / 12);
}
// Obertöne mit mehreren Oszillatoren pro Ton
const partials = [
{ mult: 1, gain: 1.00 },
{ mult: 2, gain: 0.50 },
{ mult: 3, gain: 0.25 },
{ mult: 4, gain: 0.12 },
{ mult: 5, gain: 0.06 },
];
partials.forEach(p => {
const osc = audioCtx.createOscillator();
osc.frequency.value = freq * p.mult;
// ...
});
Klangfarbe
Mehrere Tonerzeuger gleichzeitig: In obigem Beispiel laufen für einen Klang ähnlich einem Elektropiano 5 Oszillatoren parallel – einer pro Oberton mit unterschiedlichen Lautstärken. Mit diesem Prinzip eröffnen sich viele Möglichkeiten, um verschiedene Instrumente nachzuahmen und der Kreativität bei der Gestaltung neuer Klänge sind kaum Genzen gesetzt.
Stereo / Raumklang
Mit dem StereoPannerNode Knoten wird die Balance des Sounds zwischen linkem und rechtem Lautsprecher verändert, wenn der Benutzer Stereo-Fähigkeiten hat, wird im letzten Beispiel eingesetzt.
Mittels PannerNode ist sogar räumliches Audio mit 3D-Positionierung von Klängen im Raum und Veränderungen abhängig von Kopfbewegungen machbar.
Darauf wird hier nicht weiter eingegangen, z.B. bei MDN findest du Informationen dazu:
- Definition bei MDN
- Anleitung zur Verwendung bei MDN
- Demo Boombox
- Grundlagen der Audio-Räumlichkeit im Web
Visualisierung
Der AnalyserNode hört in die Signalkette hinein, ohne das Audio zu verändern. Er liefert zwei Ansichten: die Wellenform (Zeitbereich) und das Frequenzspektrum (Frequenzbereich).
// AnalyserNode einbinden
analyser = ctx.createAnalyser();
analyser.fftSize = 2048;
// Schleife mit requestAnimationFrame
function draw() {
raf = requestAnimationFrame(draw);
// ... Daten lesen und zeichnen
}
// Wellenform lesen und zeichnen
const timeBuf = new Uint8Array(analyser.fftSize);
analyser.getByteTimeDomainData(timeBuf);
// buf enthält 2048 Werte von 0–255 (128 = Nulllinie)
timeBuf.forEach((v, i) => {
const x = plotX1 + i * (plotW1 / timeBuf.length);
const y = (v / 128) * (H1 / 2);
i === 0 ? w1.moveTo(x, y) : w1.lineTo(x, y);
});
// Frequenzspektrum lesen und zeichnen
const freqBuf = new Uint8Array(analyser.frequencyBinCount);
analyser.getByteFrequencyData(freqBuf);
// buf enthält 1024 Werte von 0–255 (0 = still, 255 = laut)
freqBuf.forEach((v, i) => {
const barHeight = (v / 255) * plotH2;
w2.fillRect(plotX2 + i * barWidth, plotH2 - barHeight, barWidth, barHeight);
});
<!-- Zeichnen per Canvas -->
<p>Wellenform (Zeitbereich):</p>
<canvas id="canvasWave"></canvas>
<p>Frequenzspektrum:</p>
<canvas id="canvasFreq"></canvas>
Audio-Datei abspielen
Ein typischer Anwendungsfall der Web Audio API ist das Laden einer Audiodatei und deren Dekodierung in einen AudioBuffer. Dafür verwendet man die moderne Kombination aus fetch und async/await, damit der Ladevorgang asynchron abläuft und die Ausführung des restlichen Programms nicht blockiert.
Hier ein Beispiel-Code, wie die API eingesetzt werden könnte.
let audioContext = null;
let audioBuffer = null;
// AudioContext nur einmalig erzeugen – Browser erlauben ihn erst
// nach einer Nutzerinteraktion (z. B. einem Klick)
function getAudioContext() {
if (!audioContext) {
audioContext = new AudioContext();
}
return audioContext;
}
async function loadAudio() {
if (audioBuffer) return audioBuffer; // bereits geladen, nichts tun
const audioCtx = getAudioContext();
const response = await fetch("Hi.mp3");
const arrayBuffer = await response.arrayBuffer();
audioBuffer = await audioCtx.decodeAudioData(arrayBuffer);
return audioBuffer;
}
async function playSirene() {
try {
const audioCtx = getAudioContext();
if (!audioBuffer) await loadAudio();
if (audioCtx.state === "suspended") await audioCtx.resume();
// Für jede Wiedergabe muss eine neue BufferSourceNode erzeugt werden –
// eine Node kann nur einmal abgespielt werden.
const source = audioCtx.createBufferSource();
source.buffer = audioBuffer;
source.connect(audioCtx.destination);
source.start();
} catch (err) {
console.error("Fehler beim Abspielen:", err);
}
}
document.getElementById("playBtn").addEventListener("click", playSirene);
Das Beispiel zeigt die click-Behandlung für einen Button, der beim Drücken die Datei Hi.mp3 lädt und abspielt. Beim ersten Klick wird die Datei geladen und dekodiert; bei weiteren Klicks wird der bereits im Speicher gehaltene audioBuffer direkt wiederverwendet. Zu beachten ist, dass eine BufferSourceNode nur einmal verwendet werden kann – für jede neue Wiedergabe muss über createBufferSource() eine neue Node erstellt werden. Der audioBuffer selbst bleibt dabei erhalten und wird nicht neu geladen.
Fehlerbehandlung: Sowohl fetch als auch decodeAudioData können Fehler werfen, etwa wenn die Datei nicht erreichbar ist oder das Format nicht unterstützt wird. Der try/catch-Block stellt sicher, dass solche Fehler nicht stillschweigend verschwinden.
Hinweis zum lokalen Testen: Browser blockieren fetch über den lokalen Pfad file://. Das ist kein Browser-Bug, sondern eine Sicherheitsmassnahme (CORS-Policy für lokale Dateien).
Mini-Mischpult
In diesem Beispiel wird der Einsatz von Nodes für Balance, Hall und Echo gezeigt.
Für den Hall wird hier eine einfache Delay-Feedback-Schleife verwendet: Ein ConvolverNode könnte wesentlich natürlicheren Halleffekt erzeugen, dazu benötigt man zusätzlich einen IR-Buffer (Impulse Response = Impulsantwort), deshalb wird der Einfachheit halber darauf verzichtet.
function buildGraph(audioCtx) {
gainNode = audioCtx.createGain();
pannerNode = audioCtx.createStereoPanner();
reverbDelay = audioCtx.createDelay(5.0);
reverbFeedback = audioCtx.createGain();
echoDelay = audioCtx.createDelay(2.0);
echoFeedback = audioCtx.createGain();
// Lautstärke → Balance → Reverb-Loop → Echo-Loop → Ausgang
gainNode.connect(pannerNode);
pannerNode.connect(reverbDelay);
reverbDelay.connect(reverbFeedback);
reverbFeedback.connect(reverbDelay); // Feedback-Schleife für einfachen Hall
reverbDelay.connect(echoDelay);
echoDelay.connect(echoFeedback);
echoFeedback.connect(echoDelay); // Feedback-Schleife für Echo
echoDelay.connect(audioCtx.destination);
Siehe auch
- Arcade-Spiele

Jump 'n Run- Töne per Web Audio API
- Kollisionserkennung
Weblinks
- ↑ Web Audio API 1.1 Editor’s Draft (W3C)
- ↑ Web Audio API (MDN)
- ↑ Web Audio API (de.wikipedia.org)
Beispiele und Frameworks