@ugfoundation/swaralipi-js 0.8.2 → 0.9.1

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.
Files changed (52) hide show
  1. package/README.md +1 -1
  2. package/dist/{batch-6FPBT5DP.js → batch-NEM7JXHV.js} +5 -5
  3. package/dist/{batch-6FPBT5DP.js.map → batch-NEM7JXHV.js.map} +1 -1
  4. package/dist/{chunk-UMBKIGVQ.js → chunk-DOEFSS66.js} +5 -4
  5. package/dist/chunk-DOEFSS66.js.map +1 -0
  6. package/dist/{chunk-4HNT6OAT.js → chunk-MYVIQU4O.js} +12 -3
  7. package/dist/chunk-MYVIQU4O.js.map +1 -0
  8. package/dist/{chunk-4IVUPMRK.js → chunk-SEN266BY.js} +28 -13
  9. package/dist/chunk-SEN266BY.js.map +1 -0
  10. package/dist/{chunk-FULC22MN.js → chunk-Z6A3CP5V.js} +28 -19
  11. package/dist/chunk-Z6A3CP5V.js.map +1 -0
  12. package/dist/cli.cjs +33 -19
  13. package/dist/cli.cjs.map +1 -1
  14. package/dist/cli.js +3 -3
  15. package/dist/convert/index.cjs +31 -17
  16. package/dist/convert/index.cjs.map +1 -1
  17. package/dist/convert/index.d.cts +1 -1
  18. package/dist/convert/index.d.ts +1 -1
  19. package/dist/convert/index.js +3 -3
  20. package/dist/index.cjs +38 -17
  21. package/dist/index.cjs.map +1 -1
  22. package/dist/index.d.cts +2 -2
  23. package/dist/index.d.ts +2 -2
  24. package/dist/index.js +2 -2
  25. package/dist/{lay-Csa4CD46.d.cts → lay-CZIzR9cM.d.ts} +16 -2
  26. package/dist/{lay-Ct9ky_EE.d.ts → lay-CfDlPhH2.d.cts} +16 -2
  27. package/dist/player/index.cjs +116 -71
  28. package/dist/player/index.cjs.map +1 -1
  29. package/dist/player/index.d.cts +11 -9
  30. package/dist/player/index.d.ts +11 -9
  31. package/dist/player/index.js +89 -66
  32. package/dist/player/index.js.map +1 -1
  33. package/dist/{schedule-B_UaluBi.d.cts → schedule-BaovCtmf.d.ts} +31 -12
  34. package/dist/{schedule-CdILTNsk.d.ts → schedule-CU-VECDH.d.cts} +31 -12
  35. package/dist/{schema-DGA_bNVZ.d.ts → schema-Cf_epUIC.d.cts} +333 -63
  36. package/dist/{schema-DGA_bNVZ.d.cts → schema-Cf_epUIC.d.ts} +333 -63
  37. package/dist/spec/index.cjs +38 -17
  38. package/dist/spec/index.cjs.map +1 -1
  39. package/dist/spec/index.d.cts +26 -8
  40. package/dist/spec/index.d.ts +26 -8
  41. package/dist/spec/index.js +2 -2
  42. package/dist/viewer/index.cjs +156 -73
  43. package/dist/viewer/index.cjs.map +1 -1
  44. package/dist/viewer/index.d.cts +25 -7
  45. package/dist/viewer/index.d.ts +25 -7
  46. package/dist/viewer/index.js +78 -27
  47. package/dist/viewer/index.js.map +1 -1
  48. package/package.json +1 -1
  49. package/dist/chunk-4HNT6OAT.js.map +0 -1
  50. package/dist/chunk-4IVUPMRK.js.map +0 -1
  51. package/dist/chunk-FULC22MN.js.map +0 -1
  52. package/dist/chunk-UMBKIGVQ.js.map +0 -1
@@ -51,22 +51,6 @@ var noteSchema = z.lazy(
51
51
  )
52
52
  );
53
53
  var laySchema = z.enum(["drut", "madhya", "vilambit"]);
