Signatur
Beschreibung
Das Ereignis complete wird auf einem OfflineAudioContext ausgelöst, sobald das Rendern nach startRendering() fertig ist. Das Ereignisobjekt ist ein OfflineAudioCompletionEvent. Seine Eigenschaft renderedBuffer enthält das Ergebnis als AudioBuffer.
Einen Listener meldest du mit addEventListener("complete", handler) an oder alternativ über die Eigenschaft oncomplete. Das Ereignis wird nicht weitergereicht (kein Bubbling) und lässt sich nicht abbrechen.
In modernem Code nutzt man meist das Promise, das startRendering() zurückgibt. Es wird mit demselben AudioBuffer erfüllt. Das Ereignis ist trotzdem nützlich, wenn mehrere unabhängige Programmteile auf das Ende des Renderns reagieren sollen. Es hilft auch bei älterem Code, der noch mit Rückruffunktionen arbeitet.
Typische Einsatzfälle sind das Exportieren von Audio (z. B. als WAV), das Anwenden von Effekten schneller als in Echtzeit, Wellenform-Vorschauen und die Analyse von Audiodateien ohne Wiedergabe.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $type Pflicht | string | Der Ereignisname "complete". |
|
| $handler Pflicht | (event: OfflineAudioCompletionEvent) => void | Rückruffunktion. Sie erhält ein OfflineAudioCompletionEvent, dessen Eigenschaft renderedBuffer den fertigen AudioBuffer enthält. |
|
| $options | boolean | AddEventListenerOptions | false | Optionale Listener-Optionen, z. B. { once: true } oder { signal }. |
Rückgabewert
addEventListener gibt nichts zurück. Das fertige Audio steht im Handler unter event.renderedBuffer (AudioBuffer).Beispiele
Rendern abschließen mit addEventListener
// 2 Sekunden Stereo bei 44,1 kHz offline rendern
const ctx = new OfflineAudioContext(2, 44100 * 2, 44100);
const osc = ctx.createOscillator();
osc.frequency.value = 440;
osc.connect(ctx.destination);
osc.start();
ctx.addEventListener("complete", (event) => {
const buffer = event.renderedBuffer;
console.log(`Fertig: ${buffer.duration} s, ${buffer.numberOfChannels} Kanäle`);
}, { once: true });
ctx.startRendering();
Variante mit der Eigenschaft oncomplete
const ctx = new OfflineAudioContext(1, 48000, 48000);
const osc = ctx.createOscillator();
osc.connect(ctx.destination);
osc.start();
ctx.oncomplete = ({ renderedBuffer }) => {
const samples = renderedBuffer.getChannelData(0);
const peak = samples.reduce((max, s) => Math.max(max, Math.abs(s)), 0);
console.log("Spitzenpegel:", peak.toFixed(2));
ctx.oncomplete = null; // Handler wieder entfernen
};
ctx.startRendering();
Datei mit Effekt offline bearbeiten und abspielen (Promise + Ereignis)
const processFile = async (url) => {
const res = await fetch(url);
const data = await res.arrayBuffer();
// Zum Dekodieren genügt ein kleiner temporärer Kontext
const tmp = new OfflineAudioContext(2, 1, 44100);
const source = await tmp.decodeAudioData(data);
const ctx = new OfflineAudioContext(
source.numberOfChannels, source.length, source.sampleRate
);
const node = ctx.createBufferSource();
node.buffer = source;
const gain = ctx.createGain();
gain.gain.value = 0.5; // Lautstärke halbieren
node.connect(gain).connect(ctx.destination);
node.start();
// Ereignis z. B. für eine Fortschrittsanzeige
const onDone = () => console.log("Rendern beendet");
ctx.addEventListener("complete", onDone);
const rendered = await ctx.startRendering(); // gleicher Buffer wie event.renderedBuffer
ctx.removeEventListener("complete", onDone);
const live = new AudioContext();
const player = live.createBufferSource();
player.buffer = rendered;
player.connect(live.destination);
player.start();
};
processFile("/audio/sample.mp3");
// Wichtig · Fallstricke
- Ereignis oder Promise:
startRendering()gibt ein Promise zurück, das mit demselbenAudioBuffererfüllt wird. Für neuen Code istawaitmeist übersichtlicher. Nutzt du beides, verarbeite das Ergebnis nicht versehentlich doppelt. - Nur einmal pro Kontext: Ein
OfflineAudioContextrendert nur einmal. Ein zweiter Aufruf vonstartRendering()weist das Promise mit einemInvalidStateErrorzurück. Danach kommt kein weiterescomplete. Für einen neuen Durchlauf brauchst du einen neuen Kontext. - Listener vorher anmelden: Melde den Handler an, bevor du
startRendering()aufrufst. Sonst kann das Ereignis bei sehr kurzen Puffern verpasst werden. - Speicher: Die Länge (
length) wird beim Erzeugen fest vorgegeben. Lange Puffer mit vielen Kanälen belegen viel Arbeitsspeicher (32-Bit-Float pro Sample und Kanal). - Kompatibilität: Das Ereignis und
oncompletefunktionieren in allen modernen Browsern. Sehr alte Safari-Versionen brauchtenwebkitOfflineAudioContextund kannten die Promise-Variante nicht. Dort waroncompleteder einzige Weg. - Kein Bubbling, nicht abbrechbar:
preventDefault()hat keine Wirkung.