Start · Sprachen · JavaScript · Referenz · OfflineAudioContext.startRendering()

OfflineAudioContext.startRendering()

Methode

Rendert den Audio-Graphen eines <code>OfflineAudioContext</code> schneller als in Echtzeit und liefert das Ergebnis als <code>AudioBuffer</code> über ein Promise.

seit JavaScript Baseline: alle modernen Browser (Promise-Variante Kategorie: webapi

Signatur

OfflineAudioContext.prototype.startRendering()

Beschreibung

startRendering() startet die Offline-Verarbeitung eines OfflineAudioContext. Anders als beim AudioContext wird der Ton dabei nicht an die Lautsprecher ausgegeben, sondern so schnell berechnet, wie die CPU es erlaubt. Alle Knoten, Verbindungen und geplanten Parameteränderungen (z. B. setValueAtTime(), linearRampToValueAtTime()) werden berücksichtigt.

Die Methode gibt ein Promise zurück, das mit einem AudioBuffer erfüllt wird. Dessen Länge, Kanalzahl und Abtastrate entsprechen den Werten, die dem OfflineAudioContext-Konstruktor übergeben wurden. Zusätzlich löst der Kontext am Ende das Ereignis complete aus (oncomplete), dessen OfflineAudioCompletionEvent.renderedBuffer denselben Puffer enthält.

Typische Einsatzgebiete sind das Exportieren von Effektketten als Datei (z. B. WAV), das Vorberechnen von Klängen, Wellenform-Analysen, Normalisierung, Resampling oder automatisierte Audio-Tests, bei denen deterministische Ergebnisse benötigt werden.

Wichtig: Der Graph muss vor dem Aufruf vollständig aufgebaut und alle Quellen per start() eingeplant sein. Ein Kontext kann nur einmal gerendert werden.

Rückgabewert

Typ
Promise<AudioBuffer>
Beschreibung
Ein Promise, das mit dem gerenderten AudioBuffer erfüllt wird. Es wird mit einer InvalidStateError-DOMException abgelehnt, wenn bereits gerendert wurde oder der Kontext geschlossen ist.

Beispiele

Einen Sinuston offline erzeugen

const sampleRate = 44100;
const ctx = new OfflineAudioContext({ numberOfChannels: 1, length: sampleRate * 2, sampleRate });

const osc = new OscillatorNode(ctx, { type: 'sine', frequency: 440 });
const gain = new GainNode(ctx, { gain: 0 });

// Fade-in über 0,5 s, danach Fade-out
gain.gain.linearRampToValueAtTime(0.8, 0.5);
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);
2 1 88200

Audiodatei mit Filter bearbeiten und im normalen Kontext abspielen

const response = await fetch('/audio/stimme.mp3');
const arrayBuffer = await response.arrayBuffer();

// Zum Dekodieren genügt ein temporärer Offline-Kontext
const decoder = new OfflineAudioContext(2, 1, 44100);
const source = await decoder.decodeAudioData(arrayBuffer);

const offline = new OfflineAudioContext(
  source.numberOfChannels,
  source.length,
  source.sampleRate
);

const player = new AudioBufferSourceNode(offline, { buffer: source });
const lowpass = new BiquadFilterNode(offline, { type: 'lowpass', frequency: 1200 });
player.connect(lowpass).connect(offline.destination);
player.start();

const rendered = await offline.startRendering();

// Ergebnis in Echtzeit wiedergeben
const live = new AudioContext();
const out = new AudioBufferSourceNode(live, { buffer: rendered });
out.connect(live.destination);
out.start();

Spitzenpegel ermitteln und complete-Ereignis nutzen

const ctx = new OfflineAudioContext(1, 44100, 44100);
const osc = new OscillatorNode(ctx, { type: 'square', frequency: 220 });
const gain = new GainNode(ctx, { gain: 0.5 });
osc.connect(gain).connect(ctx.destination);
osc.start();

ctx.addEventListener('complete', (event) => {
  console.log('Fertig, Samples:', event.renderedBuffer.length);
});

try {
  const buffer = await ctx.startRendering();
  const data = buffer.getChannelData(0);
  const peak = data.reduce((max, v) => Math.max(max, Math.abs(v)), 0);
  console.log('Spitzenpegel:', peak.toFixed(2));
} catch (err) {
  console.error('Rendern fehlgeschlagen:', err.name);
}
Fertig, Samples: 44100 Spitzenpegel: 0.50

// Wichtig · Fallstricke

  • Nur einmal aufrufbar: Ein zweiter Aufruf führt zu einem abgelehnten Promise mit InvalidStateError. Für einen neuen Durchlauf einen neuen OfflineAudioContext erzeugen.
  • Feste Länge: Die Ausgabelänge wird im Konstruktor festgelegt (length in Samples, nicht Sekunden). Audio nach dem Ende wird abgeschnitten, Stille am Ende wird nicht entfernt.
  • Veraltete Callback-Variante: Ältere Implementierungen gaben void zurück und lieferten das Ergebnis nur über oncomplete. Heute unterstützen alle modernen Browser das Promise; in sehr alten WebKit-Versionen hieß der Konstruktor webkitOfflineAudioContext.
  • Speicherbedarf: Lange Renderings mit vielen Kanälen erzeugen große Float32Arrays (4 Byte pro Sample und Kanal) – eine Stunde Stereo bei 48 kHz entspricht etwa 1,4 GB.
  • Blockierung: Das Rendern läuft zwar asynchron im Audio-Thread, ScriptProcessorNode und AudioWorklet-Code können es aber stark verlangsamen. Mit suspend(zeit) lässt sich das Rendern an bestimmten Stellen anhalten, um den Graphen zu ändern.