import type { Chapter } from '../../ui/types.ts' import type { Params } from '../../engine/types.ts' import driver from '../membrane/driver.m?raw' import script from './drum.m?raw' import text from './text.md?raw' import { CentsPanels, STRIKE_CONTROL, StrikePanels, strikeParams, strikeSummary, type CentsOut, type StrikeOut, } from '../membrane/panels.tsx' import { fmtCents } from '../common/panels.tsx' export const ch04: Chapter = { id: 'square', nav: 'A square drum', part: 'Drums', title: 'A square drum', blurb: 'The same scheme in two dimensions: an inharmonic set of partials, a stability limit of 1/√2, and a pitch error that depends on the direction a wave travels.', text, labs: [ { id: 'strike', title: 'Striking the drum', caption: 'The fundamental is 150 Hz. Listen to the exact drum first, then to the grid; move the strike to the centre and hear three quarters of the modes disappear.', driver, script, controls: [ { kind: 'slider', key: 'N', label: 'grid intervals N', min: 0, max: 0, values: [24, 32, 48, 64] }, { kind: 'slider', key: 'lam', label: 'Courant number λ', min: 0, max: 0, values: [0.3, 0.5, 0.7] }, STRIKE_CONTROL, ], defaults: { N: 48, lam: 0.7, at: 'off' }, derive: (p: Params) => strikeParams(p, 'fd2'), editorOpen: true, render: (d: StrikeOut) => , summary: strikeSummary, }, { id: 'cents', title: 'Pitch error in every direction', caption: 'Modes at three wavelengths, at directions from nearly along an edge to nearly along the other. Markers are measured; lines are the dispersion relation at the same modes.', driver, script, controls: [{ kind: 'slider', key: 'N', label: 'grid intervals N', min: 0, max: 0, values: [32, 64] }], defaults: { N: 64 }, derive: (p: Params) => { const N = Number(p.N) return { mode: 'cents', N, lams: [0.3, 0.5, Math.SQRT1_2], rs: [N / 8, N / 4, N / 2], nang: 9 } }, render: (d: CentsOut) => , summary: (d: CentsOut) => [{ label: 'measured minus predicted, largest', value: fmtCents(d.agree) }], }, ], }