Signatur
Beschreibung
BaseAudioContext ist die gemeinsame Grundlage aller Audio-Kontexte der Web Audio API. Das Interface lässt sich nicht direkt instanziieren. Man arbeitet immer mit einer der beiden Unterklassen: AudioContext für die Wiedergabe in Echtzeit über die Audioausgabe des Geräts oder OfflineAudioContext, um Audio schneller als in Echtzeit in einen AudioBuffer zu rendern, z. B. für Export oder Analyse.
Das Interface bündelt alles, was beide Kontextarten brauchen:
- Eigenschaften:
currentTime(Audio-Uhr in Sekunden, auf Abtastwerte genau),destination(derAudioDestinationNodeals Endpunkt des Graphen),listener(derAudioListenerfür räumliches Audio),sampleRate,state("suspended","running"oder"closed") undaudioWorklet. - Fabrikmethoden:
createOscillator(),createGain(),createBiquadFilter(),createBufferSource(),createAnalyser(),createDelay(),createDynamicsCompressor(),createConvolver(),createPanner(),createStereoPanner(),createWaveShaper(),createChannelSplitter()/createChannelMerger(),createConstantSource(),createIIRFilter(),createPeriodicWave(),createBuffer(). - Dekodierung:
decodeAudioData(arrayBuffer)wandelt komprimierte Audiodaten (MP3, AAC, Ogg, WAV …) in einenAudioBufferum und gibt ein Promise zurück. - Ereignis:
statechange(bzw.onstatechange) wird ausgelöst, sobald sichstateändert.
Wenn du Hilfsfunktionen schreibst, die mit beiden Kontextarten funktionieren sollen, z. B. Effektketten oder Synthesizer-Stimmen, typisiere den Parameter als BaseAudioContext. Dann läuft derselbe Code live im Browser und auch beim Offline-Rendern.
Rückgabewert
new AudioContext() oder new OfflineAudioContext().Beispiele
Kontext erzeugen und einen Ton abspielen
// AudioContext erbt von BaseAudioContext
const ctx = new AudioContext();
console.log(ctx instanceof BaseAudioContext);
document.querySelector('#play').addEventListener('click', async () => {
if (ctx.state === 'suspended') await ctx.resume();
const osc = ctx.createOscillator();
const gain = ctx.createGain();
osc.frequency.value = 440;
gain.gain.setValueAtTime(0.2, ctx.currentTime);
gain.gain.exponentialRampToValueAtTime(0.001, ctx.currentTime + 1);
osc.connect(gain).connect(ctx.destination);
osc.start();
osc.stop(ctx.currentTime + 1);
});
Wiederverwendbare Effektkette für beide Kontextarten
// Funktioniert mit AudioContext UND OfflineAudioContext
const createLowpassChain = (/** @type {BaseAudioContext} */ ctx, cutoff = 800) => {
const filter = ctx.createBiquadFilter();
filter.type = 'lowpass';
filter.frequency.value = cutoff;
const out = ctx.createGain();
out.gain.value = 0.8;
filter.connect(out).connect(ctx.destination);
return filter; // Eingang der Kette
};
// Offline 2 Sekunden Stereo mit 44,1 kHz rendern
const offline = new OfflineAudioContext(2, 44100 * 2, 44100);
const input = createLowpassChain(offline, 1200);
const osc = offline.createOscillator();
osc.type = 'sawtooth';
osc.connect(input);
osc.start();
const rendered = await offline.startRendering();
console.log(rendered.duration, rendered.numberOfChannels);
Audiodatei laden, dekodieren und abspielen
const ctx = new AudioContext();
const loadSound = async (url) => {
const res = await fetch(url);
const data = await res.arrayBuffer();
return ctx.decodeAudioData(data); // Promise<AudioBuffer>
};
const buffer = await loadSound('/sounds/klick.mp3');
console.log(`Dauer: ${buffer.duration.toFixed(2)} s, Rate: ${buffer.sampleRate} Hz`);
const source = ctx.createBufferSource();
source.buffer = buffer;
source.connect(ctx.destination);
source.start();
Zustandsänderungen beobachten
const ctx = new AudioContext();
const onState = () => console.log('Zustand:', ctx.state);
ctx.addEventListener('statechange', onState);
await ctx.resume(); // nach einer Nutzeraktion
await ctx.suspend();
ctx.removeEventListener('statechange', onState);
// Alternative über die on-Property:
ctx.onstatechange = () => console.log('neu:', ctx.state);
await ctx.close();
// Wichtig · Fallstricke
- Nicht instanziierbar:
new BaseAudioContext()wirft einenTypeError. Verwende stattdessenAudioContextoderOfflineAudioContext. - Autoplay-Richtlinien: Browser starten einen
AudioContextoft im Zustand"suspended". Ruferesume()erst nach einer Nutzeraktion auf, etwa einem Klick.resume(),suspend()undclose()gehören übrigens zuAudioContext, nicht zuBaseAudioContext. BeimOfflineAudioContextgibt es zusätzlichstartRendering(). - Knoten sind an ihren Kontext gebunden: Knoten aus verschiedenen Kontexten lassen sich nicht miteinander verbinden. Ein Versuch löst einen
InvalidAccessErroraus. - Ressourcen: Jeder
AudioContextbelegt System-Audioressourcen, und manche Browser begrenzen die Anzahl. Verwende einen Kontext pro Anwendung und gib ihn mitclose()frei. decodeAudioData: Die Methode übernimmt den übergebenenArrayBuffer(er wird „detached“) und ist danach nicht mehr nutzbar. Die veraltete Callback-Variante sollte man nicht mehr verwenden. Beim Laden von fremden Ursprüngen gelten die CORS-Regeln.- Zeitplanung: Plane Ereignisse immer relativ zu
currentTime, nicht mitsetTimeout. Nur so bleibt das Timing auf Abtastwerte genau. - Kompatibilität: Das Interface ist in allen modernen Browsern verfügbar. In älteren Safari-Versionen gab es nur
webkitAudioContext, ohne eigenständigesBaseAudioContext.audioWorkletsetzt einen sicheren Kontext (HTTPS) voraus.