Waveloop: Fable留给我的

Hacker News Top 工具

摘要

作者回顾了使用AI模型Fable 5创建Waveloop的过程,这是一款音乐可视化工具,通过半圆环展示和声与旋律结构。它利用颜色和角度来表示音高类别和音程,并支持离线模式与实时麦克风模式。

暂无内容
查看原文
查看缓存全文

缓存时间: 2026/06/30 21:39

# waveloop:fable留给我的遗产 来源:https://neynt.ca/writing/waveloop/ 在拥有Fable 5的那两天里,它把我变成了一个音乐可视化工具。这是我从记事起就一直梦想的事情。 你可以在这里看到:Waveloop (https://saltblock.neynt.ca/waveloop.html) --- 这个想法是:一个音乐可视化工具应该能直观地揭示音乐的和谐与旋律结构。大多数可视化工具都做不到这一点——你只能得到一种模糊的响度感,最多能区分低音和高音,仅此而已。我们怎样才能做得更好?众所周知,西方大小调音乐理论的基础是12√2,即连续半音之间的频率比。(我忽略了其他调律体系,它们都足够接近十二平均律。)十二个这样的半音带你到下一个八度,而相隔整数个八度的音符被认为属于相同的音高类别。 Waveloop在色环上捕捉了这种循环结构:每个半音30°,每旋转一周就是一个八度。音乐中的任何一个瞬间都被捕捉为一个螺旋堆叠的直方图,显示每个音高类别的能量分布。直方图的每一层使用不同颜色来表示不同八度:低音区用柔和的蓝绿色,中音区用火焰般的橙色、红色和紫色,高音区用闪亮的金色和天蓝色,沿着oklch色彩空间螺旋上升。 这种表示法有几个很好的特性: **你可以直接通过角度来读取音程。** 以下是音程: - **m2** 30° - **M2** 60° - **m3** 90° - **M3** 120° - **P4** 150° - **TT** 180° - **P5** 210° - **m6** 240° - **M6** 270° - **m7** 300° - **M7** 330° **你可以从和弦的形状判断其性质。** 移调会旋转形状,转位则不改变它。以下是几种常见和弦性质: - **maj** 0 · 4 · 7 - **min** 0 · 3 · 7 - **dim** 0 · 3 · 6 - **aug** 0 · 4 · 8 - **sus4** 0 · 5 · 7 - **sus2** 0 · 2 · 7 - **dom7** 0 · 4 · 7 · 10 - **maj7** 0 · 4 · 7 · 11 - **min7** 0 · 3 · 7 · 10 Waveloop主要工作在离线模式下,它会预先计算特定曲目的CQT,但Fable也给了我一个实时麦克风模式。当我打开它时,我发现它能相当快速可靠地识别我弹奏的尤克里里和弦。 --- 我们失去Fable大约一周了。为了提醒自己曾经拥有的是什么,我看了看一些waveloop代码。首先让我印象深刻的是它非常**紧凑**。之前的模型写代码时就像一个FAANG里理性上进的工程师,正稳步晋升直到止步于L5级别;而这个模型的写作风格更像是我想象中Terry Davis独自在房间里写代码的样子。看看waveloop文件顶部这段注释。它毫不废话地描述了刚刚写出的代码。这些注释更像是信息密度最大化的意图记录,就像锁文件一样,从中原则上可以推导出其余代码。 ```c /* 可视化工具是一个音高类轮盘:角度 = fract(log2(f / 440)),这样每个音符的每个八度都落在同一根辐条上(A在12点钟方向,顺时针上升)。 CPU保持大约5秒的每个寄存器频段的发射历史,并在每一帧将其光栅化为在此采样的RGBA径向轨迹图(REGS垂直堆叠的块,T轴=半径;rgb = 预乘的寄存器颜色,并内置衰减,a = 衰减能量): 每一行历史记录位于其自身存储振幅所携带到的半径处,因此运动是由振幅驱动的——最响的成分会穿过整个窗口,而安静的伴奏和噪声则停留在环附近,主旋律在视觉上领先于其他所有东西(参见rasterTrails)。 颜色是连续的Oklch,在CPU端每个FFT频段计算(色相以对数刻度对绝对频率进行编码,20 Hz为红色,20 kHz为紫色;明度沿寄存器轴上升——低音暗色,中音在常见基频附近全饱和,高音淡而闪亮)。 显示能量范围在0..EMAX之间(响亮的基频会过冲1而不是在旧的AGC上限处削波);轨迹图将sqrt(v / EMAX)存储在alpha中(rgb预乘该编码后的alpha),以便u8纹理在保持低端精度的同时携带额外的动态余量。 由于频段一直保持分离直到屏幕,同时在不同八度发声的音高类会在轮缘上呈现为堆叠直方图(低音寄存器在最内侧),颜色通过寄存器斜坡连续滑动(u_rim携带每个角度的寄存器分布的逆CDF),而不是在几个频段颜色之间切换;寄存器存在于堆叠位置和色相中,而不是速度中。 场延伸到屏幕最远角落之外,半径是年龄的凹函数,因此物质从轮缘涌出,并在向外漂移时减速。 */ ``` 这段文字非常技术性。这个模型毫不避讳地运用它所有的知识。它随口就提到alpha预乘和基频。它喜欢使用缩写词:CDF、FFT、AGC。我几乎跟不上。文笔也很有文学性。它将12个音高类别类比为钟面上的12个刻度。噪音会“**徘徊**”。物质从轮缘“**涌出**”。Fable不惧怕使用它的全部词汇来紧凑而生动地表达它想说的任何内容。 下面是它的和弦检测函数。看起来相当扎实,而且令人惊讶的是代码量很少。 ```javascript const NOTE_NAMES = ['A', 'A#', 'B', 'C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#']; const QUALITIES = [ { name: '', ivs: [0, 4, 7] }, { name: 'm', ivs: [0, 3, 7] }, { name: 'dim', ivs: [0, 3, 6] }, { name: 'aug', ivs: [0, 4, 8] }, { name: 'sus4', ivs: [0, 5, 7] }, { name: 'sus2', ivs: [0, 2, 7] }, { name: '7', ivs: [0, 4, 7, 10] }, { name: 'maj7', ivs: [0, 4, 7, 11] }, { name: 'm7', ivs: [0, 3, 7, 10] }, ]; function detectChord() { let total = 0; for (let i = 0; i < 12; i++) total += chroma[i]; chromaAgc = Math.max(chromaAgc * 0.995, total, 1e-6); if (total < 0.15 * chromaAgc || chromaAgc < 1e-3) return null; const c = new Array(12); for (let i = 0; i < 12; i++) c[i] = chroma[i] / total; let best = null, bestScore = 0; for (let root = 0; root < 12; root++) { for (const q of QUALITIES) { let inS = 0; for (let k = 0; k < q.ivs.length; k++) { inS += c[(root + q.ivs[k]) % 12] * (k === 0 ? 1.15 : 1); } const score = inS / Math.pow(q.ivs.length, 0.55); if (score > bestScore) { bestScore = score; best = { root, q }; } } } if (!best) return null; let frac = 0; for (const iv of best.q.ivs) frac += c[(best.root + iv) % 12]; if (frac < 0.5) return null; // 和弦音之外能量太多 return { name: NOTE_NAMES[best.root] + best.q.name, root: best.root, pcs: best.q.ivs.map((iv) => (best.root + iv) % 12), }; } ``` --- 我还让Fable制作了一个讲解视频。**这用了三条提示**。我的第一条提示是这样的: ``` 好吧不管了,开干吧。我们还要制作一个基于manim的视频,解释waveloop背后的数学原理,从最基础的“第一性原理音乐理论”开始,一直讲到FFT、CQT、所有DSP、圆形堆叠直方图、oklch……我觉得应该有一个TTS插件让你给视频配音。 ``` 结果当然是垃圾。但在我给出以下反馈之后: ``` 好吧,我们来迭代那个视频。 - 一:配音糟糕透顶。toebeans有一个使用qwen3-tts-voicedesign的TTS服务器——请用类似的东西以配置好的声音来旁白。 - 二:旁白中穿插了很多非常刺耳的噪音,不知道为什么。 - 三:更多地使用与屏幕视觉对应的生成音效。 - 四:少花时间在非常基础的内容上,多深入一些更复杂的数学细节。 - 五:让脚本更口语化。感觉就像在跟朋友聊天,或者在看3blue1brown或2swap的视频。 - 六:关键且困难的是:不要在每个点上都啰嗦地给观众灌输事实,而要让你感觉用户自己也能发现这一切。 - 七:视频中少用文字。用非常有趣且说明性的视觉来代替文字。这不是幻灯片。文字只应该作为图表的一部分出现,而不是重复旁白已经解释过的东西。 ``` 我们得到了上面你看到的那个视频——大体上是这样的。我又跟进了一个清理请求: ``` 这好多了。让我们对数学使用正确的排版,通过生成一个VoiceDesign样本来保持一致的说话声音(或者你用qwen tts做这件事的方式),并确保我们的图表不会重叠。 ``` 就这样。是的,它仍然不是一个出色的视频。但在我第一次看的时候,它足够吸引人,让我看完了整整十分钟。 --- AI使用声明:我使用了Claude来生成图表的SVG。但所有文字都是我自己写的。

相似文章