54
- var rowSchema = z.object({
55
- /** Optional line label (e.g. a tuk/section marker). */
56
- label: z.string().optional(),
57
- /**
58
- * লয়: the tempo tier this row switches to, held until another row changes
59
- * it (absent on every row = the whole song at `meta.bpm`, i.e. দ্রুত).
60
- * Read it with `rowLay()`, which also picks up the mark NLTR *prints*
61
- * ("বিলম্বিত লয়:") in already-converted documents.
62
- */
63
- lay: laySchema.optional(),
64
- notes: z.array(noteSchema)
65
- });
66
- var partSchema = z.object({
67
- name: z.string().optional(),
68
- rows: z.array(rowSchema)
69
- });
70
54
  var taalSchema = z.object({
71
55
  /** Player sample key, e.g. `dadra`, `teentaal`. */
72
56
  id: z.string(),
@@ -87,6 +71,31 @@ var taalSchema = z.object({
87
71
  }).refine((t) => t.bhaags === void 0 || t.bhaags.reduce((a, b) => a + b, 0) === t.numBeats, {
88
72
  message: "bhaags must sum to numBeats"
89
73
  });
74
+ var rowSchema = z.object({
75
+ /** Optional line label (e.g. a tuk/section marker). */
76
+ label: z.string().optional(),
77
+ /**
78
+ * লয়: the tempo tier this row switches to, held until another row changes
79
+ * it (absent on every row = the whole song at `meta.bpm`, i.e. দ্রুত).
80
+ * Read it with `rowLay()`, which also picks up the mark NLTR *prints*
81
+ * ("বিলম্বিত লয়:") in already-converted documents.
82
+ */
83
+ lay: laySchema.optional(),
84
+ /**
85
+ * তালফেরতা: the তাল this row switches to, held until another row changes it
86
+ * (absent on every row = the whole song in `meta.taal`). `null` = মুক্তছন্দ
87
+ * from here on: the accompaniment rests until a later row names a taal.
88
+ * Independent of `lay` — either, both or neither may change on one row.
89
+ */
90
+ taal: taalSchema.nullable().optional(),
91
+ /** That taal's name as printed (e.g. `ষষ্ঠী(২/৪)`) — `meta.taalName`'s twin. */
92
+ taalName: z.string().optional(),
93
+ notes: z.array(noteSchema)
94
+ });
95
+ var partSchema = z.object({
96
+ name: z.string().optional(),
97
+ rows: z.array(rowSchema)
98
+ });
90
99
  var metaSchema = z.object({
91
100
  title: z.string(),
92
101
  /** Cross-reference to a gitabitan.io song content id (filename, immutable). */
@@ -125,7 +134,7 @@ var swaralipiSchema = z.object({
125
134
  });
126
135
 
127
136
  // src/spec/index.ts
128
- var SPEC_VERSION = "0.8.2";
137
+ var SPEC_VERSION = "0.9.1";
129
138
  function parseSwaralipi(data) {
130
139
  return swaralipiSchema.parse(data);
131
140
  }
@@ -134,5 +143,5 @@ function safeParseSwaralipi(data) {
134
143
  }
135
144
 
136
145
  export { SPEC_VERSION, barSchema, bracketSchema, graceSchema, laySchema, metaSchema, microtoneSchema, noteSchema, octaveSchema, parseSwaralipi, partSchema, rowSchema, safeParseSwaralipi, svaraLetterSchema, svaraSchema, swaralipiSchema, taalSchema };
137
- //# sourceMappingURL=chunk-FULC22MN.js.map
138
- //# sourceMappingURL=chunk-FULC22MN.js.map
146
+ //# sourceMappingURL=chunk-Z6A3CP5V.js.map
147
+ //# sourceMappingURL=chunk-Z6A3CP5V.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/spec/schema.ts","../src/spec/index.ts"],"names":[],"mappings":"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","file":"chunk-Z6A3CP5V.js","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. */\n meend?: 'start' | 'end';\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 * 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']).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 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.9.1';\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/cli.cjs CHANGED
@@ -15,7 +15,7 @@ var __export = (target, all) => {
15
15
  for (var name in all)
16
16
  __defProp(target, name, { get: all[name], enumerable: true });
17
17
  };
18
- var octaveSchema, svaraLetterSchema, svaraSchema, microtoneSchema, barSchema, bracketSchema, graceSchema, noteSchema, laySchema, rowSchema, partSchema, taalSchema, metaSchema, swaralipiSchema;
18
+ var octaveSchema, svaraLetterSchema, svaraSchema, microtoneSchema, barSchema, bracketSchema, graceSchema, noteSchema, laySchema, taalSchema, rowSchema, partSchema, metaSchema, swaralipiSchema;
19
19
  var init_schema = __esm({
20
20
  "src/spec/schema.ts"() {
21
21
  octaveSchema = zod.z.enum([
@@ -68,22 +68,6 @@ var init_schema = __esm({
68
68
  )
69
69
  );
70
70
  laySchema = zod.z.enum(["drut", "madhya", "vilambit"]);
71
- rowSchema = zod.z.object({
72
- /** Optional line label (e.g. a tuk/section marker). */
73
- label: zod.z.string().optional(),
74
- /**
75
- * লয়: the tempo tier this row switches to, held until another row changes
76
- * it (absent on every row = the whole song at `meta.bpm`, i.e. দ্রুত).
77
- * Read it with `rowLay()`, which also picks up the mark NLTR *prints*
78
- * ("বিলম্বিত লয়:") in already-converted documents.
79
- */
80
- lay: laySchema.optional(),
81
- notes: zod.z.array(noteSchema)
82
- });
83
- partSchema = zod.z.object({
84
- name: zod.z.string().optional(),
85
- rows: zod.z.array(rowSchema)
86
- });
87
71
  taalSchema = zod.z.object({
88
72
  /** Player sample key, e.g. `dadra`, `teentaal`. */
89
73
  id: zod.z.string(),
@@ -104,6 +88,31 @@ var init_schema = __esm({
104
88
  }).refine((t) => t.bhaags === void 0 || t.bhaags.reduce((a, b) => a + b, 0) === t.numBeats, {
105
89
  message: "bhaags must sum to numBeats"
106
90
  });
91
+ rowSchema = zod.z.object({
92
+ /** Optional line label (e.g. a tuk/section marker). */
93
+ label: zod.z.string().optional(),
94
+ /**
95
+ * লয়: the tempo tier this row switches to, held until another row changes
96
+ * it (absent on every row = the whole song at `meta.bpm`, i.e. দ্রুত).
97
+ * Read it with `rowLay()`, which also picks up the mark NLTR *prints*
98
+ * ("বিলম্বিত লয়:") in already-converted documents.
99
+ */
100
+ lay: laySchema.optional(),
101
+ /**
102
+ * তালফেরতা: the তাল this row switches to, held until another row changes it
103
+ * (absent on every row = the whole song in `meta.taal`). `null` = মুক্তছন্দ
104
+ * from here on: the accompaniment rests until a later row names a taal.
105
+ * Independent of `lay` — either, both or neither may change on one row.
106
+ */
107
+ taal: taalSchema.nullable().optional(),
108
+ /** That taal's name as printed (e.g. `ষষ্ঠী(২/৪)`) — `meta.taalName`'s twin. */
109
+ taalName: zod.z.string().optional(),
110
+ notes: zod.z.array(noteSchema)
111
+ });
112
+ partSchema = zod.z.object({
113
+ name: zod.z.string().optional(),
114
+ rows: zod.z.array(rowSchema)
115
+ });
107
116
  metaSchema = zod.z.object({
108
117
  title: zod.z.string(),
109
118
  /** Cross-reference to a gitabitan.io song content id (filename, immutable). */
@@ -144,7 +153,10 @@ var init_schema = __esm({
144
153
  });
145
154
 
146
155
  // src/spec/taals.ts
147
- var TAALS;
156
+ function isTaalFerta(name) {
157
+ return name !== void 0 && name.normalize("NFC").replace(/[\s-]/g, "") === TAAL_FERTA;
158
+ }
159
+ var TAALS, TAAL_FERTA;
148
160
  var init_taals = __esm({
149
161
  "src/spec/taals.ts"() {
150
162
  TAALS = {
@@ -168,6 +180,7 @@ var init_taals = __esm({
168
180
  dhamaar: { id: "dhamaar", numBeats: 14, bhaags: [5, 2, 3, 4], sam: 0, khaali: [7] }
169
181
  // ধামার
170
182
  };
183
+ TAAL_FERTA = "\u09A4\u09BE\u09B2\u09AB\u09C7\u09B0\u09A4\u09BE";
171
184
  }
172
185
  });
173
186
 
@@ -177,7 +190,7 @@ var init_spec = __esm({
177
190
  "src/spec/index.ts"() {
178
191
  init_schema();
179
192
  init_taals();
180
- SPEC_VERSION = "0.8.2";
193
+ SPEC_VERSION = "0.9.1";
181
194
  }
182
195
  });
183
196
 
@@ -428,6 +441,7 @@ function resolveTaal(nameRaw, avartanRaw, geometry) {
428
441
  if (!taalName || TAAL_FREE.includes(taalName)) {
429
442
  return { taalName: taalName ? TAAL_FREE_CANON : void 0, avartan, matched: "none", warnings };
430
443
  }
444
+ if (isTaalFerta(taalName)) return { taalName: TAAL_FERTA, avartan, matched: "none", warnings };
431
445
  const parenMatch = taalName.match(/^(.*?)\s*\(([০-৯\d/\s]+)\)\s*$/);
432
446
  const base = (parenMatch ? parenMatch[1] : taalName).trim();
433
447
  let hintBhaags;