news 2026/8/23 17:00:31

数组值如何变成声波?Visual Sorting的Web Audio声音引擎实现深度剖析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
数组值如何变成声波?Visual Sorting的Web Audio声音引擎实现深度剖析

数组值如何变成声波?Visual Sorting的Web Audio声音引擎实现深度剖析

【免费下载链接】visual-sorting🔮 🔈 Visual Sorting (aka "The Sound Of Sorting") is a tool that provides a visualization of sorting algorithms, accompanied by an auditory experience.项目地址: https://gitcode.com/gh_mirrors/vi/visual-sorting

Visual Sorting(又名 The Sound Of Sorting)是一款排序算法可视化工具:它把数组中的每个值画成一根柱子,并让算法"碰"到的柱子发出对应音高——值越大,声音越尖。整副"声音魔法"其实只用了不到 50 行基于 Web Audio API 的代码,本文带你拆解这套声音引擎的完整实现原理。

一、为什么排序可以"听起来"?

传统教学里,我们靠眼睛观察柱子的移动来理解排序过程。而 Visual Sorting 借鉴了经典视频The Sound of Sorting的创意:把数组值映射到音频频率,让耳朵参与观察。

这样做的直观好处是:

  • 🎵 听到连续低音符,说明算法在处理小区间;
  • 📈 听到"刮玻璃"式的高频滑音,说明它在跨大步长扫描;
  • 🏁 排序快结束时,音符逐渐单调上扬——你"听"到了数组变有序。

整个功能由一条清晰的数据流驱动,下面逐层拆解。

二、声音引擎本体:只有 50 行的 sound.ts

核心实现全部集中在 sound.ts 中,对外只暴露 3 个函数:

函数职责关键代码位置
soundStart(size, name)启动振荡器,计算频率步长sound.ts#L17-L30
soundStop()停止并断开振荡器sound.ts#L32-L43
playValue(value)把数组值换算成频率并即时发声sound.ts#L45-L50

引擎设计上有两个要点:

  1. 全局单例AudioContext。浏览器限制同一页面并发 AudioContext 数量,且排序全程只需要一条音频流,因此 sound.ts#L9 在模块加载时就用new AudioContext()创建唯一上下文,并仅在浏览器环境创建(SSR 渲染时自动跳过)。
  2. 一个持续运转的振荡器,而不是每个值建一个新振荡器。如果每次访问数组元素都新建振荡器,会产生大量杂音和性能开销;这里采用"长鸣 + 改频率"策略——振荡器一直响,每次只改写它的frequency参数。

三、值到频率:一条线性映射公式

"数组值如何变成声波"的答案,就藏在两个常量与一行公式里。

