Start · Sprachen · JavaScript · Referenz · ConvolverNode

ConvolverNode

Schnittstelle

Ein <code>AudioNode</code>, der das Eingangssignal mit einer Impulsantwort (<code>AudioBuffer</code>) linear faltet, typischerweise für realistische Hall- und Raumeffekte.

seit JavaScript Baseline: alle modernen Browser (Web Audio API) Kategorie: webapi

Signatur

interface ConvolverNode extends AudioNode

Beschreibung

ConvolverNode gehört zur Web Audio API und führt eine lineare Faltung des Eingangssignals mit einer Impulsantwort durch. Die Impulsantwort ist eine Aufnahme davon, wie ein Raum (Kirche, Konzertsaal, Badezimmer) oder ein Gerät (Lautsprecherbox, Federhall) auf einen kurzen Impuls reagiert. Wird ein beliebiges Signal damit gefaltet, klingt es so, als wäre es in diesem Raum bzw. durch dieses Gerät abgespielt worden.

Der Knoten hat genau einen Eingang und einen Ausgang. Instanzen erzeugt man mit new ConvolverNode(context, options) oder mit der Fabrikmethode BaseAudioContext.createConvolver(). Die Impulsantwort weist man über die Eigenschaft buffer zu. Meist lädt man sie als WAV-Datei per fetch() und dekodiert sie mit decodeAudioData(). Man kann sie aber auch selbst erzeugen, etwa als abklingendes Rauschen.

Wichtige Eigenschaften:

  • buffer: ein AudioBuffer (Mono, Stereo oder 4 Kanäle) mit der Impulsantwort, oder null.
  • normalize: ein boolean, Standard ist true. Er legt fest, ob die Impulsantwort beim Zuweisen an buffer anhand ihrer Leistung (RMS) auf eine gleichmäßige Lautstärke skaliert wird.

In der Praxis schaltet man den Convolver fast immer parallel zum trockenen Signal (Dry/Wet-Mix). Das Verhältnis steuert man mit zwei GainNodes.

Parameter

Name Typ Default Beschreibung
$context Pflicht BaseAudioContext Der AudioContext oder OfflineAudioContext, zu dem der Knoten gehört (nur beim Konstruktor).
$options ConvolverOptions {} Optionales Objekt mit buffer (AudioBuffer | null), disableNormalization (boolean, Standard false) sowie den allgemeinen AudioNodeOptions channelCount, channelCountMode und channelInterpretation.

Rückgabewert

Typ
ConvolverNode
Beschreibung
Eine neue ConvolverNode-Instanz, die mit dem angegebenen Kontext verbunden werden kann.

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 startReverb = async () => {
  const impulse = await loadImpulse('/audio/konzertsaal.wav');
  const convolver = new ConvolverNode(ctx, { buffer: impulse });

  const osc = new OscillatorNode(ctx, { type: 'sawtooth', frequency: 220 });
  osc.connect(convolver).connect(ctx.destination);
  osc.start();
  osc.stop(ctx.currentTime + 0.5);
  console.log('Kanäle der Impulsantwort:', convolver.buffer.numberOfChannels);
};

document.querySelector('#play').addEventListener('click', async () => {
  await ctx.resume();
  await startReverb();
});
Kanäle der Impulsantwort: 2

Synthetische Impulsantwort ohne Datei erzeugen

const ctx = new AudioContext();

// Abklingendes Stereo-Rauschen als künstlicher Raum
const createImpulse = (seconds = 2.5, decay = 3) => {
  const length = Math.floor(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();
console.log(convolver.normalize, convolver.buffer.duration.toFixed(1));
true 2.5

Dry/Wet-Mix für ein Audio-Element

const ctx = new AudioContext();
const audioEl = document.querySelector('audio');
const source = ctx.createMediaElementSource(audioEl);

const convolver = new ConvolverNode(ctx);
const dry = new GainNode(ctx, { gain: 0.7 });
const wet = new GainNode(ctx, { gain: 0.3 });

source.connect(dry).connect(ctx.destination);
source.connect(convolver).connect(wet).connect(ctx.destination);

const res = await fetch('/audio/kirche.wav');
convolver.buffer = await ctx.decodeAudioData(await res.arrayBuffer());

// Regler 0..1 steuert den Hallanteil
document.querySelector('#mix').addEventListener('input', (e) => {
  const mix = Number(e.target.value);
  wet.gain.setTargetAtTime(mix, ctx.currentTime, 0.05);
  dry.gain.setTargetAtTime(1 - mix, ctx.currentTime, 0.05);
});

// Wichtig · Fallstricke

  • Setze normalize vor buffer: Die Normalisierung wird nur in dem Moment berechnet, in dem buffer zugewiesen wird. Wenn du normalize danach änderst, hat das erst beim nächsten Zuweisen eine Wirkung. Im Konstruktor entspricht disableNormalization: true dem Wert normalize = false.
  • Abtastrate: Die Abtastrate des AudioBuffer muss der des Kontexts entsprechen, sonst wird ein NotSupportedError geworfen. decodeAudioData() rechnet die Datei automatisch auf die Rate des Kontexts um.
  • Kanalanzahl: Die Impulsantwort darf nur 1, 2 oder 4 Kanäle haben. Für channelCount sind nur 1 oder 2 erlaubt, und channelCountMode darf nicht "max" sein.
  • Leistung: Die Faltung ist rechenintensiv. Lange Impulsantworten mit mehreren Sekunden kosten viel CPU, vor allem auf Mobilgeräten. Nutze einen gemeinsamen Convolver als Hall-Bus, statt für jede Quelle einen eigenen anzulegen.
  • Autoplay: Browser starten einen AudioContext im Zustand suspended. Rufe ctx.resume() daher erst nach einer Nutzerinteraktion auf.
  • CORS: Impulsantworten von fremden Domains brauchen passende CORS-Header. Bei createMediaElementSource() mit fremden Quellen bleibt der Ausgang ohne CORS stumm.
  • Kompatibilität: Die Schnittstelle wird in allen modernen Browsern unterstützt. Den Konstruktor new ConvolverNode() gibt es erst in neueren Versionen; sehr alte Safari-Versionen brauchen createConvolver() bzw. webkitAudioContext.