[{"data":1,"prerenderedAt":338},["ShallowReactive",2],{"blog-audio-visualizer":3},{"id":4,"title":5,"body":6,"category":322,"date":323,"description":324,"draft":325,"extension":326,"meta":327,"navigation":328,"path":329,"seo":330,"stem":331,"tags":332,"__hash__":337},"blog\u002Fblog\u002Faudio-visualizer.md","Web Audio 音乐可视化",{"type":7,"value":8,"toc":313},"minimark",[9,13,35,39,61,66,75,85,98,143,158,162,171,220,223,226,230,253,256,268,271,274,287,297,309],[10,11,5],"h1",{"id":12},"web-audio-音乐可视化",[14,15,16,17,21,22,26,27,30,31,34],"p",{},"浏览器里的音乐播放器不只是 ",[18,19,20],"code",{},"\u003Caudio>"," 控件。通过 ",[23,24,25],"strong",{},"Web Audio API"," 把音频流接入 ",[18,28,29],{},"AnalyserNode","，再用 ",[23,32,33],{},"Canvas"," 读取频谱数据，就能做出随节拍律动的可视化。下方 demo 支持四种频谱样式、LRC 歌词滚动与歌单切换。",[36,37,38],"h2",{"id":38},"核心链路",[14,40,41,42,45,46,48,49,52,53,56,57,60],{},"整个 demo 可以拆成三条并行管线：",[23,43,44],{},"音频图","负责把 ",[18,47,20],{}," 接入 Web Audio；",[23,50,51],{},"Canvas 动画","每帧读取分析器数据并绘制；",[23,54,55],{},"歌词","根据 ",[18,58,59],{},"currentTime"," 滚动高亮。",[62,63,65],"h3",{"id":64},"_1-音频图从元素到-analysernode","1. 音频图：从元素到 AnalyserNode",[14,67,68,70,71,74],{},[18,69,20],{}," 本身只负责解码和播放。第一次点击播放时，才创建 ",[18,72,73],{},"AudioContext"," 并把元素挂到音频图上：",[76,77,82],"pre",{"className":78,"code":80,"language":81},[79],"language-text","\u003Caudio> → MediaElementSource → AnalyserNode → destination（扬声器）\n                              ↓\n                    每帧读取频谱 \u002F 波形数据\n","text",[18,83,80],{"__ignoreMap":84},"",[14,86,87,89,90,93,94,97],{},[18,88,29],{}," 是可视化的数据来源。",[18,91,92],{},"fftSize"," 设为 256（128 个频点），",[18,95,96],{},"smoothingTimeConstant"," 控制相邻帧的平滑程度——数值越大，柱状跳动越「黏」，越小则越灵敏。",[76,99,103],{"className":100,"code":101,"language":102,"meta":84,"style":84},"language-javascript shiki shiki-themes github-light github-dark","audioCtx = new AudioContext()\nsource = audioCtx.createMediaElementSource(audio)\nanalyser = audioCtx.createAnalyser()\nanalyser.fftSize = 256\nsource.connect(analyser)\nanalyser.connect(audioCtx.destination)\n","javascript",[18,104,105,113,119,125,131,137],{"__ignoreMap":84},[106,107,110],"span",{"class":108,"line":109},"line",1,[106,111,112],{},"audioCtx = new AudioContext()\n",[106,114,116],{"class":108,"line":115},2,[106,117,118],{},"source = audioCtx.createMediaElementSource(audio)\n",[106,120,122],{"class":108,"line":121},3,[106,123,124],{},"analyser = audioCtx.createAnalyser()\n",[106,126,128],{"class":108,"line":127},4,[106,129,130],{},"analyser.fftSize = 256\n",[106,132,134],{"class":108,"line":133},5,[106,135,136],{},"source.connect(analyser)\n",[106,138,140],{"class":108,"line":139},6,[106,141,142],{},"analyser.connect(audioCtx.destination)\n",[14,144,145,146,149,150,153,154,157],{},"浏览器要求 ",[23,147,148],{},"用户手势"," 后才能 ",[18,151,152],{},"resume()"," 音频上下文，所以 demo 必须点播放才能启动；暂停时取消 ",[18,155,156],{},"requestAnimationFrame","，Canvas 回到 idle 态。",[62,159,161],{"id":160},"_2-canvas-绘制同一数据源四种画法","2. Canvas 绘制：同一数据源，四种画法",[14,163,164,165,167,168,170],{},"绘制循环在 ",[18,166,156],{}," 里跑。根据当前模式，从 ",[18,169,29],{}," 取不同数据：",[172,173,174,190],"table",{},[175,176,177],"thead",{},[178,179,180,184,187],"tr",{},[181,182,183],"th",{},"模式",[181,185,186],{},"读取方法",[181,188,189],{},"绘制思路",[191,192,193,207],"tbody",{},[178,194,195,199,204],{},[196,197,198],"td",{},"圆形 \u002F 柱状 \u002F 粒子",[196,200,201],{},[18,202,203],{},"getByteFrequencyData",[196,205,206],{},"128 个频点映射为半径、柱高或粒子位移",[178,208,209,212,217],{},[196,210,211],{},"波形",[196,213,214],{},[18,215,216],{},"getByteTimeDomainData",[196,218,219],{},"时域采样连成曲线，并做帧间平滑",[14,221,222],{},"频谱类模式用频率能量驱动视觉；波形模式看的是振幅随时间的变化。切歌或切模式时会清空帧间缓存，避免上一首的能量「残留」。",[14,224,225],{},"每首歌还配了一套主题色（主色、辅色、光晕），切歌时同步更新 Canvas 渐变和 UI 变量。",[62,227,229],{"id":228},"_3-歌词同步","3. 歌词同步",[14,231,232,233,236,237,240,241,244,245,248,249,252],{},"LRC 文本先解析成 ",[18,234,235],{},"{ time, text }[]","，播放过程中根据 ",[18,238,239],{},"audio.currentTime"," 二分查找当前行，用 ",[18,242,243],{},"transform: translateY(...)"," 把高亮行滚到视口中央。",[18,246,247],{},"timeupdate"," 事件触发频繁，滚动逻辑做了 500ms 节流；点击某行歌词则 ",[18,250,251],{},"seek"," 到对应时间。",[36,254,255],{"id":255},"在线体验",[14,257,258,259,261,262,267],{},"下方为完整交互 demo（需点击播放后启动 ",[18,260,73],{},"）。也可 ",[263,264,266],"a",{"href":265},"\u002Fdemos\u002Faudio-viz","全屏预览"," 打开独立页面。",[269,270],"audio-visualizer-demo",{},[36,272,273],{"id":273},"小结",[14,275,276,277,286],{},"Web Audio 可视化并不复杂：",[23,278,279,280,282,283,285],{},"把 ",[18,281,20],{}," 接入 ",[18,284,29],{},"，再在 Canvas 里每帧读数据、画图形","。难点在于体验细节——播放前后的 idle 动画、切歌时的状态重置、波形与频谱不同的平滑策略，以及歌词与进度的双向联动。",[14,288,289,290,293,294,296],{},"四种频谱样式共用同一套分析器，只是映射方式不同；这也是前端可视化里常见的模式：",[23,291,292],{},"数据层稳定，表现层可插拔","。如果你要做自己的播放器可视化，可以从一个 ",[18,295,29],{}," + 一种绘制函数开始，再逐步加模式和主题。",[14,298,299,300,303,304,308],{},"想走另一条 Web Audio 路线——用振荡器",[23,301,302],{},"合成","声音而非分析播放——可以看 ",[263,305,307],{"href":306},"\u002Fblog\u002Fweb-piano","网页钢琴与 Web Audio 合成","。",[310,311,312],"style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":84,"searchDepth":121,"depth":121,"links":314},[315,320,321],{"id":38,"depth":115,"text":38,"children":316},[317,318,319],{"id":64,"depth":121,"text":65},{"id":160,"depth":121,"text":161},{"id":228,"depth":121,"text":229},{"id":255,"depth":115,"text":255},{"id":273,"depth":115,"text":273},"music","2026-05-18","用 Canvas 与 Web Audio API 实现圆形、柱状、波形、粒子四种频谱，并同步 LRC 歌词。",false,"md",{},true,"\u002Fblog\u002Faudio-visualizer",{"title":5,"description":324},"blog\u002Faudio-visualizer",[333,334,335,336],"web-audio","canvas","visualization","vue","ghCDv_tcwtPfmSAefPGprSYdKOWg6tvA3kUQQMnVylU",1782309644802]