From 8fef43e752acf94d5094681cea6b8e579e60ee59 Mon Sep 17 00:00:00 2001 From: PSheon Date: Wed, 23 Sep 2026 10:47:29 +0800 Subject: [PATCH 1/7] fix(pwa): never answer a worker's own script from the cache MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Turbopack hands a worker its chunk list in the script URL's fragment (`/_next/static/chunks/turbopack-worker-….js#params=…`). A fragment is not part of a Request, so answering one from the service worker's asset cache loses it and the worker dies on the first line with "Missing worker bootstrap config". In a production build with the service worker in control, that killed every worker on the site: the diffusion model, the head camera's training, the path tracer's scene builder. Worker scripts now go straight to the network. Found while adding article 014, whose figures are three workers; `e2e/music-ai.spec.ts` covers it. Co-Authored-By: Claude Opus 5 (1M context) --- public/sw.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/public/sw.js b/public/sw.js index 5936854..1c5bac9 100644 --- a/public/sw.js +++ b/public/sw.js @@ -97,5 +97,9 @@ self.addEventListener("fetch", (event) => { const { request } = event, url = new URL(request.url); // Only our own GETs. Vercel's analytics endpoints and anything cross-origin go straight to the network. if (request.method !== "GET" || url.origin !== self.location.origin || url.pathname.startsWith("/_vercel/")) return; + // A worker's own script goes straight to the network, never through a cache. The bundler hands a worker its chunk + // list in the URL's fragment (`…/turbopack-worker-…js#params=…`), and a fragment is not part of a Request: answering + // one from here loses it, and every worker on the site dies with "Missing worker bootstrap config". + if (request.destination === "worker" || request.destination === "sharedworker") return; event.respondWith(isAsset(url) ? cacheFirst(request) : networkFirst(request)); }); From f74303ec80488ab08a555fbd9665f64879500be3 Mon Sep 17 00:00:00 2001 From: PSheon Date: Wed, 23 Sep 2026 10:47:47 +0800 Subject: [PATCH 2/7] feat(music-ai): Bach's chorales as tokens, and a Transformer that writes them MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The model is lib/ml's Transformer again (the one № 004 builds), 64,704 parameters: 56 words, a 16-step window, two layers. A chorale becomes one token per voice per eighth note — a pitch, HOLD or REST — so writing music is writing the next word. Beside it: what a piece is measured by (in key, voice crossings, parallel fifths, held notes, chord variety), a copy detector against the training set, the five-line rules composer, and DPO for the preference figure. Data: Craig Sapp's edition of Bach's 370 four-part chorales, CC BY-NC-SA 4.0, moved to C major or A minor, 333 to train on and 37 kept back. scripts/music rebuilds both .bin files byte for byte from the corpus clone and a checkpoint; the corpus and the runs live outside git (docs/research/music-ai). Co-Authored-By: Claude Opus 5 (1M context) --- content/posts/music-ai/components/music.ts | 278 +++++++++++++++++++++ public/posts/music-ai/chorales.bin | Bin 0 -> 159152 bytes public/posts/music-ai/judge.bin | Bin 0 -> 258816 bytes scripts/music/convert.py | 56 +++++ scripts/music/pack.ts | 56 +++++ 5 files changed, 390 insertions(+) create mode 100644 content/posts/music-ai/components/music.ts create mode 100644 public/posts/music-ai/chorales.bin create mode 100644 public/posts/music-ai/judge.bin create mode 100644 scripts/music/convert.py create mode 100644 scripts/music/pack.ts diff --git a/content/posts/music-ai/components/music.ts b/content/posts/music-ai/components/music.ts new file mode 100644 index 0000000..d825a9c --- /dev/null +++ b/content/posts/music-ai/components/music.ts @@ -0,0 +1,278 @@ +import { Adam, Mat, Tape, Transformer, type Rng, type TransformerConfig } from "@/lib/ml"; + +/* + * Music as tokens, a Transformer that composes, and what we measure about what it writes. The recipe and every number + * the article quotes come from docs/research/music-ai (run B: d 48, 2 layers, a 16-step window). + * + * A chorale is a grid of eighth notes. Each step has four voices, soprano to bass, and each voice-step is one token: + * a new note is its pitch, a held one HOLD, silence REST. So the model writes S A T B, S A T B, … and knows which voice + * is next only from its position: windows must always start on a soprano. + */ +export const LO = 31, HI = 84; +export const HOLD = HI - LO + 1, REST = HOLD + 1, VOCAB = REST + 1; +export const VOICES = 4; +export const STEPS_IN_WINDOW = 16; +export const CONFIG: TransformerConfig = { vocab: VOCAB, ctx: STEPS_IN_WINDOW * VOICES, d: 48, heads: 4, layers: 2 }; +/** Every composition starts from the same C major chord: C5 G4 E4 C3. */ +export const PROMPT = [72 - LO, 67 - LO, 64 - LO, 48 - LO]; +/** The 5-gram's validation loss on the same split (nats per token): the line the Transformer has to cross. */ +export const NGRAM_LOSS = 1.462; + +export interface Piece { pitches: number[][]; onset: number[][] } + +/** chorales.bin: u16 train count, u16 validation count, u16 length per chorale, then one byte per token. */ +export function parseChorales(buffer: ArrayBuffer): { train: number[][]; val: number[][] } { + const view = new DataView(buffer), bytes = new Uint8Array(buffer); + const nTrain = view.getUint16(0, true), nVal = view.getUint16(2, true), all: number[][] = []; + let at = 4 + 2 * (nTrain + nVal); + for (let i = 0; i < nTrain + nVal; i++) { + const len = view.getUint16(4 + 2 * i, true); + all.push(Array.from(bytes.subarray(at, at + len))); + at += len; + } + return { train: all.slice(0, nTrain), val: all.slice(nTrain) }; +} + +/** Tokens back to what sounds: the pitch of each voice at each step (−1 silent), and whether it starts there. */ +export function decode(ids: ArrayLike): Piece { + const pitches: number[][] = [], onset: number[][] = [], last = [-1, -1, -1, -1]; + for (let t = 0; t * VOICES < ids.length; t++) { + const p: number[] = [], o: number[] = []; + for (let v = 0; v < VOICES; v++) { + const id = ids[t * VOICES + v]; + if (id === undefined || id === REST) { if (id === REST) last[v] = -1; p.push(-1); o.push(0); } + else if (id === HOLD) { p.push(last[v]); o.push(0); } + else { last[v] = id + LO; p.push(last[v]); o.push(1); } + } + pitches.push(p); onset.push(o); + } + return { pitches, onset }; +} + +/** The context for the next token: the latest ≤ ctx tokens, cut so that it still starts on a soprano. */ +export function context(ids: number[], ctx = CONFIG.ctx): number[] { + return ids.slice(Math.max(0, Math.ceil((ids.length - ctx) / VOICES) * VOICES)); +} + +export function compose(model: Transformer, steps: number, temperature: number, rng: Rng, prompt = PROMPT): number[] { + const ids = [...prompt]; + while (ids.length < steps * VOICES) { + const ctx = context(ids, model.config.ctx); + const { logits } = model.forward(new Tape(), ctx); + const row = logits.data.subarray((ctx.length - 1) * VOCAB, ctx.length * VOCAB); + let max = -Infinity; + for (const x of row) max = Math.max(max, x); + const p = Array.from(row, (x) => Math.exp((x - max) / temperature)); + let u = rng() * p.reduce((a, b) => a + b, 0), k = 0; + while (u > p[k] && k < p.length - 1) u -= p[k++]; + ids.push(k); + } + return ids; +} + +/** A random training window of one context plus one token, starting on a step boundary. */ +export function window(pool: number[][], rng: Rng, ctx = CONFIG.ctx): number[] { + const seq = pool[Math.floor(rng() * pool.length)]; + const steps = seq.length / VOICES, len = Math.min(ctx + VOICES, seq.length); + const start = Math.floor(rng() * Math.max(1, steps - len / VOICES + 1)) * VOICES; + return seq.slice(start, start + len); +} + +/** Next-token training: Adam, lr 3e-3 with a 100-step warm-up and a cosine decay to a tenth, batches of 8. */ +export class Composer { + readonly model: Transformer; + private readonly adam: Adam; + step = 0; + + constructor(private readonly train: number[][], private readonly rng: Rng, readonly steps: number, weights?: Float32Array) { + this.model = new Transformer(CONFIG, rng); + if (weights) load(this.model, weights); + this.adam = new Adam(this.model.params); + } + + /** One optimiser step. Returns the batch's mean loss in nats per token. */ + learn(batch = 8, lr = 3e-3): number { + this.model.zeroGrad(); + const tape = new Tape(); + let loss = 0; + for (let b = 0; b < batch; b++) { + const w = window(this.train, this.rng); + loss += tape.crossEntropy(this.model.forward(tape, w.slice(0, -1).slice(0, CONFIG.ctx)).logits, w.slice(1, CONFIG.ctx + 1), 1 / batch) / batch; + } + tape.backward(); + const s = this.step++; + this.adam.step(lr * Math.min(1, (s + 1) / 100) * (0.1 + 0.9 * 0.5 * (1 + Math.cos((Math.PI * s) / this.steps)))); + return loss; + } +} + +/** Mean loss on fixed validation windows (the same ones every time, so the curve is comparable with itself). */ +export function validate(model: Transformer, windows: number[][]): number { + let s = 0; + for (const w of windows) s += new Tape().crossEntropy(model.forward(new Tape(), w.slice(0, -1).slice(0, CONFIG.ctx)).logits, w.slice(1, CONFIG.ctx + 1)); + return s / windows.length; +} + +export function load(model: Transformer, weights: Float32Array) { + let k = 0; + for (const p of Object.values(model.params)) for (let i = 0; i < p.data.length; i++) p.data[i] = weights[k++]; +} + +/** + * The opponent with no AI in it: a soprano that walks a C pentatonic scale by 1/f noise (Voss's dice trick — four + * dice rerolled at halving rates, which is how the pitch of real music wanders), over I–vi–IV–V, a bar each. + * It never plays a wrong note and never crosses a voice; the article's numbers say what it pays for that. + */ +export function rulesPiece(steps: number, rng: Rng): Piece { + const scale = [60, 62, 64, 67, 69, 72, 74, 76, 79, 81]; + const chords = [[48, 55, 64], [45, 57, 64], [41, 53, 60], [43, 55, 62]]; // C, Am, F, G: bass, tenor, alto + const dice = [rng(), rng(), rng(), rng()]; + const pitches: number[][] = [], onset: number[][] = []; + let soprano = -1; + for (let t = 0; t < steps; t++) { + if (t % 2 === 0) for (let d = 0; d < dice.length; d++) if (((t / 2) & ((1 << d) - 1)) === 0) dice[d] = rng(); + const chord = chords[Math.floor(t / 8) % chords.length]; + const next = scale[Math.min(scale.length - 1, Math.floor((dice.reduce((a, b) => a + b, 0) / dice.length) * scale.length))]; + const sings = t % 2 === 0 && next !== soprano; + if (sings) soprano = next; + pitches.push([soprano, chord[2], chord[1], chord[0]]); + onset.push([sings ? 1 : 0, ...(t % 8 === 0 ? [1, 1, 1] : [0, 0, 0])]); + } + return { pitches, onset }; +} + +// --------------------------------------------------------------------------------------------------------------- +// What we measure. None of it says "beautiful": it says whether the texture does what four-part writing does. + +/** C major's pitch classes, plus F# and G# (A minor's raised sixth and seventh). Every chorale was moved to C or A minor. */ +const KEY = new Set([0, 2, 4, 5, 7, 9, 11, 6, 8]); + +export interface Report { + /** share of new notes in the key */ + inKey: number; + /** parallel fifths or octaves per 100 steps */ + parallels: number; + /** share of steps where a lower voice is above a higher one */ + crossings: number; + /** share of sounding voice-steps that are held */ + held: number; + /** distinct chords (pitch-class sets) per 100 steps */ + chords: number; +} + +export function report({ pitches, onset }: Piece): Report { + let notes = 0, inKey = 0, parallels = 0, crossings = 0, held = 0, cells = 0; + const chords = new Set(); + for (let t = 0; t < pitches.length; t++) { + const p = pitches[t]; + for (let v = 0; v < VOICES; v++) { + if (p[v] < 0) continue; + cells++; + if (onset[t][v]) { notes++; if (KEY.has(p[v] % 12)) inKey++; } else held++; + } + for (let v = 0; v < VOICES - 1; v++) if (p[v] >= 0 && p[v + 1] >= 0 && p[v + 1] > p[v]) { crossings++; break; } + chords.add(p.filter((x) => x >= 0).map((x) => x % 12).sort((a, b) => a - b).join(",")); + if (t === 0) continue; + const q = pitches[t - 1]; + for (let a = 0; a < VOICES; a++) + for (let b = a + 1; b < VOICES; b++) { + if (p[a] < 0 || p[b] < 0 || q[a] < 0 || q[b] < 0) continue; + const now = (p[a] - p[b]) % 12, before = (q[a] - q[b]) % 12; + const together = p[a] !== q[a] && p[b] !== q[b] && Math.sign(p[a] - q[a]) === Math.sign(p[b] - q[b]); + if (together && now === before && (now === 7 || now === 0)) parallels++; + } + } + const n = pitches.length; + return { inKey: notes ? inKey / notes : 0, parallels: (100 * parallels) / n, crossings: crossings / n, held: cells ? held / cells : 0, chords: (100 * chords.size) / n }; +} + +/** Which training steps (all four voices) sound the same, for finding the longest stretch copied from the chorales. */ +export class CopyFinder { + private readonly index = new Map(); + private readonly pieces: number[][][]; + + constructor(train: number[][]) { + this.pieces = train.map((t) => decode(t).pitches); + this.pieces.forEach((c, ci) => c.forEach((p, t) => { + const k = p.join(","); + const list = this.index.get(k); + if (list) list.push([ci, t]); else this.index.set(k, [[ci, t]]); + })); + } + + /** The longest run of steps in `pitches` that also occurs, in the same order, in one training chorale. */ + longest(pitches: number[][]): { steps: number; chorale: number; at: number; from: number } { + let best = { steps: 0, chorale: -1, at: 0, from: 0 }; + for (let t = 0; t < pitches.length; t++) + for (const [ci, s] of this.index.get(pitches[t].join(",")) ?? []) { + const c = this.pieces[ci]; + let n = 0; + while (t + n < pitches.length && s + n < c.length && c[s + n].join(",") === pitches[t + n].join(",")) n++; + if (n > best.steps) best = { steps: n, chorale: ci, at: s, from: t }; + } + return best; + } +} + +// --------------------------------------------------------------------------------------------------------------- +// Preference tuning (DPO). The reader hears two short pieces and picks one; the model moves toward the pick and away +// from the other, measured against a frozen copy of itself so that it cannot drift far from Bach (β is the leash). + +/** Sum of log-probabilities of the tokens after the prompt, and what crossEntropy needs to push on them. */ +function logProb(model: Transformer, ids: number[], tape: Tape): { value: number; logits: Mat; targets: number[]; count: number } { + const { logits } = model.forward(tape, ids.slice(0, -1)); + const targets = ids.slice(1).map((t, i) => (i + 1 < PROMPT.length ? -1 : t)); + let value = 0, count = 0; + for (let r = 0; r < targets.length; r++) { + if (targets[r] < 0) continue; + const row = logits.data.subarray(r * VOCAB, (r + 1) * VOCAB); + let max = -Infinity; + for (const x of row) max = Math.max(max, x); + let s = 0; + for (const x of row) s += Math.exp(x - max); + value += row[targets[r]] - max - Math.log(s); + count++; + } + return { value, logits, targets, count }; +} + +export class Judge { + readonly policy: Transformer; + private readonly reference: Transformer; + private readonly adam: Adam; + choices = 0; + + /** + * β 0.5 and lr 1e-4 per pick: 20 picks of "more held notes" took held notes from 48 % to 64 % with the validation loss + * unchanged; at 3e-4 the same 20 went to 88 % and the loss rose from 1.195 to 1.257 (docs/research/music-ai). + */ + constructor(weights: Float32Array, private readonly beta = 0.5, private readonly lr = 1e-4) { + this.policy = new Transformer(CONFIG); + this.reference = new Transformer(CONFIG); + load(this.policy, weights); + load(this.reference, weights); + this.adam = new Adam(this.policy.params); + } + + /** Two candidates of one window each (16 steps, 8 seconds at 60 bpm), sampled at temperature 1. */ + pair(rng: Rng): [number[], number[]] { + const n = CONFIG.ctx + 1; + return [compose(this.policy, Math.ceil(n / VOICES), 1, rng).slice(0, n), compose(this.policy, Math.ceil(n / VOICES), 1, rng).slice(0, n)]; + } + + /** One DPO step on one choice: L = −log σ(β[(log π(win) − log π₀(win)) − (log π(lose) − log π₀(lose))]). */ + choose(win: number[], lose: number[]) { + this.policy.zeroGrad(); + const tape = new Tape(); + const pw = logProb(this.policy, win, tape), pl = logProb(this.policy, lose, tape); + const rw = logProb(this.reference, win, new Tape()).value, rl = logProb(this.reference, lose, new Tape()).value; + const z = this.beta * (pw.value - rw - (pl.value - rl)); + const g = this.beta * (1 - 1 / (1 + Math.exp(-z))); + // crossEntropy's gradient is weight × d(mean NLL), and log p = −count × mean NLL. + tape.crossEntropy(pw.logits, pw.targets, g * pw.count); + tape.crossEntropy(pl.logits, pl.targets, -g * pl.count); + tape.backward(); + this.adam.step(this.lr); + this.choices++; + } +} diff --git a/public/posts/music-ai/chorales.bin b/public/posts/music-ai/chorales.bin new file mode 100644 index 0000000000000000000000000000000000000000..00f0365eb9151c0d6bc5a7683182a3892c37a7ab GIT binary patch literal 159152 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≥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

