Signatur
Beschreibung
OfflineAudioContext ist das Gegenstück zu AudioContext: Beide erben von BaseAudioContext und bieten dieselben Fabrikmethoden (createOscillator(), createGain(), createBiquadFilter(), decodeAudioData() …). Der Unterschied liegt in der Ausgabe: Ein OfflineAudioContext spielt nichts auf der Hardware ab, sondern berechnet das Ergebnis des Audiographen so schnell wie die CPU es zulässt und liefert es als AudioBuffer zurück.
Typische Einsatzgebiete sind:
- Effekte, Filter oder Mischungen auf eine Audiodatei anwenden und das Ergebnis exportieren (z. B. als WAV)
- Wellenform- oder Spektrumsdaten vorab berechnen (z. B. für Visualisierungen)
- Audioanalyse wie Tempo- oder Pegelerkennung ohne Echtzeitwiedergabe
- Automatisierte Tests von Audiographen mit deterministischem Ergebnis
Länge, Kanalanzahl und Abtastrate werden beim Erzeugen fest vorgegeben. Nach dem Aufbau des Graphen startet startRendering() die Berechnung und gibt ein Promise<AudioBuffer> zurück; zusätzlich wird das Ereignis complete (oncomplete) mit einem OfflineAudioCompletionEvent ausgelöst. Mit suspend(zeit) und resume() lässt sich das Rendern an bestimmten Zeitpunkten anhalten, um den Graphen zu verändern.
Wichtige Mitglieder: die schreibgeschützte Eigenschaft length (Länge in Sample-Frames), die Methoden startRendering(), suspend() und resume() sowie das Ereignis complete.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $numberOfChannels Pflicht | number | Anzahl der Kanäle des Ergebnis-Buffers (mindestens 1 bis 32 werden unterstützt). In der Objekt-Variante optional, Standard 1. |
|
| $length Pflicht | number | Länge des Ergebnisses in Sample-Frames, also Sekunden * sampleRate. Muss größer als 0 sein. |
|
| $sampleRate Pflicht | number | Abtastrate in Hz (Browser unterstützen mindestens 8000–96000, meist 3000–768000). | |
| $options | { numberOfChannels?: number, length: number, sampleRate: number } | Alternative Konstruktorform: ein einziges Objekt mit denselben Werten, z. B. new OfflineAudioContext({ length, sampleRate }). |
Rückgabewert
startRendering() liefert später ein Promise<AudioBuffer> mit dem gerenderten Audio.Beispiele
Zwei Sekunden Sinuston offline rendern
const sampleRate = 44100;
const ctx = new OfflineAudioContext(1, sampleRate * 2, sampleRate);
const osc = ctx.createOscillator();
osc.frequency.value = 440;
const gain = ctx.createGain();
// sanftes Ausblenden über die zwei Sekunden
gain.gain.setValueAtTime(1, 0);
gain.gain.linearRampToValueAtTime(0, 2);
osc.connect(gain).connect(ctx.destination);
osc.start(0);
const buffer = await ctx.startRendering();
console.log(buffer.duration, buffer.numberOfChannels, buffer.length);
Audiodatei filtern und das Ergebnis abspielen
const response = await fetch('/audio/sprache.mp3');
const arrayBuffer = await response.arrayBuffer();
// Zum Dekodieren genügt ein kurzer Offline-Kontext
const decoder = new OfflineAudioContext(1, 1, 44100);
const source = await decoder.decodeAudioData(arrayBuffer);
const offline = new OfflineAudioContext({
numberOfChannels: source.numberOfChannels,
length: source.length,
sampleRate: source.sampleRate,
});
const node = offline.createBufferSource();
node.buffer = source;
const lowpass = offline.createBiquadFilter();
lowpass.type = 'lowpass';
lowpass.frequency.value = 1000;
node.connect(lowpass).connect(offline.destination);
node.start();
const filtered = await offline.startRendering();
// Ergebnis in einem normalen AudioContext abspielen (nach Nutzerinteraktion)
const live = new AudioContext();
const player = live.createBufferSource();
player.buffer = filtered;
player.connect(live.destination);
player.start();
Rendern mit suspend() anhalten und Graphen ändern
const sr = 48000;
const ctx = new OfflineAudioContext(1, sr * 3, sr);
const osc = ctx.createOscillator();
osc.type = 'square';
osc.frequency.value = 220;
osc.connect(ctx.destination);
osc.start();
// Bei Sekunde 1 anhalten und die Frequenz umschalten
ctx.suspend(1).then(() => {
osc.frequency.value = 330;
console.log('Pausiert bei', ctx.currentTime.toFixed(2), 's');
ctx.resume();
});
ctx.oncomplete = (event) => {
console.log('Fertig, Länge:', event.renderedBuffer.length);
};
await ctx.startRendering();
// Wichtig · Fallstricke
- Nur einmal renderbar: Ein weiterer Aufruf von
startRendering()auf demselben Kontext lehnt das Promise mit einemInvalidStateErrorab. Für jeden neuen Durchlauf einen neuenOfflineAudioContexterzeugen. - Speicherbedarf: Der Ergebnis-Buffer belegt ca.
length × numberOfChannels × 4Byte (32-Bit-Float). Zehn Minuten Stereo bei 48 kHz sind schon rund 230 MB – lange Dateien besser in Abschnitten verarbeiten. - Feste Länge: Alles, was nach
lengthFrames klingt (z. B. Hall-Ausklang), wird abgeschnitten. Etwas Reserve einplanen. - suspend(): Die Zeit wird auf eine Render-Quantum-Grenze (128 Frames) gerundet;
suspend()sollte vorstartRendering()bzw. während einer Pause aufgerufen werden. Zeitpunkte außerhalb der Länge oder doppelt belegte Zeitpunkte führen zu Fehlern. - Keine Autoplay-Sperre: Da nichts hörbar ausgegeben wird, braucht ein Offline-Kontext keine Nutzergeste – das spätere Abspielen im
AudioContextaber schon. - Kompatibilität: In allen aktuellen Browsern verfügbar. Sehr alte Safari-Versionen kannten nur
webkitOfflineAudioContextmit Callback-basiertemoncompletestatt Promise; die Objekt-Konstruktorform ist dort ebenfalls nicht vorhanden. Nicht in Node.js enthalten (nur über Drittpakete wienode-web-audio-api).AudioWorkletwird im Offline-Kontext unterstützt,MediaElementAudioSourceNodeundMediaStream-Knoten dagegen nicht sinnvoll nutzbar.