Signatur
Beschreibung
Die Methode createConvolver() eines AudioContext oder OfflineAudioContext liefert einen neuen ConvolverNode. Dieser Knoten führt eine lineare Faltung (Convolution) zwischen dem Eingangssignal und einer Impulsantwort (Impulse Response, IR) durch. Damit kann man die akustischen Eigenschaften eines echten Raums wie einer Kirche, eines Konzertsaals oder eines Treppenhauses auf beliebiges Audio übertragen.
Die Impulsantwort ist ein AudioBuffer. Man weist sie der Eigenschaft convolver.buffer zu. Meist lädt man dafür eine WAV-Datei per fetch() und dekodiert sie mit decodeAudioData(). Man kann die IR aber auch synthetisch aus abklingendem Rauschen erzeugen. Solange kein Puffer gesetzt ist, gibt der Knoten Stille aus.
In der Praxis mischt man das trockene Originalsignal (dry) mit dem verhallten Signal (wet) über zwei GainNodes. Mit der Eigenschaft normalize (Standard: true) wird die Lautstärke der IR automatisch angeglichen. Das verhindert, dass stark unterschiedliche Impulsantworten zu großen Pegelsprüngen führen.
Als moderne Alternative gibt es den Konstruktor new ConvolverNode(context, { buffer, disableNormalization }). Mit ihm lassen sich die Optionen direkt beim Erzeugen setzen.
Rückgabewert
ConvolverNode ohne gesetzten buffer und mit normalize = true.Beispiele
Hall mit geladener Impulsantwort
const ctx = new AudioContext();
const loadImpulse = async (url) => {
const res = await fetch(url);
const data = await res.arrayBuffer();
return ctx.decodeAudioData(data);
};
const setupReverb = async () => {
const convolver = ctx.createConvolver();
convolver.buffer = await loadImpulse('/audio/ir/concert-hall.wav');
const audioEl = document.querySelector('audio');
const source = ctx.createMediaElementSource(audioEl);
source.connect(convolver);
convolver.connect(ctx.destination);
console.log('Hall aktiv, IR-Länge:', convolver.buffer.duration.toFixed(2), 's');
};
// Wegen der Autoplay-Richtlinie erst nach einer Nutzeraktion starten
document.querySelector('#start').addEventListener('click', async () => {
await ctx.resume();
await setupReverb();
});
Synthetische Impulsantwort (ohne Datei)
const ctx = new AudioContext();
// Abklingendes Stereo-Rauschen als künstlicher Raum
const createImpulse = (seconds = 2, decay = 3) => {
const length = ctx.sampleRate * seconds;
const impulse = ctx.createBuffer(2, length, ctx.sampleRate);
for (let ch = 0; ch < 2; ch++) {
const data = impulse.getChannelData(ch);
for (let i = 0; i < length; i++) {
data[i] = (Math.random() * 2 - 1) * (1 - i / length) ** decay;
}
}
return impulse;
};
const convolver = ctx.createConvolver();
convolver.buffer = createImpulse(3, 4);
console.log(convolver.normalize, convolver.buffer.numberOfChannels);
Dry/Wet-Mischung mit regelbarem Hallanteil
const ctx = new AudioContext();
const osc = ctx.createOscillator();
const dry = ctx.createGain();
const wet = ctx.createGain();
const convolver = ctx.createConvolver();
// Kurze Impulsantwort aus Rauschen
const len = ctx.sampleRate * 1.5;
const ir = ctx.createBuffer(2, len, ctx.sampleRate);
for (let c = 0; c < 2; c++) {
const d = ir.getChannelData(c);
for (let i = 0; i < len; i++) d[i] = (Math.random() * 2 - 1) * Math.exp(-i / (len / 5));
}
convolver.buffer = ir;
const setMix = (amount) => {
// amount: 0 = trocken, 1 = nur Hall
dry.gain.value = 1 - amount;
wet.gain.value = amount;
};
setMix(0.35);
osc.connect(dry).connect(ctx.destination);
osc.connect(convolver).connect(wet).connect(ctx.destination);
osc.start();
osc.stop(ctx.currentTime + 0.3); // kurzer Ton, der Hall klingt nach
console.log(`Dry: ${dry.gain.value}, Wet: ${wet.gain.value}`);
// Wichtig · Fallstricke
- Abtastrate: Der
AudioBufferder Impulsantwort muss dieselbesampleRatewie der Kontext haben, sonst wird einNotSupportedErrorgeworfen.decodeAudioData()rechnet die Daten automatisch passend um. - Kanäle: Erlaubt sind IR-Puffer mit 1, 2 oder 4 Kanälen. Andere Kanalzahlen führen zu einem
NotSupportedError. normalizevorbuffersetzen: Die Normalisierung wird nur beim Zuweisen des Puffers berechnet. Eine spätere Änderung vonnormalizewirkt erst beim nächsten Setzen vonbuffer.- Performance: Lange Impulsantworten (mehrere Sekunden, Stereo) kosten viel CPU, besonders auf Mobilgeräten. Kürze die IR, wenn das Audio aussetzt.
- Autoplay: Ein
AudioContextstartet oft im Zustandsuspended. Rufectx.resume()nach einer Nutzeraktion auf. - CORS: Wird eine IR-Datei von einer fremden Domain per
fetch()geladen, muss der Server passende CORS-Header senden. - Kompatibilität: In allen modernen Browsern verfügbar. Ältere Safari-Versionen brauchen das Präfix
webkitAudioContext.