D-aJ3!pY!nl^;~c( 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

-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 Z`j+qTC_0j_h(FrTV<{T?l)txq>%V97+<*W8 literal 0 HcmV?d00001 diff --git a/public/posts/music-ai/judge.bin b/public/posts/music-ai/judge.bin new file mode 100644 index 0000000000000000000000000000000000000000..33e57cd515310ed5c6a9d4659620ea598aff8d44 GIT binary patch literal 258816 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≫Vo8Zn2rnIQQhEnN9N?^q9< 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 an eighth-note grid, one JSON file. +# Clone the corpus first; it is not part of this repo: +# git clone --depth 1 https://github.com/craigsapp/bach-370-chorales +# uv run --with music21 python scripts/music/convert.py [kern dir] [out.json] +# Each chorale is transposed to C major or A minor. A step holds, for S A T B, the MIDI pitch sounding (or -1), +# whether that note starts on this step, and whether a fermata (phrase end) is on it. +import glob, json, math, os, sys +from music21 import converter, interval, pitch, note, expressions + +STEP = 0.5 # quarter lengths: an eighth note +out, skipped = [], [] +KERN = sys.argv[1] if len(sys.argv) > 1 else "bach-370-chorales/kern" +OUT = sys.argv[2] if len(sys.argv) > 2 else "chorales.json" +for path in sorted(glob.glob(f"{KERN}/*.krn")): + name = os.path.basename(path)[:-4] + try: + score = converter.parse(path) + parts = list(score.parts) + if len(parts) != 4: + skipped.append((name, f"{len(parts)} parts")); continue + key = score.analyze("key") + tonic = "C" if key.mode == "major" else "A" + shift = interval.Interval(key.tonic, pitch.Pitch(tonic)) + # Keep transpositions within a tritone so voices stay in their ranges. + if shift.semitones > 6: shift = interval.Interval(shift.semitones - 12) + if shift.semitones < -6: shift = interval.Interval(shift.semitones + 12) + score = score.transpose(shift) + parts = list(score.parts) + # kern lists bass first; order voices top-down by mean pitch to be sure. + def mean(p): + ps = [n.pitch.midi for n in p.recurse().notes if n.isNote] + return sum(ps) / max(1, len(ps)) + parts.sort(key=mean, reverse=True) + length = max(p.highestTime for p in parts) + n = int(math.ceil(length / STEP)) + pitches = [[-1] * 4 for _ in range(n)] + onset = [[0] * 4 for _ in range(n)] + fermata = [0] * n + for v, p in enumerate(parts): + for el in p.flatten().notesAndRests: + if not el.isNote: continue + a = int(round(el.offset / STEP)); b = int(round((el.offset + el.quarterLength) / STEP)) + tied_in = el.tie is not None and el.tie.type in ("continue", "stop") + for t in range(a, min(b, n)): + pitches[t][v] = el.pitch.midi + onset[t][v] = 1 if (t == a and not tied_in) else 0 + if any(isinstance(e, expressions.Fermata) for e in el.expressions) and b - 1 < n: + fermata[max(a, b - 1)] = 1 + ts = score.recurse().getElementsByClass("TimeSignature") + out.append({"id": name, "mode": key.mode, "shift": shift.semitones, "meter": ts[0].ratioString if ts else "4/4", + "pitches": pitches, "onset": onset, "fermata": fermata}) + except Exception as e: # report and go on + skipped.append((name, repr(e)[:80])) +json.dump(out, open(OUT, "w")) +print(len(out), "chorales,", len(skipped), "skipped") +for s in skipped[:20]: print(" skipped", *s) diff --git a/scripts/music/pack.ts b/scripts/music/pack.ts new file mode 100644 index 0000000..cb127ef --- /dev/null +++ b/scripts/music/pack.ts @@ -0,0 +1,56 @@ +// Article 014's data files, from the chorales convert.py writes and a checkpoint train.ts saves: +// +// npx tsx scripts/music/pack.ts +// +// public/posts/music-ai/chorales.bin u16 train count, u16 validation count, u16 length per chorale, then one +// byte per token (training chorales first). Bach, Craig Sapp's edition, +// CC BY-NC-SA 4.0 — so is this file. +// public/posts/music-ai/judge.bin float32 parameters in the Transformer's own order, for figures 02 and 03. +// +// The corpus, the research scripts and the runs live outside this repo (docs/research/music-ai explains where). +import fs from "node:fs"; +import path from "node:path"; +import { Transformer, mulberry32 } from "@/lib/ml"; +import { CONFIG, HOLD, LO, REST } from "@/content/posts/music-ai/components/music"; + +interface Chorale { pitches: number[][]; onset: number[][] } + +const [source, checkpoint] = process.argv.slice(2); +if (!source || !checkpoint) throw new Error("usage: pack.ts "); +const out = path.join(process.cwd(), "public/posts/music-ai"); +fs.mkdirSync(out, { recursive: true }); + +/** One token per voice per eighth: a new note is its pitch, a held one HOLD, silence REST. */ +function tokens(c: Chorale): number[] { + const ids: number[] = []; + c.pitches.forEach((step, t) => step.forEach((p, v) => ids.push(p < 0 ? REST : c.onset[t][v] || t === 0 ? p - LO : HOLD))); + return ids; +} + +// The same seeded split the research used: 90 % to train on, 10 % kept back. +const chorales: Chorale[] = JSON.parse(fs.readFileSync(source, "utf8")); +const rng = mulberry32(2026); +const order = chorales.map((_, i) => i).sort(() => rng() - 0.5); +const nVal = Math.round(chorales.length * 0.1); +const val = order.slice(0, nVal).map((i) => tokens(chorales[i])); +const train = order.slice(nVal).map((i) => tokens(chorales[i])); + +const all = [...train, ...val]; +const bytes = all.reduce((n, t) => n + t.length, 0); +const buffer = Buffer.alloc(4 + 2 * all.length + bytes); +buffer.writeUInt16LE(train.length, 0); +buffer.writeUInt16LE(val.length, 2); +all.forEach((t, i) => buffer.writeUInt16LE(t.length, 4 + 2 * i)); +let at = 4 + 2 * all.length; +for (const t of all) for (const id of t) buffer[at++] = id; +fs.writeFileSync(`${out}/chorales.bin`, buffer); + +// The checkpoint is a map of parameter name to numbers; the page reads them in the Transformer's own order. +const saved: Record = JSON.parse(fs.readFileSync(checkpoint, "utf8")); +const model = new Transformer(CONFIG); +const weights = new Float32Array(model.parameterCount()); +let k = 0; +for (const name of Object.keys(model.params)) for (const x of saved[name]) weights[k++] = x; +fs.writeFileSync(`${out}/judge.bin`, Buffer.from(weights.buffer)); + +console.log(`${train.length} + ${val.length} chorales, ${bytes} tokens, ${buffer.length} bytes; ${weights.length} parameters, ${weights.byteLength} bytes`); From d0c0d80773929d408358955105b474dfefb5d65c Mon Sep 17 00:00:00 2001 From: PSheon Date: Wed, 23 Sep 2026 10:47:47 +0800 Subject: [PATCH 3/7] feat(music-ai): a synthesiser, one player for the page, and a piano roll MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Every sample is computed here, with none of the browser's own instruments or effects: three soft voices (a warm pad, an electric piano by FM, a flute with breath), a damped stereo reverb laid out like Freeverb, and a low-pass over the mix. The first organ was sharp — 6 to 16 dB more in the 1–4 kHz band the ear is most sensitive to (docs/research/music-ai, "Timbre"). The player owns the page's single AudioContext and the synthesiser worker: playing something stops whatever was playing, changing the instrument keeps the position and never leaves a gap, a piece counts as finished when the music ends rather than when its reverb tail does, and the last figure to leave stops the sound and closes the context. Co-Authored-By: Claude Opus 5 (1M context) --- .../posts/music-ai/components/piano-roll.tsx | 57 ++++++++ content/posts/music-ai/components/player.ts | 119 +++++++++++++++++ content/posts/music-ai/components/synth.ts | 125 ++++++++++++++++++ 3 files changed, 301 insertions(+) create mode 100644 content/posts/music-ai/components/piano-roll.tsx create mode 100644 content/posts/music-ai/components/player.ts create mode 100644 content/posts/music-ai/components/synth.ts diff --git a/content/posts/music-ai/components/piano-roll.tsx b/content/posts/music-ai/components/piano-roll.tsx new file mode 100644 index 0000000..16eca82 --- /dev/null +++ b/content/posts/music-ai/components/piano-roll.tsx @@ -0,0 +1,57 @@ +"use client"; + +import { useRef } from "react"; +import type { Piece } from "./music"; +import { usePlayhead } from "./player"; + +/** Soprano to bass. Each voice wears one series colour (DESIGN §2's order), and the legend names them. */ +export const VOICE_COLOURS = ["var(--signal)", "var(--signal-3)", "var(--signal-2)", "var(--chart-5)"]; +const LOW = 36, HIGH = 84, STEP_W = 8, ROW_H = 2.4; + +/** A piano roll: time to the right, pitch upward, one bar per note. A playhead crosses it while `playKey` plays. */ +export function PianoRoll({ piece, label, playKey, className }: { piece: Piece | null; label: string; playKey: string; className?: string }) { + const head = useRef(null); + const steps = Math.max(piece?.pitches.length ?? 48, 1); + const W = steps * STEP_W, H = (HIGH - LOW) * ROW_H; + usePlayhead(playKey, (f) => { + const line = head.current; + if (!line) return; + line.style.opacity = f === null ? "0" : "1"; + if (f !== null) line.setAttribute("transform", `translate(${(f * W).toFixed(1)} 0)`); + }); + + const notes: { x: number; y: number; w: number; v: number }[] = []; + if (piece) + for (let v = 0; v < 4; v++) + for (let t = 0; t < piece.pitches.length; ) { + const p = piece.pitches[t][v]; + if (p < 0) { t++; continue; } + let len = 1; + while (t + len < piece.pitches.length && piece.pitches[t + len][v] === p && !piece.onset[t + len][v]) len++; + notes.push({ x: t * STEP_W, y: (HIGH - Math.min(HIGH, Math.max(LOW, p))) * ROW_H, w: len * STEP_W, v }); + t += len; + } + + return ( + + {/* A faint line at every bar (eight eighths), and C3 / C4 / C5 as the only pitch rules. */} + {Array.from({ length: Math.floor(steps / 8) + 1 }, (_, i) => )} + {[48, 60, 72].map((c) => )} + {notes.map((n, i) => )} + + + ); +} + +export function VoiceLegend({ names }: { names: string[] }) { + return ( +

+ {names.map((n, i) => ( + + + {n} + + ))} +

+ ); +} diff --git a/content/posts/music-ai/components/player.ts b/content/posts/music-ai/components/player.ts new file mode 100644 index 0000000..1157ff0 --- /dev/null +++ b/content/posts/music-ai/components/player.ts @@ -0,0 +1,119 @@ +"use client"; + +import { useCallback, useEffect, useRef, useState } from "react"; +import type { Piece } from "./music"; +import type { Reply, Request } from "./protocol"; +import type { Timbre } from "./synth"; +import { createMusicWorker } from "./worker-factory"; + +/* + * One synthesiser worker and one AudioContext for the page, shared by every figure: playing something stops whatever + * was playing. The worker is separate from the training one, so a note never waits behind a training step. The + * AudioContext is made on the first press of Play (a browser only lets a page make sound after a gesture). + */ +let synth: Worker | null = null, audio: AudioContext | null = null, source: AudioBufferSourceNode | null = null; +/** Fires when the music itself ends, a little before the buffer does: the reverb tail rings on, the controls do not wait for it. */ +let endTimer: ReturnType | null = null; +let nextId = 0, current: { key: string; started: number; seconds: number } | null = null; +/** What is playing, kept so that changing the timbre can re-render the same piece at once. */ +let last: { key: string; piece: Piece } | null = null; +const listeners = new Set<() => void>(); +const changed = () => listeners.forEach((f) => f()); + +function worker(): Worker { + synth ??= createMusicWorker(); + return synth; +} + +export function stopAll() { + if (endTimer) { clearTimeout(endTimer); endTimer = null; } + source?.stop(); + source = null; + current = null; + changed(); +} + +/** Counts the figures using the player: when the last one goes (the reader navigated away), the sound stops with it. */ +let users = 0; + +export function useStopOnLeave() { + useEffect(() => { + users++; + return () => { + if (--users > 0) return; + stopAll(); + synth?.terminate(); + synth = null; + void audio?.close(); + audio = null; + }; + }, []); +} + +/** Swap the timbre of what is playing without going back to the beginning. Silence stays silent. */ +export function restyle(timbre: Timbre) { + const at = current && current.started >= 0 && audio ? audio.currentTime - current.started : 0; + if (last && current) void play(last.key, last.piece, timbre, at); +} + +async function play(key: string, piece: Piece, timbre: Timbre, offset = 0) { + // Changing the timbre of what is already playing keeps the old sound going until the new one is ready, so the + // music does not stop for the second or so the synthesiser takes. Anything else stops at once. + const swap = current?.key === key && !!source; + const previous = source; + if (!swap) stopAll(); + last = { key, piece }; + audio ??= new AudioContext(); + if (audio.state === "suspended") await audio.resume(); + const id = ++nextId, w = worker(); + current = { key, started: -1, seconds: 0 }; + changed(); + const reply = await new Promise>((resolve) => { + const on = ({ data }: MessageEvent) => { if (data.type === "audio" && data.id === id) { w.removeEventListener("message", on); resolve(data); } }; + w.addEventListener("message", on); + w.postMessage({ type: "render", id, piece, timbre } satisfies Request); + }); + if (current?.key !== key || id !== nextId || !audio) return; // something else was asked for meanwhile + const buffer = audio.createBuffer(2, reply.left.length, 44100); + buffer.copyToChannel(reply.left as Float32Array, 0); + buffer.copyToChannel(reply.right as Float32Array, 1); + if (swap && previous) { previous.onended = null; previous.stop(); if (source === previous) source = null; } + const node = audio.createBufferSource(); + node.buffer = buffer; + node.connect(audio.destination); + node.onended = () => { if (source === node) { source = null; current = null; changed(); } }; + node.start(0, Math.max(0, Math.min(offset, buffer.duration - 0.05))); + source = node; + current = { key, started: audio.currentTime - offset, seconds: reply.seconds }; + // The buffer carries three seconds of reverb after the last note. Count the piece as played when the music ends + // (plus a moment), or Play stays "Stop" for several silent seconds. + if (endTimer) clearTimeout(endTimer); + endTimer = setTimeout(() => { endTimer = null; current = null; changed(); }, Math.max(0, reply.seconds + 0.8 - offset) * 1000); + changed(); +} + +/** Which key is playing (or being prepared), and a function for how far through it is (0–1, or null before it starts). */ +export function usePlayer() { + const [, force] = useState(0); + useEffect(() => { + const f = () => force((n) => n + 1); + listeners.add(f); + return () => { listeners.delete(f); }; + }, []); + const progress = useCallback(() => (current && current.started >= 0 && audio ? Math.min(1, (audio.currentTime - current.started) / current.seconds) : null), []); + return { playing: current?.key ?? null, play, stop: stopAll, restyle, progress }; +} + +/** Moves a playhead while `key` plays: calls `draw` every frame with the fraction played, and with null when it stops. */ +export function usePlayhead(key: string, draw: (fraction: number | null) => void) { + const { playing, progress } = usePlayer(); + const drawRef = useRef(draw); + useEffect(() => { drawRef.current = draw; }); + useEffect(() => { + if (playing !== key) { drawRef.current(null); return; } + let frame = 0; + const tick = () => { drawRef.current(progress()); frame = requestAnimationFrame(tick); }; + frame = requestAnimationFrame(tick); + return () => cancelAnimationFrame(frame); + }, [playing, key, progress]); +} diff --git a/content/posts/music-ai/components/synth.ts b/content/posts/music-ai/components/synth.ts new file mode 100644 index 0000000..8fc4265 --- /dev/null +++ b/content/posts/music-ai/components/synth.ts @@ -0,0 +1,125 @@ +import type { Piece } from "./music"; + +/* + * The instrument the model's scores are played on, computed sample by sample (no Web Audio oscillators or effects): + * three soft voices, a damped stereo reverb laid out like Freeverb, and a gentle low-pass on the mix. The first + * version was an organ of five harmonics with a fast attack and an undamped echo; Paul found it sharp, and it had + * 14 dB more energy in the 1–4 kHz band the ear is most sensitive to (docs/research/music-ai, "Timbre"). + */ +export type Timbre = "pad" | "epiano" | "flute"; +export const TIMBRES: Timbre[] = ["pad", "epiano", "flute"]; +export const SAMPLE_RATE = 44100; +export const BPM = 60; +/** Seconds per step: an eighth note at 60 beats a minute. */ +export const STEP_SECONDS = 60 / BPM / 2; + +export interface Audio { left: Float32Array; right: Float32Array; seconds: number } + +function noise(seed: number) { + let a = seed | 0; + return () => { a = (Math.imul(a, 1664525) + 1013904223) | 0; return a / 2147483648; }; +} + +/** One note into the two channels. Lower voices sit a little louder; the four are spread across the stereo field. */ +function note(L: Float32Array, R: Float32Array, timbre: Timbre, midi: number, start: number, dur: number, voice: number) { + const f = 440 * 2 ** ((midi - 69) / 12); + const level = [0.5, 0.55, 0.6, 0.75][voice], pan = [0.35, 0.6, 0.4, 0.5][voice]; + const gl = Math.cos((pan * Math.PI) / 2), gr = Math.sin((pan * Math.PI) / 2); + const rnd = noise(midi * 131 + Math.round(start * 1000)); + const attack = timbre === "pad" ? 0.35 : timbre === "flute" ? 0.12 : 0.008; + const release = timbre === "pad" ? 1.4 : timbre === "flute" ? 0.35 : 1.2; + const total = Math.round((dur + release) * SAMPLE_RATE), a0 = Math.round(start * SAMPLE_RATE); + const w = 2 * Math.PI * f, detune = 2 ** (4 / 1200); + let breath = 0; + for (let i = 0; i < total && a0 + i < L.length; i++) { + const t = i / SAMPLE_RATE; + const sustain = t < dur ? 1 : Math.exp(-(t - dur) / (release / 4)); + let env: number, x: number; + if (timbre === "pad") { + // The fundamental and a soft octave, each doubled 4 cents apart: the slow beating between them is the warmth. + env = Math.min(1, t / attack) ** 2 * sustain; + x = 0.5 * (Math.sin(w * t) + Math.sin(w * detune * t)) + 0.12 * (Math.sin(2 * w * t) + Math.sin((2 * w * t) / detune)) + 0.03 * Math.sin(3 * w * t); + } else if (timbre === "flute") { + // A sine with a little second harmonic, a breath of noise on the attack, and a vibrato that fades in. + env = Math.min(1, t / attack) * sustain; + const vib = 1 + 0.003 * Math.sin(2 * Math.PI * 4.8 * t) * Math.min(1, t / 0.6); + breath = 0.97 * breath + 0.03 * rnd(); + x = Math.sin(w * vib * t) + 0.08 * Math.sin(2 * w * vib * t) + 3 * breath * Math.exp(-t / 0.08); + } else { + // An electric piano by two-operator FM: the modulation index decays, so the tone rounds off as it sounds. + env = Math.min(1, t / attack) * Math.exp(-t / 2.2) * sustain; + x = Math.sin(w * t + 1.1 * Math.exp(-t / 0.35) * Math.sin(w * t)); + } + const s = 0.16 * level * env * x; + L[a0 + i] += s * gl; + R[a0 + i] += s * gr; + } +} + +/** Freeverb's layout: eight feedback combs with a low-pass inside the loop (the tail darkens as it decays), four all-passes. */ +function reverb(L: Float32Array, R: Float32Array, room = 0.84, damp = 0.45, wet = 0.32) { + const combs = [1116, 1188, 1277, 1356, 1422, 1491, 1557, 1617], passes = [556, 441, 341, 225]; + const side = (input: Float32Array, spread: number) => { + const out = new Float32Array(input.length); + for (const d0 of combs) { + const d = d0 + spread, buf = new Float32Array(d); + let idx = 0, store = 0; + for (let i = 0; i < input.length; i++) { + const y = buf[idx]; + store = y * (1 - damp) + store * damp; + buf[idx] = input[i] * 0.015 + store * room; + out[i] += y; + if (++idx === d) idx = 0; + } + } + for (const d0 of passes) { + const d = d0 + spread, buf = new Float32Array(d); + let idx = 0; + for (let i = 0; i < out.length; i++) { + const b = buf[idx], x = out[i]; + out[i] = b - x; + buf[idx] = x + b * 0.5; + if (++idx === d) idx = 0; + } + } + return out; + }; + const wl = side(L, 0), wr = side(R, 23); + for (let i = 0; i < L.length; i++) { + L[i] = L[i] * (1 - wet) + wl[i] * wet * 3; + R[i] = R[i] * (1 - wet) + wr[i] * wet * 3; + } +} + +/** Two one-pole low-passes: 12 dB per octave above `hz`. */ +function lowpass(x: Float32Array, hz: number) { + const a = Math.exp((-2 * Math.PI * hz) / SAMPLE_RATE); + for (let pass = 0; pass < 2; pass++) { + let y = 0; + for (let i = 0; i < x.length; i++) x[i] = y = (1 - a) * x[i] + a * y; + } +} + +export function render({ pitches, onset }: Piece, timbre: Timbre): Audio { + const seconds = pitches.length * STEP_SECONDS; + const n = Math.ceil((seconds + 3) * SAMPLE_RATE); + const L = new Float32Array(n), R = new Float32Array(n); + for (let v = 0; v < 4; v++) { + for (let t = 0; t < pitches.length; ) { + const p = pitches[t][v]; + if (p < 0) { t++; continue; } + let len = 1; + while (t + len < pitches.length && pitches[t + len][v] === p && !onset[t + len][v]) len++; + note(L, R, timbre, p, t * STEP_SECONDS, len * STEP_SECONDS, v); + t += len; + } + } + reverb(L, R); + lowpass(L, 3200); + lowpass(R, 3200); + let peak = 0; + for (let i = 0; i < n; i++) peak = Math.max(peak, Math.abs(L[i]), Math.abs(R[i])); + const g = 0.7 / (peak || 1); + for (let i = 0; i < n; i++) { L[i] *= g; R[i] *= g; } + return { left: L, right: R, seconds }; +} From c34e0a3d6f57601e7d083cc54dce0b257b912aa2 Mon Sep 17 00:00:00 2001 From: PSheon Date: Wed, 23 Sep 2026 10:47:47 +0800 Subject: [PATCH 4/7] feat(music-ai): run training, tuning and synthesis off the main thread MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit One worker file serves all of it. Training keeps a worker to itself for the three minutes it holds the thread; figures 02 and 03 share a second one, so the trained model and the chorales are fetched and parsed once instead of twice; the player has a third for synthesis, so a note never waits behind a training step. Every message carries which figure asked, because a shared worker's replies reach both and loading one figure used to reset the other. Workers are made in one place (worker-factory.ts): three `new Worker(new URL(…))` call sites for the same file left the production bundle unable to boot any of them. Co-Authored-By: Claude Opus 5 (1M context) --- .../posts/music-ai/components/music.worker.ts | 145 ++++++++++++++++++ content/posts/music-ai/components/protocol.ts | 43 ++++++ .../music-ai/components/shared-worker.ts | 32 ++++ .../music-ai/components/worker-factory.ts | 6 + 4 files changed, 226 insertions(+) create mode 100644 content/posts/music-ai/components/music.worker.ts create mode 100644 content/posts/music-ai/components/protocol.ts create mode 100644 content/posts/music-ai/components/shared-worker.ts create mode 100644 content/posts/music-ai/components/worker-factory.ts diff --git a/content/posts/music-ai/components/music.worker.ts b/content/posts/music-ai/components/music.worker.ts new file mode 100644 index 0000000..864b567 --- /dev/null +++ b/content/posts/music-ai/components/music.worker.ts @@ -0,0 +1,145 @@ +/// +import { mulberry32 } from "@/lib/ml"; +import { Transformer } from "@/lib/ml"; +import { CONFIG, Composer, CopyFinder, Judge, VOICES, compose, decode, load, parseChorales, report, rulesPiece, validate, window, type Report } from "./music"; +import type { BlindItem, Reply, Request } from "./protocol"; +import { render } from "./synth"; + +/* + * Training, composing, preference tuning and the synthesiser all run here, so the page keeps scrolling. Snapshots are + * taken where docs/research/music-ai saw the model change its mind: it drones first, then the voices stop crossing, + * then the key and the rhythm settle. + */ +const SNAPSHOTS = [0, 100, 250, 500, 1000, 2400]; +/** A composition is six bars: 48 eighths, 24 seconds. The blind test uses four, so three in a row stay listenable. */ +const PIECE_STEPS = 48; +const BLIND_STEPS = 32; +const EVERY = 10; + +const send = (reply: Reply, transfer: Transferable[] = []) => (self as unknown as Worker).postMessage(reply, transfer); +let run = 0; +let data: ReturnType | null = null; +let finder: CopyFinder | null = null; +let judge: Judge | null = null; +let candidates: [number[], number[]] | null = null; +let before: Report | null = null; +let trained: Transformer | null = null; +let weights: Float32Array | null = null; + +/** Run B at step 1,000, as shipped in judge.bin: the blind test composes with it and the judge figure tunes a copy. */ +async function judgeWeights(): Promise { + weights ??= new Float32Array(await (await fetch("/posts/music-ai/judge.bin")).arrayBuffer()); + return weights; +} + +async function trainedModel(): Promise { + if (!trained) { + trained = new Transformer(CONFIG); + load(trained, await judgeWeights()); + } + return trained; +} + +async function chorales() { + if (!data) data = parseChorales(await (await fetch("/posts/music-ai/chorales.bin")).arrayBuffer()); + finder ??= new CopyFinder(data.train); + return data; +} + +/** How the model writes right now, from eight seeds (the same eight every time, so a change is the model's): what the judge figure shows. */ +function measure(model: Composer["model"]): Report { + const reps = [1, 2, 3, 4, 5, 6, 7, 8].map((seed) => report(decode(compose(model, 32, 0.7, mulberry32(seed))))); + const mean = (k: keyof Report) => reps.reduce((s, r) => s + r[k], 0) / reps.length; + return { inKey: mean("inKey"), parallels: mean("parallels"), crossings: mean("crossings"), held: mean("held"), chords: mean("chords") }; +} + +self.onmessage = async ({ data: request }: MessageEvent) => { + // Every reply goes back tagged with whoever asked, because two figures share this worker. + const post = (reply: Reply, transfer: Transferable[] = []) => send({ ...reply, from: request.from }, transfer); + if (request.type === "stop") { run++; return; } + + if (request.type === "render") { + const audio = render(request.piece, request.timbre); + post({ type: "audio", id: request.id, ...audio }, [audio.left.buffer, audio.right.buffer]); + return; + } + + if (request.type === "train") { + const id = ++run; + post({ type: "loading" }); + let d: Awaited>; + try { d = await chorales(); } catch { post({ type: "failed" }); return; } + const rng = mulberry32(request.seed), composer = new Composer(d.train, rng, request.steps); + const valRng = mulberry32(99), valWindows = Array.from({ length: 24 }, () => window(d.val, valRng)); + const t0 = performance.now(); + let losses = 0, count = 0; + const snapshot = () => { + const piece = decode(compose(composer.model, PIECE_STEPS, 0.7, mulberry32(request.seed + composer.step))); + post({ type: "snapshot", snapshot: { step: composer.step, seconds: (performance.now() - t0) / 1000, val: validate(composer.model, valWindows), piece, report: report(piece), copied: finder!.longest(piece.pitches).steps } }); + }; + snapshot(); + const chunk = () => { + if (id !== run) return; + for (let i = 0; i < EVERY && composer.step < request.steps; i++) { losses += composer.learn(); count++; } + post({ type: "progress", step: composer.step, steps: request.steps, loss: losses / count, seconds: (performance.now() - t0) / 1000 }); + losses = 0; count = 0; + if (SNAPSHOTS.includes(composer.step) || composer.step === request.steps) snapshot(); + if (composer.step < request.steps) setTimeout(chunk, 0); + else post({ type: "done" }); + }; + setTimeout(chunk, 0); + return; + } + + if (request.type === "blind") { + post({ type: "loading" }); + try { + const d = await chorales(), model = await trainedModel(); + const rng = mulberry32(Math.floor(Math.random() * 2 ** 31)); + // Bach is an excerpt of a validation chorale — one the model never saw — starting on a bar line. + const chorale = d.val[Math.floor(rng() * d.val.length)]; + const bars = Math.max(1, Math.floor(chorale.length / VOICES / 8) - BLIND_STEPS / 8); + const from = Math.floor(rng() * bars) * 8 * VOICES; + const items: BlindItem[] = [ + { who: "bach" as const, piece: decode(chorale.slice(from, from + BLIND_STEPS * VOICES)) }, + { who: "ai" as const, piece: decode(compose(model, BLIND_STEPS, 0.7, rng)) }, + { who: "rules" as const, piece: rulesPiece(BLIND_STEPS, rng) }, + ].map((x) => ({ ...x, report: report(x.piece) })); + // Shuffled, so that A, B and C say nothing. + for (let i = items.length - 1; i > 0; i--) { const j = Math.floor(rng() * (i + 1)); [items[i], items[j]] = [items[j], items[i]]; } + post({ type: "blind", items }); + } catch { post({ type: "failed" }); } + return; + } + + if (request.type === "judge") { + post({ type: "loading" }); + try { + judge = new Judge(await judgeWeights()); + before = measure(judge.policy); + // The first pair comes with the model, so the figure has something to play the moment it is ready. + candidates = judge.pair(mulberry32(Math.floor(Math.random() * 2 ** 31))); + post({ type: "pair", pieces: [decode(candidates[0].slice(0, -1)), decode(candidates[1].slice(0, -1))] }); + } catch { post({ type: "failed" }); } + return; + } + + if (!judge) return; + if (request.type === "sample") { + post({ type: "sample", piece: decode(compose(judge.policy, PIECE_STEPS, 0.7, mulberry32(Math.floor(Math.random() * 2 ** 31)))) }); + return; + } + if (request.type === "pair") { + candidates = judge.pair(mulberry32(request.seed)); + post({ type: "pair", pieces: [decode(candidates[0].slice(0, -1)), decode(candidates[1].slice(0, -1))] }); + return; + } + if (request.type === "choose" && candidates) { + const [a, b] = candidates; + judge.choose(request.winner === 0 ? a : b, request.winner === 0 ? b : a); + // The next pair first, so the reader can listen while the numbers are worked out. + candidates = judge.pair(mulberry32(Math.floor(Math.random() * 2 ** 31))); + post({ type: "pair", pieces: [decode(candidates[0].slice(0, -1)), decode(candidates[1].slice(0, -1))] }); + post({ type: "judged", choices: judge.choices, now: measure(judge.policy), before: before! }); + } +}; diff --git a/content/posts/music-ai/components/protocol.ts b/content/posts/music-ai/components/protocol.ts new file mode 100644 index 0000000..bb24c74 --- /dev/null +++ b/content/posts/music-ai/components/protocol.ts @@ -0,0 +1,43 @@ +import type { Piece, Report } from "./music"; +import type { Timbre } from "./synth"; + +/** One candidate in the blind test: who wrote it is sent with it, and the page keeps it hidden until the reader answers. */ +export interface BlindItem { who: "bach" | "ai" | "rules"; piece: Piece; report: Report } + +export interface Snapshot { + step: number; + seconds: number; + val: number; + piece: Piece; + report: Report; + /** the longest stretch, in eighth notes, found note for note in one training chorale */ + copied: number; +} + +/** Both the judge and the blind test talk to one worker, so every message carries who asked: a reply meant for one figure must not reset the other. */ +export type Request = { from?: number } & RequestBody; + +type RequestBody = + | { type: "train"; seed: number; steps: number } + | { type: "stop" } + | { type: "render"; id: number; piece: Piece; timbre: Timbre } + | { type: "judge" } + | { type: "pair"; seed: number } + | { type: "choose"; winner: 0 | 1 } + | { type: "sample" } + | { type: "blind" }; + +export type Reply = { from?: number } & ReplyBody; + +type ReplyBody = + | { type: "loading" } + | { type: "failed" } + | { type: "progress"; step: number; steps: number; loss: number; seconds: number } + | { type: "snapshot"; snapshot: Snapshot } + | { type: "done" } + | { type: "audio"; id: number; left: Float32Array; right: Float32Array; seconds: number } + | { type: "ready" } + | { type: "pair"; pieces: [Piece, Piece] } + | { type: "judged"; choices: number; now: Report; before: Report } + | { type: "blind"; items: BlindItem[] } + | { type: "sample"; piece: Piece }; diff --git a/content/posts/music-ai/components/shared-worker.ts b/content/posts/music-ai/components/shared-worker.ts new file mode 100644 index 0000000..9bf9d7e --- /dev/null +++ b/content/posts/music-ai/components/shared-worker.ts @@ -0,0 +1,32 @@ +"use client"; + +import { useEffect, useRef, useState } from "react"; +import type { Reply, Request } from "./protocol"; +import { createMusicWorker } from "./worker-factory"; + +/* + * Figures 02 and 03 use the same trained composer (judge.bin, 223 KB) and the same chorales, so they share one worker + * and one copy of both instead of fetching and parsing them twice. Training keeps a worker of its own: it holds the + * thread for minutes at a time. + */ +let shared: Worker | null = null, users = 0, ids = 0; + +/** The shared worker, with `onReply` attached for as long as the component lives. */ +export function useSharedWorker(onReply: (reply: Reply) => void): (request: Request) => void { + // One identity per figure, fixed for its lifetime. + const [id] = useState(() => ++ids); + const handler = useRef(onReply); + useEffect(() => { handler.current = onReply; }); + useEffect(() => { + users++; + shared ??= createMusicWorker(); + const listener = ({ data }: MessageEvent) => { if (data.from === id) handler.current(data); }; + shared.addEventListener("message", listener); + const worker = shared; + return () => { + worker.removeEventListener("message", listener); + if (--users === 0) { worker.terminate(); shared = null; } + }; + }, [id]); + return (request: Request) => shared?.postMessage({ ...request, from: id }); +} diff --git a/content/posts/music-ai/components/worker-factory.ts b/content/posts/music-ai/components/worker-factory.ts new file mode 100644 index 0000000..2abc237 --- /dev/null +++ b/content/posts/music-ai/components/worker-factory.ts @@ -0,0 +1,6 @@ +/** + * The one place a music worker is made. Turbopack wires `new Worker(new URL(…))` at build time, and three separate + * call sites for the same worker file left the production bundle with "Missing worker bootstrap config": in + * development every figure worked, in a production build none of them did. + */ +export const createMusicWorker = () => new Worker(new URL("./music.worker.ts", import.meta.url), { type: "module" }); From 7c44f918edc86bbd26bca02056f53e83e680f555 Mon Sep 17 00:00:00 2001 From: PSheon Date: Wed, 23 Sep 2026 10:48:06 +0800 Subject: [PATCH 5/7] =?UTF-8?q?feat(music-ai):=20three=20figures=20?= =?UTF-8?q?=E2=80=94=20train=20and=20listen,=20judge=20it,=20guess=20who?= =?UTF-8?q?=20wrote=20it?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fig. 01 trains a composer in about three minutes and improvises at six moments on the way, so the reader hears it stop noodling; the snapshot they picked is never taken from under them by the next one, and the numbers underneath say what changed. Fig. 02 is the reader as the judge: two pieces, one pick, one DPO step against a frozen copy of the model. About twenty picks are audible; at the page's learning rate that moves held notes from 48 % to 64 % without the model forgetting Bach (docs/research/music-ai). Fig. 03 is the blind test: Bach, the model and five lines of maths, shuffled, with the piano rolls and the answers held back until the reader has guessed — a chorale and a block-chord machine look nothing alike. Co-Authored-By: Claude Opus 5 (1M context) --- .../posts/music-ai/components/blind-lab.tsx | 129 +++++++++++++++ .../music-ai/components/composer-lab.tsx | 152 ++++++++++++++++++ content/posts/music-ai/components/index.ts | 11 ++ .../posts/music-ai/components/judge-lab.tsx | 96 +++++++++++ content/posts/music-ai/components/labels.ts | 101 ++++++++++++ content/posts/music-ai/components/labs.ts | 3 + 6 files changed, 492 insertions(+) create mode 100644 content/posts/music-ai/components/blind-lab.tsx create mode 100644 content/posts/music-ai/components/composer-lab.tsx create mode 100644 content/posts/music-ai/components/index.ts create mode 100644 content/posts/music-ai/components/judge-lab.tsx create mode 100644 content/posts/music-ai/components/labels.ts create mode 100644 content/posts/music-ai/components/labs.ts diff --git a/content/posts/music-ai/components/blind-lab.tsx b/content/posts/music-ai/components/blind-lab.tsx new file mode 100644 index 0000000..2f50bb8 --- /dev/null +++ b/content/posts/music-ai/components/blind-lab.tsx @@ -0,0 +1,129 @@ +"use client"; + +import { Check, Heart, Pause, Play, Shuffle } from "lucide-react"; +import { useState } from "react"; +import { Button } from "@/components/ui/button"; +import { cn } from "@/lib/utils"; +import { TimbrePicker } from "./composer-lab"; +import { useLabels } from "./labels"; +import { PianoRoll, VoiceLegend } from "./piano-roll"; +import { usePlayer, useStopOnLeave } from "./player"; +import type { BlindItem } from "./protocol"; +import { useSharedWorker } from "./shared-worker"; +import type { Timbre } from "./synth"; + +type Who = BlindItem["who"]; +const WHO: Who[] = ["bach", "ai", "rules"]; +const LETTERS = ["A", "B", "C"]; + +/** Fig. 03: Bach, the AI and five lines of maths, unlabelled. Guess who wrote what, and say which one you liked. */ +export function BlindLab() { + const t = useLabels(); + const [state, setState] = useState<"idle" | "loading" | "listening" | "revealed" | "failed">("idle"); + const [items, setItems] = useState([]); + const [guesses, setGuesses] = useState<(Who | null)[]>([null, null, null]); + const [favourite, setFavourite] = useState(null); + const [timbre, setTimbre] = useState("pad"); + const player = usePlayer(); + useStopOnLeave(); + const send = useSharedWorker((data) => { + if (data.type === "loading") setState("loading"); + else if (data.type === "failed") setState("failed"); + else if (data.type === "blind") { setItems(data.items); setState("listening"); } + }); + + const deal = () => { + player.stop(); + setGuesses([null, null, null]); + setFavourite(null); + setItems([]); + send({ type: "blind" }); + }; + + if (state === "idle" || state === "loading" || state === "failed") + return ( +
+ +

{state === "failed" ? t.failed : state === "loading" ? t.judgeLoading : t.blindHow}

+
+ ); + + const revealed = state === "revealed"; + const right = items.filter((item, i) => guesses[i] === item.who).length; + + return ( +
+
+

{t.blindHow}

+ { setTimbre(v); player.restyle(v); }} /> +
+ +
+ {items.map((item, i) => { + const key = `blind-${i}-${item.who}`, playing = player.playing === key; + const correct = guesses[i] === item.who; + return ( +
+
+

{LETTERS[i]}

+ +
+ + {/* No roll before the answers: a chorale and a block-chord machine look nothing alike, which would give it away. */} + {revealed && } + +
+ {t.blindGuess} +
+ {WHO.map((who) => ( + + ))} +
+
+ + + + {revealed && ( +
+

+ {t.blindAnswer}: {t.blindWho[item.who]} · {correct ? t.blindCorrect : t.blindWrong} +

+

{t.parallels} {item.report.parallels.toFixed(1)} · {t.blindChords} {item.report.chords.toFixed(0)}

+
+ )} +
+ ); + })} +
+ + {revealed && } + +
+ {revealed ? ( + <> + {t.blindScore(right)} + {favourite !== null && items[favourite] && {t.blindYours} {t.blindWho[items[favourite].who]}} + + + ) : ( + <> + + {guesses.some((g) => g === null) ? t.blindNeedAll : t.blindWaiting} + + )} +
+
+ ); +} diff --git a/content/posts/music-ai/components/composer-lab.tsx b/content/posts/music-ai/components/composer-lab.tsx new file mode 100644 index 0000000..9ff36d9 --- /dev/null +++ b/content/posts/music-ai/components/composer-lab.tsx @@ -0,0 +1,152 @@ +"use client"; + +import { Pause, Play, Square } from "lucide-react"; +import { useEffect, useRef, useState } from "react"; +import { Readout } from "@/components/lab/readout"; +import { Sparkline } from "@/components/lab/sparkline"; +import { Button } from "@/components/ui/button"; +import { cn } from "@/lib/utils"; +import { useLabels } from "./labels"; +import { NGRAM_LOSS } from "./music"; +import { PianoRoll, VoiceLegend } from "./piano-roll"; +import { usePlayer, useStopOnLeave } from "./player"; +import type { Reply, Request, Snapshot } from "./protocol"; +import { TIMBRES, type Timbre } from "./synth"; +import { createMusicWorker } from "./worker-factory"; + +/** 2,400 steps of 8 windows: about three minutes (69 ms a step in Chromium on an M4 Pro; docs/research/music-ai). */ +const STEPS = 2400; + +export function TimbrePicker({ value, onChange }: { value: Timbre; onChange(t: Timbre): void }) { + const t = useLabels(); + return ( +
+ {t.timbre} + {TIMBRES.map((name) => ( + + ))} +
+ ); +} + +/** Fig. 01: the reader trains a composer in a worker and hears what it writes at six moments on the way. */ +export function ComposerLab() { + const t = useLabels(); + const worker = useRef(null); + const [state, setState] = useState<"idle" | "loading" | "training" | "done" | "failed">("idle"); + const [losses, setLosses] = useState([]), [progress, setProgress] = useState({ step: 0, seconds: 0 }); + const [snapshots, setSnapshots] = useState([]), [chosen, setChosen] = useState(null); + const [timbre, setTimbre] = useState("pad"), [autoplay, setAutoplay] = useState(true); + // Once the reader picks a snapshot themselves, a new one no longer takes the stage from under them. + const [pinned, setPinned] = useState(false), [unheard, setUnheard] = useState([]); + const player = usePlayer(); + useStopOnLeave(); + const auto = useRef({ autoplay, timbre, pinned }); + useEffect(() => { auto.current = { autoplay, timbre, pinned }; }, [autoplay, timbre, pinned]); + useEffect(() => () => worker.current?.terminate(), []); + + const start = () => { + worker.current?.terminate(); + const w = createMusicWorker(); + worker.current = w; + w.onmessage = ({ data }: MessageEvent) => { + if (data.type === "loading") setState("loading"); + else if (data.type === "failed") setState("failed"); + else if (data.type === "progress") { setState("training"); setProgress({ step: data.step, seconds: data.seconds }); setLosses((l) => [...l, data.loss]); } + else if (data.type === "snapshot") { + const s = data.snapshot; + setSnapshots((list) => [...list, s]); + if (auto.current.pinned) { setUnheard((u) => [...u, s.step]); return; } + setChosen(s.step); + if (auto.current.autoplay) void player.play(`snap-${s.step}`, s.piece, auto.current.timbre); + } else if (data.type === "done") { setState("done"); w.terminate(); worker.current = null; } + }; + setLosses([]); setSnapshots([]); setChosen(null); setProgress({ step: 0, seconds: 0 }); setPinned(false); setUnheard([]); + w.postMessage({ type: "train", seed: Math.floor(Math.random() * 2 ** 31), steps: STEPS } satisfies Request); + }; + const stop = () => { worker.current?.terminate(); worker.current = null; setState("idle"); }; + + const shown = snapshots.find((s) => s.step === chosen) ?? snapshots.at(-1) ?? null; + const key = shown ? `snap-${shown.step}` : "snap-none"; + const playing = player.playing === key; + const busy = state === "loading" || state === "training"; + const eta = state === "training" && progress.step > 0 ? (progress.seconds / progress.step) * (STEPS - progress.step) : null; + + return ( +
+
+ {busy ? ( + + ) : ( + + )} + {state === "loading" ? t.loading : state === "failed" ? t.failed : t.trainNote} +
+ +
+
+
+ +
+
+
+ + + + +
+
+

{t.loss}

+ +

{t.lossNote}

+
+
+ +
+
+

{t.snapshots}

+ +
+
+ {snapshots.map((s) => ( + + ))} +
+
+ {shown ? :

{t.waiting}

} +
+
+ + +
+ { setTimbre(v); player.restyle(v); }} /> + {shown && ( +
+ + + + + +
+ )} + {shown && ( +

{t.metricsNote}

+ )} +
+
+
+ ); +} diff --git a/content/posts/music-ai/components/index.ts b/content/posts/music-ai/components/index.ts new file mode 100644 index 0000000..e9d1e3c --- /dev/null +++ b/content/posts/music-ai/components/index.ts @@ -0,0 +1,11 @@ +"use client"; + +import dynamic from "next/dynamic"; + +/* The article's instruments as one lazy chunk: see content/posts/slam-2d/components/index.ts for why it is done this way. */ +const loading = typeof window === "undefined" ? null : import("./labs"); +const labs = () => loading ?? import("./labs"); + +export const ComposerLab = dynamic(() => labs().then((m) => m.ComposerLab)); +export const JudgeLab = dynamic(() => labs().then((m) => m.JudgeLab)); +export const BlindLab = dynamic(() => labs().then((m) => m.BlindLab)); diff --git a/content/posts/music-ai/components/judge-lab.tsx b/content/posts/music-ai/components/judge-lab.tsx new file mode 100644 index 0000000..f9529e1 --- /dev/null +++ b/content/posts/music-ai/components/judge-lab.tsx @@ -0,0 +1,96 @@ +"use client"; + +import { Check, Pause, Play, RotateCcw, Volume2 } from "lucide-react"; +import { useEffect, useRef, useState } from "react"; +import { Readout } from "@/components/lab/readout"; +import { Button } from "@/components/ui/button"; +import { useLabels } from "./labels"; +import type { Piece, Report } from "./music"; +import { PianoRoll, VoiceLegend } from "./piano-roll"; +import { usePlayer, useStopOnLeave } from "./player"; +import { useSharedWorker } from "./shared-worker"; + +import { TimbrePicker } from "./composer-lab"; +import type { Timbre } from "./synth"; + +/** Fig. 02: the reader is the judge. Two candidates, one pick, one DPO step; the numbers show what the picks did. */ +export function JudgeLab() { + const t = useLabels(); + const [state, setState] = useState<"idle" | "loading" | "ready" | "thinking" | "failed">("idle"); + const [pair, setPair] = useState<[Piece, Piece] | null>(null), [round, setRound] = useState(0); + const [stats, setStats] = useState<{ choices: number; now: Report; before: Report } | null>(null); + const [timbre, setTimbre] = useState("pad"); + const player = usePlayer(); + useStopOnLeave(); + // The reply arrives long after the click, so the worker callback reads the timbre through a ref. + const timbreRef = useRef(timbre); + useEffect(() => { timbreRef.current = timbre; }, [timbre]); + const send = useSharedWorker((data) => { + if (data.type === "loading") setState("loading"); + else if (data.type === "failed") setState("failed"); + else if (data.type === "pair") { setPair(data.pieces); setRound((r) => r + 1); setState("ready"); } + else if (data.type === "judged") setStats({ choices: data.choices, now: data.now, before: data.before }); + else if (data.type === "sample") void player.play("judge-fresh", data.piece, timbreRef.current); + }); + const load = () => { setStats(null); send({ type: "judge" }); }; + const pick = (winner: 0 | 1) => { + player.stop(); + setState("thinking"); + send({ type: "choose", winner }); + }; + + if (state === "idle" || state === "loading" || state === "failed") + return ( +
+ +

{state === "loading" ? t.judgeLoading : state === "failed" ? t.failed : `${t.judgeNote} ${t.judgeHint}`}

+
+ ); + + return ( +
+
+

{state === "thinking" ? t.thinking : t.judgeReady}

+ { setTimbre(v); player.restyle(v); }} /> +
+
+ {[0, 1].map((i) => { + const key = `judge-${round}-${i}`, piece = pair?.[i] ?? null, playing = player.playing === key; + return ( +
+
+

{t.candidate(i)}

+ +
+ {piece && } + +
+ ); + })} +
+
+ +
+ + +
+
+ +
+

{stats ? `${t.choices(stats.choices)} · ${t.since}` : t.judgeHint}

+ {stats && ( +
+ + + + +
+ )} +
+
+ ); +} diff --git a/content/posts/music-ai/components/labels.ts b/content/posts/music-ai/components/labels.ts new file mode 100644 index 0000000..7d1430a --- /dev/null +++ b/content/posts/music-ai/components/labels.ts @@ -0,0 +1,101 @@ +"use client"; + +import { useLocaleLabels } from "@/components/lab/use-locale-labels"; + +const zh = { + train: "開始訓練", again: "重新訓練", stop: "停止", + trainNote: "在你的瀏覽器裡從零訓練,大約三分鐘。可以邊練邊聽,也可以繼續往下讀。", + loading: "下載 333 首聖詠中…", failed: "資料載入失敗,重新整理再試一次。", + step: "步數", seconds: "已經過", secondsUnit: "秒", loss: "猜下一個音的誤差", + lossNote: "曲線是訓練時的誤差;虛線是 5-gram 在驗證資料上的成績(1.46),拿來和每個片段旁邊的驗證誤差比。", + autoplay: "有新片段就自動播放", + snapshots: "它在這些時刻即興了一段", + snapshotAt: (step: number) => `第 ${step} 步`, + play: "播放", playing: "播放中", stopPlay: "停止播放", + timbre: "音色", timbres: { pad: "溫暖墊音", epiano: "柔和電鋼琴", flute: "長笛" }, + roll: (step: number) => `第 ${step} 步寫的六小節:一條線是一個聲部,由上到下是女高音、女低音、男高音、男低音`, + voices: ["女高音", "女低音", "男高音", "男低音"], + inKey: "在調上", crossings: "聲部交錯", held: "拖長的音", parallels: "平行五度", copied: "最長抄襲", + per100: "次/百格", eighths: "格", + val: "驗證誤差", + waiting: "按「開始訓練」,第 0 步的亂彈會出現在這裡。", + + stopTrain: "停止訓練", + eta: "大約還要", + metricsNote: "一格=一個八分音符,八格是一小節。驗證誤差是它猜下一個音的平均誤差,越低越好,5-gram 的成績是 1.46。", + rollPlain: "四個聲部的樂譜,由上到下是女高音、女低音、男高音、男低音", + isNew: "新", + judgeHint: "大約選 20 次就聽得出差別;選太多次它會只剩持續音。", + judgeListen: "聽它現在寫的", + judgeReset: "從頭開始", + blindNeedAll: "三段都猜完才能對答案", + blindWaiting: "聽完三段,再猜誰是誰", + blindStart: "出三段給我聽", + blindHow: "三段各四小節,一段是巴赫本人、一段是練好 1000 步的 AI、一段是五行數學規則,順序是隨機的。聽完再猜。", + blindGuess: "你覺得這段是誰寫的", + blindWho: { bach: "巴赫", ai: "AI", rules: "數學規則" }, + blindFavourite: "最喜歡這段", + blindReveal: "對答案", + blindAgain: "換三段", + blindScore: (right: number) => `猜對 ${right} / 3`, + blindYours: "你最喜歡的是", + blindCorrect: "猜對", blindWrong: "猜錯", blindAnswer: "答案", + blindChords: "和弦種類", + judgeStart: "載入一個練好的作曲家", judgeLoading: "下載模型中…", judgeReady: "它寫了兩段,聽完選你比較喜歡的", + pick: "選這段", candidate: (i: number): string => (i === 0 ? "A 段" : "B 段"), + choices: (n: number) => `你已經選了 ${n} 次`, + since: "從你開始選到現在", + thinking: "它正在照你的選擇改自己…", + judgeNote: "每選一次,模型往你選的那段靠近一點、離另一段遠一點(DPO)。它同時被拉在原本的樣子附近,不會一下子跑太遠。", + before: "調教前", now: "現在", +}; + +const en: typeof zh = { + train: "Start training", again: "Train again", stop: "Stop", + trainNote: "Trained from scratch in your browser, in about three minutes. Listen as it learns, or keep reading.", + loading: "Downloading 333 chorales…", failed: "The data failed to load. Reload the page to try again.", + step: "Step", seconds: "Elapsed", secondsUnit: "s", loss: "Error guessing the next note", + lossNote: "The curve is the training error; the dashed line is a 5-gram's validation score (1.46), to compare with each snapshot's validation error.", + autoplay: "Play each new snapshot", + snapshots: "It improvised at these moments", + snapshotAt: (step: number) => `Step ${step}`, + play: "Play", playing: "Playing", stopPlay: "Stop", + timbre: "Sound", timbres: { pad: "Warm pad", epiano: "Soft e-piano", flute: "Flute" }, + roll: (step: number) => `Six bars written at step ${step}: one line per voice, soprano, alto, tenor and bass from the top`, + voices: ["Soprano", "Alto", "Tenor", "Bass"], + inKey: "In key", crossings: "Voices crossing", held: "Held notes", parallels: "Parallel fifths", copied: "Longest copy", + per100: "/100 steps", eighths: "steps", + val: "Validation error", + waiting: "Press Start training: step 0's noodling will appear here.", + + stopTrain: "Stop training", + eta: "About", + metricsNote: "One step is an eighth note; eight of them make a bar. The validation error is how well it guesses the next note, lower is better; a 5-gram gets 1.46.", + rollPlain: "A score for four voices: soprano, alto, tenor and bass from the top", + isNew: "new", + judgeHint: "About 20 picks is enough to hear the difference; many more and it holds every note.", + judgeListen: "Hear what it writes now", + judgeReset: "Start over", + blindNeedAll: "Guess all three to see the answers", + blindWaiting: "Listen to all three, then guess", + blindStart: "Give me three pieces", + blindHow: "Four bars each: one by Bach, one by the AI trained for 1,000 steps, one by the five lines of maths, in a random order. Listen first, then guess.", + blindGuess: "Who wrote this one?", + blindWho: { bach: "Bach", ai: "The AI", rules: "The maths" }, + blindFavourite: "My favourite", + blindReveal: "Show the answers", + blindAgain: "Three more", + blindScore: (right: number) => `${right} of 3 right`, + blindYours: "You liked", + blindCorrect: "right", blindWrong: "wrong", blindAnswer: "Answer", + blindChords: "Distinct chords", + judgeStart: "Load a trained composer", judgeLoading: "Downloading the model…", judgeReady: "It wrote two pieces. Listen, then pick the one you like", + pick: "Pick this one", candidate: (i: number) => (i === 0 ? "A" : "B"), + choices: (n: number) => `${n} picks so far`, + since: "Since your first pick", + thinking: "Changing itself to match your pick…", + judgeNote: "Each pick moves the model a little toward the piece you chose and away from the other (DPO), while a leash keeps it near where it started.", + before: "Before", now: "Now", +}; + +export const useLabels = () => useLocaleLabels(zh, en); diff --git a/content/posts/music-ai/components/labs.ts b/content/posts/music-ai/components/labs.ts new file mode 100644 index 0000000..c340ac5 --- /dev/null +++ b/content/posts/music-ai/components/labs.ts @@ -0,0 +1,3 @@ +export { BlindLab } from "./blind-lab"; +export { ComposerLab } from "./composer-lab"; +export { JudgeLab } from "./judge-lab"; From 8a5f37bdfce68b5e427ccaccba7257fc27f802a2 Mon Sep 17 00:00:00 2001 From: PSheon Date: Wed, 23 Sep 2026 10:48:06 +0800 Subject: [PATCH 6/7] =?UTF-8?q?feat(music-ai):=20publish=20=E2=84=96=20014?= =?UTF-8?q?,=20an=20AI=20composer=20you=20train=20and=20tune=20yourself?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A small Transformer learns Bach's chorales in the reader's browser in three minutes, and they hear it learn. Then the honest half: the copy detector shows it composing rather than remembering (5 to 10 eighths at the end, once 32), the judge figure shows it gaming the score — asked for fewer parallel fifths it learns to stop moving — and five lines of maths get a blind test of their own. Numbers are the page's own recipe, measured twice in node and averaged (docs/research/music-ai). Sound is checked by hand: CI cannot hear, so e2e/music-ai.spec.ts covers training, a pick, the blind test's secrecy, and that nothing heavy is fetched before it is asked for. The smoke test's single-article tag moved to `multi-task`: `llm` now has two. Co-Authored-By: Claude Opus 5 (1M context) --- README.md | 12 ++- components/site/post-cover.tsx | 25 +++++ content/posts/music-ai/en.mdx | 165 +++++++++++++++++++++++++++++++++ content/posts/music-ai/zh.mdx | 117 +++++++++++++++++++++++ e2e/a11y.spec.ts | 2 + e2e/music-ai.spec.ts | 82 ++++++++++++++++ e2e/smoke.spec.ts | 4 +- 7 files changed, 402 insertions(+), 5 deletions(-) create mode 100644 content/posts/music-ai/en.mdx create mode 100644 content/posts/music-ai/zh.mdx create mode 100644 e2e/music-ai.spec.ts diff --git a/README.md b/README.md index bd12f8c..83202f9 100644 --- a/README.md +++ b/README.md @@ -6,12 +6,13 @@ **[blog.psheon.me](https://blog.psheon.me)** · [English](https://blog.psheon.me/en) · [中文](https://blog.psheon.me/zh) · [RSS](https://blog.psheon.me/en/feed.xml) An interactive blog. Every article builds one thing from scratch — a CNN, a Transformer, a diffusion model, -neuroevolution, a quadruped's walking policy, a SLAM system, a city of autonomous agents, a task scheduler, a path tracer — and +neuroevolution, a quadruped's walking policy, a SLAM system, a city of autonomous agents, a task scheduler, a path tracer, +an AI composer — and ships with instruments you can train, open up and break right in the page. Apart from MuJoCo's physics in article 006, everything is written in TypeScript and runs in the reader's tab: no TensorFlow.js, no ONNX Runtime, no server. Bilingual (繁體中文 / English). 從零實作的互動部落格:每一篇都能在瀏覽器裡訓練、拆開、弄壞。CNN、Transformer、擴散模型、神經演化、 -機器狗走路策略、SLAM、自己過日子的小鎮居民、任務排程器、路徑追蹤器,全部用 TypeScript 從零寫起,不靠任何機器學習函式庫, +機器狗走路策略、SLAM、自己過日子的小鎮居民、任務排程器、路徑追蹤器、AI 作曲家,全部用 TypeScript 從零寫起,不靠任何機器學習函式庫, 也不靠伺服器。 ![paul.notebook](https://blog.psheon.me/en/opengraph-image) @@ -20,6 +21,7 @@ everything is written in TypeScript and runs in the reader's tab: no TensorFlow. | № | English | 中文 | | --- | --- | --- | +| 014 | [Train your own AI composer in three minutes: from noodling to calm](https://blog.psheon.me/en/posts/music-ai) | [三分鐘訓練你的 AI 作曲家:聽它從亂彈到療癒](https://blog.psheon.me/zh/posts/music-ai) | | 013 | [A mini Figure AI in three minutes: one camera, one arm](https://blog.psheon.me/en/posts/head-camera) | [三分鐘打造迷你 Figure AI:只給它一顆相機、一隻手臂](https://blog.psheon.me/zh/posts/head-camera) | | 012 | [Putting a path tracer in a 3D playground: crash a car, gun a plane, fly a helicopter](https://blog.psheon.me/en/posts/light-playground) | [把光追放進 3D 遊樂園:體驗開車碰撞、飛機加速、直升機飛行](https://blog.psheon.me/zh/posts/light-playground) | | 011 | [How a picture clears from snow: a WebGPU path tracer from scratch](https://blog.psheon.me/en/posts/light-from-noise) | [一張圖怎麼從雪花變清晰:從零寫一個 WebGPU 路徑追蹤器](https://blog.psheon.me/zh/posts/light-from-noise) | @@ -118,6 +120,7 @@ Conventions that keep pages fast and honest: | `styles/launch-ui.css` | Glass, fade and hairline utilities from Launch UI | | `public/sw.js` | The service worker (network first for pages, cache first for immutable assets) | | `scripts/train-mnist` | One-off PyTorch training for article 001; exports weights and golden values for the tests | +| `scripts/music` | Packs article 014's chorales and its trained composer into `public/posts/music-ai/*.bin` | | `scripts/light` | Packs the light series' assets (the playground, the vehicles, the character and its clips) into `public/posts/light-playground/*.bin`: geometry, skeleton and names only, never a texture | | `tests` | Vitest suites, grouped by library and by article | | `e2e` | Playwright smoke tests and axe accessibility checks | @@ -142,4 +145,7 @@ Layout primitives and CSS utilities adapted from [Launch UI](https://www.launchu AAPL price data in the trading article is daily closing prices for 2024. The Lite3 robot model and walking policy in article 006 come from DEEP Robotics; their licences are in `public/lite3/`. The light series' playground is the geometry of [Sketchbook](https://github.com/swift502/Sketchbook)'s world by -Jan Blaha (MIT); its textures are not used and `world.glb` is never committed. +Jan Blaha (MIT); its textures are not used and `world.glb` is never committed. Article 014 trains on +[Craig Sapp's digital edition of Bach's 370 four-part chorales](https://github.com/craigsapp/bach-370-chorales) +(CC BY-NC-SA 4.0); the tokens and the trained model in `public/posts/music-ai/` are derived from it and carry the +same licence. diff --git a/components/site/post-cover.tsx b/components/site/post-cover.tsx index efa3c5b..2bb91fe 100644 --- a/components/site/post-cover.tsx +++ b/components/site/post-cover.tsx @@ -318,6 +318,30 @@ function HeadCamera() { ); } +/** № 014: a piano roll that starts as scattered notes and settles into four voices, the way the composer learns. */ +function MusicAi() { + const rand = rng(23); + // Four voices on their own rows. On the left each note is thrown anywhere; by the right they have found their rows. + const notes: { x: number; y: number; w: number; v: number }[] = []; + const rows = [26, 42, 58, 74]; + for (let v = 0; v < 4; v++) { + for (let x = 12; x < 150; ) { + const settled = Math.min(1, Math.max(0, (x - 30) / 70)); + const stray = (rand() - 0.5) * 46 * (1 - settled); + const w = r1(6 + rand() * (4 + 12 * settled)); + notes.push({ x: r1(x), y: r1(rows[v] + stray + (settled > 0.6 ? (rand() - 0.5) * 7 : 0)), w, v }); + x += w + 3; + } + } + const ink = [S, S3, S2, "var(--chart-5)"]; + return ( + <> + {[12, 47, 82, 117, 150].map((x) => )} + {notes.map((n, i) => )} + + ); +} + const covers: Record ReactNode> = { "cnn-from-scratch": Cnn, "ai-flappy-bird": Flappy, @@ -332,6 +356,7 @@ const covers: Record ReactNode> = { "light-from-noise": Light, "light-playground": Playground, "head-camera": HeadCamera, + "music-ai": MusicAi, }; export function PostCover({ slug, no, className }: { slug: string; no: number; className?: string }) { diff --git a/content/posts/music-ai/en.mdx b/content/posts/music-ai/en.mdx new file mode 100644 index 0000000..86b533d --- /dev/null +++ b/content/posts/music-ai/en.mdx @@ -0,0 +1,165 @@ +--- +title: "Train your own AI composer in three minutes: from noodling to calm" +description: "Train a small Transformer to write four-part chorales from scratch, in your browser, and listen to it turn noodling into music. Then judge it: twenty clicks make it calmer — and show you how it games the judge." +seoTitle: "Train an AI composer in three minutes" +seoDescription: "Train a Transformer from scratch in your browser until it writes four-part chorales, hear it learn, tune it to your taste, and watch it game the judge." +date: 2026-09-23 +tags: [generative, llm, from-scratch] +no: 14 +interactive: true +--- + +import { BlindLab, ComposerLab, JudgeLab } from "./components"; + +The composer below knows nothing at all. Press train and it reads 333 of Bach's four-part chorales in your browser, +improvising a piece for you at six moments as it learns, starting with the noodling of step 0. + + + + + +First, what this is not. It is not Suno: it does not sing and it does not produce audio. It writes a score — which +voice, which note, how long — and a synthesiser written from scratch plays it. The model has sixty-five thousand +parameters and its weights are 260 KB, about a tenth of a three-minute MP3. + +## Turning music into words + +A chorale is cut into a grid of eighth notes. Each step has four voices, soprano down to bass, and each voice-step is +one token: a new note is its pitch, a held note is `HOLD`, silence is `REST`. So what the model writes looks like +this: soprano, alto, tenor, bass, soprano, alto, tenor, bass, and so on. + +```ts title="content/posts/music-ai/components/music.ts" +export const HOLD = HI - LO + 1, REST = HOLD + 1, VOCAB = REST + 1; // 54 pitches + 2 = 56 words +``` + +From here it is exactly [№ 004's Transformer](/en/posts/transformer-from-scratch), the same code: look at the words +so far, guess the next one. There it learned to write numbers backwards; here it learns Bach. + +There is a trap in this: the only way the model knows whose turn it is, is *which position* a word is in. So every +window of the last 64 words has to start on the soprano, or the model reads every voice as its +neighbour.I walked into it the first time I let it compose: the bass climbed above the tenor and the voices +crossed six steps out of ten. Training was never affected, only composing. + +## What it learns first + +Train it a few times in figure 1 and the order barely changes. Here are two runs of figure 1's own recipe, five pieces measured at each +moment, averaged. The validation error is how well it guesses the next note, lower being better; parallel fifths are +four-part writing's cardinal sin, two voices a fifth apart moving the same way:The table was measured in +node, running the same code and the same 2,400 steps as the browser. On my M4 Pro a step takes about 69 ms in Chrome, +so the whole run is under three minutes. Scripts and output are in `docs/research/music-ai/`. + +| step | val. error | in key | voices crossing | held notes | parallel fifths (per 100 steps) | +| --- | --- | --- | --- | --- | --- | +| 0 | 4.51 | 82% | 87% | 0.5% | 3.9 | +| 100 | 2.01 | 99% | 36% | 78% | 1.1 | +| 250 | 1.60 | 99.7% | 1.9% | 50% | 9.8 | +| 500 | 1.39 | 99.6% | 1.1% | 55% | 10.0 | +| 1000 | 1.21 | 98.7% | 1.8% | 54% | 12.0 | +| 2000 | 1.07 | 99.2% | 1.3% | 53% | 8.9 | +| 2400 | 1.05 | 99.5% | 0% | 65% | 7.2 | +| Bach himself | | 97.7% | 2.6% | 45% | 0.16 | + +1. **Holding notes comes first.** At step 100, 78% of the notes are held: it has found that "carry on with the + previous note" is the best guess going, so it drones. +2. **Then the voices learn their ranges.** Crossings fall from 87% to 2% by step 250, and stay cleaner than Bach's. +3. **The key settles; the rhythm does not quite.** In-key notes hold at 99%, and held notes come back to about 50%, a little above Bach's 45% — then rise to 65% by the end of the run, which is slower than Bach. +4. **Parallel fifths never arrive.** Bach breaks the rule 0.16 times per hundred steps; the model spends the whole + run between 7 and 12. + +In my browser the validation error passes 1.46 inside a minute, which is the best a 5-gram — look at the four words +before, count how often each word follows — manages on the same data. The 5-gram composes far worse: it cannot see +past four words, so a voice that has held a note for one step has forgotten which note it is on, and the voices cross +72% of the time. + +## Is it composing, or remembering? + +The "longest copy" in figure 1 takes every step it wrote and looks for the longest run that appears, note for note, in +one of the 333 training chorales. At 1,000 steps it is 3 to 6 steps (a step is an eighth note, eight of them a bar) — +less than a bar. A chorale runs about 107 steps. + +So it is mostly composing. But the longer it trains, the longer the pieces it remembers: at 2,400 steps the longest +copy is 5 to 10 steps — and one piece in ten copied 32 steps, four whole bars, so it can hold a passage verbatim. + +## You be the judge + +The "calm" in the title is not something it knows. Bach's chorales are neither slow nor quiet; slowing down and +quietening are what you are about to tune into it. + +The trained model writes like Bach, which is not necessarily what you want to hear. Your turn: it writes two pieces, +you pick one, and it moves a little towards the one you picked and away from the other. Models like ChatGPT are tuned +on human preferences (RLHF); this is DPO, a simpler version that came later, with you as the judge. + + + + + +Keep picking the slower, quieter one and it slows down. I tried it with an automatic judge, set up exactly like this +figure: always pick the piece with more held notes, and after 20 picks held notes go from 48% to 64%; after 40 they +reach 78%, the chords lose half their variety, and it is on its way to a drone. + +### It finds the hole in the judge + +Then I had the automatic judge mark parallel fifths instead: always pick the piece that breaks the rule less. After 40 +picks the rate barely moves, 12.3 per hundred steps down to 10.9 — but held notes are up from 48% to 58% and the +chords have lost a quarter of their variety. By 80 picks the rate is 8.0, held notes 63%, and distinct chords are down +from 45 to 29. + +It really has brought the mistakes down, and the way it did it is to **move less**: a voice that stays put cannot walk +into a parallel fifth. + +This is reward hacking, one of the hardest problems in training large language models: the judge measures one thing, +the model optimises "keep the judge happy", and any gap between the two is a gap it will find. The textbook has two +answers: + +- **A score that cannot be gamed that way.** Count the mistakes *per step on which voices move*, so standing still + buys nothing. +- **A shorter leash.** DPO has a β that decides how far the model may drift from the model it started as. + +At the strength this figure uses, the two answers buy very little: over the same 80 picks the hack-proof judge gets +parallel fifths to 7.0 against the gameable judge's 8.0, and both end up with 63% held notes. Both still learn to move +less first. + +The difference shows when you push harder. Updating once per four picks, at three times the learning rate: the +gameable judge gets to 5.9, at the price of 73% held notes and half the chords; the hack-proof judge gets to 7.0 with +52% held notes and 41 chords, near where it started. **The harder you optimise, the more gaming pays** — which is +exactly the position anyone tuning a large model is in. The figure above is deliberately gentle, so that twenty clicks +do not wreck it. + +## Can it beat five lines of maths? + +Its last opponent uses no AI at all and fits in five lines: a 1/f random walk over a C pentatonic scale, above a fixed +C–Am–F–G, a bar each. + +```ts title="simplified from content/posts/music-ai/components/music.ts" +const scale = [60, 62, 64, 67, 69, 72, 74, 76, 79, 81]; // C pentatonic +const chords = [[48, 55, 64], [45, 57, 64], [41, 53, 60], [43, 55, 62]]; +for (let d = 0; d < 4; d++) if (t % (2 << d) === 0) dice[d] = rng(); // four dice +const soprano = scale[Math.floor(mean(dice) * scale.length)]; // a 1/f melody +voices.push([soprano, ...chords[Math.floor(t / 8) % 4]]); // a chord a bar +``` + +It never plays a wrong note and its voices never cross. + +But it breaks the parallel-fifths rule 19.8 times per hundred steps, over a hundred times Bach's rate, and it has half +his harmonic variety. Four voices shifting together *are* a run of parallel fifths. + +So: can you hear it? Three pieces below, four bars each — one by Bach (from the 37 chorales the model never saw), one +by the model after 1,000 steps, one by the five lines of maths, shuffled every time. + + + + + +Once you have the answers, the two numbers under each card tell you that the three differ by more than how they sound. + +## The data and the sound + +- The data is Craig Sapp's edition of [Bach's 370 four-part chorales](https://github.com/craigsapp/bach-370-chorales), + licensed CC BY-NC-SA 4.0; the tokens and the trained model this page uses carry the same licence. Every chorale is + moved to C major or A minor and sampled onto a grid of eighth notes: 333 to train on, 37 kept back to check against. +- The synthesiser is written from scratch, with none of the browser's own instruments or effects: the warm pad is a + fundamental and a soft octave, each doubled 4 cents apart, with a slow attack; the reverb follows Freeverb's layout, + so the tail darkens as it fades. The first version was an organ of five harmonics, and the first thing I heard was + how sharp it was: 6 to 16 dB more in the 1–4 kHz band than this one. +- Everything here that measures "like Bach" is a proxy: in key, voices crossing, parallel fifths, held notes, chord + variety. They can say whether a piece follows the rules. They cannot say whether it is any good. diff --git a/content/posts/music-ai/zh.mdx b/content/posts/music-ai/zh.mdx new file mode 100644 index 0000000..473d97d --- /dev/null +++ b/content/posts/music-ai/zh.mdx @@ -0,0 +1,117 @@ +--- +title: 三分鐘訓練你的 AI 作曲家:聽它從亂彈到療癒 +description: 在瀏覽器裡從零訓練一個會寫四部合唱的小 Transformer,邊練邊聽它從亂彈變成音樂。然後你當評審,點二十下把它調得更放鬆;也看它怎麼找到評審的漏洞。 +seoTitle: 三分鐘訓練你的 AI 作曲家 +seoDescription: 在瀏覽器裡從零訓練一個會寫四部合唱的小 Transformer,邊練邊聽它進步,再當評審把它調得更放鬆,看它怎麼鑽評審的漏洞。 +date: 2026-09-23 +tags: [generative, llm, from-scratch] +no: 14 +interactive: true +--- + +import { BlindLab, ComposerLab, JudgeLab } from "./components"; + +下面這個作曲家現在什麼都不會。按下訓練,它會在你的瀏覽器裡讀巴赫的 333 首四部合唱,一邊學,一邊在六個時刻即興一段給你聽,從第 0 步的亂彈開始。 + + + + + +先說這不是什麼。這不是 Suno:它不會唱歌,也不產生聲音檔。它寫的是樂譜,「哪個聲部、什麼音、拖多長」,再由一個從零寫的合成器演奏出來。模型只有六萬五千個參數,權重檔 260 KB,大約是一首三分鐘 MP3 的十分之一。 + +## 音樂怎麼變成字 + +一首合唱被切成一格一格的八分音符。每一格有四個聲部,從女高音到男低音,每個聲部是一個 token:新的音就是它的音高,延續上一個音是 `HOLD`,休止是 `REST`。所以模型寫的東西長這樣:女高、女低、男高、男低,女高、女低、男高、男低…… + +```ts title="content/posts/music-ai/components/music.ts" +export const HOLD = HI - LO + 1, REST = HOLD + 1, VOCAB = REST + 1; // 54 個音高 + 2 = 56 個字 +``` + +接下來就和 [№ 004 的 Transformer](/zh/posts/transformer-from-scratch) 一模一樣,連程式都是同一份:看前面的字,猜下一個字。那篇它學的是把數字倒過來寫,這篇學的是巴赫。 + +這裡有個陷阱:模型只靠「這是第幾個字」分辨聲部,所以每次取最近的 64 個字,開頭都必須剛好是女高音,否則它會把每個聲部都當成隔壁那一個。我第一次讓它作曲時就踩到了:男低音一路爬到男高音上面,六成的時間聲部都交錯。訓練本身沒受影響,只有作曲時會錯。 + +## 它先學會什麼 + +在圖 1 多練幾次,會發現它每次學會的順序都差不多。我用圖 1 的配方練了兩次,每個時刻寫五段、量同樣的東西,下面是兩次的平均。驗證誤差是它猜下一個音的平均誤差,越低越好;平行五度是四部寫作的頭號禁忌,指兩個聲部隔著純五度一起往同一個方向走:表是在 node 裡跑的,和瀏覽器裡是同一份程式、同樣 2400 步。在我的 M4 Pro 上,Chrome 裡一步約 69 毫秒,整輪不到三分鐘。量法和輸出在 `docs/research/music-ai/`。 + +| 步數 | 驗證誤差 | 在調上 | 聲部交錯 | 拖長的音 | 平行五度(每百格) | +| --- | --- | --- | --- | --- | --- | +| 0 | 4.51 | 82% | 87% | 0.5% | 3.9 | +| 100 | 2.01 | 99% | 36% | 78% | 1.1 | +| 250 | 1.60 | 99.7% | 1.9% | 50% | 9.8 | +| 500 | 1.39 | 99.6% | 1.1% | 55% | 10.0 | +| 1000 | 1.21 | 98.7% | 1.8% | 54% | 12.0 | +| 2000 | 1.07 | 99.2% | 1.3% | 53% | 8.9 | +| 2400 | 1.05 | 99.5% | 0% | 65% | 7.2 | +| 巴赫本人 | | 97.7% | 2.6% | 45% | 0.16 | + +1. **先學會拖長音。** 第 100 步有 78% 的音都是拖著的:它發現「繼續上一個音」最常猜對,於是幾乎只會持續音。 +2. **再學會各守各的音域。** 聲部交錯從 87% 掉到 250 步的 2%,之後就一直比巴赫還乾淨。 +3. **調性穩下來,節奏沒有完全穩。** 調內音一路維持在 99%;拖長的音回到 50% 上下,比巴赫的 45% 多一點,到訓練尾聲又升到 65%,聽起來會比巴赫慢。 +4. **平行五度學不會。** 巴赫一百格才犯 0.16 次,它整輪都在 7 到 12 次之間晃。 + +在我的瀏覽器裡,驗證誤差不到一分鐘就低於 1.46,那是一個 5-gram(只看前面四個字、把次數數起來)在同一份資料上的最好成績。5-gram 的作曲更慘:它看不到四個字以前,一個聲部拖了一格,它就忘了自己在哪個音上,72% 的時間聲部交錯。 + +## 它在作曲,還是在背譜? + +圖 1 裡的「最長抄襲」,是拿它寫的每一格去比對 333 首訓練曲目,找出和其中一首一模一樣、連續最長的一段。練到 1000 步時是 3 到 6 格(一格是一個八分音符,八格一小節),不到一小節;一首聖詠平均有 107 格。 + +所以它多半是在作曲。但練得越久,記住的片段越長:2400 步時變成 5 到 10 格。而且十段裡出現過一段整整抄了 32 格、也就是四小節的例外——它確實有能力把整段譜背下來。 + +## 你當評審 + +標題說的「療癒」不是它本來就會的。巴赫的合唱不慢也不安靜;慢下來、安靜下來,是接下來你自己調出來的。 + +練好的模型寫得像巴赫,但不一定是你想聽的。現在換你:它一次寫兩段,你選一段,它就往你選的那段靠近一點,離另一段遠一點。ChatGPT 這類模型就是用人的偏好調教出來的(RLHF);這裡用的是它後來一個比較簡單的版本 DPO,只是評審換成你。 + + + + + +你一直選比較慢、比較安靜的那段,它就會慢下來。我用一個自動評審試過,設定和這張圖一模一樣:每次選「拖長的音比較多」的那段,選 20 次,拖長音從 48% 升到 64%;選 40 次變成 78%,和弦的種類掉了一半,開始只剩持續音。 + +### 它會找評審的漏洞 + +然後我讓自動評審改考平行五度:每次選犯得比較少的那段。選 40 次,平行五度從每百格 12.3 次只降到 10.9 次,幾乎沒動;拖長音倒是從 48% 升到 58%,和弦的種類少了四分之一。選到 80 次,平行五度降到 8.0,拖長音 63%、和弦種類從 45 掉到 29。 + +它確實把犯規壓下來了,但用的辦法是**少動**:不動的聲部不可能走出平行五度。 + +這叫 reward hacking,是訓練大型語言模型時最頭痛的問題之一:評審量的是一件事,模型最佳化的是「讓評審滿意」,兩者只要有一點縫,它就會找到。書上的修法有兩招: + +- **換一個鑽不了漏洞的評分。** 改算「每次有聲部移動時,犯了幾次」,不動就拿不到好處。 +- **把繩子拉緊。** DPO 裡有一個 β,決定模型可以離原本的自己多遠。 + +在這張圖的力道下,這兩招只買到一點點:同樣選 80 次,防鑽的評審把平行五度壓到 7.0,可鑽的是 8.0,而兩者的拖長音都是 63%。它們都還是先學會少動。 + +差別要推得更用力才看得出來。我把更新改成累積四次一起做、學習率調成三倍:可鑽的評審把平行五度壓到 5.9,代價是拖長音衝到 73%、和弦種類只剩一半;防鑽的評審壓到 7.0,拖長音 52%、和弦種類 41,和原本差不多。**越用力優化,鑽漏洞越划算**,這正是大模型調教時的處境。上面那張圖故意留在溫和的力道,免得你點個二十下它就跑偏。 + +## 它贏得過五行數學嗎? + +最後是一個不用任何 AI 的對手,五行就寫得完:五聲音階(C D E G A)上的一條 1/f 隨機旋律,底下墊著固定的 C–Am–F–G 四個和弦。 + +```ts title="簡化自 content/posts/music-ai/components/music.ts" +const scale = [60, 62, 64, 67, 69, 72, 74, 76, 79, 81]; // C 五聲音階 +const chords = [[48, 55, 64], [45, 57, 64], [41, 53, 60], [43, 55, 62]]; +for (let d = 0; d < 4; d++) if (t % (2 << d) === 0) dice[d] = rng(); // 四顆骰子 +const soprano = scale[Math.floor(mean(dice) * scale.length)]; // 1/f 旋律 +voices.push([soprano, ...chords[Math.floor(t / 8) % 4]]); // 每小節換和弦 +``` + +它永遠不會彈錯音,聲部也永遠不會交錯。 + +但它的平行五度是每百格 19.8 次,巴赫的一百多倍,和弦種類只有巴赫的一半。四個和弦一起平移,就是一連串的平行五度。 + +所以,聽得出來嗎?下面三段各四小節,一段是巴赫本人(模型沒看過的那 37 首裡的一段)、一段是練好 1000 步的 AI、一段是五行數學,順序每次都重新洗過。 + + + + + +對完答案,卡片下面那兩個數字會告訴你,三段的差別不只在聽感上。 + +## 資料和聲音 + +- 資料是 Craig Sapp 整理的[巴赫 370 首四部聖詠](https://github.com/craigsapp/bach-370-chorales),授權是 CC BY-NC-SA 4.0;這一頁用到的樂譜資料和練好的模型,也以同樣的授權提供。每一首都移到 C 大調或 a 小調,切成八分音符的格子,333 首拿來訓練,37 首留著驗證。 +- 合成器是自己寫的,沒有用瀏覽器內建的樂器或效果:溫暖墊音是基音加一個輕輕的八度,各疊兩個相差 4 音分的音,慢慢起音;殘響照 Freeverb 的結構,尾音會越來越暗。第一版是五個泛音的風琴,我第一次聽就覺得太尖:1–4 kHz 比現在多了 6 到 16 dB。 +- 所有的「像不像巴赫」都是代理指標:在不在調上、聲部有沒有交錯、平行五度、拖長音的比例、和弦的種類。它們說得出一段音樂「守不守規矩」,說不出好不好聽。 diff --git a/e2e/a11y.spec.ts b/e2e/a11y.spec.ts index 8594d4c..f65b32d 100644 --- a/e2e/a11y.spec.ts +++ b/e2e/a11y.spec.ts @@ -19,6 +19,8 @@ export const pages = [ "/en/posts/city-of-agents", "/zh/posts/task-scheduler", "/en/posts/task-scheduler", + "/zh/posts/music-ai", + "/en/posts/music-ai", ]; for (const theme of ["dark", "light"] as const) { diff --git a/e2e/music-ai.spec.ts b/e2e/music-ai.spec.ts new file mode 100644 index 0000000..e682333 --- /dev/null +++ b/e2e/music-ai.spec.ts @@ -0,0 +1,82 @@ +import AxeBuilder from "@axe-core/playwright"; +import { expect, test } from "@playwright/test"; + +/* + * № 014, music-ai. The figures make sound, which CI cannot hear; what is checked here is everything around it — + * that training really runs and produces a score, that a pick changes the model, and that the blind test keeps its + * answers to itself until the reader has guessed. + */ +const ZH = "/zh/posts/music-ai", EN = "/en/posts/music-ai"; + +test.beforeEach(async ({ request }) => { + test.skip((await request.get(ZH)).status() === 404, "music-ai is still a draft"); +}); + +test("fig. 01: training writes a score and measures it", async ({ page }) => { + // A hundred steps of a 65k-parameter Transformer in a worker: about 7 s alone, much more with the suite running. + test.setTimeout(180_000); + await page.goto(ZH); + const figure = page.locator('figure[data-instrument="composer / train"]'); + await figure.scrollIntoViewIfNeeded(); + await expect(figure.getByRole("alert")).toHaveCount(0); + await figure.getByTestId("music-train").click(); + // Step 0's noodling arrives before any training, then the first real snapshot. + await expect(figure.getByRole("button", { name: /第 0 步/ })).toBeVisible({ timeout: 60_000 }); + await expect(figure.getByRole("button", { name: /第 100 步/ })).toBeVisible({ timeout: 120_000 }); + // The roll is drawn from what it wrote: notes, not an empty box. + await expect(figure.locator("svg[role=img] rect").first()).toBeVisible(); + await expect(figure.getByTestId("music-report")).toContainText("%"); + await figure.getByRole("button", { name: "停止訓練" }).click(); + await expect(figure.getByTestId("music-train")).toBeVisible(); +}); + +test("fig. 02: a pick tunes the model and the numbers say what changed", async ({ page }) => { + test.setTimeout(180_000); + await page.goto(ZH); + const figure = page.locator('figure[data-instrument="composer / judge"]'); + await figure.scrollIntoViewIfNeeded(); + await figure.getByTestId("music-judge-load").click(); + await expect(figure.getByTestId("music-pick-0")).toBeEnabled({ timeout: 60_000 }); + await figure.getByTestId("music-pick-0").click(); + await expect(figure.getByTestId("music-judge-stats")).toContainText("→", { timeout: 60_000 }); + await expect(figure.getByText(/你已經選了 1 次/)).toBeVisible(); +}); + +test("fig. 03: the blind test hides the answers until all three are guessed", async ({ page }) => { + test.setTimeout(180_000); + await page.goto(ZH); + const figure = page.locator('figure[data-instrument="composer / blind"]'); + await figure.scrollIntoViewIfNeeded(); + await figure.getByTestId("music-blind-deal").click(); + await expect(figure.getByTestId("music-blind-play-2")).toBeVisible({ timeout: 60_000 }); + // Nothing on screen says who wrote what, and the rolls are not drawn yet ("對答案" is the button, "答案:" is the reveal). + await expect(figure.getByText(/答案:/)).toHaveCount(0); + await expect(figure.locator("svg[role=img]")).toHaveCount(0); + await expect(figure.getByTestId("music-blind-reveal")).toBeDisabled(); + // The guesses live in a fieldset each; the timbre picker is a group too, so ask for the fieldsets. + for (let i = 0; i < 3; i++) await figure.locator("fieldset").nth(i).getByRole("button", { name: "巴赫" }).click(); + await figure.getByTestId("music-blind-reveal").click(); + await expect(figure.getByTestId("music-blind-score")).toContainText("/ 3"); + await expect(figure.locator("svg[role=img]")).toHaveCount(3); +}); + +test("nothing heavy is fetched before the reader asks for it", async ({ page }) => { + const requests: string[] = []; + page.on("request", (r) => requests.push(r.url())); + await page.goto(ZH, { waitUntil: "networkidle" }); + // The chorales and the trained model arrive on Start training / Load, not with the article. + expect(requests.filter((url) => /music-ai\/\w+\.bin/.test(url))).toEqual([]); +}); + +for (const theme of ["dark", "light"] as const) { + for (const path of [ZH, EN]) { + test(`axe: ${path} (${theme})`, async ({ page }) => { + await page.addInitScript((value) => localStorage.setItem("theme", value), theme); + await page.goto(path); + await expect(page.locator("html")).toHaveClass(new RegExp(theme)); + await page.waitForTimeout(1500); + const { violations } = await new AxeBuilder({ page }).withTags(["wcag2a", "wcag2aa", "wcag21a", "wcag21aa"]).analyze(); + expect(violations.map((v) => `${v.id}: ${v.nodes.map((n) => n.target.join(" ")).join(" | ")}`)).toEqual([]); + }); + } +} diff --git a/e2e/smoke.spec.ts b/e2e/smoke.spec.ts index 6f216d2..57259cb 100644 --- a/e2e/smoke.spec.ts +++ b/e2e/smoke.spec.ts @@ -133,8 +133,8 @@ test("feeds and sitemap are served", async ({ request }) => { const sitemap = await (await request.get("/sitemap.xml")).text(); expect(sitemap).toContain("/zh/tags/from-scratch"); // A tag with one article is left out, and its page asks not to be indexed. - expect(sitemap).not.toContain("/zh/tags/llm"); - expect(await (await request.get("/zh/tags/llm")).text()).toContain('content="noindex, follow"'); + expect(sitemap).not.toContain("/zh/tags/multi-task"); + expect(await (await request.get("/zh/tags/multi-task")).text()).toContain('content="noindex, follow"'); }); // Next replaces `alternates` and `openGraph` wholesale when a page sets them, which once cost article From 83d5efdca3669f1bd428b9f328ddbd69f4d9e3e9 Mon Sep 17 00:00:00 2001 From: PSheon Date: Wed, 23 Sep 2026 10:48:06 +0800 Subject: [PATCH 7/7] docs(research): the music-AI spike, and the rules sound follows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit RESULTS.md carries every number the article quotes and the ones it does not: the licence trail for the data, both training recipes, the preference-tuning tables at the research push and at the page's gentler one (where the reward-hacking contrast does not reproduce, which the article now says), the timbre work, and two ways of measuring harshness that were wrong. DESIGN.md §4 gains "Instruments that make sound": one player per page, sound that stops when the figures go, a piece that ends with its music and not its reverb, and the fact that CI cannot hear. HANDOFF.md gets article 014, and COMMITS.md two scopes that were already in the log. Co-Authored-By: Claude Opus 5 (1M context) --- docs/COMMITS.md | 3 +- docs/DESIGN.md | 17 ++ docs/HANDOFF.md | 24 ++- docs/research/music-ai/RESULTS.md | 238 +++++++++++++++++++++++++ docs/research/music-ai/baseline.ts.txt | 74 ++++++++ docs/research/music-ai/convert.py.txt | 52 ++++++ docs/research/music-ai/dpo.ts.txt | 121 +++++++++++++ docs/research/music-ai/eval.ts.txt | 57 ++++++ docs/research/music-ai/hiband.ts.txt | 27 +++ docs/research/music-ai/music.ts.txt | 162 +++++++++++++++++ docs/research/music-ai/synth.ts.txt | 122 +++++++++++++ docs/research/music-ai/train.ts.txt | 88 +++++++++ 12 files changed, 981 insertions(+), 4 deletions(-) create mode 100644 docs/research/music-ai/RESULTS.md create mode 100644 docs/research/music-ai/baseline.ts.txt create mode 100644 docs/research/music-ai/convert.py.txt create mode 100644 docs/research/music-ai/dpo.ts.txt create mode 100644 docs/research/music-ai/eval.ts.txt create mode 100644 docs/research/music-ai/hiband.ts.txt create mode 100644 docs/research/music-ai/music.ts.txt create mode 100644 docs/research/music-ai/synth.ts.txt create mode 100644 docs/research/music-ai/train.ts.txt diff --git a/docs/COMMITS.md b/docs/COMMITS.md index 70a0753..b8f4d7b 100644 --- a/docs/COMMITS.md +++ b/docs/COMMITS.md @@ -40,7 +40,8 @@ The area, lowercase, `[a-z0-9._/-]`. Optional only when the change really belong (`docs: production is blog.psheon.me`). - **An article**: its slug or the short name already in the log: `cnn`, `transformer`, `diffusion`, `flappy`, `lite3`, - `slam`, `city`, `scheduler`, `light`, `playground` (the figure), `light-playground` (the article's text). + `slam`, `city`, `scheduler`, `light`, `playground` (the figure), `light-playground` (the article's text), + `head-camera`, `music-ai`. - **Shared code**: `rt` (`lib/rt`), `ml`, `controls` (`components/lab`), `ui`, `site`, `home`, `header`, `search`, `post`. - **Everything else**: `e2e`, `deps`, `research` (`docs/research`), `repo`, `release` (release PR titles only). diff --git a/docs/DESIGN.md b/docs/DESIGN.md index bd4eeb7..27ea24e 100644 --- a/docs/DESIGN.md +++ b/docs/DESIGN.md @@ -130,6 +130,23 @@ Rules inside an instrument: - A stage whose content depends on colour (coloured point clouds) stays dark in both themes: wrap it in `className="dark bg-[#070918]"`. +### Instruments that make sound + +Article 014 is the first one that plays music, and its rules hold for the next one: + +- **One player for the page.** `content/posts/music-ai/components/player.ts` owns the single `AudioContext` and the + synthesiser worker; a figure asks it to play and whatever was playing stops. The context is created on the reader's + first press of Play, because a browser will not make sound before a gesture. +- **Sound stops when the figures go.** The last figure to unmount stops playback, terminates the worker and closes + the context, or the music plays on over the next article. +- **A piece ends when the music does.** The rendered buffer carries a reverb tail; treating the end of the buffer as + the end of playback left Play saying "Stop" over several seconds of silence. +- **Changing the instrument keeps the position** and the old sound plays until the new one is ready. +- **Nothing is heard by CI**, so the sound is made by pure functions with tests, and the E2E tests check everything + around it. A figure that only makes sound is not accessible: the piano roll, the numbers and the captions carry the + same information. +- Audio and models are fetched when the reader asks for them, never with the article (`e2e/music-ai.spec.ts` checks). + ### Controls for steering something by hand One thumb stick for the whole site: `components/lab/stick.tsx` (drag it, or focus it and use the arrows / W A S D; it diff --git a/docs/HANDOFF.md b/docs/HANDOFF.md index dd0ae2f..0e68450 100644 --- a/docs/HANDOFF.md +++ b/docs/HANDOFF.md @@ -1,4 +1,4 @@ -# Handoff — main session, last revised 2026-09-22 +# Handoff — main session, last revised 2026-09-23 For whoever picks this up next. Read this, then the memory files under `~/.claude/projects/-Users-paul-jiang-Desktop-Paul/memory/` (they are loaded automatically, this file is not), then @@ -14,16 +14,34 @@ For whoever picks this up next. Read this, then the memory files under | Production | (since 2026-09-21; DNS on Cloudflare, CNAME to Vercel, DNS only). Vercel project `paul-notebook`, deploys `main`. `paul-notebook.vercel.app` redirects 308 to it, path kept. Production env: `NEXT_PUBLIC_SITE_URL=https://blog.psheon.me` | | Dev server | `pnpm dev` on :3000 | | Other worktrees | None since 2026-09-22: `feat/city-of-agents`, `feat/sche` and `feat/vla` are merged and deleted. One writer per checkout | -| Tests | 323 unit tests (2 skipped) and 206 E2E runs (two projects: desktop, mobile), plus axe on every article. CI runs all of it on every push | +| Tests | 323 unit tests (2 skipped) and 218 E2E runs (two projects: desktop, mobile), plus axe on every article. CI runs all of it on every push | Published, in both languages: 001 CNN, 002 Flappy Bird, 003 trading agent, 004 Transformer, 005 HydraNet, 006 Lite3, 007 point-cloud diffusion, 008 2D SLAM, 009 city of agents, 010 a task scheduler from scratch (published 2026-09-21; built on `feat/sche` by another session), 011 and 012 the light series (PR #14), 013 `head-camera` (PR #15, merged from -`feat/vla`). All thirteen had their copy polished with Paul on 2026-09-22, item by item. The earlier PCB-flip +`feat/vla`), 014 `music-ai` (2026-09-23). Articles 001–013 had their copy polished with Paul on 2026-09-22, item by +item, and 014 the same way as it was written. The earlier PCB-flip VLA draft (№ 014) was dropped the same day, Paul found it dull; its simulation (arm, rasteriser, world) lives on as `content/posts/head-camera/components/sim`, which 013 imports, with its tests in `tests/head-camera/`; its notes stay in `docs/research/pcb-flip-vla/`. A draft shows only in `next dev`, with a mark in the page's language ("草稿" / "DRAFT"). +### № 014, the AI composer (2026-09-23) + +A small Transformer (65k parameters, `lib/ml` again) learns Bach's four-part chorales in the reader's browser in about +three minutes, and a synthesiser written sample by sample plays what it writes. Three figures: train and listen, +tune it with your own picks (DPO, and it games the judge), and a blind test against Bach and five lines of maths. + +- `docs/research/music-ai/RESULTS.md` holds every number, both recipes (the research schedule and the page's), the + timbre work and the measurements that were thrown away. Copies of the research scripts sit beside it. +- The data is **CC BY-NC-SA 4.0** (Craig Sapp's edition of the chorales), and so are `public/posts/music-ai/*.bin` + and anything else derived from them: attribution is in the README, the article and the licence note. +- `scripts/music/convert.py` and `scripts/music/pack.ts` rebuild those two files byte for byte from the corpus clone + and a checkpoint, both of which live outside git in `Desktop/Paul/music-work/` (with every run and the MP3 packs). +- Sound has its own rules now: DESIGN.md §4 "Instruments that make sound". The player is one `AudioContext` and one + worker for the page; figures 02 and 03 share a second worker, and every message carries which figure asked. +- CI cannot hear: `e2e/music-ai.spec.ts` checks training, tuning, the blind test's secrecy and that nothing heavy is + fetched before the reader asks. + ### The light series (two articles, published 2026-09-22) `light-from-noise` (№ 011, part one: what path tracing is) and `light-playground` (№ 012, part two: a playground you diff --git a/docs/research/music-ai/RESULTS.md b/docs/research/music-ai/RESULTS.md new file mode 100644 index 0000000..4bbe70d --- /dev/null +++ b/docs/research/music-ai/RESULTS.md @@ -0,0 +1,238 @@ +# Music AI spike — lab notebook + +Question: can a reader train a small music model in the browser, in minutes, that makes calm music worth listening +to? And the honest follow-ups: does it compose or copy, and does it beat a few lines of rules? + +Everything here ran in node with `lib/ml` (the code the browser runs), on an M4 Pro. Scripts, data and runs are in +`Desktop/Paul/music-work/` (outside git); copies of the scripts are kept beside this file. + +## Data (2026-09-22) + +- **Source: Craig Sapp's digital edition of 370 Bach chorales**, , + **CC BY-NC-SA 4.0**. Non-commercial use with attribution is fine for this site; anything derived from it that we + publish (the token file, trained weights) must carry the same licence. +- Rejected: `czhuang/JSB-Chorales-dataset` (the one papers use) declares no licence; music21's chorales are + distributed with permission for music21 only; the Nottingham folk set is GPL-3.0 and mostly jigs and reels, not calm. +- `convert.py` (music21) parses the kern files, transposes each chorale to C major or A minor (the smaller shift, at + most a tritone), and samples an eighth-note grid: per step, the MIDI pitch of S A T B, whether it starts there, and + fermatas. All 370 convert. 39,602 steps (107 per chorale on average), 194 major, 176 minor; 331 in 4/4, 38 in 3/4. + Rests are 1.0 % of voice-steps. Spot check: chor001 (G major, shifted +5) opens C3 E4 G4 C5, which is its GG B d g. +- Tokens: one per voice per step, S A T B: a new note is its pitch (MIDI 31–84, 54 ids), a held one HOLD, silence + REST. Vocabulary 56. Split by chorale with a fixed seed: 333 train (143,232 tokens), 37 validation (15,176). + +## Yardsticks (`baseline.ts`) + +None of these says "beautiful". They say whether the texture does what four-part writing does. Reference values are +Bach's own validation chorales. + +| | in key | parallel 5ths/8ves per 100 steps | voice crossings | roughness | distinct chords per 100 steps | +| --- | --- | --- | --- | --- | --- | +| Bach (37 validation chorales) | 97.7 % | 0.16 | 2.6 % | 0.67 | 40 | +| Rules: pentatonic 1/f melody over I–vi–IV–V (5 seeds) | 100 % | 19.8 | 0 % | 0.50 | 19 | +| 5-gram, T 0.7 (3 seeds) | 79.5 % | 2.1 | 72 % | 0.90 | 83 | + +- In key: C major's pitch classes plus F# and G# (A minor's raised 6th and 7th). Roughness: Plomp–Levelt after + Sethares, 6 harmonics at 1/k per note, summed over all partial pairs, averaged per step. +- The rule composer never plays a wrong note and is the smoothest, but moves its block chords in parallel + constantly: 120 times Bach's rate. It also has half the harmonic variety. +- n-gram validation loss (nats per token, add-0.05 smoothing, the context includes which voice is next): + 1-gram 2.133, 2-gram 1.695, 3-gram 1.510, 4-gram 1.472, **5-gram 1.462**, 6-gram 1.595, 8-gram 1.927. + **1.46 is the line the Transformer has to cross.** +- The 5-gram composes badly despite that loss: voices cross on 72 % of steps. Its window is the previous step's four + tokens, and a held note is the token HOLD, so a voice that has held for one step has forgotten its own pitch. + +## Transformer runs (`train.ts`) + +Adam, lr 3e-3 with 100 warm-up steps and cosine decay to a tenth, batch 8 windows, 4 heads, windows start on a step +boundary. Samples start from a C major chord (C5 G4 E4 C3) and run 64 steps (8 bars); three seeds per temperature. + +Speed (node, one thread): d 64, 2 layers, 32-step window (128 tokens), 114,944 parameters: about 290 ms per step. +d 48, 2 layers, 16-step window: about 145 ms per step. So three minutes in the page is roughly 600 or 1,250 steps. + +**A bug to remember:** the first samples crossed voices on 60 % of steps. Sampling slid the context window one token +at a time, so position 0 stopped being the soprano and every voice read as its neighbour. The window must slide by +whole steps (`ceil((len − ctx) / 4) × 4`). Training was never affected; `eval.ts` re-scores saved checkpoints with the +fix. Any number logged by `train.ts` before the fix (its `log.txt` checkpoint lines) is void. + +### Run B: d 48, 2 layers, 16-step window (64 tokens), 4,000 steps, 300 s in all + +`eval.ts`, 5 seeds × 64 steps from the C major chord, temperature 0.7: + +| step | ≈ time | val loss | in key | parallels /100 | crossings | held | chords /100 | longest copy (steps) | +| --- | --- | --- | --- | --- | --- | --- | --- | --- | +| 0 | 0 | 4.11 | 88 % | 5.3 | 84 % | 1 % | 96 | 1 | +| 100 | 15 s | 1.98 | 99 % | 1.9 | 35 % | 77 % | 31 | 2–8 | +| 250 | 35 s | 1.58 | 99.6 % | 10.3 | 4.4 % | 45 % | 52 | 2–4 | +| 500 | 70 s | 1.40 | 99 % | 11.9 | 0.3 % | 49 % | 35 | 4–8 | +| 1000 | 145 s | 1.20 | 99.4 % | 7.5 | 1.9 % | 47 % | 41 | 4–6 | +| 2000 | | 1.08 | 99.7 % | 6.6 | 1.9 % | 48 % | 42 | 4–6 | +| 4000 | | 0.98 | 98.9 % | 6.6 | 0.3 % | 55 % | 36 | 6–9 | + +(The times assume ~145 ms per step; this run shared the machine with run A, so its own wall clock was not clean.) + +- It passes the 5-gram's 1.46 before step 500, a little over a minute. +- Order of learning, as the table shows it: first "hold notes" (step 100 holds 77 %: it drones), then voices stop + crossing (by 250–500), key and rhythm settle; parallel fifths are last and never get near Bach (6.6 vs 0.16). +- Copying grows with training: at 1,000 steps the longest stretch found verbatim in the training set is 4–6 eighths + (under a bar); at 4,000, 6–9. For comparison, a chorale is about 107 steps long. +- At temperature 1.0 everything is looser (crossings 4–15 %, in key 97 %). + +### Preference tuning (`dpo.ts`): the reader's clicks, simulated + +DPO on the step-1000 checkpoint of run B. Each "click" is a pair of samples (16 steps, temperature 1.0) and a judge +picks one; ties are skipped. 4 pairs per Adam update, lr 3e-4. Evaluated on 8 fresh 64-step samples at 0.7. +Before: parallels 12.3 per 100 steps, held 48 %, chords 45 (these 8 seeds; the 5-seed table above says 7.5). + +| judge | β | pairs | parallels | held | chords | val loss | reading | +| --- | --- | --- | --- | --- | --- | --- | --- | +| fewest parallels | 0.2 | 40 | 5.9 | **73 %** | **25** | 1.199 | reward hacking: it learned to move less | +| fewest parallels | 1.0 | 40 | 10.5 | 55 % | 36 | 1.199 | a tighter leash: hacks less, learns less | +| fewest parallels **per step on which voices move** | 0.2 | 40 | 12.7 | 47 % | 44 | 1.205 | no effect at 40 | +| same | 0.5 | 80 | **7.0** | 52 % | 41 | 1.209 | learned the rule without gaming it | +| more held notes ("calm") | 0.5 | 20 | 6.1 | 68 % | 27 | 1.204 | 20 clicks audibly slower | +| more held notes | 0.5 | 40 | 1.6 | 89 % | 11 | 1.225 | too far: a drone | + +- 40 pairs take about 12 s in node; each pair draws two samples, so a human-paced version is bound by listening, + not computing. **Twenty choices is enough to move the music audibly**, which is a count a reader will make. +- The first judge is the article's best moment: asked for fewer mistakes, the model found that the way to make none + is to play nothing. The fix is the one real RLHF uses: a judge that cannot be gamed that way, and a leash (β). +- Single runs, 8 samples each: the direction of every row is clear, the second digit is not. Seeds before prose. + +### Listening pack + +`music-work/listen/` (MP3, 35–40 s each, 60 bpm eighths = 0.5 s, soft additive organ + feedback-delay reverb): +Bach's chor127 (validation), the rules, the 5-gram, run B at 0 / 100 / 250 / 500 / 1,000 / 4,000 steps, and the four +DPO results above, and run A at 4,000 steps. **Nobody has listened yet; the metrics are proxies.** Paul's ears decide. + +### Run A: d 64, 2 layers, 32-step window (128 tokens), 114,944 parameters, 4,000 steps, 1,185 s + +Same evaluation, temperature 0.7: step 1,000 val 1.09, parallels 7.5, crossings 1.3 %, chords 29; step 4,000 val +**0.93**, in key 98.6 %, parallels **5.0**, crossings 0.3 %, held 48 %, chords 45, longest copy 6–10. +Twice the context and 1.4× the width buys 0.05 nats and a little on parallels; it does not close the gap to Bach's +0.16. At about 300 ms per step (sharing the machine) it gets 600 steps in three minutes against B's 1,250, and B at +1,250 is ahead of A at 600. **For the page, B's size is the right one.** + +### Open + +- Timing in a real browser (a worker): node's V8 should be close; measure it. +- Seeds for the DPO table; the judge a reader would really be (a human) is slower and noisier than these. +- Whether the samples are pleasant at all. + +## Timbre (2026-09-22, after Paul's first listen: "the key is fine but it is too sharp") + +The first organ was 5 harmonics at 1/k², a 60 ms attack and four undamped feedback delays (a metallic ring). +`synth.ts` has three softer voices, all through a Freeverb-style reverb (8 damped combs + 4 all-passes, stereo) and a +12 dB/octave low-pass at 3.2 kHz on the mix: + +- **pad**: fundamental + soft octave, each doubled 4 cents apart (slow beating), 350 ms attack, 1.4 s release. +- **epiano**: two-operator FM whose index decays (bright for a moment, then round), 2.2 s decay. +- **flute**: sine + a little 2nd harmonic, a breath of noise on the attack, 4.8 Hz vibrato fading in. + +Band levels relative to the whole spectrum (`hiband.ts`, 4096-point Hann FFT frames; Bach's chor127 / the AI sample): + +| voice | 1–4 kHz | above 2 kHz | +| --- | --- | --- | +| old organ | −19.0 / −19.7 dB | −33.4 / −32.5 dB | +| pad | −25.1 / −25.1 dB | −82.9 / −54.7 dB | +| epiano | −25.9 / −26.8 dB | −59.2 / −51.8 dB | +| flute | −34.7 / −34.9 dB | −49.2 / −50.1 dB | + +Two measures I tried first and threw away: the spectral centroid (475 → ~340 Hz) is dominated by the fundamentals +and says little about harshness; "signal minus a low-pass" is not a high-pass (the low-pass's phase lag leaves the +low end in), and reported 20–30 % above 2 kHz for every voice. Listening files: `music-work/listen/timbres/`. + +## In the page (draft № 014, 2026-09-22) + +- Chromium (Playwright, M4 Pro), the worker in `content/posts/music-ai/components/music.worker.ts`: 1,200 steps in + 83 s, **69 ms per step**, validation loss 1.17 at the end (24 fixed windows). Half node's 145 ms, which was measured + while run A shared the machine. The figure now trains 2,400 steps (about 2.8 minutes). +- The article's learning-order table is run B's (cosine over 4,000 steps); the page's schedule decays over 2,400. + Rerun the table with the page's exact recipe before publishing. + +## Fig 03 and the player (2026-09-23) + +- The blind test ships as fig 03: four bars each of Bach (an excerpt of a validation chorale, never trained on), the + step-1,000 model at temperature 0.7, and the rules composer, shuffled. The piano rolls stay hidden until the reader + answers, because a chorale and a block-chord machine are obvious on sight. One live round measured, for a sanity + check: Bach parallels 0.0 / 72 chords per 100 steps, rules 18.8 / 31, the AI 9.4 / 66 — the same ordering as the + offline table. +- Three bugs Paul found while playing with the draft, all in the shared player: + 1. Changing the timbre only restarted the sound in fig 01, because each figure did it for itself. The player now + owns "what is playing" and every figure asks it to restyle, keeping the position and with no gap in the sound + (the old buffer plays until the new one is ready). + 2. The music kept playing after navigating away: nothing stopped the page-level player when the figures unmounted. + The last figure to leave now stops it, terminates the synth worker and closes the AudioContext (verified: the + context goes from `running` to `closed`). + 3. Play stayed "Stop" for three or four silent seconds at the end, because the buffer carries a three-second + reverb tail. Playback now counts as finished when the music ends plus 0.8 s: a 24-second piece flips back at 25 s. + +## UI review of the draft (2026-09-23) + +Checked at 1440 and 390, both themes, with axe (no violations before or after) and the network log. Thirteen things +changed; the ones worth remembering: + +- **A shared worker needs to say who asked.** Figures 02 and 03 now use one worker (judge.bin 223 KB and the + chorales are fetched and parsed once, not twice), and the first version broadcast every reply to both: loading the + judge reset the blind test to its loading screen. Every message carries the id of the figure that asked. +- Auto-play used to take the stage: pick an earlier snapshot to listen to and the next one stole it. Choosing a + snapshot by hand now pins it, and later ones are marked "new" instead. +- Figure 02 could only be read, not heard — the whole article is about listening. It now has "hear what it writes + now" and "start over", and says that about twenty picks is where the difference becomes audible. +- The numbers had no explanation anywhere ("6.3 per 100 steps" of what?). One line under them now says a step is an + eighth note, eight make a bar, and what the validation error means. +- The piano roll's alternative text in figures 02 and 03 claimed "six bars written at step 0", copied from figure 01. +- Training's "Stop" sat beside playback's "Stop": it is "Stop training" now. The progress bar has an estimate again. +- The auto-play checkbox was 13 px with a 16 px label; the label is now 24 px tall with the site's `tap` hit area. + +## DPO at the page's own recipe (2026-09-23) + +The table above updates once per four choices at lr 3e-4. The page updates on every choice at lr 1e-4, so the +article's numbers were re-measured with the page's recipe (8 samples of 64 steps at 0.7; before: parallels 12.3, +held 48 %, chords 45, val 1.195): + +| judge | picks | parallels | held | chords | val | +| --- | --- | --- | --- | --- | --- | +| more held notes ("calm") | 20 | 6.1 | 64 % | 28 | 1.194 | +| more held notes | 40 | 3.9 | 78 % | 21 | 1.196 | +| fewest parallels (gameable) | 40 | 10.9 | 58 % | 35 | 1.200 | +| fewest parallels (gameable) | 80 | 8.0 | 63 % | 29 | 1.199 | +| parallels per moving step | 80 | 7.0 | 63 % | 29 | 1.199 | + +**The clean reward-hacking contrast does not reproduce at this gentler push.** Both judges drift toward holding +(63 % either way) and the hack-proof one only buys 8.0 → 7.0. The sharp version (gameable 5.9 with 73 % held and 25 +chords, versus hack-proof 7.0 with 52 % held and 41 chords) needs the harder push. The article now says exactly +that: the harder you optimise, the more gaming pays, which is the real lesson; the figure stays gentle so that +twenty clicks do not wreck the model. Paul chose to keep the page's learning rate as it is. + +## The page's own recipe, measured twice (2026-09-23) — the table the article prints + +`train.ts page-2400 2400 48 2 16 8 3e-3`, twice (seeds 7 and 11), 195 s each in node; `eval.ts`, five pieces of 64 +steps at temperature 0.7 per checkpoint. The article's table is the mean of the two runs. + +| step | val | in key | crossings | held | parallels | chords | longest copy | +| --- | --- | --- | --- | --- | --- | --- | --- | +| 0 | 4.51 | 82 % | 87 % | 0.5 % | 3.9 | 97 | 1 | +| 100 | 2.01 | 99 % | 36 % | 78 % | 1.1 | 30 | 2–5 | +| 250 | 1.60 | 99.7 % | 1.9 % | 50 % | 9.8 | 45 | 2–4 | +| 500 | 1.39 | 99.6 % | 1.1 % | 55 % | 10.0 | 34 | 2–6 | +| 1000 | 1.21 | 98.7 % | 1.8 % | 54 % | 12.0 | 38 | 3–6 | +| 2000 | 1.07 | 99.2 % | 1.3 % | 53 % | 8.9 | 38 | 6–10 | +| 2400 | 1.05 | 99.5 % | 0 % | 65 % | 7.2 | 28 | 5–10, once 32 | + +- Held notes rise again at the end of the cosine decay (70 % and 59 % in the two runs), so the model the reader ends + up with is slower than Bach's 45 %. The article says so rather than quoting the mid-training number. +- **One sample in ten copied 32 steps — four whole bars — from a training chorale** (run 7, step 2,400). The other + nine were 5 to 10. It is in the article: the model can hold a passage verbatim, and the copy detector is the way to + catch it. +- Parallel fifths never settle: 7 to 12 per hundred steps the whole way, against Bach's 0.16. +- Run B (the 4,000-step schedule) is still the reference for the DPO work, because judge.bin is its step-1,000 + checkpoint. + +## Where everything lives + +- In the repo: the article (`content/posts/music-ai/`), the data files (`public/posts/music-ai/*.bin`, CC BY-NC-SA + 4.0), the packing scripts (`scripts/music/convert.py`, `scripts/music/pack.ts`), these notes and copies of the + research scripts beside them. +- Outside the repo, in `Desktop/Paul/music-work/`: the corpus clone (`bach-370-chorales/`), `chorales.json`, every + run under `runs/`, the rendered WAV and MP3 packs (`listen/`, `timbres/`). `pack.ts` in the repo reproduces both + `.bin` files from `chorales.json` and a checkpoint, byte for byte. diff --git a/docs/research/music-ai/baseline.ts.txt b/docs/research/music-ai/baseline.ts.txt new file mode 100644 index 0000000..e0061e2 --- /dev/null +++ b/docs/research/music-ai/baseline.ts.txt @@ -0,0 +1,74 @@ +// Reference numbers: Bach's own validation chorales, n-gram models, and a rule-based "five lines of maths" composer. +import { HOLD, REST, VOCAB, VOICES, decode, longestCopy, renderWav, report, trainTokens, valSet, valTokens } from "./music"; +import { mulberry32 } from "../Blog/lib/ml/neuroevolution"; + +const mean = (rs: ReturnType[]) => Object.fromEntries(Object.keys(rs[0]).map((k) => [k, +(rs.reduce((s, r) => s + (r as any)[k], 0) / rs.length).toFixed(3)])); +console.log("train tokens", trainTokens.reduce((s, t) => s + t.length, 0), "val tokens", valTokens.reduce((s, t) => s + t.length, 0), "vocab", VOCAB); +console.log("bach (validation)", mean(valSet.map((c) => report(c.pitches, c.onset)))); + +// n-gram with add-k smoothing, context = previous n-1 tokens. Validation cross-entropy in nats per token. +function ngram(n: number, k = 0.05) { + const counts = new Map(); + for (const seq of trainTokens) + for (let t = 0; t < seq.length; t++) { + const ctx = seq.slice(Math.max(0, t - n + 1), t).join(",") + "|" + (t % VOICES); + if (!counts.has(ctx)) counts.set(ctx, new Float64Array(VOCAB)); + counts.get(ctx)![seq[t]]++; + } + const prob = (ctx: string, id: number) => { + const c = counts.get(ctx); + if (!c) return 1 / VOCAB; + const total = c.reduce((a, b) => a + b, 0); + return (c[id] + k) / (total + k * VOCAB); + }; + let nll = 0, count = 0; + for (const seq of valTokens) + for (let t = 0; t < seq.length; t++) { nll -= Math.log(prob(seq.slice(Math.max(0, t - n + 1), t).join(",") + "|" + (t % VOICES), seq[t])); count++; } + return { nll: nll / count, counts, prob }; +} +for (const n of [1, 2, 3, 4, 5, 6, 8]) console.log(`${n}-gram val nats/token`, ngram(n).nll.toFixed(3)); + +// Rule composer: pentatonic C (C D E G A) soprano as a 1/f (Voss) walk, a fixed I–vi–IV–V progression under it. +function rules(steps: number, seed: number) { + const rng = mulberry32(seed); + const penta = [60, 62, 64, 67, 69, 72, 74, 76, 79, 81]; + const dice = [0, 0, 0, 0].map(() => rng()); + const chords = [[48, 55, 64], [45, 57, 64], [41, 53, 60], [43, 55, 62]]; // C, Am, F, G (bass, tenor, alto) + const pitches: number[][] = [], onset: number[][] = []; + let last = -1; + for (let t = 0; t < steps; t++) { + if (t % 2 === 0) for (let b = 0; b < 4; b++) if (((t / 2) & ((1 << b) - 1)) === 0) dice[b] = rng(); + const idx = Math.floor((dice.reduce((a, b) => a + b, 0) / 4) * penta.length); + const s = penta[Math.min(penta.length - 1, idx)], ch = chords[Math.floor(t / 8) % 4]; + const newS = t % 2 === 0 && s !== last; + pitches.push([newS || t % 2 === 1 ? (t % 2 === 0 ? s : last) : last, ch[2], ch[1], ch[0]]); + onset.push([newS ? 1 : 0, t % 8 === 0 ? 1 : 0, t % 8 === 0 ? 1 : 0, t % 8 === 0 ? 1 : 0]); + if (newS) last = s; + } + return { pitches, onset }; +} +const rs = [1, 2, 3, 4, 5].map((s) => rules(96, s)); +console.log("rules", mean(rs.map((r) => report(r.pitches, r.onset))), "copy", Math.max(...rs.map((r) => longestCopy(r.pitches)))); +renderWav("out/rules.wav", rs[0].pitches, rs[0].onset); +renderWav("out/bach-val.wav", valSet[0].pitches, valSet[0].onset); +console.log("bach val chorale for listening:", valSet[0].id); + +// Let the 5-gram compose, from the same C major chord the Transformer starts from. +{ + const { prob } = ngram(5); + for (const temp of [0.7, 1.0]) { + const out = [1, 2, 3].map((seed) => { + const r = mulberry32(seed), ids = [72 - 31, 67 - 31, 64 - 31, 48 - 31]; + while (ids.length < 64 * VOICES) { + const ctx = ids.slice(-4).join(",") + "|" + (ids.length % VOICES); + const p = Array.from({ length: VOCAB }, (_, k) => prob(ctx, k) ** (1 / temp)); + let u = r() * p.reduce((a, b) => a + b, 0), k = 0; + while (u > p[k] && k < VOCAB - 1) u -= p[k++]; + ids.push(k); + } + return decode(ids); + }); + console.log(`5-gram T${temp}`, mean(out.map((d) => report(d.pitches, d.onset))), "copy", out.map((d) => longestCopy(d.pitches))); + renderWav(`out/5gram-T${temp}.wav`, out[0].pitches, out[0].onset); + } +} diff --git a/docs/research/music-ai/convert.py.txt b/docs/research/music-ai/convert.py.txt new file mode 100644 index 0000000..b9d6ac6 --- /dev/null +++ b/docs/research/music-ai/convert.py.txt @@ -0,0 +1,52 @@ +# Bach chorales (Craig Sapp's edition, CC BY-NC-SA 4.0) -> an eighth-note grid, one JSON file. +# uv run --with music21 python convert.py +# Each chorale is transposed to C major or A minor. A step holds, for S A T B, the MIDI pitch sounding (or -1), +# whether that note starts on this step, and whether a fermata (phrase end) is on it. +import glob, json, math, os, sys +from music21 import converter, interval, pitch, note, expressions + +STEP = 0.5 # quarter lengths: an eighth note +out, skipped = [], [] +for path in sorted(glob.glob("bach-370-chorales/kern/*.krn")): + name = os.path.basename(path)[:-4] + try: + score = converter.parse(path) + parts = list(score.parts) + if len(parts) != 4: + skipped.append((name, f"{len(parts)} parts")); continue + key = score.analyze("key") + tonic = "C" if key.mode == "major" else "A" + shift = interval.Interval(key.tonic, pitch.Pitch(tonic)) + # Keep transpositions within a tritone so voices stay in their ranges. + if shift.semitones > 6: shift = interval.Interval(shift.semitones - 12) + if shift.semitones < -6: shift = interval.Interval(shift.semitones + 12) + score = score.transpose(shift) + parts = list(score.parts) + # kern lists bass first; order voices top-down by mean pitch to be sure. + def mean(p): + ps = [n.pitch.midi for n in p.recurse().notes if n.isNote] + return sum(ps) / max(1, len(ps)) + parts.sort(key=mean, reverse=True) + length = max(p.highestTime for p in parts) + n = int(math.ceil(length / STEP)) + pitches = [[-1] * 4 for _ in range(n)] + onset = [[0] * 4 for _ in range(n)] + fermata = [0] * n + for v, p in enumerate(parts): + for el in p.flatten().notesAndRests: + if not el.isNote: continue + a = int(round(el.offset / STEP)); b = int(round((el.offset + el.quarterLength) / STEP)) + tied_in = el.tie is not None and el.tie.type in ("continue", "stop") + for t in range(a, min(b, n)): + pitches[t][v] = el.pitch.midi + onset[t][v] = 1 if (t == a and not tied_in) else 0 + if any(isinstance(e, expressions.Fermata) for e in el.expressions) and b - 1 < n: + fermata[max(a, b - 1)] = 1 + ts = score.recurse().getElementsByClass("TimeSignature") + out.append({"id": name, "mode": key.mode, "shift": shift.semitones, "meter": ts[0].ratioString if ts else "4/4", + "pitches": pitches, "onset": onset, "fermata": fermata}) + except Exception as e: # report and go on + skipped.append((name, repr(e)[:80])) +json.dump(out, open("chorales.json", "w")) +print(len(out), "chorales,", len(skipped), "skipped") +for s in skipped[:20]: print(" skipped", *s) diff --git a/docs/research/music-ai/dpo.ts.txt b/docs/research/music-ai/dpo.ts.txt new file mode 100644 index 0000000..8bb667b --- /dev/null +++ b/docs/research/music-ai/dpo.ts.txt @@ -0,0 +1,121 @@ +// Preference tuning (DPO) on a trained checkpoint, with an automatic judge standing in for the reader. +// npx tsx dpo.ts [pairs] [pairsPerUpdate] [beta] [lr] +// The reader's click is simulated: of two samples, the judge prefers the one with fewer parallel fifths/octaves +// ("parallels") or with more held notes ("calm"). Ties are skipped (a reader would skip them too). +import fs from "node:fs"; +import { Mat, Tape } from "../Blog/lib/ml/autograd"; +import { Adam, Transformer } from "../Blog/lib/ml/transformer"; +import { mulberry32 } from "../Blog/lib/ml/neuroevolution"; +import { LO, VOCAB, VOICES, decode, longestCopy, renderWav, report, valTokens } from "./music"; + +const [file, d, ctxSteps, judge = "parallels", pairsArg = "40", perArg = "4", betaArg = "0.2", lrArg = "3e-4"] = process.argv.slice(2); +const CTX = +ctxSteps * VOICES, PAIRS = +pairsArg, PER = +perArg, BETA = +betaArg, LR = +lrArg; +const config = { vocab: VOCAB, ctx: CTX, d: +d, heads: 4, layers: 2 }; +const policy = new Transformer(config), ref = new Transformer(config); +const w = JSON.parse(fs.readFileSync(file, "utf8")); +for (const m of [policy, ref]) for (const [k, p] of Object.entries(m.params)) p.data.set(w[k]); +const adam = new Adam(policy.params); +const PROMPT = [72 - LO, 67 - LO, 64 - LO, 48 - LO]; +const LEN = CTX; // a whole sample fits in one window, so its probability is one forward pass + +function sample(model: Transformer, tokens: number, temperature: number, r: () => number): number[] { + const ids = [...PROMPT]; + while (ids.length < tokens) { + const ctx = ids.slice(Math.max(0, Math.ceil((ids.length - CTX) / VOICES) * VOICES)); + const { logits } = model.forward(new Tape(), ctx); + const row = logits.data.subarray((ctx.length - 1) * VOCAB, ctx.length * VOCAB); + let max = -Infinity; for (const x of row) max = Math.max(max, x); + const p = Array.from(row, (x) => Math.exp((x - max) / temperature)); + let u = r() * p.reduce((a, b) => a + b, 0), k = 0; + while (u > p[k] && k < p.length - 1) u -= p[k++]; + ids.push(k); + } + return ids; +} + +/** Sum of log-probabilities of the tokens after the prompt. */ +function logProb(model: Transformer, ids: number[], tape: Tape): { value: number; logits: Mat; targets: number[] } { + const { logits } = model.forward(tape, ids.slice(0, -1)); + const targets = ids.slice(1).map((t, i) => (i + 1 < PROMPT.length ? -1 : t)); + let lp = 0; + for (let r = 0; r < targets.length; r++) { + if (targets[r] < 0) continue; + const row = logits.data.subarray(r * VOCAB, (r + 1) * VOCAB); + let max = -Infinity; for (const x of row) max = Math.max(max, x); + let s = 0; for (const x of row) s += Math.exp(x - max); + lp += row[targets[r]] - max - Math.log(s); + } + return { value: lp, logits, targets }; +} + +/** How often two voices move in parallel fifths/octaves, per step on which at least two voices move: holding still cannot game it. */ +function perMove(pitches: number[][]): number { + let moves = 0, par = 0; + for (let t = 1; t < pitches.length; t++) { + const p = pitches[t], q = pitches[t - 1]; + if (p.filter((x, v) => x !== q[v]).length >= 2) moves++; + for (let a = 0; a < 4; a++) for (let c = a + 1; c < 4; c++) { + if (p[a] < 0 || p[c] < 0 || q[a] < 0 || q[c] < 0) continue; + const now = (p[a] - p[c]) % 12, was = (q[a] - q[c]) % 12; + if (p[a] !== q[a] && p[c] !== q[c] && Math.sign(p[a] - q[a]) === Math.sign(p[c] - q[c]) && now === was && (now === 7 || now === 0)) par++; + } + } + return moves ? par / moves : 0; +} +const score = (ids: number[]) => { + const g = decode(ids), r = report(g.pitches, g.onset); + if (judge === "calm") return r.holdShare; + if (judge === "permove") return -perMove(g.pitches); + return -r.parallels; +}; + +function evaluate(label: string) { + const reps = [1, 2, 3, 4, 5, 6, 7, 8].map((seed) => { const g = decode(sample(policy, 64 * VOICES, 0.7, mulberry32(1000 + seed))); return { r: report(g.pitches, g.onset), copy: longestCopy(g.pitches), g }; }); + const mean = (k: keyof (typeof reps)[0]["r"]) => +(reps.reduce((s, x) => s + x.r[k], 0) / reps.length).toFixed(3); + const valRng = mulberry32(99); + let val = 0; + for (let i = 0; i < 64; i++) { + const seq = valTokens[Math.floor(valRng() * valTokens.length)]; + const steps = seq.length / VOICES, len = Math.min(CTX + VOICES, seq.length); + const start = Math.floor(valRng() * Math.max(1, steps - len / VOICES + 1)) * VOICES; + const win = seq.slice(start, start + len); + val += new Tape().crossEntropy(policy.forward(new Tape(), win.slice(0, -1).slice(0, CTX)).logits, win.slice(1, CTX + 1)); + } + console.log(label, JSON.stringify({ val: +(val / 64).toFixed(3), inKey: mean("inKey"), parallels: mean("parallels"), crossings: mean("crossings"), hold: mean("holdShare"), chords: mean("distinctChords"), copy: reps.map((x) => x.copy) })); + return reps[0].g; +} + +const tag = `${judge}-p${PAIRS}-b${BETA}-lr${LR}`; +const before = evaluate("before"); +renderWav(`out/dpo-${tag}-before.wav`, before.pitches, before.onset); +const r = mulberry32(5); +let used = 0, skipped = 0, sampled = 0; +const start = Date.now(); +while (used < PAIRS) { + policy.zeroGrad(); + const tape = new Tape(); + let n = 0; + while (n < PER && used < PAIRS) { + const a = sample(policy, LEN + 1, 1.0, r), b = sample(policy, LEN + 1, 1.0, r); + sampled += 2; + const sa = score(a), sb = score(b); + if (sa === sb) { skipped++; continue; } + const [win, lose] = sa > sb ? [a, b] : [b, a]; + const pw = logProb(policy, win, tape), pl = logProb(policy, lose, tape); + const rw = logProb(ref, win, new Tape()).value, rl = logProb(ref, lose, new Tape()).value; + const z = BETA * (pw.value - rw - (pl.value - rl)); + const g = BETA * (1 - 1 / (1 + Math.exp(-z))) / PER; // −dL/dz · β, averaged over the update's pairs + const count = (t: number[]) => t.filter((x) => x >= 0).length; + // crossEntropy's gradient is weight × d(mean NLL); log p = −count × mean NLL. + tape.crossEntropy(pw.logits, pw.targets, g * count(pw.targets)); + tape.crossEntropy(pl.logits, pl.targets, -g * count(pl.targets)); + n++; used++; + } + tape.backward(); + adam.step(LR); + if (used % 20 === 0 || used === PAIRS) console.log(`pairs ${used} (skipped ties ${skipped}) ${((Date.now() - start) / 1000).toFixed(0)} s`); +} +const after = evaluate("after"); +renderWav(`out/dpo-${tag}-after.wav`, after.pitches, after.onset); +fs.writeFileSync(`out/dpo-${tag}.json`, JSON.stringify(Object.fromEntries(Object.entries(policy.params).map(([k, m]) => [k, Array.from(m.data, (x) => +x.toFixed(5))])))); +console.log("samples drawn", sampled); diff --git a/docs/research/music-ai/eval.ts.txt b/docs/research/music-ai/eval.ts.txt new file mode 100644 index 0000000..25d7ac5 --- /dev/null +++ b/docs/research/music-ai/eval.ts.txt @@ -0,0 +1,57 @@ +// Re-evaluate saved checkpoints: validation loss, samples at two temperatures (5 seeds, 64 steps), metrics, WAVs. +// npx tsx eval.ts [layers] +import fs from "node:fs"; +import { Tape } from "../Blog/lib/ml/autograd"; +import { Transformer } from "../Blog/lib/ml/transformer"; +import { mulberry32 } from "../Blog/lib/ml/neuroevolution"; +import { LO, VOCAB, VOICES, decode, longestCopy, renderWav, report, valTokens } from "./music"; + +const [dir, d, ctxSteps, layers = "2"] = process.argv.slice(2); +const CTX = +ctxSteps * VOICES; +const model = new Transformer({ vocab: VOCAB, ctx: CTX, d: +d, heads: 4, layers: +layers }); + +export function sample(steps: number, temperature: number, seed: number, prompt = [72 - LO, 67 - LO, 64 - LO, 48 - LO]): number[] { + const r = mulberry32(seed), ids = [...prompt]; + while (ids.length < steps * VOICES) { + const ctx = ids.slice(Math.max(0, Math.ceil((ids.length - CTX) / VOICES) * VOICES)); + const { logits } = model.forward(new Tape(), ctx); + const row = logits.data.subarray((ctx.length - 1) * VOCAB, ctx.length * VOCAB); + let max = -Infinity; for (const x of row) max = Math.max(max, x); + const p = Array.from(row, (x) => Math.exp((x - max) / temperature)); + let u = r() * p.reduce((a, b) => a + b, 0), k = 0; + while (u > p[k] && k < p.length - 1) u -= p[k++]; + ids.push(k); + } + return ids; +} + +// The same 64 validation windows as train.ts. +function window(pool: number[][], r: () => number): number[] { + const seq = pool[Math.floor(r() * pool.length)]; + const steps = seq.length / VOICES, len = Math.min(CTX + VOICES, seq.length); + const start = Math.floor(r() * Math.max(1, steps - len / VOICES + 1)) * VOICES; + return seq.slice(start, start + len); +} +const valRng = mulberry32(99), valWindows = Array.from({ length: 64 }, () => window(valTokens, valRng)); + +const files = fs.readdirSync(dir).filter((f) => /^model-\d+\.json$/.test(f)).sort((a, b) => parseInt(a.slice(6)) - parseInt(b.slice(6))); +const rows: string[] = []; +for (const f of files) { + const step = parseInt(f.slice(6)); + const w = JSON.parse(fs.readFileSync(`${dir}/${f}`, "utf8")); + for (const [k, m] of Object.entries(model.params)) m.data.set(w[k]); + let val = 0; + for (const win of valWindows) val += new Tape().crossEntropy(model.forward(new Tape(), win.slice(0, -1).slice(0, CTX)).logits, win.slice(1, CTX + 1)); + val /= valWindows.length; + const line: Record = { step, val: +val.toFixed(3) }; + for (const temp of [0.7, 1.0]) { + const rs = [1, 2, 3, 4, 5].map((seed) => decode(sample(64, temp, seed))); + const reps = rs.map((r) => report(r.pitches, r.onset)); + const mean = (k: keyof (typeof reps)[0]) => +(reps.reduce((s, r) => s + r[k], 0) / reps.length).toFixed(3); + line[`T${temp}`] = { inKey: mean("inKey"), parallels: mean("parallels"), crossings: mean("crossings"), rough: mean("rough"), hold: mean("holdShare"), chords: mean("distinctChords"), copy: rs.map((r) => longestCopy(r.pitches)) }; + renderWav(`${dir}/eval-step${step}-T${temp}.wav`, rs[0].pitches, rs[0].onset); + } + rows.push(JSON.stringify(line)); + console.log(rows.at(-1)); +} +fs.writeFileSync(`${dir}/eval.txt`, rows.join("\n") + "\n"); diff --git a/docs/research/music-ai/hiband.ts.txt b/docs/research/music-ai/hiband.ts.txt new file mode 100644 index 0000000..ded6c74 --- /dev/null +++ b/docs/research/music-ai/hiband.ts.txt @@ -0,0 +1,27 @@ +// Share of spectral energy above 2 kHz (and above 4 kHz), from 4096-point Hann-windowed FFT frames. WAV 16-bit in. +import fs from "node:fs"; +function fft(re: Float64Array, im: Float64Array) { + const n = re.length; + for (let i = 1, j = 0; i < n; i++) { let bit = n >> 1; for (; j & bit; bit >>= 1) j ^= bit; j ^= bit; if (i < j) { [re[i], re[j]] = [re[j], re[i]]; [im[i], im[j]] = [im[j], im[i]]; } } + for (let len = 2; len <= n; len <<= 1) { + const ang = (-2 * Math.PI) / len; + for (let i = 0; i < n; i += len) for (let k = 0; k < len / 2; k++) { + const wr = Math.cos(ang * k), wi = Math.sin(ang * k), a = i + k, b = a + len / 2; + const xr = re[b] * wr - im[b] * wi, xi = re[b] * wi + im[b] * wr; + re[b] = re[a] - xr; im[b] = im[a] - xi; re[a] += xr; im[a] += xi; + } + } +} +const bands = (f: string) => { + const b = fs.readFileSync(f), ch = b.readUInt16LE(22), n = (b.length - 44) / 2 / ch, N = 4096; + let e2 = 0, e4 = 0, all = 0, mid = 0; + for (let s = 0; s + N <= n; s += N) { + const re = new Float64Array(N), im = new Float64Array(N); + for (let i = 0; i < N; i++) { let v = 0; for (let c = 0; c < ch; c++) v += b.readInt16LE(44 + ((s + i) * ch + c) * 2); re[i] = (v / ch) * (0.5 - 0.5 * Math.cos((2 * Math.PI * i) / N)); } + fft(re, im); + for (let k = 1; k < N / 2; k++) { const e = re[k] ** 2 + im[k] ** 2, hz = (k * 44100) / N; all += e; if (hz > 2000) e2 += e; if (hz > 4000) e4 += e; if (hz > 1000 && hz < 4000) mid += e; } + } + const db = (x: number) => (10 * Math.log10(x / all)).toFixed(1).padStart(6); + return `1–4 kHz ${db(mid)} dB >2 kHz ${db(e2)} dB >4 kHz ${db(e4)} dB`; +}; +for (const f of process.argv.slice(2)) console.log(f.padEnd(44), bands(f)); diff --git a/docs/research/music-ai/music.ts.txt b/docs/research/music-ai/music.ts.txt new file mode 100644 index 0000000..e209529 --- /dev/null +++ b/docs/research/music-ai/music.ts.txt @@ -0,0 +1,162 @@ +// Shared pieces of the music-AI spike: tokens, the split, sampling, the metrics, a WAV writer. +import fs from "node:fs"; +import { mulberry32 } from "../Blog/lib/ml/neuroevolution"; + +export interface Chorale { id: string; mode: string; meter: string; pitches: number[][]; onset: number[][]; fermata: number[] } +export const LO = 31, HI = 84; +export const HOLD = HI - LO + 1, REST = HOLD + 1, VOCAB = REST + 1; +export const VOICES = 4; + +export const chorales: Chorale[] = JSON.parse(fs.readFileSync(new URL("./chorales.json", import.meta.url), "utf8")); + +/** One token per voice per eighth: S A T B. A new note is its pitch, a held one HOLD, silence REST. */ +export function tokens(c: Chorale): number[] { + const out: number[] = []; + c.pitches.forEach((step, t) => step.forEach((p, v) => out.push(p < 0 ? REST : c.onset[t][v] || t === 0 ? p - LO : HOLD))); + return out; +} + +/** Split by chorale, seeded: 90 % train, 10 % validation. */ +const rng = mulberry32(2026); +const order = chorales.map((_, i) => i).sort(() => rng() - 0.5); +const nVal = Math.round(chorales.length * 0.1); +export const valSet = order.slice(0, nVal).map((i) => chorales[i]); +export const trainSet = order.slice(nVal).map((i) => chorales[i]); +export const trainTokens = trainSet.map(tokens); +export const valTokens = valSet.map(tokens); + +/** Tokens back to sounding pitches per step and voice (-1 silent), and onsets. */ +export function decode(ids: number[]): { pitches: number[][]; onset: number[][] } { + const pitches: number[][] = [], onset: number[][] = []; + const last = [-1, -1, -1, -1]; + for (let t = 0; t * VOICES < ids.length; t++) { + const p: number[] = [], o: number[] = []; + for (let v = 0; v < VOICES; v++) { + const id = ids[t * VOICES + v]; + if (id === undefined) { p.push(-1); o.push(0); continue; } + if (id === HOLD) { p.push(last[v]); o.push(0); } + else if (id === REST) { last[v] = -1; p.push(-1); o.push(0); } + else { last[v] = id + LO; p.push(id + LO); o.push(1); } + } + pitches.push(p); onset.push(o); + } + return { pitches, onset }; +} + +// --------------------------------------------------------------------------------------------------------------- +// Metrics. None of them says "beautiful"; they say whether the texture obeys what four-part writing obeys. + +/** C major's pitch classes, plus F# and G#: A minor's raised sixth and seventh. Every chorale is in C major or A minor. */ +const KEY = new Set([0, 2, 4, 5, 7, 9, 11, 6, 8]); + +/** Plomp–Levelt roughness of a chord of sine-rich tones (6 harmonics, 1/k amplitudes), after Sethares. */ +export function roughness(midi: number[]): number { + const partials: [number, number][] = []; + for (const m of midi) if (m >= 0) for (let k = 1; k <= 6; k++) partials.push([440 * 2 ** ((m - 69) / 12) * k, 1 / k]); + let r = 0; + for (let i = 0; i < partials.length; i++) + for (let j = i + 1; j < partials.length; j++) { + const [f1, a1] = partials[i], [f2, a2] = partials[j]; + const s = 0.24 / (0.021 * Math.min(f1, f2) + 19), d = Math.abs(f2 - f1); + r += Math.min(a1, a2) * (Math.exp(-3.5 * s * d) - Math.exp(-5.75 * s * d)); + } + return r; +} + +export interface Report { + inKey: number; // share of note onsets whose pitch class belongs to C major or A minor (with raised 6, 7) + parallels: number; // parallel fifths/octaves per 100 steps (between any two voices, on moving steps) + crossings: number; // share of steps where a lower voice sounds above a higher one + rough: number; // mean chord roughness + holdShare: number; // share of voice-steps that are held (rhythm) + distinctChords: number; // distinct pitch-class sets per 100 steps (variety) +} + +export function report(pitches: number[][], onset: number[][]): Report { + let notes = 0, inKey = 0, parallels = 0, crossings = 0, rough = 0, held = 0, cells = 0; + const chords = new Set(); + const key = KEY; + for (let t = 0; t < pitches.length; t++) { + const p = pitches[t]; + for (let v = 0; v < 4; v++) { + if (p[v] < 0) continue; + cells++; + if (onset[t][v]) { notes++; if (key.has(p[v] % 12)) inKey++; } else held++; + } + for (let v = 0; v < 3; v++) if (p[v] >= 0 && p[v + 1] >= 0 && p[v + 1] > p[v]) { crossings++; break; } + rough += roughness(p); + chords.add(p.filter((x) => x >= 0).map((x) => x % 12).sort((a, b) => a - b).join(",")); + if (t > 0) { + const q = pitches[t - 1]; + for (let a = 0; a < 4; a++) + for (let b = a + 1; b < 4; b++) { + if (p[a] < 0 || p[b] < 0 || q[a] < 0 || q[b] < 0) continue; + const now = (p[a] - p[b]) % 12, before = (q[a] - q[b]) % 12; + const moved = p[a] !== q[a] && p[b] !== q[b] && Math.sign(p[a] - q[a]) === Math.sign(p[b] - q[b]); + if (moved && now === before && (now === 7 || now === 0)) parallels++; + } + } + } + const n = pitches.length; + return { inKey: inKey / notes, parallels: (100 * parallels) / n, crossings: crossings / n, rough: rough / n, holdShare: held / cells, distinctChords: (100 * chords.size) / n }; +} + +/** Longest run of steps (all four voices equal) that also occurs somewhere in the training set. */ +export function longestCopy(pitches: number[][]): number { + const key = (p: number[]) => p.join(","); + const index = new Map(); + trainSet.forEach((c, ci) => c.pitches.forEach((p, t) => { const k = key(p); if (!index.has(k)) index.set(k, []); index.get(k)!.push([ci, t]); })); + let best = 0; + for (let t = 0; t < pitches.length; t++) { + for (const [ci, s] of index.get(key(pitches[t])) ?? []) { + const c = trainSet[ci].pitches; + let n = 0; + while (t + n < pitches.length && s + n < c.length && key(c[s + n]) === key(pitches[t + n])) n++; + if (n > best) best = n; + } + } + return best; +} + +// --------------------------------------------------------------------------------------------------------------- +// Sound: a soft additive organ with a slow attack, and a simple feedback-delay reverb. Mono, 44.1 kHz, 16-bit. + +export function renderWav(file: string, pitches: number[][], onset: number[][], { bpm = 60, sampleRate = 44100 } = {}) { + const stepSec = 60 / bpm / 2; // an eighth + const n = Math.ceil((pitches.length * stepSec + 3) * sampleRate); + const out = new Float32Array(n); + for (let v = 0; v < 4; v++) { + let t = 0; + while (t < pitches.length) { + const p = pitches[t][v]; + if (p < 0) { t++; continue; } + let len = 1; + while (t + len < pitches.length && pitches[t + len][v] === p && !onset[t + len][v]) len++; + const f = 440 * 2 ** ((p - 69) / 12), a0 = Math.round(t * stepSec * sampleRate), dur = len * stepSec; + const total = Math.round((dur + 0.6) * sampleRate); + for (let i = 0; i < total && a0 + i < n; i++) { + const s = i / sampleRate; + const env = Math.min(1, s / 0.06) * (s < dur ? 1 : Math.exp(-(s - dur) / 0.18)); + let x = 0; + for (let k = 1; k <= 5; k++) x += Math.sin(2 * Math.PI * f * k * s) / (k * k); + out[a0 + i] += 0.12 * env * x; + } + t += len; + } + } + // Reverb: four feedback delays, a little of the dry signal fed in. + const wet = new Float32Array(n); + for (const [ms, g] of [[29.7, 0.72], [37.1, 0.7], [41.1, 0.68], [43.7, 0.66]] as const) { + const d = Math.round((ms / 1000) * sampleRate), buf = new Float32Array(n); + for (let i = 0; i < n; i++) buf[i] = out[i] + (i >= d ? g * buf[i - d] : 0); + for (let i = 0; i < n; i++) wet[i] += buf[i] * 0.18; + } + let peak = 0; + for (let i = 0; i < n; i++) { out[i] = out[i] * 0.75 + wet[i] * 0.35; peak = Math.max(peak, Math.abs(out[i])); } + const buf = Buffer.alloc(44 + n * 2); + buf.write("RIFF", 0); buf.writeUInt32LE(36 + n * 2, 4); buf.write("WAVE", 8); buf.write("fmt ", 12); + buf.writeUInt32LE(16, 16); buf.writeUInt16LE(1, 20); buf.writeUInt16LE(1, 22); buf.writeUInt32LE(sampleRate, 24); + buf.writeUInt32LE(sampleRate * 2, 28); buf.writeUInt16LE(2, 32); buf.writeUInt16LE(16, 34); buf.write("data", 36); buf.writeUInt32LE(n * 2, 40); + for (let i = 0; i < n; i++) buf.writeInt16LE(Math.round((out[i] / (peak || 1)) * 0.85 * 32767), 44 + i * 2); + fs.writeFileSync(file, buf); +} diff --git a/docs/research/music-ai/synth.ts.txt b/docs/research/music-ai/synth.ts.txt new file mode 100644 index 0000000..ae8c6b1 --- /dev/null +++ b/docs/research/music-ai/synth.ts.txt @@ -0,0 +1,122 @@ +// Softer voices for the listening tests: three timbres, a damped stereo reverb (Freeverb's layout), a gentle +// low-pass on the mix, and the spectral centroid of the result as a number for "how bright". +import fs from "node:fs"; + +export type Timbre = "pad" | "epiano" | "flute"; +const SR = 44100; + +/** Deterministic noise for breath and detune. */ +function noise(seed: number) { let a = seed; return () => { a = (a * 1664525 + 1013904223) | 0; return a / 2147483648; }; } + +/** One note into L/R. Voice 0 is the soprano; lower voices sit a little louder and wider apart in the stereo field. */ +function note(L: Float32Array, R: Float32Array, timbre: Timbre, midi: number, start: number, dur: number, voice: number) { + const f = 440 * 2 ** ((midi - 69) / 12); + const level = [0.5, 0.55, 0.6, 0.75][voice]; + const pan = [0.35, 0.6, 0.4, 0.5][voice]; // 0 left … 1 right + const gl = Math.cos((pan * Math.PI) / 2), gr = Math.sin((pan * Math.PI) / 2); + const rnd = noise(midi * 131 + Math.round(start * 1000)); + const attack = timbre === "pad" ? 0.35 : timbre === "flute" ? 0.12 : 0.008; + const release = timbre === "pad" ? 1.4 : timbre === "flute" ? 0.35 : 1.2; + const total = Math.round((dur + release) * SR), a0 = Math.round(start * SR); + let breath = 0; + for (let i = 0; i < total && a0 + i < L.length; i++) { + const t = i / SR; + let env: number, x: number; + const on = t < dur ? 1 : Math.exp(-(t - dur) / (release / 4)); + if (timbre === "pad") { + // Fundamental and a soft octave, each doubled 4 cents apart: the slow beating is the warmth. + env = Math.min(1, t / attack) ** 2 * on; + const d = 2 ** (4 / 1200); + x = 0.5 * (Math.sin(2 * Math.PI * f * t) + Math.sin(2 * Math.PI * f * d * t)) + 0.12 * (Math.sin(4 * Math.PI * f * t) + Math.sin(4 * Math.PI * f / d * t)) + 0.03 * Math.sin(6 * Math.PI * f * t); + } else if (timbre === "flute") { + // A sine, a little second harmonic, a breath of filtered noise at the start, and a slow vibrato. + env = Math.min(1, t / attack) * on; + const vib = 1 + 0.003 * Math.sin(2 * Math.PI * 4.8 * t) * Math.min(1, t / 0.6); + breath = 0.97 * breath + 0.03 * rnd(); + x = Math.sin(2 * Math.PI * f * vib * t) + 0.08 * Math.sin(4 * Math.PI * f * vib * t) + 3 * breath * Math.exp(-t / 0.08); + } else { + // Electric piano by two-operator FM: the modulation index decays, so the tone softens as it sounds. + env = Math.min(1, t / attack) * Math.exp(-t / 2.2) * on; + const index = 1.1 * Math.exp(-t / 0.35); + x = Math.sin(2 * Math.PI * f * t + index * Math.sin(2 * Math.PI * f * t)); + } + const s = 0.16 * level * env * x; + L[a0 + i] += s * gl; R[a0 + i] += s * gr; + } +} + +/** Freeverb: eight damped feedback combs and four all-passes per side, the right side's delays a little longer. */ +function reverb(inL: Float32Array, inR: Float32Array, room = 0.84, damp = 0.45, wet = 0.32) { + const combs = [1116, 1188, 1277, 1356, 1422, 1491, 1557, 1617], alls = [556, 441, 341, 225]; + const side = (input: Float32Array, spread: number) => { + const out = new Float32Array(input.length); + for (const d0 of combs) { + const d = d0 + spread, buf = new Float32Array(d); let idx = 0, store = 0; + for (let i = 0; i < input.length; i++) { + const y = buf[idx]; + store = y * (1 - damp) + store * damp; // the damping is a low-pass inside the loop: the tail darkens as it decays + buf[idx] = input[i] * 0.015 + store * room; + out[i] += y; + idx = (idx + 1) % d; + } + } + for (const d0 of alls) { + const d = d0 + spread, buf = new Float32Array(d); let idx = 0; + for (let i = 0; i < out.length; i++) { + const b = buf[idx], x = out[i]; + out[i] = b - x; buf[idx] = x + b * 0.5; + idx = (idx + 1) % d; + } + } + return out; + }; + const wl = side(inL, 0), wr = side(inR, 23); + for (let i = 0; i < inL.length; i++) { inL[i] = inL[i] * (1 - wet) + wl[i] * wet * 3; inR[i] = inR[i] * (1 - wet) + wr[i] * wet * 3; } +} + +/** Two one-pole low-passes in a row at `hz`: a gentle 12 dB/octave roll-off over the whole mix. */ +function lowpass(x: Float32Array, hz: number) { + const a = Math.exp((-2 * Math.PI * hz) / SR); + for (let pass = 0; pass < 2; pass++) { let y = 0; for (let i = 0; i < x.length; i++) x[i] = y = (1 - a) * x[i] + a * y; } +} + +/** Amplitude-weighted mean frequency of the whole signal (Hz), from 2048-point frames: higher sounds brighter. */ +export function centroid(x: Float32Array): number { + const N = 2048; let num = 0, den = 0; + for (let s = 0; s + N <= x.length; s += N * 8) { + for (let k = 1; k < N / 2; k += 2) { + let re = 0, im = 0; + for (let n = 0; n < N; n++) { const w = 0.5 - 0.5 * Math.cos((2 * Math.PI * n) / N), v = x[s + n] * w; re += v * Math.cos((2 * Math.PI * k * n) / N); im -= v * Math.sin((2 * Math.PI * k * n) / N); } + const mag = Math.hypot(re, im); num += mag * ((k * SR) / N); den += mag; + } + } + return den ? num / den : 0; +} + +export function renderStereo(file: string, pitches: number[][], onset: number[][], timbre: Timbre, { bpm = 60, octave = 0 } = {}) { + const stepSec = 60 / bpm / 2, n = Math.ceil((pitches.length * stepSec + 4) * SR); + const L = new Float32Array(n), R = new Float32Array(n); + for (let v = 0; v < 4; v++) { + let t = 0; + while (t < pitches.length) { + const p = pitches[t][v]; + if (p < 0) { t++; continue; } + let len = 1; + while (t + len < pitches.length && pitches[t + len][v] === p && !onset[t + len][v]) len++; + note(L, R, timbre, p + 12 * octave, t * stepSec, len * stepSec, v); + t += len; + } + } + reverb(L, R); + lowpass(L, 3200); lowpass(R, 3200); + let peak = 0; for (let i = 0; i < n; i++) peak = Math.max(peak, Math.abs(L[i]), Math.abs(R[i])); + const g = (0.8 / (peak || 1)); + const buf = Buffer.alloc(44 + n * 4); + buf.write("RIFF", 0); buf.writeUInt32LE(36 + n * 4, 4); buf.write("WAVE", 8); buf.write("fmt ", 12); + buf.writeUInt32LE(16, 16); buf.writeUInt16LE(1, 20); buf.writeUInt16LE(2, 22); buf.writeUInt32LE(SR, 24); + buf.writeUInt32LE(SR * 4, 28); buf.writeUInt16LE(4, 32); buf.writeUInt16LE(16, 34); buf.write("data", 36); buf.writeUInt32LE(n * 4, 40); + for (let i = 0; i < n; i++) { buf.writeInt16LE(Math.round(L[i] * g * 32767), 44 + i * 4); buf.writeInt16LE(Math.round(R[i] * g * 32767), 46 + i * 4); } + fs.writeFileSync(file, buf); + const mono = new Float32Array(n); for (let i = 0; i < n; i++) mono[i] = (L[i] + R[i]) / 2; + return centroid(mono); +} diff --git a/docs/research/music-ai/train.ts.txt b/docs/research/music-ai/train.ts.txt new file mode 100644 index 0000000..e91604c --- /dev/null +++ b/docs/research/music-ai/train.ts.txt @@ -0,0 +1,88 @@ +// Train a small Transformer on the chorales with lib/ml (the same code the browser runs), sample at checkpoints. +// npx tsx train.ts [steps] [d] [layers] [ctxSteps] [batch] [lr] +import fs from "node:fs"; +import { Tape } from "../Blog/lib/ml/autograd"; +import { Adam, Transformer } from "../Blog/lib/ml/transformer"; +import { mulberry32 } from "../Blog/lib/ml/neuroevolution"; +import { LO, VOCAB, VOICES, decode, longestCopy, renderWav, report, trainTokens, valTokens } from "./music"; + +const [name = "run", stepsArg = "2000", dArg = "64", layersArg = "2", ctxStepsArg = "32", batchArg = "8", lrArg = "3e-3"] = process.argv.slice(2); +const STEPS = +stepsArg, D = +dArg, LAYERS = +layersArg, CTX = +ctxStepsArg * VOICES, BATCH = +batchArg, LR = +lrArg; +const dir = `runs/${name}`; +fs.mkdirSync(dir, { recursive: true }); +const log = (s: string) => { console.log(s); fs.appendFileSync(`${dir}/log.txt`, s + "\n"); }; + +const rng = mulberry32(7); +const model = new Transformer({ vocab: VOCAB, ctx: CTX, d: D, heads: 4, layers: LAYERS }, rng); +const adam = new Adam(model.params); +log(`params ${model.parameterCount()} ctx ${CTX} batch ${BATCH} lr ${LR}`); + +/** A random window that starts on a step boundary, so the voice order S A T B is always in phase. */ +function window(pool: number[][], r: () => number): number[] { + const seq = pool[Math.floor(r() * pool.length)]; + const steps = seq.length / VOICES, len = Math.min(CTX + VOICES, seq.length); + const start = Math.floor(r() * Math.max(1, steps - len / VOICES + 1)) * VOICES; + return seq.slice(start, start + len); +} + +function lossOn(ids: number[], tape: Tape, weight: number) { + const input = ids.slice(0, -1).slice(0, CTX), targets = ids.slice(1, CTX + 1); + return tape.crossEntropy(model.forward(tape, input).logits, targets, weight); +} + +/** Validation loss on fixed windows: 64 of them, the same every time. */ +const valRng = mulberry32(99), valWindows = Array.from({ length: 64 }, () => window(valTokens, valRng)); +function validate(): number { + let s = 0; + for (const w of valWindows) s += lossOn(w, new Tape(), 1); + return s / valWindows.length; +} + +function sample(steps: number, temperature: number, seed: number): number[] { + const r = mulberry32(seed); + const ids = [72 - LO, 67 - LO, 64 - LO, 48 - LO]; // a C major chord to start from + while (ids.length < steps * VOICES) { + // Slide by whole steps: position 0 must stay the soprano, or every voice reads as its neighbour. + const ctx = ids.slice(Math.max(0, Math.ceil((ids.length - CTX) / VOICES) * VOICES)); + const { logits } = model.forward(new Tape(), ctx); + const row = logits.data.subarray((ctx.length - 1) * VOCAB, ctx.length * VOCAB); + let max = -Infinity; for (const x of row) max = Math.max(max, x); + const p = Array.from(row, (x) => Math.exp((x - max) / temperature)); + let u = r() * p.reduce((a, b) => a + b, 0), k = 0; + while (u > p[k] && k < p.length - 1) u -= p[k++]; + ids.push(k); + } + return ids; +} + +function checkpoint(step: number) { + const val = validate(); + const out: Record = { step, val: +val.toFixed(4) }; + for (const temp of [0.7, 1.0]) { + const rs = [1, 2, 3].map((seed) => decode(sample(64, temp, seed))); + const mean = (k: string) => +(rs.reduce((s, r) => s + (report(r.pitches, r.onset) as any)[k], 0) / rs.length).toFixed(3); + out[`T${temp}`] = { inKey: mean("inKey"), parallels: mean("parallels"), crossings: mean("crossings"), rough: mean("rough"), holdShare: mean("holdShare"), chords: mean("distinctChords"), copy: Math.max(...rs.map((r) => longestCopy(r.pitches))) }; + renderWav(`${dir}/step${step}-T${temp}.wav`, rs[0].pitches, rs[0].onset); + } + log(JSON.stringify(out)); + fs.writeFileSync(`${dir}/model-${step}.json`, JSON.stringify(Object.fromEntries(Object.entries(model.params).map(([k, m]) => [k, Array.from(m.data, (x) => +x.toFixed(5))])))); +} + +const checkpoints = new Set([0, 100, 250, 500, 1000, 2000, 4000, 8000, 16000].filter((s) => s <= STEPS).concat([STEPS])); +const start = Date.now(); +let running = 0; +for (let step = 0; step <= STEPS; step++) { + if (checkpoints.has(step)) { log(`t=${((Date.now() - start) / 1000).toFixed(0)}s`); checkpoint(step); } + if (step === STEPS) break; + model.zeroGrad(); + const tape = new Tape(); + let loss = 0; + for (let b = 0; b < BATCH; b++) loss += lossOn(window(trainTokens, rng), tape, 1 / BATCH) / BATCH; + tape.backward(); + // Short warm-up, then a cosine decay to a tenth. + const lr = LR * Math.min(1, (step + 1) / 100) * (0.1 + 0.9 * 0.5 * (1 + Math.cos((Math.PI * step) / STEPS))); + adam.step(lr); + running = step === 0 ? loss : 0.98 * running + 0.02 * loss; + if (step % 50 === 0) log(`step ${step} loss ${running.toFixed(3)} ${((Date.now() - start) / (step + 1)).toFixed(0)} ms/step`); +} +log(`done in ${((Date.now() - start) / 1000).toFixed(0)} s`);