HN 日本語サマリー

← 一覧へ戻る
科学・技術

Waveloop: Fableが私に残したもの

Waveloop: What Fable left me (neynt.ca)

98 pointsby personjerry39 コメント

要約

この記事は、著者がFable 5というAIツールを使って作成した音楽ビジュアライザー「Waveloop」について紹介しています。Waveloopは、西洋音楽理論の基礎である12平均律に基づいて、音のハーモニーとメロディ構造を視覚的に表現するツールです。音楽のピッチクラスを円形の積み重ねヒストグラムで表示し、音程を角度として、コードの性質を形状として認識できる画期的なビジュアライザーとなっています。また、Fableが生成したコードの密度の高さや、その「文学的」なスタイルについても考察されています。

全文翻訳

waveloop: Fableが私に残したもの Fable 5があった2日間で、それは私に音楽ビジュアライザーを作ってくれました。これは、私が記憶している限りずっと夢見てきたことの実現です。 ここで見ることができます: Waveloop そのアイデアは、音楽ビジュアライザーが音楽のハーモニーとメロディ構造を内臓的に明らかにすべきだということです。ほとんどのビジュアライザーはこれを達成できません—曖昧な音量感と、おそらく低音/高音の分離しか得られません。 どうすればもっと良くできるでしょうか?ご存知のように、西洋全音階音楽理論の基礎は¹²√2、連続する半音間の周波数比です。(私は他の音律を無視します。それらはすべて12-TETに十分に近いです。)これの12回が次のオクターブに連れて行き、完全に整数オクターブ離れた音は同じピッチクラスにあると見なされます。 Waveloopはこの周期的な構造を半音あたり30°、1オクターブあたり1回転の半音階円で捉えています。音楽の任意の瞬間は、各ピッチクラスがどれだけ存在するかを示すらせん状の積み重ねヒストグラムとして捉えられます。ヒストグラムのレイヤーは異なるオクターブを捉える異なる色です:低音にはくすんだ青と緑、中音には燃えるようなオレンジ、赤、紫、高音にはきらめく金と空の色で、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がなくなって約1週間が経ち、かつて何があったかを思い出すために、waveloopのコードをいくつか見てみました。 最初に驚いたのは、その密度の高さです。以前のモデルは、FAANGの完璧に合理的な昇進志向のエンジニアがL5に昇進するまで着実に昇進していくかのようにコードを書いていましたが、このモデルはテリー・デイヴィスが彼の部屋で一人でコードを書いたであろう方法に似ています。 waveloopファイルの先頭にあるこのコメントを見てください。それは、書かれたばかりのコードを明白な言葉で説明するために言葉を浪費していません。コメントは、意図を最大限に情報密度の高い記録として、残りのコードが原理的に導き出せるロックファイルのように見えます。 /* The visualizer is a pitch-class wheel: angle = fract(log2(f / 440)), so every octave of a note lands on the same spoke (A at 12 o'clock, ascending clockwise). The CPU keeps ~5 seconds of per-register-band emission history and rasterizes it every frame into the RGBA radial trail map sampled here (REGS vertically stacked blocks, T axis = radius; rgb = premultiplied register color with fade baked in, a = faded energy): each history row sits at the radius its own stored amplitude has carried it to, so motion is amplitude-driven - the loudest components shoot across the whole window while quiet accompaniment and noise linger near the ring, and the main line visually outruns everything else (see rasterTrails below). Color is continuous Oklch, computed CPU-side per FFT bin (hue encodes absolute frequency on a log scale, red at 20 Hz to violet at 20 kHz; lightness climbs the register axis - dark bass, fully saturated mids around common fundamentals, pale sparkly treble). Display energies live in 0..EMAX (loud fundamentals overshoot 1 instead of clipping at the old AGC ceiling); the trail map stores sqrt(v / EMAX) in alpha (and rgb premultiplied by that encoded alpha) so the u8 texture keeps low-end precision while carrying the extra headroom. Because the bands stay separate all the way to the screen, a pitch class sounding in several octaves renders as a stacked histogram on the rim (low register innermost), with color gliding continuously through the register ramp up the stack (u_rim carries the inverse CDF of each angle's register distribution) instead of cutting between a few band colors; register lives in the stack position and hue, never in the speed. The field extends past the farthest screen corner, and radius is a concave function of age, so material surges off the rim and decelerates as it drifts outward. */ 文章は非常に技術的です。このモデルは、その知識のすべてを活用することをためらいません。アルファ乗算と基本周波数を同じ息でさりげなく言及しています。頭字語を好みます。CDF、FFT、AGC。私はほとんどついていけません。 文章はまた文学的です。それは12の音楽のピッチクラスを時計の12の目盛りになぞらえています。ノイズは残ります。物質は縁から湧き出ます。Fableは、言いたいことを簡潔かつ鮮やかに捉えるために、その語彙のすべてを使うことをためらいません。 以下は、コード検出のための関数です。これは完全に堅実に見え、そのコードの少なさに驚かされます。 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; // too much energy outside the chord tones return { name: NOTE_NAMES[best.root] + best.q.name, root: best.root, pcs: best.q.ivs.map((iv) => (best.root + iv) % 12), }; } Fableには説明ビデオも作ってもらいました。 これは3つのプロンプトでした。最初のプロンプトはこれでした: ok fuck it let's ball. let's also make a manim-based video explaining the mathematical principles behind waveloop, building up from basic "music theory from first principles" all the way to fft, cqt, all that dsp, the circular stacked histogram, oklch... i think we should have a tts plugin that lets you voice it over. そしてそれは、もちろんひどいものでした。しかし、このフィードバックを提供した後: ok let's iterate on that video. - one: the voiceover is atrocious. toebeans has a tts server making use of qwen3-tts-voicedesign -- please use a similar sorta thing to narrate the video in the configured voice. - there's a lot of very loud noise that punctuates the narration. not sure why. - let's make far more use of generated sounds that correspond with the visuals on screen. - let's spend far less time on the very basics and dig a bit more into detail about the particulars of the more sophisticated math. - make the script more conversational. make it feel like you're talking to a friend, or watching a 3blue1brown or 2swap video. - the key, and admittedly difficult: don't belabor any individual point to try to cram facts into the watcher's head, but make it feel like the user could have discovered this all themselves. - use far less text in the video. make very interesting and illustrative visuals to make up for the lack of text. this isn't a slideshow