waveshapernode通过非线性映射函数(如tanh软削波、硬截断等)对音频进行实时失真处理,配合过采样和滤波可模拟电吉他失真音色。

用 WaveShaperNode 模拟电吉他失真,核心是设计一个非线性映射函数,把输入波形“挤压”或“削顶”,产生谐波丰富的畸变效果。它不依赖外部采样,纯数学建模,轻量且可实时调节。
理解失真原理:非线性变换是关键
电吉他失真本质是放大器过载导致的波形裁剪(clipping)和软饱和(soft saturation)。WaveShaperNode 正是干这事的——它接收 -1 到 +1 区间的输入样本,按你定义的数组或函数一对一映射为输出值。映射曲线越“弯”,谐波越多,音色越毛躁或温暖。
常见有效映射方式:
-
硬削波(Hard Clipping):超出阈值直接截断,如
y = Math.max(-0.7, Math.min(0.7, x))→ 高频刺耳,适合高增益金属失真 -
软削波(Soft Clipping / Saturate):用 tanh、atan 或多项式平滑压缩,如
y = Math.tanh(x * gain)→ 更自然,类似电子管暖失真 - 整流+混合(Full-wave Rectify + Blend):取绝对值再与原信号混合 → 增加偶次谐波,有复古晶体管味
创建并配置 WaveShaperNode
先生成足够长(通常 4096 或 8192 点)的映射数组,再传给节点:
const audioCtx = new (window.AudioContext || window.webkitAudioContext)();
const distortion = audioCtx.createWaveShaper();
<p>function makeDistortionCurve(amount = 100) {
const nSamples = 4096;
const curve = new Float32Array(nSamples);
const deg = Math.PI / 180;</p><p>// 示例:带增益控制的 tanh 软饱和
const gain = amount / 50; // amount 0–200 调节强度
for (let i = 0; i 2) / nSamples - 1; // 映射到 [-1, 1]
curve[i] = Math.tanh(x gain);
}
return curve;
}</p><p>distortion.curve = makeDistortionCurve(150); // 应用曲线
distortion.oversample = '4x'; // 开启 4x 过采样,大幅减少数字削波杂音
</p>
注意:oversample 设为 '2x' 或 '4x' 很重要——原始 1x 模式下高频失真会产生明显 aliasing(混叠噪声),听感发“渣”。
串联进音频图并调音色
典型链路:声源 → 增益(可选)→ WaveShaper(失真)→ 低通滤波(去高频刺耳)→ 输出
// 示例:接在 Oscillator 后 const osc = audioCtx.createOscillator(); const gainNode = audioCtx.createGain(); const filter = audioCtx.createBiquadFilter(); <p>gainNode.gain.value = 0.3; // 先衰减防爆音 osc.connect(gainNode); gainNode.connect(distortion); distortion.connect(filter); filter.type = 'lowshelf'; filter.frequency.value = 3000; filter.gain.value = -6; // 削弱刺耳高频 filter.connect(audioCtx.destination);</p><p>osc.start(); </p>
实战建议:
- 失真前加
GainNode控制输入电平——推得越狠,失真越重;这是模拟“吉他音量旋钮控制失真度”的关键 - 失真后必加滤波:用
BiquadFilterNode做 lowshelf 或 lowpass,切掉 5kHz 以上毛刺,让音色更像真实箱头 - 可动态更新
curve数组实现旋钮实时调参(如用input[type="range"]绑定 amount)
进阶技巧:叠加多段失真 & 干湿比
真实吉他音箱常有多级增益电路。可用两个 WaveShaper 串联模拟前级+后级,或用 ChannelSplitter + ChannelMerger 实现干湿混合:
const wet = audioCtx.createGain(); const dry = audioCtx.createGain(); wet.gain.value = 0.7; // 失真占比 dry.gain.value = 0.3; // 干声占比 <p>source.connect(dry); source.connect(distortion); distortion.connect(wet);</p><p>const merger = audioCtx.createChannelMerger(2); dry.connect(merger, 0, 0); wet.connect(merger, 0, 0); merger.connect(output); </p>
这样避免全失真带来的浑浊,保留拨弦瞬态和低频骨架,音色更清晰有力。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











