Signatur
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. Beinullwird 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
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);
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
Float32Arraywirken sich also nicht aus. Um die Kurve zu ändern, weist ducurvejedes Mal ein neues Array zu. - Eine Kurve mit weniger als 2 Elementen löst einen
InvalidStateErroraus. 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 vorhernull. - 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
GainNodedahinter. - Autoplay-Richtlinien: Ein
AudioContextstartet oft im Zustandsuspended. Rufectx.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 nurcreateWaveShaper()überwebkitAudioContext.