效果与淡入淡出
本指南演示如何使用 nodes、fade 和 play 模块实现音频效果和淡入淡出过渡。
演示
音源
或
效果链
淡化
使用的模块
- nodes: 音频节点工厂函数(
createGain、createPanner、chain等) - fade: 淡入/淡出和交叉淡入淡出工具
- play: 核心播放引擎(通过
through选项路由效果链)
代码示例
1. 音量控制
使用 createGain() 创建 GainNode,并通过 play() 函数的 through 选项进行路由。使用 rampGain() 可以平滑地改变音量,不会产生爆音。
import { WaaPlayer } from "waa-play";
const waa = new WaaPlayer();await waa.ensureRunning();
const buffer = await waa.load("/audio/track.mp3");const gain = waa.createGain(0.5); // Initial volume 50%
const playback = waa.play(buffer, { through: [gain] });
// Ramp to 100% volume over 3 secondswaa.rampGain(gain, 1.0, 3);当您将 GainNode 传递给 through 选项时,play() 会自动将音源连接到增益节点,然后再连接到目标。
函数 API 版
import { createContext, ensureRunning } from "waa-play/context";import { loadBuffer } from "waa-play/buffer";import { createGain, rampGain } from "waa-play/nodes";import { play } from "waa-play/play";
const ctx = createContext();await ensureRunning(ctx);
const buffer = await loadBuffer(ctx, "/audio/track.mp3");const gain = createGain(ctx, 0.5);
const playback = play(ctx, buffer, { through: [gain] });rampGain(gain, 1.0, 3);2. 立体声声像
使用 createPanner() 创建 StereoPannerNode 以控制左右声像。值的范围从 -1(左)到 1(右)。
import { WaaPlayer } from "waa-play";
const waa = new WaaPlayer();await waa.ensureRunning();
const buffer = await waa.load("/audio/track.mp3");const panner = waa.createPanner(0); // Center
const playback = waa.play(buffer, { through: [panner] });
// Pan leftpanner.pan.value = -1;
// Pan rightpanner.pan.value = 1;
// Back to centerpanner.pan.value = 0;函数 API 版
import { createContext, ensureRunning } from "waa-play/context";import { loadBuffer } from "waa-play/buffer";import { createPanner } from "waa-play/nodes";import { play } from "waa-play/play";
const ctx = createContext();await ensureRunning(ctx);
const buffer = await loadBuffer(ctx, "/audio/track.mp3");const panner = createPanner(ctx, 0);
const playback = play(ctx, buffer, { through: [panner] });panner.pan.value = -1; // Left3. 效果链
组合多个效果以实现丰富的声音处理。将节点数组传递给 through 以自动将它们链接在一起。
import { WaaPlayer } from "waa-play";
const waa = new WaaPlayer();await waa.ensureRunning();
const buffer = await waa.load("/audio/track.mp3");
// Build effect chainconst gain = waa.createGain(0.8);const filter = waa.createFilter({ type: "lowpass", frequency: 1000 });const compressor = waa.createCompressor();const panner = waa.createPanner(0.5);
// Auto-chain: gain → filter → compressor → panner → destinationconst playback = waa.play(buffer, { through: [gain, filter, compressor, panner],});
// Adjust filter frequencyfilter.frequency.value = 500;使用 through 选项时,play() 会自动连接节点,因此不需要 chain()。在 play() 之外构建节点图时使用 chain()。
函数 API 版
使用 chain() 显式构建节点图的示例:
import { createContext, ensureRunning } from "waa-play/context";import { loadBuffer } from "waa-play/buffer";import { createGain, createFilter, createCompressor, createPanner, chain,} from "waa-play/nodes";import { play } from "waa-play/play";
const ctx = createContext();await ensureRunning(ctx);
const buffer = await loadBuffer(ctx, "/audio/track.mp3");
const gain = createGain(ctx, 0.8);const filter = createFilter(ctx, { type: "lowpass", frequency: 1000 });const compressor = createCompressor(ctx);const panner = createPanner(ctx, 0.5);
// Explicitly connect with chain()chain(gain, filter, compressor, panner);
const playback = play(ctx, buffer, { through: [gain] });4. 淡入/淡出
使用 fadeIn() 和 fadeOut() 实现平滑的淡入淡出效果。autoFade() 可以在播放开始和结束时自动淡入淡出。
import { WaaPlayer } from "waa-play";
const waa = new WaaPlayer();await waa.ensureRunning();
const buffer = await waa.load("/audio/track.mp3");const gain = waa.createGain(0); // Start at 0 volume
const playback = waa.play(buffer, { through: [gain] });
// Fade in over 2 seconds (equal-power curve)waa.fadeIn(gain, 1, { duration: 2, curve: "equal-power" });
// Fade out over 2 secondssetTimeout(() => { waa.fadeOut(gain, { duration: 2 });}, 5000);使用 autoFade() 可以自动设置播放开始和结束时的淡入淡出。
import { WaaPlayer } from "waa-play";
const waa = new WaaPlayer();await waa.ensureRunning();
const buffer = await waa.load("/audio/track.mp3");const gain = waa.createGain(0);
const playback = waa.play(buffer, { through: [gain] });
// Fade in 1s at start, fade out 2s over the last 2 secondswaa.autoFade(playback, gain, { fadeIn: 1, fadeOut: 2 });函数 API 版
import { createContext, ensureRunning } from "waa-play/context";import { loadBuffer } from "waa-play/buffer";import { createGain } from "waa-play/nodes";import { play } from "waa-play/play";import { fadeIn, fadeOut, autoFade } from "waa-play/fade";
const ctx = createContext();await ensureRunning(ctx);
const buffer = await loadBuffer(ctx, "/audio/track.mp3");const gain = createGain(ctx, 0);
const playback = play(ctx, buffer, { through: [gain] });
// Fade infadeIn(gain, 1, { duration: 2, curve: "equal-power" });
// Auto fadeautoFade(playback, gain, { fadeIn: 1, fadeOut: 2 });5. DJ 交叉淡入淡出
在两个音轨之间交叉淡入淡出,实现无缝的 DJ 风格过渡。
import { WaaPlayer } from "waa-play";
const waa = new WaaPlayer();await waa.ensureRunning();
const bufferA = await waa.load("/audio/track-a.mp3");const bufferB = await waa.load("/audio/track-b.mp3");
// Track A (full volume)const gainA = waa.createGain(1);const playbackA = waa.play(bufferA, { through: [gainA], loop: true });
// Track B (muted)const gainB = waa.createGain(0);const playbackB = waa.play(bufferB, { through: [gainB], loop: true });
// Crossfade from track A to track B over 3 secondssetTimeout(() => { waa.crossfade(gainA, gainB, { duration: 3, curve: "equal-power" });}, 5000);crossfade() 同时将一个 GainNode 从 1 淡出到 0,将另一个从 0 淡入到 1。使用 curve: "equal-power" 可以确保在交叉淡入淡出期间音量感知均匀。
函数 API 版
import { createContext, ensureRunning } from "waa-play/context";import { loadBuffer } from "waa-play/buffer";import { createGain } from "waa-play/nodes";import { play } from "waa-play/play";import { crossfade } from "waa-play/fade";
const ctx = createContext();await ensureRunning(ctx);
const bufferA = await loadBuffer(ctx, "/audio/track-a.mp3");const bufferB = await loadBuffer(ctx, "/audio/track-b.mp3");
const gainA = createGain(ctx, 1);const playbackA = play(ctx, bufferA, { through: [gainA], loop: true });
const gainB = createGain(ctx, 0);const playbackB = play(ctx, bufferB, { through: [gainB], loop: true });
setTimeout(() => { crossfade(gainA, gainB, { duration: 3, curve: "equal-power" });}, 5000);