Start · Sprachen · JavaScript · Referenz · WaveShaperNode

WaveShaperNode

Schnittstelle

Ein <code>WaveShaperNode</code> ist ein nichtlinearer Verzerrer der Web Audio API. Er bildet jedes Eingangssample über eine Kennlinie (<code>curve</code>) auf einen neuen Wert ab.

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

Signatur

interface WaveShaperNode extends AudioNode

Beschreibung

WaveShaperNode ist ein AudioNode mit genau einem Eingang und einem Ausgang. Jedes Eingangssample im Bereich −1 bis +1 wird über eine Übertragungskurve abgebildet. Diese Kurve ist ein Float32Array und steht in der Eigenschaft curve. Zwischen den Stützstellen der Kurve wird linear interpoliert. So entstehen Effekte wie Distortion, Overdrive, Fuzz, Bitcrusher-ähnliche Stufungen oder ein weiches Clipping (Soft-Clipping) als Limiter.

Erzeugt wird der Knoten mit new WaveShaperNode(context, options) oder mit der Fabrikmethode AudioContext.createWaveShaper(). Die wichtigsten Eigenschaften sind:

  • curve (Float32Array | null): die Kennlinie. Sie braucht mindestens 2 Werte. Bei null wird das Signal unverändert durchgereicht.
  • oversample ("none" | "2x" | "4x"): interne Überabtastung. Sie verringert Aliasing-Artefakte, die durch die Nichtlinearität entstehen.

Typische Einsätze sind Gitarren-Verzerrer, Sättigung („Wärme“) in Synthesizern und Klangdesign in Spielen. Außerdem kann der Knoten Werte umrechnen, zum Beispiel ein Steuersignal auf einen anderen Wertebereich abbilden. Nichtlineare Verzerrung erzeugt Obertöne. Deshalb setzt man meist einen Filter (BiquadFilterNode) davor oder dahinter und regelt den Pegel mit einem GainNode nach.

Parameter

Name Typ Default Beschreibung
$context Pflicht BaseAudioContext Der AudioContext bzw. OfflineAudioContext, zu dem der Knoten gehört.
$options object {} Optionale Einstellungen für den Konstruktor.
$options.curve Float32Array | number[] null Anfangskurve der Kennlinie. Sie braucht mindestens 2 Werte.
$options.oversample "none" | "2x" | "4x" "none" Stufe der Überabtastung gegen Aliasing.
$options.channelCount / channelCountMode / channelInterpretation number | string 2 / "max" / "speakers" Übliche AudioNode-Einstellungen für die Kanäle.

Rückgabewert

Typ
WaveShaperNode
Beschreibung
Ein neuer Verzerrer-Knoten. Er muss per connect() in den Audiograph eingebunden werden.

Beispiele

Distortion-Kurve erzeugen und Knoten anlegen

const ctx = new AudioContext();

// Klassische Verzerrerkurve; amount steuert die Stärke
const makeDistortionCurve = (amount = 50, samples = 44100) => {
  const curve = new Float32Array(samples);
  const k = amount;
  const deg = Math.PI / 180;
  for (let i = 0; i < samples; i++) {
    const x = (i * 2) / samples - 1;
    curve[i] = ((3 + k) * x * 20 * deg) / (Math.PI + k * Math.abs(x));
  }
  return curve;
};

const shaper = new WaveShaperNode(ctx, {
  curve: makeDistortionCurve(400),
  oversample: '4x'
});

console.log(shaper.curve.length, shaper.oversample);
44100 4x

Oszillator durch den Verzerrer schicken (mit createWaveShaper)

const ctx = new AudioContext();
const osc = ctx.createOscillator();
const shaper = ctx.createWaveShaper();
const gain = ctx.createGain();

// Soft-Clipping über tanh
const n = 1024;
const curve = new Float32Array(n);
for (let i = 0; i < n; i++) {
  const x = (i / (n - 1)) * 2 - 1;
  curve[i] = Math.tanh(x * 5);
}
shaper.curve = curve;
shaper.oversample = '2x';
gain.gain.value = 0.3; // Pegel nach der Verzerrung absenken

osc.connect(shaper).connect(gain).connect(ctx.destination);

document.querySelector('#play').addEventListener('click', async () => {
  await ctx.resume();
  osc.start();
  osc.stop(ctx.currentTime + 2);
});

Mikrofon als Gitarren-Overdrive mit Regler

const ctx = new AudioContext();
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
const source = ctx.createMediaStreamSource(stream);

const makeCurve = (drive) => {
  const n = 2048;
  const c = new Float32Array(n);
  for (let i = 0; i < n; i++) {
    const x = (i / (n - 1)) * 2 - 1;
    c[i] = Math.tanh(x * drive) / Math.tanh(drive);
  }
  return c;
};

const shaper = new WaveShaperNode(ctx, { curve: makeCurve(3), oversample: '4x' });
const lowpass = new BiquadFilterNode(ctx, { type: 'lowpass', frequency: 5000 });

source.connect(shaper).connect(lowpass).connect(ctx.destination);

// Regler <input type="range" id="drive" min="1" max="20">
document.querySelector('#drive').addEventListener('input', (e) => {
  shaper.curve = makeCurve(Number(e.target.value)); // neues Array zuweisen
});

// Wichtig · Fallstricke

  • Die Kurve wird kopiert: Beim Zuweisen übernimmt der Knoten eine Kopie des Arrays. Spätere Änderungen am ursprünglichen Float32Array wirken sich also nicht aus. Um die Kurve zu ändern, weist du curve jedes Mal ein neues Array zu.
  • Eine Kurve mit weniger als 2 Elementen löst einen InvalidStateError aus. Das gilt je nach Browser auch, wenn schon eine Kurve gesetzt ist und erneut zugewiesen wird. In älteren Implementierungen war nur eine einzige Zuweisung erlaubt; setze in diesem Fall vorher null.
  • Die Kurve bildet nur den Eingangsbereich von −1 bis +1 ab. Werte außerhalb werden auf den ersten bzw. letzten Kurvenwert geklemmt. Eine Kurve mit ungerader Länge hat einen exakten Mittelpunkt bei 0; das hilft gegen Gleichspannungsanteile (DC-Offset).
  • oversample: "4x" klingt sauberer, braucht aber deutlich mehr Rechenzeit. Auf Mobilgeräten sollte man das abwägen.
  • Verzerrung erhöht den Pegel und den Obertonanteil stark. Um die Ohren zu schonen und Clipping am Ausgang zu vermeiden, setze immer einen GainNode dahinter.
  • Autoplay-Richtlinien: Ein AudioContext startet oft im Zustand suspended. Rufe ctx.resume() in einem Handler für eine Nutzeraktion auf.
  • Kompatibilität: Der Konstruktor new WaveShaperNode() funktioniert in allen aktuellen Browsern. Sehr alte Safari-Versionen kennen nur createWaveShaper() über webkitAudioContext.