@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
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/spec/schema.ts","../src/spec/taals.ts","../src/spec/grace.ts","../src/spec/lay.ts","../src/spec/svara.ts","../src/spec/index.ts"],"names":["z"],"mappings":"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","file":"index.cjs","sourcesContent":["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","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 * লয় (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","/**\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","/**\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"]}
|
|
1
|
+
{"version":3,"sources":["../src/spec/schema.ts","../src/spec/taals.ts","../src/spec/grace.ts","../src/spec/lay.ts","../src/spec/svara.ts","../src/spec/index.ts"],"names":["z"],"mappings":"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","file":"index.cjs","sourcesContent":["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","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 * লয় (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","/**\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","/**\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"]}
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { SPEC_VERSION, barSchema, bracketSchema, graceSchema, laySchema, metaSchema, microtoneSchema, noteSchema, octaveSchema, parseSwaralipi, partSchema, rowSchema, safeParseSwaralipi, svaraLetterSchema, svaraSchema, swaralipiSchema, taalSchema } from './chunk-
|
|
1
|
+
export { SPEC_VERSION, barSchema, bracketSchema, graceSchema, laySchema, metaSchema, microtoneSchema, noteSchema, octaveSchema, parseSwaralipi, partSchema, rowSchema, safeParseSwaralipi, svaraLetterSchema, svaraSchema, swaralipiSchema, taalSchema } from './chunk-UV5OJYT3.js';
|
|
2
2
|
export { LAYS, LAY_SPEEDS, TAALS, TAAL_FERTA, graceNotes, hasKomal, hasTivra, isTaalFerta, printedLay, resolveLaySpeeds, rowLay, sameTaal } from './chunk-KOHSKHXI.js';
|
|
3
3
|
//# sourceMappingURL=index.js.map
|
|
4
4
|
//# sourceMappingURL=index.js.map
|
package/dist/player/index.cjs
CHANGED
|
@@ -145,6 +145,145 @@ function rowLay(row) {
|
|
|
145
145
|
return row.lay ?? printedLay(row.notes);
|
|
146
146
|
}
|
|
147
147
|
|
|
148
|
+
// src/player/lyrics.ts
|
|
149
|
+
var MATCH = 2;
|
|
150
|
+
var GAP = 1;
|
|
151
|
+
var JUMP = 4;
|
|
152
|
+
var RUN = 3;
|
|
153
|
+
var STRAY = 8;
|
|
154
|
+
var EPS = 1e-6;
|
|
155
|
+
var [DIAG, UP, LEFT, JUMPED] = [1, 2, 3, 4];
|
|
156
|
+
var letters = (s) => s.normalize("NFD").replace(/ৎ/g, "\u09A4").replace(/[^\p{L}\p{M}]|[়্]/gu, "").toLowerCase();
|
|
157
|
+
function alignLyrics(doc, text) {
|
|
158
|
+
const sung = [];
|
|
159
|
+
doc.parts.forEach(
|
|
160
|
+
(part, p) => part.rows.forEach(
|
|
161
|
+
(row, r) => row.notes.forEach((note, i) => {
|
|
162
|
+
for (const letter of letters(note.lyric ?? "")) sung.push({ letter, path: `${p}.${r}.${i}` });
|
|
163
|
+
})
|
|
164
|
+
)
|
|
165
|
+
);
|
|
166
|
+
const said = [];
|
|
167
|
+
const starts = [];
|
|
168
|
+
let at = 0;
|
|
169
|
+
let gap = true;
|
|
170
|
+
for (const ch of text) {
|
|
171
|
+
const ls = letters(ch);
|
|
172
|
+
if (ls === "") {
|
|
173
|
+
gap ||= /[\s\p{P}]/u.test(ch);
|
|
174
|
+
if (/[\p{M}\p{Cf}]/u.test(ch) && said.at(-1)?.to === at) said.at(-1).to += ch.length;
|
|
175
|
+
} else {
|
|
176
|
+
if (gap) starts.push(said.length);
|
|
177
|
+
gap = false;
|
|
178
|
+
}
|
|
179
|
+
for (const letter of ls) said.push({ letter, from: at, to: at + ch.length });
|
|
180
|
+
at += ch.length;
|
|
181
|
+
}
|
|
182
|
+
const n = sung.length;
|
|
183
|
+
const m = said.length;
|
|
184
|
+
const w = m + 1;
|
|
185
|
+
const from = new Uint8Array((n + 1) * w);
|
|
186
|
+
const best = new Int32Array(n + 1);
|
|
187
|
+
let prev = new Int32Array(w).fill(-1073741824);
|
|
188
|
+
prev[0] = 0;
|
|
189
|
+
let cur = new Int32Array(w);
|
|
190
|
+
const settle = (i, row) => {
|
|
191
|
+
for (let j2 = 1; j2 < w; j2++) if (row[j2] > row[best[i]]) best[i] = j2;
|
|
192
|
+
for (const s of starts) {
|
|
193
|
+
if (row[best[i]] - JUMP > row[s]) {
|
|
194
|
+
row[s] = row[best[i]] - JUMP;
|
|
195
|
+
from[i * w + s] = JUMPED;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
for (let j2 = 1; j2 < w; j2++) {
|
|
199
|
+
if (row[j2 - 1] - GAP > row[j2]) {
|
|
200
|
+
row[j2] = row[j2 - 1] - GAP;
|
|
201
|
+
from[i * w + j2] = LEFT;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
};
|
|
205
|
+
settle(0, prev);
|
|
206
|
+
for (let i = 1; i <= n; i++) {
|
|
207
|
+
cur[0] = prev[0] - GAP;
|
|
208
|
+
from[i * w] = UP;
|
|
209
|
+
for (let j2 = 1; j2 < w; j2++) {
|
|
210
|
+
const diag = prev[j2 - 1] + (sung[i - 1].letter === said[j2 - 1].letter ? MATCH : -GAP);
|
|
211
|
+
const up = prev[j2] - GAP;
|
|
212
|
+
cur[j2] = Math.max(diag, up);
|
|
213
|
+
from[i * w + j2] = diag >= up ? DIAG : UP;
|
|
214
|
+
}
|
|
215
|
+
best[i] = 0;
|
|
216
|
+
settle(i, cur);
|
|
217
|
+
[prev, cur] = [cur, prev];
|
|
218
|
+
}
|
|
219
|
+
const pairs = [];
|
|
220
|
+
let j = 0;
|
|
221
|
+
for (let k = 1; k < w; k++) if (prev[k] > prev[j]) j = k;
|
|
222
|
+
for (let i = n; i > 0; ) {
|
|
223
|
+
const step = from[i * w + j];
|
|
224
|
+
if (step === JUMPED) j = best[i];
|
|
225
|
+
else if (step === LEFT) j--;
|
|
226
|
+
else if (step === UP) i--;
|
|
227
|
+
else {
|
|
228
|
+
if (sung[i - 1].letter === said[j - 1].letter) pairs.push([i - 1, j - 1]);
|
|
229
|
+
i--;
|
|
230
|
+
j--;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
pairs.reverse();
|
|
234
|
+
const wordStart = new Set(starts);
|
|
235
|
+
const follows = (k) => pairs[k][0] === pairs[k - 1][0] + 1 && (pairs[k][1] === pairs[k - 1][1] + 1 || wordStart.has(pairs[k][1]));
|
|
236
|
+
const out = /* @__PURE__ */ new Map();
|
|
237
|
+
const last = /* @__PURE__ */ new Map();
|
|
238
|
+
for (let a = 0, b = 1; a < pairs.length; a = b++) {
|
|
239
|
+
while (b < pairs.length && follows(b)) b++;
|
|
240
|
+
if (b - a < RUN) continue;
|
|
241
|
+
for (const [s, t] of pairs.slice(a, b)) {
|
|
242
|
+
const { path } = sung[s];
|
|
243
|
+
const { from: lo, to: hi } = said[t];
|
|
244
|
+
const span = out.get(path);
|
|
245
|
+
if (span === void 0) out.set(path, [lo, hi]);
|
|
246
|
+
else if (t === last.get(path) + 1) span[1] = hi;
|
|
247
|
+
else continue;
|
|
248
|
+
last.set(path, t);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
return out;
|
|
252
|
+
}
|
|
253
|
+
var mod = (a, n) => (a % n + n) % n;
|
|
254
|
+
var sings = (v) => v.note.svara !== void 0 || v.note.sustain === true;
|
|
255
|
+
function excerptVisits(order, at, { lyrics, ranges }, cycle) {
|
|
256
|
+
const pos = order.map((v) => lyrics.get(`${v.p}.${v.r}.${v.i}`)?.[0]);
|
|
257
|
+
for (let a = 0; a < order.length; a++) {
|
|
258
|
+
if (pos[a] !== void 0 || letters(order[a].note.lyric ?? "") === "") continue;
|
|
259
|
+
let b = a;
|
|
260
|
+
let stray = 0;
|
|
261
|
+
while (b < order.length && pos[b] === void 0) stray += letters(order[b++].note.lyric ?? "").length;
|
|
262
|
+
if (stray >= STRAY) pos.fill(-1, a, b);
|
|
263
|
+
a = b;
|
|
264
|
+
}
|
|
265
|
+
const visits = [];
|
|
266
|
+
let first;
|
|
267
|
+
let end = 0;
|
|
268
|
+
for (const [lo, hi] of ranges) {
|
|
269
|
+
const inside = (k) => pos[k] === void 0 ? void 0 : pos[k] >= lo && pos[k] < hi;
|
|
270
|
+
const a = order.findIndex((_, k) => inside(k) === true);
|
|
271
|
+
if (a < 0) continue;
|
|
272
|
+
let b = a + 1;
|
|
273
|
+
while (b < order.length && inside(b) !== false) b++;
|
|
274
|
+
while (b - 1 > a && !sings(order[b - 1])) b--;
|
|
275
|
+
const n = cycle(order[a]);
|
|
276
|
+
if (first === void 0) first = a;
|
|
277
|
+
else if (n !== void 0) {
|
|
278
|
+
const gap = mod(at[a] - at[end], n);
|
|
279
|
+
if (gap > EPS) visits.push({ ...order[end - 1], note: { rest: true, durationMatra: gap } });
|
|
280
|
+
}
|
|
281
|
+
visits.push(...order.slice(a, b));
|
|
282
|
+
end = b;
|
|
283
|
+
}
|
|
284
|
+
return { visits, matra: first === void 0 ? 0 : at[first] };
|
|
285
|
+
}
|
|
286
|
+
|
|
148
287
|
// src/convert/codec.ts
|
|
149
288
|
var LETTERS = {
|
|
150
289
|
s: { letter: "s" },
|
|
@@ -310,7 +449,7 @@ function decodeCell(text) {
|
|
|
310
449
|
var UNDECODED_CELL = /[srgmpqnvtduka]/i;
|
|
311
450
|
var isSilent = (n) => n.svara === void 0 && n.rest !== true && n.sustain !== true && !(n.raw !== void 0 && UNDECODED_CELL.test(n.raw));
|
|
312
451
|
var STOP_MARK = /^\|+$/;
|
|
313
|
-
var
|
|
452
|
+
var EPS2 = 1e-6;
|
|
314
453
|
var edges = (n, kind, edge) => n.brackets?.filter((b) => b.kind === kind && b.edge === edge).length ?? 0;
|
|
315
454
|
var sounds = (n) => n.svara !== void 0 || n.rest === true || n.sustain === true;
|
|
316
455
|
var matra = (notes) => notes.reduce((sum, n) => sum + (n.durationMatra ?? 1), 0);
|
|
@@ -324,6 +463,7 @@ function playOrder(doc) {
|
|
|
324
463
|
const { asthayi, stop, returns } = form(tokens);
|
|
325
464
|
const changed = changedNotes(tokens);
|
|
326
465
|
const out = [];
|
|
466
|
+
let last = -1;
|
|
327
467
|
const sing = (lo, hi, useChanged) => {
|
|
328
468
|
const repeats = [];
|
|
329
469
|
let owed = 0;
|
|
@@ -338,11 +478,12 @@ function playOrder(doc) {
|
|
|
338
478
|
owed = 0;
|
|
339
479
|
continue;
|
|
340
480
|
}
|
|
341
|
-
if (owed >
|
|
481
|
+
if (owed > EPS2 && t.timed) owed -= matra([t.note]);
|
|
342
482
|
else {
|
|
343
483
|
const sub = useChanged || again ? changed.get(k) : void 0;
|
|
344
|
-
const fits = sub !== void 0 && matra(sub) >= matra([t.note]) -
|
|
484
|
+
const fits = sub !== void 0 && matra(sub) >= matra([t.note]) - EPS2;
|
|
345
485
|
for (const note of fits ? sub : [t.note]) out.push({ p: t.p, r: t.r, i: t.i, note });
|
|
486
|
+
if (t.timed) last = k;
|
|
346
487
|
owed = fits ? matra(sub) - matra([t.note]) : 0;
|
|
347
488
|
}
|
|
348
489
|
const loop = edges(t.note, "repeat", "close") > 0 ? repeats.at(-1) : void 0;
|
|
@@ -359,7 +500,7 @@ function playOrder(doc) {
|
|
|
359
500
|
let from = 0;
|
|
360
501
|
for (const ret of returns) {
|
|
361
502
|
sing(from, ret.resume, false);
|
|
362
|
-
sing(asthayi, stop + 1, ret.changed);
|
|
503
|
+
if (last !== stop) sing(asthayi, stop + 1, ret.changed);
|
|
363
504
|
from = ret.resume;
|
|
364
505
|
}
|
|
365
506
|
sing(from, tokens.length, false);
|
|
@@ -409,9 +550,7 @@ function form(tokens) {
|
|
|
409
550
|
const stop = tokens.findIndex(
|
|
410
551
|
(t, k) => k >= asthayi && k < asthayiEnd && k < lastSung && t.note.above?.some((a) => STOP_MARK.test(a.raw ?? "")) === true
|
|
411
552
|
);
|
|
412
|
-
|
|
413
|
-
const atClose = returns[0]?.resume === asthayiEnd && !tokens.slice(stop + 1, asthayiEnd).some((t) => t.timed);
|
|
414
|
-
return { asthayi, stop, returns: atClose ? returns.slice(1) : returns };
|
|
553
|
+
return { asthayi, stop, returns: stop < 0 ? [] : returns };
|
|
415
554
|
}
|
|
416
555
|
function changedNotes(tokens) {
|
|
417
556
|
const out = /* @__PURE__ */ new Map();
|
|
@@ -535,8 +674,6 @@ function buildSchedule(doc, opts = {}) {
|
|
|
535
674
|
const events = [];
|
|
536
675
|
let cursor = 0;
|
|
537
676
|
let lastPitched = -1;
|
|
538
|
-
let samMatra;
|
|
539
|
-
let matra2 = 0;
|
|
540
677
|
const speeds = resolveLaySpeeds(doc.meta.laySpeeds, opts.laySpeeds);
|
|
541
678
|
const withLay = opts.lay !== false;
|
|
542
679
|
const tempo = [{ beat: 0, endBeat: 0, scale: 1, lay: "drut", taal: doc.meta.taal }];
|
|
@@ -555,7 +692,15 @@ function buildSchedule(doc, opts = {}) {
|
|
|
555
692
|
rows.set(`${p}.${r}`, { scale, lay: layNow, taal, glides: meendContinuations(row.notes) });
|
|
556
693
|
})
|
|
557
694
|
);
|
|
558
|
-
const
|
|
695
|
+
const order = opts.repeats === true ? playOrder(doc) : doc.parts.flatMap((part, p) => part.rows.flatMap((row, r) => row.notes.map((note, i) => ({ p, r, i, note }))));
|
|
696
|
+
const at = [0];
|
|
697
|
+
let samMatra;
|
|
698
|
+
for (const { note } of order) {
|
|
699
|
+
const m = at[at.length - 1];
|
|
700
|
+
if (samMatra === void 0 && note.above?.some((a) => a.raw !== void 0 && SAM_TICK.test(a.raw))) samMatra = m;
|
|
701
|
+
at.push(note.bar === void 0 && !isSilent(note) ? m + (note.durationMatra ?? 1) : m);
|
|
702
|
+
}
|
|
703
|
+
const { visits, matra: matra2 } = opts.excerpt ? excerptVisits(order, at, opts.excerpt, (v) => rows.get(`${v.p}.${v.r}`).taal?.numBeats) : { visits: order, matra: 0 };
|
|
559
704
|
let rowNow = "";
|
|
560
705
|
for (const { p, r, i, note } of visits) {
|
|
561
706
|
const row = rows.get(`${p}.${r}`);
|
|
@@ -571,14 +716,6 @@ function buildSchedule(doc, opts = {}) {
|
|
|
571
716
|
}
|
|
572
717
|
}
|
|
573
718
|
}
|
|
574
|
-
if (samMatra === void 0 && note.above !== void 0) {
|
|
575
|
-
for (const a of note.above) {
|
|
576
|
-
if (a.raw !== void 0 && SAM_TICK.test(a.raw)) {
|
|
577
|
-
samMatra = matra2;
|
|
578
|
-
break;
|
|
579
|
-
}
|
|
580
|
-
}
|
|
581
|
-
}
|
|
582
719
|
if (note.bar !== void 0 || isSilent(note)) continue;
|
|
583
720
|
const path = `${p}.${r}.${i}`;
|
|
584
721
|
const written = note.durationMatra ?? 1;
|
|
@@ -604,10 +741,9 @@ function buildSchedule(doc, opts = {}) {
|
|
|
604
741
|
events.push({ beat: cursor, durationBeats: dur, midi: null, kan, resh, path, kind: "rest" });
|
|
605
742
|
}
|
|
606
743
|
cursor += dur;
|
|
607
|
-
matra2 += written;
|
|
608
744
|
}
|
|
609
745
|
const numBeats = tempo[0].taal?.numBeats;
|
|
610
|
-
const pickupMatra =
|
|
746
|
+
const pickupMatra = numBeats !== void 0 && numBeats > 0 ? ((matra2 - (samMatra ?? 0)) % numBeats + numBeats) % numBeats : 0;
|
|
611
747
|
tempo[tempo.length - 1].endBeat = cursor;
|
|
612
748
|
return { events, totalBeats: cursor, pickupBeats: pickupMatra / tempo[0].scale, tempo };
|
|
613
749
|
}
|
|
@@ -946,6 +1082,8 @@ var SwaralipiPlayer = class {
|
|
|
946
1082
|
/** Per-song setBpm tweak: beats meta.bpm but is cleared by the next load(). */
|
|
947
1083
|
#bpmTweak;
|
|
948
1084
|
#doc;
|
|
1085
|
+
/** Play only these stretches of the song's text (see `load`). */
|
|
1086
|
+
#excerpt;
|
|
949
1087
|
/** Taal mode (`loadTaal`): loops one avartan of this taal's theka with no
|
|
950
1088
|
* melody. Mutually exclusive with `#doc`. */
|
|
951
1089
|
#taal;
|
|
@@ -988,6 +1126,8 @@ var SwaralipiPlayer = class {
|
|
|
988
1126
|
/** Listeners on the bound sheet, removed on rebind. */
|
|
989
1127
|
#unbind;
|
|
990
1128
|
#sheet;
|
|
1129
|
+
/** The bound sheet's highlight — beside, never instead of, the consumer's `onHighlight`. */
|
|
1130
|
+
#paint;
|
|
991
1131
|
/** Preview cap, counted in listening time so a seek or a loop can't dodge it. */
|
|
992
1132
|
#listened = 0;
|
|
993
1133
|
#listenedSince = 0;
|
|
@@ -1078,10 +1218,13 @@ var SwaralipiPlayer = class {
|
|
|
1078
1218
|
/* ----------------------------------------------------------------- */
|
|
1079
1219
|
/* Loading + transport control */
|
|
1080
1220
|
/* ----------------------------------------------------------------- */
|
|
1081
|
-
/** Set the document to play. Stops any current playback.
|
|
1082
|
-
|
|
1221
|
+
/** Set the document to play. Stops any current playback. With `excerpt`,
|
|
1222
|
+
* only the notes singing those stretches of the song's text play, in order
|
|
1223
|
+
* (see `alignLyrics`); the length, seeks and repeats all keep to them. */
|
|
1224
|
+
load(doc, { excerpt } = {}) {
|
|
1083
1225
|
this.#halt();
|
|
1084
1226
|
this.#doc = doc;
|
|
1227
|
+
this.#excerpt = excerpt;
|
|
1085
1228
|
this.#taal = void 0;
|
|
1086
1229
|
this.#taalOverride = void 0;
|
|
1087
1230
|
this.#bpmTweak = void 0;
|
|
@@ -1404,7 +1547,7 @@ var SwaralipiPlayer = class {
|
|
|
1404
1547
|
*/
|
|
1405
1548
|
bindSheet(target, opts = {}) {
|
|
1406
1549
|
const block = opts.autoScroll === true ? "center" : opts.autoScroll || void 0;
|
|
1407
|
-
this.#
|
|
1550
|
+
this.#paint = (path, yourTurn) => {
|
|
1408
1551
|
target.clearHighlights();
|
|
1409
1552
|
if (path === null) return;
|
|
1410
1553
|
const el2 = target.highlight(path, yourTurn);
|
|
@@ -1516,6 +1659,7 @@ var SwaralipiPlayer = class {
|
|
|
1516
1659
|
this.#opts.onState?.(state);
|
|
1517
1660
|
}
|
|
1518
1661
|
#emitHighlight(path, yourTurn = false) {
|
|
1662
|
+
this.#paint?.(path, yourTurn);
|
|
1519
1663
|
this.#opts.onHighlight?.(path, yourTurn);
|
|
1520
1664
|
}
|
|
1521
1665
|
#emitLoop() {
|
|
@@ -1673,7 +1817,8 @@ var SwaralipiPlayer = class {
|
|
|
1673
1817
|
tonic: this.#opts.tonic,
|
|
1674
1818
|
baseOctave: this.#opts.baseOctave,
|
|
1675
1819
|
laySpeeds: this.#opts.laySpeeds,
|
|
1676
|
-
repeats: this.#opts.repeats
|
|
1820
|
+
repeats: this.#opts.repeats,
|
|
1821
|
+
excerpt: this.#excerpt
|
|
1677
1822
|
};
|
|
1678
1823
|
}
|
|
1679
1824
|
/** Effective tempo: snapped to the taal's available tabla tempos while a
|
|
@@ -2245,8 +2390,8 @@ function concatBytes(chunks) {
|
|
|
2245
2390
|
}
|
|
2246
2391
|
async function loadLame() {
|
|
2247
2392
|
try {
|
|
2248
|
-
const
|
|
2249
|
-
const Mp3Encoder =
|
|
2393
|
+
const mod2 = await import('@breezystack/lamejs');
|
|
2394
|
+
const Mp3Encoder = mod2.Mp3Encoder ?? mod2.default?.Mp3Encoder;
|
|
2250
2395
|
if (!Mp3Encoder) throw new Error("no Mp3Encoder export");
|
|
2251
2396
|
return Mp3Encoder;
|
|
2252
2397
|
} catch {
|
|
@@ -2430,6 +2575,7 @@ exports.SwaralipiPlayer = SwaralipiPlayer;
|
|
|
2430
2575
|
exports.TABLA_BPMS = TABLA_BPMS;
|
|
2431
2576
|
exports.TABLA_VARIATIONS = TABLA_VARIATIONS;
|
|
2432
2577
|
exports.TONEJS_INSTRUMENTS_BASE = TONEJS_INSTRUMENTS_BASE;
|
|
2578
|
+
exports.alignLyrics = alignLyrics;
|
|
2433
2579
|
exports.buildSchedule = buildSchedule;
|
|
2434
2580
|
exports.createBuffers = createBuffers;
|
|
2435
2581
|
exports.drumPattern = drumPattern;
|