@ugfoundation/swaralipi-js 0.13.0 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -0
- package/dist/{batch-BS2AIZOR.js → batch-D4HRATTH.js} +4 -4
- package/dist/{batch-BS2AIZOR.js.map → batch-D4HRATTH.js.map} +1 -1
- package/dist/{chunk-5N6HGPFH.js → chunk-QQOC6LRA.js} +3 -3
- package/dist/{chunk-5N6HGPFH.js.map → chunk-QQOC6LRA.js.map} +1 -1
- package/dist/{chunk-3ZBNANDF.js → chunk-UV5OJYT3.js} +3 -3
- package/dist/{chunk-3ZBNANDF.js.map → chunk-UV5OJYT3.js.map} +1 -1
- package/dist/{chunk-ZNJTMQIX.js → chunk-YBFM5NLW.js} +159 -23
- package/dist/chunk-YBFM5NLW.js.map +1 -0
- package/dist/cli.cjs +1 -1
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +2 -2
- package/dist/convert/index.cjs +1 -1
- package/dist/convert/index.cjs.map +1 -1
- package/dist/convert/index.js +2 -2
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1 -1
- package/dist/player/index.cjs +172 -26
- package/dist/player/index.cjs.map +1 -1
- package/dist/player/index.d.cts +9 -5
- package/dist/player/index.d.ts +9 -5
- package/dist/player/index.js +15 -6
- package/dist/player/index.js.map +1 -1
- package/dist/{schedule-ClyON98C.d.ts → schedule-DsVESieT.d.ts} +27 -2
- package/dist/{schedule-V-fgepvP.d.cts → schedule-oJgg_bnc.d.cts} +27 -2
- package/dist/spec/index.cjs +1 -1
- package/dist/spec/index.cjs.map +1 -1
- package/dist/spec/index.d.cts +1 -1
- package/dist/spec/index.d.ts +1 -1
- package/dist/spec/index.js +1 -1
- package/dist/viewer/index.cjs +68 -33
- package/dist/viewer/index.cjs.map +1 -1
- package/dist/viewer/index.d.cts +1 -1
- package/dist/viewer/index.d.ts +1 -1
- package/dist/viewer/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-ZNJTMQIX.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/spec/lay.ts","../../src/spec/taals.ts","../../src/spec/grace.ts","../../src/spec/svara.ts","../../src/spec/schema.ts","../../src/spec/index.ts","../../src/player/schedule.ts","../../src/player/pitch.ts","../../src/convert/codec.ts","../../src/player/repeats.ts","../../src/viewer/render.ts","../../src/viewer/glyphs.ts","../../src/viewer/fit.ts","../../src/viewer/styles.ts","../../src/viewer/staff.ts","../../src/player/instruments.ts","../../src/viewer/print.ts","../../src/viewer/transliterate.ts","../../src/viewer/element.ts"],"names":["z","last","matra","EPS","edges","note","m","escapeHtml","safeParseSwaralipi","html"],"mappings":"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AA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAA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","file":"index.cjs","sourcesContent":["/**\n * লয় (laya) — the tempo tier a passage is sung at.\n *\n * Hindustani names the three tiers বিলম্বিত / মধ্য / দ্রুত (vilambit = slow,\n * madhya = medium, drut = fast), and Rabindrasangeet swaralipi uses the same\n * words: NLTR prints \"বিলম্বিত লয়:\" / \"দ্রুত লয়:\" at the head of the line\n * where the tempo changes (see `printedLay`).\n *\n * `meta.bpm` is the **দ্রুত** tempo — the fast one — so the tiers are\n * multipliers ≤ 1 on it and a document with no লয় marks plays exactly as it\n * did before this field existed.\n *\n * Zod-free on purpose: the viewer, player and creator import this directly\n * (the `spec/index.js` barrel would drag zod into their browser bundles — the\n * same rule as `taals.ts` and `grace.ts`).\n */\nimport type { Note, Row } from './schema.js';\n\nexport type Lay = 'drut' | 'madhya' | 'vilambit';\n\nexport const LAYS: readonly Lay[] = ['drut', 'madhya', 'vilambit'];\n\n/**\n * ### The tempo factors — change them HERE.\n *\n * Fraction of `meta.bpm` each tier is played at. Consumers override per\n * document (`meta.laySpeeds`) or per player/export call (`laySpeeds`), so\n * these are only the fallback.\n */\nexport const LAY_SPEEDS: Record<Lay, number> = {\n drut: 1,\n madhya: 0.75,\n vilambit: 0.5,\n};\n\nexport type LaySpeeds = Partial<Record<Lay, number>>;\n\n/** Resolve the factors actually in force: call option → document → default. */\nexport function resolveLaySpeeds(doc?: LaySpeeds, opt?: LaySpeeds): Record<Lay, number> {\n return { ...LAY_SPEEDS, ...doc, ...opt };\n}\n\n/**\n * The printed লয় mark: the leading lyric-only cells NLTR writes a tempo\n * change as (\"বিলম্বিত\" \"লয়:\"). Reading it means the 1738 already-converted\n * songs change tempo without being reconverted or edited.\n *\n * ponytail: matches the first word only, and only in the leading annotation\n * position where real lyrics never sit — so 'মধ্যমান' (a taal) can't trip it.\n * If a source ever writes the mark elsewhere in the row, give it `row.lay`.\n */\nconst PRINTED: Record<string, Lay> = { দ্রুত: 'drut', মধ্য: 'madhya', বিলম্বিত: 'vilambit' };\n\nexport function printedLay(notes: Note[]): Lay | undefined {\n const first = notes[0];\n if (first === undefined || first.lyric === undefined) return undefined;\n for (const k of Object.keys(first)) if (k !== 'lyric') return undefined;\n return PRINTED[first.lyric.normalize('NFC')];\n}\n\n/** The লয় this row switches to, if any: the explicit field wins over the\n * source's printed mark. `undefined` = carry on at the previous tier. */\nexport function rowLay(row: Row): Lay | undefined {\n return row.lay ?? printedLay(row.notes);\n}\n","import type { Taal } from './schema.js';\n\n/**\n * Reference definitions for the taals the player will sample:\n * adachautaal, dadra, ektaal, jhaptaal, kehrwa, rupak, shashthi, teentaal,\n * jhampak, dhamaar, rupakra, khemta.\n *\n * `numBeats` and the `bhaags` given below are standard Hindustani taal theory.\n * `bhaags` is omitted where a single canonical division isn't well-agreed\n * (adachautaal) — we assert only what's uncontested. `sam` is beat 0 for all.\n *\n * Tabla loops live under `tabla/<id>/` by default; per-taal variation and\n * skip-bpm overrides (e.g. shashthi → `tabla/shashthi-pro/`) are in\n * instruments.ts's `TABLA_VARIATIONS`.\n */\nexport const TAALS = {\n dadra: { id: 'dadra', numBeats: 6, bhaags: [3, 3], sam: 0, khaali: [3] },\n kehrwa: { id: 'kehrwa', numBeats: 8, bhaags: [4, 4], sam: 0, khaali: [4] },\n rupak: { id: 'rupak', numBeats: 7, bhaags: [3, 2, 2], sam: 0, khaali: [0] },\n jhaptaal: { id: 'jhaptaal', numBeats: 10, bhaags: [2, 3, 2, 3], sam: 0, khaali: [5] },\n ektaal: { id: 'ektaal', numBeats: 12, bhaags: [2, 2, 2, 2, 2, 2], sam: 0, khaali: [2, 6] },\n adachautaal: { id: 'adachautaal', numBeats: 14, sam: 0 },\n choutaal: { id: 'choutaal', numBeats: 12, bhaags: [2, 2, 2, 2, 2, 2], sam: 0, khaali: [2, 6] }, // চৌতাল\n shashthi: { id: 'shashthi', numBeats: 6, bhaags: [2, 4], sam: 0 }, // ষষ্ঠী\n teora: { id: 'teora', numBeats: 7, bhaags: [3, 2, 2], sam: 0 }, // টেওরা\n teentaal: { id: 'teentaal', numBeats: 16, bhaags: [4, 4, 4, 4], sam: 0, khaali: [8] },\n aratheka: { id: 'aratheka', numBeats: 16, bhaags: [4, 4, 4, 4], sam: 0, khaali: [8] }, // আড়াঠেকা\n jhampak: { id: 'jhampak', numBeats: 5, bhaags: [3, 2], sam: 0 }, // ঝম্পক\n dhamaar: { id: 'dhamaar', numBeats: 14, bhaags: [5, 2, 3, 4], sam: 0, khaali: [7] }, // ধামার\n rupakra: { id: 'rupakra', numBeats: 8, bhaags: [3, 2, 3], sam: 0 }, // রূপকড়া\n khemta: { id: 'khemta', numBeats: 12, bhaags: [3, 3, 3, 3], sam: 0, khaali: [6] }, // খেমটা\n} as const satisfies Record<string, Taal>;\n\nexport type TaalId = keyof typeof TAALS;\n\n/**\n * The name a তালফেরতা song's header prints instead of one taal (Swarabitan /\n * Gitabitan's own word; gitabitan.io's taxonomy spells it তাল-ফেরতা). The\n * taals themselves live on the rows (`row.taal`).\n */\nexport const TAAL_FERTA = 'তালফেরতা';\n\n/** Whether a printed taal name is the তালফেরতা heading (either spelling). */\nexport function isTaalFerta(name: string | undefined): boolean {\n return name !== undefined && name.normalize('NFC').replace(/[\\s-]/g, '') === TAAL_FERTA;\n}\n\n/**\n * Whether two taal marks name the same accompaniment — the তালফেরতা test.\n * `null` (মুক্তছন্দ) and `undefined` (no taal) are only equal to themselves.\n * Compared by value: a row restating the taal in force is not a change.\n */\nexport function sameTaal(a: Taal | null | undefined, b: Taal | null | undefined): boolean {\n if (a === b) return true;\n if (!a || !b) return false;\n return a.id === b.id && a.numBeats === b.numBeats && a.variation === b.variation && String(a.bhaags) === String(b.bhaags);\n}\n","/**\n * কণ / রেশ readers. Zod-free on purpose: the viewer and the player import\n * this directly (the `spec/index.js` barrel would drag zod into their\n * browser bundles — see `taals.ts` for the same rule).\n */\nimport type { Grace, Note, Svara } from './schema.js';\n\n/** Normalise a grace payload to its note list; the legacy tuple is one note. */\nexport function graceNotes(grace: Grace | undefined): Note[] {\n if (grace === undefined) return [];\n return typeof grace[0] === 'string' ? [{ svara: grace as Svara }] : (grace as Note[]);\n}\n","/**\n * Which svaras admit which alteration — স and প are অচল (immovable), ম has\n * only its তীব্র (কড়ি) form, and র গ ধ ন only their কোমল form. The notation\n * fonts encode exactly this (no glyph exists for a কোমল প), so a flag the\n * sheet cannot draw must not move the pitch either.\n *\n * Zod-free on purpose: the viewer and the player import this directly (the\n * `spec/index.js` barrel would drag zod into their browser bundles — see\n * `taals.ts` and `grace.ts` for the same rule).\n */\nimport type { SvaraLetter } from './schema.js';\n\nexport function hasKomal(letter: SvaraLetter): boolean {\n return letter === 'r' || letter === 'g' || letter === 'd' || letter === 'n';\n}\n\nexport function hasTivra(letter: SvaraLetter): boolean {\n return letter === 'm';\n}\n","import { z } from 'zod';\nimport type { Lay } from './lay.js';\n\n/**\n * swaralipi-js JSON spec — Zod schema + inferred types.\n\n/** Octave registers */\nexport const octaveSchema = z.enum([\n 'ati-mandra', // very low\n 'mandra', // low (dot below)\n 'madhyam', // middle\n 'taar', // high (ref/dot above)\n 'ati-taar', // very high\n]);\nexport type Octave = z.infer<typeof octaveSchema>;\n\n/**\n * The seven shuddha svara letters:\n * `d` = ধৈবত (dha), `n` = নিষাদ (ni). Komal/tivra are flags, not letters.\n */\nexport const svaraLetterSchema = z.enum(['s', 'r', 'g', 'm', 'p', 'd', 'n']);\nexport type SvaraLetter = z.infer<typeof svaraLetterSchema>;\n\n/** A pitch as `[octave, letter]` */\nexport const svaraSchema = z.tuple([octaveSchema, svaraLetterSchema]);\nexport type Svara = z.infer<typeof svaraSchema>;\n\n/** Microtone variants below komal (legend: অল্পকোমল / অতিকোমল). */\nexport const microtoneSchema = z.enum(['alpakomal', 'atikomal']);\nexport type Microtone = z.infer<typeof microtoneSchema>;\n\n/**\n * Barline weights. Swarabitan distinguishes the light দাঁড়ি (।) that\n * separates vibhags *within* a taal cycle from the দণ্ড (danda, I) strokes:\n * - `dari` — । vibhag separator inside the cycle\n * - `single` — I end of one taal cycle (ফেরা)\n * - `double` — II section (kali) boundary / return-to-asthayi marker\n * - `quad` — IIII end of the song\n */\nexport const barSchema = z.enum(['dari', 'single', 'double', 'quad']);\nexport type Bar = z.infer<typeof barSchema>;\n\n/**\n * A repeat-bracket edge. Brackets span a range of notes; the opening note\n * carries `{ ..., edge: 'open' }` and the closing note `{ ..., edge: 'close' }`.\n * kind: `repeat` = {} গুন্ডবন্ধনী, `skip` = () বক্রবন্ধনী (omit on repeat),\n * `alt` = [] সরল বন্ধনী (changed notes on repeat).\n */\nexport const bracketSchema = z.object({\n kind: z.enum(['repeat', 'skip', 'alt']),\n edge: z.enum(['open', 'close']),\n});\nexport type Bracket = z.infer<typeof bracketSchema>;\n\n/**\n * A কণ / রেশ payload. Historically one `Svara` tuple; real notation puts\n * *several* svaras in a grace, and each may itself be a melisma, so the\n * richer form is a list of notes — reusing `Note` brings komal/tivra/\n * microtone/sustain along for free. The tuple form stays valid, so 0.7.x\n * documents parse unchanged; read either with `graceNotes()`.\n */\nexport type Grace = Svara | Note[];\nexport const graceSchema: z.ZodType<Grace> = z.lazy(() =>\n z.union([svaraSchema, z.array(noteSchema).min(1)]),\n);\n\n/**\n * A single token in a row. A token is one of: a pitched note (`svara`),\n * a rest (`rest`), an আ-কার sustain (`sustain`), a barline (`bar`), or a\n * purely raw/undecoded cell (`raw`) — possibly carrying annotations\n * (`above`/`below`) or a lyric syllable on an otherwise empty column.\n * The `.refine` enforces that a note carries at least one of these so\n * truly empty tokens can't slip through.\n *\n * `above`/`below` make `Note` recursive, so the type is hand-written and\n * the schema is typed `z.ZodType<Note>` via `z.lazy` (all fields are\n * optional, hence input ≡ output and the annotation is sound).\n */\nexport interface Note {\n /** Pitch. Omitted for rests, sustains, and barlines. */\n svara?: Svara;\n /** কোমল (flat). */\n komal?: boolean;\n /** তীব্র / কড়ি (sharp — applies to ma). */\n tivra?: boolean;\n /** Sub-komal microtone (legend: অল্পকোমল / অতিকোমল). */\n microtone?: Microtone;\n /** Duration in মাত্রা (beats): 1 (default), 0.5, 0.25, 2, … */\n durationMatra?: number;\n /**\n * আ-কার: no new syllable attack. Alone (no `svara`) it holds the previous\n * note's pitch and vowel; combined with `svara` it is a melisma — the\n * pitch moves while the previous syllable's vowel continues (Swarabitan\n * writes these with a leading hyphen, e.g. `-sfa`).\n */\n sustain?: boolean;\n /** বিরাম: a rest of `durationMatra` beats. */\n rest?: boolean;\n /** কণ স্বর: one or more grace notes attached before this note. */\n kan?: Grace;\n /**\n * রেশ: an after-touch grace — the legend's mirror of কণ, written small to\n * the *right* of the note (\"আসল স্বরের পরে … অন্য স্বরের ঈষৎ রেশ লাগে;\n * তখন সেই স্বর ক্ষুদ্র অক্ষরে দক্ষিণ পার্শ্বে লিখিত হয়, যথা— রা˰স\").\n * Swarabitan writes it as a trailing uppercase letter (`mpaM`, `raS`).\n */\n resh?: Grace;\n /** মীড় (glide/slur) endpoint; `both` ends the arc coming in and starts the next (ণা‿পা‿ধা). */\n meend?: 'start' | 'end' | 'both';\n /**\n * অর্ধমাত্রা (ঃ): this note closes a cell whose matra unit is a *half* —\n * `সঃ` = ½ matra, `সরঃ` = two ¼s, `রাঃ` = 1½ (legend p. ১৩৫).\n * Explicit rather than derived, because durations alone cannot distinguish\n * two half-matra cells (`সঃ গঃ`) from one matra split in two (`সরা`); this\n * flag is what closes the cell and prints the ঃ.\n */\n halfMatra?: boolean;\n /** Barline. A bar token usually has no `svara`. */\n bar?: Bar;\n /** Repeat-bracket edges opening/closing on this token. */\n brackets?: Bracket[];\n /** Lyric syllable aligned under this note */\n lyric?: string;\n /** Lossless passthrough of the source cell (e.g. raw Swarabitan code). */\n raw?: string;\n /**\n * Curation only: why a converter (e.g. an image reader) doubts this cell —\n * `\"স্বর: পা? ধা?\"`. The creator outlines it until someone edits the cell or\n * accepts it, which deletes the field. Viewer and player ignore it.\n */\n review?: string;\n /**\n * Annotation notes rendered above this column: alt-on-repeat passages\n * (legend: পরিবর্তিত স্বর in [ ] শিরোদেশে), stop marks, beat numbers.\n */\n above?: Note[];\n /** Annotation notes rendered below this column. */\n below?: Note[];\n}\n\nexport const noteSchema: z.ZodType<Note> = z.lazy(() =>\n z\n .object({\n svara: svaraSchema.optional(),\n komal: z.boolean().optional(),\n tivra: z.boolean().optional(),\n microtone: microtoneSchema.optional(),\n durationMatra: z.number().positive().optional(),\n sustain: z.boolean().optional(),\n rest: z.boolean().optional(),\n kan: graceSchema.optional(),\n resh: graceSchema.optional(),\n meend: z.enum(['start', 'end', 'both']).optional(),\n halfMatra: z.boolean().optional(),\n bar: barSchema.optional(),\n brackets: z.array(bracketSchema).optional(),\n lyric: z.string().optional(),\n raw: z.string().optional(),\n review: z.string().optional(),\n above: z.array(noteSchema).optional(),\n below: z.array(noteSchema).optional(),\n })\n .refine(\n (n) =>\n n.svara !== undefined ||\n n.rest === true ||\n n.sustain === true ||\n n.bar !== undefined ||\n n.raw !== undefined ||\n (n.brackets !== undefined && n.brackets.length > 0) ||\n (n.above !== undefined && n.above.length > 0) ||\n (n.below !== undefined && n.below.length > 0) ||\n n.lyric !== undefined,\n {\n message:\n 'note must carry one of: svara, rest, sustain, bar, raw, lyric, brackets, or a non-empty above/below',\n },\n ),\n);\n\n/** লয় tier. `Lay` (and the tempo factors) live in the zod-free ./lay.js,\n * which the viewer/player import directly; `satisfies` keeps the two in step. */\nexport const laySchema = z.enum(['drut', 'madhya', 'vilambit']) satisfies z.ZodType<Lay>;\n\n/**\n * Taal definition. `numBeats` is the cycle length in মাত্রা; `bhaags` (if\n * present) must sum to `numBeats`; `sam`/`khaali` are 0-based beat indices.\n */\nexport const taalSchema = z\n .object({\n /** Player sample key, e.g. `dadra`, `teentaal`. */\n id: z.string(),\n /**\n * Which tabla loop variation to play, e.g. `pro` (CDN dir suffix). Optional\n * and additive — omitted means the taal's default variation, so existing\n * docs are unaffected. The player honors it but never exposes a variation\n * picker; selecting a non-default variation is the consumer's premium policy.\n */\n variation: z.string().optional(),\n numBeats: z.number().int().positive(),\n /** Vibhag groupings; if given, they sum to numBeats. */\n bhaags: z.array(z.number().int().positive()).optional(),\n /** Sam (cycle start) beat index, 0-based. */\n sam: z.number().int().nonnegative().optional(),\n /** Khaali (wave) beat indices, 0-based. */\n khaali: z.array(z.number().int().nonnegative()).optional(),\n })\n .refine((t) => t.bhaags === undefined || t.bhaags.reduce((a, b) => a + b, 0) === t.numBeats, {\n message: 'bhaags must sum to numBeats',\n });\nexport type Taal = z.infer<typeof taalSchema>;\n\n/** A written line of the song: a sequence of note tokens. */\nexport const rowSchema = z.object({\n /** Optional line label (e.g. a tuk/section marker). */\n label: z.string().optional(),\n /**\n * লয়: the tempo tier this row switches to, held until another row changes\n * it (absent on every row = the whole song at `meta.bpm`, i.e. দ্রুত).\n * Read it with `rowLay()`, which also picks up the mark NLTR *prints*\n * (\"বিলম্বিত লয়:\") in already-converted documents.\n */\n lay: laySchema.optional(),\n /**\n * তালফেরতা: the তাল this row switches to, held until another row changes it\n * (absent on every row = the whole song in `meta.taal`). `null` = মুক্তছন্দ\n * from here on: the accompaniment rests until a later row names a taal.\n * Independent of `lay` — either, both or neither may change on one row.\n */\n taal: taalSchema.nullable().optional(),\n /** That taal's name as printed (e.g. `ষষ্ঠী(২/৪)`) — `meta.taalName`'s twin. */\n taalName: z.string().optional(),\n notes: z.array(noteSchema),\n});\nexport type Row = z.infer<typeof rowSchema>;\n\n/** A structural section: আস্থায়ী / অন্তরা / সঞ্চারী / আভোগ, or free text. */\nexport const partSchema = z.object({\n name: z.string().optional(),\n rows: z.array(rowSchema),\n});\nexport type Part = z.infer<typeof partSchema>;\n\n/** Document-level metadata. */\nexport const metaSchema = z.object({\n title: z.string(),\n /** Cross-reference to a gitabitan.io song content id (filename, immutable). */\n songId: z.string().optional(),\n /** Source NLTR node/song id. */\n nltrId: z.number().int().optional(),\n taal: taalSchema.optional(),\n /**\n * The taal name as printed in the source (e.g. `ষষ্ঠী(২/৪)`), except\n * free rhythm which is normalised to `মুক্তছন্দ`. Always set by the NLTR\n * converter; `taal` is set only when the name resolves to a definition.\n */\n taalName: z.string().optional(),\n /** Base pitch for playback, e.g. `C`, `C#`, or the player's `cs` form. */\n tonic: z.string().optional(),\n /** Default playback tempo in matra/min. Player-only — the viewer ignores it.\n * The player adopts it on `load()` (precedence: constructor `bpm` → `setBpm`\n * tweak → this → 90). `null` is the converter's blank placeholder = unset. */\n bpm: z.number().positive().nullable().optional(),\n /** Per-document override of the লয় tempo factors (fractions of `bpm`).\n * Defaults live in `LAY_SPEEDS`; a player/export option overrides both. */\n laySpeeds: z\n .object({ drut: z.number().positive(), madhya: z.number().positive(), vilambit: z.number().positive() })\n .partial()\n .optional(),\n raag: z.string().optional(),\n /** আবর্তন: number of taal cycles, when the source states it. */\n avartan: z.number().int().positive().optional(),\n /** স্বরলিপিকার (notation author). */\n notationBy: z.string().optional(),\n /** Provenance note or URL. */\n source: z.string().optional(),\n});\nexport type Meta = z.infer<typeof metaSchema>;\n\n/** A complete swaralipi document. */\nexport const swaralipiSchema = z.object({\n /** Spec version this document targets (see SPEC_VERSION in ./index). */\n version: z.string(),\n meta: metaSchema,\n parts: z.array(partSchema),\n});\nexport type Swaralipi = z.infer<typeof swaralipiSchema>;\n","/**\n * @ugfoundation/swaralipi-js/spec\n *\n * The swaralipi JSON spec: Zod schemas, inferred TS types, and parse helpers.\n */\nimport { swaralipiSchema, type Swaralipi } from './schema.js';\n\n/** Current spec version. Documents declare the version they target. */\nexport const SPEC_VERSION = '0.13.0';\n\nexport {\n octaveSchema,\n svaraLetterSchema,\n svaraSchema,\n microtoneSchema,\n barSchema,\n bracketSchema,\n graceSchema,\n laySchema,\n noteSchema,\n rowSchema,\n partSchema,\n taalSchema,\n metaSchema,\n swaralipiSchema,\n} from './schema.js';\n\nexport type {\n Octave,\n SvaraLetter,\n Svara,\n Microtone,\n Bar,\n Bracket,\n Grace,\n Note,\n Row,\n Part,\n Taal,\n Meta,\n Swaralipi,\n} from './schema.js';\n\nexport { TAALS, TAAL_FERTA, isTaalFerta, sameTaal, type TaalId } from './taals.js';\nexport { graceNotes } from './grace.js';\nexport {\n LAYS,\n LAY_SPEEDS,\n printedLay,\n resolveLaySpeeds,\n rowLay,\n type Lay,\n type LaySpeeds,\n} from './lay.js';\nexport { hasKomal, hasTivra } from './svara.js';\n\n/** Parse + validate unknown data into a `Swaralipi`. Throws `ZodError` on failure. */\nexport function parseSwaralipi(data: unknown): Swaralipi {\n return swaralipiSchema.parse(data);\n}\n\n/** Non-throwing variant: returns Zod's `{ success, data | error }` result. */\nexport function safeParseSwaralipi(data: unknown) {\n return swaralipiSchema.safeParse(data);\n}\n","/**\n * Pure spec-doc → playback timeline. No Tone, no audio — the player turns\n * this `Schedule` into Transport events, but it is fully unit-testable on its\n * own and mirrors the viewer's spec-driven (not raw-driven) reading.\n *\n * Timing unit is the মাত্রা (matra / beat). One global beat cursor runs across\n * every part and row: NLTR \"systems\" (rows) are wraps of one continuous line,\n * and parts (asthayi → antara …) play back-to-back, so the music never pauses\n * at a row or part boundary.\n *\n * Each audible column carries the same `data-note` path the viewer emits\n * (`part.row.note`, note = absolute index into `row.notes`; see\n * src/viewer/render.ts), so `SwaralipiPlayer` can drive `highlight()` directly.\n */\nimport type { Note, Swaralipi, Taal } from '../spec/index.js';\nimport { resolveLaySpeeds, rowLay, type Lay, type LaySpeeds } from '../spec/lay.js';\nimport { sameTaal } from '../spec/taals.js';\nimport { graceMidis, parseTonic, svaraToMidi } from './pitch.js';\nimport { isSilent, playOrder } from './repeats.js';\n\nexport interface PlayEvent {\n /** Onset in matra from the start of the document. */\n beat: number;\n /** Ring length in matra (extended by following আ-কার holds). */\n durationBeats: number;\n /** Pitch as MIDI, or null for a rest / আ-কার hold column. */\n midi: number | null;\n /** MIDI of each কণ grace on this column, in written order (empty = none). */\n kan: number[];\n /** MIDI of each রেশ grace on this column, in written order (empty = none). */\n resh: number[];\n /** `part.row.note` highlight path. */\n path: string;\n kind: 'note' | 'rest' | 'sustain';\n /**\n * মীড়: this pitch is reached by **gliding** from the previous pitched event,\n * not by a new attack. The two (or more) notes are one continuous sound whose\n * pitch travels — see `meendContinuations`. Consumers pair an attack with its\n * targets via `glideTargets`.\n */\n glide?: true;\n}\n\n/**\n * One accompaniment stretch of the timeline: a লয় and a তাল held constant.\n * A new segment starts wherever either changes — they are independent marks.\n * `scale` is the fraction of the base bpm the passage sounds at, and it is\n * exactly the factor a looping accompaniment must change its own tempo by —\n * `beat` × secondsPerBeat gives its start in seconds. Always at least one\n * segment, the first at beat 0.\n */\nexport interface TempoSegment {\n /** Start, in schedule beats (see PlayEvent.beat). */\n beat: number;\n /** End, in schedule beats (= the next segment's start, or totalBeats). */\n endBeat: number;\n scale: number;\n lay: Lay;\n /** তাল in force: `meta.taal` until a row's `taal` changes it. `null` = an\n * explicit মুক্তছন্দ passage; `undefined` = the document names no taal. */\n taal?: Taal | null;\n}\n\nexport interface Schedule {\n events: PlayEvent[];\n /** Total length in matra (the cursor's final value). */\n totalBeats: number;\n /**\n * অনাগত/anacrusis offset: beats the melody must be pushed later so the song's\n * সম (sam) lands on a cyclic accompaniment's sam. Many songs begin part-way\n * through the তাল cycle (the notation's first beat-label is `2`/`3`… and the\n * সম tick `1f`/`2f`… appears a few beats in) — without a shift the pickup note\n * would sound on the tabla's sam. Derived purely from the notation's own সম\n * tick position and `meta.taal.numBeats`; 0 when the song starts on sam or has\n * no sam tick. The player/exporter apply it only when a rhythm actually loops.\n */\n pickupBeats: number;\n /** লয় / তাল stretches, in order and gapless. One entry (drut, scale 1,\n * `meta.taal`) for a document that never changes either — i.e. every\n * document written before `row.lay` / `row.taal` existed. */\n tempo: TempoSegment[];\n}\n\nexport interface ScheduleOptions {\n /** Tonic; accepts `C`, `C#`, `cs`… (see parseTonic). Default C. */\n tonic?: string;\n /** Octave of madhyam Sa (C4 = MIDI 60). Default 4. */\n baseOctave?: number;\n /** Override the লয় tempo factors (see LAY_SPEEDS / meta.laySpeeds). */\n laySpeeds?: LaySpeeds;\n /** Apply লয় at all. Default true. The staff view sets it false: it reads\n * `durationBeats` as written note values, where a 0.75 stretch is not a\n * writable duration. */\n lay?: boolean;\n /** Sing the song's form (see playOrder): each `{ }` twice, `( )` only the\n * first time, the `[ ]` notes on the repeat, and back to the asthayi at each\n * kali's end. Default false — the written order, which the staff view and\n * anything grouping events by row rely on; the player and the audio/MIDI\n * exports turn it on. */\n repeats?: boolean;\n}\n\n/**\n * Below-annotation raws that are মীড় arc drawing segments (codec known-raw):\n * `w`/`x` are the left/right curled ends, the rest are straight fill pieces.\n * Lives here rather than in the viewer because **both** need it and the viewer\n * may import the player (never the reverse — that would pull Tone into it).\n */\nexport const ARC_RAW_RE = /^[wWxXyYjJeEzZ$=_<>`\\\\]+$/;\nexport const isArcRaw = (raw: string | undefined): raw is string =>\n raw !== undefined && ARC_RAW_RE.test(raw);\n\n/** The spec's `meend` as the corpus's own arc marks; `both` = close, then re-open. */\nconst MEEND_MARKS: Record<NonNullable<Note['meend']>, string> = { start: 'w', end: 'x', both: 'xw' };\n\n/**\n * Note indices in one row that lie under a মীড় arc **without opening it** —\n * i.e. every note the pitch glides *to*, as opposed to the one it glides\n * *from*.\n *\n * Swarabitan's legend defines the under-arc as \"কোনো এক স্বর যখন আর এক স্বরে\n * বিশেষরূপে গড়াইয়া যায়\" — when one svara *rolls into* another (example:\n * ণা‿পা). It is one continuous phonation, which is why 90 % of the corpus's\n * 7 419 arcs end on a melisma (a note under the *same* held syllable, lyric ৹).\n * So the notes under an arc must not be re-articulated: only the first sounds.\n *\n * Two encodings feed the same scan — the converter's below-row `w`/`x` raws\n * (every meend in the 1738-song corpus) and the spec's own `meend: start|end`\n * (what the creator writes). A cell may carry both ends (`xw` =\n * close then re-open, `wx` = an arc drawn inside the one cell), so marks are\n * read **in order** — reading them as an unordered set left a `wx` arc open and\n * slurred the next eighteen notes into a single slide. Arcs are resolved per row — exactly one arc in the\n * whole corpus wraps across a row, so cross-row state would not pay for itself.\n */\nexport function meendContinuations(notes: Note[]): Set<number> {\n const out = new Set<number>();\n /** Notes seen since the arc opened — committed only once it closes. */\n let pending: number[] | undefined;\n notes.forEach((note, i) => {\n let marks = note.meend ? MEEND_MARKS[note.meend] : '';\n for (const b of note.below ?? []) if (isArcRaw(b.raw)) marks += b.raw;\n let marked = false;\n for (const ch of marks) {\n if (ch === 'x' || ch === 'X') {\n // Closes here: this note and everything since the open are targets.\n if (pending !== undefined) for (const k of [...pending, i]) out.add(k);\n pending = undefined;\n marked = true;\n } else if (ch === 'w' || ch === 'W') {\n pending = []; // opens here: this note is the source, not a target\n marked = true;\n }\n }\n if (!marked && pending !== undefined) pending.push(i);\n });\n // An arc left open at the row's end is a notation slip (5 in 1738 songs), not\n // a glide: committing it would slur the whole rest of the line into one\n // 16-beat slide. The viewer still draws it as a system-wrap continuation.\n return out;\n}\n\n/**\n * The glide targets belonging to the attack at `events[i]`: the pitched events\n * that follow it flagged `glide`. Silent columns (আ-কার holds) are transparent\n * — the note is still ringing through them — but a rest ends the phrase.\n * Consumers skip events that are themselves `glide` (already consumed here).\n */\nexport function glideTargets(events: PlayEvent[], i: number): PlayEvent[] {\n const out: PlayEvent[] = [];\n for (let j = i + 1; j < events.length; j++) {\n const ev = events[j]!;\n if (ev.kind === 'rest') break;\n if (ev.midi === null) continue;\n if (ev.glide !== true) break;\n out.push(ev);\n }\n return out;\n}\n\n/** Schedule beats between a grace and its column's start; consecutive graces step by it. */\nexport const GRACE_STEP = 0.12;\n\n/**\n * When each grace of `ev` sounds, in written order, mirrored around the\n * column's start: a কণ (written left of its svara) touches just before it, a\n * রেশ (written right) just after — so on a hold or rest column they touch under\n * whatever is still ringing. Not at the column's end: every grace is a fresh\n * strike, and one struck just before the next column is heard as its কণ.\n */\nexport function graceTouches(ev: PlayEvent): { midi: number; beat: number }[] {\n // ponytail: a fixed step, so several graces on a very short column spill past\n // it (two রেশ on a 1/5-matra note); scale the step by column length if needed.\n return [\n ...ev.kan.map((midi, g) => ({ midi, beat: ev.beat - GRACE_STEP * (ev.kan.length - g) })),\n ...ev.resh.map((midi, g) => ({ midi, beat: ev.beat + GRACE_STEP * (g + 1) })),\n ];\n}\n\n/**\n * One line of the sheet as the practice controls move by it: a `part.row`\n * with at least one timed column. It runs from its first event to the next\n * line's (the last one to `totalBeats`), so a line's trailing bars and holds\n * belong to it. A row sung twice (a repeat, a return to the asthayi) is two\n * lines with one `row`.\n */\nexport interface Line {\n /** `part.row` — the viewer's `data-row`. */\n row: string;\n /** Index of the line's first event. */\n first: number;\n beat: number;\n endBeat: number;\n}\n\nconst rowOf = (path: string): string => path.split('.').slice(0, 2).join('.');\nconst noteOf = (path: string): number => Number(path.split('.')[2] ?? 0);\n/** Written order of two `part.row` keys. */\nexport const byRow = (a: string, b: string): number => {\n const [ap = 0, ar = 0] = a.split('.').map(Number);\n const [bp = 0, br = 0] = b.split('.').map(Number);\n return ap - bp || ar - br;\n};\n\n/** The schedule's events grouped into sheet lines, in play order. A row of\n * bars and annotations only has no events, so it is not a line; a repeat that\n * jumps back within a row starts a new one. */\nexport function scheduleLines(schedule: Pick<Schedule, 'events' | 'totalBeats'>): Line[] {\n const lines: Line[] = [];\n let note = Infinity;\n schedule.events.forEach((ev, i) => {\n const n = noteOf(ev.path);\n if (lines.at(-1)?.row !== rowOf(ev.path) || n < note) lines.push({ row: rowOf(ev.path), first: i, beat: ev.beat, endBeat: 0 });\n note = n;\n });\n lines.forEach((line, k) => (line.endBeat = lines[k + 1]?.beat ?? schedule.totalBeats));\n return lines;\n}\n\n/** Index of the line holding event `i`. */\nexport function lineAt(lines: Line[], i: number): number {\n let k = 0;\n while (k + 1 < lines.length && lines[k + 1]!.first <= i) k++;\n return k;\n}\n\n/**\n * The line `path` (`part.row[.note]`) names — its own row, else the next row\n * that sounds — sung at the pass nearest line `near` (-1: the first pass).\n * -1 when no line is at or after it.\n */\nexport function lineFor(lines: Line[], path: string, near: number): number {\n let row: string | undefined;\n for (const line of lines) if (byRow(line.row, rowOf(path)) >= 0 && (row === undefined || byRow(line.row, row) < 0)) row = line.row;\n let best = -1;\n lines.forEach((line, k) => {\n if (line.row === row && (best < 0 || Math.abs(k - near) < Math.abs(best - near))) best = k;\n });\n return best;\n}\n\n/**\n * The event a tap or a seek to `path` (`part.row.note`, or `part.row` for the\n * line's start) should start from: the first event at or after that note in\n * its own line, else the line's last one — a closing bar belongs to its line,\n * not the next — else the next line's first. A line sung more than once\n * resolves to the pass nearest event `near` (default: the first pass). A note\n * reached by a মীড় glide has no attack of its own, so the glide's source is\n * returned instead. -1 when nothing sounds from there on.\n */\nexport function eventAt(events: PlayEvent[], path: string, near = -1): number {\n const lines = scheduleLines({ events, totalBeats: 0 });\n const k = lineFor(lines, path, near < 0 ? -1 : lineAt(lines, near));\n if (k < 0) return -1;\n const end = lines[k + 1]?.first ?? events.length;\n let i = lines[k]!.first;\n if (lines[k]!.row === rowOf(path)) while (i < end - 1 && noteOf(events[i]!.path) < noteOf(path)) i++;\n while (i > 0 && events[i]!.glide === true) i--;\n return i;\n}\n\n/** A সম beat-tick: a beat-label digit carrying the reph tick (`1f`/`2F`…). It\n * marks the sam wherever it lands; the digit is a within-line vibhag number, so\n * only the trailing f/F (not the value) identifies sam. Labels live on a note's\n * `above` annotations (see the converter's beat-label handling). */\nconst SAM_TICK = /^\\d+[fF]$/;\n\n/**\n * Walk a document into a flat, time-ordered list of play events.\n *\n * - svara note → an attack at the cursor; advances by `durationMatra ?? 1`.\n * - rest → a silent column that still advances the cursor.\n * - sustain **with** svara (melisma) → a fresh attack (the pitch moves under\n * a held vowel); advances.\n * - sustain **without** svara (আ-কার hold) → no attack, but the previous\n * audible note's ring is extended; still emitted (midi null) so the lyric\n * column highlights; advances.\n * - a svara under a মীড় arc (but not the note the arc opened on) → still its\n * own event, flagged `glide`: the pitch is reached by sliding from the\n * previous attack rather than by striking again (see meendContinuations).\n * - bar / bracket-only / carrier / structural raw → ignored (no event, no\n * advance); an *undecoded* notation cell (see isSilent) instead plays as a\n * rest, so it keeps its matra and the তাল stays aligned.\n *\n * Written order by default; with `repeats` the walk follows the sung order\n * (playOrder), so a column sung twice is two events with one path.\n */\nexport function buildSchedule(doc: Swaralipi, opts: ScheduleOptions = {}): Schedule {\n const tonicPc = parseTonic(opts.tonic ?? doc.meta.tonic);\n const baseOctave = opts.baseOctave ?? 4;\n const events: PlayEvent[] = [];\n let cursor = 0;\n /** Index in `events` of the last pitched attack, for hold-extension. */\n let lastPitched = -1;\n /** Matra position of the first সম tick (see SAM_TICK), if any. Counted in\n * *written* matra, so the anacrusis maths stays independent of the লয়. */\n let samMatra: number | undefined;\n let matra = 0;\n\n // লয় and তাল: a row's mark holds until another row changes it, in written\n // order — so a repeat or a return to the asthayi sings each row at its own\n // tempo and taal, not at whatever the jump came from. `scale` < 1 stretches\n // the written matra over more schedule beats, which is what makes the\n // passage sound slower at one transport tempo.\n const speeds = resolveLaySpeeds(doc.meta.laySpeeds, opts.laySpeeds);\n const withLay = opts.lay !== false;\n const tempo: TempoSegment[] = [{ beat: 0, endBeat: 0, scale: 1, lay: 'drut', taal: doc.meta.taal }];\n const rows = new Map<string, { scale: number; lay: Lay; taal: Taal | null | undefined; glides: Set<number> }>();\n let scale = 1;\n let layNow: Lay = 'drut';\n let taal: Taal | null | undefined = doc.meta.taal;\n doc.parts.forEach((part, p) =>\n part.rows.forEach((row, r) => {\n const lay = withLay ? rowLay(row) : undefined;\n if (lay !== undefined && speeds[lay] !== scale) {\n scale = speeds[lay];\n layNow = lay;\n }\n if (row.taal !== undefined) taal = row.taal;\n rows.set(`${p}.${r}`, { scale, lay: layNow, taal, glides: meendContinuations(row.notes) });\n }),\n );\n\n const visits =\n opts.repeats === true\n ? playOrder(doc)\n : doc.parts.flatMap((part, p) => part.rows.flatMap((row, r) => row.notes.map((note, i) => ({ p, r, i, note }))));\n let rowNow = '';\n for (const { p, r, i, note } of visits) {\n const row = rows.get(`${p}.${r}`)!;\n if (rowNow !== `${p}.${r}`) {\n rowNow = `${p}.${r}`;\n // The two marks are independent, so a segment starts wherever either moves.\n const last = tempo[tempo.length - 1]!;\n if (row.scale !== last.scale || !sameTaal(row.taal, last.taal)) {\n const seg: TempoSegment = { beat: cursor, endBeat: cursor, scale: row.scale, lay: row.lay, taal: row.taal };\n // Two marks with nothing between them are one switch, not a 0-beat segment.\n if (last.beat === cursor) tempo[tempo.length - 1] = seg;\n else {\n last.endBeat = cursor;\n tempo.push(seg);\n }\n }\n }\n // A সম tick can ride any column (incl. a bar/carrier), so scan before\n // the silent-column early return, recording only the first one.\n if (samMatra === undefined && note.above !== undefined) {\n for (const a of note.above) {\n if (a.raw !== undefined && SAM_TICK.test(a.raw)) {\n samMatra = matra;\n break;\n }\n }\n }\n if (note.bar !== undefined || isSilent(note)) continue;\n const path = `${p}.${r}.${i}`;\n const written = note.durationMatra ?? 1;\n const dur = written / row.scale;\n // Any column that takes time can carry graces, a hold or rest included.\n const kan = graceMidis(note.kan, tonicPc, baseOctave);\n const resh = graceMidis(note.resh, tonicPc, baseOctave);\n\n if (note.svara !== undefined) {\n // svara note or melisma — a real attack, unless a মীড় glides into it.\n events.push({\n beat: cursor,\n durationBeats: dur,\n midi: svaraToMidi(note, tonicPc, baseOctave),\n kan,\n resh,\n path,\n kind: note.sustain === true ? 'sustain' : 'note',\n ...(row.glides.has(i) && lastPitched >= 0 ? { glide: true as const } : {}),\n });\n lastPitched = events.length - 1;\n } else if (note.sustain === true) {\n // আ-কার hold — extend the ringing note, emit a silent highlight column.\n if (lastPitched >= 0) events[lastPitched]!.durationBeats += dur;\n events.push({ beat: cursor, durationBeats: dur, midi: null, kan, resh, path, kind: 'sustain' });\n } else {\n // rest.\n events.push({ beat: cursor, durationBeats: dur, midi: null, kan, resh, path, kind: 'rest' });\n }\n cursor += dur;\n matra += written;\n }\n\n // Anacrusis: shift the melody so its sam falls on a cyclic sam. If sam is at\n // matra S in an N-beat cycle, S + shift ≡ 0 (mod N) → shift = (N − S mod N) mod N\n // (a partial-to-full cycle count-in; 0 when the song already starts on sam).\n // The opening taal's cycle — the one the count-in is played in.\n const numBeats = tempo[0]!.taal?.numBeats;\n const pickupMatra =\n samMatra !== undefined && numBeats !== undefined && numBeats > 0\n ? (numBeats - (samMatra % numBeats)) % numBeats\n : 0;\n tempo[tempo.length - 1]!.endBeat = cursor;\n\n // The count-in is played at the tempo the song *starts* in.\n return { events, totalBeats: cursor, pickupBeats: pickupMatra / tempo[0]!.scale, tempo };\n}\n","/**\n * Pure svara → pitch math for the player. No Tone, no audio — unit-testable\n * in plain Node and shared by the scheduler.\n *\n * The model: a tonic (Sa) pitch-class + a per-note scale degree + octave\n * register + komal/tivra/microtone accidentals → an absolute MIDI number,\n * which the Tone.Sampler pitch-shifts from the nearest santoor sample.\n */\nimport { graceNotes } from '../spec/grace.js';\nimport { hasKomal, hasTivra } from '../spec/svara.js';\nimport type { Note, Octave, SvaraLetter } from '../spec/index.js';\n\n/** Octave register offset in octaves, relative to madhyam (middle). */\nexport const OCTAVE_OFFSET: Record<Octave, number> = {\n 'ati-mandra': -2,\n mandra: -1,\n madhyam: 0,\n taar: 1,\n 'ati-taar': 2,\n};\n\n/**\n * Shuddha (natural) scale degrees in semitones above Sa — the Bilawal/major\n * thaat that Rabindrasangeet swaralipi notates against. `d` = dha, `n` = ni\n * (standard sargam letter convention).\n */\nexport const SHUDDHA: Record<SvaraLetter, number> = {\n s: 0,\n r: 2,\n g: 4,\n m: 5,\n p: 7,\n d: 9,\n n: 11,\n};\n\n/** Sharp-spelled pitch-class names, index = semitone 0–11. */\nconst SHARP_NAMES = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B'] as const;\n\n/** Pitch-class lookup. Accepts sharps (`C#`, `Cs`, `cs`) and flats (`Db`). */\nconst PITCH_CLASS: Record<string, number> = {\n c: 0,\n 'c#': 1,\n db: 1,\n d: 2,\n 'd#': 3,\n eb: 3,\n e: 4,\n 'e#': 5,\n fb: 4,\n f: 5,\n 'f#': 6,\n gb: 6,\n g: 7,\n 'g#': 8,\n ab: 8,\n a: 9,\n 'a#': 10,\n bb: 10,\n b: 11,\n 'b#': 0,\n cb: 11,\n};\n\n/**\n * Parse a tonic string to a pitch-class 0–11. Accepts `C`, `C#`, `Db`, and\n * the player/sample lowercase-`s` sharp form (`cs`, `Cs`); case-insensitive.\n * Unknown input falls back to 0 (C).\n */\nexport function parseTonic(tonic: string | undefined): number {\n if (!tonic) return 0;\n const key = tonic.trim().toLowerCase().replace(/s/g, '#');\n return PITCH_CLASS[key] ?? 0;\n}\n\n/**\n * Semitone of a note relative to Sa (degree + accidentals), ignoring octave.\n * Returns null when the note carries no pitch (rest/sustain-hold/bar).\n *\n * Microtones (অল্পকোমল/অতিকোমল) are approximated to the komal pitch — a\n * documented v1 limitation (the sampler can't bend a sub-komal microtone\n * cleanly per note); matches the viewer's placeholder treatment.\n */\nexport function svaraSemitone(note: Note): number | null {\n if (note.svara === undefined) return null;\n const [, letter] = note.svara;\n let semi = SHUDDHA[letter];\n // Only alter what the notation can actually draw: স/প are অচল and ম has no\n // কোমল form, so a stray flag on one of those must sound as written (the\n // viewer falls back to the shuddha glyph — see glyphs.ts).\n if ((note.komal === true || note.microtone !== undefined) && hasKomal(letter)) semi -= 1;\n if (note.tivra === true && hasTivra(letter)) semi += 1;\n return semi;\n}\n\n/**\n * Absolute MIDI for a note, or null when it has no pitch. madhyam Sa lands on\n * the tonic in octave `baseOctave` (C4 = MIDI 60). Out-of-sample registers\n * are produced by the Sampler pitch-shifting from the nearest recorded note.\n */\nexport function svaraToMidi(note: Note, tonicPc: number, baseOctave = 4): number | null {\n const semi = svaraSemitone(note);\n if (semi === null || note.svara === undefined) return null;\n const [octave] = note.svara;\n return (baseOctave + 1 + OCTAVE_OFFSET[octave]) * 12 + tonicPc + semi;\n}\n\n/** MIDI of a কণ/রেশ grace: one pitch per grace svara, in written order.\n * Goes through `svaraToMidi`, so a komal/tivra grace sounds as written (the\n * legacy tuple form carries no accidentals and is shuddha by construction). */\nexport function graceMidis(\n grace: Note['kan'],\n tonicPc: number,\n baseOctave = 4,\n): number[] {\n return graceNotes(grace)\n .map((n) => svaraToMidi(n, tonicPc, baseOctave))\n .filter((m): m is number => m !== null);\n}\n\n/** MIDI → Tone note name (`C#4`). */\nexport function midiToSampleName(midi: number): string {\n const pc = ((midi % 12) + 12) % 12;\n const octave = Math.floor(midi / 12) - 1;\n return `${SHARP_NAMES[pc]}${octave}`;\n}\n\n/** MIDI → santoor sample filename stem (`cs4`): lowercase, `#` → `s`. */\nexport function sampleFileName(midi: number): string {\n return midiToSampleName(midi).toLowerCase().replace('#', 's');\n}\n\n/**\n * Logistic S-curve on [0, 1], normalised so f(0) = 0 and f(1) = 1.\n *\n * A মীড় is **not** a linear ramp. The hand (or the voice) accelerates away\n * from the source pitch and decelerates into the target — \"if the pull is too\n * fast, the melody loses its vocal quality; if it is too slow, the note dies\n * before reaching its destination\". That S shape is the established model for\n * portamento pitch contours (Yang & Chew's logistic fit, ISMIR 2016), and its\n * coefficient has a direct musical meaning: `steepness` is how abruptly the\n * pitch leaves one svara for the next.\n */\nexport function sCurve(x: number, steepness = 8): number {\n const t = Math.min(Math.max(x, 0), 1);\n const logistic = (u: number) => 1 / (1 + Math.exp(-steepness * (u - 0.5)));\n const lo = logistic(0);\n return (logistic(t) - lo) / (logistic(1) - lo);\n}\n","/**\n * The Swarabitan ASCII codec: decode one grid-cell text into spec `Note`s.\n *\n * NLTR renders notation through the legacy \"Swarabitan\" webfont, which maps\n * ASCII to akarmatrik glyphs. The table below was derived by dumping every\n * glyph of `Swarabitan.woff` (tools/font-dump/) and cross-checking against\n * the Swarabitan legend scans, the rendered reference screenshot of song\n * 4270, and corpus-wide token statistics. Evidence per assignment:\n *\n * Letters (full-size glyphs):\n * s=স r=র g=গ m=ম p=প q=ধ n=ন — the seven shuddha letters\n * d=দ (komal dha) t=জ্ঞ (komal ga) — legend: কোমল র—ঋ, কোমল গ—জ্ঞ,\n * k=ক্ষ (tivra ma) u=ণ (komal ni) — কড়ি ম—ক্ষ, কোমল ধ—দ, কোমল ন—ণ\n * v=ঋ (komal re)\n * Modifiers:\n * f = রেফ above → taar octave (zero-width high combining mark)\n * h = হসন্ত below → mandra octave (low combining mark; corpus nh/uh/dh/ph)\n * leading '-' = no new vowel attack (melisma; lyric row shows ৹)\n * trailing 'a' = the আ-কার matra carrier; k letter-units in one cell\n * share it → k notes of 1/k matra each\n * UPPERCASE letter = small raised form = কণ (kan/grace) prefix; takes its\n * own f/h (corpus: Sfua, NHsa, QHpha); width ratios ~0.65\n * confirm uppercase↔lowercase pairing\n * Structurals (own cells):\n * A = thin full-height bar → দাঁড়ি vibhag separator (fixed columns)\n * l = serif danda I → cycle end; ll / single-glyph L = section\n * %=সা &=নি — precomposed one-matra forms (rare)\n * Known-but-kept-raw marks (drawn pieces the spec doesn't model yet):\n * w x = left/right ends of a long under-arc; E J j y $ < > = _ = arc/line\n * fill segments; | = thin yugal-dari stop mark (mostly annotation rows);\n * digits/!/@ (+f/F sam tick) = taal beat labels; b=× o O e ` + , . i : ;\n * = dots/ticks/duration marks; B C * ^ ~ c = rare precomposed/legacy forms.\n *\n * Decoding never throws: any chunk outside the grammar becomes a raw-only\n * note and is reported as unknown — zero data loss by construction.\n */\nimport type { Note, Octave, Svara, SvaraLetter } from '../spec/index.js';\n\nexport interface CellDecode {\n notes: Note[];\n /** Chunks that failed the grammar (reported, kept as raw notes). */\n unknownTokens: string[];\n /** Chunks understood but intentionally left raw (marks, beat labels …). */\n knownRawTokens: string[];\n /** True if at least one chunk decoded to a semantic note. */\n decoded: boolean;\n}\n\ninterface LetterDef {\n letter: SvaraLetter;\n komal?: true;\n tivra?: true;\n}\n\n/** ASCII → svara letter (+ komal/tivra). The five non-shuddha glyph letters\n * are distinct characters in akarmatrik, so the flags live here. */\nconst LETTERS: Record<string, LetterDef> = {\n s: { letter: 's' },\n r: { letter: 'r' },\n g: { letter: 'g' },\n m: { letter: 'm' },\n p: { letter: 'p' },\n q: { letter: 'd' }, // ধ — shuddha dha\n n: { letter: 'n' },\n d: { letter: 'd', komal: true }, // দ\n t: { letter: 'g', komal: true }, // জ্ঞ\n k: { letter: 'm', tivra: true }, // ক্ষ\n u: { letter: 'n', komal: true }, // ণ\n v: { letter: 'r', komal: true }, // ঋ\n};\n\n/** Standalone structural tokens (bars are handled by the bar-run rule). */\nconst STRUCTURALS: Record<string, () => Note> = {\n '%': () => ({ svara: ['madhyam', 's'] }), // precomposed সা\n '&': () => ({ svara: ['madhyam', 'n'] }), // precomposed নি\n};\n\n/**\n * Bar/bracket runs: `l`(I danda) `ll`/`L`(II) `llll`/`LL`(IIII) `A`(দাঁড়ি),\n * plus composites the corpus writes into one cell — `l[]l` / `L[]L` (the\n * legend's \"I [ ] I\" return-to-asthayi-with-changed-notes marker), `AA`,\n * and `-A` (the previous note's continuation dash sharing the dari's cell).\n */\nconst BAR_RUN_RE = /^(-)?([lLA[\\]]+)$/;\n\nfunction decodeBarRun(body: string): Note[] | undefined {\n const m = body.match(BAR_RUN_RE);\n if (!m || !/[lLA]/.test(m[2]!)) return undefined;\n const notes: Note[] = [];\n if (m[1]) notes.push({ sustain: true });\n const run = m[2]!;\n let i = 0;\n while (i < run.length) {\n const ch = run[i]!;\n if (ch === 'l' || ch === 'L') {\n let j = i;\n while (j < run.length && run[j] === ch) j++;\n const strokes = (j - i) * (ch === 'L' ? 2 : 1);\n notes.push({ bar: strokes >= 4 ? 'quad' : strokes >= 2 ? 'double' : 'single' });\n i = j;\n } else if (ch === 'A') {\n notes.push({ bar: 'dari' });\n i++;\n } else {\n notes.push({ brackets: [{ kind: 'alt', edge: ch === '[' ? 'open' : 'close' }] });\n i++;\n }\n }\n return notes;\n}\n\n/** Marks/labels that are understood but deliberately preserved raw-only. */\nconst KNOWN_RAW_RE = [\n /^[wxyjEJ$<>=_]+$/, // arc & line drawing segments\n /^\\|+$/, // thin yugal-dari stop mark\n /^[0-9!@#]{1,2}[fF]?:?$/, // beat-number labels incl. 10–16 (sam tick = f/F, e.g. 1f / 1F / 2:)\n /^[oOe`+,.;:iI~^*bcBCWXYFHZz'\"?]$/, // dots, ticks, duration marks, legacy forms\n];\n\nconst OPEN_BRACKETS: Record<string, 'repeat' | 'skip' | 'alt'> = {\n '{': 'repeat',\n '(': 'skip',\n '[': 'alt',\n};\nconst CLOSE_BRACKETS: Record<string, 'repeat' | 'skip' | 'alt'> = {\n '}': 'repeat',\n ')': 'skip',\n ']': 'alt',\n};\n\nfunction octaveOf(mark: string | undefined): Octave {\n if (mark === 'f' || mark === 'F') return 'taar';\n if (mark === 'h' || mark === 'H') return 'mandra';\n return 'madhyam';\n}\n\n/**\n * Body grammar of one chunk (brackets already peeled):\n *\n * [beat-digit] ['-'] [KAN] unit* ['a'] [fh] [i:] [KAN] [beat-digit]\n *\n * where unit = letter [fh] and KAN = uppercase letter [fFhH]. Corpus\n * realities beyond the canonical `[-]KAN unit+ a` shape:\n * - octave mark typed after the আ-কার: `saf` ≡ `sfa` (taar sa) — the reph\n * applies to the last unit;\n * - trailing `i` (two stacked rings, ঃ-shaped) or `:` (two lozenges — a\n * different glyph) after the matra: a **matra sign worth ½**, the আ-কার's\n * half-brother (legend `রাঃ` = 1½, `সঃ` = ½; corpus rows fit their taal\n * cycle 114:19 in favour of that reading over \"articulation only\"). The\n * durations below still ignore it — they split the cell evenly among its\n * units, so `qinqi` decodes ⅓⅓⅓ where the sheet says ½ ¼ ¼. The viewer\n * reads the marks off `raw` and draws them right (viewer/render.ts\n * `rawMarks`); playback is what the even split still gets wrong;\n * - trailing KAN (`-aR`): an anticipatory grace drawn at the cell's right\n * edge, leading into the next note — attached to this cell's last note;\n * - the cut mark may also lead or sit between units (`-iqi`, `mpimi`);\n * - leading `z` = blank spacer glyph (empty outline in the font) — skipped.\n * A standalone detached `a` (no hyphen) is a 1-matra rest per the legend\n * (\"হাইফেন-বর্জিত … বিরামের মাত্রা\").\n */\nconst BODY_RE =\n /^([0-9!@][fF]?)?([zj]*)(-)?([i:])?(?:([SRGMPQNDTKUV])([fFhH])?)?((?:[srgmpqndtkuv][fh]?[i:]?)+)?(a)?([fh])?([i:])?(?:([SRGMPQNDTKUV])([fFhH])?)?([0-9!@][fF]?)?(-)?$/;\n\nfunction decodeChunk(chunk: string): { notes: Note[]; kind: 'decoded' | 'known' | 'unknown' } {\n // 1. Peel brackets.\n const opens: ('repeat' | 'skip' | 'alt')[] = [];\n const closes: ('repeat' | 'skip' | 'alt')[] = [];\n let body = chunk;\n while (body.length > 0) {\n const kind = OPEN_BRACKETS[body[0]!];\n if (kind === undefined) break;\n opens.push(kind);\n body = body.slice(1);\n }\n while (body.length > 0) {\n const kind = CLOSE_BRACKETS[body[body.length - 1]!];\n if (kind === undefined) break;\n closes.unshift(kind);\n body = body.slice(0, -1);\n }\n\n const finish = (notes: Note[], kind: 'decoded' | 'known' | 'unknown') => {\n if (notes.length === 0) notes.push({});\n const first = notes[0]!;\n const last = notes[notes.length - 1]!;\n if (opens.length > 0) first.brackets = [...opens.map((kind_) => ({ kind: kind_, edge: 'open' as const })), ...(first.brackets ?? [])];\n if (closes.length > 0) last.brackets = [...(last.brackets ?? []), ...closes.map((kind_) => ({ kind: kind_, edge: 'close' as const }))];\n return { notes, kind };\n };\n\n // 2. Bracket-only chunk → raw carrier for the bracket edges.\n if (body === '') return finish([{}], 'decoded');\n\n // 3. Bar/bracket runs, then the remaining standalone structurals.\n const barRun = decodeBarRun(body);\n if (barRun) return finish(barRun, 'decoded');\n const structural = STRUCTURALS[body];\n if (structural) return finish([structural()], 'decoded');\n\n // 4. Known raw marks.\n if (KNOWN_RAW_RE.some((re) => re.test(body))) return finish([{}], 'known');\n\n // 5. Note grammar.\n const m = body.match(BODY_RE);\n if (m) {\n const [, , , hyphen, , kanLetter, kanOct, unitsStr, aakar, postOct, , trailKan, trailKanOct] = m;\n const attachKan = (note: Note, letter: string, oct: string | undefined) => {\n const def = LETTERS[letter.toLowerCase()]!;\n // NOTE: the spec kan is a plain [octave, letter] tuple, so a komal\n // kan letter (e.g. D = small দ) is projected onto its shuddha\n // letter; the exact glyph stays recoverable from `raw`.\n note.kan = [octaveOf(oct?.toLowerCase()), def.letter] as Svara;\n };\n if (unitsStr) {\n const units = unitsStr.match(/[srgmpqndtkuv][fh]?/g) ?? [];\n const notes: Note[] = units.map((unit) => {\n const def = LETTERS[unit[0]!]!;\n const note: Note = { svara: [octaveOf(unit[1]), def.letter] as Svara };\n if (def.komal) note.komal = true;\n if (def.tivra) note.tivra = true;\n if (units.length > 1) note.durationMatra = 1 / units.length;\n return note;\n });\n const last = notes[notes.length - 1]!;\n // Post-আকার octave mark (`saf`): applies to the last unit unless it\n // already carries its own mark.\n if (postOct && last.svara![0] === 'madhyam') {\n last.svara = [octaveOf(postOct), last.svara![1]] as Svara;\n }\n if (hyphen) notes[0]!.sustain = true;\n if (kanLetter) attachKan(notes[0]!, kanLetter, kanOct);\n if (trailKan && last.kan === undefined) attachKan(last, trailKan, trailKanOct);\n return finish(notes, 'decoded');\n }\n if (aakar) {\n // '-a' = sustain (hold previous pitch, no new attack);\n // bare detached 'a' = one-matra rest (legend: hyphen-less matra sign).\n const note: Note = hyphen ? { sustain: true } : { rest: true };\n if (trailKan) attachKan(note, trailKan, trailKanOct);\n else if (kanLetter) attachKan(note, kanLetter, kanOct);\n return finish([note], 'decoded');\n }\n if (hyphen && !kanLetter && !trailKan) {\n // A bare continuation dash (`-`, `-i`) — the আ-কার is implied.\n return finish([{ sustain: true }], 'decoded');\n }\n // Kan without units, or digit-edges with no note between — keep raw.\n }\n\n return finish([{}], 'unknown');\n}\n\n/**\n * Decode one cell's text. Multi-chunk cells (whitespace-separated) emit\n * notes in order; the first note of each chunk carries that chunk's source\n * text in `raw`, so joining a cell's `raw` values with spaces reproduces\n * the normalized cell text (the lossless property tests rely on this).\n */\nexport function decodeCell(text: string): CellDecode {\n const chunks = text.split(/\\s+/).filter((c) => c.length > 0);\n const out: CellDecode = { notes: [], unknownTokens: [], knownRawTokens: [], decoded: false };\n for (const chunk of chunks) {\n const { notes, kind } = decodeChunk(chunk);\n notes[0]!.raw = chunk;\n if (kind === 'decoded') out.decoded = true;\n else if (kind === 'known') out.knownRawTokens.push(chunk);\n else out.unknownTokens.push(chunk);\n out.notes.push(...notes);\n }\n return out;\n}\n","/**\n * The order a swaralipi is **sung** in, as opposed to the order it is written.\n * Swarabitan's legend (স্বরবিতান pp. ১৩৫–১৩৬, gitabitan.io/bn/swaralipi/how-to-read/):\n *\n * - `{ }` is sung twice; `( )` inside it is left out the second time, and the\n * `[ ]` notes written above stand in for the notes under them.\n * - II at a kali's end sends the singer back to the asthayi's opening II, on\n * to the ‖ stop mark, then into the next kali: D.S. al Fine, with ‖ as the\n * Fine. I[ ]I / II[ ]II make that return sing the `[ ]` notes.\n * - IIII written as one stroke group ends the song: no return.\n *\n * The notation is written for this order, so every jump lands where the grid\n * expects it: the \"৹ ৹ ৹\" after a kali-end II is the rest of the cycle the ‖\n * broke off, which is what keeps a looping tabla on sam. Whatever the marks\n * leave unsaid (no ‖, a stray bracket) is sung as written.\n */\nimport { decodeCell } from '../convert/codec.js';\nimport type { Bracket, Note, Swaralipi } from '../spec/schema.js';\n\n/** One note as sung: where it is written (for highlights) and what sounds. */\nexport interface Visit {\n p: number;\n r: number;\n i: number;\n /** The written note, or a `[ ]` note standing in for it on a repeat. */\n note: Note;\n}\n\n/**\n * A raw the codec could not decode but which still **holds a matra** in the\n * source grid: it carries svara letters or the আ-কার carrier `a` (e.g. a\n * mistyped `` `-a `` / `frsfa` / `PUda`). Bracket, bar-glyph and beat-label\n * carriers contain none of these, so they stay timeless. Dropping these\n * columns outright ran the melody ahead of the তাল from that point on.\n */\nconst UNDECODED_CELL = /[srgmpqnvtduka]/i;\n\n/** A column that produces no sound and no time advance (bar, bracket-only,\n * carrier, structural raw). Mirrors the viewer's non-pitched, non-rest\n * classes. */\nexport const isSilent = (n: Note): boolean =>\n n.svara === undefined &&\n n.rest !== true &&\n n.sustain !== true &&\n !(n.raw !== undefined && UNDECODED_CELL.test(n.raw));\n\n/** ‖ written above a note: অবসানের চিহ্ন, where a return to the asthayi stops. */\nconst STOP_MARK = /^\\|+$/;\nconst EPS = 1e-6;\n\ninterface Token extends Visit {\n timed: boolean;\n}\n\nconst edges = (n: Note, kind: Bracket['kind'], edge: Bracket['edge']): number =>\n n.brackets?.filter((b) => b.kind === kind && b.edge === edge).length ?? 0;\nconst sounds = (n: Note): boolean => n.svara !== undefined || n.rest === true || n.sustain === true;\nconst matra = (notes: Note[]): number => notes.reduce((sum, n) => sum + (n.durationMatra ?? 1), 0);\n\n/** Every note of `doc` in the order it is sung. */\nexport function playOrder(doc: Swaralipi): Visit[] {\n const tokens: Token[] = [];\n doc.parts.forEach((part, p) =>\n part.rows.forEach((row, r) =>\n row.notes.forEach((note, i) => tokens.push({ p, r, i, note, timed: note.bar === undefined && !isSilent(note) })),\n ),\n );\n const { asthayi, stop, returns } = form(tokens);\n const changed = changedNotes(tokens);\n const out: Visit[] = [];\n\n /** Sing tokens lo..hi-1: each `{ }` twice, its `( )` only the first time. */\n const sing = (lo: number, hi: number, useChanged: boolean): void => {\n const repeats: { open: number; again: boolean }[] = [];\n // Matra of written notes a longer `[ ]` note already sang over.\n let owed = 0;\n for (let k = lo; k < hi; ) {\n const t = tokens[k]!;\n if (edges(t.note, 'repeat', 'open') > 0 && repeats.at(-1)?.open !== k) repeats.push({ open: k, again: false });\n const again = repeats.at(-1)?.again === true;\n const skipTo = again && edges(t.note, 'skip', 'open') > 0 ? skipEnd(tokens, k, hi) : -1;\n if (skipTo >= 0) {\n if (edges(tokens[skipTo]!.note, 'repeat', 'close') > 0) repeats.pop();\n k = skipTo + 1;\n owed = 0;\n continue;\n }\n if (owed > EPS && t.timed) owed -= matra([t.note]);\n else {\n const sub = useChanged || again ? changed.get(k) : undefined;\n // A `[ ]` note shorter than the one it replaces would pull the melody off sam.\n const fits = sub !== undefined && matra(sub) >= matra([t.note]) - EPS;\n for (const note of fits ? sub : [t.note]) out.push({ p: t.p, r: t.r, i: t.i, note });\n owed = fits ? matra(sub) - matra([t.note]) : 0;\n }\n const loop = edges(t.note, 'repeat', 'close') > 0 ? repeats.at(-1) : undefined;\n if (loop !== undefined && !loop.again) {\n loop.again = true;\n k = loop.open;\n owed = 0;\n continue;\n }\n if (loop !== undefined) repeats.pop();\n k++;\n }\n };\n\n let from = 0;\n for (const ret of returns) {\n sing(from, ret.resume, false);\n sing(asthayi, stop + 1, ret.changed);\n from = ret.resume;\n }\n sing(from, tokens.length, false);\n return out;\n}\n\n/**\n * The song's form: where the asthayi starts (its opening II, else the top),\n * where a return stops (the first ‖ in the asthayi), and the token after each\n * kali-end II or I[ ]I. No ‖ → no returns: the notation then does not say how\n * far back to sing.\n */\nfunction form(tokens: Token[]): { asthayi: number; stop: number; returns: { resume: number; changed: boolean }[] } {\n // A II opens a kali when its row's singing comes after it, and closes one\n // when the singing comes before; mid-row, it alternates with the last II.\n const first = new Map<string, number>();\n const last = new Map<string, number>();\n tokens.forEach((t, k) => {\n if (!t.timed) return;\n const row = `${t.p}.${t.r}`;\n if (!first.has(row)) first.set(row, k);\n last.set(row, k);\n });\n const opens: number[] = [];\n let opening = false;\n tokens.forEach((t, k) => {\n if (t.note.bar !== 'double') return;\n const row = `${t.p}.${t.r}`;\n const before = (first.get(row) ?? Infinity) < k;\n const after = (last.get(row) ?? -1) > k;\n opening = before !== after ? after : !opening;\n if (opening) opens.push(k);\n });\n\n // A kali ends on a closing II, or on I[ ]I / II[ ]II (an empty `[ ]` among\n // the bars); a run of bars holding IIII ends the song instead.\n const returns: { resume: number; changed: boolean }[] = [];\n for (let k = 0; k < tokens.length; k++) {\n let at = -1;\n let open = false;\n let changed = false;\n let end = false;\n for (; k < tokens.length && !tokens[k]!.timed; k++) {\n const n = tokens[k]!.note;\n if (n.bar === 'quad') end = true;\n if (n.bar === 'double' && !opens.includes(k)) at = k;\n if (edges(n, 'alt', 'open') > 0) open = true;\n if (open && edges(n, 'alt', 'close') > 0) {\n at = k;\n changed = true;\n }\n }\n if (at >= 0 && !end) returns.push({ resume: at + 1, changed });\n }\n\n const top = opens[0];\n const asthayi = top !== undefined && top < (returns[0]?.resume ?? Infinity) ? top : 0;\n // The asthayi ends at its own closing II, or where the next kali opens. A ‖\n // with nothing sung after it is the song's own end (\"এইখানে একেবারে থামিবে\"),\n // not where a return stops.\n const asthayiEnd = Math.min(returns[0]?.resume ?? Infinity, opens.find((k) => k > asthayi) ?? Infinity, tokens.length);\n const lastSung = tokens.reduce((last, t, k) => (t.timed ? k : last), -1);\n const stop = tokens.findIndex(\n (t, k) =>\n k >= asthayi && k < asthayiEnd && k < lastSung && t.note.above?.some((a) => STOP_MARK.test(a.raw ?? '')) === true,\n );\n if (stop < 0) return { asthayi, stop, returns: [] };\n // A ‖ right at the asthayi's own close was just sung: there the singer\n // \"stops and takes up another kali\", not the whole asthayi again.\n const atClose = returns[0]?.resume === asthayiEnd && !tokens.slice(stop + 1, asthayiEnd).some((t) => t.timed);\n return { asthayi, stop, returns: atClose ? returns.slice(1) : returns };\n}\n\n/**\n * The `[ ]` notes written above each column, by token: what is sung there on\n * a repeat. A span runs from the above-row `[` to its `]`; a column under it\n * with nothing above keeps its own note.\n */\nfunction changedNotes(tokens: Token[]): Map<number, Note[]> {\n const out = new Map<number, Note[]>();\n let row = '';\n let inside = false;\n tokens.forEach((t, k) => {\n // ponytail: a span is closed at the row's end — no corpus span crosses a row.\n if (row !== `${t.p}.${t.r}`) {\n row = `${t.p}.${t.r}`;\n inside = false;\n }\n const notes: Note[] = [];\n for (const above of t.note.above ?? []) {\n // An older converter left a few cells like `[sfa]` undecoded: read them as it now would.\n const read = above.raw !== undefined && !sounds(above) && above.brackets === undefined;\n for (const a of read ? decodeCell(above.raw!).notes : [above]) {\n if (edges(a, 'alt', 'open') > 0) inside = true;\n if (inside && sounds(a)) notes.push(a);\n if (edges(a, 'alt', 'close') > 0) inside = false;\n }\n }\n if (notes.length > 0) out.set(k, notes);\n });\n return out;\n}\n\n/** The token closing the `( )` that opens at `k`, or -1 if it never closes. */\nfunction skipEnd(tokens: Token[], k: number, hi: number): number {\n for (let depth = 0, j = k; j < hi; j++) {\n depth += edges(tokens[j]!.note, 'skip', 'open') - edges(tokens[j]!.note, 'skip', 'close');\n if (depth <= 0) return j;\n }\n return -1;\n}\n","/**\n * Pure spec-JSON → HTML renderer. No DOM, no side effects: usable for SSR\n * (Astro/static sites emit `renderToHtml(doc)` next to a\n * `<style>${SWARALIPI_CSS}</style>`) and unit-testable in plain Node.\n *\n * Layout model: NLTR emits a whole song as ONE html table whose every row has\n * the same column count, which is why its lines align down the page like the\n * printed স্বরবিতান. We reproduce that: the document is one CSS grid, each\n * `Row` is a `subgrid` child of it, and **one column = one cell** (a matra\n * group / bar / carrier — see groupRowIntoCells), so rows are commensurable.\n * Four fixed-height grid rows per row: above-annotations / notation / below\n * (slur arcs, marks) / lyric. A cell's sub-notes are set tight as one word\n * and its syllables likewise, both centred on the column — NLTR's and the\n * print's setting (রসা over ধা৹); `data-note` stays on the per-note span, so\n * P2.3's highlight targets are unchanged.\n *\n * Column *offsets* (the anacrusis that NLTR right-aligns into the সম) are\n * re-derived from the document alone — see alignRows.\n *\n * Rendering is spec-driven (semantics, not `raw`): grouping derives from\n * `durationMatra` accumulation so hand-authored documents without `raw`\n * render identically. `raw` is consulted only for (a) raw-only fallback\n * notes (never dropped — dimmed, in Swarabitan when loaded), (b) beat\n * labels, and (c) the অর্ধমাত্রা/ছেদ marks and the আ-কার, which only the\n * source cell can place (see rawMarks + codec.ts).\n */\nimport { isArcRaw } from '../player/schedule.js';\nimport { graceNotes } from '../spec/grace.js';\nimport type { Lay } from '../spec/lay.js';\nimport { isTaalFerta, sameTaal } from '../spec/taals.js';\nimport type { Meta, Note, Row, Swaralipi, Taal } from '../spec/index.js';\nimport {\n composeCluster,\n FREE_TAAL_LABELS,\n LABELS,\n LAY_LABELS,\n localizeDigits,\n MARKS,\n type GridLang,\n type LangMarks,\n type ViewerLang,\n} from './glyphs.js';\n\nexport interface RenderOptions {\n /** Notation + UI language. Default `bn`. */\n lang?: ViewerLang;\n /** Render the NLTR-style নাম/তাল/আবর্তন header block. Default true. */\n showHeader?: boolean;\n /**\n * Lyric/title transliterator for `hi`/`en` (see loadLyricTransliterator).\n * Without it, non-bn renders keep Bengali lyrics (graceful interim).\n */\n transliterate?: (bengaliText: string) => string;\n}\n\nconst EPS = 1e-6;\n\nconst isIntegral = (x: number) => Math.abs(x - Math.round(x)) < EPS;\n\nfunction escapeHtml(s: string): string {\n return s\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"');\n}\n\n/* ------------------------------------------------------------------ */\n/* Cell grouping */\n/* ------------------------------------------------------------------ */\n\nexport interface Cell {\n kind: 'bar' | 'group' | 'raw' | 'carrier';\n /** Index of the cell's first note within the row's notes array. */\n start: number;\n notes: Note[];\n}\n\nconst isPitched = (n: Note) => n.svara !== undefined || n.rest === true || n.sustain === true;\n\n/**\n * The raw text a raw-only note should display, or undefined when there is\n * nothing to show beyond what semantics already render (a bracket-only\n * chunk's raw is fully expressed by its bracket glyphs).\n */\nfunction rawDisplay(note: Note): string | undefined {\n if (note.raw === undefined) return undefined;\n if ((note.brackets?.length ?? 0) > 0 && /^[{}()[\\]]*$/.test(note.raw)) return undefined;\n return note.raw;\n}\n\n/**\n * Group a row's notes into rendered cells using a fractional-duration\n * accumulator (raw-independent — works for hand-authored docs):\n * - bar / raw-only / carrier notes force-close and form singleton cells;\n * - full-matra notes are singleton groups;\n * - fractional notes accumulate until the sum reaches an integer matra\n * boundary (epsilon for 1/3, 0.2 chains), then the group closes;\n * - `halfMatra` (the অর্ধমাত্রা ঃ) closes the cell on a half boundary — the\n * only case durations alone cannot resolve (`সঃ গঃ` vs `সরা`).\n * The converter emits k notes × 1/k per source cell, so groups coincide\n * with source cells; an incomplete trailing group still closes at row end\n * (the matra carrier lands on its last note).\n *\n * Adjacent bar/carrier cells are finally merged, because NLTR types them as\n * ONE table cell: the song-end `L L` (‖ ‖) and the asthayi-return `l [ ] l`\n * each occupy a single column, not two or four.\n */\nexport function groupRowIntoCells(notes: Note[]): Cell[] {\n const cells: Cell[] = [];\n let cur: Cell | undefined;\n let acc = 0;\n const close = () => {\n if (cur) {\n cells.push(cur);\n cur = undefined;\n }\n acc = 0;\n };\n notes.forEach((note, i) => {\n if (note.bar !== undefined) {\n close();\n cells.push({ kind: 'bar', start: i, notes: [note] });\n return;\n }\n if (!isPitched(note)) {\n close();\n cells.push({ kind: rawDisplay(note) !== undefined ? 'raw' : 'carrier', start: i, notes: [note] });\n return;\n }\n const d = note.durationMatra ?? 1;\n if (isIntegral(d) && note.halfMatra !== true) {\n close();\n cells.push({ kind: 'group', start: i, notes: [note] });\n return;\n }\n cur ??= { kind: 'group', start: i, notes: [] };\n cur.notes.push(note);\n acc += d;\n if (note.halfMatra === true || (acc > EPS && isIntegral(acc))) close();\n });\n close();\n return mergeStructural(absorbBrackets(cells));\n}\n\nconst isStructural = (c: Cell) => c.kind === 'bar' || c.kind === 'carrier';\n\n/** A carrier holding nothing but bracket edges — NLTR types those *inside*\n * the note's own cell (`{ma`, `ma}`); the converter only splits them out when\n * the source separated them with whitespace. */\nfunction bracketEdges(cell: Cell): { open: boolean; close: boolean } | undefined {\n if (cell.kind !== 'carrier') return undefined;\n let open = false;\n let close = false;\n for (const note of cell.notes) {\n if (note.raw !== undefined && !/^[{}()[\\]\\s]*$/.test(note.raw)) return undefined;\n for (const b of note.brackets ?? []) {\n if (b.edge === 'open') open = true;\n else close = true;\n }\n }\n return open || close ? { open, close } : undefined;\n}\n\n/**\n * Fold a bracket-only carrier into the matra it belongs to: an opening edge\n * joins the following group, a closing edge the preceding one. Without this a\n * `{` steals a column of its own and slides the whole rest of the row — and its\n * syllable with it (4295 such notes across 673 of the 1738 NLTR songs). A\n * carrier holding both edges is the `[]` alt marker, which does own a column.\n */\nfunction absorbBrackets(cells: Cell[]): Cell[] {\n const out: Cell[] = [];\n for (let i = 0; i < cells.length; i++) {\n const cell = cells[i]!;\n const edges = bracketEdges(cell);\n if (edges !== undefined && edges.open !== edges.close) {\n const prev = out[out.length - 1];\n const next = cells[i + 1];\n if (edges.close && prev?.kind === 'group') {\n prev.notes = [...prev.notes, ...cell.notes];\n continue;\n }\n if (edges.open && next?.kind === 'group') {\n next.notes = [...cell.notes, ...next.notes];\n next.start = cell.start;\n continue;\n }\n }\n out.push(cell);\n }\n return out;\n}\n\nfunction mergeStructural(cells: Cell[]): Cell[] {\n const out: Cell[] = [];\n for (const cell of cells) {\n const prev = out[out.length - 1];\n if (prev !== undefined && isStructural(prev) && isStructural(cell)) {\n prev.notes = [...prev.notes, ...cell.notes];\n if (cell.kind === 'bar') prev.kind = 'bar';\n } else out.push(cell);\n }\n return out;\n}\n\n/* ------------------------------------------------------------------ */\n/* Row alignment (reconstructing NLTR's shared column grid) */\n/* ------------------------------------------------------------------ */\n\nexport interface Layout {\n /** Total columns the document's grid needs. */\n width: number;\n /** Column offset of each row, in document order. */\n offsets: number[];\n}\n\n/** Bars that end a section — the row after one starts a fresh phrase. */\nconst SECTION_BARS: ReadonlySet<string> = new Set(['double', 'quad']);\n\nconst isBarCell = (cell: Cell | undefined) => cell?.kind === 'bar';\nconst endsSection = (cell: Cell | undefined) =>\n isBarCell(cell) && SECTION_BARS.has(cell!.notes[cell!.notes.length - 1]!.bar!);\n\n/**\n * Give every row of a document its column offset, so all rows share one set\n * of grid tracks (NLTR's single-table layout, re-derived from the spec JSON\n * — the source column index is not stored).\n *\n * A full line is `W` cells wide (the modal width of rows that open on a bar).\n * A shorter row is right-aligned into the সম only when it *starts* a phrase —\n * it opens without a bar, or it is the first row, or the previous row closed\n * a section (‖). A short row that merely finishes one stays flush left. A row\n * without its own closing bar leaves that last column empty, so it ends one\n * column earlier.\n *\n * Measured against all 1738 NLTR pages: 99.1 % of rows and 99.4 % of cells\n * land on the source's exact column. The residual is source defects — rows\n * where NLTR itself skips a column — which this packs flush instead.\n */\nexport function alignRows(rows: Cell[][]): Layout {\n const counts = new Map<number, number>();\n for (const cells of rows)\n if (isBarCell(cells[0])) counts.set(cells.length, (counts.get(cells.length) ?? 0) + 1);\n\n let width = 0;\n let best = 0;\n for (const [len, n] of counts)\n if (n > best || (n === best && len > width)) {\n width = len;\n best = n;\n }\n // No row opens on a bar (hand-authored docs often don't): the widest row is the line.\n if (width === 0) for (const cells of rows) width = Math.max(width, cells.length);\n\n const offsets = rows.map((cells, i) => {\n if (cells.length === 0 || cells.length >= width) return 0;\n const prev = rows[i - 1];\n const phraseStart = !isBarCell(cells[0]) || i === 0 || endsSection(prev?.[prev.length - 1]);\n if (!phraseStart) return 0;\n return Math.max(0, width - cells.length - (isBarCell(cells[cells.length - 1]) ? 0 : 1));\n });\n\n rows.forEach((cells, i) => {\n width = Math.max(width, offsets[i]! + cells.length);\n });\n return { width, offsets };\n}\n\n/* ------------------------------------------------------------------ */\n/* Arc (slur) resolution */\n/* ------------------------------------------------------------------ */\n\nexport interface Arc {\n /** 0-based index of the arc's first / last **cell** within the row. */\n start: number;\n end: number;\n /** Index, within that cell's notes, of the note the arc hangs from / into. */\n startNote: number;\n endNote: number;\n /** True when the matching end lies on a previous / following system. */\n openLeft: boolean;\n openRight: boolean;\n /** Fill-segments-only row: render a straight underline, no curled ends. */\n line?: boolean;\n}\n\n/**\n * Resolve under-arcs for one row down to the **note** each end hangs from, so a\n * slur inside one half-matra cell (মজ্ঞা) still runs centre to centre. Sources,\n * scanned left→right:\n * - spec `meend: 'start' | 'end'` — exact notes;\n * - below-annotation raws, which belong to the whole cell (NLTR types them\n * centred under the column): `w` opens on the cell's first sounded note,\n * `x` closes on its last, `$` (Swarabitan's short in-cell arc) runs first to\n * last, and `xw` — close, then re-open — meets in the middle instead.\n * Unmatched `x` → arc from cell 0 with a squared-off (open) left end;\n * unclosed `w` → arc to the last cell with an open right end — both match\n * the print's behavior when an arc continues across a system wrap.\n * A row with fill segments but no ends at all renders one straight line.\n */\nexport function resolveArcs(cells: Cell[]): Arc[] {\n const arcs: Arc[] = [];\n let open: { cell: number; note: number } | undefined;\n let sawEnds = false;\n const fillCells: number[] = [];\n\n const openAt = (cell: number, note: number) => {\n sawEnds = true;\n open ??= { cell, note };\n };\n const closeAt = (cell: number, note: number) => {\n sawEnds = true;\n const from = open ?? { cell: 0, note: 0 };\n arcs.push({\n start: from.cell,\n startNote: from.note,\n end: cell,\n endNote: note,\n openLeft: open === undefined,\n openRight: false,\n });\n open = undefined;\n };\n\n cells.forEach((cell, i) => {\n const pitched = cell.notes.flatMap((n, j) => (isPitched(n) ? [j] : []));\n const first = pitched[0] ?? 0;\n const last = pitched[pitched.length - 1] ?? cell.notes.length - 1;\n let marks = '';\n cell.notes.forEach((note, j) => {\n if (note.meend === 'end' || note.meend === 'both') closeAt(i, j);\n if (note.meend === 'start' || note.meend === 'both') openAt(i, j);\n for (const b of note.below ?? []) if (isArcRaw(b.raw)) marks += b.raw;\n });\n const reopens = /[xX].*[wW]/.test(marks);\n for (const ch of marks) {\n if (ch === 'w' || ch === 'W') openAt(i, reopens ? last : first);\n else if (ch === 'x' || ch === 'X') closeAt(i, reopens ? first : last);\n else if (ch === '$') {\n openAt(i, first);\n closeAt(i, last);\n } else fillCells.push(i);\n }\n });\n\n const lastCell = Math.max(cells.length - 1, 0);\n const lastNote = (c: number) => Math.max((cells[c]?.notes.length ?? 1) - 1, 0);\n if (open !== undefined) {\n arcs.push({\n start: open.cell,\n startNote: open.note,\n end: lastCell,\n endNote: lastNote(lastCell),\n openLeft: false,\n openRight: true,\n });\n } else if (!sawEnds && fillCells.length > 0) {\n const end = Math.max(...fillCells);\n arcs.push({\n start: Math.min(...fillCells),\n startNote: 0,\n end,\n endNote: lastNote(end),\n openLeft: true,\n openRight: true,\n line: true,\n });\n }\n return arcs;\n}\n\n/**\n * Which notes draw each arc and which cells clip it (styles.ts). An end hangs\n * Swarabitan's hook from its note's centre and runs the flat toward the other\n * end: `sw-mo` opens, `sw-mc` closes, both cut by their cell's `sw-mk` clip at\n * the mid-gap, where the next cell's run carries on. Inside one cell there is\n * no gap to cut at, so `-b` runs stop at their own note's edge and `-s` pairs\n * share one note. A cell the arc only passes under draws one `sw-mm` fill run,\n * a note between two ends in one cell a `sw-mf`.\n */\nfunction arcInk(cells: Cell[], arcs: Arc[]): { cells: string[]; notes: string[][] } {\n const ink = { cells: cells.map(() => ''), notes: cells.map((c) => c.notes.map(() => '')) };\n const mark = (c: number, j: number, cls: string, clip = false) => {\n ink.notes[c]![j] += ` ${cls}`;\n if (clip && !ink.cells[c]!.includes(' sw-mk')) ink.cells[c] += ' sw-mk';\n };\n for (const arc of arcs) {\n const { start: s, end: e, startNote: j, endNote: k } = arc;\n const hookL = arc.line !== true && !arc.openLeft;\n const hookR = arc.line !== true && !arc.openRight;\n if (s === e && hookL && hookR) {\n if (j === k) {\n mark(s, j, 'sw-mos');\n mark(s, j, 'sw-mcs');\n } else {\n mark(s, j, 'sw-mob');\n for (let n = j + 1; n < k; n++) mark(s, n, 'sw-mf');\n mark(s, k, 'sw-mcb');\n }\n continue;\n }\n // ponytail: a fill-only line runs mid-gap to mid-gap, not note edge to edge\n for (let c = s; c <= e; c++) {\n if (c === s && hookL) mark(c, j, 'sw-mo', true);\n else if (c === e && hookR) mark(c, k, 'sw-mc', true);\n else mark(c, 0, 'sw-mm', true);\n }\n }\n return ink;\n}\n\n/* ------------------------------------------------------------------ */\n/* Raw-derived marks (codec grammar: src/convert/codec.ts) */\n/* ------------------------------------------------------------------ */\n\n/** Swarabitan letter-units, lowercase only — an uppercase letter is a কণ. */\nconst SVARA_CHAR = /[srgmpqndtkuv]/;\n\ninterface RawMarks {\n /** The source typed a matra sign (`a`); a ঃ-only cell must not grow one. */\n aakar: boolean;\n /** Marks before the first cluster — `-iqi` is -ঃধঃ, not -ধঃঃ. */\n pre: string;\n /** Marks after note j, as typed (`i` and `:` are different Swarabitan\n * glyphs: two open rings vs two filled lozenges). */\n post: string[];\n}\n\n/**\n * Where a decoded cell's অর্ধমাত্রা/ছেদ marks sit and whether its আ-কার is\n * real, both read off `raw` — because that is what the Swarabitan sheet\n * shows. `i`/`:` is a matra sign (legend: `রাঃ` = 1½, `সঃ` = ½), so it lands\n * where it was typed and a cell without an `a` carries no আ-কার: `ipi` is\n * ঃপঃ and `qinqi` is ধঃনধঃ, never the cell-trailing পাঃঃ / ধনধাঃঃ that\n * counting the marks alone produces. Undefined for hand-authored notes (no\n * raw), which keep the spec-driven matra and `halfMatra`.\n */\nfunction rawMarks(raw: string | undefined, count: number): RawMarks | undefined {\n if (raw === undefined) return undefined;\n const marks: RawMarks = { aakar: false, pre: '', post: new Array<string>(count).fill('') };\n // A mark before every letter leads the cluster; one in a letterless chunk\n // (`-i`, `-ai`) trails the hyphen/matra that IS the note.\n const leads = SVARA_CHAR.test(raw);\n let seen = 0;\n for (const ch of raw) {\n if (SVARA_CHAR.test(ch)) seen = Math.min(seen + 1, count);\n else if (ch === 'a') marks.aakar = true;\n else if (ch === 'i' || ch === ':') {\n if (seen > 0) marks.post[seen - 1] += ch;\n else if (leads) marks.pre += ch;\n else marks.post[0] += ch;\n }\n }\n return marks;\n}\n\n/** Beat-number label (above rows): pure digits + optional sam tick. */\nfunction parseBeatLabel(raw: string): { digits: string; sam: boolean } | undefined {\n const m = raw.match(/^([0-9]{1,2})([fF])?:?$/);\n if (!m) return undefined;\n return { digits: m[1]!, sam: m[2] !== undefined };\n}\n\n/* ------------------------------------------------------------------ */\n/* Note / annotation fragments */\n/* ------------------------------------------------------------------ */\n\ninterface Ctx {\n lang: GridLang;\n marks: LangMarks;\n tr: (s: string) => string;\n}\n\nconst BRACKET_GLYPHS = {\n open: { repeat: '{', skip: '(', alt: '[' },\n close: { repeat: '}', skip: ')', alt: ']' },\n} as const;\n\nfunction bracketGlyphs(note: Note, edge: 'open' | 'close'): string {\n if (!note.brackets) return '';\n return note.brackets\n .filter((b) => b.edge === edge)\n .map((b) => `<span class=\"sw-br\">${BRACKET_GLYPHS[edge][b.kind]}</span>`)\n .join('');\n}\n\n/** A lone matra glyph: the note's own notation font supplies it — bn = the\n * Swarabitan আ-কার (`a`), hi/en = an en-dash (Bhatkhande has no matra sign).\n * Used for rests (বিরাম = detached matra), আ-কার holds and n>1 durations. */\nfunction matraGlyph(ctx: Ctx): string {\n return ctx.lang === 'bn' ? '<span class=\"sw-cl\">a</span>' : '<span class=\"sw-iso\">–</span>';\n}\n\n/** কণ (before the note) / রেশ (after it): small raised clusters beside the\n * main one — the legend's two mirrored grace marks. A grace may hold several\n * svaras, each with its own komal/tivra/microtone and its own melisma hyphen;\n * they render as one small cluster apiece, in order. */\nfunction renderGrace(grace: Note['kan'], cls: 'sw-kan' | 'sw-resh', ctx: Ctx): string {\n return graceNotes(grace)\n .map((n) => {\n if (n.svara === undefined) return '';\n const [octave, letter] = n.svara;\n const c = composeCluster(letter, {\n komal: n.komal,\n tivra: n.tivra,\n octave,\n withMatra: false,\n lang: ctx.lang,\n });\n const hy = n.sustain === true ? ctx.marks.hyphen : '';\n const micro =\n n.microtone !== undefined\n ? `<span class=\"sw-micro\" title=\"${n.microtone}\">${localizeDigits(n.microtone === 'atikomal' ? '2' : '1', ctx.lang)}</span>`\n : '';\n return `<span class=\"${[cls, ...c.classes].join(' ')}\">${hy}${c.text}</span>${micro}`;\n })\n .join('');\n}\n\ninterface PitchedOpts {\n /** Whole আ-কার matras this (cell-final) note carries: 0 for a bare\n * অর্ধমাত্রা cell, 1 normally, n for an n-matra note. */\n matras: number;\n /** অর্ধমাত্রা/ছেদ marks drawn before this note's cluster / after it, as the\n * source typed them (Swarabitan `i` / `:`). */\n pre: string;\n post: string;\n}\n\n/** অর্ধমাত্রা/ছেদ marks. Swarabitan carries them as real glyphs, so bn types\n * the source keys straight through; Bhatkhande has no such sign, so hi/en get\n * one CSS-drawn pair of rings apiece (styles.ts). */\nfunction cutGlyphs(marks: string, ctx: Ctx): string {\n if (marks === '') return '';\n return ctx.lang === 'bn'\n ? `<span class=\"sw-cl\" title=\"${ctx.marks.cut}\">${marks}</span>`\n : `<span class=\"sw-cut\" title=\"${ctx.marks.cut}\"></span>`.repeat(marks.length);\n}\n\n/**\n * The matra marks a cell's final note carries: its total duration as whole\n * আ-কার matras plus an optional অর্ধমাত্রা ঃ (legend `রাঃ` = 1½, `সঃ` = ½).\n * Only a `halfMatra` cell may show zero matras — every other cell keeps at\n * least one, so an incomplete trailing group still gets its carrier.\n */\nexport function cellMatra(cell: Cell): { matras: number; half: boolean } {\n // Only the pitched notes carry duration — a cell may also hold an absorbed\n // bracket edge, which is a glyph, not a matra.\n const pitched = cell.notes.filter(isPitched);\n const total = pitched.reduce((a, n) => a + (n.durationMatra ?? 1), 0);\n const half = pitched.some((n) => n.halfMatra === true);\n const whole = Math.floor(total + EPS);\n return { matras: half ? whole : Math.max(1, whole), half };\n}\n\n/**\n * Per-note render options for one group cell: the আ-কার lands on the cell's\n * last note, the ঃ marks where the source typed them (`rawMarks`), and a\n * hand-authored `halfMatra` — which has no raw to read — keeps its single\n * cell-trailing mark.\n */\nfunction cellPitchedOpts(cell: Cell): PitchedOpts[] {\n const { matras, half } = cellMatra(cell);\n // Indices of the notes that actually take a matra: an absorbed bracket edge\n // sits in the cell but owns no duration, matra sign or ঃ mark.\n const pitched: number[] = [];\n cell.notes.forEach((n, j) => {\n if (isPitched(n)) pitched.push(j);\n });\n const first = pitched[0];\n const last = pitched[pitched.length - 1];\n const marks = rawMarks(first === undefined ? undefined : cell.notes[first]!.raw, pitched.length);\n const aakars = marks !== undefined && !marks.aakar ? 0 : matras;\n return cell.notes.map((note, j) => {\n if (!isPitched(note)) return { matras: 0, pre: '', post: '' };\n return {\n matras: j === last ? aakars : 0,\n pre: j === first ? (marks?.pre ?? '') : '',\n post: marks !== undefined ? marks.post[pitched.indexOf(j)]! : half && j === last ? 'i' : '',\n };\n });\n}\n\n/**\n * A cell's lyric, split into one slice per *pitched* sub-note. The slices sit\n * side by side as one word centred under the cell's notes, which are one word\n * too — so no syllable can overrun its neighbour or a ৹, however narrow the\n * note above it. An absorbed bracket edge is not a slice — its syllable was\n * typed against the note beside it, so it folds into that note's slice.\n */\nfunction cellLyricSlices(cell: Cell): string[] | undefined {\n if (!cell.notes.some((n) => n.lyric !== undefined)) return undefined;\n const pitched = cell.notes.filter(isPitched);\n if (pitched.length === 0) return cell.notes.map((n) => n.lyric ?? '');\n const slices = new Array<string>(pitched.length).fill('');\n let k = 0;\n for (const note of cell.notes) {\n const at = Math.min(k, pitched.length - 1);\n slices[at] += note.lyric ?? '';\n if (isPitched(note)) k++;\n }\n return slices;\n}\n\n/** Inner HTML of one pitched/sustain/rest note: brackets, kan, melisma\n * hyphen, notation-font cluster, extra matras, cut marks, closing brackets.\n * The font (keyed on lang in styles.ts) renders komal/tivra/octave/matra —\n * composeCluster only picks the ASCII, so there is no Unicode hazard here. */\nfunction renderPitchedInner(note: Note, opts: PitchedOpts, ctx: Ctx): string {\n let inner = bracketGlyphs(note, 'open');\n inner += renderGrace(note.kan, 'sw-kan', ctx);\n if (note.sustain === true) inner += `<span class=\"sw-hy\">${ctx.marks.hyphen}</span>`;\n inner += cutGlyphs(opts.pre, ctx);\n if (note.svara !== undefined) {\n const [octave, letter] = note.svara;\n const c = composeCluster(letter, {\n komal: note.komal,\n tivra: note.tivra,\n octave,\n // The first matra is composed into the cluster itself (bn: the font's\n // trailing `a`); any further ones are separate glyphs below.\n withMatra: opts.matras >= 1,\n lang: ctx.lang,\n });\n inner += `<span class=\"${['sw-cl', ...c.classes].join(' ')}\">${c.text}</span>`;\n } else if (note.rest === true) {\n // বিরাম is *drawn* as a detached matra sign, so it always shows at least\n // one — a sub-matra rest would otherwise be invisible.\n inner += matraGlyph(ctx).repeat(Math.max(1, opts.matras));\n } else if (note.sustain === true) {\n inner += matraGlyph(ctx).repeat(opts.matras);\n }\n if (note.microtone !== undefined) {\n // Legend: অল্পকোমল = superscript ১ after the letter, অতিকোমল = ২.\n const mark = localizeDigits(note.microtone === 'atikomal' ? '2' : '1', ctx.lang);\n inner += `<span class=\"sw-micro\" title=\"${note.microtone}\">${mark}</span>`;\n }\n inner += renderGrace(note.resh, 'sw-resh', ctx);\n if (note.svara !== undefined && opts.matras > 1) {\n inner += matraGlyph(ctx).repeat(opts.matras - 1);\n }\n inner += cutGlyphs(opts.post, ctx);\n inner += bracketGlyphs(note, 'close');\n return inner;\n}\n\n/** Swarabitan glyphs (the .sw-bar font): A = vibhag dari, l = I cycle\n * danda, L = II section pair, song-end = II II. */\nconst BAR_GLYPHS = { dari: 'A', single: 'l', double: 'L', quad: 'LL' } as const;\n\nfunction renderBarInner(note: Note): string {\n return `${bracketGlyphs(note, 'open')}${BAR_GLYPHS[note.bar!]}${bracketGlyphs(note, 'close')}`;\n}\n\n/**\n * Render an annotation note list (above/below content) as inline mini\n * notation: beat labels, stop marks, bars, recursive note groups, raw\n * fallback. Reuses the same grouping as the main row.\n */\nfunction renderAnnotation(notes: Note[], ctx: Ctx): string {\n const parts: string[] = [];\n for (const cell of groupRowIntoCells(notes)) {\n if (cell.kind === 'bar') {\n const note = cell.notes[0]!;\n parts.push(`<span class=\"sw-bar sw-bar--${note.bar}\">${renderBarInner(note)}</span>`);\n continue;\n }\n if (cell.kind === 'group') {\n const opts = cellPitchedOpts(cell);\n cell.notes.forEach((note, j) => {\n parts.push(`<span class=\"sw-n\">${renderPitchedInner(note, opts[j]!, ctx)}</span>`);\n });\n continue;\n }\n const note = cell.notes[0]!;\n const raw = rawDisplay(note);\n if (raw !== undefined) {\n const beat = parseBeatLabel(raw);\n if (beat) {\n parts.push(\n `<span class=\"sw-beat${beat.sam ? ' sw-sam' : ''}\">${localizeDigits(beat.digits, ctx.lang)}</span>`,\n );\n } else if (/^\\|+$/.test(raw)) {\n parts.push(`<span class=\"sw-stop\">${raw}</span>`);\n } else {\n parts.push(`<span class=\"sw-raw\" title=\"${escapeHtml(raw)}\">${escapeHtml(raw)}</span>`);\n }\n continue;\n }\n const brackets = bracketGlyphs(note, 'open') + bracketGlyphs(note, 'close');\n if (brackets !== '') parts.push(`<span class=\"sw-carrier\">${brackets}</span>`);\n }\n return parts.join('');\n}\n\n/** Lyric cell text: the ৹ melisma mark is notation (not language text) —\n * swap it per-lang, transliterating only the linguistic remainder. */\nfunction lyricText(s: string, ctx: Ctx): string {\n return s\n .split('৹')\n .map((part) => (part === '' ? '' : ctx.tr(part)))\n .join(ctx.marks.melisma);\n}\n\n/* ------------------------------------------------------------------ */\n/* Row / header / document */\n/* ------------------------------------------------------------------ */\n\n/** Column 1 is the row-label track, so cell 0 starts at column 2. */\nconst COL_BASE = 2;\n\n/** One note's rendered content, whatever kind of cell it sits in. */\nfunction renderNote(note: Note, kind: Cell['kind'], opts: PitchedOpts | undefined, ctx: Ctx): string {\n if (note.bar !== undefined) return renderBarInner(note);\n if (kind === 'group' && opts !== undefined) return renderPitchedInner(note, opts, ctx);\n const raw = rawDisplay(note);\n return (\n bracketGlyphs(note, 'open') +\n (raw !== undefined ? `<span class=\"sw-raw\" title=\"${escapeHtml(raw)}\">${escapeHtml(raw)}</span>` : '') +\n bracketGlyphs(note, 'close')\n );\n}\n\nfunction renderRow(row: Row, partIdx: number, rowIdx: number, offset: number, ctx: Ctx): string {\n const cells = groupRowIntoCells(row.notes);\n const ink = arcInk(cells, resolveArcs(cells));\n const out: string[] = [];\n if (row.label !== undefined)\n out.push(`<span class=\"sw-label\">${escapeHtml(ctx.tr(row.label))}</span>`);\n\n cells.forEach((cell, ci) => {\n const col = offset + ci + COL_BASE;\n const opts = cell.kind === 'group' ? cellPitchedOpts(cell) : [];\n const barCls = cell.kind === 'bar' ? ' sw-bar-cell' : '';\n\n const notes = cell.notes\n .map((note, j) => {\n const path = `${partIdx}.${rowIdx}.${cell.start + j}`;\n const bar = note.bar !== undefined ? ` sw-bar sw-bar--${note.bar}` : '';\n return `<span class=\"sw-n${bar}${ink.notes[ci]![j]}\" data-note=\"${path}\">${renderNote(note, cell.kind, opts[j], ctx)}</span>`;\n })\n .join('');\n out.push(`<span class=\"sw-cell${barCls}${ink.cells[ci]}\" style=\"grid-column:${col}\">${notes}</span>`);\n\n // One slice per sub-note, empties included, set as one tight word the way\n // NLTR and the print set it (রসা over ধা৹).\n const slices = cellLyricSlices(cell);\n if (slices !== undefined) {\n const html = slices.map((t) => `<span>${escapeHtml(lyricText(t, ctx))}</span>`).join('');\n out.push(`<span class=\"sw-lyr\" style=\"grid-column:${col}\">${html}</span>`);\n }\n\n const above = cell.notes.flatMap((n) => n.above ?? []);\n if (above.length > 0)\n out.push(`<span class=\"sw-above\" style=\"grid-column:${col}\">${renderAnnotation(above, ctx)}</span>`);\n\n const below = cell.notes.flatMap((n) => (n.below ?? []).filter((b) => !isArcRaw(b.raw)));\n if (below.length > 0)\n out.push(`<span class=\"sw-below\" style=\"grid-column:${col}\">${renderAnnotation(below, ctx)}</span>`);\n });\n\n return `<div class=\"sw-row\" data-row=\"${partIdx}.${rowIdx}\">${out.join('')}</div>`;\n}\n\nfunction renderHeader(meta: Meta, ctx: Ctx): string {\n return renderMetaHeader(meta, ctx.lang, ctx.tr);\n}\n\n/**\n * The নাম / তাল / রাগ / আবর্তন / স্বরলিপিকার header block, shared by the\n * akarmatrik grid and the staff view so both show the same metadata (localized\n * labels; values injected pre-localized by the consumer). Exported so the\n * staff renderer can reuse the exact markup + styling.\n */\nexport function renderMetaHeader(\n meta: Meta,\n lang: GridLang,\n tr: (s: string) => string = (s) => s,\n): string {\n const L = LABELS[lang];\n const rows: string[] = [];\n const add = (label: string, value: string) =>\n rows.push(\n `<div class=\"sw-meta-row\"><span class=\"sw-meta-label\">${escapeHtml(label)}</span><span class=\"sw-meta-value\">${escapeHtml(value)}</span></div>`,\n );\n add(L.title, tr(meta.title));\n const taal = meta.taalName ?? meta.taal?.id;\n if (taal !== undefined) add(L.taal, tr(taal));\n if (meta.raag !== undefined) add(L.raag, tr(meta.raag));\n if (meta.avartan !== undefined) add(L.avartan, localizeDigits(String(meta.avartan), lang));\n if (meta.notationBy !== undefined) add(L.notationBy, tr(meta.notationBy));\n return `<header class=\"sw-header\">${rows.join('')}</header>`;\n}\n\n/** Render a complete swaralipi document to an HTML string. Pair with\n * SWARALIPI_CSS (shadow DOM does this automatically; SSR consumers emit a\n * `<style>` themselves). All source text is HTML-escaped. */\nexport function renderToHtml(doc: Swaralipi, opts: RenderOptions = {}): string {\n // Grid renderer handles bn/hi/en; `staff` is async (see renderStaffHtml) and\n // reaches this path only via the print/element wrappers, which fall back to bn.\n const lang: GridLang = opts.lang === 'hi' || opts.lang === 'en' ? opts.lang : 'bn';\n const tr = lang !== 'bn' && opts.transliterate ? opts.transliterate : (s: string) => s;\n const ctx: Ctx = { lang, marks: MARKS[lang], tr };\n\n // One grid for the whole document (NLTR = one table), so every row shares\n // the same tracks. `.sw-part` is `display: contents`, so section headings\n // and rows are all direct children of that grid; rows borrow its columns\n // via `subgrid`, which needs the tracks stated explicitly.\n const layout = alignRows(doc.parts.flatMap((p) => p.rows.map((r) => groupRowIntoCells(r.notes))));\n // max-content (not auto) for the row-label track: an auto track is the one\n // thing grid `justify-content: normal` will stretch, which would swallow all\n // the free space and shove the notation to the right.\n const tracks = `grid-template-columns:max-content repeat(${layout.width},minmax(calc(var(--sw-matra, 1.4em) * var(--sw-tight, 1)),max-content))`;\n\n const out: string[] = [`<div class=\"sw-sheet\" lang=\"${lang}\">`];\n if (opts.showHeader !== false) out.push(renderHeader(doc.meta, ctx));\n out.push(`<div class=\"sw-scroll\"><div class=\"sw-block\" style=\"${tracks}\">`);\n let n = 0;\n // লয়: mark the line where the tempo tier turns over, and only there.\n // ponytail: the `row.lay` field only — a source that *prints* the mark in its\n // own lyric band (NLTR's \"বিলম্বিত লয়:\") already shows it, and suppressing\n // those cells would shift every `data-note` path after them.\n let lay: Lay | undefined;\n // তালফেরতা: same rule — the band only where the taal in force changes. The\n // opening taal is the header's, so a row restating it prints nothing —\n // unless the header reads \"তালফেরতা\", which names no taal: then the first\n // row taal is printed too, as স্বরবিতান heads the song with its first taal.\n let taal: Taal | null | undefined = doc.meta.taal;\n let named = !isTaalFerta(doc.meta.taalName);\n doc.parts.forEach((part, p) => {\n out.push('<section class=\"sw-part\">');\n if (part.name !== undefined)\n out.push(`<h3 class=\"sw-part-name\">${escapeHtml(ctx.tr(part.name))}</h3>`);\n part.rows.forEach((row, r) => {\n // স্বরবিতান prints both as one centred line between systems (\"কাওয়ালি\",\n // \"দ্রুত লয়\"), so a row changing both gets one band, taal first.\n const marks: string[] = [];\n if (row.taal !== undefined && (!named || !sameTaal(row.taal, taal))) {\n taal = row.taal;\n named = true;\n const name = row.taalName ?? (taal === null ? FREE_TAAL_LABELS[ctx.lang] : taal.id);\n marks.push(`<span class=\"sw-taal\" data-taal=\"${escapeHtml(taal?.id ?? 'free')}\">${escapeHtml(ctx.tr(name))}</span>`);\n }\n if (row.lay !== undefined && row.lay !== lay) {\n lay = row.lay;\n marks.push(`<span class=\"sw-lay\" data-lay=\"${lay}\">${escapeHtml(LAY_LABELS[ctx.lang][lay])}</span>`);\n }\n if (marks.length > 0) out.push(`<div class=\"sw-change\">${marks.join('')}</div>`);\n out.push(renderRow(row, p, r, layout.offsets[n++]!, ctx));\n });\n out.push('</section>');\n });\n out.push('</div></div></div>');\n return out.join('');\n}\n","/**\n * Per-language notation encoding for the viewer.\n *\n * Every language renders its notation through a dedicated, purpose-built\n * font whose glyphs ARE the akarmatrik/Bhatkhande marks — so composeCluster\n * emits that font's ASCII encoding and the font does all the hard work\n * (komal/tivra forms, octave reph/dots, matra). This is why the viewer no\n * longer touches Unicode cluster composition at all: the old reph-over-\n * vowel, hasanta-before-matra and dotted-circle hazards simply don't exist\n * when the font supplies precomposed glyphs keyed by plain ASCII.\n *\n * - bn → NLTR's **Swarabitan** (the akarmatrik font this project decodes).\n * Letters s r g m p q n = স র গ ম প ধ ন (q=ধ); komal v t d u = ঋ জ্ঞ দ ণ;\n * tivra ma k = the authentic কড়ি-ম conjunct (ম-based — has NO Unicode\n * form, which is what forced this whole approach); suffix f = taar reph,\n * h = mandra hasanta; trailing a = the আ-কার matra carrier. See codec.ts.\n * - hi/en → **Ome Bhatkhande** Hindi/English (SIL OFL 1.1, © Omenad —\n * github.com/omenad/fonts). Same clean keymap for both: lowercase\n * s r g m p d n = the seven shuddha swaras, uppercase R G M D N = komal\n * Re/Ga, tivra Ma, komal Dha/Ni; octave suffix u/l = taar/mandra dot,\n * U/L = ati (two dots). Bhatkhande has no আ-কার, so no matra is appended.\n *\n * The font is applied by CSS keyed on `.sw-sheet`'s `lang` (see styles.ts);\n * composeCluster only chooses the ASCII. The single residual CSS mark is the\n * bn ati-octave extra dot (Swarabitan's f/h are single reph/hasanta only).\n */\nimport { hasKomal } from '../spec/svara.js';\nimport type { Lay } from '../spec/lay.js';\nimport type { Octave, SvaraLetter } from '../spec/index.js';\n\n/** Akarmatrik/Bhatkhande grid languages, rendered synchronously by renderToHtml. */\nexport type GridLang = 'bn' | 'hi' | 'en';\n\n/** All viewer languages. `staff` = Western staff notation (async, via abcjs). */\nexport type ViewerLang = GridLang | 'staff';\n\n/** bn Swarabitan glyph keys (shuddha / komal / tivra). Missing komal/tivra\n * entries fall back to the shuddha key (those alterations don't occur). */\nconst SWARABITAN_SHUDDHA: Record<SvaraLetter, string> = {\n s: 's', r: 'r', g: 'g', m: 'm', p: 'p', d: 'q', n: 'n', // q = ধ\n};\nconst SWARABITAN_KOMAL: Partial<Record<SvaraLetter, string>> = {\n r: 'v', g: 't', d: 'd', n: 'u', // ঋ জ্ঞ দ ণ\n};\nconst SWARABITAN_TIVRA: Partial<Record<SvaraLetter, string>> = { m: 'k' }; // কড়ি-ম\n\n/** hi/en Ome Bhatkhande octave suffix (u/l single dot, U/L two dots). */\nconst BHATKHANDE_OCTAVE: Record<Octave, string> = {\n madhyam: '',\n taar: 'u',\n mandra: 'l',\n 'ati-taar': 'U',\n 'ati-mandra': 'L',\n};\n\n/** Digits 0-9 in the target script (beat labels, avartan). */\nexport const DIGITS: Record<GridLang, string> = {\n bn: '০১২৩৪৫৬৭৮৯',\n hi: '०१२३४५६७८९',\n en: '0123456789',\n};\n\nexport interface LangMarks {\n /** Melisma / no-new-attack dash before a sustained cluster. */\n hyphen: string;\n /** Lyric continuation mark shown under sustains (the source uses ৹). */\n melisma: string;\n /** ছেদ cut/articulation mark (two stacked rings, ঃ-shaped). */\n cut: string;\n}\n\nexport const MARKS: Record<GridLang, LangMarks> = {\n bn: { hyphen: '-', melisma: '৹', cut: 'ঃ' },\n hi: { hyphen: '-', melisma: '॰', cut: 'ः' },\n en: { hyphen: '-', melisma: '·', cut: ':' },\n};\n\n/** Header labels (NLTR prints নাম / তাল / আবর্তন …). */\nexport const LABELS: Record<\n GridLang,\n { title: string; taal: string; raag: string; avartan: string; notationBy: string }\n> = {\n bn: { title: 'নাম', taal: 'তাল', raag: 'রাগ', avartan: 'আবর্তন', notationBy: 'স্বরলিপিকার' },\n hi: { title: 'नाम', taal: 'ताल', raag: 'राग', avartan: 'आवर्तन', notationBy: 'स्वरलिपिकार' },\n // \"Cycle\", not \"Avartan\": the English sheet is read by people who do not know the word, and\n // one taal cycle is exactly what the number counts.\n en: { title: 'Song', taal: 'Taal', raag: 'Raag', avartan: 'Cycles', notationBy: 'Notator' },\n};\n\n/** লয় tier names, printed where a row changes tempo. bn/hi keep the Indian\n * term; en names the tempo first (a reader of the English sheet may not know\n * the word — the same call `LABELS.en` makes with \"Cycles\" over \"Avartan\"). */\nexport const LAY_LABELS: Record<GridLang, Record<Lay, string>> = {\n bn: { drut: 'দ্রুত লয়', madhya: 'মধ্য লয়', vilambit: 'বিলম্বিত লয়' },\n hi: { drut: 'द्रुत लय', madhya: 'मध्य लय', vilambit: 'विलंबित लय' },\n en: { drut: 'Fast (drut)', madhya: 'Medium (madhya)', vilambit: 'Slow (vilambit)' },\n};\n\n/** Printed where a row switches to free rhythm (`row.taal: null`) with no\n * `taalName` of its own. bn is the converter's canonical মুক্তছন্দ. */\nexport const FREE_TAAL_LABELS: Record<GridLang, string> = {\n bn: 'মুক্তছন্দ',\n hi: 'मुक्तछंद',\n en: 'Free rhythm',\n};\n\n/** The practice surface's words: the sheet's own accessible name (it says\n * what a tap does), a repeat being on, and the learner's turn to sing. */\nexport const PRACTICE_LABELS: Record<GridLang, { sheet: string; repeat: string; turn: string }> = {\n bn: { sheet: 'স্বরলিপি — যে লাইন থেকে শুনতে চান, সেখানে ছুঁয়ে দিন', repeat: 'লাইনটি বারবার বাজবে', turn: 'এবার আপনি গান' },\n hi: { sheet: 'स्वरलिपि — जिस पंक्ति से सुनना हो, उसे छुएँ', repeat: 'पंक्ति दोहराई जा रही है', turn: 'अब आप गाइए' },\n en: { sheet: 'Swaralipi — tap a line to play from it', repeat: 'Repeating the line', turn: 'Your turn — sing' },\n};\n\n/** A composed notation cluster: the font's ASCII text plus any residual CSS\n * classes the font itself cannot express (only the bn ati-octave dot). */\nexport interface Cluster {\n text: string;\n classes: string[];\n}\n\nexport interface ComposeOptions {\n komal?: boolean;\n tivra?: boolean;\n octave: Octave;\n /** Append the আ-কার matra carrier (bn group-final notes only). */\n withMatra: boolean;\n lang: GridLang;\n}\n\n/**\n * Compose one svara into its notation-font ASCII. bn = Swarabitan\n * (letter + f/h octave + a matra); hi/en = Ome Bhatkhande (case-encoded\n * letter + u/l/U/L octave, no matra). The font renders the actual glyph.\n */\nexport function composeCluster(letter: SvaraLetter, opts: ComposeOptions): Cluster {\n const classes: string[] = [];\n\n if (opts.lang === 'bn') {\n let text =\n (opts.tivra && SWARABITAN_TIVRA[letter]) ||\n (opts.komal && SWARABITAN_KOMAL[letter]) ||\n SWARABITAN_SHUDDHA[letter];\n if (opts.octave === 'taar' || opts.octave === 'ati-taar') text += 'f';\n else if (opts.octave === 'mandra' || opts.octave === 'ati-mandra') text += 'h';\n // Swarabitan's f/h are single reph/hasanta; ati adds a CSS extra dot.\n if (opts.octave === 'ati-taar') classes.push('sw-ati-taar');\n if (opts.octave === 'ati-mandra') classes.push('sw-ati-mandra');\n if (opts.withMatra) text += 'a';\n return { text, classes };\n }\n\n // hi / en — Ome Bhatkhande.\n let base: string = letter;\n if (opts.tivra && letter === 'm') base = 'M';\n else if (opts.komal && hasKomal(letter)) base = base.toUpperCase();\n return { text: base + BHATKHANDE_OCTAVE[opts.octave], classes };\n}\n\n/** Map ASCII digits in `s` to the target script's digits. */\nexport function localizeDigits(s: string, lang: GridLang): string {\n const digits = DIGITS[lang];\n return s.replace(/[0-9]/g, (d) => digits[d.charCodeAt(0) - 48]!);\n}\n","/**\n * Fit a sheet's shared grid to the width it has, then layer a user zoom on\n * top.\n *\n * The whole document is one grid (see render.ts), so a sheet has exactly one\n * natural width — a wide তাল overruns a phone or an A4 page. Two levers, in\n * this order, because they cost different things:\n *\n * 1. **Spacing.** `--sw-cell-gap` and the `--sw-matra` column floor are\n * 25–35 % of that natural width (measured over the corpus), and giving\n * them up costs only air between the columns — the alignment is\n * untouched, since every row still borrows the same tracks. Compressed\n * only as far as the container demands, down to `minSpacing`.\n * 2. **Type size.** Everything inside is em-relative, so scaling the sheet's\n * `font-size` scales the notation without disturbing the columns (a\n * `transform` would scale it too, but would also break print\n * pagination). This is what actually makes the glyphs smaller, so it\n * runs second and stops at `minSize` px — past that the block scrolls\n * inside `.sw-scroll` rather than becoming unreadable. It also runs the\n * other way: a sheet narrower than its container grows (to 2x) rather\n * than leaving dead space to the right of every row.\n *\n * `zoom` (default 1) multiplies the fit scale so callers can zoom in past\n * fit-to-width, or below the readability floor deliberately; past that point\n * `.sw-scroll` panning is expected, same as a photo viewer. `minScale` is a\n * second, relative floor used by print, where paper cannot scroll.\n *\n * Self-contained on purpose — print.ts serialises this function into the\n * print page, so it must not close over anything or import anything (the\n * defaults below are literals for the same reason).\n */\nexport function fitSwaralipi(\n root: Document | ShadowRoot | HTMLElement,\n minScale = 0,\n zoom = 1,\n minSpacing = 0.35,\n minSize = 12,\n): void {\n const sheets = root.querySelectorAll<HTMLElement>('.sw-sheet');\n for (const sheet of sheets) {\n const scroll = sheet.querySelector<HTMLElement>('.sw-scroll');\n const block = sheet.querySelector<HTMLElement>('.sw-block');\n if (scroll === null || block === null) continue;\n // Measure unscaled and untightened, so repeated calls converge instead of\n // ratcheting down.\n sheet.style.removeProperty('--sw-size');\n sheet.style.removeProperty('--sw-tight');\n const available = scroll.clientWidth;\n let natural = block.offsetWidth;\n if (available === 0 || natural === 0) continue;\n\n // 1. Tighten the columns, but only as far as the container actually\n // asks: the width grows monotonically with --sw-tight, so binary-search\n // the loosest value that still fits. (A coarse ladder overshot the fit\n // and left the block short of the right edge — the gap this fixes.)\n if (natural > available && minSpacing < 1) {\n let loose = minSpacing;\n let tight = 1;\n for (let i = 0; i < 6; i++) {\n const mid = (loose + tight) / 2;\n sheet.style.setProperty('--sw-tight', String(mid));\n if (block.offsetWidth <= available) loose = mid;\n else tight = mid;\n }\n sheet.style.setProperty('--sw-tight', String(loose));\n natural = block.offsetWidth;\n }\n\n // 2. Scale the type for whatever is left — down to the readability floor\n // (past which .sw-scroll pans), or *up* to fill a container wider than\n // the sheet's natural width, since minSize/minSpacing are floors, not\n // targets. Capped at 2x so a two-column fragment cannot balloon; a\n // reader who wants more zooms (the literal is inline because print.ts\n // serialises this function — it can close over nothing).\n const base = parseFloat(getComputedStyle(sheet).fontSize);\n if (!(base > 0)) continue; // no readable base size (a DOM without layout)\n // (offsetWidth, not scrollWidth: a cell's spacer overhangs half a column gap\n // past the grid, and that clipped ink is not width to fit.)\n // (available - 1: offsetWidth is a rounded integer, so filling it exactly\n // can land a pixel over and raise a phantom scrollbar.)\n let fit = Math.max(minScale, Math.min((available - 1) / natural, 2));\n if (minSize > 0) fit = Math.max(fit, Math.min(1, minSize / base));\n const scale = fit * zoom;\n if (scale === 1) continue;\n sheet.style.setProperty('--sw-size', `${(base * scale).toFixed(3)}px`);\n }\n}\n\n/** Zoom bounds/step for zoomIn()/zoomOut()/the `zoom` property — exported so\n * a consumer's own zoom UI (e.g. a slider) can match the element's clamp. */\nexport const MIN_ZOOM = 0.5;\nexport const MAX_ZOOM = 3;\nexport const ZOOM_STEP = 1.2;\n","/**\n * Encapsulated stylesheet for the viewer. Injected into the\n * `<swaralipi-sheet>` shadow root automatically; SSR consumers emit it\n * themselves: `<style>${SWARALIPI_CSS}</style>` next to `renderToHtml()`.\n *\n * Theming hooks (CSS custom properties, all optional):\n * --sw-loop repeated-line band; --sw-loop-edge its edge, the learner's\n * hollow highlight and \"your turn\" tag (--sw-turn-ink on it)\n * --sw-row-hover hover tint of a tappable line; --sw-focus the focus ring\n * --sw-font font stack (default: Noto Sans Bengali + system Bengali)\n * --sw-size base font size\n * --sw-cell-gap horizontal gap between source cells\n * --sw-tight 0–1 multiplier on the column spacing (gap + matra floor);\n * set by fitSwaralipi to compress before shrinking type\n * --sw-matra minimum width of one matra column\n * --sw-header-min floor for the নাম/তাল/আবর্তন header (it must stay legible\n * when the notation is scaled down to fit a phone)\n * --sw-lay-min same floor for the তাল / লয় change band\n * --sw-hl player-highlight background (P2.3)\n * --sw-rule header rule / muted line color\n *\n * All ink uses `currentColor`, so the sheet follows the host's text color\n * (dark mode included). The only octave mark drawn as a pseudo-element is\n * the bn ati-octave extra dot (Swarabitan's f/h glyphs are a single\n * reph/hasanta); everything else is a real glyph in the notation font.\n */\n\n/** Notation fonts, self-hosted on the project CDN (CORS-enabled), keyed by\n * the CSS `font-family` this stylesheet uses. bn = NLTR's Swarabitan; hi/en\n * = Ome Bhatkhande (SIL OFL 1.1, © Omenad — github.com/omenad/fonts).\n * Self-hosters: declare your own \\`@font-face\\` for any of these families\n * before this stylesheet / before defineSwaralipiSheet() and it wins. */\nexport const NOTATION_FONT_URLS: Record<string, string> = {\n Swarabitan: 'https://lipighor.pages.dev/swarabitan/Swarabitan.ttf',\n ome_bhatkhande_hindi: 'https://lipighor.pages.dev/ome-bhatkhande/OmeBhatkhandeHindi.ttf',\n ome_bhatkhande_english:\n 'https://lipighor.pages.dev/ome-bhatkhande/OmeBhatkhandeEnglish.ttf',\n};\n\n/** @deprecated use NOTATION_FONT_URLS.Swarabitan */\nexport const SWARABITAN_FONT_URL = NOTATION_FONT_URLS.Swarabitan;\n\n/* Each language renders its notation through one dedicated font — the\n * glyphs ARE the akarmatrik/Bhatkhande marks, keyed by plain ASCII (see\n * glyphs.ts). @font-face covers document use (SSR, print); the element also\n * registers these via the FontFace API because @font-face inside a shadow\n * root's adopted sheet is ignored. display:block — a flash of the ASCII\n * fallback ('kfa', 'srgm') would read as content. */\nconst FONT_FACES = Object.entries(NOTATION_FONT_URLS)\n .map(\n ([family, url]) =>\n `@font-face { font-family: ${family}; src: url('${url}') format('truetype'); font-display: block; }`,\n )\n .join('\\n');\n\nexport const SWARALIPI_CSS = `\n${FONT_FACES}\n\n/* A custom element is display:inline by default, and Resize Observer\n \"Observations do not fire for non-replaced inline Elements\" — they report\n one empty content rect and nothing after\n (https://drafts.csswg.org/resize-observer/). The element's re-fit-on-resize\n is that observer, so without this rule the sheet is fitted once, to whatever\n width it happened to have, and never again. */\n:host { display: block; }\n\n.sw-sheet {\n font-family: var(--sw-font, 'Noto Sans Bengali', 'Kohinoor Bangla', 'Bangla Sangam MN', 'Nirmala UI', 'Noto Sans Devanagari', sans-serif);\n font-size: var(--sw-size, 1.125rem);\n line-height: 1.5;\n}\n\n/* ---- notation font, per language (the note clusters + grace notes) ---- */\n.sw-sheet[lang=\"bn\"] :is(.sw-cl, .sw-kan, .sw-resh) { font-family: Swarabitan, var(--sw-font, sans-serif); }\n.sw-sheet[lang=\"hi\"] :is(.sw-cl, .sw-kan, .sw-resh) { font-family: ome_bhatkhande_hindi, var(--sw-font, sans-serif); }\n.sw-sheet[lang=\"en\"] :is(.sw-cl, .sw-kan, .sw-resh) { font-family: ome_bhatkhande_english, var(--sw-font, sans-serif); }\n\n/* ---- header ---- */\n.sw-header {\n margin: 0 0 0.75em;\n padding: 0 0 0.5em;\n border-bottom: 1px solid var(--sw-rule, rgba(128, 128, 128, 0.35));\n /* Scales with the sheet, but never below the floor: fitSwaralipi shrinks\n .sw-sheet's font-size to fit the notation, and the metadata is prose —\n it has no columns to align and must stay readable on a phone. */\n font-size: max(0.95em, var(--sw-header-min, 0.95rem));\n}\n.sw-meta-row { display: flex; gap: 0.3em; }\n.sw-meta-label { font-weight: 600; min-width: 4.5em; }\n.sw-meta-label::after { content: ':'; font-weight: 400; margin-left: 0.15em; }\n\n.sw-part-name { font-size: 0.85em; font-weight: 600; margin: 1em 0 0.2em; opacity: 0.85; }\n\n/* তাল / লয় change: the line where the তালফেরতা or the tempo tier turns over,\n centred between two systems the way স্বরবিতান prints \"ঝাঁপতাল\" or\n \"দ্রুত লয়\". A full-width band rather than a row label — the label track is\n what the notation columns are measured against, and a six-em word in it\n would shove the whole sheet right. */\n.sw-change {\n grid-column: 1 / -1;\n display: flex;\n align-items: center;\n gap: 0.6em;\n margin: 0.8em 0 0;\n /* Floored like the header: fitSwaralipi shrinks the sheet to fit the\n notation's columns, and this label has none to align. */\n font-size: max(0.7em, var(--sw-lay-min, 0.72rem));\n font-weight: 600;\n letter-spacing: 0.09em;\n opacity: 0.75;\n break-after: avoid;\n}\n.sw-change::before,\n.sw-change::after {\n content: '';\n flex: 1;\n height: 1px;\n background: var(--sw-rule, rgba(128, 128, 128, 0.35));\n}\n.sw-taal + .sw-lay::before { content: '·'; margin-right: 0.6em; }\n\n/* ---- block grid: ONE column set for the whole sheet ----\n * NLTR emits a song as a single html table, which is why its lines align\n * down the page. Same here: .sw-block owns the tracks, every .sw-row\n * borrows them with subgrid, and .sw-part is display:contents so section\n * headings sit in the same grid instead of breaking it. */\n.sw-scroll { overflow-x: auto; }\n.sw-block {\n display: grid;\n column-gap: calc(var(--sw-cell-gap, 0.4em) * var(--sw-tight, 1));\n align-items: end;\n width: max-content;\n /* The last column's cell spacers overhang half a gap past the grid; clip\n that sideways so it neither counts as width to fit nor raises a scrollbar. */\n overflow-x: clip;\n}\n.sw-part { display: contents; }\n/* Four FIXED bands per row — above / notation / arc / lyric — so a beat label,\n * a কণ or a মীড় never changes how far a line sits from its words: the\n * notation hugs its lyric and the next system starts a little further off,\n * as the printed স্বরবিতান sets it. Content taller than its band overflows\n * rather than pushing the rhythm apart. */\n.sw-row {\n grid-column: 1 / -1;\n display: grid;\n grid-template-columns: subgrid;\n grid-template-rows: 0.95em 1.35em 0.4em 1.35em;\n align-items: end;\n padding-bottom: 0.35em;\n line-height: 1.35;\n}\n.sw-label { grid-column: 1; grid-row: 2; padding-right: 0.5em; font-weight: 600; }\n\n/* One column per cell, its notes set tight as one word (রসা) and centred by\n * two flex spacers. Each spacer overhangs half the column gap (a min-width\n * paid back by a negative margin, so the column is sized by the notes alone),\n * which lets neighbouring cells' spacers meet mid-gap: a মীড় crossing cells is\n * inked by these boxes with no hole between them. */\n.sw-cell, .sw-lyr { display: flex; justify-content: center; white-space: nowrap; }\n.sw-cell {\n --sw-half-gap: calc(var(--sw-cell-gap, 0.4em) * var(--sw-tight, 1) / 2);\n grid-row: 2;\n align-self: stretch;\n}\n.sw-cell::before, .sw-cell::after { content: ''; flex: 1 0 0; min-width: var(--sw-half-gap); }\n.sw-cell::before { margin-left: calc(var(--sw-half-gap) * -1); }\n.sw-cell::after { margin-right: calc(var(--sw-half-gap) * -1); }\n.sw-cell > .sw-n { position: relative; }\n.sw-above { grid-row: 1; font-size: 0.7em; line-height: 1; justify-self: center; white-space: nowrap; }\n.sw-below { grid-row: 3; font-size: 0.62em; line-height: 1; justify-self: center; white-space: nowrap; }\n.sw-lyr { grid-row: 4; }\n\n/* ---- notation clusters & marks ---- */\n.sw-cl { position: relative; display: inline-block; }\n\n/* bn ati-octave: Swarabitan's f/h give a single reph/hasanta, so ati adds\n * one extra dot above (ati-taar) / below (ati-mandra). bn-only — hi/en get\n * the two-dot glyph natively from the U/L octave suffix. */\n.sw-ati-taar::before,\n.sw-ati-mandra::before {\n content: '';\n position: absolute;\n left: 0.25em;\n width: 0.16em;\n height: 0.16em;\n border-radius: 50%;\n background: currentColor;\n}\n.sw-ati-taar::before { top: -0.3em; }\n.sw-ati-mandra::before { bottom: -0.35em; }\n\n/* grace notes: small raised clusters — কণ before the note, রেশ after it.\n * line-height 0 (here and on .sw-micro): a raised inline box taller than the\n * strut grows its line box and drops that one note's baseline below its\n * neighbours' (css2 §10.8). */\n.sw-kan,\n.sw-resh {\n position: relative;\n display: inline-block;\n font-size: 0.58em;\n line-height: 0;\n vertical-align: 0.75em;\n}\n.sw-kan { margin-right: 0.08em; }\n.sw-resh { margin-left: 0.08em; }\n\n.sw-hy { padding-right: 0.02em; }\n.sw-iso { display: inline-block; margin-left: -0.18em; }\n/* The অর্ধমাত্রা / ছেদ mark: two stacked rings (legend p. ১৩৫). bn types\n * Swarabitan's own glyph (the ASCII i key) — an isolated Unicode ঃ has no base and\n * every Bengali text font shapes it with a dotted circle (an NBSP carrier\n * does not help), but the notation font has the mark itself. hi/en fall back\n * to these drawn rings: Bhatkhande has no such sign. */\n.sw-cut {\n position: relative;\n display: inline-block;\n width: 0.3em;\n height: 1em;\n vertical-align: baseline;\n}\n.sw-cut::before, .sw-cut::after {\n content: '';\n position: absolute;\n left: 0.08em;\n width: 0.15em;\n height: 0.15em;\n border-radius: 50%;\n background: currentColor;\n}\n.sw-cut::before { top: 0.2em; }\n.sw-cut::after { top: 0.55em; }\n.sw-br { opacity: 0.8; padding: 0 0.06em; }\n.sw-micro { font-size: 0.6em; line-height: 0; vertical-align: super; opacity: 0.8; }\n\n/* raw fallback: never dropped, visibly non-notation. Swarabitan first —\n * raw IS that font's encoding, so undecoded cells show NLTR's own glyphs\n * (dimmed: semantics unverified); monospace ASCII when the font is out. */\n.sw-raw {\n font-family: Swarabitan, ui-monospace, SFMono-Regular, Menlo, monospace;\n font-size: 0.72em;\n opacity: 0.55;\n}\n/* above the notes, raw is the notator's own mark (alt passages, ‖): full ink */\n.sw-above .sw-raw { font-size: 1em; opacity: 1; }\n\n/* ---- bars: dari (A) and danda (l/L) Swarabitan glyphs, all langs;\n * its | is the ‖ অবসান stop mark ---- */\n.sw-bar, .sw-stop {\n font-family: Swarabitan, var(--sw-font, sans-serif);\n white-space: nowrap;\n}\n.sw-bar--quad { letter-spacing: 0.15em; }\n/* a bar owns a whole column but needs no matra of width */\n.sw-bar-cell { min-width: 0; }\n\n/* ---- মীড় under-arcs (from w/x/$ segments and spec meend) ----\n * Swarabitan's own arc, all langs: w is the opening hook, curling down from\n * its tip into a flat, x its mirror, y that flat alone — and they join\n * hole-free, so one run of text is a whole end (tools/align-check/glyph.html).\n * Each end sets its hook tip on its note's centre and runs the flat toward the\n * other end (render.ts arcInk): across cells it is cut at the mid-gap, where\n * the next cell's run carries on (.sw-mk clips a cell half a gap past each\n * side, as far as its spacers reach); inside one cell, at its note's edge. So\n * a long arc extends the flat and a short one trims it off. line-height 0 sets\n * every run's baseline the same distance below its note. The clip reaches\n * 0.5px further so two cells' anti-aliased edges overlap instead of leaving a\n * hairline seam between their identical flats. */\n.sw-mk { clip-path: inset(-3em calc(var(--sw-half-gap) * -1 - 0.5px)); }\n.sw-mo::after, .sw-mob::after, .sw-mos::after,\n.sw-mc::before, .sw-mcb::before, .sw-mcs::before,\n.sw-mf::before, .sw-mm::before {\n content: 'yyyyyyyyyyyy';\n position: absolute;\n top: calc(100% + 0.05em);\n font-family: Swarabitan;\n font-size: 0.9em;\n line-height: 0;\n white-space: pre;\n /* Cuts the width-constrained runs (-b/-s/-f) at their note's edge. NOT\n * overflow-x:clip — WebKit clips the block axis with it too, and these\n * boxes are line-height 0, so Safari erased every মীড় on the sheet. */\n clip-path: inset(-3em 0);\n}\n.sw-mo::after, .sw-mob::after, .sw-mos::after { content: 'wyyyyyyyyyyyy'; }\n/* rtl: a closing run cut short keeps its hook on its right edge */\n.sw-mc::before, .sw-mcb::before, .sw-mcs::before { content: 'yyyyyyyyyyyyx'; direction: rtl; }\n.sw-mo::after, .sw-mob::after { left: 50%; }\n.sw-mc::before, .sw-mcb::before { right: 50%; }\n.sw-mos::after { left: 0; }\n.sw-mcs::before { right: 0; }\n.sw-mf::before { left: 0; right: 0; }\n.sw-mm::before { left: -12em; }\n/* Inside one cell a hook gets half a note to curl in, about a third of its\n * curl: squeezed to half width (same stroke) it lands flat at the cut, so the\n * two flats meet level whatever the notes' widths — a small arc, not a V. */\n.sw-mob::after, .sw-mos::after, .sw-mcb::before, .sw-mcs::before { width: 100%; transform: scaleX(0.5); }\n.sw-mob::after, .sw-mos::after { transform-origin: left; }\n.sw-mcb::before, .sw-mcs::before { transform-origin: right; }\n\n/* ---- annotation content ---- */\n.sw-beat { position: relative; display: inline-block; padding: 0 0.1em; }\n.sw-sam::after {\n content: '';\n position: absolute;\n top: -0.45em;\n left: 50%;\n width: 0.1em;\n height: 0.4em;\n background: currentColor;\n transform: rotate(14deg);\n}\n\n/* ---- player sync (P2.3) ---- */\n.sw-hl { background: var(--sw-hl, rgba(255, 196, 64, 0.45)); border-radius: 0.15em; }\n/* Staff notes are SVG <g> — background doesn't paint there, so recolour the\n glyph fill/stroke instead (abcjs draws note heads/stems as filled paths). */\n.sw-staff .sw-hl, .sw-staff .sw-hl * { fill: var(--sw-hl-note, #d68400); stroke: var(--sw-hl-note, #d68400); }\n\n/* ---- practice: tap a line, repeat it, sing it back ----\n * Only a sheet a player drives is [seekable]. The whole line is the tap\n * target, so it is the line that answers the pointer. A repeat shades its\n * lines and fades the rest (focus, as Soundslice fades outside a loop); on the\n * learner's pass the highlight goes hollow — it marks where to sing, not what\n * is sounding — and the repeat's first line wears a \"your turn\" tag. None of\n * it moves a column: backgrounds, opacity and an out-of-flow tag only. */\n:host([seekable]) .sw-row { cursor: pointer; }\n:host(:focus-visible) { outline: 2px solid var(--sw-focus, currentColor); outline-offset: 0.3em; border-radius: 0.2em; }\n.sw-row { border-radius: 0.3em; }\n@media (hover: hover) {\n :host([seekable]) .sw-row:hover { background: var(--sw-row-hover, rgba(128, 128, 128, 0.08)); }\n}\n.sw-looping .sw-row:not(.sw-loop) { opacity: 0.6; }\n.sw-row.sw-loop {\n background: var(--sw-loop, rgba(255, 196, 64, 0.13));\n box-shadow: inset 0.2em 0 var(--sw-loop-edge, #a85a00);\n}\n.sw-hl.sw-hl-turn { background: none; box-shadow: inset 0 0 0 0.09em var(--sw-loop-edge, #a85a00); }\n/* The tag rides the line's above-band at its right end — a grid item spanning\n every column, so it sizes no track — and is sticky, so on a phone where the\n line runs past the screen it waits at the visible edge instead. */\n.sw-row[data-turn]::after {\n content: attr(data-turn);\n grid-column: 1 / -1;\n grid-row: 1;\n justify-self: end;\n align-self: start;\n position: sticky;\n right: 0.2em;\n translate: 0 -0.3em;\n font-size: max(0.6em, 0.7rem);\n font-weight: 600;\n line-height: 1.6;\n padding: 0 0.7em;\n border-radius: 1em;\n color: var(--sw-turn-ink, #fff);\n background: var(--sw-loop-edge, #a85a00);\n}\n.sw-live { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }\n@media (prefers-reduced-motion: no-preference) {\n .sw-row { transition: opacity 0.25s, background-color 0.25s; }\n}\n@media print {\n .sw-row { opacity: 1 !important; background: none !important; box-shadow: none !important; }\n .sw-row[data-turn]::after { content: none; }\n .sw-hl { background: none !important; box-shadow: none !important; }\n}\n\n/* ---- element error box ---- */\n.sw-error {\n font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\n font-size: 0.85em;\n padding: 0.6em 0.8em;\n border: 1px solid rgba(200, 64, 64, 0.6);\n border-radius: 0.3em;\n color: #b33;\n background: rgba(200, 64, 64, 0.08);\n}\n`;\n\n/**\n * Print stylesheet — pair with `SWARALIPI_CSS` (renderPrintDocument injects\n * both). Gated on `@media print`, so it also works if a consumer drops it into\n * a page and prints that page directly.\n *\n * - `print-color-adjust: exact` forces the marks that are drawn as tiny\n * `background: currentColor` pseudo-elements (octave dots, arcs, danda\n * strokes, sam tick) to actually print — browsers drop backgrounds by\n * default, which would silently strip the notation's diacritics.\n * - rows are un-clipped (no scrollbar on paper) and kept whole across page\n * breaks; part headings stay with their first row.\n */\nexport const SWARALIPI_PRINT_CSS = `\n@page { margin: 16mm; }\n@media print {\n .sw-sheet, .sw-staff { -webkit-print-color-adjust: exact; print-color-adjust: exact; color: #000; }\n .sw-scroll { overflow: visible !important; }\n .sw-row { break-inside: avoid; page-break-inside: avoid; }\n .sw-part-name, .sw-header, .sw-change { break-after: avoid-page; page-break-after: avoid; }\n .sw-hl { background: none !important; }\n /* Keep each engraved staff system whole across a page break (the abcjs line\n is a <div> wrapping the <svg>, so the break rule must sit on the div). */\n .sw-staff-lines > div { break-inside: avoid; page-break-inside: avoid; }\n .sw-staff-meta { break-after: avoid-page; page-break-after: avoid; }\n}\n`;\n\n/** Staff-notation (abcjs) wrapper chrome: instrument/tempo header + a fluid\n * SVG. The engraving itself is drawn by abcjs; this only frames it. */\nexport const SWARALIPI_STAFF_CSS = `\n.sw-staff { color: currentColor; }\n.sw-staff-meta { display: flex; gap: 1.25em; align-items: baseline; margin: 0 0 .5em; font-size: .95em; opacity: .85; }\n.sw-staff-instrument { font-weight: 600; }\n.sw-staff-drums { opacity: .75; }\n.sw-staff-tempo { font-variant-numeric: tabular-nums; }\n/* abcjs (oneSvgPerLine) wraps the music into one <div><svg> per system; stack\n them as short, swaralipi-style lines. abcjs sets a fixed pixel height +\n overflow:hidden on each wrapper div — neutralise it so the viewBox'd SVG can\n scale to the container (and to the print page) instead of being clipped. */\n.sw-staff-lines > div { margin: 0 0 .35em; height: auto !important; overflow: visible !important; }\n/* Fill up to the engraved (staffwidth) size — shrink to fit a narrow container,\n but never stretch past natural width (abcToSvg pins per-SVG max-width in px),\n else a short last system balloons. */\n.sw-staff-lines svg { display: block; width: 100%; height: auto; }\n.sw-staff-missing { padding: 1em; border: 1px dashed currentColor; border-radius: 6px; opacity: .8; font-size: .9em; }\n.sw-staff-title { font-size: 1.15em; font-weight: 700; }\n.sw-staff-subtitle { opacity: .8; font-size: .95em; margin-top: .15em; }\n`;\n","/**\n * Staff (Western) notation — a 4th \"language\" for the viewer.\n *\n * Staff notation IS the melody voice drawn as a Western score, so it reuses\n * the player's pure `buildSchedule` (the same (midi, beat, durationBeats, kan)\n * the MIDI export writes) and turns it into an **ABC notation** string, which\n * `abcjs` (MIT, zero-dep) engraves to SVG. abcjs is loaded through a *dynamic*\n * `import('abcjs')` — an optional peer dep, exactly like tone/lamejs — so the\n * viewer bundle keeps its bare-load guarantee and only consumers who want staff\n * notation install it. Without it, `renderStaffHtml` returns a graceful notice.\n *\n * Scope (matches the player/MIDI): a single treble-clef melody line. The chosen\n * instrument is a header label, not a clef change (the line is monophonic and\n * treble covers piano + violin range with ledger lines). Microtones render as\n * their komal approximation — the same documented limitation as playback, since\n * abcjs has no sub-komal glyph.\n */\nimport type { Swaralipi, Taal } from '../spec/index.js';\nimport { buildSchedule, glideTargets, type PlayEvent, type Schedule } from '../player/schedule.js';\nimport { TAALS, type TaalId } from '../spec/taals.js';\nimport { drumPattern, type DrumVoice } from '../player/instruments.js';\nimport { renderMetaHeader } from './render.js';\nimport type { GridLang } from './glyphs.js';\n\nexport interface StaffOptions {\n /** Tonic (Sa). Accepts `C`, `C#`, `cs`… Default: `meta.tonic`, else `C`. */\n tonic?: string;\n /** Octave of madhyam Sa (C4 = MIDI 60). Default 4. */\n baseOctave?: number;\n /** Tempo written into the score (Q:) and shown as a header. Default `meta.bpm`, else 90. */\n bpm?: number;\n /** Instrument name shown above the staff (label only — clef stays treble). */\n instrument?: string;\n /** Show the নাম/তাল/আবর্তন/স্বরলিপিকার header block. Default true. */\n showHeader?: boolean;\n /** Language for the header **labels** (values are injected pre-localized by\n * the consumer). Default `en` — staff is the Western view. */\n headerLang?: GridLang;\n /** Transliterate header values (title/taal/notator) — same fn as the grid. */\n transliterate?: (bengaliText: string) => string;\n /** Include the `w:` lyric line under each staff. Default true. */\n lyrics?: boolean;\n /** Matra per bar (one তাল cycle). Default `meta.taal.numBeats`, else 4. */\n beatsPerBar?: number;\n /** Target line width in px passed to abcjs (music wraps within it). Default 680. */\n staffwidth?: number;\n /** Preferred bars per wrapped line (swaralipi-short systems). Default 4. */\n measuresPerLine?: number;\n /** abcjs `scale`. Default 1. */\n scale?: number;\n /** Add a second percussion staff below the melody, sequencing a Western\n * drumset (kick/snare/hi-hat) to the taal's sam/tali/khaali structure —\n * the same pattern `SwaralipiPlayer`'s `rhythm: 'drums'` plays, engraved via\n * abcjs `%%percmap`. Default false (the score stays a single staff). Taal:\n * `meta.taal`, else a plain 4-beat cycle (matches `beatsPerBar`'s fallback). */\n drums?: boolean;\n}\n\n/* ---- MIDI → ABC pitch spelling -------------------------------------- */\n\n/** Sharp-spelled ABC pitch tokens, index = pitch-class 0–11. `^` = sharp. */\nconst ABC_SHARP = ['C', '^C', 'D', '^D', 'E', 'F', '^F', 'G', '^G', 'A', '^A', 'B'] as const;\n\n/**\n * MIDI number → ABC pitch token. ABC's octave anchor is fixed by the standard:\n * middle C (MIDI 60, C4) is uppercase `C`; lowercase `c` = C5; a comma drops an\n * octave (`C,` = C3), an apostrophe raises one (`c'` = C6). Sharps carry a `^`.\n */\nexport function midiToAbc(midi: number): string {\n const pc = ((midi % 12) + 12) % 12;\n const octave = Math.floor(midi / 12) - 1; // MIDI 60 → 4\n const token = ABC_SHARP[pc]!;\n const acc = token[0] === '^' ? '^' : '';\n const letter = acc ? token[1]! : token[0]!;\n return octave >= 5\n ? acc + letter.toLowerCase() + \"'\".repeat(octave - 5)\n : acc + letter + ','.repeat(4 - octave);\n}\n\n/**\n * ABC duration suffix for a beat length, where the unit note (`L:`) is one\n * matra = a quarter note. Whole numbers append the multiplier (`2`, `3`);\n * simple fractions use `/n` (`/2` = eighth); anything else falls back to the\n * nearest 1/4-matra count of `/4` units so odd durations still sum correctly.\n */\nexport function abcDuration(beats: number): string {\n if (Math.abs(beats - 1) < 1e-6) return '';\n if (Math.abs(beats - Math.round(beats)) < 1e-6) return String(Math.round(beats));\n const inv = 1 / beats;\n if (Math.abs(inv - Math.round(inv)) < 1e-6) return `/${Math.round(inv)}`;\n // Fallback: express in sixteenth-note (1/4-matra) units, e.g. 0.75 → 3/4.\n const sixteenths = Math.max(1, Math.round(beats * 4));\n return `${sixteenths}/4`;\n}\n\n/** One ABC note token: optional grace, the pitch, its duration. */\nfunction abcNote(ev: PlayEvent): string {\n const grace = ev.kan.length > 0 ? `{${ev.kan.map(midiToAbc).join('')}}` : '';\n return `${grace}${midiToAbc(ev.midi!)}${abcDuration(ev.durationBeats)}`;\n}\n\n/**\n * The `part.row.note` path for each ABC note/rest token, in emission order —\n * i.e. index N here is abcjs's `data-index=\"N\"` (verified: abcjs assigns one\n * incrementing index per `.abcjs-note`/`.abcjs-rest` element, in tune order,\n * and skips bars entirely — the same tokens `buildAbc` pushes). Used to paint\n * `data-note` onto the engraved SVG so playback highlighting reuses the exact\n * `highlight()`/`data-note` mechanism the grid languages already have.\n */\nfunction eventPaths(schedule: Schedule): string[] {\n const paths: string[] = [];\n for (const ev of schedule.events) {\n if (ev.midi !== null || ev.kind === 'rest') paths.push(ev.path);\n }\n return paths;\n}\n\n/* ---- Schedule → ABC tune -------------------------------------------- */\n\n/** One তাল stretch of the score: its meter, and drum voices when drums are on. */\nexport interface AbcMeter {\n /** Start, in schedule beats. */\n beat: number;\n /** Matra per bar (one তাল cycle) from here on. */\n beatsPerBar: number;\n /** Per-matra drum voices from here on; `undefined` rests (মুক্তছন্দ). */\n drums?: DrumVoice[];\n}\n\nconst barLen = (m: AbcMeter): number => (m.beatsPerBar > 0 ? m.beatsPerBar : 4);\n\n/** Strip newlines/field-leaders so a title/text is safe inside an ABC field. */\nfunction abcText(s: string): string {\n return s.replace(/[\\r\\n]+/g, ' ').trim();\n}\n\n/**\n * Build a complete ABC tune string from a schedule. Pure and dependency-free\n * (the testable seam). Rests advance time as `z`; melody notes carry duration;\n * lyrics become a `w:` line aligned to the notes.\n *\n * Bar lines are inserted every `beatsPerBar` matra (= one তাল cycle, so an ABC\n * measure is one আবর্তন). This is what lets abcjs **wrap into short systems** —\n * it only breaks lines at bar lines. `M:` is set to match so the notes-per-bar\n * check-out. The tempo (`Q:`) rides the header.\n *\n * `drums`, if given, is the taal's per-beat `drumPattern()` — a second\n * `V:2 clef=perc` percussion staff is added below the melody, cycling that\n * pattern one quarter-note per matra with `%%percmap` GM drum sounds (see\n * `buildDrumVoice`). Both voices share the same bar grid, so they wrap and\n * align together.\n *\n * `meters`, if given, is one entry per তাল stretch (তালফেরতা): at each start\n * the running bar is closed and the new meter restated inline as `[M:n/4]` —\n * the bracketed form, because a bare `M:` line forces a new system.\n */\nexport function buildAbc(\n schedule: Schedule,\n lyricOf: (ev: PlayEvent) => string | undefined,\n opts: { bpm: number; lyrics: boolean; beatsPerBar: number; drums?: DrumVoice[]; meters?: AbcMeter[] },\n): string {\n const meters = opts.meters?.length ? opts.meters : [{ beat: 0, beatsPerBar: opts.beatsPerBar, drums: opts.drums }];\n const withDrums = opts.drums !== undefined || meters.some((m) => m.drums !== undefined);\n let m = 0;\n let beatsPerBar = barLen(meters[0]!);\n const tokens: string[] = [];\n const words: string[] = [];\n let barPos = 0; // matra elapsed within the current measure\n const EPS = 1e-6;\n\n const advance = (dur: number) => {\n barPos += dur;\n // Close every full measure (a note may fill/overflow more than one).\n while (barPos >= beatsPerBar - EPS) {\n tokens.push('|');\n words.push('|');\n barPos -= beatsPerBar;\n }\n };\n\n schedule.events.forEach((ev, i) => {\n while (m + 1 < meters.length && ev.beat >= meters[m + 1]!.beat - EPS) {\n m++;\n if (barPos > EPS) {\n tokens.push('|');\n words.push('|');\n }\n barPos = 0;\n const next = barLen(meters[m]!);\n if (next !== beatsPerBar) tokens.push(`[M:${ratioMeter(next)}]`);\n beatsPerBar = next;\n }\n if (ev.midi === null) {\n if (ev.kind === 'rest') {\n tokens.push(`z${abcDuration(ev.durationBeats)}`);\n words.push('*');\n advance(ev.durationBeats);\n }\n return; // zero-time আ-কার holds already folded into the previous note\n }\n // মীড় → an ABC slur over the glided notes: one bow/breath, pitch moving.\n const more = glideTargets(schedule.events, i).length > 0;\n const slurOpen = ev.glide !== true && more ? '(' : '';\n const slurClose = ev.glide === true && !more ? ')' : '';\n tokens.push(`${slurOpen}${abcNote(ev)}${slurClose}`);\n const lyr = lyricOf(ev);\n // abcjs splits w: on spaces; '~' joins a multi-word syllable, '*' is blank.\n words.push(lyr ? abcText(lyr).replace(/\\s+/g, '~') : '*');\n advance(ev.durationBeats);\n });\n\n // Final barline (song end) if the last note didn't land exactly on a bar.\n if (tokens.length && tokens[tokens.length - 1] !== '|') tokens.push('|]');\n else if (tokens.length) tokens[tokens.length - 1] = '|]';\n\n // No T: title — abcjs draws it oversized above the first system and collides\n // with the host page. Title/tempo/instrument live in the `.sw-staff` wrapper.\n const meter = ratioMeter(barLen(meters[0]!));\n const head = ['X:1', `M:${meter}`, 'L:1/4', `Q:1/4=${Math.round(opts.bpm)}`];\n if (withDrums) head.push(...percMapLines(meters.flatMap((x) => x.drums ?? [])));\n head.push('K:C treble');\n\n const melodyBody = tokens.length ? tokens.join(' ') : 'z |]';\n const lines = [...head];\n if (withDrums) {\n lines.push('V:1', melodyBody);\n if (opts.lyrics && words.some((w) => w !== '*' && w !== '|')) lines.push(`w: ${words.join(' ')}`);\n lines.push('V:2 clef=perc stem=up', buildDrumVoice(schedule.totalBeats, meters));\n } else {\n lines.push(melodyBody);\n if (opts.lyrics && words.some((w) => w !== '*' && w !== '|')) lines.push(`w: ${words.join(' ')}`);\n }\n return lines.join('\\n');\n}\n\n/** Meter string for a bar of N quarter-note beats (N/4). */\nfunction ratioMeter(beats: number): string {\n return `${Math.max(1, Math.round(beats))}/4`;\n}\n\n/* ---- Percussion voice (Western-drumset rendering of the taal) -------- */\n\n/** ABC pitch letter used as each drum voice's percmap key (arbitrary but\n * fixed — must be a real ABC note letter, not `z`/`x`, which abcjs reserves\n * for rests/invisible rests). GM percussion names abcjs's `%%percmap`\n * understands; see the General MIDI drum map. */\nconst DRUM_ABC: Record<DrumVoice, { note: string; gm: string }> = {\n kick: { note: 'F,', gm: 'bass-drum-1' },\n snare: { note: 'C', gm: 'acoustic-snare' },\n hihat: { note: 'g', gm: 'closed-hi-hat' },\n tom1: { note: 'E', gm: 'high-tom' },\n tom2: { note: 'A,', gm: 'low-mid-tom' },\n tom3: { note: 'D,', gm: 'low-floor-tom' },\n};\n\n/** `%%percmap` header lines mapping each used drum voice to its GM sound. */\nfunction percMapLines(voices: Iterable<DrumVoice>): string[] {\n const seen = new Set<DrumVoice>();\n const lines: string[] = [];\n for (const v of voices) {\n if (seen.has(v)) continue;\n seen.add(v);\n const { note, gm } = DRUM_ABC[v];\n lines.push(`%%percmap ${note} ${gm}`);\n }\n return lines;\n}\n\n/**\n * Build the `V:2 clef=perc` drum-voice tune body: one quarter-note token per\n * matra for `totalBeats` (cycling each stretch's `drumPattern`, a rest where it\n * has none), barred every `beatsPerBar` matra and re-metered at each তাল\n * change — the same bar grid as the melody voice, so both staves wrap and\n * align together.\n */\nfunction buildDrumVoice(totalBeats: number, meters: AbcMeter[]): string {\n const tokens: string[] = [];\n meters.forEach((m, i) => {\n const bpb = barLen(m);\n if (i > 0) {\n if (tokens.length > 0 && tokens[tokens.length - 1] !== '|') tokens.push('|');\n if (bpb !== barLen(meters[i - 1]!)) tokens.push(`[M:${ratioMeter(bpb)}]`);\n }\n const end = meters[i + 1]?.beat ?? Math.max(1, Math.ceil(totalBeats));\n const n = Math.ceil(end - m.beat - 1e-6);\n for (let beat = 0; beat < n; beat++) {\n tokens.push(m.drums?.length ? DRUM_ABC[m.drums[beat % m.drums.length]!].note : 'z');\n if ((beat + 1) % bpb === 0) tokens.push('|');\n }\n });\n if (tokens.length === 0 || tokens[tokens.length - 1] !== '|') tokens.push('|]');\n else tokens[tokens.length - 1] = '|]';\n return tokens.join(' ');\n}\n\n/* ---- Doc → ABC (wires the schedule to the doc's lyrics) -------------- */\n\n/** Map each schedule event back to its source note's lyric via the `part.row.note` path. */\nfunction lyricLookup(doc: Swaralipi): (ev: PlayEvent) => string | undefined {\n return (ev) => {\n const [p, r, i] = ev.path.split('.').map(Number);\n return doc.parts[p!]?.rows[r!]?.notes[i!]?.lyric;\n };\n}\n\n/** The taal driving a stretch's drum pattern: its own (if known to the player's\n * sample/theory tables), else a plain 4-beat cycle — mirrors the player's own\n * `taalId ?? { numBeats: 4, sam: 0 }` fallback in `#buildRhythm`. */\nfunction resolveDrumTaal(taal: Taal | null | undefined): Pick<Taal, 'numBeats' | 'sam' | 'bhaags' | 'khaali'> {\n const id = taal?.id;\n return id !== undefined && id in TAALS ? TAALS[id as TaalId] : { numBeats: 4, sam: 0 };\n}\n\n/** Build the ABC tune string for a whole document (schedule + lyrics + tempo).\n * The measure length is one তাল cycle — per stretch, so a তালফেরতা changes the\n * time signature where the taal changes — falling back to 4.\n * `opts.drums` adds the percussion staff (see `buildAbc`). */\nexport function docToAbc(doc: Swaralipi, opts: StaffOptions = {}): string {\n const schedule = buildSchedule(doc, { tonic: opts.tonic, baseOctave: opts.baseOctave, lay: false });\n const bpm = opts.bpm ?? doc.meta.bpm ?? 90;\n const meters: AbcMeter[] = schedule.tempo.map((seg) => ({\n beat: seg.beat,\n beatsPerBar: opts.beatsPerBar ?? seg.taal?.numBeats ?? 4,\n drums: opts.drums && seg.taal !== null ? drumPattern(resolveDrumTaal(seg.taal)) : undefined,\n }));\n return buildAbc(schedule, lyricLookup(doc), {\n bpm,\n lyrics: opts.lyrics !== false,\n beatsPerBar: meters[0]!.beatsPerBar,\n drums: opts.drums ? (meters[0]!.drums ?? []) : undefined,\n meters,\n });\n}\n\n/* ---- ABC → SVG via abcjs (browser/jsdom only) ----------------------- */\n\n/**\n * Render an ABC tune string to engraved HTML using abcjs. Requires a DOM\n * (`document`) — abcjs measures glyphs and draws into an element; call it in a\n * browser, in a print iframe, or under jsdom (tests stub `getBBox`). abcjs is\n * dynamically imported so it is never bundled or loaded unless staff notation\n * is actually used.\n *\n * The music is **wrapped into short systems** (a few bars per line, each its\n * own SVG-in-DIV) — matching how আকারমাত্রিক swaralipi is laid out in stacked\n * rows rather than one long staff. Returns the full multi-line markup (all\n * line DIVs), or a notice string if abcjs is not installed.\n *\n * `notePaths`, if given, is the `part.row.note` highlight path for each ABC\n * melody note/rest token in schedule order (see `eventPaths`). The melody is\n * voice 0; abcjs emits its `.abcjs-v0.abcjs-note`/`.abcjs-rest` elements in\n * document order = that same order, so painting `notePaths[i]` onto the i-th\n * melody element gives every engraved note the same `data-note` attribute the\n * grid languages use — playback highlighting works identically for staff. (We\n * key off voice + document order, NOT `data-index`: with a drum voice abcjs\n * numbers each line/voice block separately, so data-index isn't global order.)\n */\nexport async function abcToSvg(abc: string, opts: StaffOptions = {}, notePaths?: string[]): Promise<string> {\n if (typeof document === 'undefined') {\n throw new Error('abcToSvg requires a DOM; render staff notation in the browser or print iframe');\n }\n let ABCJS: typeof import('abcjs');\n try {\n const mod = await import('abcjs');\n ABCJS = (mod as { default?: typeof import('abcjs') }).default ?? mod;\n } catch {\n return `<div class=\"sw-staff-missing\">Staff notation needs the optional <code>abcjs</code> package.</div>`;\n }\n // abcjs measures glyph/line heights from live layout to decide where to wrap\n // and split systems — a purely detached div reports height 0, collapsing the\n // staves. So render into an off-screen-but-attached host, read the markup,\n // then remove it.\n const host = document.createElement('div');\n host.style.cssText = 'position:fixed; left:-10000px; top:0; width:720px; visibility:hidden;';\n const mount = document.body ?? document.documentElement;\n mount.appendChild(host);\n try {\n ABCJS.renderAbc(host, abc, {\n add_classes: true,\n staffwidth: opts.staffwidth ?? 680,\n scale: opts.scale ?? 1,\n // Reflow into short lines. staffwidth is the width budget;\n // preferredMeasuresPerLine keeps systems swaralipi-short.\n // (Not `responsive: resize` — its absolute-positioned aspect-ratio wrapper\n // overlaps the header and mis-sizes on the print page.)\n wrap: { minSpacing: 1.8, maxSpacing: 2.7, preferredMeasuresPerLine: opts.measuresPerLine ?? 4 },\n // CRUCIAL: put each wrapped system in its OWN <svg> (default is all systems\n // stacked in one tall SVG, which is atomic and can't page-break — that was\n // the near-blank-first-page / mid-staff-cutoff print bug). One SVG per line\n // lets `break-inside: avoid` keep each staff whole while pages fill.\n oneSvgPerLine: true,\n });\n // abcjs sizes each SVG with fixed pixel width/height and NO viewBox, so it\n // can't shrink to a narrow container / print page. Give each a viewBox and\n // drop the fixed size; the CSS then scales it (aspect ratio preserved).\n for (const svg of host.querySelectorAll('svg')) {\n const w = parseFloat(svg.getAttribute('width') ?? '');\n const h = parseFloat(svg.getAttribute('height') ?? '');\n if (w > 0 && h > 0) {\n // abcjs (v6) sets a fixed pixel width/height (and a viewBox). The fixed\n // width blocks shrinking to a narrow container, but dropping it lets the\n // CSS `width:100%` STRETCH a short system to fill a wide container. So\n // drop the fixed size (shrink-to-fit) but pin max-width to the engraved\n // width (never stretch past it) — the score stays swaralipi-sized.\n if (!svg.getAttribute('viewBox')) svg.setAttribute('viewBox', `0 0 ${w} ${h}`);\n svg.setAttribute('preserveAspectRatio', 'xMinYMin meet');\n svg.removeAttribute('width');\n svg.removeAttribute('height');\n svg.setAttribute('style', `max-width:${w}px`);\n }\n }\n // Paint data-note onto each engraved MELODY note/rest so playback\n // highlighting works exactly like the grid languages (see notePaths doc).\n // abcjs's `data-index` is NOT global tune order — with a drum voice it\n // numbers each (line, voice) block separately, so the drum notes get indices\n // that collide with the melody's. The melody is always voice 0 (`abcjs-v0`);\n // its note/rest elements appear in document order = schedule order, so we\n // match `notePaths` by position over just those, ignoring data-index.\n if (notePaths) {\n const melody = host.querySelectorAll('.abcjs-v0.abcjs-note, .abcjs-v0.abcjs-rest');\n let i = 0;\n for (const el of melody) {\n const path = notePaths[i++];\n if (path !== undefined) el.setAttribute('data-note', path);\n }\n }\n // abcjs emits one <div><svg>…</svg></div> per wrapped line; return them all.\n return host.innerHTML;\n } finally {\n host.remove();\n }\n}\n\n/**\n * Full doc → staff-notation HTML fragment: the shared নাম/তাল/আবর্তন/স্বরলিপিকার\n * header (same block as the akarmatrik grid, so the staff shows the identical\n * metadata) + an instrument label + the wrapped Western systems. Styled by\n * SWARALIPI_CSS + SWARALIPI_STAFF_CSS. Async because abcjs is dynamic-imported.\n */\nexport async function renderStaffHtml(doc: Swaralipi, opts: StaffOptions = {}): Promise<string> {\n const bpm = opts.bpm ?? doc.meta.bpm ?? 90;\n const abc = docToAbc(doc, { ...opts, bpm });\n const schedule = buildSchedule(doc, { tonic: opts.tonic, baseOctave: opts.baseOctave, lay: false });\n const engraved = await abcToSvg(abc, opts, eventPaths(schedule));\n // The abcjs output is the wrapped systems (or the \"needs abcjs\" notice, which\n // is passed through un-wrapped).\n const lines = engraved.includes('sw-staff-missing')\n ? engraved\n : `<div class=\"sw-staff-lines\">${engraved}</div>`;\n // Same header as the grid (title/taal/raag/avartan/notator). Labels in\n // headerLang (default en — the Western view); values are pre-localized by\n // the consumer. abcjs engraves the tempo (Q:) itself, so the instrument label\n // is the only extra strip.\n const header =\n opts.showHeader === false ? '' : renderMetaHeader(doc.meta, opts.headerLang ?? 'en', opts.transliterate);\n const metaParts: string[] = [];\n if (opts.instrument) metaParts.push(`<span class=\"sw-staff-instrument\">${escapeAttr(opts.instrument)}</span>`);\n if (opts.drums) metaParts.push(`<span class=\"sw-staff-drums\">+ drums</span>`);\n const meta = metaParts.length ? `<div class=\"sw-staff-meta\">${metaParts.join('')}</div>` : '';\n return `<div class=\"sw-staff\">${header}${meta}${lines}</div>`;\n}\n\nfunction escapeAttr(s: string): string {\n return s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/\"/g, '"');\n}\n\n/* ---- Bare taal (theka) drum staff ----------------------------------- */\n\n/** Options for the standalone taal staff (a single percussion voice — no\n * melody doc). Layout fields mirror `StaffOptions`; `abcToSvg` reads them. */\nexport interface TaalStaffOptions {\n /** Tempo written into the score (Q:). Default 90. */\n bpm?: number;\n /** Per-matra drum voices (one per beat of the cycle). Default: the taal's own\n * `drumPattern()` (sam→kick, tali→snare, khaali→hihat). Length is cycled to\n * `numBeats`, so an explicit book-accurate mapping overrides the geometric one. */\n drums?: DrumVoice[];\n /** Theka bols aligned under each matra (the `w:` line). One per beat. */\n bols?: string[];\n /** abcjs target width in px. Default 680. */\n staffwidth?: number;\n /** abcjs `scale`. Default 1. */\n scale?: number;\n}\n\n/**\n * Build a **percussion-only** ABC tune for one avartan of a taal — no melody\n * voice. One quarter-note per matra over a single `V:1 clef=perc` staff, voices\n * from `opts.drums ?? drumPattern(taal)`, `%%percmap` for the used sounds, and\n * (optional) bols as the aligned `w:` line. The whole cycle is one bar (M:n/4).\n * Pure + dependency-free — the testable seam, mirroring `buildAbc`.\n */\nexport function buildTaalAbc(taal: Pick<Taal, 'numBeats' | 'sam' | 'bhaags' | 'khaali'>, opts: TaalStaffOptions = {}): string {\n const n = Math.max(1, taal.numBeats);\n const src = opts.drums && opts.drums.length ? opts.drums : drumPattern(taal);\n const voices = Array.from({ length: n }, (_, i) => src[i % src.length]!);\n const bpm = Math.round(opts.bpm ?? 90);\n const head = ['X:1', `M:${ratioMeter(n)}`, 'L:1/4', `Q:1/4=${bpm}`, ...percMapLines(voices), 'K:C'];\n const lines = [...head, 'V:1 clef=perc stem=up', buildDrumVoice(n, [{ beat: 0, beatsPerBar: n, drums: voices }])];\n if (opts.bols?.length) {\n const w = opts.bols.slice(0, n).map((b) => (b.trim() ? abcText(b).replace(/\\s+/g, '~') : '*'));\n while (w.length < n) w.push('*');\n lines.push(`w: ${w.join(' ')}`);\n }\n return lines.join('\\n');\n}\n\n/**\n * Render a standalone taal theka as an engraved drum staff (abcjs). Each perc\n * note carries `data-note=\"<matra-index>\"` so a consumer's per-beat clock can\n * highlight the active note (the same `data-note` mechanism the grid uses).\n * Async because abcjs is dynamic-imported; returns a \"needs abcjs\" notice if\n * the optional package is absent.\n */\nexport async function renderTaalStaffHtml(\n taal: Pick<Taal, 'numBeats' | 'sam' | 'bhaags' | 'khaali'>,\n opts: TaalStaffOptions = {},\n): Promise<string> {\n const abc = buildTaalAbc(taal, opts);\n const n = Math.max(1, taal.numBeats);\n const paths = Array.from({ length: n }, (_, i) => String(i));\n const engraved = await abcToSvg(abc, { staffwidth: opts.staffwidth, scale: opts.scale }, paths);\n const lines = engraved.includes('sw-staff-missing') ? engraved : `<div class=\"sw-staff-lines\">${engraved}</div>`;\n return `<div class=\"sw-staff sw-staff--taal\">${lines}</div>`;\n}\n","/**\n * Tone.js instrument/asset factories. Tone is **injected** (never imported\n * here) so this module — like the scheduler — stays free of a static `tone`\n * dependency; the player passes the dynamically-imported module in.\n *\n * Melodic instruments are a small registry (INSTRUMENTS) of Tone.Sampler\n * note→file maps + where to fetch them. `piano` (CC-BY Salamander) is the\n * default and CDN-hosted, as are `harmonium`/`violin`/`flute` (CC-BY,\n * tonejs-instruments); `santoor` is local (under the player's `soundsBaseUrl`).\n * Consumers can register more (e.g. a self-hosted sitar) via the player's\n * `customInstruments` option — true sampled sitar/sarod/sarangi/esraj have no\n * free web set, only commercial Kontakt libraries.\n *\n * Asset layout under `soundsBaseUrl`:\n * santoor/<note>.mp3 c4..c7 + sharps (37 files)\n * tanpura/<pc>.mp3 12 pitch classes (c, cs, d, …)\n * tabla/<seg>/<seg><bpm>bpm.mp3 seg = <taal>[-<variation>], bpm 60..300 step 15\n * metronome/metro2.mp3\n */\n// Import TAALS from the taals subpath (not the ../spec/index barrel): the\n// barrel re-exports schema.ts, which statically imports zod — pulling that into\n// the player would break its \"loads bare in a browser\" guarantee. taals.ts has\n// only a type-only schema import, so this keeps the player runtime zod-free.\nimport type { Taal } from '../spec/schema.js';\nimport { TAALS, type TaalId } from '../spec/taals.js';\nimport { sCurve, sampleFileName } from './pitch.js';\n\n/** The dynamically-imported Tone module, typed without importing it. */\nexport type ToneModule = typeof import('tone');\n\n/** A melodic instrument: a Tone.Sampler note→filename map + where to find it. */\nexport interface InstrumentDef {\n /** Human label for UIs. */\n label: string;\n /** Tone.Sampler `urls`: note name (`C#4`) → filename (`Cs4.mp3`). */\n urls: Record<string, string>;\n /** Sample directory: an absolute URL, or — when `local` — a path segment\n * appended to the player's `soundsBaseUrl`. */\n baseUrl: string;\n /** `baseUrl` is relative to `soundsBaseUrl` (needs it set). */\n local?: boolean;\n /** Sampler release time in seconds. */\n release?: number;\n}\n\n/** Built-in melody instrument ids (consumers may add their own via the\n * player's `customInstruments`, so the runtime id type stays open). */\nexport type InstrumentId = string;\n\n/**\n * Default host for the project's samples (santoor / tabla / tanpura /\n * metronome) — CORS-enabled, so the player works with zero config. Override via\n * the player's `soundsBaseUrl` to self-host. (Melody defaults to the CDN-hosted\n * piano, so it needs no host.) Licences: see THIRD-PARTY.md.\n */\nexport const DEFAULT_SOUNDS_BASE = 'https://bitoron.pages.dev/audio/instruments/';\n/** CC-BY Salamander Grand Piano (Tone's de-facto piano), CDN-hosted. */\nexport const SALAMANDER_BASE = 'https://tonejs.github.io/audio/salamander/';\n/** CC-BY tonejs-instruments sample CDN (harmonium/violin/flute). */\nexport const TONEJS_INSTRUMENTS_BASE = 'https://nbrosowsky.github.io/tonejs-instruments/samples/';\n\n/** Build a Tone.Sampler `urls` map from bare note keys (`C#4` → `Cs4.mp3`). */\nfunction keyMap(keys: readonly string[]): Record<string, string> {\n const m: Record<string, string> = {};\n for (const k of keys) m[k] = `${k.replace('#', 's')}.mp3`;\n return m;\n}\n\nconst PIANO_KEYS = [\n 'A0', 'C1', 'D#1', 'F#1', 'A1', 'C2', 'D#2', 'F#2', 'A2', 'C3', 'D#3', 'F#3',\n 'A3', 'C4', 'D#4', 'F#4', 'A4', 'C5', 'D#5', 'F#5', 'A5', 'C6', 'D#6', 'F#6',\n 'A6', 'C7', 'D#7', 'F#7', 'A7', 'C8',\n] as const;\n// harmonium — a core Rabindrasangeet accompaniment (C2..C5). The CDN set has no F#4 (404).\nconst HARMONIUM_KEYS = [\n 'C2', 'C#2', 'D2', 'D#2', 'E2', 'F2', 'F#2', 'G2', 'G#2', 'A2', 'A#2',\n 'C3', 'C#3', 'D3', 'D#3', 'E3', 'F3', 'F#3', 'G3', 'G#3', 'A3', 'A#3',\n 'C4', 'C#4', 'D4', 'D#4', 'E4', 'F4', 'G4', 'G#4', 'A4', 'A#4',\n 'C5', 'C#5', 'D5',\n] as const;\nconst VIOLIN_KEYS = ['A3', 'C4', 'E4', 'G4', 'A4', 'C5', 'E5', 'G5', 'A5', 'C6', 'E6', 'G6', 'A6', 'C7'] as const;\nconst FLUTE_KEYS = ['C4', 'E4', 'A4', 'C5', 'E5', 'A5', 'C6', 'E6', 'A6', 'C7'] as const;\n\n/** Built-in melody instruments. santoor is local; the rest are CDN-hosted\n * (CC-BY) so they need only network — `pianoBaseUrl`/`customInstruments`\n * override for self-hosting. */\nexport const INSTRUMENTS: Record<string, InstrumentDef> = {\n piano: { label: 'Grand piano', urls: keyMap(PIANO_KEYS), baseUrl: SALAMANDER_BASE, release: 1 },\n santoor: { label: 'Santoor', urls: santoorUrls(), baseUrl: 'santoor/', local: true, release: 1.2 },\n harmonium: { label: 'Harmonium', urls: keyMap(HARMONIUM_KEYS), baseUrl: `${TONEJS_INSTRUMENTS_BASE}harmonium/`, release: 1.4 },\n violin: { label: 'Violin', urls: keyMap(VIOLIN_KEYS), baseUrl: `${TONEJS_INSTRUMENTS_BASE}violin/`, release: 1 },\n flute: { label: 'Flute', urls: keyMap(FLUTE_KEYS), baseUrl: `${TONEJS_INSTRUMENTS_BASE}flute/`, release: 1 },\n};\n\n/** Taals with recorded tabla loops (everything else → metronome fallback). */\nexport const SAMPLED_TAALS: ReadonlySet<TaalId> = new Set(\n Object.keys(TAALS) as TaalId[],\n);\n\n/** Available tabla loop tempos (file suffix `…<bpm>bpm.mp3`). */\nexport const TABLA_BPMS: readonly number[] = Array.from({ length: 17 }, (_, i) => 60 + i * 15);\n\n/**\n * Tabla loop variations per taal. Most taals have one unnamed loop at\n * `tabla/<id>/`; an entry here overrides that:\n * - `variations` lists the variation suffixes, **first = default**.\n * A lone named variation (shashthi → `pro`, i.e. `tabla/shashthi-pro/`) IS\n * the default; later entries are premium upsells the player never auto-selects.\n * An empty-string entry (kehrwa → `''`) means the unnamed `tabla/<id>/` loop\n * is the default and a named entry follows it as an upsell.\n * - `skipBpms` are grid tempos this taal's loops were not recorded at.\n * Consumers read this to build a variation/upsell UI; the player itself only\n * ever plays the default (or whatever a doc's `meta.taal.variation` pins).\n */\nexport const TABLA_VARIATIONS: Record<\n string,\n { variations: string[]; skipBpms?: number[] }\n> = {\n // ষষ্ঠী loops live under `tabla/shashthi-pro/`; full bpm grid recorded except 225.\n shashthi: { variations: ['pro'], skipBpms: [225] },\n // Kehrwa keeps its unnamed default loop; `qawwali` (tabla/kehrwa-qawwali/) is a\n // premium upsell variation recorded 90–300 (no 60/75).\n // ponytail: skipBpms is per-taal, so it can't restrict qawwali's 60/75 without\n // also dropping them from the default (which has them) — a qawwali doc pinned\n // ≤67 bpm 404s harmlessly. Make skipBpms per-variation only if that edge bites.\n kehrwa: { variations: ['', 'qawwali'] },\n};\n\n/** Tabla tempos actually available for a taal: the grid minus any it lacks. */\nexport function tablaBpms(taalId: string): readonly number[] {\n const skip = TABLA_VARIATIONS[taalId]?.skipBpms;\n return skip && skip.length ? TABLA_BPMS.filter((b) => !skip.includes(b)) : TABLA_BPMS;\n}\n\n/** CDN directory/filename segment for a taal's tabla loop: `<taalId>` or\n * `<taalId>-<variation>` (explicit variation, else the taal's default). */\nfunction tablaSeg(taalId: string, variation?: string): string {\n const v = variation ?? TABLA_VARIATIONS[taalId]?.variations[0]; // default = first variation, else unnamed\n return v ? `${taalId}-${v}` : taalId;\n}\n\n/** Ensure exactly one trailing slash. */\nexport function normalizeBase(url: string): string {\n return url.endsWith('/') ? url : `${url}/`;\n}\n\n/** The 37 santoor samples, as a Tone.Sampler `urls` map (`C4` → `c4.mp3`). */\nexport function santoorUrls(): Record<string, string> {\n const urls: Record<string, string> = {};\n const add = (midi: number) => {\n const stem = sampleFileName(midi); // e.g. cs4\n const name = stem.replace('s', '#').replace(/^(.)/, (c) => c.toUpperCase()); // C#4\n urls[name] = `${stem}.mp3`;\n };\n for (let midi = 60; midi <= 95; midi++) add(midi); // C4..B6 (full)\n add(96); // C7\n return urls;\n}\n\nconst PC_BASE: Record<string, number> = { c: 0, d: 2, e: 4, f: 5, g: 7, a: 9, b: 11 };\n\n/** Parse a sample note name (`C#4`, `Ds3`, `Bb2`) to a MIDI number. */\nexport function noteToMidi(name: string): number {\n const m = /^([a-g])([#sb]?)(-?\\d+)$/i.exec(name.trim());\n if (!m) return NaN;\n const base = PC_BASE[m[1]!.toLowerCase()]!;\n const acc = m[2] === 'b' ? -1 : m[2] === '' ? 0 : 1; // # / s → sharp\n return (Number(m[3]) + 1) * 12 + base + acc;\n}\n\n/**\n * Restrict a Sampler `urls` map to just the samples needed to cover MIDI\n * `[lo, hi]`: every sample inside the range, plus the nearest one below and\n * above it (so Tone interpolates the edges without extrapolating). Cuts a\n * typical song from ~37 santoor files to a handful — a big win on mobile and\n * never worse on fast links (Tone fetches what's left in parallel). The\n * Sampler pitch-shifts from the nearest sample, so audio is unchanged.\n */\nexport function subsetUrls(\n urls: Record<string, string>,\n lo: number,\n hi: number,\n): Record<string, string> {\n const entries = Object.entries(urls)\n .map(([k, f]) => ({ k, f, midi: noteToMidi(k) }))\n .filter((e) => Number.isFinite(e.midi))\n .sort((a, b) => a.midi - b.midi);\n if (entries.length === 0) return { ...urls };\n\n const keep = new Set<string>();\n for (const e of entries) if (e.midi >= lo && e.midi <= hi) keep.add(e.k);\n // nearest sample at/below lo and at/above hi for clean interpolation\n let floor: string | undefined;\n let ceil: string | undefined;\n for (const e of entries) if (e.midi <= lo) floor = e.k;\n for (const e of entries) if (e.midi >= hi) { ceil = e.k; break; }\n if (floor) keep.add(floor);\n if (ceil) keep.add(ceil);\n if (keep.size === 0) {\n // range entirely outside the sample set — keep the single nearest sample\n const mid = (lo + hi) / 2;\n const nearest = entries.reduce((a, b) => (Math.abs(b.midi - mid) < Math.abs(a.midi - mid) ? b : a));\n keep.add(nearest.k);\n }\n\n const out: Record<string, string> = {};\n for (const e of entries) if (keep.has(e.k)) out[e.k] = e.f;\n return out;\n}\n\n/** Resolve a representative sample URL for an instrument (its first sample),\n * used to probe availability. undefined when a local instrument has no\n * `soundsBaseUrl` or the def has no samples. */\nexport function instrumentSampleUrl(def: InstrumentDef, soundsBaseUrl?: string): string | undefined {\n if (def.local && soundsBaseUrl === undefined) return undefined;\n const base = def.local ? `${normalizeBase(soundsBaseUrl ?? '')}${def.baseUrl}` : def.baseUrl;\n const file = Object.values(def.urls)[0];\n return file === undefined ? undefined : `${normalizeBase(base)}${file}`;\n}\n\n/**\n * Liveness check for a sample URL: a single tiny ranged GET (one byte), the\n * same CORS-enabled fetch Tone uses to load the buffer — so a pass means Tone\n * can actually load it. Resolves false on any error/timeout/non-2xx, and false\n * (no throw) when `fetch` is unavailable (Node/SSR). `Range: bytes=0-0` is a\n * CORS-safelisted header, so no preflight.\n */\nexport async function probeUrl(url: string, timeoutMs = 6000): Promise<boolean> {\n if (typeof fetch === 'undefined') return false;\n const ctrl = typeof AbortController !== 'undefined' ? new AbortController() : undefined;\n const timer = ctrl ? setTimeout(() => ctrl.abort(), timeoutMs) : undefined;\n try {\n const res = await fetch(url, {\n method: 'GET',\n headers: { Range: 'bytes=0-0' },\n cache: 'no-store',\n signal: ctrl?.signal,\n });\n return res.ok; // 200 / 206\n } catch {\n return false;\n } finally {\n if (timer !== undefined) clearTimeout(timer);\n }\n}\n\n/**\n * Snap a tabla loop's end to the nearest whole beat of its measured length so a\n * slightly-mistrimmed file still phase-locks to the melody grid instead of\n * drifting a fraction of a beat each cycle. `spb` = seconds per beat (60/bpm).\n * No-op for correctly trimmed loops (already an integer beat count); never\n * extends past the buffer — a too-short file can't be repaired here.\n *\n * ponytail: belt-and-braces for off-spec audio; the real fix is trimming each\n * loop to exactly `cycles × numBeats × 60/bpm` seconds at production time.\n */\nexport function quantizeLoopEnd(durationSec: number, spb: number): number {\n if (spb <= 0) return durationSec;\n const beats = Math.round(durationSec / spb);\n if (beats < 1) return durationSec; // too short to snap to a beat\n return Math.min(beats * spb, durationSec);\n}\n\n/** Snap an arbitrary bpm to the nearest available tabla tempo (default grid;\n * pass a taal's `tablaBpms()` so it never snaps to a tempo that taal lacks). */\nexport function nearestTablaBpm(bpm: number, bpms: readonly number[] = TABLA_BPMS): number {\n return bpms.reduce((best, b) => (Math.abs(b - bpm) < Math.abs(best - bpm) ? b : best), bpms[0]!);\n}\n\n/** URL of the tabla loop for a taal at a (snapped) bpm, optionally a named\n * variation (defaults to the taal's default variation — see TABLA_VARIATIONS). */\nexport function tablaUrl(base: string, taalId: string, bpm: number, variation?: string): string {\n const seg = tablaSeg(taalId, variation);\n return `${normalizeBase(base)}tabla/${seg}/${seg}${bpm}bpm.mp3`;\n}\n\n/**\n * Pitch class (0 = C) the tabla loops were recorded at: their dayan (the tuned\n * right drum) rings at Sa ≈ C — measured off the CDN loops themselves\n * (spectral peak of the stroke decays, ~529 Hz = C5 +20 cents, consistent\n * across taals and across every bpm variant, i.e. the tempo set was\n * time-stretched, not resampled). Calibration knob: re-measure and change this\n * if the loop set is ever re-recorded.\n */\nexport const TABLA_TONIC_SEMITONE = 0;\n\n/**\n * Semitones to pitch-shift a tabla loop so its dayan matches the song's Sa.\n * Wrapped to the nearer direction (−5…+6): the drum is octave-agnostic, so a\n * B tonic shifts down 1 rather than up 11.\n */\nexport function tablaShiftSemitones(tonicSemitone: number): number {\n const d = (((tonicSemitone - TABLA_TONIC_SEMITONE) % 12) + 12) % 12;\n return d > 6 ? d - 12 : d;\n}\n\n/**\n * Grain settings for a retuned tabla loop (`Tone.GrainPlayer`, which detunes\n * independently of playback rate — so the loop keeps its recorded tempo and\n * stays phase-locked).\n *\n * Why not `Tone.PitchShift` after a plain `Player`: measured offline on the\n * teentaal loop, both shift accurately (±2 and −5 semitones confirmed by\n * spectral cross-correlation), but PitchShift's delay lines push the first\n * stroke 20–35 ms late (audibly behind the melody) and smear the spectrum;\n * GrainPlayer holds the onset at ~4 ms. Grains short enough not to blur the\n * strokes, overlapped half-way so the loop stays seamless.\n */\nexport const TABLA_GRAIN_SEC = 0.06;\nexport const TABLA_GRAIN_OVERLAP_SEC = 0.03;\n\n/** URL of the metronome click. */\nexport function metronomeUrl(base: string): string {\n return `${normalizeBase(base)}metronome/metro2.mp3`;\n}\n\n/** Build the metronome click `Tone.Player`. */\nexport function createMetronome(Tone: ToneModule, base: string) {\n return new Tone.Player(metronomeUrl(base));\n}\n\n/** Tanpura pitch-class sample stems (filename = `<stem>.mp3`). */\nexport const TANPURA_PCS = ['c', 'cs', 'd', 'ds', 'e', 'f', 'fs', 'g', 'gs', 'a', 'as', 'b'] as const;\n\n/* ---- Drum kit (Western-drumset rendering of an Indian taal) ------------\n *\n * A real drumset \"translation\" of tabla bols is an established practice\n * (e.g. Sunny Jain's Drum Atlas: India — kick on sam, snare on the accented\n * tali claps, hi-hat filling/ghosting the khaali wave), not something\n * invented here. DRUM_VOICES are one-shot acoustic-kit samples (CC0-cleared\n * Apache-2.0 Tonejs/audio collection, https://github.com/Tonejs/audio,\n * already the CDN this project uses directly for the Salamander piano) —\n * same trust tier as the other CDN-hosted instruments, no new hosting.\n */\nexport const DRUM_KIT_BASE = 'https://tonejs.github.io/audio/drum-samples/acoustic-kit/';\n\nexport type DrumVoice = 'kick' | 'snare' | 'hihat' | 'tom1' | 'tom2' | 'tom3';\nconst DRUM_FILES: Record<DrumVoice, string> = {\n kick: 'kick.mp3',\n snare: 'snare.mp3',\n hihat: 'hihat.mp3',\n tom1: 'tom1.mp3',\n tom2: 'tom2.mp3',\n tom3: 'tom3.mp3',\n};\n\n/** Build the drum-kit `Tone.Players` (one-shot voices, not looped/pitched). */\nexport function createDrumKit(Tone: ToneModule, base: string = DRUM_KIT_BASE) {\n const urls: Record<string, string> = {};\n for (const [voice, file] of Object.entries(DRUM_FILES)) urls[voice] = file;\n return new Tone.Players({ urls, baseUrl: normalizeBase(base) });\n}\n\n/**\n * Per-beat drumset voice for one তাল cycle, following sam/tali/khaali theory:\n * sam (cycle start) → kick, the first beat of each accented (non-khaali)\n * vibhag → snare (the tali clap), the first beat of a khaali vibhag → closed\n * hihat (the khaali \"wave off\"), every other beat → hihat (fill, keeping the\n * kit's groove going the way a tabla's filler strokes do).\n */\nexport function drumPattern(taal: Pick<Taal, 'numBeats' | 'sam' | 'bhaags' | 'khaali'>): DrumVoice[] {\n const n = taal.numBeats;\n const sam = taal.sam ?? 0;\n const khaali = new Set(taal.khaali ?? []);\n const bhaags = taal.bhaags ?? [n];\n const pattern: DrumVoice[] = new Array(n).fill('hihat');\n\n let pos = 0;\n for (const len of bhaags) {\n pattern[pos] = khaali.has(pos) ? 'hihat' : 'snare';\n pos += len;\n }\n pattern[sam] = 'kick';\n return pattern;\n}\n\n/**\n * Build a melody `Tone.Sampler` for an instrument def. Resolves the sample\n * directory (local → under `soundsBaseUrl`, else the def's absolute CDN URL)\n * and, when a MIDI `range` is given, loads only the samples that cover it.\n */\nexport function createSampler(\n Tone: ToneModule,\n def: InstrumentDef,\n soundsBaseUrl: string | undefined,\n range?: { lo: number; hi: number },\n) {\n const base = def.local ? `${normalizeBase(soundsBaseUrl ?? '')}${def.baseUrl}` : def.baseUrl;\n const urls = range ? subsetUrls(def.urls, range.lo, range.hi) : def.urls;\n return new Tone.Sampler({ urls, baseUrl: normalizeBase(base), release: def.release ?? 1 });\n}\n\n/* ---- মীড় (meend) — the sounded glide -------------------------------------\n *\n * A মীড় is one continuous sound whose pitch travels between svaras; the notes\n * it covers are never re-struck. A `Tone.Sampler` cannot do that — it has no\n * pitch parameter at all (checked against tone 15's own typings). What it does\n * have, one layer down, is `ToneBufferSource.playbackRate`, a real AudioParam:\n * so a glide is the instrument's own sample, started once, with its playback\n * rate automated — a tape slide, which is exactly what a hardware sampler does\n * for portamento.\n *\n * The pitch is automated as an S-curve (see `sCurve`), not a straight line, and\n * it leaves the source svara only after `MEEND_HOLD` of the gap so the written\n * note keeps its identity before rolling into the next — arriving exactly on\n * the target's own matra.\n *\n * ponytail: the glide reads from a second `ToneAudioBuffers` over the same\n * URLs as the Sampler (the browser HTTP cache means no extra download, just a\n * second decode). Share one buffer set if memory ever matters.\n */\n\n/**\n * Fraction of the gap between two মীড় notes spent holding the source pitch\n * before the slide begins. 0 = slide the whole way (an alaap-slow meend);\n * 0.5 = hold half the note, then roll into the target.\n */\nexport const MEEND_HOLD = 0.5;\n\n/** Automation points per glide leg — enough to hear as continuous. */\nconst GLIDE_STEPS = 24;\n\n/** Sampler `urls` key whose pitch is nearest `midi` (the sample to slide). */\nexport function nearestSampleKey(urls: Record<string, string>, midi: number): string {\n let best = '';\n let bestDiff = Infinity;\n for (const key of Object.keys(urls)) {\n const diff = Math.abs(noteToMidi(key) - midi);\n if (diff < bestDiff) {\n bestDiff = diff;\n best = key;\n }\n }\n return best;\n}\n\n/** The same samples `createSampler` loads, as raw buffers for the glide voice. */\nexport function createBuffers(\n Tone: ToneModule,\n def: InstrumentDef,\n soundsBaseUrl: string | undefined,\n range?: { lo: number; hi: number },\n) {\n const base = def.local ? `${normalizeBase(soundsBaseUrl ?? '')}${def.baseUrl}` : def.baseUrl;\n const urls = range ? subsetUrls(def.urls, range.lo, range.hi) : def.urls;\n return { buffers: new Tone.ToneAudioBuffers({ urls, baseUrl: normalizeBase(base) }), urls };\n}\n\n/** One মীড় leg: the pitch to reach and the absolute time to reach it by. */\nexport interface GlideLeg {\n midi: number;\n /** Seconds on the transport; `legs[0]` is the attack itself. */\n at: number;\n}\n\n/**\n * Sound one মীড় phrase: a single attack on `legs[0]` whose pitch then slides\n * through every following leg, ending at `endSec`. Used by both the live\n * player and the offline export.\n */\nexport function triggerGlide(\n Tone: ToneModule,\n buffers: InstanceType<ToneModule['ToneAudioBuffers']>,\n urls: Record<string, string>,\n dest: InstanceType<ToneModule['Gain']>,\n legs: readonly GlideLeg[],\n endSec: number,\n release = 1,\n hold = MEEND_HOLD,\n): void {\n const key = nearestSampleKey(urls, legs[0]!.midi);\n if (key === '' || !buffers.has(key)) return;\n const sampleMidi = noteToMidi(key);\n const rate = (midi: number) => Math.pow(2, (midi - sampleMidi) / 12);\n\n const source = new Tone.ToneBufferSource({\n url: buffers.get(key),\n fadeOut: release,\n curve: 'exponential',\n // Bind to the destination's context explicitly. `Tone.Offline` restores the\n // global context the moment it starts rendering, so a node built inside a\n // transport callback would otherwise land on the *online* context and the\n // offline export would render the glide as silence.\n context: dest.context,\n }).connect(dest);\n // Clean up after the note — but only on a live context. An offline render\n // runs its whole clock *before* `startRendering()`, so an onended-dispose\n // would disconnect the node before a single sample was rendered (the export\n // came out silent). The offline context is discarded wholesale anyway.\n if (!dest.context.isOffline) source.onended = () => source.dispose();\n\n const rates = source.playbackRate;\n rates.setValueAtTime(rate(legs[0]!.midi), legs[0]!.at);\n for (let k = 1; k < legs.length; k++) {\n const from = legs[k - 1]!;\n const to = legs[k]!;\n const start = from.at + (to.at - from.at) * hold;\n const values: number[] = [];\n for (let n = 0; n <= GLIDE_STEPS; n++) {\n values.push(rate(from.midi + (to.midi - from.midi) * sCurve(n / GLIDE_STEPS)));\n }\n rates.setValueCurveAtTime(values, start, Math.max(to.at - start, 0.02));\n }\n source.start(legs[0]!.at, 0, Math.max(endSec - legs[0]!.at, 0.05));\n}\n\n/** Build a tanpura `Tone.Players` loading only the given pitch-class stems\n * (the drone only ever plays Sa + Pa, so we fetch 2 files, not 12). */\nexport function createTanpura(Tone: ToneModule, base: string, stems: readonly string[] = TANPURA_PCS) {\n const urls: Record<string, string> = {};\n for (const s of stems) urls[s] = `${s}.mp3`;\n return new Tone.Players({ urls, baseUrl: `${normalizeBase(base)}tanpura/` });\n}\n","/**\n * Print / \"Save as PDF\" support.\n *\n * High-fidelity PDF of আকারমাত্রিক notation can only come from the browser's\n * own print engine — it reuses the exact HarfBuzz shaping (reph, conjuncts,\n * matra) and the CSS-drawn marks (octave dots, slur arcs, danda strokes) that\n * the viewer renders on screen. Rasterizers (html2canvas) and PDF-primitive\n * libraries (jsPDF/pdfmake) have no Indic shaping and drop pseudo-element\n * marks, so we deliberately avoid them. Staff notation (lang `staff`) is drawn\n * by abcjs to SVG, which the same print engine engraves faithfully.\n *\n * `renderPrintDocument` builds a self-contained HTML page from the pure\n * `renderToHtml` + `SWARALIPI_CSS` (so it sidesteps the shadow-DOM \"print drops\n * encapsulated styles\" gotcha); `printSwaralipi` prints it via a hidden iframe.\n * Both reuse the same renderer as the viewer, so the PDF matches the screen.\n *\n * Every printed page also carries a light diagonal watermark and a notator\n * credit footer — both defaulted for gitabitan.io but overridable by consumers.\n */\nimport type { Swaralipi } from '../spec/index.js';\nimport type { ViewerLang } from './glyphs.js';\nimport { renderToHtml } from './render.js';\nimport { renderStaffHtml, type StaffOptions } from './staff.js';\nimport { SWARALIPI_CSS, SWARALIPI_PRINT_CSS, SWARALIPI_STAFF_CSS } from './styles.js';\nimport { fitSwaralipi } from './fit.js';\n\n/** Default diagonal page watermark (empty string disables it). */\nexport const DEFAULT_WATERMARK = 'www.gitabitan.io';\n/** Default notator credit printed in the footer. */\nexport const DEFAULT_NOTATOR = 'gitabitan.io Team';\n\nexport interface PrintOptions extends StaffOptions {\n /** Notation + UI language. `staff` = Western staff notation. Default `bn`. */\n lang?: ViewerLang;\n /** Render the নাম/তাল header block. Default true. */\n showHeader?: boolean;\n /** Lyric/title transliterator for hi/en (see loadLyricTransliterator). */\n transliterate?: (bengaliText: string) => string;\n /** Document `<title>` — the browser's default \"Save as PDF\" filename.\n * Defaults to the document's `meta.title`. */\n title?: string;\n /** Diagonal full-page watermark. Default `www.gitabitan.io`; '' to disable. */\n watermark?: string;\n /** Notator credited in the footer. Default `gitabitan.io Team`; '' to disable.\n * A document's `meta.notationBy` takes precedence when present. */\n notator?: string;\n}\n\nfunction escapeHtml(s: string): string {\n return s\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"');\n}\n\n/** Diagonal watermark: an SVG data-URI **background** on a fixed, empty `<div>`.\n *\n * Two constraints, and only this shape satisfies both.\n *\n * 1. IT MUST FIT. The box is unknowable from in here — a phone's print page, an A4\n * page, or a 1240×6000 rendered sheet whose `<body>` the consumer additionally\n * `zoom`s. A `vw` font-size answers to the viewport, not to that box, so the old\n * rotated `<span>` ran off the edge and was clipped: \"www.gitabitan\" with the \".io\"\n * shorn off. `preserveAspectRatio` + `background-size: contain` scale the mark into\n * whatever box it lands in, and `textLength` pins the line inside the viewBox — so it\n * fits BY CONSTRUCTION at every size, aspect ratio, zoom, watermark string and font.\n *\n * 2. IT MUST REPEAT ON EVERY PRINTED PAGE. Chrome tiles a `position: fixed` BOX per page\n * but NOT a fixed *replaced* element: an inline `<svg>`, whether fixed itself or\n * inside a fixed div, paints on page one and nowhere else (verified against a real\n * paginated PDF). A background image is part of the box's own painting, so it repeats\n * — and `print-color-adjust: exact` is what carries it past Chrome's \"Background\n * graphics\" checkbox, which is off by default.\n *\n * The SVG is an isolated document and cannot inherit the page's fonts, hence the inline\n * `sans-serif`. `font-size` then only sets the HEIGHT (textLength fixes the width), so it\n * is estimated from the character count to keep glyph proportions natural (~0.62em average\n * advance for bold sans). Capped, or a short mark like \"DRAFT\" would be stretched across\n * the whole page — there the natural width is used instead and the line simply centres. */\nfunction watermarkCss(text: string): string {\n if (!text) return '';\n const span = 92; // rotated -35° inside a 100×100 viewBox, this clears every edge\n const size = Math.min(18, span / (0.62 * text.length));\n const len = Math.min(span, 0.62 * text.length * size);\n const svg =\n '<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 100 100\" preserveAspectRatio=\"xMidYMid meet\">' +\n '<text x=\"50\" y=\"50\" dy=\".35em\" text-anchor=\"middle\" font-family=\"sans-serif\" font-weight=\"700\"' +\n ` fill=\"rgba(0,0,0,0.07)\" font-size=\"${size.toFixed(2)}\" textLength=\"${len.toFixed(2)}\"` +\n ` lengthAdjust=\"spacingAndGlyphs\" transform=\"rotate(-35 50 50)\">${escapeHtml(text)}</text></svg>`;\n return `\n.sw-watermark {\n position: fixed; inset: 0; z-index: 0; pointer-events: none;\n background: url(\"data:image/svg+xml,${encodeURIComponent(svg)}\") center / contain no-repeat;\n -webkit-print-color-adjust: exact; print-color-adjust: exact;\n}\nbody > .sw-sheet, body > .sw-footer { position: relative; z-index: 1; }\n`;\n}\n\n/** Build the body chrome (watermark layer + notator footer) shared by all langs. */\nfunction chrome(text: string, notator: string): { top: string; bottom: string } {\n const top = text ? '<div class=\"sw-watermark\" aria-hidden=\"true\"></div>' : '';\n const bottom = notator ? `<footer class=\"sw-footer\">${escapeHtml(notator)}</footer>` : '';\n return { top, bottom };\n}\n\n/** Resolve the notator: an explicit '' suppresses the footer (the header block already\n * credits the notator), else doc's meta.notationBy wins, else the option/default. */\nfunction resolveNotator(doc: Swaralipi, opts: PrintOptions): string {\n if (opts.notator === '') return '';\n return doc.meta.notationBy ?? opts.notator ?? DEFAULT_NOTATOR;\n}\n\n/** Assemble the full standalone HTML page around a rendered body fragment. */\nfunction pageHtml(lang: ViewerLang, title: string, bodyHtml: string, opts: PrintOptions, doc: Swaralipi): string {\n const watermark = opts.watermark ?? DEFAULT_WATERMARK;\n const { top, bottom } = chrome(watermark, resolveNotator(doc, opts));\n return `<!doctype html>\n<html lang=\"${escapeHtml(lang)}\">\n<head>\n<meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n<title>${escapeHtml(title)}</title>\n<style>\n${SWARALIPI_CSS}\n${SWARALIPI_STAFF_CSS}\n${SWARALIPI_PRINT_CSS}\n${watermarkCss(watermark)}\nhtml, body { margin: 0; }\n/* The printable width of A4 at the @page margin above. The sheet is one grid\n with one natural width, so the fit script needs a real page-sized box to\n measure against — the iframe's own width is not it. */\nbody { width: 178mm; color: #111; background: #fff; -webkit-print-color-adjust: exact; print-color-adjust: exact; }\n.sw-sheet { max-width: 100%; }\n.sw-footer { margin-top: 12px; padding-top: 6px; border-top: 1px solid #ddd; font-size: 12px; color: #555; text-align: right; }\n</style>\n</head>\n<body>${top}${bodyHtml}${bottom}\n<script>window.__swFit=function(){(${fitSwaralipi.toString()})(document,0.45,1,undefined,0)};window.__swFit()</script>\n</body>\n</html>`;\n}\n\n/**\n * Build a complete, standalone HTML document for printing an akarmatrik\n * (bn/hi/en) swaralipi sheet, with watermark + notator footer. Usable for a\n * hidden-iframe print, a new browser tab, or server-side headless-Chrome PDF.\n *\n * For `lang: 'staff'` this renders the grid instead (staff engraving is async\n * — use `renderStaffPrintDocument` or `printSwaralipi`, which handle it).\n */\nexport function renderPrintDocument(doc: Swaralipi, opts: PrintOptions = {}): string {\n const lang: ViewerLang = opts.lang === 'staff' ? 'bn' : opts.lang ?? 'bn';\n const tr = lang !== 'bn' && opts.transliterate ? opts.transliterate : (s: string) => s;\n const title = opts.title ?? tr(doc.meta.title);\n const body = renderToHtml(doc, { lang, showHeader: opts.showHeader, transliterate: opts.transliterate });\n return pageHtml(lang, title, body, opts, doc);\n}\n\n/**\n * Async variant that engraves staff notation (abcjs) into the print page. Falls\n * back to the grid document for non-staff langs. Returns a self-contained HTML\n * string (for headless-Chrome PDF or a print iframe).\n */\nexport async function renderStaffPrintDocument(doc: Swaralipi, opts: PrintOptions = {}): Promise<string> {\n if (opts.lang !== 'staff') return renderPrintDocument(doc, opts);\n const title = opts.title ?? doc.meta.title;\n // renderStaffHtml renders the shared নাম/তাল/আবর্তন/স্বরলিপিকার header itself\n // (same block as the grid), so the page just wraps its output.\n const staff = await renderStaffHtml(doc, opts);\n return pageHtml('en', title, staff, opts, doc);\n}\n\n/**\n * Open the browser print dialog for a swaralipi document (the user picks a\n * printer or \"Save as PDF\"). Renders into an off-screen iframe so it prints\n * only the sheet — independent of the host page's chrome and CSS — then cleans\n * up. Browser-only; throws in a non-DOM environment (use renderPrintDocument /\n * renderStaffPrintDocument for SSR / headless-Chrome instead).\n */\nexport function printSwaralipi(doc: Swaralipi, opts: PrintOptions = {}): void {\n if (typeof document === 'undefined') {\n throw new Error('printSwaralipi requires a DOM; use renderPrintDocument() for server-side PDF');\n }\n // Grid langs render synchronously (preserving the sync print contract); only\n // staff must await abcjs before the iframe exists.\n if (opts.lang === 'staff') {\n void renderStaffPrintDocument(doc, opts).then(printHtmlInIframe);\n } else {\n printHtmlInIframe(renderPrintDocument(doc, opts));\n }\n}\n\n/** Print an already-assembled HTML page via a hidden, off-screen iframe. */\nfunction printHtmlInIframe(html: string): void {\n const iframe = document.createElement('iframe');\n iframe.setAttribute('aria-hidden', 'true');\n // off-screen but rendered (display:none iframes print blank); a page-ish\n // width so rows lay out before the print stylesheet takes over.\n iframe.style.cssText = 'position:fixed; left:-10000px; top:0; width:800px; height:600px; border:0;';\n\n iframe.onload = () => {\n const win = iframe.contentWindow;\n if (win === null) {\n iframe.remove();\n return;\n }\n const cleanup = () => setTimeout(() => iframe.remove(), 1000);\n win.addEventListener('afterprint', cleanup, { once: true });\n let printed = false;\n const go = () => {\n if (printed) return;\n printed = true;\n try {\n // Re-fit with the real font metrics in place — the notation fonts\n // load after first layout and change every column's width.\n (win as Window & { __swFit?: () => void }).__swFit?.();\n win.focus();\n win.print();\n } catch {\n /* printing unavailable (e.g. headless) — leave cleanup to afterprint */\n }\n };\n // The notation is rendered ENTIRELY in the CDN notation fonts, so a\n // not-yet-downloaded face prints as raw ASCII — or blank, under\n // `font-display: block`. `fonts.ready` alone is not enough: it can resolve\n // before layout has even requested the faces. Force each declared face to\n // download, then print; a timeout prints anyway so a slow/unreachable font\n // (e.g. a lang whose CDN font isn't up yet) never blocks the dialog.\n const fonts = iframe.contentDocument?.fonts;\n if (fonts && typeof fonts.forEach === 'function') {\n const loads: Promise<unknown>[] = [Promise.resolve(fonts.ready)];\n fonts.forEach((face) => loads.push(face.load().catch(() => undefined)));\n void Promise.all(loads).then(go);\n setTimeout(go, 3000); // never let a slow/unreachable font block the dialog\n } else {\n setTimeout(go, 250);\n }\n };\n\n iframe.srcdoc = html;\n document.body.appendChild(iframe);\n}\n","/**\n * Lazy lyric transliteration for `hi` / `en` renders.\n *\n * Swara glyphs come from the sync tables in glyphs.ts; only *linguistic*\n * text (lyrics, title, names) needs transliteration, so sanscript loads via\n * dynamic import — `bn`-only consumers (and their bundles) never touch it.\n */\nimport type { GridLang, ViewerLang } from './glyphs.js';\n\nexport type Transliterator = (bengaliText: string) => string;\n\nconst TARGET: Record<Exclude<GridLang, 'bn'>, string> = {\n hi: 'devanagari',\n en: 'iast',\n};\n\n/**\n * Load a Bengali→target transliterator for the given viewer language.\n * Returns undefined for `bn` (no work to do). Pass the result as\n * `RenderOptions.transliterate`; the `<swaralipi-sheet>` element wires this\n * automatically when its `lang` attribute changes.\n */\nexport async function loadLyricTransliterator(lang: ViewerLang): Promise<Transliterator | undefined> {\n if (lang === 'bn' || lang === 'staff') return undefined; // staff has no lyric script to convert\n const mod = (await import('@indic-transliteration/sanscript')) as {\n default?: { t(text: string, from: string, to: string): string };\n t?(text: string, from: string, to: string): string;\n };\n const sanscript = mod.default ?? mod;\n const target = TARGET[lang];\n return (text) => sanscript.t!(text, 'bengali', target);\n}\n","/**\n * The `<swaralipi-sheet>` custom element — a thin shadow-DOM shell around\n * the pure renderer.\n *\n * The element class is created lazily inside defineSwaralipiSheet():\n * a top-level `extends HTMLElement` would throw on import in Node, and this\n * module must stay importable for SSR (where only renderToHtml is used).\n * Nothing registers automatically — call defineSwaralipiSheet() once.\n *\n * Validation is off by default (converter output is pre-validated); setting\n * `validate = true` parses documents against the Zod schema via a dynamic\n * import, so the viewer bundle stays free of bare runtime imports (it can\n * be loaded directly from dist/ in a browser without a bundler).\n */\nimport type { Swaralipi } from '../spec/index.js';\nimport { renderToHtml } from './render.js';\nimport { renderStaffHtml, type StaffOptions } from './staff.js';\nimport { SWARALIPI_CSS, SWARALIPI_STAFF_CSS, NOTATION_FONT_URLS } from './styles.js';\nimport { printSwaralipi, type PrintOptions } from './print.js';\nimport { fitSwaralipi, MIN_ZOOM, MAX_ZOOM, ZOOM_STEP } from './fit.js';\nimport { loadLyricTransliterator, type Transliterator } from './transliterate.js';\nimport { PRACTICE_LABELS, type ViewerLang } from './glyphs.js';\n\nexport interface SwaralipiSheetElement extends HTMLElement {\n /** The document to render (property only; renders on assignment). */\n doc: Swaralipi | undefined;\n /** Parse documents against the spec schema before rendering. */\n validate: boolean;\n /** Add the player-highlight class to the note at \"part.row.note\" — drawn\n * hollow when it is the learner's turn to sing it. */\n highlight(path: string, yourTurn?: boolean): HTMLElement | null;\n clearHighlights(): void;\n /** Shade the repeated lines (`part.row`, inclusive; null clears) and mark\n * the learner's turn on them. The player's bindSheet calls this. */\n markLoop(loop: { from: string; to: string } | null, yourTurn?: boolean): void;\n /** Open the print dialog (→ \"Save as PDF\") for the current document. */\n print(options?: PrintOptions): void;\n /** Options for the `staff` language (instrument label, tonic, bpm…). */\n staffOptions: StaffOptions;\n /** Re-fit the notation to the element's current width. */\n fit(): void;\n /** How far the column spacing may be compressed to fit a narrow container\n * before the type is scaled down at all, 0–1 (attribute `min-spacing`;\n * undefined = the library default). Lower = tighter columns, bigger glyphs. */\n minSpacing: number | undefined;\n /** Smallest notation size in px the fit may produce (attribute `min-size`);\n * past it the sheet scrolls horizontally instead of shrinking further. */\n minSize: number | undefined;\n /** Zoom factor on top of fit-to-width (1 = fit; clamped to\n * [MIN_ZOOM, MAX_ZOOM]). Assigning re-fits immediately. Resets to 1 on the\n * next doc/lang re-render — a resize alone (fit()) does not reset it. */\n zoom: number;\n /** `zoom *= ZOOM_STEP`, clamped. */\n zoomIn(): void;\n /** `zoom /= ZOOM_STEP`, clamped. */\n zoomOut(): void;\n /** Back to fit-to-width (`zoom = 1`). */\n resetZoom(): void;\n}\n\nconst LANGS: ReadonlySet<string> = new Set(['bn', 'hi', 'en', 'staff']);\n\n/** The keys a bound player answers on a focused sheet (see bindSheet). */\nconst KEYS = 'Space ArrowUp ArrowDown ArrowLeft ArrowRight Home End R T Escape Shift+ArrowUp Shift+ArrowDown';\n\n/** The element nearest `x` horizontally — a tap anywhere on a line picks the\n * note under it, so a fingertip never has to land on a 12px glyph. */\nfunction nearest(els: Element[], x: number): Element | undefined {\n let best: Element | undefined;\n let gap = Infinity;\n for (const el of els) {\n const r = el.getBoundingClientRect();\n const d = Math.abs(r.left + r.width / 2 - x);\n if (d < gap) [best, gap] = [el, d];\n }\n return best;\n}\n\n/** Browsers ignore @font-face inside a shadow root's (adopted) stylesheet —\n * faces must live at document scope, so register the notation fonts there\n * via the FontFace API. No-op without FontFace (jsdom/SSR) or for any family\n * already present (SSR CSS on the page, or a self-hoster's own declaration). */\nfunction ensureNotationFonts(): void {\n if (typeof FontFace === 'undefined' || typeof document === 'undefined') return;\n const present = new Set<string>();\n for (const f of document.fonts) present.add(f.family.replace(/['\"]/g, ''));\n for (const [family, url] of Object.entries(NOTATION_FONT_URLS)) {\n if (present.has(family)) continue;\n document.fonts.add(new FontFace(family, `url(${url})`, { display: 'block' }));\n }\n}\n\nlet sharedSheet: CSSStyleSheet | undefined;\n\nfunction createElementClass(): CustomElementConstructor {\n return class SwaralipiSheet extends HTMLElement implements SwaralipiSheetElement {\n static observedAttributes = ['src', 'lang', 'hide-header', 'min-spacing', 'min-size', 'seekable'];\n\n #doc: Swaralipi | undefined;\n #root: ShadowRoot;\n #adopted = false;\n #abort: AbortController | undefined;\n #translit: Transliterator | undefined;\n #translitLang: ViewerLang | undefined;\n #renderSeq = 0;\n #staffOptions: StaffOptions = {};\n #resize: ResizeObserver | undefined;\n #fittedAt = -1;\n #zoom = 1;\n /** Where the pointer went down, to tell a tap from a drag. */\n #down: [number, number] | undefined;\n #marks: { loop: { from: string; to: string } | null; turn: boolean } = { loop: null, turn: false };\n /** Attributes `seekable` added, and so takes away again. */\n #owned: string[] = [];\n validate = false;\n\n constructor() {\n super();\n this.#root = this.attachShadow({ mode: 'open' });\n this.#root.addEventListener('pointerdown', (e) => {\n const { clientX, clientY } = e as PointerEvent;\n this.#down = [clientX, clientY];\n });\n this.#root.addEventListener('click', (e) => this.#onClick(e as MouseEvent));\n if (\n typeof CSSStyleSheet !== 'undefined' &&\n 'replaceSync' in CSSStyleSheet.prototype &&\n 'adoptedStyleSheets' in this.#root\n ) {\n if (!sharedSheet) {\n sharedSheet = new CSSStyleSheet();\n sharedSheet.replaceSync(SWARALIPI_CSS + SWARALIPI_STAFF_CSS);\n }\n this.#root.adoptedStyleSheets = [...this.#root.adoptedStyleSheets, sharedSheet];\n this.#adopted = true;\n }\n }\n\n get doc(): Swaralipi | undefined {\n return this.#doc;\n }\n\n set doc(value: Swaralipi | undefined) {\n this.#doc = value;\n if (value !== undefined && this.validate) {\n void import('../spec/index.js')\n .then(({ safeParseSwaralipi }) => {\n const result = safeParseSwaralipi(value);\n if (!result.success) this.#renderError(result.error.message);\n })\n .catch(() => undefined);\n }\n this.#render();\n }\n\n get staffOptions(): StaffOptions {\n return this.#staffOptions;\n }\n\n set staffOptions(value: StaffOptions) {\n this.#staffOptions = value;\n if (this.#lang === 'staff') this.#render(); // live-update the score\n }\n\n get #lang(): ViewerLang {\n const attr = this.getAttribute('lang');\n return attr !== null && LANGS.has(attr) ? (attr as ViewerLang) : 'bn';\n }\n\n get #practice() {\n const lang = this.#lang;\n return PRACTICE_LABELS[lang === 'staff' ? 'en' : lang];\n }\n\n /** A tap on a line plays from the note nearest the tap: the whole line is\n * the target (WCAG 2.5.8 counts a position inside one target as picking\n * a value), fired on the up-event like any click (2.5.2). The player bound\n * by bindSheet answers it; a host can veto it with preventDefault(). */\n #onClick(e: MouseEvent): void {\n if (!this.hasAttribute('seekable') || e.button !== 0 || e.ctrlKey || e.metaKey || e.altKey) return;\n // A drag that ends here was selecting a lyric, not tapping.\n if (this.#down !== undefined && Math.hypot(e.clientX - this.#down[0], e.clientY - this.#down[1]) > 6) return;\n const target = e.target as Element;\n const row = target.closest('.sw-row');\n const notes = row === null ? [] : [...row.querySelectorAll('[data-note]:not(.sw-bar)')];\n const hit = target.closest('[data-note]:not(.sw-bar)') ?? nearest(notes, e.clientX);\n const path = hit?.getAttribute('data-note');\n if (path == null) return;\n this.dispatchEvent(\n new CustomEvent('swaralipi-seek', { detail: { path, extend: e.shiftKey }, bubbles: true, cancelable: true }),\n );\n }\n\n attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void {\n if (oldValue === newValue) return;\n if (name === 'src') {\n if (newValue !== null) void this.#load(newValue);\n return;\n }\n if (name === 'min-spacing' || name === 'min-size') {\n this.fit(); // spacing/size floors are layout-only — no re-render needed\n return;\n }\n if (name === 'seekable') {\n // Keys only reach a focused element, so a sheet a player drives joins\n // the tab order, named for what a tap does — minding whatever its host\n // set itself, and taking back only what it added.\n for (const a of this.#owned) this.removeAttribute(a);\n this.#owned = [];\n if (newValue === null) return;\n const want = { tabindex: '0', role: 'region', 'aria-label': this.#practice.sheet, 'aria-keyshortcuts': KEYS };\n for (const [a, v] of Object.entries(want)) {\n if (this.hasAttribute(a)) continue;\n this.setAttribute(a, v);\n this.#owned.push(a);\n }\n return;\n }\n if (name === 'lang' && this.#owned.includes('aria-label')) this.setAttribute('aria-label', this.#practice.sheet);\n if (name === 'lang') this.#ensureTransliterator();\n this.#render();\n }\n\n connectedCallback(): void {\n this.#ensureTransliterator();\n this.#render();\n // The sheet is one grid with one natural width; re-fit it whenever the\n // box it lives in changes (the shared columns cannot reflow).\n if (this.#resize === undefined && typeof ResizeObserver !== 'undefined') {\n this.#resize = new ResizeObserver(([entry]) => {\n // Only on a real width change: re-fitting alters the sheet's own\n // height, which would otherwise re-enter through the observer.\n const w = entry?.contentRect.width ?? -1;\n if (w === this.#fittedAt) return;\n this.#fittedAt = w;\n this.#fit();\n });\n this.#resize.observe(this);\n }\n // The notation IS the font, so a fit that lands before the faces do\n // measured fallback metrics. `document.fonts.ready` cannot be trusted to\n // catch that: read while nothing is loading it is already resolved, so on\n // a cold cache the re-fit fired before the face was even requested (and a\n // warm cache hid the bug, which is why it only bit the first load).\n // `loadingdone` fires every time the set finishes a batch, so every fit —\n // render, resize, reveal — gets its correction.\n document.fonts?.addEventListener('loadingdone', this.#onFontsLoaded);\n }\n\n #onFontsLoaded = (): void => {\n if (this.#doc !== undefined) this.fit();\n };\n\n disconnectedCallback(): void {\n this.#abort?.abort();\n this.#resize?.disconnect();\n this.#resize = undefined;\n document.fonts?.removeEventListener('loadingdone', this.#onFontsLoaded);\n }\n\n /** Scale the notation to fit the available width, times the zoom factor. */\n #fit(): void {\n fitSwaralipi(this.#root, 0, this.#zoom, this.minSpacing, this.minSize);\n }\n\n /** Numeric attribute, or undefined for fitSwaralipi's own default. */\n #attrNum(name: string): number | undefined {\n const value = parseFloat(this.getAttribute(name) ?? '');\n return Number.isFinite(value) ? value : undefined;\n }\n\n #setAttrNum(name: string, value: number | undefined): void {\n if (value === undefined) this.removeAttribute(name);\n else this.setAttribute(name, String(value));\n }\n\n get minSpacing(): number | undefined {\n return this.#attrNum('min-spacing');\n }\n\n set minSpacing(value: number | undefined) {\n this.#setAttrNum('min-spacing', value);\n }\n\n get minSize(): number | undefined {\n return this.#attrNum('min-size');\n }\n\n set minSize(value: number | undefined) {\n this.#setAttrNum('min-size', value);\n }\n\n /** Re-fit the current render (public for hosts that resize the sheet\n * themselves, e.g. a tab that was hidden while the document loaded). */\n fit(): void {\n this.#fittedAt = -1;\n this.#fit();\n }\n\n get zoom(): number {\n return this.#zoom;\n }\n\n set zoom(factor: number) {\n this.#zoom = Math.min(MAX_ZOOM, Math.max(MIN_ZOOM, factor));\n this.#fit();\n }\n\n zoomIn(): void {\n this.zoom = this.#zoom * ZOOM_STEP;\n }\n\n zoomOut(): void {\n this.zoom = this.#zoom / ZOOM_STEP;\n }\n\n resetZoom(): void {\n this.zoom = 1;\n }\n\n async #load(url: string): Promise<void> {\n this.#abort?.abort();\n const abort = new AbortController();\n this.#abort = abort;\n try {\n const res = await fetch(url, { signal: abort.signal });\n if (!res.ok) throw new Error(`fetch ${url}: HTTP ${res.status}`);\n this.doc = (await res.json()) as Swaralipi;\n } catch (err) {\n if (abort.signal.aborted) return;\n this.#renderError(err instanceof Error ? err.message : String(err));\n this.dispatchEvent(new ErrorEvent('error', { error: err, message: String(err) }));\n }\n }\n\n /** Load (once per lang) the lyric transliterator, then re-render. */\n #ensureTransliterator(): void {\n const lang = this.#lang;\n if (lang === 'bn' || this.#translitLang === lang) return;\n void loadLyricTransliterator(lang)\n .then((t) => {\n if (t === undefined || this.#lang !== lang) return;\n this.#translit = t;\n this.#translitLang = lang;\n this.#render();\n })\n .catch(() => undefined); // graceful: lyrics stay Bengali\n }\n\n #styleFallback(): string {\n return this.#adopted ? '' : `<style>${SWARALIPI_CSS}${SWARALIPI_STAFF_CSS}</style>`;\n }\n\n #render(): void {\n const seq = ++this.#renderSeq; // guards against out-of-order async staff renders\n this.#zoom = 1; // a new doc/lang starts back at fit-to-width; #fit() alone (resize) keeps it\n if (this.#doc === undefined) {\n this.#root.innerHTML = this.#styleFallback();\n return;\n }\n const lang = this.#lang;\n if (lang === 'staff') {\n const doc = this.#doc;\n void renderStaffHtml(doc, this.staffOptions)\n .then((html) => {\n if (seq !== this.#renderSeq) return;\n this.#root.innerHTML = this.#styleFallback() + html;\n this.#applyMarks();\n })\n .catch(() => undefined);\n return;\n }\n const html = renderToHtml(this.#doc, {\n lang,\n showHeader: !this.hasAttribute('hide-header'),\n transliterate: this.#translitLang === lang ? this.#translit : undefined,\n });\n this.#root.innerHTML = this.#styleFallback() + html;\n this.#applyMarks();\n this.#fit();\n }\n\n markLoop(loop: { from: string; to: string } | null, yourTurn = false): void {\n this.#marks = { loop, turn: yourTurn };\n this.#applyMarks();\n }\n\n /** Shade the repeated lines and dim the rest; the first of them carries\n * the \"your turn\" cue. A polite live region says the same aloud. */\n #applyMarks(): void {\n const { loop, turn } = this.#marks;\n const rows = [...this.#root.querySelectorAll<HTMLElement>('.sw-row')];\n const at = (row: string | undefined) => rows.findIndex((r) => r.dataset.row === row);\n const [a, b] = loop === null ? [0, -1] : [at(loop.from), at(loop.to)];\n rows.forEach((r, i) => {\n r.classList.toggle('sw-loop', i >= a && i <= b);\n if (turn && i === a) r.dataset.turn = this.#practice.turn;\n else delete r.dataset.turn;\n });\n this.#root.querySelector('.sw-block')?.classList.toggle('sw-looping', loop !== null);\n let live = this.#root.querySelector('.sw-live');\n if (live === null) {\n live = Object.assign(document.createElement('div'), { className: 'sw-live' });\n live.setAttribute('role', 'status');\n this.#root.append(live);\n }\n live.textContent = turn ? this.#practice.turn : loop !== null ? this.#practice.repeat : '';\n }\n\n #renderError(message: string): void {\n const div = document.createElement('div');\n div.className = 'sw-error';\n div.textContent = message;\n this.#root.innerHTML = this.#styleFallback();\n this.#root.appendChild(div);\n }\n\n highlight(path: string, yourTurn = false): HTMLElement | null {\n if (!/^\\d+\\.\\d+\\.\\d+$/.test(path)) return null;\n const el = this.#root.querySelector<HTMLElement>(`[data-note=\"${path}\"]`);\n el?.classList.add('sw-hl');\n el?.classList.toggle('sw-hl-turn', yourTurn);\n return el;\n }\n\n clearHighlights(): void {\n for (const el of this.#root.querySelectorAll('.sw-hl')) el.classList.remove('sw-hl', 'sw-hl-turn');\n }\n\n print(options: PrintOptions = {}): void {\n if (this.#doc === undefined) return;\n const lang = this.#lang;\n printSwaralipi(this.#doc, {\n lang,\n showHeader: !this.hasAttribute('hide-header'),\n transliterate: this.#translitLang === lang ? this.#translit : undefined,\n ...(lang === 'staff' ? this.staffOptions : {}),\n ...options,\n });\n }\n };\n}\n\n/** Per-tag constructors: a custom-element class can only be registered\n * under one name, so each tag gets its own. */\nconst registered = new Map<string, CustomElementConstructor>();\n\n/**\n * Register `<swaralipi-sheet>` (or a custom tag name). Idempotent. Throws\n * outside a DOM environment — use renderToHtml() for SSR.\n */\nexport function defineSwaralipiSheet(tagName = 'swaralipi-sheet'): CustomElementConstructor {\n if (typeof customElements === 'undefined' || typeof HTMLElement === 'undefined') {\n throw new Error('swaralipi-sheet requires a DOM; use renderToHtml() for server-side rendering');\n }\n const existing = customElements.get(tagName);\n if (existing) return existing;\n ensureNotationFonts();\n const ctor = registered.get(tagName) ?? createElementClass();\n registered.set(tagName, ctor);\n customElements.define(tagName, ctor);\n return ctor;\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/spec/lay.ts","../../src/spec/taals.ts","../../src/spec/grace.ts","../../src/spec/svara.ts","../../src/spec/schema.ts","../../src/spec/index.ts","../../src/player/schedule.ts","../../src/player/pitch.ts","../../src/player/lyrics.ts","../../src/convert/codec.ts","../../src/player/repeats.ts","../../src/viewer/render.ts","../../src/viewer/glyphs.ts","../../src/viewer/fit.ts","../../src/viewer/styles.ts","../../src/viewer/staff.ts","../../src/player/instruments.ts","../../src/viewer/print.ts","../../src/viewer/transliterate.ts","../../src/viewer/element.ts"],"names":["z","EPS","last","matra","edges","note","m","mod","escapeHtml","safeParseSwaralipi","html"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * লয় (laya) — the tempo tier a passage is sung at.\n *\n * Hindustani names the three tiers বিলম্বিত / মধ্য / দ্রুত (vilambit = slow,\n * madhya = medium, drut = fast), and Rabindrasangeet swaralipi uses the same\n * words: NLTR prints \"বিলম্বিত লয়:\" / \"দ্রুত লয়:\" at the head of the line\n * where the tempo changes (see `printedLay`).\n *\n * `meta.bpm` is the **দ্রুত** tempo — the fast one — so the tiers are\n * multipliers ≤ 1 on it and a document with no লয় marks plays exactly as it\n * did before this field existed.\n *\n * Zod-free on purpose: the viewer, player and creator import this directly\n * (the `spec/index.js` barrel would drag zod into their browser bundles — the\n * same rule as `taals.ts` and `grace.ts`).\n */\nimport type { Note, Row } from './schema.js';\n\nexport type Lay = 'drut' | 'madhya' | 'vilambit';\n\nexport const LAYS: readonly Lay[] = ['drut', 'madhya', 'vilambit'];\n\n/**\n * ### The tempo factors — change them HERE.\n *\n * Fraction of `meta.bpm` each tier is played at. Consumers override per\n * document (`meta.laySpeeds`) or per player/export call (`laySpeeds`), so\n * these are only the fallback.\n */\nexport const LAY_SPEEDS: Record<Lay, number> = {\n drut: 1,\n madhya: 0.75,\n vilambit: 0.5,\n};\n\nexport type LaySpeeds = Partial<Record<Lay, number>>;\n\n/** Resolve the factors actually in force: call option → document → default. */\nexport function resolveLaySpeeds(doc?: LaySpeeds, opt?: LaySpeeds): Record<Lay, number> {\n return { ...LAY_SPEEDS, ...doc, ...opt };\n}\n\n/**\n * The printed লয় mark: the leading lyric-only cells NLTR writes a tempo\n * change as (\"বিলম্বিত\" \"লয়:\"). Reading it means the 1738 already-converted\n * songs change tempo without being reconverted or edited.\n *\n * ponytail: matches the first word only, and only in the leading annotation\n * position where real lyrics never sit — so 'মধ্যমান' (a taal) can't trip it.\n * If a source ever writes the mark elsewhere in the row, give it `row.lay`.\n */\nconst PRINTED: Record<string, Lay> = { দ্রুত: 'drut', মধ্য: 'madhya', বিলম্বিত: 'vilambit' };\n\nexport function printedLay(notes: Note[]): Lay | undefined {\n const first = notes[0];\n if (first === undefined || first.lyric === undefined) return undefined;\n for (const k of Object.keys(first)) if (k !== 'lyric') return undefined;\n return PRINTED[first.lyric.normalize('NFC')];\n}\n\n/** The লয় this row switches to, if any: the explicit field wins over the\n * source's printed mark. `undefined` = carry on at the previous tier. */\nexport function rowLay(row: Row): Lay | undefined {\n return row.lay ?? printedLay(row.notes);\n}\n","import type { Taal } from './schema.js';\n\n/**\n * Reference definitions for the taals the player will sample:\n * adachautaal, dadra, ektaal, jhaptaal, kehrwa, rupak, shashthi, teentaal,\n * jhampak, dhamaar, rupakra, khemta.\n *\n * `numBeats` and the `bhaags` given below are standard Hindustani taal theory.\n * `bhaags` is omitted where a single canonical division isn't well-agreed\n * (adachautaal) — we assert only what's uncontested. `sam` is beat 0 for all.\n *\n * Tabla loops live under `tabla/<id>/` by default; per-taal variation and\n * skip-bpm overrides (e.g. shashthi → `tabla/shashthi-pro/`) are in\n * instruments.ts's `TABLA_VARIATIONS`.\n */\nexport const TAALS = {\n dadra: { id: 'dadra', numBeats: 6, bhaags: [3, 3], sam: 0, khaali: [3] },\n kehrwa: { id: 'kehrwa', numBeats: 8, bhaags: [4, 4], sam: 0, khaali: [4] },\n rupak: { id: 'rupak', numBeats: 7, bhaags: [3, 2, 2], sam: 0, khaali: [0] },\n jhaptaal: { id: 'jhaptaal', numBeats: 10, bhaags: [2, 3, 2, 3], sam: 0, khaali: [5] },\n ektaal: { id: 'ektaal', numBeats: 12, bhaags: [2, 2, 2, 2, 2, 2], sam: 0, khaali: [2, 6] },\n adachautaal: { id: 'adachautaal', numBeats: 14, sam: 0 },\n choutaal: { id: 'choutaal', numBeats: 12, bhaags: [2, 2, 2, 2, 2, 2], sam: 0, khaali: [2, 6] }, // চৌতাল\n shashthi: { id: 'shashthi', numBeats: 6, bhaags: [2, 4], sam: 0 }, // ষষ্ঠী\n teora: { id: 'teora', numBeats: 7, bhaags: [3, 2, 2], sam: 0 }, // টেওরা\n teentaal: { id: 'teentaal', numBeats: 16, bhaags: [4, 4, 4, 4], sam: 0, khaali: [8] },\n aratheka: { id: 'aratheka', numBeats: 16, bhaags: [4, 4, 4, 4], sam: 0, khaali: [8] }, // আড়াঠেকা\n jhampak: { id: 'jhampak', numBeats: 5, bhaags: [3, 2], sam: 0 }, // ঝম্পক\n dhamaar: { id: 'dhamaar', numBeats: 14, bhaags: [5, 2, 3, 4], sam: 0, khaali: [7] }, // ধামার\n rupakra: { id: 'rupakra', numBeats: 8, bhaags: [3, 2, 3], sam: 0 }, // রূপকড়া\n khemta: { id: 'khemta', numBeats: 12, bhaags: [3, 3, 3, 3], sam: 0, khaali: [6] }, // খেমটা\n} as const satisfies Record<string, Taal>;\n\nexport type TaalId = keyof typeof TAALS;\n\n/**\n * The name a তালফেরতা song's header prints instead of one taal (Swarabitan /\n * Gitabitan's own word; gitabitan.io's taxonomy spells it তাল-ফেরতা). The\n * taals themselves live on the rows (`row.taal`).\n */\nexport const TAAL_FERTA = 'তালফেরতা';\n\n/** Whether a printed taal name is the তালফেরতা heading (either spelling). */\nexport function isTaalFerta(name: string | undefined): boolean {\n return name !== undefined && name.normalize('NFC').replace(/[\\s-]/g, '') === TAAL_FERTA;\n}\n\n/**\n * Whether two taal marks name the same accompaniment — the তালফেরতা test.\n * `null` (মুক্তছন্দ) and `undefined` (no taal) are only equal to themselves.\n * Compared by value: a row restating the taal in force is not a change.\n */\nexport function sameTaal(a: Taal | null | undefined, b: Taal | null | undefined): boolean {\n if (a === b) return true;\n if (!a || !b) return false;\n return a.id === b.id && a.numBeats === b.numBeats && a.variation === b.variation && String(a.bhaags) === String(b.bhaags);\n}\n","/**\n * কণ / রেশ readers. Zod-free on purpose: the viewer and the player import\n * this directly (the `spec/index.js` barrel would drag zod into their\n * browser bundles — see `taals.ts` for the same rule).\n */\nimport type { Grace, Note, Svara } from './schema.js';\n\n/** Normalise a grace payload to its note list; the legacy tuple is one note. */\nexport function graceNotes(grace: Grace | undefined): Note[] {\n if (grace === undefined) return [];\n return typeof grace[0] === 'string' ? [{ svara: grace as Svara }] : (grace as Note[]);\n}\n","/**\n * Which svaras admit which alteration — স and প are অচল (immovable), ম has\n * only its তীব্র (কড়ি) form, and র গ ধ ন only their কোমল form. The notation\n * fonts encode exactly this (no glyph exists for a কোমল প), so a flag the\n * sheet cannot draw must not move the pitch either.\n *\n * Zod-free on purpose: the viewer and the player import this directly (the\n * `spec/index.js` barrel would drag zod into their browser bundles — see\n * `taals.ts` and `grace.ts` for the same rule).\n */\nimport type { SvaraLetter } from './schema.js';\n\nexport function hasKomal(letter: SvaraLetter): boolean {\n return letter === 'r' || letter === 'g' || letter === 'd' || letter === 'n';\n}\n\nexport function hasTivra(letter: SvaraLetter): boolean {\n return letter === 'm';\n}\n","import { z } from 'zod';\nimport type { Lay } from './lay.js';\n\n/**\n * swaralipi-js JSON spec — Zod schema + inferred types.\n\n/** Octave registers */\nexport const octaveSchema = z.enum([\n 'ati-mandra', // very low\n 'mandra', // low (dot below)\n 'madhyam', // middle\n 'taar', // high (ref/dot above)\n 'ati-taar', // very high\n]);\nexport type Octave = z.infer<typeof octaveSchema>;\n\n/**\n * The seven shuddha svara letters:\n * `d` = ধৈবত (dha), `n` = নিষাদ (ni). Komal/tivra are flags, not letters.\n */\nexport const svaraLetterSchema = z.enum(['s', 'r', 'g', 'm', 'p', 'd', 'n']);\nexport type SvaraLetter = z.infer<typeof svaraLetterSchema>;\n\n/** A pitch as `[octave, letter]` */\nexport const svaraSchema = z.tuple([octaveSchema, svaraLetterSchema]);\nexport type Svara = z.infer<typeof svaraSchema>;\n\n/** Microtone variants below komal (legend: অল্পকোমল / অতিকোমল). */\nexport const microtoneSchema = z.enum(['alpakomal', 'atikomal']);\nexport type Microtone = z.infer<typeof microtoneSchema>;\n\n/**\n * Barline weights. Swarabitan distinguishes the light দাঁড়ি (।) that\n * separates vibhags *within* a taal cycle from the দণ্ড (danda, I) strokes:\n * - `dari` — । vibhag separator inside the cycle\n * - `single` — I end of one taal cycle (ফেরা)\n * - `double` — II section (kali) boundary / return-to-asthayi marker\n * - `quad` — IIII end of the song\n */\nexport const barSchema = z.enum(['dari', 'single', 'double', 'quad']);\nexport type Bar = z.infer<typeof barSchema>;\n\n/**\n * A repeat-bracket edge. Brackets span a range of notes; the opening note\n * carries `{ ..., edge: 'open' }` and the closing note `{ ..., edge: 'close' }`.\n * kind: `repeat` = {} গুন্ডবন্ধনী, `skip` = () বক্রবন্ধনী (omit on repeat),\n * `alt` = [] সরল বন্ধনী (changed notes on repeat).\n */\nexport const bracketSchema = z.object({\n kind: z.enum(['repeat', 'skip', 'alt']),\n edge: z.enum(['open', 'close']),\n});\nexport type Bracket = z.infer<typeof bracketSchema>;\n\n/**\n * A কণ / রেশ payload. Historically one `Svara` tuple; real notation puts\n * *several* svaras in a grace, and each may itself be a melisma, so the\n * richer form is a list of notes — reusing `Note` brings komal/tivra/\n * microtone/sustain along for free. The tuple form stays valid, so 0.7.x\n * documents parse unchanged; read either with `graceNotes()`.\n */\nexport type Grace = Svara | Note[];\nexport const graceSchema: z.ZodType<Grace> = z.lazy(() =>\n z.union([svaraSchema, z.array(noteSchema).min(1)]),\n);\n\n/**\n * A single token in a row. A token is one of: a pitched note (`svara`),\n * a rest (`rest`), an আ-কার sustain (`sustain`), a barline (`bar`), or a\n * purely raw/undecoded cell (`raw`) — possibly carrying annotations\n * (`above`/`below`) or a lyric syllable on an otherwise empty column.\n * The `.refine` enforces that a note carries at least one of these so\n * truly empty tokens can't slip through.\n *\n * `above`/`below` make `Note` recursive, so the type is hand-written and\n * the schema is typed `z.ZodType<Note>` via `z.lazy` (all fields are\n * optional, hence input ≡ output and the annotation is sound).\n */\nexport interface Note {\n /** Pitch. Omitted for rests, sustains, and barlines. */\n svara?: Svara;\n /** কোমল (flat). */\n komal?: boolean;\n /** তীব্র / কড়ি (sharp — applies to ma). */\n tivra?: boolean;\n /** Sub-komal microtone (legend: অল্পকোমল / অতিকোমল). */\n microtone?: Microtone;\n /** Duration in মাত্রা (beats): 1 (default), 0.5, 0.25, 2, … */\n durationMatra?: number;\n /**\n * আ-কার: no new syllable attack. Alone (no `svara`) it holds the previous\n * note's pitch and vowel; combined with `svara` it is a melisma — the\n * pitch moves while the previous syllable's vowel continues (Swarabitan\n * writes these with a leading hyphen, e.g. `-sfa`).\n */\n sustain?: boolean;\n /** বিরাম: a rest of `durationMatra` beats. */\n rest?: boolean;\n /** কণ স্বর: one or more grace notes attached before this note. */\n kan?: Grace;\n /**\n * রেশ: an after-touch grace — the legend's mirror of কণ, written small to\n * the *right* of the note (\"আসল স্বরের পরে … অন্য স্বরের ঈষৎ রেশ লাগে;\n * তখন সেই স্বর ক্ষুদ্র অক্ষরে দক্ষিণ পার্শ্বে লিখিত হয়, যথা— রা˰স\").\n * Swarabitan writes it as a trailing uppercase letter (`mpaM`, `raS`).\n */\n resh?: Grace;\n /** মীড় (glide/slur) endpoint; `both` ends the arc coming in and starts the next (ণা‿পা‿ধা). */\n meend?: 'start' | 'end' | 'both';\n /**\n * অর্ধমাত্রা (ঃ): this note closes a cell whose matra unit is a *half* —\n * `সঃ` = ½ matra, `সরঃ` = two ¼s, `রাঃ` = 1½ (legend p. ১৩৫).\n * Explicit rather than derived, because durations alone cannot distinguish\n * two half-matra cells (`সঃ গঃ`) from one matra split in two (`সরা`); this\n * flag is what closes the cell and prints the ঃ.\n */\n halfMatra?: boolean;\n /** Barline. A bar token usually has no `svara`. */\n bar?: Bar;\n /** Repeat-bracket edges opening/closing on this token. */\n brackets?: Bracket[];\n /** Lyric syllable aligned under this note */\n lyric?: string;\n /** Lossless passthrough of the source cell (e.g. raw Swarabitan code). */\n raw?: string;\n /**\n * Curation only: why a converter (e.g. an image reader) doubts this cell —\n * `\"স্বর: পা? ধা?\"`. The creator outlines it until someone edits the cell or\n * accepts it, which deletes the field. Viewer and player ignore it.\n */\n review?: string;\n /**\n * Annotation notes rendered above this column: alt-on-repeat passages\n * (legend: পরিবর্তিত স্বর in [ ] শিরোদেশে), stop marks, beat numbers.\n */\n above?: Note[];\n /** Annotation notes rendered below this column. */\n below?: Note[];\n}\n\nexport const noteSchema: z.ZodType<Note> = z.lazy(() =>\n z\n .object({\n svara: svaraSchema.optional(),\n komal: z.boolean().optional(),\n tivra: z.boolean().optional(),\n microtone: microtoneSchema.optional(),\n durationMatra: z.number().positive().optional(),\n sustain: z.boolean().optional(),\n rest: z.boolean().optional(),\n kan: graceSchema.optional(),\n resh: graceSchema.optional(),\n meend: z.enum(['start', 'end', 'both']).optional(),\n halfMatra: z.boolean().optional(),\n bar: barSchema.optional(),\n brackets: z.array(bracketSchema).optional(),\n lyric: z.string().optional(),\n raw: z.string().optional(),\n review: z.string().optional(),\n above: z.array(noteSchema).optional(),\n below: z.array(noteSchema).optional(),\n })\n .refine(\n (n) =>\n n.svara !== undefined ||\n n.rest === true ||\n n.sustain === true ||\n n.bar !== undefined ||\n n.raw !== undefined ||\n (n.brackets !== undefined && n.brackets.length > 0) ||\n (n.above !== undefined && n.above.length > 0) ||\n (n.below !== undefined && n.below.length > 0) ||\n n.lyric !== undefined,\n {\n message:\n 'note must carry one of: svara, rest, sustain, bar, raw, lyric, brackets, or a non-empty above/below',\n },\n ),\n);\n\n/** লয় tier. `Lay` (and the tempo factors) live in the zod-free ./lay.js,\n * which the viewer/player import directly; `satisfies` keeps the two in step. */\nexport const laySchema = z.enum(['drut', 'madhya', 'vilambit']) satisfies z.ZodType<Lay>;\n\n/**\n * Taal definition. `numBeats` is the cycle length in মাত্রা; `bhaags` (if\n * present) must sum to `numBeats`; `sam`/`khaali` are 0-based beat indices.\n */\nexport const taalSchema = z\n .object({\n /** Player sample key, e.g. `dadra`, `teentaal`. */\n id: z.string(),\n /**\n * Which tabla loop variation to play, e.g. `pro` (CDN dir suffix). Optional\n * and additive — omitted means the taal's default variation, so existing\n * docs are unaffected. The player honors it but never exposes a variation\n * picker; selecting a non-default variation is the consumer's premium policy.\n */\n variation: z.string().optional(),\n numBeats: z.number().int().positive(),\n /** Vibhag groupings; if given, they sum to numBeats. */\n bhaags: z.array(z.number().int().positive()).optional(),\n /** Sam (cycle start) beat index, 0-based. */\n sam: z.number().int().nonnegative().optional(),\n /** Khaali (wave) beat indices, 0-based. */\n khaali: z.array(z.number().int().nonnegative()).optional(),\n })\n .refine((t) => t.bhaags === undefined || t.bhaags.reduce((a, b) => a + b, 0) === t.numBeats, {\n message: 'bhaags must sum to numBeats',\n });\nexport type Taal = z.infer<typeof taalSchema>;\n\n/** A written line of the song: a sequence of note tokens. */\nexport const rowSchema = z.object({\n /** Optional line label (e.g. a tuk/section marker). */\n label: z.string().optional(),\n /**\n * লয়: the tempo tier this row switches to, held until another row changes\n * it (absent on every row = the whole song at `meta.bpm`, i.e. দ্রুত).\n * Read it with `rowLay()`, which also picks up the mark NLTR *prints*\n * (\"বিলম্বিত লয়:\") in already-converted documents.\n */\n lay: laySchema.optional(),\n /**\n * তালফেরতা: the তাল this row switches to, held until another row changes it\n * (absent on every row = the whole song in `meta.taal`). `null` = মুক্তছন্দ\n * from here on: the accompaniment rests until a later row names a taal.\n * Independent of `lay` — either, both or neither may change on one row.\n */\n taal: taalSchema.nullable().optional(),\n /** That taal's name as printed (e.g. `ষষ্ঠী(২/৪)`) — `meta.taalName`'s twin. */\n taalName: z.string().optional(),\n notes: z.array(noteSchema),\n});\nexport type Row = z.infer<typeof rowSchema>;\n\n/** A structural section: আস্থায়ী / অন্তরা / সঞ্চারী / আভোগ, or free text. */\nexport const partSchema = z.object({\n name: z.string().optional(),\n rows: z.array(rowSchema),\n});\nexport type Part = z.infer<typeof partSchema>;\n\n/** Document-level metadata. */\nexport const metaSchema = z.object({\n title: z.string(),\n /** Cross-reference to a gitabitan.io song content id (filename, immutable). */\n songId: z.string().optional(),\n /** Source NLTR node/song id. */\n nltrId: z.number().int().optional(),\n taal: taalSchema.optional(),\n /**\n * The taal name as printed in the source (e.g. `ষষ্ঠী(২/৪)`), except\n * free rhythm which is normalised to `মুক্তছন্দ`. Always set by the NLTR\n * converter; `taal` is set only when the name resolves to a definition.\n */\n taalName: z.string().optional(),\n /** Base pitch for playback, e.g. `C`, `C#`, or the player's `cs` form. */\n tonic: z.string().optional(),\n /** Default playback tempo in matra/min. Player-only — the viewer ignores it.\n * The player adopts it on `load()` (precedence: constructor `bpm` → `setBpm`\n * tweak → this → 90). `null` is the converter's blank placeholder = unset. */\n bpm: z.number().positive().nullable().optional(),\n /** Per-document override of the লয় tempo factors (fractions of `bpm`).\n * Defaults live in `LAY_SPEEDS`; a player/export option overrides both. */\n laySpeeds: z\n .object({ drut: z.number().positive(), madhya: z.number().positive(), vilambit: z.number().positive() })\n .partial()\n .optional(),\n raag: z.string().optional(),\n /** আবর্তন: number of taal cycles, when the source states it. */\n avartan: z.number().int().positive().optional(),\n /** স্বরলিপিকার (notation author). */\n notationBy: z.string().optional(),\n /** Provenance note or URL. */\n source: z.string().optional(),\n});\nexport type Meta = z.infer<typeof metaSchema>;\n\n/** A complete swaralipi document. */\nexport const swaralipiSchema = z.object({\n /** Spec version this document targets (see SPEC_VERSION in ./index). */\n version: z.string(),\n meta: metaSchema,\n parts: z.array(partSchema),\n});\nexport type Swaralipi = z.infer<typeof swaralipiSchema>;\n","/**\n * @ugfoundation/swaralipi-js/spec\n *\n * The swaralipi JSON spec: Zod schemas, inferred TS types, and parse helpers.\n */\nimport { swaralipiSchema, type Swaralipi } from './schema.js';\n\n/** Current spec version. Documents declare the version they target. */\nexport const SPEC_VERSION = '0.14.0';\n\nexport {\n octaveSchema,\n svaraLetterSchema,\n svaraSchema,\n microtoneSchema,\n barSchema,\n bracketSchema,\n graceSchema,\n laySchema,\n noteSchema,\n rowSchema,\n partSchema,\n taalSchema,\n metaSchema,\n swaralipiSchema,\n} from './schema.js';\n\nexport type {\n Octave,\n SvaraLetter,\n Svara,\n Microtone,\n Bar,\n Bracket,\n Grace,\n Note,\n Row,\n Part,\n Taal,\n Meta,\n Swaralipi,\n} from './schema.js';\n\nexport { TAALS, TAAL_FERTA, isTaalFerta, sameTaal, type TaalId } from './taals.js';\nexport { graceNotes } from './grace.js';\nexport {\n LAYS,\n LAY_SPEEDS,\n printedLay,\n resolveLaySpeeds,\n rowLay,\n type Lay,\n type LaySpeeds,\n} from './lay.js';\nexport { hasKomal, hasTivra } from './svara.js';\n\n/** Parse + validate unknown data into a `Swaralipi`. Throws `ZodError` on failure. */\nexport function parseSwaralipi(data: unknown): Swaralipi {\n return swaralipiSchema.parse(data);\n}\n\n/** Non-throwing variant: returns Zod's `{ success, data | error }` result. */\nexport function safeParseSwaralipi(data: unknown) {\n return swaralipiSchema.safeParse(data);\n}\n","/**\n * Pure spec-doc → playback timeline. No Tone, no audio — the player turns\n * this `Schedule` into Transport events, but it is fully unit-testable on its\n * own and mirrors the viewer's spec-driven (not raw-driven) reading.\n *\n * Timing unit is the মাত্রা (matra / beat). One global beat cursor runs across\n * every part and row: NLTR \"systems\" (rows) are wraps of one continuous line,\n * and parts (asthayi → antara …) play back-to-back, so the music never pauses\n * at a row or part boundary.\n *\n * Each audible column carries the same `data-note` path the viewer emits\n * (`part.row.note`, note = absolute index into `row.notes`; see\n * src/viewer/render.ts), so `SwaralipiPlayer` can drive `highlight()` directly.\n */\nimport type { Note, Swaralipi, Taal } from '../spec/index.js';\nimport { resolveLaySpeeds, rowLay, type Lay, type LaySpeeds } from '../spec/lay.js';\nimport { sameTaal } from '../spec/taals.js';\nimport { graceMidis, parseTonic, svaraToMidi } from './pitch.js';\nimport { excerptVisits, type Excerpt } from './lyrics.js';\nimport { isSilent, playOrder } from './repeats.js';\n\nexport interface PlayEvent {\n /** Onset in matra from the start of the document. */\n beat: number;\n /** Ring length in matra (extended by following আ-কার holds). */\n durationBeats: number;\n /** Pitch as MIDI, or null for a rest / আ-কার hold column. */\n midi: number | null;\n /** MIDI of each কণ grace on this column, in written order (empty = none). */\n kan: number[];\n /** MIDI of each রেশ grace on this column, in written order (empty = none). */\n resh: number[];\n /** `part.row.note` highlight path. */\n path: string;\n kind: 'note' | 'rest' | 'sustain';\n /**\n * মীড়: this pitch is reached by **gliding** from the previous pitched event,\n * not by a new attack. The two (or more) notes are one continuous sound whose\n * pitch travels — see `meendContinuations`. Consumers pair an attack with its\n * targets via `glideTargets`.\n */\n glide?: true;\n}\n\n/**\n * One accompaniment stretch of the timeline: a লয় and a তাল held constant.\n * A new segment starts wherever either changes — they are independent marks.\n * `scale` is the fraction of the base bpm the passage sounds at, and it is\n * exactly the factor a looping accompaniment must change its own tempo by —\n * `beat` × secondsPerBeat gives its start in seconds. Always at least one\n * segment, the first at beat 0.\n */\nexport interface TempoSegment {\n /** Start, in schedule beats (see PlayEvent.beat). */\n beat: number;\n /** End, in schedule beats (= the next segment's start, or totalBeats). */\n endBeat: number;\n scale: number;\n lay: Lay;\n /** তাল in force: `meta.taal` until a row's `taal` changes it. `null` = an\n * explicit মুক্তছন্দ passage; `undefined` = the document names no taal. */\n taal?: Taal | null;\n}\n\nexport interface Schedule {\n events: PlayEvent[];\n /** Total length in matra (the cursor's final value). */\n totalBeats: number;\n /**\n * অনাগত/anacrusis offset: beats the melody must be pushed later so the song's\n * সম (sam) lands on a cyclic accompaniment's sam. Many songs begin part-way\n * through the তাল cycle (the notation's first beat-label is `2`/`3`… and the\n * সম tick `1f`/`2f`… appears a few beats in) — without a shift the pickup note\n * would sound on the tabla's sam. Derived purely from the notation's own সম\n * tick position and `meta.taal.numBeats`; 0 when the song starts on sam or has\n * no sam tick. The player/exporter apply it only when a rhythm actually loops.\n */\n pickupBeats: number;\n /** লয় / তাল stretches, in order and gapless. One entry (drut, scale 1,\n * `meta.taal`) for a document that never changes either — i.e. every\n * document written before `row.lay` / `row.taal` existed. */\n tempo: TempoSegment[];\n}\n\nexport interface ScheduleOptions {\n /** Tonic; accepts `C`, `C#`, `cs`… (see parseTonic). Default C. */\n tonic?: string;\n /** Octave of madhyam Sa (C4 = MIDI 60). Default 4. */\n baseOctave?: number;\n /** Override the লয় tempo factors (see LAY_SPEEDS / meta.laySpeeds). */\n laySpeeds?: LaySpeeds;\n /** Apply লয় at all. Default true. The staff view sets it false: it reads\n * `durationBeats` as written note values, where a 0.75 stretch is not a\n * writable duration. */\n lay?: boolean;\n /** Sing the song's form (see playOrder): each `{ }` twice, `( )` only the\n * first time, the `[ ]` notes on the repeat, and back to the asthayi at each\n * kali's end. Default false — the written order, which the staff view and\n * anything grouping events by row rely on; the player and the audio/MIDI\n * exports turn it on. */\n repeats?: boolean;\n /** Play only the notes singing these stretches of the song's text (see\n * alignLyrics / excerptVisits). Taken from the order above. */\n excerpt?: Excerpt;\n}\n\n/**\n * Below-annotation raws that are মীড় arc drawing segments (codec known-raw):\n * `w`/`x` are the left/right curled ends, the rest are straight fill pieces.\n * Lives here rather than in the viewer because **both** need it and the viewer\n * may import the player (never the reverse — that would pull Tone into it).\n */\nexport const ARC_RAW_RE = /^[wWxXyYjJeEzZ$=_<>`\\\\]+$/;\nexport const isArcRaw = (raw: string | undefined): raw is string =>\n raw !== undefined && ARC_RAW_RE.test(raw);\n\n/** The spec's `meend` as the corpus's own arc marks; `both` = close, then re-open. */\nconst MEEND_MARKS: Record<NonNullable<Note['meend']>, string> = { start: 'w', end: 'x', both: 'xw' };\n\n/**\n * Note indices in one row that lie under a মীড় arc **without opening it** —\n * i.e. every note the pitch glides *to*, as opposed to the one it glides\n * *from*.\n *\n * Swarabitan's legend defines the under-arc as \"কোনো এক স্বর যখন আর এক স্বরে\n * বিশেষরূপে গড়াইয়া যায়\" — when one svara *rolls into* another (example:\n * ণা‿পা). It is one continuous phonation, which is why 90 % of the corpus's\n * 7 419 arcs end on a melisma (a note under the *same* held syllable, lyric ৹).\n * So the notes under an arc must not be re-articulated: only the first sounds.\n *\n * Two encodings feed the same scan — the converter's below-row `w`/`x` raws\n * (every meend in the 1738-song corpus) and the spec's own `meend: start|end`\n * (what the creator writes). A cell may carry both ends (`xw` =\n * close then re-open, `wx` = an arc drawn inside the one cell), so marks are\n * read **in order** — reading them as an unordered set left a `wx` arc open and\n * slurred the next eighteen notes into a single slide. Arcs are resolved per row — exactly one arc in the\n * whole corpus wraps across a row, so cross-row state would not pay for itself.\n */\nexport function meendContinuations(notes: Note[]): Set<number> {\n const out = new Set<number>();\n /** Notes seen since the arc opened — committed only once it closes. */\n let pending: number[] | undefined;\n notes.forEach((note, i) => {\n let marks = note.meend ? MEEND_MARKS[note.meend] : '';\n for (const b of note.below ?? []) if (isArcRaw(b.raw)) marks += b.raw;\n let marked = false;\n for (const ch of marks) {\n if (ch === 'x' || ch === 'X') {\n // Closes here: this note and everything since the open are targets.\n if (pending !== undefined) for (const k of [...pending, i]) out.add(k);\n pending = undefined;\n marked = true;\n } else if (ch === 'w' || ch === 'W') {\n pending = []; // opens here: this note is the source, not a target\n marked = true;\n }\n }\n if (!marked && pending !== undefined) pending.push(i);\n });\n // An arc left open at the row's end is a notation slip (5 in 1738 songs), not\n // a glide: committing it would slur the whole rest of the line into one\n // 16-beat slide. The viewer still draws it as a system-wrap continuation.\n return out;\n}\n\n/**\n * The glide targets belonging to the attack at `events[i]`: the pitched events\n * that follow it flagged `glide`. Silent columns (আ-কার holds) are transparent\n * — the note is still ringing through them — but a rest ends the phrase.\n * Consumers skip events that are themselves `glide` (already consumed here).\n */\nexport function glideTargets(events: PlayEvent[], i: number): PlayEvent[] {\n const out: PlayEvent[] = [];\n for (let j = i + 1; j < events.length; j++) {\n const ev = events[j]!;\n if (ev.kind === 'rest') break;\n if (ev.midi === null) continue;\n if (ev.glide !== true) break;\n out.push(ev);\n }\n return out;\n}\n\n/** Schedule beats between a grace and its column's start; consecutive graces step by it. */\nexport const GRACE_STEP = 0.12;\n\n/**\n * When each grace of `ev` sounds, in written order, mirrored around the\n * column's start: a কণ (written left of its svara) touches just before it, a\n * রেশ (written right) just after — so on a hold or rest column they touch under\n * whatever is still ringing. Not at the column's end: every grace is a fresh\n * strike, and one struck just before the next column is heard as its কণ.\n */\nexport function graceTouches(ev: PlayEvent): { midi: number; beat: number }[] {\n // ponytail: a fixed step, so several graces on a very short column spill past\n // it (two রেশ on a 1/5-matra note); scale the step by column length if needed.\n return [\n ...ev.kan.map((midi, g) => ({ midi, beat: ev.beat - GRACE_STEP * (ev.kan.length - g) })),\n ...ev.resh.map((midi, g) => ({ midi, beat: ev.beat + GRACE_STEP * (g + 1) })),\n ];\n}\n\n/**\n * One line of the sheet as the practice controls move by it: a `part.row`\n * with at least one timed column. It runs from its first event to the next\n * line's (the last one to `totalBeats`), so a line's trailing bars and holds\n * belong to it. A row sung twice (a repeat, a return to the asthayi) is two\n * lines with one `row`.\n */\nexport interface Line {\n /** `part.row` — the viewer's `data-row`. */\n row: string;\n /** Index of the line's first event. */\n first: number;\n beat: number;\n endBeat: number;\n}\n\nconst rowOf = (path: string): string => path.split('.').slice(0, 2).join('.');\nconst noteOf = (path: string): number => Number(path.split('.')[2] ?? 0);\n/** Written order of two `part.row` keys. */\nexport const byRow = (a: string, b: string): number => {\n const [ap = 0, ar = 0] = a.split('.').map(Number);\n const [bp = 0, br = 0] = b.split('.').map(Number);\n return ap - bp || ar - br;\n};\n\n/** The schedule's events grouped into sheet lines, in play order. A row of\n * bars and annotations only has no events, so it is not a line; a repeat that\n * jumps back within a row starts a new one. */\nexport function scheduleLines(schedule: Pick<Schedule, 'events' | 'totalBeats'>): Line[] {\n const lines: Line[] = [];\n let note = Infinity;\n schedule.events.forEach((ev, i) => {\n const n = noteOf(ev.path);\n if (lines.at(-1)?.row !== rowOf(ev.path) || n < note) lines.push({ row: rowOf(ev.path), first: i, beat: ev.beat, endBeat: 0 });\n note = n;\n });\n lines.forEach((line, k) => (line.endBeat = lines[k + 1]?.beat ?? schedule.totalBeats));\n return lines;\n}\n\n/** Index of the line holding event `i`. */\nexport function lineAt(lines: Line[], i: number): number {\n let k = 0;\n while (k + 1 < lines.length && lines[k + 1]!.first <= i) k++;\n return k;\n}\n\n/**\n * The line `path` (`part.row[.note]`) names — its own row, else the next row\n * that sounds — sung at the pass nearest line `near` (-1: the first pass).\n * -1 when no line is at or after it.\n */\nexport function lineFor(lines: Line[], path: string, near: number): number {\n let row: string | undefined;\n for (const line of lines) if (byRow(line.row, rowOf(path)) >= 0 && (row === undefined || byRow(line.row, row) < 0)) row = line.row;\n let best = -1;\n lines.forEach((line, k) => {\n if (line.row === row && (best < 0 || Math.abs(k - near) < Math.abs(best - near))) best = k;\n });\n return best;\n}\n\n/**\n * The event a tap or a seek to `path` (`part.row.note`, or `part.row` for the\n * line's start) should start from: the first event at or after that note in\n * its own line, else the line's last one — a closing bar belongs to its line,\n * not the next — else the next line's first. A line sung more than once\n * resolves to the pass nearest event `near` (default: the first pass). A note\n * reached by a মীড় glide has no attack of its own, so the glide's source is\n * returned instead. -1 when nothing sounds from there on.\n */\nexport function eventAt(events: PlayEvent[], path: string, near = -1): number {\n const lines = scheduleLines({ events, totalBeats: 0 });\n const k = lineFor(lines, path, near < 0 ? -1 : lineAt(lines, near));\n if (k < 0) return -1;\n const end = lines[k + 1]?.first ?? events.length;\n let i = lines[k]!.first;\n if (lines[k]!.row === rowOf(path)) while (i < end - 1 && noteOf(events[i]!.path) < noteOf(path)) i++;\n while (i > 0 && events[i]!.glide === true) i--;\n return i;\n}\n\n/** A সম beat-tick: a beat-label digit carrying the reph tick (`1f`/`2F`…). It\n * marks the sam wherever it lands; the digit is a within-line vibhag number, so\n * only the trailing f/F (not the value) identifies sam. Labels live on a note's\n * `above` annotations (see the converter's beat-label handling). */\nconst SAM_TICK = /^\\d+[fF]$/;\n\n/**\n * Walk a document into a flat, time-ordered list of play events.\n *\n * - svara note → an attack at the cursor; advances by `durationMatra ?? 1`.\n * - rest → a silent column that still advances the cursor.\n * - sustain **with** svara (melisma) → a fresh attack (the pitch moves under\n * a held vowel); advances.\n * - sustain **without** svara (আ-কার hold) → no attack, but the previous\n * audible note's ring is extended; still emitted (midi null) so the lyric\n * column highlights; advances.\n * - a svara under a মীড় arc (but not the note the arc opened on) → still its\n * own event, flagged `glide`: the pitch is reached by sliding from the\n * previous attack rather than by striking again (see meendContinuations).\n * - bar / bracket-only / carrier / structural raw → ignored (no event, no\n * advance); an *undecoded* notation cell (see isSilent) instead plays as a\n * rest, so it keeps its matra and the তাল stays aligned.\n *\n * Written order by default; with `repeats` the walk follows the sung order\n * (playOrder), so a column sung twice is two events with one path.\n */\nexport function buildSchedule(doc: Swaralipi, opts: ScheduleOptions = {}): Schedule {\n const tonicPc = parseTonic(opts.tonic ?? doc.meta.tonic);\n const baseOctave = opts.baseOctave ?? 4;\n const events: PlayEvent[] = [];\n let cursor = 0;\n /** Index in `events` of the last pitched attack, for hold-extension. */\n let lastPitched = -1;\n\n // লয় and তাল: a row's mark holds until another row changes it, in written\n // order — so a repeat or a return to the asthayi sings each row at its own\n // tempo and taal, not at whatever the jump came from. `scale` < 1 stretches\n // the written matra over more schedule beats, which is what makes the\n // passage sound slower at one transport tempo.\n const speeds = resolveLaySpeeds(doc.meta.laySpeeds, opts.laySpeeds);\n const withLay = opts.lay !== false;\n const tempo: TempoSegment[] = [{ beat: 0, endBeat: 0, scale: 1, lay: 'drut', taal: doc.meta.taal }];\n const rows = new Map<string, { scale: number; lay: Lay; taal: Taal | null | undefined; glides: Set<number> }>();\n let scale = 1;\n let layNow: Lay = 'drut';\n let taal: Taal | null | undefined = doc.meta.taal;\n doc.parts.forEach((part, p) =>\n part.rows.forEach((row, r) => {\n const lay = withLay ? rowLay(row) : undefined;\n if (lay !== undefined && speeds[lay] !== scale) {\n scale = speeds[lay];\n layNow = lay;\n }\n if (row.taal !== undefined) taal = row.taal;\n rows.set(`${p}.${r}`, { scale, lay: layNow, taal, glides: meendContinuations(row.notes) });\n }),\n );\n\n const order =\n opts.repeats === true\n ? playOrder(doc)\n : doc.parts.flatMap((part, p) => part.rows.flatMap((row, r) => row.notes.map((note, i) => ({ p, r, i, note }))));\n // Each visit's matra from the song's start, and the first সম tick's (see\n // SAM_TICK) — *written* matra, so the anacrusis maths stays independent of\n // the লয়, and an excerpt keeps every note on the beat it has in the song.\n const at = [0];\n let samMatra: number | undefined;\n for (const { note } of order) {\n const m = at[at.length - 1]!;\n if (samMatra === undefined && note.above?.some((a) => a.raw !== undefined && SAM_TICK.test(a.raw))) samMatra = m;\n at.push(note.bar === undefined && !isSilent(note) ? m + (note.durationMatra ?? 1) : m);\n }\n const { visits, matra } = opts.excerpt\n ? excerptVisits(order, at, opts.excerpt, (v) => rows.get(`${v.p}.${v.r}`)!.taal?.numBeats)\n : { visits: order, matra: 0 };\n let rowNow = '';\n for (const { p, r, i, note } of visits) {\n const row = rows.get(`${p}.${r}`)!;\n if (rowNow !== `${p}.${r}`) {\n rowNow = `${p}.${r}`;\n // The two marks are independent, so a segment starts wherever either moves.\n const last = tempo[tempo.length - 1]!;\n if (row.scale !== last.scale || !sameTaal(row.taal, last.taal)) {\n const seg: TempoSegment = { beat: cursor, endBeat: cursor, scale: row.scale, lay: row.lay, taal: row.taal };\n // Two marks with nothing between them are one switch, not a 0-beat segment.\n if (last.beat === cursor) tempo[tempo.length - 1] = seg;\n else {\n last.endBeat = cursor;\n tempo.push(seg);\n }\n }\n }\n if (note.bar !== undefined || isSilent(note)) continue;\n const path = `${p}.${r}.${i}`;\n const written = note.durationMatra ?? 1;\n const dur = written / row.scale;\n // Any column that takes time can carry graces, a hold or rest included.\n const kan = graceMidis(note.kan, tonicPc, baseOctave);\n const resh = graceMidis(note.resh, tonicPc, baseOctave);\n\n if (note.svara !== undefined) {\n // svara note or melisma — a real attack, unless a মীড় glides into it.\n events.push({\n beat: cursor,\n durationBeats: dur,\n midi: svaraToMidi(note, tonicPc, baseOctave),\n kan,\n resh,\n path,\n kind: note.sustain === true ? 'sustain' : 'note',\n ...(row.glides.has(i) && lastPitched >= 0 ? { glide: true as const } : {}),\n });\n lastPitched = events.length - 1;\n } else if (note.sustain === true) {\n // আ-কার hold — extend the ringing note, emit a silent highlight column.\n if (lastPitched >= 0) events[lastPitched]!.durationBeats += dur;\n events.push({ beat: cursor, durationBeats: dur, midi: null, kan, resh, path, kind: 'sustain' });\n } else {\n // rest.\n events.push({ beat: cursor, durationBeats: dur, midi: null, kan, resh, path, kind: 'rest' });\n }\n cursor += dur;\n }\n\n // Anacrusis: shift the melody so its sam falls on a cyclic sam. If the first\n // note is at matra M and sam at S in an N-beat cycle, the shift is\n // (M − S) mod N (a partial-to-full cycle count-in; 0 when the song already\n // starts on sam). No সম tick: the song's first note is sam. The opening\n // taal's cycle — the one the count-in is played in.\n const numBeats = tempo[0]!.taal?.numBeats;\n const pickupMatra =\n numBeats !== undefined && numBeats > 0 ? (((matra - (samMatra ?? 0)) % numBeats) + numBeats) % numBeats : 0;\n tempo[tempo.length - 1]!.endBeat = cursor;\n\n // The count-in is played at the tempo the song *starts* in.\n return { events, totalBeats: cursor, pickupBeats: pickupMatra / tempo[0]!.scale, tempo };\n}\n","/**\n * Pure svara → pitch math for the player. No Tone, no audio — unit-testable\n * in plain Node and shared by the scheduler.\n *\n * The model: a tonic (Sa) pitch-class + a per-note scale degree + octave\n * register + komal/tivra/microtone accidentals → an absolute MIDI number,\n * which the Tone.Sampler pitch-shifts from the nearest santoor sample.\n */\nimport { graceNotes } from '../spec/grace.js';\nimport { hasKomal, hasTivra } from '../spec/svara.js';\nimport type { Note, Octave, SvaraLetter } from '../spec/index.js';\n\n/** Octave register offset in octaves, relative to madhyam (middle). */\nexport const OCTAVE_OFFSET: Record<Octave, number> = {\n 'ati-mandra': -2,\n mandra: -1,\n madhyam: 0,\n taar: 1,\n 'ati-taar': 2,\n};\n\n/**\n * Shuddha (natural) scale degrees in semitones above Sa — the Bilawal/major\n * thaat that Rabindrasangeet swaralipi notates against. `d` = dha, `n` = ni\n * (standard sargam letter convention).\n */\nexport const SHUDDHA: Record<SvaraLetter, number> = {\n s: 0,\n r: 2,\n g: 4,\n m: 5,\n p: 7,\n d: 9,\n n: 11,\n};\n\n/** Sharp-spelled pitch-class names, index = semitone 0–11. */\nconst SHARP_NAMES = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B'] as const;\n\n/** Pitch-class lookup. Accepts sharps (`C#`, `Cs`, `cs`) and flats (`Db`). */\nconst PITCH_CLASS: Record<string, number> = {\n c: 0,\n 'c#': 1,\n db: 1,\n d: 2,\n 'd#': 3,\n eb: 3,\n e: 4,\n 'e#': 5,\n fb: 4,\n f: 5,\n 'f#': 6,\n gb: 6,\n g: 7,\n 'g#': 8,\n ab: 8,\n a: 9,\n 'a#': 10,\n bb: 10,\n b: 11,\n 'b#': 0,\n cb: 11,\n};\n\n/**\n * Parse a tonic string to a pitch-class 0–11. Accepts `C`, `C#`, `Db`, and\n * the player/sample lowercase-`s` sharp form (`cs`, `Cs`); case-insensitive.\n * Unknown input falls back to 0 (C).\n */\nexport function parseTonic(tonic: string | undefined): number {\n if (!tonic) return 0;\n const key = tonic.trim().toLowerCase().replace(/s/g, '#');\n return PITCH_CLASS[key] ?? 0;\n}\n\n/**\n * Semitone of a note relative to Sa (degree + accidentals), ignoring octave.\n * Returns null when the note carries no pitch (rest/sustain-hold/bar).\n *\n * Microtones (অল্পকোমল/অতিকোমল) are approximated to the komal pitch — a\n * documented v1 limitation (the sampler can't bend a sub-komal microtone\n * cleanly per note); matches the viewer's placeholder treatment.\n */\nexport function svaraSemitone(note: Note): number | null {\n if (note.svara === undefined) return null;\n const [, letter] = note.svara;\n let semi = SHUDDHA[letter];\n // Only alter what the notation can actually draw: স/প are অচল and ম has no\n // কোমল form, so a stray flag on one of those must sound as written (the\n // viewer falls back to the shuddha glyph — see glyphs.ts).\n if ((note.komal === true || note.microtone !== undefined) && hasKomal(letter)) semi -= 1;\n if (note.tivra === true && hasTivra(letter)) semi += 1;\n return semi;\n}\n\n/**\n * Absolute MIDI for a note, or null when it has no pitch. madhyam Sa lands on\n * the tonic in octave `baseOctave` (C4 = MIDI 60). Out-of-sample registers\n * are produced by the Sampler pitch-shifting from the nearest recorded note.\n */\nexport function svaraToMidi(note: Note, tonicPc: number, baseOctave = 4): number | null {\n const semi = svaraSemitone(note);\n if (semi === null || note.svara === undefined) return null;\n const [octave] = note.svara;\n return (baseOctave + 1 + OCTAVE_OFFSET[octave]) * 12 + tonicPc + semi;\n}\n\n/** MIDI of a কণ/রেশ grace: one pitch per grace svara, in written order.\n * Goes through `svaraToMidi`, so a komal/tivra grace sounds as written (the\n * legacy tuple form carries no accidentals and is shuddha by construction). */\nexport function graceMidis(\n grace: Note['kan'],\n tonicPc: number,\n baseOctave = 4,\n): number[] {\n return graceNotes(grace)\n .map((n) => svaraToMidi(n, tonicPc, baseOctave))\n .filter((m): m is number => m !== null);\n}\n\n/** MIDI → Tone note name (`C#4`). */\nexport function midiToSampleName(midi: number): string {\n const pc = ((midi % 12) + 12) % 12;\n const octave = Math.floor(midi / 12) - 1;\n return `${SHARP_NAMES[pc]}${octave}`;\n}\n\n/** MIDI → santoor sample filename stem (`cs4`): lowercase, `#` → `s`. */\nexport function sampleFileName(midi: number): string {\n return midiToSampleName(midi).toLowerCase().replace('#', 's');\n}\n\n/**\n * Logistic S-curve on [0, 1], normalised so f(0) = 0 and f(1) = 1.\n *\n * A মীড় is **not** a linear ramp. The hand (or the voice) accelerates away\n * from the source pitch and decelerates into the target — \"if the pull is too\n * fast, the melody loses its vocal quality; if it is too slow, the note dies\n * before reaching its destination\". That S shape is the established model for\n * portamento pitch contours (Yang & Chew's logistic fit, ISMIR 2016), and its\n * coefficient has a direct musical meaning: `steepness` is how abruptly the\n * pitch leaves one svara for the next.\n */\nexport function sCurve(x: number, steepness = 8): number {\n const t = Math.min(Math.max(x, 0), 1);\n const logistic = (u: number) => 1 / (1 + Math.exp(-steepness * (u - 0.5)));\n const lo = logistic(0);\n return (logistic(t) - lo) / (logistic(1) - lo);\n}\n","/**\n * Where in the song's text each note sings, and which notes sing a stretch of it.\n *\n * A swaralipi's lyric row is phonetic and split into syllables (আ|বা|র্, চি|ৎ|ত,\n * ৹ for a held syllable), and it often writes a refrain out again. So the\n * notation's letters are aligned to the text by global alignment\n * (Needleman–Wunsch) that may also jump to any word start, the way JumpDTW lets\n * a score re-enter its own repeat blocks (Fremerey, Müller & Clausen, ISMIR\n * 2010). Over gitabitan's 1827 song/notation pairs it aligns 97.9 % of the\n * notation's letters; the rest are songs whose text is only a fragment.\n */\nimport type { Swaralipi } from '../spec/schema.js';\nimport type { Visit } from './repeats.js';\n\n/** `part.row.note` → the `[start, end)` UTF-16 offsets of the text it sings. */\nexport type LyricMap = Map<string, [number, number]>;\n\n/** Play only the notes singing these `[start, end)` stretches of the text, in order. */\nexport interface Excerpt {\n lyrics: LyricMap;\n ranges: [number, number][];\n}\n\nconst MATCH = 2;\nconst GAP = 1;\nconst JUMP = 4;\nconst RUN = 3;\n// 98 % of the corpus's misspelt syllables run under 8 unplaced letters.\nconst STRAY = 8;\nconst EPS = 1e-6;\nconst [DIAG, UP, LEFT, JUMPED] = [1, 2, 3, 4];\n\n/** The letters two spellings share: virama, nukta and ৹ dropped, খণ্ড ত read as ত. */\nconst letters = (s: string): string =>\n s\n .normalize('NFD')\n .replace(/ৎ/g, 'ত')\n .replace(/[^\\p{L}\\p{M}]|[়্]/gu, '')\n .toLowerCase();\n\n/** Each note of `doc` that sings a letter of `text`, with the stretch of `text` it sings. */\nexport function alignLyrics(doc: Swaralipi, text: string): LyricMap {\n const sung: { letter: string; path: string }[] = [];\n doc.parts.forEach((part, p) =>\n part.rows.forEach((row, r) =>\n row.notes.forEach((note, i) => {\n for (const letter of letters(note.lyric ?? '')) sung.push({ letter, path: `${p}.${r}.${i}` });\n }),\n ),\n );\n const said: { letter: string; from: number; to: number }[] = [];\n const starts: number[] = [];\n let at = 0;\n let gap = true;\n for (const ch of text) {\n const ls = letters(ch);\n if (ls === '') {\n gap ||= /[\\s\\p{P}]/u.test(ch);\n // A virama / nukta / joiner belongs to the letter before it, so a span never splits a conjunct's marks off.\n if (/[\\p{M}\\p{Cf}]/u.test(ch) && said.at(-1)?.to === at) said.at(-1)!.to += ch.length;\n } else {\n if (gap) starts.push(said.length);\n gap = false;\n }\n for (const letter of ls) said.push({ letter, from: at, to: at + ch.length });\n at += ch.length;\n }\n\n const n = sung.length;\n const m = said.length;\n const w = m + 1;\n const from = new Uint8Array((n + 1) * w);\n const best = new Int32Array(n + 1);\n // Before any letter is sung the text starts at its top; anywhere else costs a jump.\n let prev = new Int32Array(w).fill(-(2 ** 30));\n prev[0] = 0;\n let cur = new Int32Array(w);\n /** Jump from the row's best cell to every word start, then let the row skip text letters. */\n const settle = (i: number, row: Int32Array): void => {\n for (let j = 1; j < w; j++) if (row[j]! > row[best[i]!]!) best[i] = j;\n for (const s of starts) {\n if (row[best[i]!]! - JUMP > row[s]!) {\n row[s] = row[best[i]!]! - JUMP;\n from[i * w + s] = JUMPED;\n }\n }\n for (let j = 1; j < w; j++) {\n if (row[j - 1]! - GAP > row[j]!) {\n row[j] = row[j - 1]! - GAP;\n from[i * w + j] = LEFT;\n }\n }\n };\n settle(0, prev);\n for (let i = 1; i <= n; i++) {\n cur[0] = prev[0]! - GAP;\n from[i * w] = UP;\n for (let j = 1; j < w; j++) {\n const diag = prev[j - 1]! + (sung[i - 1]!.letter === said[j - 1]!.letter ? MATCH : -GAP);\n const up = prev[j]! - GAP;\n cur[j] = Math.max(diag, up);\n from[i * w + j] = diag >= up ? DIAG : UP;\n }\n best[i] = 0;\n settle(i, cur);\n [prev, cur] = [cur, prev];\n }\n\n // Trace back from the best end, collecting the letters that agree.\n const pairs: [number, number][] = [];\n let j = 0;\n for (let k = 1; k < w; k++) if (prev[k]! > prev[j]!) j = k;\n for (let i = n; i > 0; ) {\n const step = from[i * w + j];\n if (step === JUMPED) j = best[i]!;\n else if (step === LEFT) j--;\n else if (step === UP) i--;\n else {\n if (sung[i - 1]!.letter === said[j - 1]!.letter) pairs.push([i - 1, j - 1]);\n i--;\n j--;\n }\n }\n pairs.reverse();\n // A lone agreeing letter (a vowel sign past the text's end) is chance, not\n // the same word: only RUN sung letters agreeing in a row place a note. A row\n // carries on into the text's next letter, or across a jump to a word start,\n // so a short word sung over and over (আয়্ আয়্) holds.\n const wordStart = new Set(starts);\n const follows = (k: number): boolean =>\n pairs[k]![0] === pairs[k - 1]![0] + 1 && (pairs[k]![1] === pairs[k - 1]![1] + 1 || wordStart.has(pairs[k]![1]));\n const out: LyricMap = new Map();\n /** The text letter each note's span ends on: a syllable grows only by the letter after it. */\n const last = new Map<string, number>();\n for (let a = 0, b = 1; a < pairs.length; a = b++) {\n while (b < pairs.length && follows(b)) b++;\n if (b - a < RUN) continue;\n for (const [s, t] of pairs.slice(a, b)) {\n const { path } = sung[s]!;\n const { from: lo, to: hi } = said[t]!;\n const span = out.get(path);\n if (span === undefined) out.set(path, [lo, hi]);\n else if (t === last.get(path)! + 1) span[1] = hi;\n else continue;\n last.set(path, t);\n }\n }\n return out;\n}\n\nconst mod = (a: number, n: number): number => ((a % n) + n) % n;\nconst sings = (v: Visit): boolean => v.note.svara !== undefined || v.note.sustain === true;\n\n/**\n * The visits of `order` that sing `excerpt`, and the matra (in `at`, each\n * visit's written matra in the whole song) the first one starts on.\n *\n * Each range plays the song's form while its words stay inside the range — a\n * `{ }` repeat, a return to the asthayi — from its first sung note to the last\n * one before the words leave it. Rests and held syllables go with it; a range\n * the notation does not sing is left out. Between two ranges a rest keeps the\n * next one on the beat it has in the whole song, so the taal never breaks.\n */\nexport function excerptVisits(\n order: Visit[],\n at: number[],\n { lyrics, ranges }: Excerpt,\n cycle: (v: Visit) => number | undefined,\n): { visits: Visit[]; matra: number } {\n // Where each visit sings in the text; -1 for words the text does not have\n // (another stanza, another song): a stretch of STRAY or more letters the\n // alignment left unplaced. A shorter one is a syllable spelt otherwise.\n const pos = order.map((v) => lyrics.get(`${v.p}.${v.r}.${v.i}`)?.[0]);\n for (let a = 0; a < order.length; a++) {\n if (pos[a] !== undefined || letters(order[a]!.note.lyric ?? '') === '') continue;\n let b = a;\n let stray = 0;\n while (b < order.length && pos[b] === undefined) stray += letters(order[b++]!.note.lyric ?? '').length;\n if (stray >= STRAY) pos.fill(-1, a, b);\n a = b;\n }\n\n const visits: Visit[] = [];\n let first: number | undefined;\n let end = 0;\n for (const [lo, hi] of ranges) {\n const inside = (k: number): boolean | undefined => (pos[k] === undefined ? undefined : pos[k]! >= lo && pos[k]! < hi);\n const a = order.findIndex((_, k) => inside(k) === true);\n if (a < 0) continue;\n let b = a + 1;\n while (b < order.length && inside(b) !== false) b++;\n while (b - 1 > a && !sings(order[b - 1]!)) b--;\n const n = cycle(order[a]!);\n if (first === undefined) first = a;\n else if (n !== undefined) {\n // ponytail: phase is the whole song's matra mod this taal's cycle, so a jump across a তালফেরতা change is approximate.\n const gap = mod(at[a]! - at[end]!, n);\n if (gap > EPS) visits.push({ ...order[end - 1]!, note: { rest: true, durationMatra: gap } });\n }\n visits.push(...order.slice(a, b));\n end = b;\n }\n return { visits, matra: first === undefined ? 0 : at[first]! };\n}\n","/**\n * The Swarabitan ASCII codec: decode one grid-cell text into spec `Note`s.\n *\n * NLTR renders notation through the legacy \"Swarabitan\" webfont, which maps\n * ASCII to akarmatrik glyphs. The table below was derived by dumping every\n * glyph of `Swarabitan.woff` (tools/font-dump/) and cross-checking against\n * the Swarabitan legend scans, the rendered reference screenshot of song\n * 4270, and corpus-wide token statistics. Evidence per assignment:\n *\n * Letters (full-size glyphs):\n * s=স r=র g=গ m=ম p=প q=ধ n=ন — the seven shuddha letters\n * d=দ (komal dha) t=জ্ঞ (komal ga) — legend: কোমল র—ঋ, কোমল গ—জ্ঞ,\n * k=ক্ষ (tivra ma) u=ণ (komal ni) — কড়ি ম—ক্ষ, কোমল ধ—দ, কোমল ন—ণ\n * v=ঋ (komal re)\n * Modifiers:\n * f = রেফ above → taar octave (zero-width high combining mark)\n * h = হসন্ত below → mandra octave (low combining mark; corpus nh/uh/dh/ph)\n * leading '-' = no new vowel attack (melisma; lyric row shows ৹)\n * trailing 'a' = the আ-কার matra carrier; k letter-units in one cell\n * share it → k notes of 1/k matra each\n * UPPERCASE letter = small raised form = কণ (kan/grace) prefix; takes its\n * own f/h (corpus: Sfua, NHsa, QHpha); width ratios ~0.65\n * confirm uppercase↔lowercase pairing\n * Structurals (own cells):\n * A = thin full-height bar → দাঁড়ি vibhag separator (fixed columns)\n * l = serif danda I → cycle end; ll / single-glyph L = section\n * %=সা &=নি — precomposed one-matra forms (rare)\n * Known-but-kept-raw marks (drawn pieces the spec doesn't model yet):\n * w x = left/right ends of a long under-arc; E J j y $ < > = _ = arc/line\n * fill segments; | = thin yugal-dari stop mark (mostly annotation rows);\n * digits/!/@ (+f/F sam tick) = taal beat labels; b=× o O e ` + , . i : ;\n * = dots/ticks/duration marks; B C * ^ ~ c = rare precomposed/legacy forms.\n *\n * Decoding never throws: any chunk outside the grammar becomes a raw-only\n * note and is reported as unknown — zero data loss by construction.\n */\nimport type { Note, Octave, Svara, SvaraLetter } from '../spec/index.js';\n\nexport interface CellDecode {\n notes: Note[];\n /** Chunks that failed the grammar (reported, kept as raw notes). */\n unknownTokens: string[];\n /** Chunks understood but intentionally left raw (marks, beat labels …). */\n knownRawTokens: string[];\n /** True if at least one chunk decoded to a semantic note. */\n decoded: boolean;\n}\n\ninterface LetterDef {\n letter: SvaraLetter;\n komal?: true;\n tivra?: true;\n}\n\n/** ASCII → svara letter (+ komal/tivra). The five non-shuddha glyph letters\n * are distinct characters in akarmatrik, so the flags live here. */\nconst LETTERS: Record<string, LetterDef> = {\n s: { letter: 's' },\n r: { letter: 'r' },\n g: { letter: 'g' },\n m: { letter: 'm' },\n p: { letter: 'p' },\n q: { letter: 'd' }, // ধ — shuddha dha\n n: { letter: 'n' },\n d: { letter: 'd', komal: true }, // দ\n t: { letter: 'g', komal: true }, // জ্ঞ\n k: { letter: 'm', tivra: true }, // ক্ষ\n u: { letter: 'n', komal: true }, // ণ\n v: { letter: 'r', komal: true }, // ঋ\n};\n\n/** Standalone structural tokens (bars are handled by the bar-run rule). */\nconst STRUCTURALS: Record<string, () => Note> = {\n '%': () => ({ svara: ['madhyam', 's'] }), // precomposed সা\n '&': () => ({ svara: ['madhyam', 'n'] }), // precomposed নি\n};\n\n/**\n * Bar/bracket runs: `l`(I danda) `ll`/`L`(II) `llll`/`LL`(IIII) `A`(দাঁড়ি),\n * plus composites the corpus writes into one cell — `l[]l` / `L[]L` (the\n * legend's \"I [ ] I\" return-to-asthayi-with-changed-notes marker), `AA`,\n * and `-A` (the previous note's continuation dash sharing the dari's cell).\n */\nconst BAR_RUN_RE = /^(-)?([lLA[\\]]+)$/;\n\nfunction decodeBarRun(body: string): Note[] | undefined {\n const m = body.match(BAR_RUN_RE);\n if (!m || !/[lLA]/.test(m[2]!)) return undefined;\n const notes: Note[] = [];\n if (m[1]) notes.push({ sustain: true });\n const run = m[2]!;\n let i = 0;\n while (i < run.length) {\n const ch = run[i]!;\n if (ch === 'l' || ch === 'L') {\n let j = i;\n while (j < run.length && run[j] === ch) j++;\n const strokes = (j - i) * (ch === 'L' ? 2 : 1);\n notes.push({ bar: strokes >= 4 ? 'quad' : strokes >= 2 ? 'double' : 'single' });\n i = j;\n } else if (ch === 'A') {\n notes.push({ bar: 'dari' });\n i++;\n } else {\n notes.push({ brackets: [{ kind: 'alt', edge: ch === '[' ? 'open' : 'close' }] });\n i++;\n }\n }\n return notes;\n}\n\n/** Marks/labels that are understood but deliberately preserved raw-only. */\nconst KNOWN_RAW_RE = [\n /^[wxyjEJ$<>=_]+$/, // arc & line drawing segments\n /^\\|+$/, // thin yugal-dari stop mark\n /^[0-9!@#]{1,2}[fF]?:?$/, // beat-number labels incl. 10–16 (sam tick = f/F, e.g. 1f / 1F / 2:)\n /^[oOe`+,.;:iI~^*bcBCWXYFHZz'\"?]$/, // dots, ticks, duration marks, legacy forms\n];\n\nconst OPEN_BRACKETS: Record<string, 'repeat' | 'skip' | 'alt'> = {\n '{': 'repeat',\n '(': 'skip',\n '[': 'alt',\n};\nconst CLOSE_BRACKETS: Record<string, 'repeat' | 'skip' | 'alt'> = {\n '}': 'repeat',\n ')': 'skip',\n ']': 'alt',\n};\n\nfunction octaveOf(mark: string | undefined): Octave {\n if (mark === 'f' || mark === 'F') return 'taar';\n if (mark === 'h' || mark === 'H') return 'mandra';\n return 'madhyam';\n}\n\n/**\n * Body grammar of one chunk (brackets already peeled):\n *\n * [beat-digit] ['-'] [KAN] unit* ['a'] [fh] [i:] [KAN] [beat-digit]\n *\n * where unit = letter [fh] and KAN = uppercase letter [fFhH]. Corpus\n * realities beyond the canonical `[-]KAN unit+ a` shape:\n * - octave mark typed after the আ-কার: `saf` ≡ `sfa` (taar sa) — the reph\n * applies to the last unit;\n * - trailing `i` (two stacked rings, ঃ-shaped) or `:` (two lozenges — a\n * different glyph) after the matra: a **matra sign worth ½**, the আ-কার's\n * half-brother (legend `রাঃ` = 1½, `সঃ` = ½; corpus rows fit their taal\n * cycle 114:19 in favour of that reading over \"articulation only\"). The\n * durations below still ignore it — they split the cell evenly among its\n * units, so `qinqi` decodes ⅓⅓⅓ where the sheet says ½ ¼ ¼. The viewer\n * reads the marks off `raw` and draws them right (viewer/render.ts\n * `rawMarks`); playback is what the even split still gets wrong;\n * - trailing KAN (`-aR`): an anticipatory grace drawn at the cell's right\n * edge, leading into the next note — attached to this cell's last note;\n * - the cut mark may also lead or sit between units (`-iqi`, `mpimi`);\n * - leading `z` = blank spacer glyph (empty outline in the font) — skipped.\n * A standalone detached `a` (no hyphen) is a 1-matra rest per the legend\n * (\"হাইফেন-বর্জিত … বিরামের মাত্রা\").\n */\nconst BODY_RE =\n /^([0-9!@][fF]?)?([zj]*)(-)?([i:])?(?:([SRGMPQNDTKUV])([fFhH])?)?((?:[srgmpqndtkuv][fh]?[i:]?)+)?(a)?([fh])?([i:])?(?:([SRGMPQNDTKUV])([fFhH])?)?([0-9!@][fF]?)?(-)?$/;\n\nfunction decodeChunk(chunk: string): { notes: Note[]; kind: 'decoded' | 'known' | 'unknown' } {\n // 1. Peel brackets.\n const opens: ('repeat' | 'skip' | 'alt')[] = [];\n const closes: ('repeat' | 'skip' | 'alt')[] = [];\n let body = chunk;\n while (body.length > 0) {\n const kind = OPEN_BRACKETS[body[0]!];\n if (kind === undefined) break;\n opens.push(kind);\n body = body.slice(1);\n }\n while (body.length > 0) {\n const kind = CLOSE_BRACKETS[body[body.length - 1]!];\n if (kind === undefined) break;\n closes.unshift(kind);\n body = body.slice(0, -1);\n }\n\n const finish = (notes: Note[], kind: 'decoded' | 'known' | 'unknown') => {\n if (notes.length === 0) notes.push({});\n const first = notes[0]!;\n const last = notes[notes.length - 1]!;\n if (opens.length > 0) first.brackets = [...opens.map((kind_) => ({ kind: kind_, edge: 'open' as const })), ...(first.brackets ?? [])];\n if (closes.length > 0) last.brackets = [...(last.brackets ?? []), ...closes.map((kind_) => ({ kind: kind_, edge: 'close' as const }))];\n return { notes, kind };\n };\n\n // 2. Bracket-only chunk → raw carrier for the bracket edges.\n if (body === '') return finish([{}], 'decoded');\n\n // 3. Bar/bracket runs, then the remaining standalone structurals.\n const barRun = decodeBarRun(body);\n if (barRun) return finish(barRun, 'decoded');\n const structural = STRUCTURALS[body];\n if (structural) return finish([structural()], 'decoded');\n\n // 4. Known raw marks.\n if (KNOWN_RAW_RE.some((re) => re.test(body))) return finish([{}], 'known');\n\n // 5. Note grammar.\n const m = body.match(BODY_RE);\n if (m) {\n const [, , , hyphen, , kanLetter, kanOct, unitsStr, aakar, postOct, , trailKan, trailKanOct] = m;\n const attachKan = (note: Note, letter: string, oct: string | undefined) => {\n const def = LETTERS[letter.toLowerCase()]!;\n // NOTE: the spec kan is a plain [octave, letter] tuple, so a komal\n // kan letter (e.g. D = small দ) is projected onto its shuddha\n // letter; the exact glyph stays recoverable from `raw`.\n note.kan = [octaveOf(oct?.toLowerCase()), def.letter] as Svara;\n };\n if (unitsStr) {\n const units = unitsStr.match(/[srgmpqndtkuv][fh]?/g) ?? [];\n const notes: Note[] = units.map((unit) => {\n const def = LETTERS[unit[0]!]!;\n const note: Note = { svara: [octaveOf(unit[1]), def.letter] as Svara };\n if (def.komal) note.komal = true;\n if (def.tivra) note.tivra = true;\n if (units.length > 1) note.durationMatra = 1 / units.length;\n return note;\n });\n const last = notes[notes.length - 1]!;\n // Post-আকার octave mark (`saf`): applies to the last unit unless it\n // already carries its own mark.\n if (postOct && last.svara![0] === 'madhyam') {\n last.svara = [octaveOf(postOct), last.svara![1]] as Svara;\n }\n if (hyphen) notes[0]!.sustain = true;\n if (kanLetter) attachKan(notes[0]!, kanLetter, kanOct);\n if (trailKan && last.kan === undefined) attachKan(last, trailKan, trailKanOct);\n return finish(notes, 'decoded');\n }\n if (aakar) {\n // '-a' = sustain (hold previous pitch, no new attack);\n // bare detached 'a' = one-matra rest (legend: hyphen-less matra sign).\n const note: Note = hyphen ? { sustain: true } : { rest: true };\n if (trailKan) attachKan(note, trailKan, trailKanOct);\n else if (kanLetter) attachKan(note, kanLetter, kanOct);\n return finish([note], 'decoded');\n }\n if (hyphen && !kanLetter && !trailKan) {\n // A bare continuation dash (`-`, `-i`) — the আ-কার is implied.\n return finish([{ sustain: true }], 'decoded');\n }\n // Kan without units, or digit-edges with no note between — keep raw.\n }\n\n return finish([{}], 'unknown');\n}\n\n/**\n * Decode one cell's text. Multi-chunk cells (whitespace-separated) emit\n * notes in order; the first note of each chunk carries that chunk's source\n * text in `raw`, so joining a cell's `raw` values with spaces reproduces\n * the normalized cell text (the lossless property tests rely on this).\n */\nexport function decodeCell(text: string): CellDecode {\n const chunks = text.split(/\\s+/).filter((c) => c.length > 0);\n const out: CellDecode = { notes: [], unknownTokens: [], knownRawTokens: [], decoded: false };\n for (const chunk of chunks) {\n const { notes, kind } = decodeChunk(chunk);\n notes[0]!.raw = chunk;\n if (kind === 'decoded') out.decoded = true;\n else if (kind === 'known') out.knownRawTokens.push(chunk);\n else out.unknownTokens.push(chunk);\n out.notes.push(...notes);\n }\n return out;\n}\n","/**\n * The order a swaralipi is **sung** in, as opposed to the order it is written.\n * Swarabitan's legend (স্বরবিতান pp. ১৩৫–১৩৬, gitabitan.io/bn/swaralipi/how-to-read/):\n *\n * - `{ }` is sung twice; `( )` inside it is left out the second time, and the\n * `[ ]` notes written above stand in for the notes under them.\n * - II at a kali's end sends the singer back to the asthayi's opening II, on\n * to the ‖ stop mark, then into the next kali: D.S. al Fine, with ‖ as the\n * Fine. I[ ]I / II[ ]II make that return sing the `[ ]` notes.\n * - IIII written as one stroke group ends the song: no return.\n *\n * The notation is written for this order, so every jump lands where the grid\n * expects it: the \"৹ ৹ ৹\" after a kali-end II is the rest of the cycle the ‖\n * broke off, which is what keeps a looping tabla on sam. Whatever the marks\n * leave unsaid (no ‖, a stray bracket) is sung as written.\n */\nimport { decodeCell } from '../convert/codec.js';\nimport type { Bracket, Note, Swaralipi } from '../spec/schema.js';\n\n/** One note as sung: where it is written (for highlights) and what sounds. */\nexport interface Visit {\n p: number;\n r: number;\n i: number;\n /** The written note, or a `[ ]` note standing in for it on a repeat. */\n note: Note;\n}\n\n/**\n * A raw the codec could not decode but which still **holds a matra** in the\n * source grid: it carries svara letters or the আ-কার carrier `a` (e.g. a\n * mistyped `` `-a `` / `frsfa` / `PUda`). Bracket, bar-glyph and beat-label\n * carriers contain none of these, so they stay timeless. Dropping these\n * columns outright ran the melody ahead of the তাল from that point on.\n */\nconst UNDECODED_CELL = /[srgmpqnvtduka]/i;\n\n/** A column that produces no sound and no time advance (bar, bracket-only,\n * carrier, structural raw). Mirrors the viewer's non-pitched, non-rest\n * classes. */\nexport const isSilent = (n: Note): boolean =>\n n.svara === undefined &&\n n.rest !== true &&\n n.sustain !== true &&\n !(n.raw !== undefined && UNDECODED_CELL.test(n.raw));\n\n/** ‖ written above a note: অবসানের চিহ্ন, where a return to the asthayi stops. */\nconst STOP_MARK = /^\\|+$/;\nconst EPS = 1e-6;\n\ninterface Token extends Visit {\n timed: boolean;\n}\n\nconst edges = (n: Note, kind: Bracket['kind'], edge: Bracket['edge']): number =>\n n.brackets?.filter((b) => b.kind === kind && b.edge === edge).length ?? 0;\nconst sounds = (n: Note): boolean => n.svara !== undefined || n.rest === true || n.sustain === true;\nconst matra = (notes: Note[]): number => notes.reduce((sum, n) => sum + (n.durationMatra ?? 1), 0);\n\n/** Every note of `doc` in the order it is sung. */\nexport function playOrder(doc: Swaralipi): Visit[] {\n const tokens: Token[] = [];\n doc.parts.forEach((part, p) =>\n part.rows.forEach((row, r) =>\n row.notes.forEach((note, i) => tokens.push({ p, r, i, note, timed: note.bar === undefined && !isSilent(note) })),\n ),\n );\n const { asthayi, stop, returns } = form(tokens);\n const changed = changedNotes(tokens);\n const out: Visit[] = [];\n // The token of the last note sung.\n let last = -1;\n\n /** Sing tokens lo..hi-1: each `{ }` twice, its `( )` only the first time. */\n const sing = (lo: number, hi: number, useChanged: boolean): void => {\n const repeats: { open: number; again: boolean }[] = [];\n // Matra of written notes a longer `[ ]` note already sang over.\n let owed = 0;\n for (let k = lo; k < hi; ) {\n const t = tokens[k]!;\n if (edges(t.note, 'repeat', 'open') > 0 && repeats.at(-1)?.open !== k) repeats.push({ open: k, again: false });\n const again = repeats.at(-1)?.again === true;\n const skipTo = again && edges(t.note, 'skip', 'open') > 0 ? skipEnd(tokens, k, hi) : -1;\n if (skipTo >= 0) {\n if (edges(tokens[skipTo]!.note, 'repeat', 'close') > 0) repeats.pop();\n k = skipTo + 1;\n owed = 0;\n continue;\n }\n if (owed > EPS && t.timed) owed -= matra([t.note]);\n else {\n const sub = useChanged || again ? changed.get(k) : undefined;\n // A `[ ]` note shorter than the one it replaces would pull the melody off sam.\n const fits = sub !== undefined && matra(sub) >= matra([t.note]) - EPS;\n for (const note of fits ? sub : [t.note]) out.push({ p: t.p, r: t.r, i: t.i, note });\n if (t.timed) last = k;\n owed = fits ? matra(sub) - matra([t.note]) : 0;\n }\n const loop = edges(t.note, 'repeat', 'close') > 0 ? repeats.at(-1) : undefined;\n if (loop !== undefined && !loop.again) {\n loop.again = true;\n k = loop.open;\n owed = 0;\n continue;\n }\n if (loop !== undefined) repeats.pop();\n k++;\n }\n };\n\n let from = 0;\n for (const ret of returns) {\n sing(from, ret.resume, false);\n // Singing that already stopped at ‖ \"takes up another kali\" there: a ‖ at\n // the asthayi's own close, or a `{ }` whose second pass skips from ‖ to `}`.\n if (last !== stop) sing(asthayi, stop + 1, ret.changed);\n from = ret.resume;\n }\n sing(from, tokens.length, false);\n return out;\n}\n\n/**\n * The song's form: where the asthayi starts (its opening II, else the top),\n * where a return stops (the first ‖ in the asthayi), and the token after each\n * kali-end II or I[ ]I. No ‖ → no returns: the notation then does not say how\n * far back to sing.\n */\nfunction form(tokens: Token[]): { asthayi: number; stop: number; returns: { resume: number; changed: boolean }[] } {\n // A II opens a kali when its row's singing comes after it, and closes one\n // when the singing comes before; mid-row, it alternates with the last II.\n const first = new Map<string, number>();\n const last = new Map<string, number>();\n tokens.forEach((t, k) => {\n if (!t.timed) return;\n const row = `${t.p}.${t.r}`;\n if (!first.has(row)) first.set(row, k);\n last.set(row, k);\n });\n const opens: number[] = [];\n let opening = false;\n tokens.forEach((t, k) => {\n if (t.note.bar !== 'double') return;\n const row = `${t.p}.${t.r}`;\n const before = (first.get(row) ?? Infinity) < k;\n const after = (last.get(row) ?? -1) > k;\n opening = before !== after ? after : !opening;\n if (opening) opens.push(k);\n });\n\n // A kali ends on a closing II, or on I[ ]I / II[ ]II (an empty `[ ]` among\n // the bars); a run of bars holding IIII ends the song instead.\n const returns: { resume: number; changed: boolean }[] = [];\n for (let k = 0; k < tokens.length; k++) {\n let at = -1;\n let open = false;\n let changed = false;\n let end = false;\n for (; k < tokens.length && !tokens[k]!.timed; k++) {\n const n = tokens[k]!.note;\n if (n.bar === 'quad') end = true;\n if (n.bar === 'double' && !opens.includes(k)) at = k;\n if (edges(n, 'alt', 'open') > 0) open = true;\n if (open && edges(n, 'alt', 'close') > 0) {\n at = k;\n changed = true;\n }\n }\n if (at >= 0 && !end) returns.push({ resume: at + 1, changed });\n }\n\n const top = opens[0];\n const asthayi = top !== undefined && top < (returns[0]?.resume ?? Infinity) ? top : 0;\n // The asthayi ends at its own closing II, or where the next kali opens. A ‖\n // with nothing sung after it is the song's own end (\"এইখানে একেবারে থামিবে\"),\n // not where a return stops.\n const asthayiEnd = Math.min(returns[0]?.resume ?? Infinity, opens.find((k) => k > asthayi) ?? Infinity, tokens.length);\n const lastSung = tokens.reduce((last, t, k) => (t.timed ? k : last), -1);\n const stop = tokens.findIndex(\n (t, k) =>\n k >= asthayi && k < asthayiEnd && k < lastSung && t.note.above?.some((a) => STOP_MARK.test(a.raw ?? '')) === true,\n );\n return { asthayi, stop, returns: stop < 0 ? [] : returns };\n}\n\n/**\n * The `[ ]` notes written above each column, by token: what is sung there on\n * a repeat. A span runs from the above-row `[` to its `]`; a column under it\n * with nothing above keeps its own note.\n */\nfunction changedNotes(tokens: Token[]): Map<number, Note[]> {\n const out = new Map<number, Note[]>();\n let row = '';\n let inside = false;\n tokens.forEach((t, k) => {\n // ponytail: a span is closed at the row's end — no corpus span crosses a row.\n if (row !== `${t.p}.${t.r}`) {\n row = `${t.p}.${t.r}`;\n inside = false;\n }\n const notes: Note[] = [];\n for (const above of t.note.above ?? []) {\n // An older converter left a few cells like `[sfa]` undecoded: read them as it now would.\n const read = above.raw !== undefined && !sounds(above) && above.brackets === undefined;\n for (const a of read ? decodeCell(above.raw!).notes : [above]) {\n if (edges(a, 'alt', 'open') > 0) inside = true;\n if (inside && sounds(a)) notes.push(a);\n if (edges(a, 'alt', 'close') > 0) inside = false;\n }\n }\n if (notes.length > 0) out.set(k, notes);\n });\n return out;\n}\n\n/** The token closing the `( )` that opens at `k`, or -1 if it never closes. */\nfunction skipEnd(tokens: Token[], k: number, hi: number): number {\n for (let depth = 0, j = k; j < hi; j++) {\n depth += edges(tokens[j]!.note, 'skip', 'open') - edges(tokens[j]!.note, 'skip', 'close');\n if (depth <= 0) return j;\n }\n return -1;\n}\n","/**\n * Pure spec-JSON → HTML renderer. No DOM, no side effects: usable for SSR\n * (Astro/static sites emit `renderToHtml(doc)` next to a\n * `<style>${SWARALIPI_CSS}</style>`) and unit-testable in plain Node.\n *\n * Layout model: NLTR emits a whole song as ONE html table whose every row has\n * the same column count, which is why its lines align down the page like the\n * printed স্বরবিতান. We reproduce that: the document is one CSS grid, each\n * `Row` is a `subgrid` child of it, and **one column = one cell** (a matra\n * group / bar / carrier — see groupRowIntoCells), so rows are commensurable.\n * Four fixed-height grid rows per row: above-annotations / notation / below\n * (slur arcs, marks) / lyric. A cell's sub-notes are set tight as one word\n * and its syllables likewise, both centred on the column — NLTR's and the\n * print's setting (রসা over ধা৹); `data-note` stays on the per-note span, so\n * P2.3's highlight targets are unchanged.\n *\n * Column *offsets* (the anacrusis that NLTR right-aligns into the সম) are\n * re-derived from the document alone — see alignRows.\n *\n * Rendering is spec-driven (semantics, not `raw`): grouping derives from\n * `durationMatra` accumulation so hand-authored documents without `raw`\n * render identically. `raw` is consulted only for (a) raw-only fallback\n * notes (never dropped — dimmed, in Swarabitan when loaded), (b) beat\n * labels, and (c) the অর্ধমাত্রা/ছেদ marks and the আ-কার, which only the\n * source cell can place (see rawMarks + codec.ts).\n */\nimport { isArcRaw } from '../player/schedule.js';\nimport { graceNotes } from '../spec/grace.js';\nimport type { Lay } from '../spec/lay.js';\nimport { isTaalFerta, sameTaal } from '../spec/taals.js';\nimport type { Meta, Note, Row, Swaralipi, Taal } from '../spec/index.js';\nimport {\n composeCluster,\n FREE_TAAL_LABELS,\n LABELS,\n LAY_LABELS,\n localizeDigits,\n MARKS,\n type GridLang,\n type LangMarks,\n type ViewerLang,\n} from './glyphs.js';\n\nexport interface RenderOptions {\n /** Notation + UI language. Default `bn`. */\n lang?: ViewerLang;\n /** Render the NLTR-style নাম/তাল/আবর্তন header block. Default true. */\n showHeader?: boolean;\n /**\n * Lyric/title transliterator for `hi`/`en` (see loadLyricTransliterator).\n * Without it, non-bn renders keep Bengali lyrics (graceful interim).\n */\n transliterate?: (bengaliText: string) => string;\n}\n\nconst EPS = 1e-6;\n\nconst isIntegral = (x: number) => Math.abs(x - Math.round(x)) < EPS;\n\nfunction escapeHtml(s: string): string {\n return s\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"');\n}\n\n/* ------------------------------------------------------------------ */\n/* Cell grouping */\n/* ------------------------------------------------------------------ */\n\nexport interface Cell {\n kind: 'bar' | 'group' | 'raw' | 'carrier';\n /** Index of the cell's first note within the row's notes array. */\n start: number;\n notes: Note[];\n}\n\nconst isPitched = (n: Note) => n.svara !== undefined || n.rest === true || n.sustain === true;\n\n/**\n * The raw text a raw-only note should display, or undefined when there is\n * nothing to show beyond what semantics already render (a bracket-only\n * chunk's raw is fully expressed by its bracket glyphs).\n */\nfunction rawDisplay(note: Note): string | undefined {\n if (note.raw === undefined) return undefined;\n if ((note.brackets?.length ?? 0) > 0 && /^[{}()[\\]]*$/.test(note.raw)) return undefined;\n return note.raw;\n}\n\n/**\n * Group a row's notes into rendered cells using a fractional-duration\n * accumulator (raw-independent — works for hand-authored docs):\n * - bar / raw-only / carrier notes force-close and form singleton cells;\n * - full-matra notes are singleton groups;\n * - fractional notes accumulate until the sum reaches an integer matra\n * boundary (epsilon for 1/3, 0.2 chains), then the group closes;\n * - `halfMatra` (the অর্ধমাত্রা ঃ) closes the cell on a half boundary — the\n * only case durations alone cannot resolve (`সঃ গঃ` vs `সরা`).\n * The converter emits k notes × 1/k per source cell, so groups coincide\n * with source cells; an incomplete trailing group still closes at row end\n * (the matra carrier lands on its last note).\n *\n * Adjacent bar/carrier cells are finally merged, because NLTR types them as\n * ONE table cell: the song-end `L L` (‖ ‖) and the asthayi-return `l [ ] l`\n * each occupy a single column, not two or four.\n */\nexport function groupRowIntoCells(notes: Note[]): Cell[] {\n const cells: Cell[] = [];\n let cur: Cell | undefined;\n let acc = 0;\n const close = () => {\n if (cur) {\n cells.push(cur);\n cur = undefined;\n }\n acc = 0;\n };\n notes.forEach((note, i) => {\n if (note.bar !== undefined) {\n close();\n cells.push({ kind: 'bar', start: i, notes: [note] });\n return;\n }\n if (!isPitched(note)) {\n close();\n cells.push({ kind: rawDisplay(note) !== undefined ? 'raw' : 'carrier', start: i, notes: [note] });\n return;\n }\n const d = note.durationMatra ?? 1;\n if (isIntegral(d) && note.halfMatra !== true) {\n close();\n cells.push({ kind: 'group', start: i, notes: [note] });\n return;\n }\n cur ??= { kind: 'group', start: i, notes: [] };\n cur.notes.push(note);\n acc += d;\n if (note.halfMatra === true || (acc > EPS && isIntegral(acc))) close();\n });\n close();\n return mergeStructural(absorbBrackets(cells));\n}\n\nconst isStructural = (c: Cell) => c.kind === 'bar' || c.kind === 'carrier';\n\n/** A carrier holding nothing but bracket edges — NLTR types those *inside*\n * the note's own cell (`{ma`, `ma}`); the converter only splits them out when\n * the source separated them with whitespace. */\nfunction bracketEdges(cell: Cell): { open: boolean; close: boolean } | undefined {\n if (cell.kind !== 'carrier') return undefined;\n let open = false;\n let close = false;\n for (const note of cell.notes) {\n if (note.raw !== undefined && !/^[{}()[\\]\\s]*$/.test(note.raw)) return undefined;\n for (const b of note.brackets ?? []) {\n if (b.edge === 'open') open = true;\n else close = true;\n }\n }\n return open || close ? { open, close } : undefined;\n}\n\n/**\n * Fold a bracket-only carrier into the matra it belongs to: an opening edge\n * joins the following group, a closing edge the preceding one. Without this a\n * `{` steals a column of its own and slides the whole rest of the row — and its\n * syllable with it (4295 such notes across 673 of the 1738 NLTR songs). A\n * carrier holding both edges is the `[]` alt marker, which does own a column.\n */\nfunction absorbBrackets(cells: Cell[]): Cell[] {\n const out: Cell[] = [];\n for (let i = 0; i < cells.length; i++) {\n const cell = cells[i]!;\n const edges = bracketEdges(cell);\n if (edges !== undefined && edges.open !== edges.close) {\n const prev = out[out.length - 1];\n const next = cells[i + 1];\n if (edges.close && prev?.kind === 'group') {\n prev.notes = [...prev.notes, ...cell.notes];\n continue;\n }\n if (edges.open && next?.kind === 'group') {\n next.notes = [...cell.notes, ...next.notes];\n next.start = cell.start;\n continue;\n }\n }\n out.push(cell);\n }\n return out;\n}\n\nfunction mergeStructural(cells: Cell[]): Cell[] {\n const out: Cell[] = [];\n for (const cell of cells) {\n const prev = out[out.length - 1];\n if (prev !== undefined && isStructural(prev) && isStructural(cell)) {\n prev.notes = [...prev.notes, ...cell.notes];\n if (cell.kind === 'bar') prev.kind = 'bar';\n } else out.push(cell);\n }\n return out;\n}\n\n/* ------------------------------------------------------------------ */\n/* Row alignment (reconstructing NLTR's shared column grid) */\n/* ------------------------------------------------------------------ */\n\nexport interface Layout {\n /** Total columns the document's grid needs. */\n width: number;\n /** Column offset of each row, in document order. */\n offsets: number[];\n}\n\n/** Bars that end a section — the row after one starts a fresh phrase. */\nconst SECTION_BARS: ReadonlySet<string> = new Set(['double', 'quad']);\n\nconst isBarCell = (cell: Cell | undefined) => cell?.kind === 'bar';\nconst endsSection = (cell: Cell | undefined) =>\n isBarCell(cell) && SECTION_BARS.has(cell!.notes[cell!.notes.length - 1]!.bar!);\n\n/**\n * Give every row of a document its column offset, so all rows share one set\n * of grid tracks (NLTR's single-table layout, re-derived from the spec JSON\n * — the source column index is not stored).\n *\n * A full line is `W` cells wide (the modal width of rows that open on a bar).\n * A shorter row is right-aligned into the সম only when it *starts* a phrase —\n * it opens without a bar, or it is the first row, or the previous row closed\n * a section (‖). A short row that merely finishes one stays flush left. A row\n * without its own closing bar leaves that last column empty, so it ends one\n * column earlier.\n *\n * Measured against all 1738 NLTR pages: 99.1 % of rows and 99.4 % of cells\n * land on the source's exact column. The residual is source defects — rows\n * where NLTR itself skips a column — which this packs flush instead.\n */\nexport function alignRows(rows: Cell[][]): Layout {\n const counts = new Map<number, number>();\n for (const cells of rows)\n if (isBarCell(cells[0])) counts.set(cells.length, (counts.get(cells.length) ?? 0) + 1);\n\n let width = 0;\n let best = 0;\n for (const [len, n] of counts)\n if (n > best || (n === best && len > width)) {\n width = len;\n best = n;\n }\n // No row opens on a bar (hand-authored docs often don't): the widest row is the line.\n if (width === 0) for (const cells of rows) width = Math.max(width, cells.length);\n\n const offsets = rows.map((cells, i) => {\n if (cells.length === 0 || cells.length >= width) return 0;\n const prev = rows[i - 1];\n const phraseStart = !isBarCell(cells[0]) || i === 0 || endsSection(prev?.[prev.length - 1]);\n if (!phraseStart) return 0;\n return Math.max(0, width - cells.length - (isBarCell(cells[cells.length - 1]) ? 0 : 1));\n });\n\n rows.forEach((cells, i) => {\n width = Math.max(width, offsets[i]! + cells.length);\n });\n return { width, offsets };\n}\n\n/* ------------------------------------------------------------------ */\n/* Arc (slur) resolution */\n/* ------------------------------------------------------------------ */\n\nexport interface Arc {\n /** 0-based index of the arc's first / last **cell** within the row. */\n start: number;\n end: number;\n /** Index, within that cell's notes, of the note the arc hangs from / into. */\n startNote: number;\n endNote: number;\n /** True when the matching end lies on a previous / following system. */\n openLeft: boolean;\n openRight: boolean;\n /** Fill-segments-only row: render a straight underline, no curled ends. */\n line?: boolean;\n}\n\n/**\n * Resolve under-arcs for one row down to the **note** each end hangs from, so a\n * slur inside one half-matra cell (মজ্ঞা) still runs centre to centre. Sources,\n * scanned left→right:\n * - spec `meend: 'start' | 'end'` — exact notes;\n * - below-annotation raws, which belong to the whole cell (NLTR types them\n * centred under the column): `w` opens on the cell's first sounded note,\n * `x` closes on its last, `$` (Swarabitan's short in-cell arc) runs first to\n * last, and `xw` — close, then re-open — meets in the middle instead.\n * Unmatched `x` → arc from cell 0 with a squared-off (open) left end;\n * unclosed `w` → arc to the last cell with an open right end — both match\n * the print's behavior when an arc continues across a system wrap.\n * A row with fill segments but no ends at all renders one straight line.\n */\nexport function resolveArcs(cells: Cell[]): Arc[] {\n const arcs: Arc[] = [];\n let open: { cell: number; note: number } | undefined;\n let sawEnds = false;\n const fillCells: number[] = [];\n\n const openAt = (cell: number, note: number) => {\n sawEnds = true;\n open ??= { cell, note };\n };\n const closeAt = (cell: number, note: number) => {\n sawEnds = true;\n const from = open ?? { cell: 0, note: 0 };\n arcs.push({\n start: from.cell,\n startNote: from.note,\n end: cell,\n endNote: note,\n openLeft: open === undefined,\n openRight: false,\n });\n open = undefined;\n };\n\n cells.forEach((cell, i) => {\n const pitched = cell.notes.flatMap((n, j) => (isPitched(n) ? [j] : []));\n const first = pitched[0] ?? 0;\n const last = pitched[pitched.length - 1] ?? cell.notes.length - 1;\n let marks = '';\n cell.notes.forEach((note, j) => {\n if (note.meend === 'end' || note.meend === 'both') closeAt(i, j);\n if (note.meend === 'start' || note.meend === 'both') openAt(i, j);\n for (const b of note.below ?? []) if (isArcRaw(b.raw)) marks += b.raw;\n });\n const reopens = /[xX].*[wW]/.test(marks);\n for (const ch of marks) {\n if (ch === 'w' || ch === 'W') openAt(i, reopens ? last : first);\n else if (ch === 'x' || ch === 'X') closeAt(i, reopens ? first : last);\n else if (ch === '$') {\n openAt(i, first);\n closeAt(i, last);\n } else fillCells.push(i);\n }\n });\n\n const lastCell = Math.max(cells.length - 1, 0);\n const lastNote = (c: number) => Math.max((cells[c]?.notes.length ?? 1) - 1, 0);\n if (open !== undefined) {\n arcs.push({\n start: open.cell,\n startNote: open.note,\n end: lastCell,\n endNote: lastNote(lastCell),\n openLeft: false,\n openRight: true,\n });\n } else if (!sawEnds && fillCells.length > 0) {\n const end = Math.max(...fillCells);\n arcs.push({\n start: Math.min(...fillCells),\n startNote: 0,\n end,\n endNote: lastNote(end),\n openLeft: true,\n openRight: true,\n line: true,\n });\n }\n return arcs;\n}\n\n/**\n * Which notes draw each arc and which cells clip it (styles.ts). An end hangs\n * Swarabitan's hook from its note's centre and runs the flat toward the other\n * end: `sw-mo` opens, `sw-mc` closes, both cut by their cell's `sw-mk` clip at\n * the mid-gap, where the next cell's run carries on. Inside one cell there is\n * no gap to cut at, so `-b` runs stop at their own note's edge and `-s` pairs\n * share one note. A cell the arc only passes under draws one `sw-mm` fill run,\n * a note between two ends in one cell a `sw-mf`.\n */\nfunction arcInk(cells: Cell[], arcs: Arc[]): { cells: string[]; notes: string[][] } {\n const ink = { cells: cells.map(() => ''), notes: cells.map((c) => c.notes.map(() => '')) };\n const mark = (c: number, j: number, cls: string, clip = false) => {\n ink.notes[c]![j] += ` ${cls}`;\n if (clip && !ink.cells[c]!.includes(' sw-mk')) ink.cells[c] += ' sw-mk';\n };\n for (const arc of arcs) {\n const { start: s, end: e, startNote: j, endNote: k } = arc;\n const hookL = arc.line !== true && !arc.openLeft;\n const hookR = arc.line !== true && !arc.openRight;\n if (s === e && hookL && hookR) {\n if (j === k) {\n mark(s, j, 'sw-mos');\n mark(s, j, 'sw-mcs');\n } else {\n mark(s, j, 'sw-mob');\n for (let n = j + 1; n < k; n++) mark(s, n, 'sw-mf');\n mark(s, k, 'sw-mcb');\n }\n continue;\n }\n // ponytail: a fill-only line runs mid-gap to mid-gap, not note edge to edge\n for (let c = s; c <= e; c++) {\n if (c === s && hookL) mark(c, j, 'sw-mo', true);\n else if (c === e && hookR) mark(c, k, 'sw-mc', true);\n else mark(c, 0, 'sw-mm', true);\n }\n }\n return ink;\n}\n\n/* ------------------------------------------------------------------ */\n/* Raw-derived marks (codec grammar: src/convert/codec.ts) */\n/* ------------------------------------------------------------------ */\n\n/** Swarabitan letter-units, lowercase only — an uppercase letter is a কণ. */\nconst SVARA_CHAR = /[srgmpqndtkuv]/;\n\ninterface RawMarks {\n /** The source typed a matra sign (`a`); a ঃ-only cell must not grow one. */\n aakar: boolean;\n /** Marks before the first cluster — `-iqi` is -ঃধঃ, not -ধঃঃ. */\n pre: string;\n /** Marks after note j, as typed (`i` and `:` are different Swarabitan\n * glyphs: two open rings vs two filled lozenges). */\n post: string[];\n}\n\n/**\n * Where a decoded cell's অর্ধমাত্রা/ছেদ marks sit and whether its আ-কার is\n * real, both read off `raw` — because that is what the Swarabitan sheet\n * shows. `i`/`:` is a matra sign (legend: `রাঃ` = 1½, `সঃ` = ½), so it lands\n * where it was typed and a cell without an `a` carries no আ-কার: `ipi` is\n * ঃপঃ and `qinqi` is ধঃনধঃ, never the cell-trailing পাঃঃ / ধনধাঃঃ that\n * counting the marks alone produces. Undefined for hand-authored notes (no\n * raw), which keep the spec-driven matra and `halfMatra`.\n */\nfunction rawMarks(raw: string | undefined, count: number): RawMarks | undefined {\n if (raw === undefined) return undefined;\n const marks: RawMarks = { aakar: false, pre: '', post: new Array<string>(count).fill('') };\n // A mark before every letter leads the cluster; one in a letterless chunk\n // (`-i`, `-ai`) trails the hyphen/matra that IS the note.\n const leads = SVARA_CHAR.test(raw);\n let seen = 0;\n for (const ch of raw) {\n if (SVARA_CHAR.test(ch)) seen = Math.min(seen + 1, count);\n else if (ch === 'a') marks.aakar = true;\n else if (ch === 'i' || ch === ':') {\n if (seen > 0) marks.post[seen - 1] += ch;\n else if (leads) marks.pre += ch;\n else marks.post[0] += ch;\n }\n }\n return marks;\n}\n\n/** Beat-number label (above rows): pure digits + optional sam tick. */\nfunction parseBeatLabel(raw: string): { digits: string; sam: boolean } | undefined {\n const m = raw.match(/^([0-9]{1,2})([fF])?:?$/);\n if (!m) return undefined;\n return { digits: m[1]!, sam: m[2] !== undefined };\n}\n\n/* ------------------------------------------------------------------ */\n/* Note / annotation fragments */\n/* ------------------------------------------------------------------ */\n\ninterface Ctx {\n lang: GridLang;\n marks: LangMarks;\n tr: (s: string) => string;\n}\n\nconst BRACKET_GLYPHS = {\n open: { repeat: '{', skip: '(', alt: '[' },\n close: { repeat: '}', skip: ')', alt: ']' },\n} as const;\n\nfunction bracketGlyphs(note: Note, edge: 'open' | 'close'): string {\n if (!note.brackets) return '';\n return note.brackets\n .filter((b) => b.edge === edge)\n .map((b) => `<span class=\"sw-br\">${BRACKET_GLYPHS[edge][b.kind]}</span>`)\n .join('');\n}\n\n/** A lone matra glyph: the note's own notation font supplies it — bn = the\n * Swarabitan আ-কার (`a`), hi/en = an en-dash (Bhatkhande has no matra sign).\n * Used for rests (বিরাম = detached matra), আ-কার holds and n>1 durations. */\nfunction matraGlyph(ctx: Ctx): string {\n return ctx.lang === 'bn' ? '<span class=\"sw-cl\">a</span>' : '<span class=\"sw-iso\">–</span>';\n}\n\n/** কণ (before the note) / রেশ (after it): small raised clusters beside the\n * main one — the legend's two mirrored grace marks. A grace may hold several\n * svaras, each with its own komal/tivra/microtone and its own melisma hyphen;\n * they render as one small cluster apiece, in order. */\nfunction renderGrace(grace: Note['kan'], cls: 'sw-kan' | 'sw-resh', ctx: Ctx): string {\n return graceNotes(grace)\n .map((n) => {\n if (n.svara === undefined) return '';\n const [octave, letter] = n.svara;\n const c = composeCluster(letter, {\n komal: n.komal,\n tivra: n.tivra,\n octave,\n withMatra: false,\n lang: ctx.lang,\n });\n const hy = n.sustain === true ? ctx.marks.hyphen : '';\n const micro =\n n.microtone !== undefined\n ? `<span class=\"sw-micro\" title=\"${n.microtone}\">${localizeDigits(n.microtone === 'atikomal' ? '2' : '1', ctx.lang)}</span>`\n : '';\n return `<span class=\"${[cls, ...c.classes].join(' ')}\">${hy}${c.text}</span>${micro}`;\n })\n .join('');\n}\n\ninterface PitchedOpts {\n /** Whole আ-কার matras this (cell-final) note carries: 0 for a bare\n * অর্ধমাত্রা cell, 1 normally, n for an n-matra note. */\n matras: number;\n /** অর্ধমাত্রা/ছেদ marks drawn before this note's cluster / after it, as the\n * source typed them (Swarabitan `i` / `:`). */\n pre: string;\n post: string;\n}\n\n/** অর্ধমাত্রা/ছেদ marks. Swarabitan carries them as real glyphs, so bn types\n * the source keys straight through; Bhatkhande has no such sign, so hi/en get\n * one CSS-drawn pair of rings apiece (styles.ts). */\nfunction cutGlyphs(marks: string, ctx: Ctx): string {\n if (marks === '') return '';\n return ctx.lang === 'bn'\n ? `<span class=\"sw-cl\" title=\"${ctx.marks.cut}\">${marks}</span>`\n : `<span class=\"sw-cut\" title=\"${ctx.marks.cut}\"></span>`.repeat(marks.length);\n}\n\n/**\n * The matra marks a cell's final note carries: its total duration as whole\n * আ-কার matras plus an optional অর্ধমাত্রা ঃ (legend `রাঃ` = 1½, `সঃ` = ½).\n * Only a `halfMatra` cell may show zero matras — every other cell keeps at\n * least one, so an incomplete trailing group still gets its carrier.\n */\nexport function cellMatra(cell: Cell): { matras: number; half: boolean } {\n // Only the pitched notes carry duration — a cell may also hold an absorbed\n // bracket edge, which is a glyph, not a matra.\n const pitched = cell.notes.filter(isPitched);\n const total = pitched.reduce((a, n) => a + (n.durationMatra ?? 1), 0);\n const half = pitched.some((n) => n.halfMatra === true);\n const whole = Math.floor(total + EPS);\n return { matras: half ? whole : Math.max(1, whole), half };\n}\n\n/**\n * Per-note render options for one group cell: the আ-কার lands on the cell's\n * last note, the ঃ marks where the source typed them (`rawMarks`), and a\n * hand-authored `halfMatra` — which has no raw to read — keeps its single\n * cell-trailing mark.\n */\nfunction cellPitchedOpts(cell: Cell): PitchedOpts[] {\n const { matras, half } = cellMatra(cell);\n // Indices of the notes that actually take a matra: an absorbed bracket edge\n // sits in the cell but owns no duration, matra sign or ঃ mark.\n const pitched: number[] = [];\n cell.notes.forEach((n, j) => {\n if (isPitched(n)) pitched.push(j);\n });\n const first = pitched[0];\n const last = pitched[pitched.length - 1];\n const marks = rawMarks(first === undefined ? undefined : cell.notes[first]!.raw, pitched.length);\n const aakars = marks !== undefined && !marks.aakar ? 0 : matras;\n return cell.notes.map((note, j) => {\n if (!isPitched(note)) return { matras: 0, pre: '', post: '' };\n return {\n matras: j === last ? aakars : 0,\n pre: j === first ? (marks?.pre ?? '') : '',\n post: marks !== undefined ? marks.post[pitched.indexOf(j)]! : half && j === last ? 'i' : '',\n };\n });\n}\n\n/**\n * A cell's lyric, split into one slice per *pitched* sub-note. The slices sit\n * side by side as one word centred under the cell's notes, which are one word\n * too — so no syllable can overrun its neighbour or a ৹, however narrow the\n * note above it. An absorbed bracket edge is not a slice — its syllable was\n * typed against the note beside it, so it folds into that note's slice.\n */\nfunction cellLyricSlices(cell: Cell): string[] | undefined {\n if (!cell.notes.some((n) => n.lyric !== undefined)) return undefined;\n const pitched = cell.notes.filter(isPitched);\n if (pitched.length === 0) return cell.notes.map((n) => n.lyric ?? '');\n const slices = new Array<string>(pitched.length).fill('');\n let k = 0;\n for (const note of cell.notes) {\n const at = Math.min(k, pitched.length - 1);\n slices[at] += note.lyric ?? '';\n if (isPitched(note)) k++;\n }\n return slices;\n}\n\n/** Inner HTML of one pitched/sustain/rest note: brackets, kan, melisma\n * hyphen, notation-font cluster, extra matras, cut marks, closing brackets.\n * The font (keyed on lang in styles.ts) renders komal/tivra/octave/matra —\n * composeCluster only picks the ASCII, so there is no Unicode hazard here. */\nfunction renderPitchedInner(note: Note, opts: PitchedOpts, ctx: Ctx): string {\n let inner = bracketGlyphs(note, 'open');\n inner += renderGrace(note.kan, 'sw-kan', ctx);\n if (note.sustain === true) inner += `<span class=\"sw-hy\">${ctx.marks.hyphen}</span>`;\n inner += cutGlyphs(opts.pre, ctx);\n if (note.svara !== undefined) {\n const [octave, letter] = note.svara;\n const c = composeCluster(letter, {\n komal: note.komal,\n tivra: note.tivra,\n octave,\n // The first matra is composed into the cluster itself (bn: the font's\n // trailing `a`); any further ones are separate glyphs below.\n withMatra: opts.matras >= 1,\n lang: ctx.lang,\n });\n inner += `<span class=\"${['sw-cl', ...c.classes].join(' ')}\">${c.text}</span>`;\n } else if (note.rest === true) {\n // বিরাম is *drawn* as a detached matra sign, so it always shows at least\n // one — a sub-matra rest would otherwise be invisible.\n inner += matraGlyph(ctx).repeat(Math.max(1, opts.matras));\n } else if (note.sustain === true) {\n inner += matraGlyph(ctx).repeat(opts.matras);\n }\n if (note.microtone !== undefined) {\n // Legend: অল্পকোমল = superscript ১ after the letter, অতিকোমল = ২.\n const mark = localizeDigits(note.microtone === 'atikomal' ? '2' : '1', ctx.lang);\n inner += `<span class=\"sw-micro\" title=\"${note.microtone}\">${mark}</span>`;\n }\n inner += renderGrace(note.resh, 'sw-resh', ctx);\n if (note.svara !== undefined && opts.matras > 1) {\n inner += matraGlyph(ctx).repeat(opts.matras - 1);\n }\n inner += cutGlyphs(opts.post, ctx);\n inner += bracketGlyphs(note, 'close');\n return inner;\n}\n\n/** Swarabitan glyphs (the .sw-bar font): A = vibhag dari, l = I cycle\n * danda, L = II section pair, song-end = II II. */\nconst BAR_GLYPHS = { dari: 'A', single: 'l', double: 'L', quad: 'LL' } as const;\n\nfunction renderBarInner(note: Note): string {\n return `${bracketGlyphs(note, 'open')}${BAR_GLYPHS[note.bar!]}${bracketGlyphs(note, 'close')}`;\n}\n\n/**\n * Render an annotation note list (above/below content) as inline mini\n * notation: beat labels, stop marks, bars, recursive note groups, raw\n * fallback. Reuses the same grouping as the main row.\n */\nfunction renderAnnotation(notes: Note[], ctx: Ctx): string {\n const parts: string[] = [];\n for (const cell of groupRowIntoCells(notes)) {\n if (cell.kind === 'bar') {\n const note = cell.notes[0]!;\n parts.push(`<span class=\"sw-bar sw-bar--${note.bar}\">${renderBarInner(note)}</span>`);\n continue;\n }\n if (cell.kind === 'group') {\n const opts = cellPitchedOpts(cell);\n cell.notes.forEach((note, j) => {\n parts.push(`<span class=\"sw-n\">${renderPitchedInner(note, opts[j]!, ctx)}</span>`);\n });\n continue;\n }\n const note = cell.notes[0]!;\n const raw = rawDisplay(note);\n if (raw !== undefined) {\n const beat = parseBeatLabel(raw);\n if (beat) {\n parts.push(\n `<span class=\"sw-beat${beat.sam ? ' sw-sam' : ''}\">${localizeDigits(beat.digits, ctx.lang)}</span>`,\n );\n } else if (/^\\|+$/.test(raw)) {\n parts.push(`<span class=\"sw-stop\">${raw}</span>`);\n } else {\n parts.push(`<span class=\"sw-raw\" title=\"${escapeHtml(raw)}\">${escapeHtml(raw)}</span>`);\n }\n continue;\n }\n const brackets = bracketGlyphs(note, 'open') + bracketGlyphs(note, 'close');\n if (brackets !== '') parts.push(`<span class=\"sw-carrier\">${brackets}</span>`);\n }\n return parts.join('');\n}\n\n/** Lyric cell text: the ৹ melisma mark is notation (not language text) —\n * swap it per-lang, transliterating only the linguistic remainder. */\nfunction lyricText(s: string, ctx: Ctx): string {\n return s\n .split('৹')\n .map((part) => (part === '' ? '' : ctx.tr(part)))\n .join(ctx.marks.melisma);\n}\n\n/* ------------------------------------------------------------------ */\n/* Row / header / document */\n/* ------------------------------------------------------------------ */\n\n/** Column 1 is the row-label track, so cell 0 starts at column 2. */\nconst COL_BASE = 2;\n\n/** One note's rendered content, whatever kind of cell it sits in. */\nfunction renderNote(note: Note, kind: Cell['kind'], opts: PitchedOpts | undefined, ctx: Ctx): string {\n if (note.bar !== undefined) return renderBarInner(note);\n if (kind === 'group' && opts !== undefined) return renderPitchedInner(note, opts, ctx);\n const raw = rawDisplay(note);\n return (\n bracketGlyphs(note, 'open') +\n (raw !== undefined ? `<span class=\"sw-raw\" title=\"${escapeHtml(raw)}\">${escapeHtml(raw)}</span>` : '') +\n bracketGlyphs(note, 'close')\n );\n}\n\nfunction renderRow(row: Row, partIdx: number, rowIdx: number, offset: number, ctx: Ctx): string {\n const cells = groupRowIntoCells(row.notes);\n const ink = arcInk(cells, resolveArcs(cells));\n const out: string[] = [];\n if (row.label !== undefined)\n out.push(`<span class=\"sw-label\">${escapeHtml(ctx.tr(row.label))}</span>`);\n\n cells.forEach((cell, ci) => {\n const col = offset + ci + COL_BASE;\n const opts = cell.kind === 'group' ? cellPitchedOpts(cell) : [];\n const barCls = cell.kind === 'bar' ? ' sw-bar-cell' : '';\n\n const notes = cell.notes\n .map((note, j) => {\n const path = `${partIdx}.${rowIdx}.${cell.start + j}`;\n const bar = note.bar !== undefined ? ` sw-bar sw-bar--${note.bar}` : '';\n return `<span class=\"sw-n${bar}${ink.notes[ci]![j]}\" data-note=\"${path}\">${renderNote(note, cell.kind, opts[j], ctx)}</span>`;\n })\n .join('');\n out.push(`<span class=\"sw-cell${barCls}${ink.cells[ci]}\" style=\"grid-column:${col}\">${notes}</span>`);\n\n // One slice per sub-note, empties included, set as one tight word the way\n // NLTR and the print set it (রসা over ধা৹).\n const slices = cellLyricSlices(cell);\n if (slices !== undefined) {\n const html = slices.map((t) => `<span>${escapeHtml(lyricText(t, ctx))}</span>`).join('');\n out.push(`<span class=\"sw-lyr\" style=\"grid-column:${col}\">${html}</span>`);\n }\n\n const above = cell.notes.flatMap((n) => n.above ?? []);\n if (above.length > 0)\n out.push(`<span class=\"sw-above\" style=\"grid-column:${col}\">${renderAnnotation(above, ctx)}</span>`);\n\n const below = cell.notes.flatMap((n) => (n.below ?? []).filter((b) => !isArcRaw(b.raw)));\n if (below.length > 0)\n out.push(`<span class=\"sw-below\" style=\"grid-column:${col}\">${renderAnnotation(below, ctx)}</span>`);\n });\n\n return `<div class=\"sw-row\" data-row=\"${partIdx}.${rowIdx}\">${out.join('')}</div>`;\n}\n\nfunction renderHeader(meta: Meta, ctx: Ctx): string {\n return renderMetaHeader(meta, ctx.lang, ctx.tr);\n}\n\n/**\n * The নাম / তাল / রাগ / আবর্তন / স্বরলিপিকার header block, shared by the\n * akarmatrik grid and the staff view so both show the same metadata (localized\n * labels; values injected pre-localized by the consumer). Exported so the\n * staff renderer can reuse the exact markup + styling.\n */\nexport function renderMetaHeader(\n meta: Meta,\n lang: GridLang,\n tr: (s: string) => string = (s) => s,\n): string {\n const L = LABELS[lang];\n const rows: string[] = [];\n const add = (label: string, value: string) =>\n rows.push(\n `<div class=\"sw-meta-row\"><span class=\"sw-meta-label\">${escapeHtml(label)}</span><span class=\"sw-meta-value\">${escapeHtml(value)}</span></div>`,\n );\n add(L.title, tr(meta.title));\n const taal = meta.taalName ?? meta.taal?.id;\n if (taal !== undefined) add(L.taal, tr(taal));\n if (meta.raag !== undefined) add(L.raag, tr(meta.raag));\n if (meta.avartan !== undefined) add(L.avartan, localizeDigits(String(meta.avartan), lang));\n if (meta.notationBy !== undefined) add(L.notationBy, tr(meta.notationBy));\n return `<header class=\"sw-header\">${rows.join('')}</header>`;\n}\n\n/** Render a complete swaralipi document to an HTML string. Pair with\n * SWARALIPI_CSS (shadow DOM does this automatically; SSR consumers emit a\n * `<style>` themselves). All source text is HTML-escaped. */\nexport function renderToHtml(doc: Swaralipi, opts: RenderOptions = {}): string {\n // Grid renderer handles bn/hi/en; `staff` is async (see renderStaffHtml) and\n // reaches this path only via the print/element wrappers, which fall back to bn.\n const lang: GridLang = opts.lang === 'hi' || opts.lang === 'en' ? opts.lang : 'bn';\n const tr = lang !== 'bn' && opts.transliterate ? opts.transliterate : (s: string) => s;\n const ctx: Ctx = { lang, marks: MARKS[lang], tr };\n\n // One grid for the whole document (NLTR = one table), so every row shares\n // the same tracks. `.sw-part` is `display: contents`, so section headings\n // and rows are all direct children of that grid; rows borrow its columns\n // via `subgrid`, which needs the tracks stated explicitly.\n const layout = alignRows(doc.parts.flatMap((p) => p.rows.map((r) => groupRowIntoCells(r.notes))));\n // max-content (not auto) for the row-label track: an auto track is the one\n // thing grid `justify-content: normal` will stretch, which would swallow all\n // the free space and shove the notation to the right.\n const tracks = `grid-template-columns:max-content repeat(${layout.width},minmax(calc(var(--sw-matra, 1.4em) * var(--sw-tight, 1)),max-content))`;\n\n const out: string[] = [`<div class=\"sw-sheet\" lang=\"${lang}\">`];\n if (opts.showHeader !== false) out.push(renderHeader(doc.meta, ctx));\n out.push(`<div class=\"sw-scroll\"><div class=\"sw-block\" style=\"${tracks}\">`);\n let n = 0;\n // লয়: mark the line where the tempo tier turns over, and only there.\n // ponytail: the `row.lay` field only — a source that *prints* the mark in its\n // own lyric band (NLTR's \"বিলম্বিত লয়:\") already shows it, and suppressing\n // those cells would shift every `data-note` path after them.\n let lay: Lay | undefined;\n // তালফেরতা: same rule — the band only where the taal in force changes. The\n // opening taal is the header's, so a row restating it prints nothing —\n // unless the header reads \"তালফেরতা\", which names no taal: then the first\n // row taal is printed too, as স্বরবিতান heads the song with its first taal.\n let taal: Taal | null | undefined = doc.meta.taal;\n let named = !isTaalFerta(doc.meta.taalName);\n doc.parts.forEach((part, p) => {\n out.push('<section class=\"sw-part\">');\n if (part.name !== undefined)\n out.push(`<h3 class=\"sw-part-name\">${escapeHtml(ctx.tr(part.name))}</h3>`);\n part.rows.forEach((row, r) => {\n // স্বরবিতান prints both as one centred line between systems (\"কাওয়ালি\",\n // \"দ্রুত লয়\"), so a row changing both gets one band, taal first.\n const marks: string[] = [];\n if (row.taal !== undefined && (!named || !sameTaal(row.taal, taal))) {\n taal = row.taal;\n named = true;\n const name = row.taalName ?? (taal === null ? FREE_TAAL_LABELS[ctx.lang] : taal.id);\n marks.push(`<span class=\"sw-taal\" data-taal=\"${escapeHtml(taal?.id ?? 'free')}\">${escapeHtml(ctx.tr(name))}</span>`);\n }\n if (row.lay !== undefined && row.lay !== lay) {\n lay = row.lay;\n marks.push(`<span class=\"sw-lay\" data-lay=\"${lay}\">${escapeHtml(LAY_LABELS[ctx.lang][lay])}</span>`);\n }\n if (marks.length > 0) out.push(`<div class=\"sw-change\">${marks.join('')}</div>`);\n out.push(renderRow(row, p, r, layout.offsets[n++]!, ctx));\n });\n out.push('</section>');\n });\n out.push('</div></div></div>');\n return out.join('');\n}\n","/**\n * Per-language notation encoding for the viewer.\n *\n * Every language renders its notation through a dedicated, purpose-built\n * font whose glyphs ARE the akarmatrik/Bhatkhande marks — so composeCluster\n * emits that font's ASCII encoding and the font does all the hard work\n * (komal/tivra forms, octave reph/dots, matra). This is why the viewer no\n * longer touches Unicode cluster composition at all: the old reph-over-\n * vowel, hasanta-before-matra and dotted-circle hazards simply don't exist\n * when the font supplies precomposed glyphs keyed by plain ASCII.\n *\n * - bn → NLTR's **Swarabitan** (the akarmatrik font this project decodes).\n * Letters s r g m p q n = স র গ ম প ধ ন (q=ধ); komal v t d u = ঋ জ্ঞ দ ণ;\n * tivra ma k = the authentic কড়ি-ম conjunct (ম-based — has NO Unicode\n * form, which is what forced this whole approach); suffix f = taar reph,\n * h = mandra hasanta; trailing a = the আ-কার matra carrier. See codec.ts.\n * - hi/en → **Ome Bhatkhande** Hindi/English (SIL OFL 1.1, © Omenad —\n * github.com/omenad/fonts). Same clean keymap for both: lowercase\n * s r g m p d n = the seven shuddha swaras, uppercase R G M D N = komal\n * Re/Ga, tivra Ma, komal Dha/Ni; octave suffix u/l = taar/mandra dot,\n * U/L = ati (two dots). Bhatkhande has no আ-কার, so no matra is appended.\n *\n * The font is applied by CSS keyed on `.sw-sheet`'s `lang` (see styles.ts);\n * composeCluster only chooses the ASCII. The single residual CSS mark is the\n * bn ati-octave extra dot (Swarabitan's f/h are single reph/hasanta only).\n */\nimport { hasKomal } from '../spec/svara.js';\nimport type { Lay } from '../spec/lay.js';\nimport type { Octave, SvaraLetter } from '../spec/index.js';\n\n/** Akarmatrik/Bhatkhande grid languages, rendered synchronously by renderToHtml. */\nexport type GridLang = 'bn' | 'hi' | 'en';\n\n/** All viewer languages. `staff` = Western staff notation (async, via abcjs). */\nexport type ViewerLang = GridLang | 'staff';\n\n/** bn Swarabitan glyph keys (shuddha / komal / tivra). Missing komal/tivra\n * entries fall back to the shuddha key (those alterations don't occur). */\nconst SWARABITAN_SHUDDHA: Record<SvaraLetter, string> = {\n s: 's', r: 'r', g: 'g', m: 'm', p: 'p', d: 'q', n: 'n', // q = ধ\n};\nconst SWARABITAN_KOMAL: Partial<Record<SvaraLetter, string>> = {\n r: 'v', g: 't', d: 'd', n: 'u', // ঋ জ্ঞ দ ণ\n};\nconst SWARABITAN_TIVRA: Partial<Record<SvaraLetter, string>> = { m: 'k' }; // কড়ি-ম\n\n/** hi/en Ome Bhatkhande octave suffix (u/l single dot, U/L two dots). */\nconst BHATKHANDE_OCTAVE: Record<Octave, string> = {\n madhyam: '',\n taar: 'u',\n mandra: 'l',\n 'ati-taar': 'U',\n 'ati-mandra': 'L',\n};\n\n/** Digits 0-9 in the target script (beat labels, avartan). */\nexport const DIGITS: Record<GridLang, string> = {\n bn: '০১২৩৪৫৬৭৮৯',\n hi: '०१२३४५६७८९',\n en: '0123456789',\n};\n\nexport interface LangMarks {\n /** Melisma / no-new-attack dash before a sustained cluster. */\n hyphen: string;\n /** Lyric continuation mark shown under sustains (the source uses ৹). */\n melisma: string;\n /** ছেদ cut/articulation mark (two stacked rings, ঃ-shaped). */\n cut: string;\n}\n\nexport const MARKS: Record<GridLang, LangMarks> = {\n bn: { hyphen: '-', melisma: '৹', cut: 'ঃ' },\n hi: { hyphen: '-', melisma: '॰', cut: 'ः' },\n en: { hyphen: '-', melisma: '·', cut: ':' },\n};\n\n/** Header labels (NLTR prints নাম / তাল / আবর্তন …). */\nexport const LABELS: Record<\n GridLang,\n { title: string; taal: string; raag: string; avartan: string; notationBy: string }\n> = {\n bn: { title: 'নাম', taal: 'তাল', raag: 'রাগ', avartan: 'আবর্তন', notationBy: 'স্বরলিপিকার' },\n hi: { title: 'नाम', taal: 'ताल', raag: 'राग', avartan: 'आवर्तन', notationBy: 'स्वरलिपिकार' },\n // \"Cycle\", not \"Avartan\": the English sheet is read by people who do not know the word, and\n // one taal cycle is exactly what the number counts.\n en: { title: 'Song', taal: 'Taal', raag: 'Raag', avartan: 'Cycles', notationBy: 'Notator' },\n};\n\n/** লয় tier names, printed where a row changes tempo. bn/hi keep the Indian\n * term; en names the tempo first (a reader of the English sheet may not know\n * the word — the same call `LABELS.en` makes with \"Cycles\" over \"Avartan\"). */\nexport const LAY_LABELS: Record<GridLang, Record<Lay, string>> = {\n bn: { drut: 'দ্রুত লয়', madhya: 'মধ্য লয়', vilambit: 'বিলম্বিত লয়' },\n hi: { drut: 'द्रुत लय', madhya: 'मध्य लय', vilambit: 'विलंबित लय' },\n en: { drut: 'Fast (drut)', madhya: 'Medium (madhya)', vilambit: 'Slow (vilambit)' },\n};\n\n/** Printed where a row switches to free rhythm (`row.taal: null`) with no\n * `taalName` of its own. bn is the converter's canonical মুক্তছন্দ. */\nexport const FREE_TAAL_LABELS: Record<GridLang, string> = {\n bn: 'মুক্তছন্দ',\n hi: 'मुक्तछंद',\n en: 'Free rhythm',\n};\n\n/** The practice surface's words: the sheet's own accessible name (it says\n * what a tap does), a repeat being on, and the learner's turn to sing. */\nexport const PRACTICE_LABELS: Record<GridLang, { sheet: string; repeat: string; turn: string }> = {\n bn: { sheet: 'স্বরলিপি — যে লাইন থেকে শুনতে চান, সেখানে ছুঁয়ে দিন', repeat: 'লাইনটি বারবার বাজবে', turn: 'এবার আপনি গান' },\n hi: { sheet: 'स्वरलिपि — जिस पंक्ति से सुनना हो, उसे छुएँ', repeat: 'पंक्ति दोहराई जा रही है', turn: 'अब आप गाइए' },\n en: { sheet: 'Swaralipi — tap a line to play from it', repeat: 'Repeating the line', turn: 'Your turn — sing' },\n};\n\n/** A composed notation cluster: the font's ASCII text plus any residual CSS\n * classes the font itself cannot express (only the bn ati-octave dot). */\nexport interface Cluster {\n text: string;\n classes: string[];\n}\n\nexport interface ComposeOptions {\n komal?: boolean;\n tivra?: boolean;\n octave: Octave;\n /** Append the আ-কার matra carrier (bn group-final notes only). */\n withMatra: boolean;\n lang: GridLang;\n}\n\n/**\n * Compose one svara into its notation-font ASCII. bn = Swarabitan\n * (letter + f/h octave + a matra); hi/en = Ome Bhatkhande (case-encoded\n * letter + u/l/U/L octave, no matra). The font renders the actual glyph.\n */\nexport function composeCluster(letter: SvaraLetter, opts: ComposeOptions): Cluster {\n const classes: string[] = [];\n\n if (opts.lang === 'bn') {\n let text =\n (opts.tivra && SWARABITAN_TIVRA[letter]) ||\n (opts.komal && SWARABITAN_KOMAL[letter]) ||\n SWARABITAN_SHUDDHA[letter];\n if (opts.octave === 'taar' || opts.octave === 'ati-taar') text += 'f';\n else if (opts.octave === 'mandra' || opts.octave === 'ati-mandra') text += 'h';\n // Swarabitan's f/h are single reph/hasanta; ati adds a CSS extra dot.\n if (opts.octave === 'ati-taar') classes.push('sw-ati-taar');\n if (opts.octave === 'ati-mandra') classes.push('sw-ati-mandra');\n if (opts.withMatra) text += 'a';\n return { text, classes };\n }\n\n // hi / en — Ome Bhatkhande.\n let base: string = letter;\n if (opts.tivra && letter === 'm') base = 'M';\n else if (opts.komal && hasKomal(letter)) base = base.toUpperCase();\n return { text: base + BHATKHANDE_OCTAVE[opts.octave], classes };\n}\n\n/** Map ASCII digits in `s` to the target script's digits. */\nexport function localizeDigits(s: string, lang: GridLang): string {\n const digits = DIGITS[lang];\n return s.replace(/[0-9]/g, (d) => digits[d.charCodeAt(0) - 48]!);\n}\n","/**\n * Fit a sheet's shared grid to the width it has, then layer a user zoom on\n * top.\n *\n * The whole document is one grid (see render.ts), so a sheet has exactly one\n * natural width — a wide তাল overruns a phone or an A4 page. Two levers, in\n * this order, because they cost different things:\n *\n * 1. **Spacing.** `--sw-cell-gap` and the `--sw-matra` column floor are\n * 25–35 % of that natural width (measured over the corpus), and giving\n * them up costs only air between the columns — the alignment is\n * untouched, since every row still borrows the same tracks. Compressed\n * only as far as the container demands, down to `minSpacing`.\n * 2. **Type size.** Everything inside is em-relative, so scaling the sheet's\n * `font-size` scales the notation without disturbing the columns (a\n * `transform` would scale it too, but would also break print\n * pagination). This is what actually makes the glyphs smaller, so it\n * runs second and stops at `minSize` px — past that the block scrolls\n * inside `.sw-scroll` rather than becoming unreadable. It also runs the\n * other way: a sheet narrower than its container grows (to 2x) rather\n * than leaving dead space to the right of every row.\n *\n * `zoom` (default 1) multiplies the fit scale so callers can zoom in past\n * fit-to-width, or below the readability floor deliberately; past that point\n * `.sw-scroll` panning is expected, same as a photo viewer. `minScale` is a\n * second, relative floor used by print, where paper cannot scroll.\n *\n * Self-contained on purpose — print.ts serialises this function into the\n * print page, so it must not close over anything or import anything (the\n * defaults below are literals for the same reason).\n */\nexport function fitSwaralipi(\n root: Document | ShadowRoot | HTMLElement,\n minScale = 0,\n zoom = 1,\n minSpacing = 0.35,\n minSize = 12,\n): void {\n const sheets = root.querySelectorAll<HTMLElement>('.sw-sheet');\n for (const sheet of sheets) {\n const scroll = sheet.querySelector<HTMLElement>('.sw-scroll');\n const block = sheet.querySelector<HTMLElement>('.sw-block');\n if (scroll === null || block === null) continue;\n // Measure unscaled and untightened, so repeated calls converge instead of\n // ratcheting down.\n sheet.style.removeProperty('--sw-size');\n sheet.style.removeProperty('--sw-tight');\n const available = scroll.clientWidth;\n let natural = block.offsetWidth;\n if (available === 0 || natural === 0) continue;\n\n // 1. Tighten the columns, but only as far as the container actually\n // asks: the width grows monotonically with --sw-tight, so binary-search\n // the loosest value that still fits. (A coarse ladder overshot the fit\n // and left the block short of the right edge — the gap this fixes.)\n if (natural > available && minSpacing < 1) {\n let loose = minSpacing;\n let tight = 1;\n for (let i = 0; i < 6; i++) {\n const mid = (loose + tight) / 2;\n sheet.style.setProperty('--sw-tight', String(mid));\n if (block.offsetWidth <= available) loose = mid;\n else tight = mid;\n }\n sheet.style.setProperty('--sw-tight', String(loose));\n natural = block.offsetWidth;\n }\n\n // 2. Scale the type for whatever is left — down to the readability floor\n // (past which .sw-scroll pans), or *up* to fill a container wider than\n // the sheet's natural width, since minSize/minSpacing are floors, not\n // targets. Capped at 2x so a two-column fragment cannot balloon; a\n // reader who wants more zooms (the literal is inline because print.ts\n // serialises this function — it can close over nothing).\n const base = parseFloat(getComputedStyle(sheet).fontSize);\n if (!(base > 0)) continue; // no readable base size (a DOM without layout)\n // (offsetWidth, not scrollWidth: a cell's spacer overhangs half a column gap\n // past the grid, and that clipped ink is not width to fit.)\n // (available - 1: offsetWidth is a rounded integer, so filling it exactly\n // can land a pixel over and raise a phantom scrollbar.)\n let fit = Math.max(minScale, Math.min((available - 1) / natural, 2));\n if (minSize > 0) fit = Math.max(fit, Math.min(1, minSize / base));\n const scale = fit * zoom;\n if (scale === 1) continue;\n sheet.style.setProperty('--sw-size', `${(base * scale).toFixed(3)}px`);\n }\n}\n\n/** Zoom bounds/step for zoomIn()/zoomOut()/the `zoom` property — exported so\n * a consumer's own zoom UI (e.g. a slider) can match the element's clamp. */\nexport const MIN_ZOOM = 0.5;\nexport const MAX_ZOOM = 3;\nexport const ZOOM_STEP = 1.2;\n","/**\n * Encapsulated stylesheet for the viewer. Injected into the\n * `<swaralipi-sheet>` shadow root automatically; SSR consumers emit it\n * themselves: `<style>${SWARALIPI_CSS}</style>` next to `renderToHtml()`.\n *\n * Theming hooks (CSS custom properties, all optional):\n * --sw-loop repeated-line band; --sw-loop-edge its edge, the learner's\n * hollow highlight and \"your turn\" tag (--sw-turn-ink on it)\n * --sw-row-hover hover tint of a tappable line; --sw-focus the focus ring\n * --sw-font font stack (default: Noto Sans Bengali + system Bengali)\n * --sw-size base font size\n * --sw-cell-gap horizontal gap between source cells\n * --sw-tight 0–1 multiplier on the column spacing (gap + matra floor);\n * set by fitSwaralipi to compress before shrinking type\n * --sw-matra minimum width of one matra column\n * --sw-header-min floor for the নাম/তাল/আবর্তন header (it must stay legible\n * when the notation is scaled down to fit a phone)\n * --sw-lay-min same floor for the তাল / লয় change band\n * --sw-hl player-highlight background (P2.3)\n * --sw-rule header rule / muted line color\n *\n * All ink uses `currentColor`, so the sheet follows the host's text color\n * (dark mode included). The only octave mark drawn as a pseudo-element is\n * the bn ati-octave extra dot (Swarabitan's f/h glyphs are a single\n * reph/hasanta); everything else is a real glyph in the notation font.\n */\n\n/** Notation fonts, self-hosted on the project CDN (CORS-enabled), keyed by\n * the CSS `font-family` this stylesheet uses. bn = NLTR's Swarabitan; hi/en\n * = Ome Bhatkhande (SIL OFL 1.1, © Omenad — github.com/omenad/fonts).\n * Self-hosters: declare your own \\`@font-face\\` for any of these families\n * before this stylesheet / before defineSwaralipiSheet() and it wins. */\nexport const NOTATION_FONT_URLS: Record<string, string> = {\n Swarabitan: 'https://lipighor.pages.dev/swarabitan/Swarabitan.ttf',\n ome_bhatkhande_hindi: 'https://lipighor.pages.dev/ome-bhatkhande/OmeBhatkhandeHindi.ttf',\n ome_bhatkhande_english:\n 'https://lipighor.pages.dev/ome-bhatkhande/OmeBhatkhandeEnglish.ttf',\n};\n\n/** @deprecated use NOTATION_FONT_URLS.Swarabitan */\nexport const SWARABITAN_FONT_URL = NOTATION_FONT_URLS.Swarabitan;\n\n/* Each language renders its notation through one dedicated font — the\n * glyphs ARE the akarmatrik/Bhatkhande marks, keyed by plain ASCII (see\n * glyphs.ts). @font-face covers document use (SSR, print); the element also\n * registers these via the FontFace API because @font-face inside a shadow\n * root's adopted sheet is ignored. display:block — a flash of the ASCII\n * fallback ('kfa', 'srgm') would read as content. */\nconst FONT_FACES = Object.entries(NOTATION_FONT_URLS)\n .map(\n ([family, url]) =>\n `@font-face { font-family: ${family}; src: url('${url}') format('truetype'); font-display: block; }`,\n )\n .join('\\n');\n\nexport const SWARALIPI_CSS = `\n${FONT_FACES}\n\n/* A custom element is display:inline by default, and Resize Observer\n \"Observations do not fire for non-replaced inline Elements\" — they report\n one empty content rect and nothing after\n (https://drafts.csswg.org/resize-observer/). The element's re-fit-on-resize\n is that observer, so without this rule the sheet is fitted once, to whatever\n width it happened to have, and never again. */\n:host { display: block; }\n\n.sw-sheet {\n font-family: var(--sw-font, 'Noto Sans Bengali', 'Kohinoor Bangla', 'Bangla Sangam MN', 'Nirmala UI', 'Noto Sans Devanagari', sans-serif);\n font-size: var(--sw-size, 1.125rem);\n line-height: 1.5;\n}\n\n/* ---- notation font, per language (the note clusters + grace notes) ---- */\n.sw-sheet[lang=\"bn\"] :is(.sw-cl, .sw-kan, .sw-resh) { font-family: Swarabitan, var(--sw-font, sans-serif); }\n.sw-sheet[lang=\"hi\"] :is(.sw-cl, .sw-kan, .sw-resh) { font-family: ome_bhatkhande_hindi, var(--sw-font, sans-serif); }\n.sw-sheet[lang=\"en\"] :is(.sw-cl, .sw-kan, .sw-resh) { font-family: ome_bhatkhande_english, var(--sw-font, sans-serif); }\n\n/* ---- header ---- */\n.sw-header {\n margin: 0 0 0.75em;\n padding: 0 0 0.5em;\n border-bottom: 1px solid var(--sw-rule, rgba(128, 128, 128, 0.35));\n /* Scales with the sheet, but never below the floor: fitSwaralipi shrinks\n .sw-sheet's font-size to fit the notation, and the metadata is prose —\n it has no columns to align and must stay readable on a phone. */\n font-size: max(0.95em, var(--sw-header-min, 0.95rem));\n}\n.sw-meta-row { display: flex; gap: 0.3em; }\n.sw-meta-label { font-weight: 600; min-width: 4.5em; }\n.sw-meta-label::after { content: ':'; font-weight: 400; margin-left: 0.15em; }\n\n.sw-part-name { font-size: 0.85em; font-weight: 600; margin: 1em 0 0.2em; opacity: 0.85; }\n\n/* তাল / লয় change: the line where the তালফেরতা or the tempo tier turns over,\n centred between two systems the way স্বরবিতান prints \"ঝাঁপতাল\" or\n \"দ্রুত লয়\". A full-width band rather than a row label — the label track is\n what the notation columns are measured against, and a six-em word in it\n would shove the whole sheet right. */\n.sw-change {\n grid-column: 1 / -1;\n display: flex;\n align-items: center;\n gap: 0.6em;\n margin: 0.8em 0 0;\n /* Floored like the header: fitSwaralipi shrinks the sheet to fit the\n notation's columns, and this label has none to align. */\n font-size: max(0.7em, var(--sw-lay-min, 0.72rem));\n font-weight: 600;\n letter-spacing: 0.09em;\n opacity: 0.75;\n break-after: avoid;\n}\n.sw-change::before,\n.sw-change::after {\n content: '';\n flex: 1;\n height: 1px;\n background: var(--sw-rule, rgba(128, 128, 128, 0.35));\n}\n.sw-taal + .sw-lay::before { content: '·'; margin-right: 0.6em; }\n\n/* ---- block grid: ONE column set for the whole sheet ----\n * NLTR emits a song as a single html table, which is why its lines align\n * down the page. Same here: .sw-block owns the tracks, every .sw-row\n * borrows them with subgrid, and .sw-part is display:contents so section\n * headings sit in the same grid instead of breaking it. */\n.sw-scroll { overflow-x: auto; }\n.sw-block {\n display: grid;\n column-gap: calc(var(--sw-cell-gap, 0.4em) * var(--sw-tight, 1));\n align-items: end;\n width: max-content;\n /* The last column's cell spacers overhang half a gap past the grid; clip\n that sideways so it neither counts as width to fit nor raises a scrollbar. */\n overflow-x: clip;\n}\n.sw-part { display: contents; }\n/* Four FIXED bands per row — above / notation / arc / lyric — so a beat label,\n * a কণ or a মীড় never changes how far a line sits from its words: the\n * notation hugs its lyric and the next system starts a little further off,\n * as the printed স্বরবিতান sets it. Content taller than its band overflows\n * rather than pushing the rhythm apart. */\n.sw-row {\n grid-column: 1 / -1;\n display: grid;\n grid-template-columns: subgrid;\n grid-template-rows: 0.95em 1.35em 0.4em 1.35em;\n align-items: end;\n padding-bottom: 0.35em;\n line-height: 1.35;\n}\n.sw-label { grid-column: 1; grid-row: 2; padding-right: 0.5em; font-weight: 600; }\n\n/* One column per cell, its notes set tight as one word (রসা) and centred by\n * two flex spacers. Each spacer overhangs half the column gap (a min-width\n * paid back by a negative margin, so the column is sized by the notes alone),\n * which lets neighbouring cells' spacers meet mid-gap: a মীড় crossing cells is\n * inked by these boxes with no hole between them. */\n.sw-cell, .sw-lyr { display: flex; justify-content: center; white-space: nowrap; }\n.sw-cell {\n --sw-half-gap: calc(var(--sw-cell-gap, 0.4em) * var(--sw-tight, 1) / 2);\n grid-row: 2;\n align-self: stretch;\n}\n.sw-cell::before, .sw-cell::after { content: ''; flex: 1 0 0; min-width: var(--sw-half-gap); }\n.sw-cell::before { margin-left: calc(var(--sw-half-gap) * -1); }\n.sw-cell::after { margin-right: calc(var(--sw-half-gap) * -1); }\n.sw-cell > .sw-n { position: relative; }\n.sw-above { grid-row: 1; font-size: 0.7em; line-height: 1; justify-self: center; white-space: nowrap; }\n.sw-below { grid-row: 3; font-size: 0.62em; line-height: 1; justify-self: center; white-space: nowrap; }\n.sw-lyr { grid-row: 4; }\n\n/* ---- notation clusters & marks ---- */\n.sw-cl { position: relative; display: inline-block; }\n\n/* bn ati-octave: Swarabitan's f/h give a single reph/hasanta, so ati adds\n * one extra dot above (ati-taar) / below (ati-mandra). bn-only — hi/en get\n * the two-dot glyph natively from the U/L octave suffix. */\n.sw-ati-taar::before,\n.sw-ati-mandra::before {\n content: '';\n position: absolute;\n left: 0.25em;\n width: 0.16em;\n height: 0.16em;\n border-radius: 50%;\n background: currentColor;\n}\n.sw-ati-taar::before { top: -0.3em; }\n.sw-ati-mandra::before { bottom: -0.35em; }\n\n/* grace notes: small raised clusters — কণ before the note, রেশ after it.\n * line-height 0 (here and on .sw-micro): a raised inline box taller than the\n * strut grows its line box and drops that one note's baseline below its\n * neighbours' (css2 §10.8). */\n.sw-kan,\n.sw-resh {\n position: relative;\n display: inline-block;\n font-size: 0.58em;\n line-height: 0;\n vertical-align: 0.75em;\n}\n.sw-kan { margin-right: 0.08em; }\n.sw-resh { margin-left: 0.08em; }\n\n.sw-hy { padding-right: 0.02em; }\n.sw-iso { display: inline-block; margin-left: -0.18em; }\n/* The অর্ধমাত্রা / ছেদ mark: two stacked rings (legend p. ১৩৫). bn types\n * Swarabitan's own glyph (the ASCII i key) — an isolated Unicode ঃ has no base and\n * every Bengali text font shapes it with a dotted circle (an NBSP carrier\n * does not help), but the notation font has the mark itself. hi/en fall back\n * to these drawn rings: Bhatkhande has no such sign. */\n.sw-cut {\n position: relative;\n display: inline-block;\n width: 0.3em;\n height: 1em;\n vertical-align: baseline;\n}\n.sw-cut::before, .sw-cut::after {\n content: '';\n position: absolute;\n left: 0.08em;\n width: 0.15em;\n height: 0.15em;\n border-radius: 50%;\n background: currentColor;\n}\n.sw-cut::before { top: 0.2em; }\n.sw-cut::after { top: 0.55em; }\n.sw-br { opacity: 0.8; padding: 0 0.06em; }\n.sw-micro { font-size: 0.6em; line-height: 0; vertical-align: super; opacity: 0.8; }\n\n/* raw fallback: never dropped, visibly non-notation. Swarabitan first —\n * raw IS that font's encoding, so undecoded cells show NLTR's own glyphs\n * (dimmed: semantics unverified); monospace ASCII when the font is out. */\n.sw-raw {\n font-family: Swarabitan, ui-monospace, SFMono-Regular, Menlo, monospace;\n font-size: 0.72em;\n opacity: 0.55;\n}\n/* above the notes, raw is the notator's own mark (alt passages, ‖): full ink */\n.sw-above .sw-raw { font-size: 1em; opacity: 1; }\n\n/* ---- bars: dari (A) and danda (l/L) Swarabitan glyphs, all langs;\n * its | is the ‖ অবসান stop mark ---- */\n.sw-bar, .sw-stop {\n font-family: Swarabitan, var(--sw-font, sans-serif);\n white-space: nowrap;\n}\n.sw-bar--quad { letter-spacing: 0.15em; }\n/* a bar owns a whole column but needs no matra of width */\n.sw-bar-cell { min-width: 0; }\n\n/* ---- মীড় under-arcs (from w/x/$ segments and spec meend) ----\n * Swarabitan's own arc, all langs: w is the opening hook, curling down from\n * its tip into a flat, x its mirror, y that flat alone — and they join\n * hole-free, so one run of text is a whole end (tools/align-check/glyph.html).\n * Each end sets its hook tip on its note's centre and runs the flat toward the\n * other end (render.ts arcInk): across cells it is cut at the mid-gap, where\n * the next cell's run carries on (.sw-mk clips a cell half a gap past each\n * side, as far as its spacers reach); inside one cell, at its note's edge. So\n * a long arc extends the flat and a short one trims it off. line-height 0 sets\n * every run's baseline the same distance below its note. The clip reaches\n * 0.5px further so two cells' anti-aliased edges overlap instead of leaving a\n * hairline seam between their identical flats. */\n.sw-mk { clip-path: inset(-3em calc(var(--sw-half-gap) * -1 - 0.5px)); }\n.sw-mo::after, .sw-mob::after, .sw-mos::after,\n.sw-mc::before, .sw-mcb::before, .sw-mcs::before,\n.sw-mf::before, .sw-mm::before {\n content: 'yyyyyyyyyyyy';\n position: absolute;\n top: calc(100% + 0.05em);\n font-family: Swarabitan;\n font-size: 0.9em;\n line-height: 0;\n white-space: pre;\n /* Cuts the width-constrained runs (-b/-s/-f) at their note's edge. NOT\n * overflow-x:clip — WebKit clips the block axis with it too, and these\n * boxes are line-height 0, so Safari erased every মীড় on the sheet. */\n clip-path: inset(-3em 0);\n}\n.sw-mo::after, .sw-mob::after, .sw-mos::after { content: 'wyyyyyyyyyyyy'; }\n/* rtl: a closing run cut short keeps its hook on its right edge */\n.sw-mc::before, .sw-mcb::before, .sw-mcs::before { content: 'yyyyyyyyyyyyx'; direction: rtl; }\n.sw-mo::after, .sw-mob::after { left: 50%; }\n.sw-mc::before, .sw-mcb::before { right: 50%; }\n.sw-mos::after { left: 0; }\n.sw-mcs::before { right: 0; }\n.sw-mf::before { left: 0; right: 0; }\n.sw-mm::before { left: -12em; }\n/* Inside one cell a hook gets half a note to curl in, about a third of its\n * curl: squeezed to half width (same stroke) it lands flat at the cut, so the\n * two flats meet level whatever the notes' widths — a small arc, not a V. */\n.sw-mob::after, .sw-mos::after, .sw-mcb::before, .sw-mcs::before { width: 100%; transform: scaleX(0.5); }\n.sw-mob::after, .sw-mos::after { transform-origin: left; }\n.sw-mcb::before, .sw-mcs::before { transform-origin: right; }\n\n/* ---- annotation content ---- */\n.sw-beat { position: relative; display: inline-block; padding: 0 0.1em; }\n.sw-sam::after {\n content: '';\n position: absolute;\n top: -0.45em;\n left: 50%;\n width: 0.1em;\n height: 0.4em;\n background: currentColor;\n transform: rotate(14deg);\n}\n\n/* ---- player sync (P2.3) ---- */\n.sw-hl { background: var(--sw-hl, rgba(255, 196, 64, 0.45)); border-radius: 0.15em; }\n/* Staff notes are SVG <g> — background doesn't paint there, so recolour the\n glyph fill/stroke instead (abcjs draws note heads/stems as filled paths). */\n.sw-staff .sw-hl, .sw-staff .sw-hl * { fill: var(--sw-hl-note, #d68400); stroke: var(--sw-hl-note, #d68400); }\n\n/* ---- practice: tap a line, repeat it, sing it back ----\n * Only a sheet a player drives is [seekable]. The whole line is the tap\n * target, so it is the line that answers the pointer. A repeat shades its\n * lines and fades the rest (focus, as Soundslice fades outside a loop); on the\n * learner's pass the highlight goes hollow — it marks where to sing, not what\n * is sounding — and the repeat's first line wears a \"your turn\" tag. None of\n * it moves a column: backgrounds, opacity and an out-of-flow tag only. */\n:host([seekable]) .sw-row { cursor: pointer; }\n:host(:focus-visible) { outline: 2px solid var(--sw-focus, currentColor); outline-offset: 0.3em; border-radius: 0.2em; }\n.sw-row { border-radius: 0.3em; }\n@media (hover: hover) {\n :host([seekable]) .sw-row:hover { background: var(--sw-row-hover, rgba(128, 128, 128, 0.08)); }\n}\n.sw-looping .sw-row:not(.sw-loop) { opacity: 0.6; }\n.sw-row.sw-loop {\n background: var(--sw-loop, rgba(255, 196, 64, 0.13));\n box-shadow: inset 0.2em 0 var(--sw-loop-edge, #a85a00);\n}\n.sw-hl.sw-hl-turn { background: none; box-shadow: inset 0 0 0 0.09em var(--sw-loop-edge, #a85a00); }\n/* The tag rides the line's above-band at its right end — a grid item spanning\n every column, so it sizes no track — and is sticky, so on a phone where the\n line runs past the screen it waits at the visible edge instead. */\n.sw-row[data-turn]::after {\n content: attr(data-turn);\n grid-column: 1 / -1;\n grid-row: 1;\n justify-self: end;\n align-self: start;\n position: sticky;\n right: 0.2em;\n translate: 0 -0.3em;\n font-size: max(0.6em, 0.7rem);\n font-weight: 600;\n line-height: 1.6;\n padding: 0 0.7em;\n border-radius: 1em;\n color: var(--sw-turn-ink, #fff);\n background: var(--sw-loop-edge, #a85a00);\n}\n.sw-live { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }\n@media (prefers-reduced-motion: no-preference) {\n .sw-row { transition: opacity 0.25s, background-color 0.25s; }\n}\n@media print {\n .sw-row { opacity: 1 !important; background: none !important; box-shadow: none !important; }\n .sw-row[data-turn]::after { content: none; }\n .sw-hl { background: none !important; box-shadow: none !important; }\n}\n\n/* ---- element error box ---- */\n.sw-error {\n font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\n font-size: 0.85em;\n padding: 0.6em 0.8em;\n border: 1px solid rgba(200, 64, 64, 0.6);\n border-radius: 0.3em;\n color: #b33;\n background: rgba(200, 64, 64, 0.08);\n}\n`;\n\n/**\n * Print stylesheet — pair with `SWARALIPI_CSS` (renderPrintDocument injects\n * both). Gated on `@media print`, so it also works if a consumer drops it into\n * a page and prints that page directly.\n *\n * - `print-color-adjust: exact` forces the marks that are drawn as tiny\n * `background: currentColor` pseudo-elements (octave dots, arcs, danda\n * strokes, sam tick) to actually print — browsers drop backgrounds by\n * default, which would silently strip the notation's diacritics.\n * - rows are un-clipped (no scrollbar on paper) and kept whole across page\n * breaks; part headings stay with their first row.\n */\nexport const SWARALIPI_PRINT_CSS = `\n@page { margin: 16mm; }\n@media print {\n .sw-sheet, .sw-staff { -webkit-print-color-adjust: exact; print-color-adjust: exact; color: #000; }\n .sw-scroll { overflow: visible !important; }\n .sw-row { break-inside: avoid; page-break-inside: avoid; }\n .sw-part-name, .sw-header, .sw-change { break-after: avoid-page; page-break-after: avoid; }\n .sw-hl { background: none !important; }\n /* Keep each engraved staff system whole across a page break (the abcjs line\n is a <div> wrapping the <svg>, so the break rule must sit on the div). */\n .sw-staff-lines > div { break-inside: avoid; page-break-inside: avoid; }\n .sw-staff-meta { break-after: avoid-page; page-break-after: avoid; }\n}\n`;\n\n/** Staff-notation (abcjs) wrapper chrome: instrument/tempo header + a fluid\n * SVG. The engraving itself is drawn by abcjs; this only frames it. */\nexport const SWARALIPI_STAFF_CSS = `\n.sw-staff { color: currentColor; }\n.sw-staff-meta { display: flex; gap: 1.25em; align-items: baseline; margin: 0 0 .5em; font-size: .95em; opacity: .85; }\n.sw-staff-instrument { font-weight: 600; }\n.sw-staff-drums { opacity: .75; }\n.sw-staff-tempo { font-variant-numeric: tabular-nums; }\n/* abcjs (oneSvgPerLine) wraps the music into one <div><svg> per system; stack\n them as short, swaralipi-style lines. abcjs sets a fixed pixel height +\n overflow:hidden on each wrapper div — neutralise it so the viewBox'd SVG can\n scale to the container (and to the print page) instead of being clipped. */\n.sw-staff-lines > div { margin: 0 0 .35em; height: auto !important; overflow: visible !important; }\n/* Fill up to the engraved (staffwidth) size — shrink to fit a narrow container,\n but never stretch past natural width (abcToSvg pins per-SVG max-width in px),\n else a short last system balloons. */\n.sw-staff-lines svg { display: block; width: 100%; height: auto; }\n.sw-staff-missing { padding: 1em; border: 1px dashed currentColor; border-radius: 6px; opacity: .8; font-size: .9em; }\n.sw-staff-title { font-size: 1.15em; font-weight: 700; }\n.sw-staff-subtitle { opacity: .8; font-size: .95em; margin-top: .15em; }\n`;\n","/**\n * Staff (Western) notation — a 4th \"language\" for the viewer.\n *\n * Staff notation IS the melody voice drawn as a Western score, so it reuses\n * the player's pure `buildSchedule` (the same (midi, beat, durationBeats, kan)\n * the MIDI export writes) and turns it into an **ABC notation** string, which\n * `abcjs` (MIT, zero-dep) engraves to SVG. abcjs is loaded through a *dynamic*\n * `import('abcjs')` — an optional peer dep, exactly like tone/lamejs — so the\n * viewer bundle keeps its bare-load guarantee and only consumers who want staff\n * notation install it. Without it, `renderStaffHtml` returns a graceful notice.\n *\n * Scope (matches the player/MIDI): a single treble-clef melody line. The chosen\n * instrument is a header label, not a clef change (the line is monophonic and\n * treble covers piano + violin range with ledger lines). Microtones render as\n * their komal approximation — the same documented limitation as playback, since\n * abcjs has no sub-komal glyph.\n */\nimport type { Swaralipi, Taal } from '../spec/index.js';\nimport { buildSchedule, glideTargets, type PlayEvent, type Schedule } from '../player/schedule.js';\nimport { TAALS, type TaalId } from '../spec/taals.js';\nimport { drumPattern, type DrumVoice } from '../player/instruments.js';\nimport { renderMetaHeader } from './render.js';\nimport type { GridLang } from './glyphs.js';\n\nexport interface StaffOptions {\n /** Tonic (Sa). Accepts `C`, `C#`, `cs`… Default: `meta.tonic`, else `C`. */\n tonic?: string;\n /** Octave of madhyam Sa (C4 = MIDI 60). Default 4. */\n baseOctave?: number;\n /** Tempo written into the score (Q:) and shown as a header. Default `meta.bpm`, else 90. */\n bpm?: number;\n /** Instrument name shown above the staff (label only — clef stays treble). */\n instrument?: string;\n /** Show the নাম/তাল/আবর্তন/স্বরলিপিকার header block. Default true. */\n showHeader?: boolean;\n /** Language for the header **labels** (values are injected pre-localized by\n * the consumer). Default `en` — staff is the Western view. */\n headerLang?: GridLang;\n /** Transliterate header values (title/taal/notator) — same fn as the grid. */\n transliterate?: (bengaliText: string) => string;\n /** Include the `w:` lyric line under each staff. Default true. */\n lyrics?: boolean;\n /** Matra per bar (one তাল cycle). Default `meta.taal.numBeats`, else 4. */\n beatsPerBar?: number;\n /** Target line width in px passed to abcjs (music wraps within it). Default 680. */\n staffwidth?: number;\n /** Preferred bars per wrapped line (swaralipi-short systems). Default 4. */\n measuresPerLine?: number;\n /** abcjs `scale`. Default 1. */\n scale?: number;\n /** Add a second percussion staff below the melody, sequencing a Western\n * drumset (kick/snare/hi-hat) to the taal's sam/tali/khaali structure —\n * the same pattern `SwaralipiPlayer`'s `rhythm: 'drums'` plays, engraved via\n * abcjs `%%percmap`. Default false (the score stays a single staff). Taal:\n * `meta.taal`, else a plain 4-beat cycle (matches `beatsPerBar`'s fallback). */\n drums?: boolean;\n}\n\n/* ---- MIDI → ABC pitch spelling -------------------------------------- */\n\n/** Sharp-spelled ABC pitch tokens, index = pitch-class 0–11. `^` = sharp. */\nconst ABC_SHARP = ['C', '^C', 'D', '^D', 'E', 'F', '^F', 'G', '^G', 'A', '^A', 'B'] as const;\n\n/**\n * MIDI number → ABC pitch token. ABC's octave anchor is fixed by the standard:\n * middle C (MIDI 60, C4) is uppercase `C`; lowercase `c` = C5; a comma drops an\n * octave (`C,` = C3), an apostrophe raises one (`c'` = C6). Sharps carry a `^`.\n */\nexport function midiToAbc(midi: number): string {\n const pc = ((midi % 12) + 12) % 12;\n const octave = Math.floor(midi / 12) - 1; // MIDI 60 → 4\n const token = ABC_SHARP[pc]!;\n const acc = token[0] === '^' ? '^' : '';\n const letter = acc ? token[1]! : token[0]!;\n return octave >= 5\n ? acc + letter.toLowerCase() + \"'\".repeat(octave - 5)\n : acc + letter + ','.repeat(4 - octave);\n}\n\n/**\n * ABC duration suffix for a beat length, where the unit note (`L:`) is one\n * matra = a quarter note. Whole numbers append the multiplier (`2`, `3`);\n * simple fractions use `/n` (`/2` = eighth); anything else falls back to the\n * nearest 1/4-matra count of `/4` units so odd durations still sum correctly.\n */\nexport function abcDuration(beats: number): string {\n if (Math.abs(beats - 1) < 1e-6) return '';\n if (Math.abs(beats - Math.round(beats)) < 1e-6) return String(Math.round(beats));\n const inv = 1 / beats;\n if (Math.abs(inv - Math.round(inv)) < 1e-6) return `/${Math.round(inv)}`;\n // Fallback: express in sixteenth-note (1/4-matra) units, e.g. 0.75 → 3/4.\n const sixteenths = Math.max(1, Math.round(beats * 4));\n return `${sixteenths}/4`;\n}\n\n/** One ABC note token: optional grace, the pitch, its duration. */\nfunction abcNote(ev: PlayEvent): string {\n const grace = ev.kan.length > 0 ? `{${ev.kan.map(midiToAbc).join('')}}` : '';\n return `${grace}${midiToAbc(ev.midi!)}${abcDuration(ev.durationBeats)}`;\n}\n\n/**\n * The `part.row.note` path for each ABC note/rest token, in emission order —\n * i.e. index N here is abcjs's `data-index=\"N\"` (verified: abcjs assigns one\n * incrementing index per `.abcjs-note`/`.abcjs-rest` element, in tune order,\n * and skips bars entirely — the same tokens `buildAbc` pushes). Used to paint\n * `data-note` onto the engraved SVG so playback highlighting reuses the exact\n * `highlight()`/`data-note` mechanism the grid languages already have.\n */\nfunction eventPaths(schedule: Schedule): string[] {\n const paths: string[] = [];\n for (const ev of schedule.events) {\n if (ev.midi !== null || ev.kind === 'rest') paths.push(ev.path);\n }\n return paths;\n}\n\n/* ---- Schedule → ABC tune -------------------------------------------- */\n\n/** One তাল stretch of the score: its meter, and drum voices when drums are on. */\nexport interface AbcMeter {\n /** Start, in schedule beats. */\n beat: number;\n /** Matra per bar (one তাল cycle) from here on. */\n beatsPerBar: number;\n /** Per-matra drum voices from here on; `undefined` rests (মুক্তছন্দ). */\n drums?: DrumVoice[];\n}\n\nconst barLen = (m: AbcMeter): number => (m.beatsPerBar > 0 ? m.beatsPerBar : 4);\n\n/** Strip newlines/field-leaders so a title/text is safe inside an ABC field. */\nfunction abcText(s: string): string {\n return s.replace(/[\\r\\n]+/g, ' ').trim();\n}\n\n/**\n * Build a complete ABC tune string from a schedule. Pure and dependency-free\n * (the testable seam). Rests advance time as `z`; melody notes carry duration;\n * lyrics become a `w:` line aligned to the notes.\n *\n * Bar lines are inserted every `beatsPerBar` matra (= one তাল cycle, so an ABC\n * measure is one আবর্তন). This is what lets abcjs **wrap into short systems** —\n * it only breaks lines at bar lines. `M:` is set to match so the notes-per-bar\n * check-out. The tempo (`Q:`) rides the header.\n *\n * `drums`, if given, is the taal's per-beat `drumPattern()` — a second\n * `V:2 clef=perc` percussion staff is added below the melody, cycling that\n * pattern one quarter-note per matra with `%%percmap` GM drum sounds (see\n * `buildDrumVoice`). Both voices share the same bar grid, so they wrap and\n * align together.\n *\n * `meters`, if given, is one entry per তাল stretch (তালফেরতা): at each start\n * the running bar is closed and the new meter restated inline as `[M:n/4]` —\n * the bracketed form, because a bare `M:` line forces a new system.\n */\nexport function buildAbc(\n schedule: Schedule,\n lyricOf: (ev: PlayEvent) => string | undefined,\n opts: { bpm: number; lyrics: boolean; beatsPerBar: number; drums?: DrumVoice[]; meters?: AbcMeter[] },\n): string {\n const meters = opts.meters?.length ? opts.meters : [{ beat: 0, beatsPerBar: opts.beatsPerBar, drums: opts.drums }];\n const withDrums = opts.drums !== undefined || meters.some((m) => m.drums !== undefined);\n let m = 0;\n let beatsPerBar = barLen(meters[0]!);\n const tokens: string[] = [];\n const words: string[] = [];\n let barPos = 0; // matra elapsed within the current measure\n const EPS = 1e-6;\n\n const advance = (dur: number) => {\n barPos += dur;\n // Close every full measure (a note may fill/overflow more than one).\n while (barPos >= beatsPerBar - EPS) {\n tokens.push('|');\n words.push('|');\n barPos -= beatsPerBar;\n }\n };\n\n schedule.events.forEach((ev, i) => {\n while (m + 1 < meters.length && ev.beat >= meters[m + 1]!.beat - EPS) {\n m++;\n if (barPos > EPS) {\n tokens.push('|');\n words.push('|');\n }\n barPos = 0;\n const next = barLen(meters[m]!);\n if (next !== beatsPerBar) tokens.push(`[M:${ratioMeter(next)}]`);\n beatsPerBar = next;\n }\n if (ev.midi === null) {\n if (ev.kind === 'rest') {\n tokens.push(`z${abcDuration(ev.durationBeats)}`);\n words.push('*');\n advance(ev.durationBeats);\n }\n return; // zero-time আ-কার holds already folded into the previous note\n }\n // মীড় → an ABC slur over the glided notes: one bow/breath, pitch moving.\n const more = glideTargets(schedule.events, i).length > 0;\n const slurOpen = ev.glide !== true && more ? '(' : '';\n const slurClose = ev.glide === true && !more ? ')' : '';\n tokens.push(`${slurOpen}${abcNote(ev)}${slurClose}`);\n const lyr = lyricOf(ev);\n // abcjs splits w: on spaces; '~' joins a multi-word syllable, '*' is blank.\n words.push(lyr ? abcText(lyr).replace(/\\s+/g, '~') : '*');\n advance(ev.durationBeats);\n });\n\n // Final barline (song end) if the last note didn't land exactly on a bar.\n if (tokens.length && tokens[tokens.length - 1] !== '|') tokens.push('|]');\n else if (tokens.length) tokens[tokens.length - 1] = '|]';\n\n // No T: title — abcjs draws it oversized above the first system and collides\n // with the host page. Title/tempo/instrument live in the `.sw-staff` wrapper.\n const meter = ratioMeter(barLen(meters[0]!));\n const head = ['X:1', `M:${meter}`, 'L:1/4', `Q:1/4=${Math.round(opts.bpm)}`];\n if (withDrums) head.push(...percMapLines(meters.flatMap((x) => x.drums ?? [])));\n head.push('K:C treble');\n\n const melodyBody = tokens.length ? tokens.join(' ') : 'z |]';\n const lines = [...head];\n if (withDrums) {\n lines.push('V:1', melodyBody);\n if (opts.lyrics && words.some((w) => w !== '*' && w !== '|')) lines.push(`w: ${words.join(' ')}`);\n lines.push('V:2 clef=perc stem=up', buildDrumVoice(schedule.totalBeats, meters));\n } else {\n lines.push(melodyBody);\n if (opts.lyrics && words.some((w) => w !== '*' && w !== '|')) lines.push(`w: ${words.join(' ')}`);\n }\n return lines.join('\\n');\n}\n\n/** Meter string for a bar of N quarter-note beats (N/4). */\nfunction ratioMeter(beats: number): string {\n return `${Math.max(1, Math.round(beats))}/4`;\n}\n\n/* ---- Percussion voice (Western-drumset rendering of the taal) -------- */\n\n/** ABC pitch letter used as each drum voice's percmap key (arbitrary but\n * fixed — must be a real ABC note letter, not `z`/`x`, which abcjs reserves\n * for rests/invisible rests). GM percussion names abcjs's `%%percmap`\n * understands; see the General MIDI drum map. */\nconst DRUM_ABC: Record<DrumVoice, { note: string; gm: string }> = {\n kick: { note: 'F,', gm: 'bass-drum-1' },\n snare: { note: 'C', gm: 'acoustic-snare' },\n hihat: { note: 'g', gm: 'closed-hi-hat' },\n tom1: { note: 'E', gm: 'high-tom' },\n tom2: { note: 'A,', gm: 'low-mid-tom' },\n tom3: { note: 'D,', gm: 'low-floor-tom' },\n};\n\n/** `%%percmap` header lines mapping each used drum voice to its GM sound. */\nfunction percMapLines(voices: Iterable<DrumVoice>): string[] {\n const seen = new Set<DrumVoice>();\n const lines: string[] = [];\n for (const v of voices) {\n if (seen.has(v)) continue;\n seen.add(v);\n const { note, gm } = DRUM_ABC[v];\n lines.push(`%%percmap ${note} ${gm}`);\n }\n return lines;\n}\n\n/**\n * Build the `V:2 clef=perc` drum-voice tune body: one quarter-note token per\n * matra for `totalBeats` (cycling each stretch's `drumPattern`, a rest where it\n * has none), barred every `beatsPerBar` matra and re-metered at each তাল\n * change — the same bar grid as the melody voice, so both staves wrap and\n * align together.\n */\nfunction buildDrumVoice(totalBeats: number, meters: AbcMeter[]): string {\n const tokens: string[] = [];\n meters.forEach((m, i) => {\n const bpb = barLen(m);\n if (i > 0) {\n if (tokens.length > 0 && tokens[tokens.length - 1] !== '|') tokens.push('|');\n if (bpb !== barLen(meters[i - 1]!)) tokens.push(`[M:${ratioMeter(bpb)}]`);\n }\n const end = meters[i + 1]?.beat ?? Math.max(1, Math.ceil(totalBeats));\n const n = Math.ceil(end - m.beat - 1e-6);\n for (let beat = 0; beat < n; beat++) {\n tokens.push(m.drums?.length ? DRUM_ABC[m.drums[beat % m.drums.length]!].note : 'z');\n if ((beat + 1) % bpb === 0) tokens.push('|');\n }\n });\n if (tokens.length === 0 || tokens[tokens.length - 1] !== '|') tokens.push('|]');\n else tokens[tokens.length - 1] = '|]';\n return tokens.join(' ');\n}\n\n/* ---- Doc → ABC (wires the schedule to the doc's lyrics) -------------- */\n\n/** Map each schedule event back to its source note's lyric via the `part.row.note` path. */\nfunction lyricLookup(doc: Swaralipi): (ev: PlayEvent) => string | undefined {\n return (ev) => {\n const [p, r, i] = ev.path.split('.').map(Number);\n return doc.parts[p!]?.rows[r!]?.notes[i!]?.lyric;\n };\n}\n\n/** The taal driving a stretch's drum pattern: its own (if known to the player's\n * sample/theory tables), else a plain 4-beat cycle — mirrors the player's own\n * `taalId ?? { numBeats: 4, sam: 0 }` fallback in `#buildRhythm`. */\nfunction resolveDrumTaal(taal: Taal | null | undefined): Pick<Taal, 'numBeats' | 'sam' | 'bhaags' | 'khaali'> {\n const id = taal?.id;\n return id !== undefined && id in TAALS ? TAALS[id as TaalId] : { numBeats: 4, sam: 0 };\n}\n\n/** Build the ABC tune string for a whole document (schedule + lyrics + tempo).\n * The measure length is one তাল cycle — per stretch, so a তালফেরতা changes the\n * time signature where the taal changes — falling back to 4.\n * `opts.drums` adds the percussion staff (see `buildAbc`). */\nexport function docToAbc(doc: Swaralipi, opts: StaffOptions = {}): string {\n const schedule = buildSchedule(doc, { tonic: opts.tonic, baseOctave: opts.baseOctave, lay: false });\n const bpm = opts.bpm ?? doc.meta.bpm ?? 90;\n const meters: AbcMeter[] = schedule.tempo.map((seg) => ({\n beat: seg.beat,\n beatsPerBar: opts.beatsPerBar ?? seg.taal?.numBeats ?? 4,\n drums: opts.drums && seg.taal !== null ? drumPattern(resolveDrumTaal(seg.taal)) : undefined,\n }));\n return buildAbc(schedule, lyricLookup(doc), {\n bpm,\n lyrics: opts.lyrics !== false,\n beatsPerBar: meters[0]!.beatsPerBar,\n drums: opts.drums ? (meters[0]!.drums ?? []) : undefined,\n meters,\n });\n}\n\n/* ---- ABC → SVG via abcjs (browser/jsdom only) ----------------------- */\n\n/**\n * Render an ABC tune string to engraved HTML using abcjs. Requires a DOM\n * (`document`) — abcjs measures glyphs and draws into an element; call it in a\n * browser, in a print iframe, or under jsdom (tests stub `getBBox`). abcjs is\n * dynamically imported so it is never bundled or loaded unless staff notation\n * is actually used.\n *\n * The music is **wrapped into short systems** (a few bars per line, each its\n * own SVG-in-DIV) — matching how আকারমাত্রিক swaralipi is laid out in stacked\n * rows rather than one long staff. Returns the full multi-line markup (all\n * line DIVs), or a notice string if abcjs is not installed.\n *\n * `notePaths`, if given, is the `part.row.note` highlight path for each ABC\n * melody note/rest token in schedule order (see `eventPaths`). The melody is\n * voice 0; abcjs emits its `.abcjs-v0.abcjs-note`/`.abcjs-rest` elements in\n * document order = that same order, so painting `notePaths[i]` onto the i-th\n * melody element gives every engraved note the same `data-note` attribute the\n * grid languages use — playback highlighting works identically for staff. (We\n * key off voice + document order, NOT `data-index`: with a drum voice abcjs\n * numbers each line/voice block separately, so data-index isn't global order.)\n */\nexport async function abcToSvg(abc: string, opts: StaffOptions = {}, notePaths?: string[]): Promise<string> {\n if (typeof document === 'undefined') {\n throw new Error('abcToSvg requires a DOM; render staff notation in the browser or print iframe');\n }\n let ABCJS: typeof import('abcjs');\n try {\n const mod = await import('abcjs');\n ABCJS = (mod as { default?: typeof import('abcjs') }).default ?? mod;\n } catch {\n return `<div class=\"sw-staff-missing\">Staff notation needs the optional <code>abcjs</code> package.</div>`;\n }\n // abcjs measures glyph/line heights from live layout to decide where to wrap\n // and split systems — a purely detached div reports height 0, collapsing the\n // staves. So render into an off-screen-but-attached host, read the markup,\n // then remove it.\n const host = document.createElement('div');\n host.style.cssText = 'position:fixed; left:-10000px; top:0; width:720px; visibility:hidden;';\n const mount = document.body ?? document.documentElement;\n mount.appendChild(host);\n try {\n ABCJS.renderAbc(host, abc, {\n add_classes: true,\n staffwidth: opts.staffwidth ?? 680,\n scale: opts.scale ?? 1,\n // Reflow into short lines. staffwidth is the width budget;\n // preferredMeasuresPerLine keeps systems swaralipi-short.\n // (Not `responsive: resize` — its absolute-positioned aspect-ratio wrapper\n // overlaps the header and mis-sizes on the print page.)\n wrap: { minSpacing: 1.8, maxSpacing: 2.7, preferredMeasuresPerLine: opts.measuresPerLine ?? 4 },\n // CRUCIAL: put each wrapped system in its OWN <svg> (default is all systems\n // stacked in one tall SVG, which is atomic and can't page-break — that was\n // the near-blank-first-page / mid-staff-cutoff print bug). One SVG per line\n // lets `break-inside: avoid` keep each staff whole while pages fill.\n oneSvgPerLine: true,\n });\n // abcjs sizes each SVG with fixed pixel width/height and NO viewBox, so it\n // can't shrink to a narrow container / print page. Give each a viewBox and\n // drop the fixed size; the CSS then scales it (aspect ratio preserved).\n for (const svg of host.querySelectorAll('svg')) {\n const w = parseFloat(svg.getAttribute('width') ?? '');\n const h = parseFloat(svg.getAttribute('height') ?? '');\n if (w > 0 && h > 0) {\n // abcjs (v6) sets a fixed pixel width/height (and a viewBox). The fixed\n // width blocks shrinking to a narrow container, but dropping it lets the\n // CSS `width:100%` STRETCH a short system to fill a wide container. So\n // drop the fixed size (shrink-to-fit) but pin max-width to the engraved\n // width (never stretch past it) — the score stays swaralipi-sized.\n if (!svg.getAttribute('viewBox')) svg.setAttribute('viewBox', `0 0 ${w} ${h}`);\n svg.setAttribute('preserveAspectRatio', 'xMinYMin meet');\n svg.removeAttribute('width');\n svg.removeAttribute('height');\n svg.setAttribute('style', `max-width:${w}px`);\n }\n }\n // Paint data-note onto each engraved MELODY note/rest so playback\n // highlighting works exactly like the grid languages (see notePaths doc).\n // abcjs's `data-index` is NOT global tune order — with a drum voice it\n // numbers each (line, voice) block separately, so the drum notes get indices\n // that collide with the melody's. The melody is always voice 0 (`abcjs-v0`);\n // its note/rest elements appear in document order = schedule order, so we\n // match `notePaths` by position over just those, ignoring data-index.\n if (notePaths) {\n const melody = host.querySelectorAll('.abcjs-v0.abcjs-note, .abcjs-v0.abcjs-rest');\n let i = 0;\n for (const el of melody) {\n const path = notePaths[i++];\n if (path !== undefined) el.setAttribute('data-note', path);\n }\n }\n // abcjs emits one <div><svg>…</svg></div> per wrapped line; return them all.\n return host.innerHTML;\n } finally {\n host.remove();\n }\n}\n\n/**\n * Full doc → staff-notation HTML fragment: the shared নাম/তাল/আবর্তন/স্বরলিপিকার\n * header (same block as the akarmatrik grid, so the staff shows the identical\n * metadata) + an instrument label + the wrapped Western systems. Styled by\n * SWARALIPI_CSS + SWARALIPI_STAFF_CSS. Async because abcjs is dynamic-imported.\n */\nexport async function renderStaffHtml(doc: Swaralipi, opts: StaffOptions = {}): Promise<string> {\n const bpm = opts.bpm ?? doc.meta.bpm ?? 90;\n const abc = docToAbc(doc, { ...opts, bpm });\n const schedule = buildSchedule(doc, { tonic: opts.tonic, baseOctave: opts.baseOctave, lay: false });\n const engraved = await abcToSvg(abc, opts, eventPaths(schedule));\n // The abcjs output is the wrapped systems (or the \"needs abcjs\" notice, which\n // is passed through un-wrapped).\n const lines = engraved.includes('sw-staff-missing')\n ? engraved\n : `<div class=\"sw-staff-lines\">${engraved}</div>`;\n // Same header as the grid (title/taal/raag/avartan/notator). Labels in\n // headerLang (default en — the Western view); values are pre-localized by\n // the consumer. abcjs engraves the tempo (Q:) itself, so the instrument label\n // is the only extra strip.\n const header =\n opts.showHeader === false ? '' : renderMetaHeader(doc.meta, opts.headerLang ?? 'en', opts.transliterate);\n const metaParts: string[] = [];\n if (opts.instrument) metaParts.push(`<span class=\"sw-staff-instrument\">${escapeAttr(opts.instrument)}</span>`);\n if (opts.drums) metaParts.push(`<span class=\"sw-staff-drums\">+ drums</span>`);\n const meta = metaParts.length ? `<div class=\"sw-staff-meta\">${metaParts.join('')}</div>` : '';\n return `<div class=\"sw-staff\">${header}${meta}${lines}</div>`;\n}\n\nfunction escapeAttr(s: string): string {\n return s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/\"/g, '"');\n}\n\n/* ---- Bare taal (theka) drum staff ----------------------------------- */\n\n/** Options for the standalone taal staff (a single percussion voice — no\n * melody doc). Layout fields mirror `StaffOptions`; `abcToSvg` reads them. */\nexport interface TaalStaffOptions {\n /** Tempo written into the score (Q:). Default 90. */\n bpm?: number;\n /** Per-matra drum voices (one per beat of the cycle). Default: the taal's own\n * `drumPattern()` (sam→kick, tali→snare, khaali→hihat). Length is cycled to\n * `numBeats`, so an explicit book-accurate mapping overrides the geometric one. */\n drums?: DrumVoice[];\n /** Theka bols aligned under each matra (the `w:` line). One per beat. */\n bols?: string[];\n /** abcjs target width in px. Default 680. */\n staffwidth?: number;\n /** abcjs `scale`. Default 1. */\n scale?: number;\n}\n\n/**\n * Build a **percussion-only** ABC tune for one avartan of a taal — no melody\n * voice. One quarter-note per matra over a single `V:1 clef=perc` staff, voices\n * from `opts.drums ?? drumPattern(taal)`, `%%percmap` for the used sounds, and\n * (optional) bols as the aligned `w:` line. The whole cycle is one bar (M:n/4).\n * Pure + dependency-free — the testable seam, mirroring `buildAbc`.\n */\nexport function buildTaalAbc(taal: Pick<Taal, 'numBeats' | 'sam' | 'bhaags' | 'khaali'>, opts: TaalStaffOptions = {}): string {\n const n = Math.max(1, taal.numBeats);\n const src = opts.drums && opts.drums.length ? opts.drums : drumPattern(taal);\n const voices = Array.from({ length: n }, (_, i) => src[i % src.length]!);\n const bpm = Math.round(opts.bpm ?? 90);\n const head = ['X:1', `M:${ratioMeter(n)}`, 'L:1/4', `Q:1/4=${bpm}`, ...percMapLines(voices), 'K:C'];\n const lines = [...head, 'V:1 clef=perc stem=up', buildDrumVoice(n, [{ beat: 0, beatsPerBar: n, drums: voices }])];\n if (opts.bols?.length) {\n const w = opts.bols.slice(0, n).map((b) => (b.trim() ? abcText(b).replace(/\\s+/g, '~') : '*'));\n while (w.length < n) w.push('*');\n lines.push(`w: ${w.join(' ')}`);\n }\n return lines.join('\\n');\n}\n\n/**\n * Render a standalone taal theka as an engraved drum staff (abcjs). Each perc\n * note carries `data-note=\"<matra-index>\"` so a consumer's per-beat clock can\n * highlight the active note (the same `data-note` mechanism the grid uses).\n * Async because abcjs is dynamic-imported; returns a \"needs abcjs\" notice if\n * the optional package is absent.\n */\nexport async function renderTaalStaffHtml(\n taal: Pick<Taal, 'numBeats' | 'sam' | 'bhaags' | 'khaali'>,\n opts: TaalStaffOptions = {},\n): Promise<string> {\n const abc = buildTaalAbc(taal, opts);\n const n = Math.max(1, taal.numBeats);\n const paths = Array.from({ length: n }, (_, i) => String(i));\n const engraved = await abcToSvg(abc, { staffwidth: opts.staffwidth, scale: opts.scale }, paths);\n const lines = engraved.includes('sw-staff-missing') ? engraved : `<div class=\"sw-staff-lines\">${engraved}</div>`;\n return `<div class=\"sw-staff sw-staff--taal\">${lines}</div>`;\n}\n","/**\n * Tone.js instrument/asset factories. Tone is **injected** (never imported\n * here) so this module — like the scheduler — stays free of a static `tone`\n * dependency; the player passes the dynamically-imported module in.\n *\n * Melodic instruments are a small registry (INSTRUMENTS) of Tone.Sampler\n * note→file maps + where to fetch them. `piano` (CC-BY Salamander) is the\n * default and CDN-hosted, as are `harmonium`/`violin`/`flute` (CC-BY,\n * tonejs-instruments); `santoor` is local (under the player's `soundsBaseUrl`).\n * Consumers can register more (e.g. a self-hosted sitar) via the player's\n * `customInstruments` option — true sampled sitar/sarod/sarangi/esraj have no\n * free web set, only commercial Kontakt libraries.\n *\n * Asset layout under `soundsBaseUrl`:\n * santoor/<note>.mp3 c4..c7 + sharps (37 files)\n * tanpura/<pc>.mp3 12 pitch classes (c, cs, d, …)\n * tabla/<seg>/<seg><bpm>bpm.mp3 seg = <taal>[-<variation>], bpm 60..300 step 15\n * metronome/metro2.mp3\n */\n// Import TAALS from the taals subpath (not the ../spec/index barrel): the\n// barrel re-exports schema.ts, which statically imports zod — pulling that into\n// the player would break its \"loads bare in a browser\" guarantee. taals.ts has\n// only a type-only schema import, so this keeps the player runtime zod-free.\nimport type { Taal } from '../spec/schema.js';\nimport { TAALS, type TaalId } from '../spec/taals.js';\nimport { sCurve, sampleFileName } from './pitch.js';\n\n/** The dynamically-imported Tone module, typed without importing it. */\nexport type ToneModule = typeof import('tone');\n\n/** A melodic instrument: a Tone.Sampler note→filename map + where to find it. */\nexport interface InstrumentDef {\n /** Human label for UIs. */\n label: string;\n /** Tone.Sampler `urls`: note name (`C#4`) → filename (`Cs4.mp3`). */\n urls: Record<string, string>;\n /** Sample directory: an absolute URL, or — when `local` — a path segment\n * appended to the player's `soundsBaseUrl`. */\n baseUrl: string;\n /** `baseUrl` is relative to `soundsBaseUrl` (needs it set). */\n local?: boolean;\n /** Sampler release time in seconds. */\n release?: number;\n}\n\n/** Built-in melody instrument ids (consumers may add their own via the\n * player's `customInstruments`, so the runtime id type stays open). */\nexport type InstrumentId = string;\n\n/**\n * Default host for the project's samples (santoor / tabla / tanpura /\n * metronome) — CORS-enabled, so the player works with zero config. Override via\n * the player's `soundsBaseUrl` to self-host. (Melody defaults to the CDN-hosted\n * piano, so it needs no host.) Licences: see THIRD-PARTY.md.\n */\nexport const DEFAULT_SOUNDS_BASE = 'https://bitoron.pages.dev/audio/instruments/';\n/** CC-BY Salamander Grand Piano (Tone's de-facto piano), CDN-hosted. */\nexport const SALAMANDER_BASE = 'https://tonejs.github.io/audio/salamander/';\n/** CC-BY tonejs-instruments sample CDN (harmonium/violin/flute). */\nexport const TONEJS_INSTRUMENTS_BASE = 'https://nbrosowsky.github.io/tonejs-instruments/samples/';\n\n/** Build a Tone.Sampler `urls` map from bare note keys (`C#4` → `Cs4.mp3`). */\nfunction keyMap(keys: readonly string[]): Record<string, string> {\n const m: Record<string, string> = {};\n for (const k of keys) m[k] = `${k.replace('#', 's')}.mp3`;\n return m;\n}\n\nconst PIANO_KEYS = [\n 'A0', 'C1', 'D#1', 'F#1', 'A1', 'C2', 'D#2', 'F#2', 'A2', 'C3', 'D#3', 'F#3',\n 'A3', 'C4', 'D#4', 'F#4', 'A4', 'C5', 'D#5', 'F#5', 'A5', 'C6', 'D#6', 'F#6',\n 'A6', 'C7', 'D#7', 'F#7', 'A7', 'C8',\n] as const;\n// harmonium — a core Rabindrasangeet accompaniment (C2..C5). The CDN set has no F#4 (404).\nconst HARMONIUM_KEYS = [\n 'C2', 'C#2', 'D2', 'D#2', 'E2', 'F2', 'F#2', 'G2', 'G#2', 'A2', 'A#2',\n 'C3', 'C#3', 'D3', 'D#3', 'E3', 'F3', 'F#3', 'G3', 'G#3', 'A3', 'A#3',\n 'C4', 'C#4', 'D4', 'D#4', 'E4', 'F4', 'G4', 'G#4', 'A4', 'A#4',\n 'C5', 'C#5', 'D5',\n] as const;\nconst VIOLIN_KEYS = ['A3', 'C4', 'E4', 'G4', 'A4', 'C5', 'E5', 'G5', 'A5', 'C6', 'E6', 'G6', 'A6', 'C7'] as const;\nconst FLUTE_KEYS = ['C4', 'E4', 'A4', 'C5', 'E5', 'A5', 'C6', 'E6', 'A6', 'C7'] as const;\n\n/** Built-in melody instruments. santoor is local; the rest are CDN-hosted\n * (CC-BY) so they need only network — `pianoBaseUrl`/`customInstruments`\n * override for self-hosting. */\nexport const INSTRUMENTS: Record<string, InstrumentDef> = {\n piano: { label: 'Grand piano', urls: keyMap(PIANO_KEYS), baseUrl: SALAMANDER_BASE, release: 1 },\n santoor: { label: 'Santoor', urls: santoorUrls(), baseUrl: 'santoor/', local: true, release: 1.2 },\n harmonium: { label: 'Harmonium', urls: keyMap(HARMONIUM_KEYS), baseUrl: `${TONEJS_INSTRUMENTS_BASE}harmonium/`, release: 1.4 },\n violin: { label: 'Violin', urls: keyMap(VIOLIN_KEYS), baseUrl: `${TONEJS_INSTRUMENTS_BASE}violin/`, release: 1 },\n flute: { label: 'Flute', urls: keyMap(FLUTE_KEYS), baseUrl: `${TONEJS_INSTRUMENTS_BASE}flute/`, release: 1 },\n};\n\n/** Taals with recorded tabla loops (everything else → metronome fallback). */\nexport const SAMPLED_TAALS: ReadonlySet<TaalId> = new Set(\n Object.keys(TAALS) as TaalId[],\n);\n\n/** Available tabla loop tempos (file suffix `…<bpm>bpm.mp3`). */\nexport const TABLA_BPMS: readonly number[] = Array.from({ length: 17 }, (_, i) => 60 + i * 15);\n\n/**\n * Tabla loop variations per taal. Most taals have one unnamed loop at\n * `tabla/<id>/`; an entry here overrides that:\n * - `variations` lists the variation suffixes, **first = default**.\n * A lone named variation (shashthi → `pro`, i.e. `tabla/shashthi-pro/`) IS\n * the default; later entries are premium upsells the player never auto-selects.\n * An empty-string entry (kehrwa → `''`) means the unnamed `tabla/<id>/` loop\n * is the default and a named entry follows it as an upsell.\n * - `skipBpms` are grid tempos this taal's loops were not recorded at.\n * Consumers read this to build a variation/upsell UI; the player itself only\n * ever plays the default (or whatever a doc's `meta.taal.variation` pins).\n */\nexport const TABLA_VARIATIONS: Record<\n string,\n { variations: string[]; skipBpms?: number[] }\n> = {\n // ষষ্ঠী loops live under `tabla/shashthi-pro/`; full bpm grid recorded except 225.\n shashthi: { variations: ['pro'], skipBpms: [225] },\n // Kehrwa keeps its unnamed default loop; `qawwali` (tabla/kehrwa-qawwali/) is a\n // premium upsell variation recorded 90–300 (no 60/75).\n // ponytail: skipBpms is per-taal, so it can't restrict qawwali's 60/75 without\n // also dropping them from the default (which has them) — a qawwali doc pinned\n // ≤67 bpm 404s harmlessly. Make skipBpms per-variation only if that edge bites.\n kehrwa: { variations: ['', 'qawwali'] },\n};\n\n/** Tabla tempos actually available for a taal: the grid minus any it lacks. */\nexport function tablaBpms(taalId: string): readonly number[] {\n const skip = TABLA_VARIATIONS[taalId]?.skipBpms;\n return skip && skip.length ? TABLA_BPMS.filter((b) => !skip.includes(b)) : TABLA_BPMS;\n}\n\n/** CDN directory/filename segment for a taal's tabla loop: `<taalId>` or\n * `<taalId>-<variation>` (explicit variation, else the taal's default). */\nfunction tablaSeg(taalId: string, variation?: string): string {\n const v = variation ?? TABLA_VARIATIONS[taalId]?.variations[0]; // default = first variation, else unnamed\n return v ? `${taalId}-${v}` : taalId;\n}\n\n/** Ensure exactly one trailing slash. */\nexport function normalizeBase(url: string): string {\n return url.endsWith('/') ? url : `${url}/`;\n}\n\n/** The 37 santoor samples, as a Tone.Sampler `urls` map (`C4` → `c4.mp3`). */\nexport function santoorUrls(): Record<string, string> {\n const urls: Record<string, string> = {};\n const add = (midi: number) => {\n const stem = sampleFileName(midi); // e.g. cs4\n const name = stem.replace('s', '#').replace(/^(.)/, (c) => c.toUpperCase()); // C#4\n urls[name] = `${stem}.mp3`;\n };\n for (let midi = 60; midi <= 95; midi++) add(midi); // C4..B6 (full)\n add(96); // C7\n return urls;\n}\n\nconst PC_BASE: Record<string, number> = { c: 0, d: 2, e: 4, f: 5, g: 7, a: 9, b: 11 };\n\n/** Parse a sample note name (`C#4`, `Ds3`, `Bb2`) to a MIDI number. */\nexport function noteToMidi(name: string): number {\n const m = /^([a-g])([#sb]?)(-?\\d+)$/i.exec(name.trim());\n if (!m) return NaN;\n const base = PC_BASE[m[1]!.toLowerCase()]!;\n const acc = m[2] === 'b' ? -1 : m[2] === '' ? 0 : 1; // # / s → sharp\n return (Number(m[3]) + 1) * 12 + base + acc;\n}\n\n/**\n * Restrict a Sampler `urls` map to just the samples needed to cover MIDI\n * `[lo, hi]`: every sample inside the range, plus the nearest one below and\n * above it (so Tone interpolates the edges without extrapolating). Cuts a\n * typical song from ~37 santoor files to a handful — a big win on mobile and\n * never worse on fast links (Tone fetches what's left in parallel). The\n * Sampler pitch-shifts from the nearest sample, so audio is unchanged.\n */\nexport function subsetUrls(\n urls: Record<string, string>,\n lo: number,\n hi: number,\n): Record<string, string> {\n const entries = Object.entries(urls)\n .map(([k, f]) => ({ k, f, midi: noteToMidi(k) }))\n .filter((e) => Number.isFinite(e.midi))\n .sort((a, b) => a.midi - b.midi);\n if (entries.length === 0) return { ...urls };\n\n const keep = new Set<string>();\n for (const e of entries) if (e.midi >= lo && e.midi <= hi) keep.add(e.k);\n // nearest sample at/below lo and at/above hi for clean interpolation\n let floor: string | undefined;\n let ceil: string | undefined;\n for (const e of entries) if (e.midi <= lo) floor = e.k;\n for (const e of entries) if (e.midi >= hi) { ceil = e.k; break; }\n if (floor) keep.add(floor);\n if (ceil) keep.add(ceil);\n if (keep.size === 0) {\n // range entirely outside the sample set — keep the single nearest sample\n const mid = (lo + hi) / 2;\n const nearest = entries.reduce((a, b) => (Math.abs(b.midi - mid) < Math.abs(a.midi - mid) ? b : a));\n keep.add(nearest.k);\n }\n\n const out: Record<string, string> = {};\n for (const e of entries) if (keep.has(e.k)) out[e.k] = e.f;\n return out;\n}\n\n/** Resolve a representative sample URL for an instrument (its first sample),\n * used to probe availability. undefined when a local instrument has no\n * `soundsBaseUrl` or the def has no samples. */\nexport function instrumentSampleUrl(def: InstrumentDef, soundsBaseUrl?: string): string | undefined {\n if (def.local && soundsBaseUrl === undefined) return undefined;\n const base = def.local ? `${normalizeBase(soundsBaseUrl ?? '')}${def.baseUrl}` : def.baseUrl;\n const file = Object.values(def.urls)[0];\n return file === undefined ? undefined : `${normalizeBase(base)}${file}`;\n}\n\n/**\n * Liveness check for a sample URL: a single tiny ranged GET (one byte), the\n * same CORS-enabled fetch Tone uses to load the buffer — so a pass means Tone\n * can actually load it. Resolves false on any error/timeout/non-2xx, and false\n * (no throw) when `fetch` is unavailable (Node/SSR). `Range: bytes=0-0` is a\n * CORS-safelisted header, so no preflight.\n */\nexport async function probeUrl(url: string, timeoutMs = 6000): Promise<boolean> {\n if (typeof fetch === 'undefined') return false;\n const ctrl = typeof AbortController !== 'undefined' ? new AbortController() : undefined;\n const timer = ctrl ? setTimeout(() => ctrl.abort(), timeoutMs) : undefined;\n try {\n const res = await fetch(url, {\n method: 'GET',\n headers: { Range: 'bytes=0-0' },\n cache: 'no-store',\n signal: ctrl?.signal,\n });\n return res.ok; // 200 / 206\n } catch {\n return false;\n } finally {\n if (timer !== undefined) clearTimeout(timer);\n }\n}\n\n/**\n * Snap a tabla loop's end to the nearest whole beat of its measured length so a\n * slightly-mistrimmed file still phase-locks to the melody grid instead of\n * drifting a fraction of a beat each cycle. `spb` = seconds per beat (60/bpm).\n * No-op for correctly trimmed loops (already an integer beat count); never\n * extends past the buffer — a too-short file can't be repaired here.\n *\n * ponytail: belt-and-braces for off-spec audio; the real fix is trimming each\n * loop to exactly `cycles × numBeats × 60/bpm` seconds at production time.\n */\nexport function quantizeLoopEnd(durationSec: number, spb: number): number {\n if (spb <= 0) return durationSec;\n const beats = Math.round(durationSec / spb);\n if (beats < 1) return durationSec; // too short to snap to a beat\n return Math.min(beats * spb, durationSec);\n}\n\n/** Snap an arbitrary bpm to the nearest available tabla tempo (default grid;\n * pass a taal's `tablaBpms()` so it never snaps to a tempo that taal lacks). */\nexport function nearestTablaBpm(bpm: number, bpms: readonly number[] = TABLA_BPMS): number {\n return bpms.reduce((best, b) => (Math.abs(b - bpm) < Math.abs(best - bpm) ? b : best), bpms[0]!);\n}\n\n/** URL of the tabla loop for a taal at a (snapped) bpm, optionally a named\n * variation (defaults to the taal's default variation — see TABLA_VARIATIONS). */\nexport function tablaUrl(base: string, taalId: string, bpm: number, variation?: string): string {\n const seg = tablaSeg(taalId, variation);\n return `${normalizeBase(base)}tabla/${seg}/${seg}${bpm}bpm.mp3`;\n}\n\n/**\n * Pitch class (0 = C) the tabla loops were recorded at: their dayan (the tuned\n * right drum) rings at Sa ≈ C — measured off the CDN loops themselves\n * (spectral peak of the stroke decays, ~529 Hz = C5 +20 cents, consistent\n * across taals and across every bpm variant, i.e. the tempo set was\n * time-stretched, not resampled). Calibration knob: re-measure and change this\n * if the loop set is ever re-recorded.\n */\nexport const TABLA_TONIC_SEMITONE = 0;\n\n/**\n * Semitones to pitch-shift a tabla loop so its dayan matches the song's Sa.\n * Wrapped to the nearer direction (−5…+6): the drum is octave-agnostic, so a\n * B tonic shifts down 1 rather than up 11.\n */\nexport function tablaShiftSemitones(tonicSemitone: number): number {\n const d = (((tonicSemitone - TABLA_TONIC_SEMITONE) % 12) + 12) % 12;\n return d > 6 ? d - 12 : d;\n}\n\n/**\n * Grain settings for a retuned tabla loop (`Tone.GrainPlayer`, which detunes\n * independently of playback rate — so the loop keeps its recorded tempo and\n * stays phase-locked).\n *\n * Why not `Tone.PitchShift` after a plain `Player`: measured offline on the\n * teentaal loop, both shift accurately (±2 and −5 semitones confirmed by\n * spectral cross-correlation), but PitchShift's delay lines push the first\n * stroke 20–35 ms late (audibly behind the melody) and smear the spectrum;\n * GrainPlayer holds the onset at ~4 ms. Grains short enough not to blur the\n * strokes, overlapped half-way so the loop stays seamless.\n */\nexport const TABLA_GRAIN_SEC = 0.06;\nexport const TABLA_GRAIN_OVERLAP_SEC = 0.03;\n\n/** URL of the metronome click. */\nexport function metronomeUrl(base: string): string {\n return `${normalizeBase(base)}metronome/metro2.mp3`;\n}\n\n/** Build the metronome click `Tone.Player`. */\nexport function createMetronome(Tone: ToneModule, base: string) {\n return new Tone.Player(metronomeUrl(base));\n}\n\n/** Tanpura pitch-class sample stems (filename = `<stem>.mp3`). */\nexport const TANPURA_PCS = ['c', 'cs', 'd', 'ds', 'e', 'f', 'fs', 'g', 'gs', 'a', 'as', 'b'] as const;\n\n/* ---- Drum kit (Western-drumset rendering of an Indian taal) ------------\n *\n * A real drumset \"translation\" of tabla bols is an established practice\n * (e.g. Sunny Jain's Drum Atlas: India — kick on sam, snare on the accented\n * tali claps, hi-hat filling/ghosting the khaali wave), not something\n * invented here. DRUM_VOICES are one-shot acoustic-kit samples (CC0-cleared\n * Apache-2.0 Tonejs/audio collection, https://github.com/Tonejs/audio,\n * already the CDN this project uses directly for the Salamander piano) —\n * same trust tier as the other CDN-hosted instruments, no new hosting.\n */\nexport const DRUM_KIT_BASE = 'https://tonejs.github.io/audio/drum-samples/acoustic-kit/';\n\nexport type DrumVoice = 'kick' | 'snare' | 'hihat' | 'tom1' | 'tom2' | 'tom3';\nconst DRUM_FILES: Record<DrumVoice, string> = {\n kick: 'kick.mp3',\n snare: 'snare.mp3',\n hihat: 'hihat.mp3',\n tom1: 'tom1.mp3',\n tom2: 'tom2.mp3',\n tom3: 'tom3.mp3',\n};\n\n/** Build the drum-kit `Tone.Players` (one-shot voices, not looped/pitched). */\nexport function createDrumKit(Tone: ToneModule, base: string = DRUM_KIT_BASE) {\n const urls: Record<string, string> = {};\n for (const [voice, file] of Object.entries(DRUM_FILES)) urls[voice] = file;\n return new Tone.Players({ urls, baseUrl: normalizeBase(base) });\n}\n\n/**\n * Per-beat drumset voice for one তাল cycle, following sam/tali/khaali theory:\n * sam (cycle start) → kick, the first beat of each accented (non-khaali)\n * vibhag → snare (the tali clap), the first beat of a khaali vibhag → closed\n * hihat (the khaali \"wave off\"), every other beat → hihat (fill, keeping the\n * kit's groove going the way a tabla's filler strokes do).\n */\nexport function drumPattern(taal: Pick<Taal, 'numBeats' | 'sam' | 'bhaags' | 'khaali'>): DrumVoice[] {\n const n = taal.numBeats;\n const sam = taal.sam ?? 0;\n const khaali = new Set(taal.khaali ?? []);\n const bhaags = taal.bhaags ?? [n];\n const pattern: DrumVoice[] = new Array(n).fill('hihat');\n\n let pos = 0;\n for (const len of bhaags) {\n pattern[pos] = khaali.has(pos) ? 'hihat' : 'snare';\n pos += len;\n }\n pattern[sam] = 'kick';\n return pattern;\n}\n\n/**\n * Build a melody `Tone.Sampler` for an instrument def. Resolves the sample\n * directory (local → under `soundsBaseUrl`, else the def's absolute CDN URL)\n * and, when a MIDI `range` is given, loads only the samples that cover it.\n */\nexport function createSampler(\n Tone: ToneModule,\n def: InstrumentDef,\n soundsBaseUrl: string | undefined,\n range?: { lo: number; hi: number },\n) {\n const base = def.local ? `${normalizeBase(soundsBaseUrl ?? '')}${def.baseUrl}` : def.baseUrl;\n const urls = range ? subsetUrls(def.urls, range.lo, range.hi) : def.urls;\n return new Tone.Sampler({ urls, baseUrl: normalizeBase(base), release: def.release ?? 1 });\n}\n\n/* ---- মীড় (meend) — the sounded glide -------------------------------------\n *\n * A মীড় is one continuous sound whose pitch travels between svaras; the notes\n * it covers are never re-struck. A `Tone.Sampler` cannot do that — it has no\n * pitch parameter at all (checked against tone 15's own typings). What it does\n * have, one layer down, is `ToneBufferSource.playbackRate`, a real AudioParam:\n * so a glide is the instrument's own sample, started once, with its playback\n * rate automated — a tape slide, which is exactly what a hardware sampler does\n * for portamento.\n *\n * The pitch is automated as an S-curve (see `sCurve`), not a straight line, and\n * it leaves the source svara only after `MEEND_HOLD` of the gap so the written\n * note keeps its identity before rolling into the next — arriving exactly on\n * the target's own matra.\n *\n * ponytail: the glide reads from a second `ToneAudioBuffers` over the same\n * URLs as the Sampler (the browser HTTP cache means no extra download, just a\n * second decode). Share one buffer set if memory ever matters.\n */\n\n/**\n * Fraction of the gap between two মীড় notes spent holding the source pitch\n * before the slide begins. 0 = slide the whole way (an alaap-slow meend);\n * 0.5 = hold half the note, then roll into the target.\n */\nexport const MEEND_HOLD = 0.5;\n\n/** Automation points per glide leg — enough to hear as continuous. */\nconst GLIDE_STEPS = 24;\n\n/** Sampler `urls` key whose pitch is nearest `midi` (the sample to slide). */\nexport function nearestSampleKey(urls: Record<string, string>, midi: number): string {\n let best = '';\n let bestDiff = Infinity;\n for (const key of Object.keys(urls)) {\n const diff = Math.abs(noteToMidi(key) - midi);\n if (diff < bestDiff) {\n bestDiff = diff;\n best = key;\n }\n }\n return best;\n}\n\n/** The same samples `createSampler` loads, as raw buffers for the glide voice. */\nexport function createBuffers(\n Tone: ToneModule,\n def: InstrumentDef,\n soundsBaseUrl: string | undefined,\n range?: { lo: number; hi: number },\n) {\n const base = def.local ? `${normalizeBase(soundsBaseUrl ?? '')}${def.baseUrl}` : def.baseUrl;\n const urls = range ? subsetUrls(def.urls, range.lo, range.hi) : def.urls;\n return { buffers: new Tone.ToneAudioBuffers({ urls, baseUrl: normalizeBase(base) }), urls };\n}\n\n/** One মীড় leg: the pitch to reach and the absolute time to reach it by. */\nexport interface GlideLeg {\n midi: number;\n /** Seconds on the transport; `legs[0]` is the attack itself. */\n at: number;\n}\n\n/**\n * Sound one মীড় phrase: a single attack on `legs[0]` whose pitch then slides\n * through every following leg, ending at `endSec`. Used by both the live\n * player and the offline export.\n */\nexport function triggerGlide(\n Tone: ToneModule,\n buffers: InstanceType<ToneModule['ToneAudioBuffers']>,\n urls: Record<string, string>,\n dest: InstanceType<ToneModule['Gain']>,\n legs: readonly GlideLeg[],\n endSec: number,\n release = 1,\n hold = MEEND_HOLD,\n): void {\n const key = nearestSampleKey(urls, legs[0]!.midi);\n if (key === '' || !buffers.has(key)) return;\n const sampleMidi = noteToMidi(key);\n const rate = (midi: number) => Math.pow(2, (midi - sampleMidi) / 12);\n\n const source = new Tone.ToneBufferSource({\n url: buffers.get(key),\n fadeOut: release,\n curve: 'exponential',\n // Bind to the destination's context explicitly. `Tone.Offline` restores the\n // global context the moment it starts rendering, so a node built inside a\n // transport callback would otherwise land on the *online* context and the\n // offline export would render the glide as silence.\n context: dest.context,\n }).connect(dest);\n // Clean up after the note — but only on a live context. An offline render\n // runs its whole clock *before* `startRendering()`, so an onended-dispose\n // would disconnect the node before a single sample was rendered (the export\n // came out silent). The offline context is discarded wholesale anyway.\n if (!dest.context.isOffline) source.onended = () => source.dispose();\n\n const rates = source.playbackRate;\n rates.setValueAtTime(rate(legs[0]!.midi), legs[0]!.at);\n for (let k = 1; k < legs.length; k++) {\n const from = legs[k - 1]!;\n const to = legs[k]!;\n const start = from.at + (to.at - from.at) * hold;\n const values: number[] = [];\n for (let n = 0; n <= GLIDE_STEPS; n++) {\n values.push(rate(from.midi + (to.midi - from.midi) * sCurve(n / GLIDE_STEPS)));\n }\n rates.setValueCurveAtTime(values, start, Math.max(to.at - start, 0.02));\n }\n source.start(legs[0]!.at, 0, Math.max(endSec - legs[0]!.at, 0.05));\n}\n\n/** Build a tanpura `Tone.Players` loading only the given pitch-class stems\n * (the drone only ever plays Sa + Pa, so we fetch 2 files, not 12). */\nexport function createTanpura(Tone: ToneModule, base: string, stems: readonly string[] = TANPURA_PCS) {\n const urls: Record<string, string> = {};\n for (const s of stems) urls[s] = `${s}.mp3`;\n return new Tone.Players({ urls, baseUrl: `${normalizeBase(base)}tanpura/` });\n}\n","/**\n * Print / \"Save as PDF\" support.\n *\n * High-fidelity PDF of আকারমাত্রিক notation can only come from the browser's\n * own print engine — it reuses the exact HarfBuzz shaping (reph, conjuncts,\n * matra) and the CSS-drawn marks (octave dots, slur arcs, danda strokes) that\n * the viewer renders on screen. Rasterizers (html2canvas) and PDF-primitive\n * libraries (jsPDF/pdfmake) have no Indic shaping and drop pseudo-element\n * marks, so we deliberately avoid them. Staff notation (lang `staff`) is drawn\n * by abcjs to SVG, which the same print engine engraves faithfully.\n *\n * `renderPrintDocument` builds a self-contained HTML page from the pure\n * `renderToHtml` + `SWARALIPI_CSS` (so it sidesteps the shadow-DOM \"print drops\n * encapsulated styles\" gotcha); `printSwaralipi` prints it via a hidden iframe.\n * Both reuse the same renderer as the viewer, so the PDF matches the screen.\n *\n * Every printed page also carries a light diagonal watermark and a notator\n * credit footer — both defaulted for gitabitan.io but overridable by consumers.\n */\nimport type { Swaralipi } from '../spec/index.js';\nimport type { ViewerLang } from './glyphs.js';\nimport { renderToHtml } from './render.js';\nimport { renderStaffHtml, type StaffOptions } from './staff.js';\nimport { SWARALIPI_CSS, SWARALIPI_PRINT_CSS, SWARALIPI_STAFF_CSS } from './styles.js';\nimport { fitSwaralipi } from './fit.js';\n\n/** Default diagonal page watermark (empty string disables it). */\nexport const DEFAULT_WATERMARK = 'www.gitabitan.io';\n/** Default notator credit printed in the footer. */\nexport const DEFAULT_NOTATOR = 'gitabitan.io Team';\n\nexport interface PrintOptions extends StaffOptions {\n /** Notation + UI language. `staff` = Western staff notation. Default `bn`. */\n lang?: ViewerLang;\n /** Render the নাম/তাল header block. Default true. */\n showHeader?: boolean;\n /** Lyric/title transliterator for hi/en (see loadLyricTransliterator). */\n transliterate?: (bengaliText: string) => string;\n /** Document `<title>` — the browser's default \"Save as PDF\" filename.\n * Defaults to the document's `meta.title`. */\n title?: string;\n /** Diagonal full-page watermark. Default `www.gitabitan.io`; '' to disable. */\n watermark?: string;\n /** Notator credited in the footer. Default `gitabitan.io Team`; '' to disable.\n * A document's `meta.notationBy` takes precedence when present. */\n notator?: string;\n}\n\nfunction escapeHtml(s: string): string {\n return s\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"');\n}\n\n/** Diagonal watermark: an SVG data-URI **background** on a fixed, empty `<div>`.\n *\n * Two constraints, and only this shape satisfies both.\n *\n * 1. IT MUST FIT. The box is unknowable from in here — a phone's print page, an A4\n * page, or a 1240×6000 rendered sheet whose `<body>` the consumer additionally\n * `zoom`s. A `vw` font-size answers to the viewport, not to that box, so the old\n * rotated `<span>` ran off the edge and was clipped: \"www.gitabitan\" with the \".io\"\n * shorn off. `preserveAspectRatio` + `background-size: contain` scale the mark into\n * whatever box it lands in, and `textLength` pins the line inside the viewBox — so it\n * fits BY CONSTRUCTION at every size, aspect ratio, zoom, watermark string and font.\n *\n * 2. IT MUST REPEAT ON EVERY PRINTED PAGE. Chrome tiles a `position: fixed` BOX per page\n * but NOT a fixed *replaced* element: an inline `<svg>`, whether fixed itself or\n * inside a fixed div, paints on page one and nowhere else (verified against a real\n * paginated PDF). A background image is part of the box's own painting, so it repeats\n * — and `print-color-adjust: exact` is what carries it past Chrome's \"Background\n * graphics\" checkbox, which is off by default.\n *\n * The SVG is an isolated document and cannot inherit the page's fonts, hence the inline\n * `sans-serif`. `font-size` then only sets the HEIGHT (textLength fixes the width), so it\n * is estimated from the character count to keep glyph proportions natural (~0.62em average\n * advance for bold sans). Capped, or a short mark like \"DRAFT\" would be stretched across\n * the whole page — there the natural width is used instead and the line simply centres. */\nfunction watermarkCss(text: string): string {\n if (!text) return '';\n const span = 92; // rotated -35° inside a 100×100 viewBox, this clears every edge\n const size = Math.min(18, span / (0.62 * text.length));\n const len = Math.min(span, 0.62 * text.length * size);\n const svg =\n '<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 100 100\" preserveAspectRatio=\"xMidYMid meet\">' +\n '<text x=\"50\" y=\"50\" dy=\".35em\" text-anchor=\"middle\" font-family=\"sans-serif\" font-weight=\"700\"' +\n ` fill=\"rgba(0,0,0,0.07)\" font-size=\"${size.toFixed(2)}\" textLength=\"${len.toFixed(2)}\"` +\n ` lengthAdjust=\"spacingAndGlyphs\" transform=\"rotate(-35 50 50)\">${escapeHtml(text)}</text></svg>`;\n return `\n.sw-watermark {\n position: fixed; inset: 0; z-index: 0; pointer-events: none;\n background: url(\"data:image/svg+xml,${encodeURIComponent(svg)}\") center / contain no-repeat;\n -webkit-print-color-adjust: exact; print-color-adjust: exact;\n}\nbody > .sw-sheet, body > .sw-footer { position: relative; z-index: 1; }\n`;\n}\n\n/** Build the body chrome (watermark layer + notator footer) shared by all langs. */\nfunction chrome(text: string, notator: string): { top: string; bottom: string } {\n const top = text ? '<div class=\"sw-watermark\" aria-hidden=\"true\"></div>' : '';\n const bottom = notator ? `<footer class=\"sw-footer\">${escapeHtml(notator)}</footer>` : '';\n return { top, bottom };\n}\n\n/** Resolve the notator: an explicit '' suppresses the footer (the header block already\n * credits the notator), else doc's meta.notationBy wins, else the option/default. */\nfunction resolveNotator(doc: Swaralipi, opts: PrintOptions): string {\n if (opts.notator === '') return '';\n return doc.meta.notationBy ?? opts.notator ?? DEFAULT_NOTATOR;\n}\n\n/** Assemble the full standalone HTML page around a rendered body fragment. */\nfunction pageHtml(lang: ViewerLang, title: string, bodyHtml: string, opts: PrintOptions, doc: Swaralipi): string {\n const watermark = opts.watermark ?? DEFAULT_WATERMARK;\n const { top, bottom } = chrome(watermark, resolveNotator(doc, opts));\n return `<!doctype html>\n<html lang=\"${escapeHtml(lang)}\">\n<head>\n<meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n<title>${escapeHtml(title)}</title>\n<style>\n${SWARALIPI_CSS}\n${SWARALIPI_STAFF_CSS}\n${SWARALIPI_PRINT_CSS}\n${watermarkCss(watermark)}\nhtml, body { margin: 0; }\n/* The printable width of A4 at the @page margin above. The sheet is one grid\n with one natural width, so the fit script needs a real page-sized box to\n measure against — the iframe's own width is not it. */\nbody { width: 178mm; color: #111; background: #fff; -webkit-print-color-adjust: exact; print-color-adjust: exact; }\n.sw-sheet { max-width: 100%; }\n.sw-footer { margin-top: 12px; padding-top: 6px; border-top: 1px solid #ddd; font-size: 12px; color: #555; text-align: right; }\n</style>\n</head>\n<body>${top}${bodyHtml}${bottom}\n<script>window.__swFit=function(){(${fitSwaralipi.toString()})(document,0.45,1,undefined,0)};window.__swFit()</script>\n</body>\n</html>`;\n}\n\n/**\n * Build a complete, standalone HTML document for printing an akarmatrik\n * (bn/hi/en) swaralipi sheet, with watermark + notator footer. Usable for a\n * hidden-iframe print, a new browser tab, or server-side headless-Chrome PDF.\n *\n * For `lang: 'staff'` this renders the grid instead (staff engraving is async\n * — use `renderStaffPrintDocument` or `printSwaralipi`, which handle it).\n */\nexport function renderPrintDocument(doc: Swaralipi, opts: PrintOptions = {}): string {\n const lang: ViewerLang = opts.lang === 'staff' ? 'bn' : opts.lang ?? 'bn';\n const tr = lang !== 'bn' && opts.transliterate ? opts.transliterate : (s: string) => s;\n const title = opts.title ?? tr(doc.meta.title);\n const body = renderToHtml(doc, { lang, showHeader: opts.showHeader, transliterate: opts.transliterate });\n return pageHtml(lang, title, body, opts, doc);\n}\n\n/**\n * Async variant that engraves staff notation (abcjs) into the print page. Falls\n * back to the grid document for non-staff langs. Returns a self-contained HTML\n * string (for headless-Chrome PDF or a print iframe).\n */\nexport async function renderStaffPrintDocument(doc: Swaralipi, opts: PrintOptions = {}): Promise<string> {\n if (opts.lang !== 'staff') return renderPrintDocument(doc, opts);\n const title = opts.title ?? doc.meta.title;\n // renderStaffHtml renders the shared নাম/তাল/আবর্তন/স্বরলিপিকার header itself\n // (same block as the grid), so the page just wraps its output.\n const staff = await renderStaffHtml(doc, opts);\n return pageHtml('en', title, staff, opts, doc);\n}\n\n/**\n * Open the browser print dialog for a swaralipi document (the user picks a\n * printer or \"Save as PDF\"). Renders into an off-screen iframe so it prints\n * only the sheet — independent of the host page's chrome and CSS — then cleans\n * up. Browser-only; throws in a non-DOM environment (use renderPrintDocument /\n * renderStaffPrintDocument for SSR / headless-Chrome instead).\n */\nexport function printSwaralipi(doc: Swaralipi, opts: PrintOptions = {}): void {\n if (typeof document === 'undefined') {\n throw new Error('printSwaralipi requires a DOM; use renderPrintDocument() for server-side PDF');\n }\n // Grid langs render synchronously (preserving the sync print contract); only\n // staff must await abcjs before the iframe exists.\n if (opts.lang === 'staff') {\n void renderStaffPrintDocument(doc, opts).then(printHtmlInIframe);\n } else {\n printHtmlInIframe(renderPrintDocument(doc, opts));\n }\n}\n\n/** Print an already-assembled HTML page via a hidden, off-screen iframe. */\nfunction printHtmlInIframe(html: string): void {\n const iframe = document.createElement('iframe');\n iframe.setAttribute('aria-hidden', 'true');\n // off-screen but rendered (display:none iframes print blank); a page-ish\n // width so rows lay out before the print stylesheet takes over.\n iframe.style.cssText = 'position:fixed; left:-10000px; top:0; width:800px; height:600px; border:0;';\n\n iframe.onload = () => {\n const win = iframe.contentWindow;\n if (win === null) {\n iframe.remove();\n return;\n }\n const cleanup = () => setTimeout(() => iframe.remove(), 1000);\n win.addEventListener('afterprint', cleanup, { once: true });\n let printed = false;\n const go = () => {\n if (printed) return;\n printed = true;\n try {\n // Re-fit with the real font metrics in place — the notation fonts\n // load after first layout and change every column's width.\n (win as Window & { __swFit?: () => void }).__swFit?.();\n win.focus();\n win.print();\n } catch {\n /* printing unavailable (e.g. headless) — leave cleanup to afterprint */\n }\n };\n // The notation is rendered ENTIRELY in the CDN notation fonts, so a\n // not-yet-downloaded face prints as raw ASCII — or blank, under\n // `font-display: block`. `fonts.ready` alone is not enough: it can resolve\n // before layout has even requested the faces. Force each declared face to\n // download, then print; a timeout prints anyway so a slow/unreachable font\n // (e.g. a lang whose CDN font isn't up yet) never blocks the dialog.\n const fonts = iframe.contentDocument?.fonts;\n if (fonts && typeof fonts.forEach === 'function') {\n const loads: Promise<unknown>[] = [Promise.resolve(fonts.ready)];\n fonts.forEach((face) => loads.push(face.load().catch(() => undefined)));\n void Promise.all(loads).then(go);\n setTimeout(go, 3000); // never let a slow/unreachable font block the dialog\n } else {\n setTimeout(go, 250);\n }\n };\n\n iframe.srcdoc = html;\n document.body.appendChild(iframe);\n}\n","/**\n * Lazy lyric transliteration for `hi` / `en` renders.\n *\n * Swara glyphs come from the sync tables in glyphs.ts; only *linguistic*\n * text (lyrics, title, names) needs transliteration, so sanscript loads via\n * dynamic import — `bn`-only consumers (and their bundles) never touch it.\n */\nimport type { GridLang, ViewerLang } from './glyphs.js';\n\nexport type Transliterator = (bengaliText: string) => string;\n\nconst TARGET: Record<Exclude<GridLang, 'bn'>, string> = {\n hi: 'devanagari',\n en: 'iast',\n};\n\n/**\n * Load a Bengali→target transliterator for the given viewer language.\n * Returns undefined for `bn` (no work to do). Pass the result as\n * `RenderOptions.transliterate`; the `<swaralipi-sheet>` element wires this\n * automatically when its `lang` attribute changes.\n */\nexport async function loadLyricTransliterator(lang: ViewerLang): Promise<Transliterator | undefined> {\n if (lang === 'bn' || lang === 'staff') return undefined; // staff has no lyric script to convert\n const mod = (await import('@indic-transliteration/sanscript')) as {\n default?: { t(text: string, from: string, to: string): string };\n t?(text: string, from: string, to: string): string;\n };\n const sanscript = mod.default ?? mod;\n const target = TARGET[lang];\n return (text) => sanscript.t!(text, 'bengali', target);\n}\n","/**\n * The `<swaralipi-sheet>` custom element — a thin shadow-DOM shell around\n * the pure renderer.\n *\n * The element class is created lazily inside defineSwaralipiSheet():\n * a top-level `extends HTMLElement` would throw on import in Node, and this\n * module must stay importable for SSR (where only renderToHtml is used).\n * Nothing registers automatically — call defineSwaralipiSheet() once.\n *\n * Validation is off by default (converter output is pre-validated); setting\n * `validate = true` parses documents against the Zod schema via a dynamic\n * import, so the viewer bundle stays free of bare runtime imports (it can\n * be loaded directly from dist/ in a browser without a bundler).\n */\nimport type { Swaralipi } from '../spec/index.js';\nimport { renderToHtml } from './render.js';\nimport { renderStaffHtml, type StaffOptions } from './staff.js';\nimport { SWARALIPI_CSS, SWARALIPI_STAFF_CSS, NOTATION_FONT_URLS } from './styles.js';\nimport { printSwaralipi, type PrintOptions } from './print.js';\nimport { fitSwaralipi, MIN_ZOOM, MAX_ZOOM, ZOOM_STEP } from './fit.js';\nimport { loadLyricTransliterator, type Transliterator } from './transliterate.js';\nimport { PRACTICE_LABELS, type ViewerLang } from './glyphs.js';\n\nexport interface SwaralipiSheetElement extends HTMLElement {\n /** The document to render (property only; renders on assignment). */\n doc: Swaralipi | undefined;\n /** Parse documents against the spec schema before rendering. */\n validate: boolean;\n /** Add the player-highlight class to the note at \"part.row.note\" — drawn\n * hollow when it is the learner's turn to sing it. */\n highlight(path: string, yourTurn?: boolean): HTMLElement | null;\n clearHighlights(): void;\n /** Shade the repeated lines (`part.row`, inclusive; null clears) and mark\n * the learner's turn on them. The player's bindSheet calls this. */\n markLoop(loop: { from: string; to: string } | null, yourTurn?: boolean): void;\n /** Open the print dialog (→ \"Save as PDF\") for the current document. */\n print(options?: PrintOptions): void;\n /** Options for the `staff` language (instrument label, tonic, bpm…). */\n staffOptions: StaffOptions;\n /** Re-fit the notation to the element's current width. */\n fit(): void;\n /** How far the column spacing may be compressed to fit a narrow container\n * before the type is scaled down at all, 0–1 (attribute `min-spacing`;\n * undefined = the library default). Lower = tighter columns, bigger glyphs. */\n minSpacing: number | undefined;\n /** Smallest notation size in px the fit may produce (attribute `min-size`);\n * past it the sheet scrolls horizontally instead of shrinking further. */\n minSize: number | undefined;\n /** Zoom factor on top of fit-to-width (1 = fit; clamped to\n * [MIN_ZOOM, MAX_ZOOM]). Assigning re-fits immediately. Resets to 1 on the\n * next doc/lang re-render — a resize alone (fit()) does not reset it. */\n zoom: number;\n /** `zoom *= ZOOM_STEP`, clamped. */\n zoomIn(): void;\n /** `zoom /= ZOOM_STEP`, clamped. */\n zoomOut(): void;\n /** Back to fit-to-width (`zoom = 1`). */\n resetZoom(): void;\n}\n\nconst LANGS: ReadonlySet<string> = new Set(['bn', 'hi', 'en', 'staff']);\n\n/** The keys a bound player answers on a focused sheet (see bindSheet). */\nconst KEYS = 'Space ArrowUp ArrowDown ArrowLeft ArrowRight Home End R T Escape Shift+ArrowUp Shift+ArrowDown';\n\n/** The element nearest `x` horizontally — a tap anywhere on a line picks the\n * note under it, so a fingertip never has to land on a 12px glyph. */\nfunction nearest(els: Element[], x: number): Element | undefined {\n let best: Element | undefined;\n let gap = Infinity;\n for (const el of els) {\n const r = el.getBoundingClientRect();\n const d = Math.abs(r.left + r.width / 2 - x);\n if (d < gap) [best, gap] = [el, d];\n }\n return best;\n}\n\n/** Browsers ignore @font-face inside a shadow root's (adopted) stylesheet —\n * faces must live at document scope, so register the notation fonts there\n * via the FontFace API. No-op without FontFace (jsdom/SSR) or for any family\n * already present (SSR CSS on the page, or a self-hoster's own declaration). */\nfunction ensureNotationFonts(): void {\n if (typeof FontFace === 'undefined' || typeof document === 'undefined') return;\n const present = new Set<string>();\n for (const f of document.fonts) present.add(f.family.replace(/['\"]/g, ''));\n for (const [family, url] of Object.entries(NOTATION_FONT_URLS)) {\n if (present.has(family)) continue;\n document.fonts.add(new FontFace(family, `url(${url})`, { display: 'block' }));\n }\n}\n\nlet sharedSheet: CSSStyleSheet | undefined;\n\nfunction createElementClass(): CustomElementConstructor {\n return class SwaralipiSheet extends HTMLElement implements SwaralipiSheetElement {\n static observedAttributes = ['src', 'lang', 'hide-header', 'min-spacing', 'min-size', 'seekable'];\n\n #doc: Swaralipi | undefined;\n #root: ShadowRoot;\n #adopted = false;\n #abort: AbortController | undefined;\n #translit: Transliterator | undefined;\n #translitLang: ViewerLang | undefined;\n #renderSeq = 0;\n #staffOptions: StaffOptions = {};\n #resize: ResizeObserver | undefined;\n #fittedAt = -1;\n #zoom = 1;\n /** Where the pointer went down, to tell a tap from a drag. */\n #down: [number, number] | undefined;\n #marks: { loop: { from: string; to: string } | null; turn: boolean } = { loop: null, turn: false };\n /** Attributes `seekable` added, and so takes away again. */\n #owned: string[] = [];\n validate = false;\n\n constructor() {\n super();\n this.#root = this.attachShadow({ mode: 'open' });\n this.#root.addEventListener('pointerdown', (e) => {\n const { clientX, clientY } = e as PointerEvent;\n this.#down = [clientX, clientY];\n });\n this.#root.addEventListener('click', (e) => this.#onClick(e as MouseEvent));\n if (\n typeof CSSStyleSheet !== 'undefined' &&\n 'replaceSync' in CSSStyleSheet.prototype &&\n 'adoptedStyleSheets' in this.#root\n ) {\n if (!sharedSheet) {\n sharedSheet = new CSSStyleSheet();\n sharedSheet.replaceSync(SWARALIPI_CSS + SWARALIPI_STAFF_CSS);\n }\n this.#root.adoptedStyleSheets = [...this.#root.adoptedStyleSheets, sharedSheet];\n this.#adopted = true;\n }\n }\n\n get doc(): Swaralipi | undefined {\n return this.#doc;\n }\n\n set doc(value: Swaralipi | undefined) {\n this.#doc = value;\n if (value !== undefined && this.validate) {\n void import('../spec/index.js')\n .then(({ safeParseSwaralipi }) => {\n const result = safeParseSwaralipi(value);\n if (!result.success) this.#renderError(result.error.message);\n })\n .catch(() => undefined);\n }\n this.#render();\n }\n\n get staffOptions(): StaffOptions {\n return this.#staffOptions;\n }\n\n set staffOptions(value: StaffOptions) {\n this.#staffOptions = value;\n if (this.#lang === 'staff') this.#render(); // live-update the score\n }\n\n get #lang(): ViewerLang {\n const attr = this.getAttribute('lang');\n return attr !== null && LANGS.has(attr) ? (attr as ViewerLang) : 'bn';\n }\n\n get #practice() {\n const lang = this.#lang;\n return PRACTICE_LABELS[lang === 'staff' ? 'en' : lang];\n }\n\n /** A tap on a line plays from the note nearest the tap: the whole line is\n * the target (WCAG 2.5.8 counts a position inside one target as picking\n * a value), fired on the up-event like any click (2.5.2). The player bound\n * by bindSheet answers it; a host can veto it with preventDefault(). */\n #onClick(e: MouseEvent): void {\n if (!this.hasAttribute('seekable') || e.button !== 0 || e.ctrlKey || e.metaKey || e.altKey) return;\n // A drag that ends here was selecting a lyric, not tapping.\n if (this.#down !== undefined && Math.hypot(e.clientX - this.#down[0], e.clientY - this.#down[1]) > 6) return;\n const target = e.target as Element;\n const row = target.closest('.sw-row');\n const notes = row === null ? [] : [...row.querySelectorAll('[data-note]:not(.sw-bar)')];\n const hit = target.closest('[data-note]:not(.sw-bar)') ?? nearest(notes, e.clientX);\n const path = hit?.getAttribute('data-note');\n if (path == null) return;\n this.dispatchEvent(\n new CustomEvent('swaralipi-seek', { detail: { path, extend: e.shiftKey }, bubbles: true, cancelable: true }),\n );\n }\n\n attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void {\n if (oldValue === newValue) return;\n if (name === 'src') {\n if (newValue !== null) void this.#load(newValue);\n return;\n }\n if (name === 'min-spacing' || name === 'min-size') {\n this.fit(); // spacing/size floors are layout-only — no re-render needed\n return;\n }\n if (name === 'seekable') {\n // Keys only reach a focused element, so a sheet a player drives joins\n // the tab order, named for what a tap does — minding whatever its host\n // set itself, and taking back only what it added.\n for (const a of this.#owned) this.removeAttribute(a);\n this.#owned = [];\n if (newValue === null) return;\n const want = { tabindex: '0', role: 'region', 'aria-label': this.#practice.sheet, 'aria-keyshortcuts': KEYS };\n for (const [a, v] of Object.entries(want)) {\n if (this.hasAttribute(a)) continue;\n this.setAttribute(a, v);\n this.#owned.push(a);\n }\n return;\n }\n if (name === 'lang' && this.#owned.includes('aria-label')) this.setAttribute('aria-label', this.#practice.sheet);\n if (name === 'lang') this.#ensureTransliterator();\n this.#render();\n }\n\n connectedCallback(): void {\n this.#ensureTransliterator();\n this.#render();\n // The sheet is one grid with one natural width; re-fit it whenever the\n // box it lives in changes (the shared columns cannot reflow).\n if (this.#resize === undefined && typeof ResizeObserver !== 'undefined') {\n this.#resize = new ResizeObserver(([entry]) => {\n // Only on a real width change: re-fitting alters the sheet's own\n // height, which would otherwise re-enter through the observer.\n const w = entry?.contentRect.width ?? -1;\n if (w === this.#fittedAt) return;\n this.#fittedAt = w;\n this.#fit();\n });\n this.#resize.observe(this);\n }\n // The notation IS the font, so a fit that lands before the faces do\n // measured fallback metrics. `document.fonts.ready` cannot be trusted to\n // catch that: read while nothing is loading it is already resolved, so on\n // a cold cache the re-fit fired before the face was even requested (and a\n // warm cache hid the bug, which is why it only bit the first load).\n // `loadingdone` fires every time the set finishes a batch, so every fit —\n // render, resize, reveal — gets its correction.\n document.fonts?.addEventListener('loadingdone', this.#onFontsLoaded);\n }\n\n #onFontsLoaded = (): void => {\n if (this.#doc !== undefined) this.fit();\n };\n\n disconnectedCallback(): void {\n this.#abort?.abort();\n this.#resize?.disconnect();\n this.#resize = undefined;\n document.fonts?.removeEventListener('loadingdone', this.#onFontsLoaded);\n }\n\n /** Scale the notation to fit the available width, times the zoom factor. */\n #fit(): void {\n fitSwaralipi(this.#root, 0, this.#zoom, this.minSpacing, this.minSize);\n }\n\n /** Numeric attribute, or undefined for fitSwaralipi's own default. */\n #attrNum(name: string): number | undefined {\n const value = parseFloat(this.getAttribute(name) ?? '');\n return Number.isFinite(value) ? value : undefined;\n }\n\n #setAttrNum(name: string, value: number | undefined): void {\n if (value === undefined) this.removeAttribute(name);\n else this.setAttribute(name, String(value));\n }\n\n get minSpacing(): number | undefined {\n return this.#attrNum('min-spacing');\n }\n\n set minSpacing(value: number | undefined) {\n this.#setAttrNum('min-spacing', value);\n }\n\n get minSize(): number | undefined {\n return this.#attrNum('min-size');\n }\n\n set minSize(value: number | undefined) {\n this.#setAttrNum('min-size', value);\n }\n\n /** Re-fit the current render (public for hosts that resize the sheet\n * themselves, e.g. a tab that was hidden while the document loaded). */\n fit(): void {\n this.#fittedAt = -1;\n this.#fit();\n }\n\n get zoom(): number {\n return this.#zoom;\n }\n\n set zoom(factor: number) {\n this.#zoom = Math.min(MAX_ZOOM, Math.max(MIN_ZOOM, factor));\n this.#fit();\n }\n\n zoomIn(): void {\n this.zoom = this.#zoom * ZOOM_STEP;\n }\n\n zoomOut(): void {\n this.zoom = this.#zoom / ZOOM_STEP;\n }\n\n resetZoom(): void {\n this.zoom = 1;\n }\n\n async #load(url: string): Promise<void> {\n this.#abort?.abort();\n const abort = new AbortController();\n this.#abort = abort;\n try {\n const res = await fetch(url, { signal: abort.signal });\n if (!res.ok) throw new Error(`fetch ${url}: HTTP ${res.status}`);\n this.doc = (await res.json()) as Swaralipi;\n } catch (err) {\n if (abort.signal.aborted) return;\n this.#renderError(err instanceof Error ? err.message : String(err));\n this.dispatchEvent(new ErrorEvent('error', { error: err, message: String(err) }));\n }\n }\n\n /** Load (once per lang) the lyric transliterator, then re-render. */\n #ensureTransliterator(): void {\n const lang = this.#lang;\n if (lang === 'bn' || this.#translitLang === lang) return;\n void loadLyricTransliterator(lang)\n .then((t) => {\n if (t === undefined || this.#lang !== lang) return;\n this.#translit = t;\n this.#translitLang = lang;\n this.#render();\n })\n .catch(() => undefined); // graceful: lyrics stay Bengali\n }\n\n #styleFallback(): string {\n return this.#adopted ? '' : `<style>${SWARALIPI_CSS}${SWARALIPI_STAFF_CSS}</style>`;\n }\n\n #render(): void {\n const seq = ++this.#renderSeq; // guards against out-of-order async staff renders\n this.#zoom = 1; // a new doc/lang starts back at fit-to-width; #fit() alone (resize) keeps it\n if (this.#doc === undefined) {\n this.#root.innerHTML = this.#styleFallback();\n return;\n }\n const lang = this.#lang;\n if (lang === 'staff') {\n const doc = this.#doc;\n void renderStaffHtml(doc, this.staffOptions)\n .then((html) => {\n if (seq !== this.#renderSeq) return;\n this.#root.innerHTML = this.#styleFallback() + html;\n this.#applyMarks();\n })\n .catch(() => undefined);\n return;\n }\n const html = renderToHtml(this.#doc, {\n lang,\n showHeader: !this.hasAttribute('hide-header'),\n transliterate: this.#translitLang === lang ? this.#translit : undefined,\n });\n this.#root.innerHTML = this.#styleFallback() + html;\n this.#applyMarks();\n this.#fit();\n }\n\n markLoop(loop: { from: string; to: string } | null, yourTurn = false): void {\n this.#marks = { loop, turn: yourTurn };\n this.#applyMarks();\n }\n\n /** Shade the repeated lines and dim the rest; the first of them carries\n * the \"your turn\" cue. A polite live region says the same aloud. */\n #applyMarks(): void {\n const { loop, turn } = this.#marks;\n const rows = [...this.#root.querySelectorAll<HTMLElement>('.sw-row')];\n const at = (row: string | undefined) => rows.findIndex((r) => r.dataset.row === row);\n const [a, b] = loop === null ? [0, -1] : [at(loop.from), at(loop.to)];\n rows.forEach((r, i) => {\n r.classList.toggle('sw-loop', i >= a && i <= b);\n if (turn && i === a) r.dataset.turn = this.#practice.turn;\n else delete r.dataset.turn;\n });\n this.#root.querySelector('.sw-block')?.classList.toggle('sw-looping', loop !== null);\n let live = this.#root.querySelector('.sw-live');\n if (live === null) {\n live = Object.assign(document.createElement('div'), { className: 'sw-live' });\n live.setAttribute('role', 'status');\n this.#root.append(live);\n }\n live.textContent = turn ? this.#practice.turn : loop !== null ? this.#practice.repeat : '';\n }\n\n #renderError(message: string): void {\n const div = document.createElement('div');\n div.className = 'sw-error';\n div.textContent = message;\n this.#root.innerHTML = this.#styleFallback();\n this.#root.appendChild(div);\n }\n\n highlight(path: string, yourTurn = false): HTMLElement | null {\n if (!/^\\d+\\.\\d+\\.\\d+$/.test(path)) return null;\n const el = this.#root.querySelector<HTMLElement>(`[data-note=\"${path}\"]`);\n el?.classList.add('sw-hl');\n el?.classList.toggle('sw-hl-turn', yourTurn);\n return el;\n }\n\n clearHighlights(): void {\n for (const el of this.#root.querySelectorAll('.sw-hl')) el.classList.remove('sw-hl', 'sw-hl-turn');\n }\n\n print(options: PrintOptions = {}): void {\n if (this.#doc === undefined) return;\n const lang = this.#lang;\n printSwaralipi(this.#doc, {\n lang,\n showHeader: !this.hasAttribute('hide-header'),\n transliterate: this.#translitLang === lang ? this.#translit : undefined,\n ...(lang === 'staff' ? this.staffOptions : {}),\n ...options,\n });\n }\n };\n}\n\n/** Per-tag constructors: a custom-element class can only be registered\n * under one name, so each tag gets its own. */\nconst registered = new Map<string, CustomElementConstructor>();\n\n/**\n * Register `<swaralipi-sheet>` (or a custom tag name). Idempotent. Throws\n * outside a DOM environment — use renderToHtml() for SSR.\n */\nexport function defineSwaralipiSheet(tagName = 'swaralipi-sheet'): CustomElementConstructor {\n if (typeof customElements === 'undefined' || typeof HTMLElement === 'undefined') {\n throw new Error('swaralipi-sheet requires a DOM; use renderToHtml() for server-side rendering');\n }\n const existing = customElements.get(tagName);\n if (existing) return existing;\n ensureNotationFonts();\n const ctor = registered.get(tagName) ?? createElementClass();\n registered.set(tagName, ctor);\n customElements.define(tagName, ctor);\n return ctor;\n}\n"]}
|