エフェクトとフェード
このガイドでは、nodes、fade、play モジュールを使用して、audio effect とフェード効果を実装する方法を説明します。
デモ
Sound Source
Effect Chain
Fade
使用モジュール
- nodes: Audio node のファクトリー関数(
createGain、createPanner、chainなど) - fade: フェードイン/アウト、クロスフェードユーティリティ
- play: コア再生エンジン(
throughオプションで effect chain をルーティング)
コード例
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);through オプションに GainNode を渡すと、play() が自動的に音源からゲインノード、そして destination へと接続します。
関数 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. Effect Chain
複数の effect を組み合わせて、リッチなサウンド処理を実現できます。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() は不要です。chain() は play() の外でノードグラフを構築する場合に使用します。
関数 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 クロスフェード
2つのトラック間でクロスフェードを行い、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);