复现 musicforprogramming.net 的音乐可视化效果
JavaScriptWeb Audio可视化
最近,我尝试复现了 musicforprogramming.net 网站上的音乐可视化效果。这个网站为程序员提供了一个独特的音乐播放体验,伴随着音乐的播放,屏幕上会显示动态的 ASCII 艺术效果。本文将详细介绍如何通过 HTML、CSS 和 JavaScript 来实现这一效果。
HTML 结构
在 index.html 文件中,我们定义了一个简单的网页结构。页面包含一个音频播放器(目前被注释掉了)和四个 <span> 元素,用于显示不同颜色的 ASCII 艺术效果。此外,还有一个播放按钮,用于控制音乐的播放和暂停。
1<!DOCTYPE html>
2<html lang="en">
3<head>
4 <meta charset="UTF-8">
5 <meta name="viewport" content="width=device-width, initial-scale=1.0">
6 <title>musicforprogramming</title>
7 <link rel="stylesheet" href="style.css">
8</head>
9<body>
10 <div class="pad grey pr-0 pb-0 pt-0">
11 <span id="fuschia"
12 class="fuschia"> </span><br>
13 <span id="orange"
14 class="orange"> </span><br>
15 <span id="yellow"
16 class="yellow"> </span><br>
17 <span id="green" class="green">________________________________</span><br>
18 <br>
19 <br>
20 <button id="play" class="green hover" disabled:true="false">[play]</button>
21 <br>
22 </div>
23 <script src="index.js"></script>
24</body>
25</html>JavaScript 逻辑
index.js 文件包含了实现音乐播放和可视化效果的核心逻辑。我们使用 AudioContext 和 AnalyserNode 来处理音频数据,并通过 requestAnimationFrame 实现动态的可视化效果。
1// 获取页面上的元素
2const F = document.getElementById("fuschia"); // 获取紫色区域的元素
3const O = document.getElementById("orange"); // 获取橙色区域的元素
4const Y = document.getElementById("yellow"); // 获取黄色区域的元素
5const G = document.getElementById("green"); // 获取绿色区域的元素
6const play = document.getElementById("play"); // 获取播放按钮元素
7
8// 创建音频上下文和音频对象
9const audioCtx = new AudioContext(); // 创建音频上下文
10const audio = new Audio('./daoxiang.mp3'); // 创建音频对象,加载音频文件
11
12// 为播放按钮添加点击事件监听器
13play.addEventListener('click', () => {
14 if (!audio.paused) { // 如果音频正在播放
15 audio.pause(); // 暂停音频
16 play.innerText = "[play]"; // 将按钮文本改为 "[play]"
17 return;
18 }
19 audio.play(); // 播放音频
20 play.innerText = "[pause]"; // 将按钮文本改为 "[pause]"
21});
22
23// 创建音频分析器
24const analyser = audioCtx.createAnalyser(); // 创建音频分析器
25analyser.minDecibels = -114; // 设置分析器的最小分贝值
26analyser.maxDecibels = -30; // 设置分析器的最大分贝值
27analyser.fftSize = 2048; // 设置 FFT(快速傅里叶变换)的大小
28analyser.smoothingTimeConstant = .666; // 设置平滑时间常数,控制音频数据的平滑程度
29
30// 设置音频属性
31audio.type = "audio/mp3"; // 设置音频类型
32audio.crossOrigin = "anonymous"; // 设置跨域属性,允许跨域请求
33audio.volume = .5; // 设置音频音量
34audio.autoplay = true; // 设置音频自动播放
35
36// 当音频可以播放时,执行以下操作
37audio.addEventListener('canplaythrough', () => {
38 // 创建音频源节点
39 const source = audioCtx.createMediaElementSource(audio);
40 // 创建增益节点(用于控制音量)
41 const gainNode = audioCtx.createGain();
42 // 将音频源连接到分析器
43 source.connect(analyser);
44 // 将音频源连接到增益节点
45 source.connect(gainNode);
46 // 将增益节点连接到音频上下文的输出(通常是扬声器)
47 gainNode.connect(audioCtx.destination);
48
49 // 创建一个数组来存储频率数据
50 const dataArray = new Uint8Array(analyser.frequencyBinCount);
51 // 调用可视化函数,开始渲染音频可视化效果
52 visualize(dataArray);
53})
54
55// 可视化函数,用于渲染音频的 ASCII 艺术效果
56function visualize(dataArray) {
57 // 获取当前频率数据
58 analyser.getByteFrequencyData(dataArray);
59 // 初始化四个颜色的 ASCII 字符串
60 let fuschia = "", orange = "", yellow = "", green = "",
61 index = 0, adjustValue = -40, multiplier = 1.08, offset = 1;
62
63 // 遍历频率数据,生成 ASCII 字符
64 for (i = 0; i < 32; i++) {
65 // 计算当前字符的索引,把当前频率数据映射到字符集范围中
66 index = Math.max(dataArray[~~offset + i] + adjustValue >> 3, 0);
67 offset *= multiplier; // 调整偏移量
68 adjustValue += 1.5; // 调整值
69 multiplier += .01; // 调整乘数
70 // 根据索引从字符集中选择字符
71 fuschia += " _.-•:*^º'"[index];
72 orange += " _.-•:*^º' "[index];
73 yellow += " _.-•:*^º' "[index];
74 green += "_.-•:*^º' "[index];
75 }
76
77 // 将生成的 ASCII 字符显示在页面上
78 F.innerText = fuschia;
79 O.innerText = orange;
80 Y.innerText = yellow;
81 G.innerText = green;
82
83 // 使用 requestAnimationFrame 递归调用 visualize 函数,实现动态效果
84 requestAnimationFrame(() => visualize(dataArray));
85}可视化效果
在 visualize 函数中,我们通过分析音频的频率数据,动态生成 ASCII 字符并将其显示在页面上。每个 <span> 元素对应不同的颜色和字符集,从而在页面上呈现出动态的视觉效果。
总结
通过这个项目,我们成功复现了 musicforprogramming.net 的音乐可视化效果。这个项目不仅展示了如何使用 Web Audio API 处理音频数据,还展示了如何通过 JavaScript 和 HTML 实现动态的视觉效果。希望这篇文章对你有所帮助,欢迎在评论区分享你的想法和改进建议。
你可以访问 GitHub 仓库 查看完整的代码和效果展示。
Happy coding! 🎵