官方文档
BaseAudioContext.createOscillator() - Web API | MDN
🧠 什么是 AudioContext?
AudioContext
是 Web Audio API 的核心接口,它提供了一个音频处理的上下文环境,允许你创建、处理和播放音频。
创建方式非常简单:
1
| const audioCtx = new (window.AudioContext || window.webkitAudioContext)();
|
兼容 Safari 的老写法也要带上。
🎛 核心概念
在 AudioContext 中,音频通过一个音频图(Audio Graph)进行处理。每个节点(AudioNode)都可以接收、处理或输出声音。
流程大概是这样的:

🔧 常用 AudioNode 和 API
1. 创建音频源
(1) 播放音频文件
1 2 3 4 5 6 7 8 9
| fetch('your-audio-file.mp3') .then(res => res.arrayBuffer()) .then(arrayBuffer => audioCtx.decodeAudioData(arrayBuffer)) .then(audioBuffer => { const source = audioCtx.createBufferSource(); source.buffer = audioBuffer; source.connect(audioCtx.destination); source.start(); });
|
(2) 生成声音(OscillatorNode)
1 2 3 4 5 6
| const oscillator = audioCtx.createOscillator(); oscillator.type = 'sine'; oscillator.frequency.setValueAtTime(440, audioCtx.currentTime); oscillator.connect(audioCtx.destination); oscillator.start(); oscillator.stop(audioCtx.currentTime + 2);
|
2. 音量控制(GainNode)
1 2 3 4
| const gainNode = audioCtx.createGain(); gainNode.gain.setValueAtTime(0.5, audioCtx.currentTime);
source.connect(gainNode).connect(audioCtx.destination);
|
3. 创建音频分析器(AnalyserNode)
如果你要做音频可视化,比如音波动画,就需要用它:
1 2 3 4 5 6 7
| const analyser = audioCtx.createAnalyser(); source.connect(analyser); analyser.connect(audioCtx.destination);
const dataArray = new Uint8Array(analyser.frequencyBinCount); analyser.getByteFrequencyData(dataArray);
|
4. 音效处理(BiquadFilterNode)
可以加滤波效果,比如低通滤波器:
1 2 3 4 5
| const filter = audioCtx.createBiquadFilter(); filter.type = 'lowpass'; filter.frequency.setValueAtTime(1000, audioCtx.currentTime);
source.connect(filter).connect(audioCtx.destination);
|
5. 控制播放时间
可以用 start(when)
和 stop(when)
控制播放时间:
1 2
| source.start(audioCtx.currentTime + 1); source.stop(audioCtx.currentTime + 5);
|
⚠️ 注意事项
AudioContext 默认是暂停状态:用户必须有操作(如点击按钮)后才能播放。
1 2 3
| document.querySelector('button').addEventListener('click', () => { audioCtx.resume(); });
|
资源释放:播放完后最好 stop()
并断开连接,释放资源。
跨域音频注意 CORS:加载外部音频文件时要保证服务端设置了 CORS 头。
示例代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
| const context = new AudioContext();
const osc = context.createOscillator(); osc.frequency.value = 220; osc.type = "square"; osc.start();
const volume = context.createGain(); volume.gain.value = 0.5;
const out = context.destination;
const nodes = new Map();
nodes.set("a", osc); nodes.set("b", volume); nodes.set("c", out);
export function inRunning() { return context.state === "running"; }
export function toggleAudio() { return inRunning() ? context.suspend() : context.resume(); }
export function updateAudioNode(id: string, data: Record<string, any>) { const node = nodes.get(id);
for (const [key, val] of Object.entries(data)) { if (node[key] instanceof AudioParam) { node[key].value = val; } else { node[key] = val; } } }
export function removeAudioNode(id: string) { const node = nodes.get(id);
node.disconnect(); node.stop?.(); nodes.delete(id); }
export function connect(sourceId: string, targetId: string) { const source = nodes.get(sourceId); const target = nodes.get(targetId);
source.connect(target); }
export function disconnect(sourceId: string, targetId: string) { const source = nodes.get(sourceId); const target = nodes.get(targetId);
source.disconnect(target); }
export function createAudioNode( id: string, type: string, data: Record<string, any> ) { switch (type) { case "osc": { const node = context.createOscillator(); node.frequency.value = data.frequency; node.type = data.type; node.start();
nodes.set(id, node); break; }
case "volume": { const node = context.createGain(); node.gain.value = data.gain;
nodes.set(id, node); break; } } }
|