1. 划定可听频段(sound.ts#L14-L15):

  • minFrequency = 10 Hz:最低音下限
  • maxFrequency = 1500 Hz:最高音上限

选择 1500 Hz 而不是更高,是为了把音调控制在人耳对频率差异分辨力最好的中低频段,避免尖锐刺耳。

2. 启动时计算步长(sound.ts#L25):

freqStepSize = maxFrequency / size

以默认 300 根柱子为例,步长约为 5 Hz——每增大 1 个数组值,音高上升约 5 Hz。

3. 发声时的映射(sound.ts#L49):

frequency = freqStepSize × (value − 1) + minFrequency

这就是一条从[1, size][10 Hz, 1500 Hz]线性映射:数组里的最小值 1 发出 10 Hz 的低沉嗡鸣,最大值size发出接近 1500 Hz 的高音。柱子越高,音调越高,视觉与听觉在此刻完全对齐。

四、算法如何"告诉"引擎该发什么音

如果引擎只负责发音,那么"什么时候发、发什么音"由谁决定?答案是排序算法本身

每个算法(如 bubble-sort.ts)都是一个 JavaScript 生成器函数,每一步yield一个 ProgressIndicator 结构:

  • access:本步骤访问了哪些下标(用于界面高亮);
  • sound哪根柱子应该发声(关键!);
  • comparisons / swaps / accesses:统计增量(顶部实时指标)。

以冒泡排序为例,每次比较arr[j]arr[j+1]时都会yieldsound: j + 1(bubble-sort.ts#L17-L23),意思是"把j+1位置柱子的值念出来"。

SortPanel.svelte 的tick()方法每走一步就检查这个字段,若存在且当前有音色启用,便调用playValue(workingArray[next.value.sound])(SortPanel.svelte#L55-L61)。

这一层解耦非常漂亮:算法只声明"语义"(我碰了哪个位置),引擎负责"物理"(换算频率、驱动扬声器)。想给新算法加声音,只需在 yield 里带上sound字段,一行都不用改音频代码。

五、24 种音色:web-audio-oscillators 与界面控制

"值→频率"解决的是音调,而音色(正弦、方波、锯齿……)则由开源库web-audio-oscillators提供(见 package.json)。

  • 界面右上角的音色下拉菜单(HeaderSoundControl.svelte)直接遍历库导出的customOscillatorTypes,共24 种振荡器可选,无需手写任何波形代码;
  • 选择结果通过savePref持久化到本地存储,刷新页面后依然保留,默认为triangle(三角波);
  • 按键盘M可一键静音——静音的实现其实就是把oscillatorType置为null,引擎会自动停止振荡器。

还有一个细节:在对比模式(两个算法同屏赛跑)下,只有 A 面板发声。因为全站共享唯一的 AudioContext,两个振荡器同时写入会互相"打架"产生和声干扰(参见 +page.svelte#L218-L222 中的注释说明)。

六、几个值得一提的工程细节

  1. 双停止保护:Web Audio 对已停止的振荡器再次调用stop()会抛InvalidStateErrorsoundStop()try/catch兜底(sound.ts#L36-L40),保证 Start/Stop 快速连点也不会报错。
  2. 启动即清理soundStart内部先执行soundStop()(sound.ts#L26),避免新旧振荡器叠加。
  3. 单步模式延时关闭:点击 Step 单步执行时,声音会在 100 ms 后自动停止(+page.svelte#L248-L252),让每一声短促清脆,便于逐步分析。
  4. 响应式开关:主页面用 Svelte 响应式语句$running && oscillatorType ? soundStart(...) : soundStop()(+page.svelte#L208-L210),排序状态一变,音频自动跟着启停。

七、动手体验

如果想亲自调试这套声音引擎,克隆仓库后本地启动即可:

git clone https://gitcode.com/gh_mirrors/vi/visual-sorting cd visual-sorting npm install npm run dev

打开页面后建议试试:选Bubble Sort+None/Triangle音色对比、把 Array size 调小(如 30)放慢速度,你能清晰地"听"出每次比较落在哪根柱子上——这正是这套 50 行 Web Audio 声音引擎想要传达的:把抽象的数组操作,翻译成耳朵也能读懂的信号

【免费下载链接】visual-sorting🔮 🔈 Visual Sorting (aka "The Sound Of Sorting") is a tool that provides a visualization of sorting algorithms, accompanied by an auditory experience.项目地址: https://gitcode.com/gh_mirrors/vi/visual-sorting

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/23 16:48:55

HyperRogue的20+种几何投影全解析:从圆盘到鱼眼的渲染秘密

HyperRogue的20种几何投影全解析:从圆盘到鱼眼的渲染秘密 【免费下载链接】hyperrogue A SDL roguelike in a non-euclidean world 项目地址: https://gitcode.com/gh_mirrors/hy/hyperrogue HyperRogue 是一款运行在非欧几里得(双曲)…

作者头像 李华
网站建设 2026/8/23 16:37:13

帧缓存还是管道直传?timecut 两种帧传输模式详解与选型指南

帧缓存还是管道直传?timecut 两种帧传输模式详解与选型指南 【免费下载链接】timecut Node.js program to record smooth movies of web pages with JavaScript animations 项目地址: https://gitcode.com/gh_mirrors/ti/timecut timecut 是一个能把网页 Jav…

作者头像 李华