Start · Sprachen · JavaScript · Referenz · WaveShaperNode.curve

WaveShaperNode.curve

Eigenschaft

Legt als <code>Float32Array</code> die Übertragungskurve fest, mit der ein <code>WaveShaperNode</code> Eingangssamples auf Ausgangswerte abbildet. So entsteht Verzerrung oder Sättigung.

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

Signatur

WaveShaperNode.curve

Beschreibung

Die Eigenschaft curve eines WaveShaperNode enthält die Übertragungskurve des Waveshapers. Jedes Eingangssample im Bereich -1 bis +1 wird auf eine Stelle in diesem Array abgebildet, und der dort gespeicherte Wert wird ausgegeben. Zwischen zwei Stützpunkten wird linear interpoliert. curve[0] gehört zum Eingang -1, das letzte Element zum Eingang +1 und das mittlere Element zum Eingang 0.

Mit curve baust du nichtlineare Effekte: Gitarren-Verzerrung (Distortion, Overdrive), weiche Sättigung à la Röhre (z. B. mit Math.tanh), harte Begrenzung (Hard Clipping), Bitcrusher-artige Treppenkurven oder eine Gleichrichtung. Ist die Kurve linear (also y = x), ändert sich das Signal nicht.

Beim Zuweisen kopiert der Browser das Array intern. Änderst du danach das ursprüngliche Float32Array, hat das keine Wirkung. Um die Kurve zu ändern, musst du erneut ein Array zuweisen. Mit null (dem Standardwert) reicht der Knoten das Signal unverändert durch.

Weil nichtlineare Kurven hohe Obertöne erzeugen, die Aliasing verursachen können, kombiniert man curve meist mit der Eigenschaft oversample ("2x" oder "4x").

Parameter

Name Typ Default Beschreibung
$value Float32Array | null null Die neue Übertragungskurve mit mindestens 2 Elementen. Die Werte liegen üblicherweise zwischen -1 und 1. null schaltet die Formung ab, das Signal läuft dann unverändert durch.

Rückgabewert

Typ
Float32Array | null
Beschreibung
Die aktuell gesetzte Kurve (eine Kopie der intern gespeicherten Werte) oder null, wenn keine Kurve gesetzt ist.

Beispiele

Klassische Distortion-Kurve auf einen Oszillator anwenden

const ctx = new AudioContext();

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

const osc = new OscillatorNode(ctx, { type: 'sine', frequency: 220 });
const shaper = new WaveShaperNode(ctx, { oversample: '4x' });
shaper.curve = makeDistortionCurve(400);

osc.connect(shaper).connect(ctx.destination);
osc.start();
osc.stop(ctx.currentTime + 2);

console.log(shaper.curve.length);
44100

Weiche Röhren-Sättigung mit Math.tanh für ein Mikrofon-Signal

const ctx = new AudioContext();

const makeTanhCurve = (drive = 3, samples = 2048) => {
  const curve = new Float32Array(samples);
  const norm = Math.tanh(drive);
  for (let i = 0; i < samples; i++) {
    const x = (i / (samples - 1)) * 2 - 1;
    curve[i] = Math.tanh(drive * x) / norm; // auf ±1 normiert
  }
  return curve;
};

const start = async () => {
  const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
  const mic = ctx.createMediaStreamSource(stream);
  const shaper = ctx.createWaveShaper();
  shaper.curve = makeTanhCurve(5);
  shaper.oversample = '2x';
  mic.connect(shaper).connect(ctx.destination);
  console.log('Sättigung aktiv:', shaper.curve !== null);
};

document.querySelector('#start').addEventListener('click', start);
Sättigung aktiv: true

Effekt per Schieberegler steuern und mit null umgehen (Bypass)

const ctx = new AudioContext();
const shaper = new WaveShaperNode(ctx);

// Harte Begrenzung: alles über threshold wird abgeschnitten
const makeClipCurve = (threshold, samples = 1024) => {
  const curve = new Float32Array(samples);
  for (let i = 0; i < samples; i++) {
    const x = (i / (samples - 1)) * 2 - 1;
    curve[i] = Math.max(-threshold, Math.min(threshold, x));
  }
  return curve;
};

const slider = document.querySelector('#clip');
slider.addEventListener('input', () => {
  const t = Number(slider.value); // 0.05 … 1
  // Array neu zuweisen, weil nachträgliche Änderungen ignoriert werden
  shaper.curve = t >= 1 ? null : makeClipCurve(t);
  console.log(shaper.curve === null ? 'Bypass' : `Clip bei ${t}`);
});
Clip bei 0.3

// Wichtig · Fallstricke

  • Die Kurve wird kopiert: Nach dem Zuweisen haben Änderungen am ursprünglichen Float32Array keine Wirkung. Um die Kurve zu ändern, musst du immer ein neues Array zuweisen.
  • Ein Array mit weniger als 2 Elementen löst einen InvalidStateError aus. Nur Float32Array ist erlaubt, normale Arrays funktionieren nicht zuverlässig.
  • Eingangswerte außerhalb von -1…+1 werden auf den ersten bzw. letzten Kurvenwert begrenzt.
  • Nullpunkt beachten: Bei einer geraden Anzahl von Elementen liegt der Eingang 0 zwischen zwei Stützpunkten. Liefert die Kurve dort nicht exakt 0, entsteht ein Gleichspannungsanteil (DC-Offset), der auch in Stille hörbar oder messbar sein kann. Eine ungerade Länge oder ein nachgeschalteter Hochpass (BiquadFilterNode) helfen dagegen.
  • Starke Verzerrung erzeugt Aliasing. Setze deshalb oversample auf "2x" oder "4x". Das kostet etwas CPU.
  • Sehr lange Kurven (z. B. 44100 Werte) sind unkritisch, bringen aber ab ein paar tausend Stützpunkten kaum hörbaren Gewinn.
  • Die Eigenschaft wird in allen aktuellen Browsern unterstützt (Chrome, Firefox, Safari, Edge). In sehr alten Safari-Versionen war nur webkitAudioContext verfügbar.
  • Verzerrung erhöht die Lautstärke oft deutlich. Setze zum Schutz des Gehörs ausreichend Pegelreserve, z. B. über einen GainNode nach dem Shaper.