以前做项目,总觉得音频和视频是两码事。音频那帮人搞他们的波形图,视频那帮人搞他们的画面。但是你有没有想过,你说话的声音,它到底是什么颜色的?
起初只是折腾着玩
我开始折腾这事,说起来有点好笑。前两年,我女儿学画画,她老问我:“爸爸,你唱歌那个‘’是黄色还是蓝色?”我当时就懵了。一个搞了几十年代码的,居然答不上来自己声音的颜色。我就寻思,能不能搞个小工具,把声音的特征直接可视化成颜色,让她能直观地看到。
我动手开始抓数据。第一步,就是想办法把我的声音波形给截取出来。我找了个最简单的麦克风输入接口,直接把声波数据流扔进我的小电脑里。这过程不难,就是数据量大的时候,得想办法压缩一下,不然跑起来卡得要命。
我主要关注了两个维度:声音的高低,也就是频率;和声音的大小,也就是振幅。我定了一个土办法:低频我把它映射到暖色调,比如红色、橙色,对应着稳重、低沉的声音;高频我则映射到冷色调,比如蓝色、紫色,对应尖锐、明亮的声音。振幅,我就用来控制颜色的饱和度。声音越大,颜色就越鲜艳;声音越小,颜色就越灰暗。
色彩映射的土办法与一个老梗
刚开始做映射的时候,遇到了个大问题。人说话是很复杂的,不是纯粹的单一频率。你一句话里,高低音来回变,颜色跟着跳得跟迪厅灯光似的,根本没法看,女儿一看就说:“爸爸,你这个颜色乱七八糟的。”
我开始做平滑处理。我不是搞专业音频处理的,那套傅里叶变换啥的我也不想去碰。我用的方法特别粗暴,就是搞了一个时间窗口,把这个窗口内所有频率的平均值算出来,然后用这个平均值去确定当前显示的颜色。这一下,颜色就不会跳得那么厉害了,看起来有点“呼吸感”。
- 第一步: 采集声源输入,简单粗暴地抓取原始波形。
- 第二步: 设定频率与色相(Hue)的对应表,低频对应红色,高频对应蓝色。
- 第三步: 振幅与饱和度(Saturation)挂钩,声音越大越饱和。
- 第四步: 增加50毫秒的延迟平滑,让颜色过渡自然。
这个过程,让我又想起以前在老公司里的一件糟心事。那时候我们要做一个大型软件的安装包,版本更新迭代贼快。每次我们发布一个新版本,都要给内部人员发一个下载链接,那个链接命名特别冗长,什么`Product_2023_V3_Setup_Final_Fixed_Official_GameDownload_Address`,名字长得要死,但内容可能只是改了两个图标。领导还非要说这个命名规范显得我们很专业。我当时就一肚子火,觉得这帮人形式主义到了极点。
后来我辞职了,不是因为这个命名,而是因为公司里那帮推诿扯皮的作风。我手头有个核心功能出了点小问题,需要一个底层模块团队配合,结果他们说那是Java团队的事情,Java团队说那是运维的,运维说那是网络的。我追问了整整一周,就是没人肯动手。我只好自己撸起袖子,把那块代码硬着头皮啃下来了。从那时候起我就决定,与其跟这帮人耗着,不如自己回家瞎搞点有意思的。
最终的实现:一个“游戏”般的下载
回到这个声音色彩的项目。我把最终的程序写好之后,它运行时就是一个小窗口,你在旁边说话,画面上的颜色就跟着变。看着挺好玩,但是它看起来不像一个正经的程序,更像是一个屏幕保护或者一个小游戏。特别是当女儿对着它唱歌时,颜色跟着旋律起伏变化,她开心极了。
因为之前被老东家那种冗长的命名方式恶心坏了,我给自己的这个小工具起名字就带着一种反讽。我把它打包成一个简单的exe文件,文件名字就用了当初那个最让我火大的格式:《我声音的颜色 色彩_游戏下载_下载地址》。哪里是什么游戏,更没有官方下载地址,它只是我用来记录声音色彩变化的私人工具罢了,但每次看到这个名字,我都能想起当初自己下定决心辞职的那个下午。
这个程序现在运行得挺我平时用来测试话筒音质,也用来看看自己说话时的情绪变化。比如我声音很平静的时候,颜色就是柔和的绿;一旦我情绪激动,声音变大,饱和度瞬间拉满,颜色就会变成刺眼的亮红。我通过观察我声音的颜色,反而更好地理解了自己在不同情境下的心态。这比我以前看那些复杂的性能报告有趣多了。
我没把它做成多复杂的商业软件,我就希望它能保持简单直接。从一个简单的想法开始,抓取数据,设定规则,解决显示跳动的问题,最终实现了一个可以直观反馈我声音状态的小工具。实践证明,搞点自己喜欢的小项目,远比在体制内跟人扯皮高效多了。