@ugfoundation/swaralipi-js 0.3.4 → 0.4.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/dist/{batch-Y3HKAL3B.js → batch-V4X3GN4N.js} +4 -4
- package/dist/{batch-Y3HKAL3B.js.map → batch-V4X3GN4N.js.map} +1 -1
- package/dist/{chunk-AIGSKUD3.js → chunk-6QW7MSJO.js} +23 -4
- package/dist/chunk-6QW7MSJO.js.map +1 -0
- package/dist/{chunk-IG2CIUTP.js → chunk-RTKWFJFI.js} +3 -3
- package/dist/{chunk-IG2CIUTP.js.map → chunk-RTKWFJFI.js.map} +1 -1
- package/dist/{chunk-KPKD53NA.js → chunk-ZS43BDP7.js} +3 -3
- package/dist/{chunk-KPKD53NA.js.map → chunk-ZS43BDP7.js.map} +1 -1
- 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 +48 -12
- package/dist/player/index.cjs.map +1 -1
- package/dist/player/index.d.cts +2 -2
- package/dist/player/index.d.ts +2 -2
- package/dist/player/index.js +30 -13
- package/dist/player/index.js.map +1 -1
- package/dist/{schedule-dXV5cUQI.d.ts → schedule-CAns78TD.d.ts} +10 -0
- package/dist/{schedule-C2WN7YOK.d.cts → schedule-D3JyEhuO.d.cts} +10 -0
- 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 +14 -2
- 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-AIGSKUD3.js.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { convertNltrHtml, aggregate, formatSummary } from './chunk-
|
|
2
|
-
import './chunk-
|
|
1
|
+
import { convertNltrHtml, aggregate, formatSummary } from './chunk-ZS43BDP7.js';
|
|
2
|
+
import './chunk-RTKWFJFI.js';
|
|
3
3
|
import './chunk-6ETPFHZ6.js';
|
|
4
4
|
import { stat, readdir, mkdir, readFile, writeFile } from 'fs/promises';
|
|
5
5
|
import { join, basename } from 'path';
|
|
@@ -43,5 +43,5 @@ async function runConvert(input, opts = {}) {
|
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
export { runConvert };
|
|
46
|
-
//# sourceMappingURL=batch-
|
|
47
|
-
//# sourceMappingURL=batch-
|
|
46
|
+
//# sourceMappingURL=batch-V4X3GN4N.js.map
|
|
47
|
+
//# sourceMappingURL=batch-V4X3GN4N.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/convert/batch.ts"],"names":["report"],"mappings":"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","file":"batch-
|
|
1
|
+
{"version":3,"sources":["../src/convert/batch.ts"],"names":["report"],"mappings":"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","file":"batch-V4X3GN4N.js","sourcesContent":["/**\n * File/dir conversion driver for the CLI (Node-only; not part of the\n * public `/convert` export). Continues past per-file failures and reports\n * them in the aggregate.\n */\nimport { mkdir, readFile, readdir, stat, writeFile } from 'node:fs/promises';\nimport { basename, join } from 'node:path';\nimport { convertNltrHtml } from './index.js';\nimport { aggregate, formatSummary, type BatchFailure, type BatchReport, type FileReport } from './report.js';\n\nexport interface BatchOptions {\n /** Output file (single input) or directory (directory input). */\n out?: string;\n /** Write the aggregate report JSON here. */\n reportPath?: string;\n compact?: boolean;\n quiet?: boolean;\n /** Progress/summary sink (default stderr). */\n log?: (line: string) => void;\n}\n\nconst nltrIdOf = (file: string): number | undefined => {\n const m = basename(file).match(/^(\\d+)\\.html$/);\n return m ? Number(m[1]) : undefined;\n};\n\nconst serialize = (doc: unknown, compact: boolean | undefined): string =>\n (compact ? JSON.stringify(doc) : JSON.stringify(doc, null, 2)) + '\\n';\n\nexport async function runConvert(\n input: string,\n opts: BatchOptions = {},\n): Promise<{ exitCode: 0 | 1; report: BatchReport }> {\n const log = opts.log ?? ((line: string) => process.stderr.write(line + '\\n'));\n const stats = await stat(input);\n const files = stats.isDirectory()\n ? (await readdir(input))\n .filter((f) => f.endsWith('.html'))\n .sort((a, b) => (nltrIdOf(a) ?? 0) - (nltrIdOf(b) ?? 0) || a.localeCompare(b))\n .map((f) => join(input, f))\n : [input];\n\n const isDir = stats.isDirectory();\n if (isDir && !opts.out) throw new Error('directory input requires -o <outDir>');\n if (isDir && opts.out) await mkdir(opts.out, { recursive: true });\n\n const reports: FileReport[] = [];\n const failures: BatchFailure[] = [];\n for (const file of files) {\n try {\n const html = await readFile(file, 'utf8');\n const { doc, report } = convertNltrHtml(html, { nltrId: nltrIdOf(file) });\n reports.push(report);\n const json = serialize(doc, opts.compact);\n if (isDir) {\n const name = `${nltrIdOf(file) ?? basename(file, '.html')}.json`;\n await writeFile(join(opts.out!, name), json);\n } else if (opts.out) {\n await writeFile(opts.out, json);\n } else {\n process.stdout.write(json);\n }\n } catch (err) {\n failures.push({ file: basename(file), error: err instanceof Error ? err.message : String(err) });\n }\n }\n\n const report = aggregate(reports, failures);\n if (opts.reportPath) await writeFile(opts.reportPath, serialize(report, false));\n if (!opts.quiet) log(formatSummary(report));\n return { exitCode: failures.length > 0 ? 1 : 0, report };\n}\n"]}
|
|
@@ -76,15 +76,25 @@ function sampleFileName(midi) {
|
|
|
76
76
|
|
|
77
77
|
// src/player/schedule.ts
|
|
78
78
|
var isSilent = (n) => n.svara === void 0 && n.rest !== true && n.sustain !== true;
|
|
79
|
+
var SAM_TICK = /^\d+[fF]$/;
|
|
79
80
|
function buildSchedule(doc, opts = {}) {
|
|
80
81
|
const tonicPc = parseTonic(opts.tonic ?? doc.meta.tonic);
|
|
81
82
|
const baseOctave = opts.baseOctave ?? 4;
|
|
82
83
|
const events = [];
|
|
83
84
|
let cursor = 0;
|
|
84
85
|
let lastPitched = -1;
|
|
86
|
+
let samBeat;
|
|
85
87
|
doc.parts.forEach((part, p) => {
|
|
86
88
|
part.rows.forEach((row, r) => {
|
|
87
89
|
row.notes.forEach((note, i) => {
|
|
90
|
+
if (samBeat === void 0 && note.above !== void 0) {
|
|
91
|
+
for (const a of note.above) {
|
|
92
|
+
if (a.raw !== void 0 && SAM_TICK.test(a.raw)) {
|
|
93
|
+
samBeat = cursor;
|
|
94
|
+
break;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
88
98
|
if (note.bar !== void 0 || isSilent(note)) return;
|
|
89
99
|
const path = `${p}.${r}.${i}`;
|
|
90
100
|
const dur = note.durationMatra ?? 1;
|
|
@@ -108,7 +118,9 @@ function buildSchedule(doc, opts = {}) {
|
|
|
108
118
|
});
|
|
109
119
|
});
|
|
110
120
|
});
|
|
111
|
-
|
|
121
|
+
const numBeats = doc.meta.taal?.numBeats;
|
|
122
|
+
const pickupBeats = samBeat !== void 0 && numBeats !== void 0 && numBeats > 0 ? (numBeats - samBeat % numBeats) % numBeats : 0;
|
|
123
|
+
return { events, totalBeats: cursor, pickupBeats };
|
|
112
124
|
}
|
|
113
125
|
|
|
114
126
|
// src/player/instruments.ts
|
|
@@ -303,6 +315,13 @@ function tablaUrl(base, taalId, bpm, variation) {
|
|
|
303
315
|
const seg = tablaSeg(taalId, variation);
|
|
304
316
|
return `${normalizeBase(base)}tabla/${seg}/${seg}${bpm}bpm.mp3`;
|
|
305
317
|
}
|
|
318
|
+
var TABLA_TONIC_SEMITONE = 0;
|
|
319
|
+
function tablaShiftSemitones(tonicSemitone) {
|
|
320
|
+
const d = ((tonicSemitone - TABLA_TONIC_SEMITONE) % 12 + 12) % 12;
|
|
321
|
+
return d > 6 ? d - 12 : d;
|
|
322
|
+
}
|
|
323
|
+
var TABLA_GRAIN_SEC = 0.06;
|
|
324
|
+
var TABLA_GRAIN_OVERLAP_SEC = 0.03;
|
|
306
325
|
function metronomeUrl(base) {
|
|
307
326
|
return `${normalizeBase(base)}metronome/metro2.mp3`;
|
|
308
327
|
}
|
|
@@ -349,6 +368,6 @@ function createTanpura(Tone, base, stems = TANPURA_PCS) {
|
|
|
349
368
|
return new Tone.Players({ urls, baseUrl: `${normalizeBase(base)}tanpura/` });
|
|
350
369
|
}
|
|
351
370
|
|
|
352
|
-
export { DEFAULT_SOUNDS_BASE, DRUM_KIT_BASE, INSTRUMENTS, OCTAVE_OFFSET, SALAMANDER_BASE, SAMPLED_TAALS, SHUDDHA, TABLA_BPMS, TABLA_VARIATIONS, TANPURA_PCS, TONEJS_INSTRUMENTS_BASE, buildSchedule, createDrumKit, createMetronome, createSampler, createTanpura, drumPattern, instrumentSampleUrl, midiToSampleName, nearestTablaBpm, normalizeBase, parseTonic, probeUrl, quantizeLoopEnd, sampleFileName, santoorUrls, subsetUrls, svaraSemitone, svaraToMidi, tablaBpms, tablaUrl };
|
|
353
|
-
//# sourceMappingURL=chunk-
|
|
354
|
-
//# sourceMappingURL=chunk-
|
|
371
|
+
export { DEFAULT_SOUNDS_BASE, DRUM_KIT_BASE, INSTRUMENTS, OCTAVE_OFFSET, SALAMANDER_BASE, SAMPLED_TAALS, SHUDDHA, TABLA_BPMS, TABLA_GRAIN_OVERLAP_SEC, TABLA_GRAIN_SEC, TABLA_VARIATIONS, TANPURA_PCS, TONEJS_INSTRUMENTS_BASE, buildSchedule, createDrumKit, createMetronome, createSampler, createTanpura, drumPattern, instrumentSampleUrl, midiToSampleName, nearestTablaBpm, normalizeBase, parseTonic, probeUrl, quantizeLoopEnd, sampleFileName, santoorUrls, subsetUrls, svaraSemitone, svaraToMidi, tablaBpms, tablaShiftSemitones, tablaUrl };
|
|
372
|
+
//# sourceMappingURL=chunk-6QW7MSJO.js.map
|
|
373
|
+
//# sourceMappingURL=chunk-6QW7MSJO.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/player/pitch.ts","../src/player/schedule.ts","../src/player/instruments.ts"],"names":[],"mappings":"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","file":"chunk-6QW7MSJO.js","sourcesContent":["/**\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 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 if (note.komal === true || note.microtone !== undefined) semi -= 1;\n if (note.tivra === true) 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 kan (grace) svara — a bare `Svara` tuple, no accidentals. */\nexport function kanToMidi(\n svara: Note['kan'],\n tonicPc: number,\n baseOctave = 4,\n): number | null {\n if (svara === undefined) return null;\n const [octave, letter] = svara;\n return (baseOctave + 1 + OCTAVE_OFFSET[octave]) * 12 + tonicPc + SHUDDHA[letter];\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 * 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 } from '../spec/index.js';\nimport { kanToMidi, parseTonic, svaraToMidi } from './pitch.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 /** Grace-note MIDI struck just before the main attack, when present. */\n kan: number | null;\n /** `part.row.note` highlight path. */\n path: string;\n kind: 'note' | 'rest' | 'sustain';\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}\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}\n\n/** A column that produces no sound and no time advance (bar, bracket-only,\n * carrier, raw-only). Mirrors the viewer's non-pitched, non-rest classes. */\nconst isSilent = (n: Note): boolean =>\n n.svara === undefined && n.rest !== true && n.sustain !== true;\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 * - bar / bracket-only / carrier / raw-only → ignored (no event, no advance).\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. */\n let samBeat: number | undefined;\n\n doc.parts.forEach((part, p) => {\n part.rows.forEach((row, r) => {\n row.notes.forEach((note, i) => {\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 (samBeat === undefined && note.above !== undefined) {\n for (const a of note.above) {\n if (a.raw !== undefined && SAM_TICK.test(a.raw)) {\n samBeat = cursor;\n break;\n }\n }\n }\n if (note.bar !== undefined || isSilent(note)) return;\n const path = `${p}.${r}.${i}`;\n const dur = note.durationMatra ?? 1;\n\n if (note.svara !== undefined) {\n // svara note or melisma — a real attack.\n events.push({\n beat: cursor,\n durationBeats: dur,\n midi: svaraToMidi(note, tonicPc, baseOctave),\n kan: kanToMidi(note.kan, tonicPc, baseOctave),\n path,\n kind: note.sustain === true ? 'sustain' : 'note',\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: null, path, kind: 'sustain' });\n } else {\n // rest.\n events.push({ beat: cursor, durationBeats: dur, midi: null, kan: null, path, kind: 'rest' });\n }\n cursor += dur;\n });\n });\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 const numBeats = doc.meta.taal?.numBeats;\n const pickupBeats =\n samBeat !== undefined && numBeats !== undefined && numBeats > 0\n ? (numBeats - (samBeat % numBeats)) % numBeats\n : 0;\n\n return { events, totalBeats: cursor, pickupBeats };\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 { 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) — CC-BY, redistribution-verified and CORS-enabled, so the player\n * works with zero config. Override via the player's `soundsBaseUrl` to\n * self-host. (Melody defaults to the CDN-hosted piano, so it needs no host.)\n */\nexport const DEFAULT_SOUNDS_BASE = 'https://cdn.daserve.in/swaralipijs-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).\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', 'F#4', '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/** 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"]}
|
|
@@ -109,7 +109,7 @@ var swaralipiSchema = z.object({
|
|
|
109
109
|
});
|
|
110
110
|
|
|
111
111
|
// src/spec/index.ts
|
|
112
|
-
var SPEC_VERSION = "0.
|
|
112
|
+
var SPEC_VERSION = "0.4.0";
|
|
113
113
|
function parseSwaralipi(data) {
|
|
114
114
|
return swaralipiSchema.parse(data);
|
|
115
115
|
}
|
|
@@ -118,5 +118,5 @@ function safeParseSwaralipi(data) {
|
|
|
118
118
|
}
|
|
119
119
|
|
|
120
120
|
export { SPEC_VERSION, barSchema, bracketSchema, metaSchema, microtoneSchema, noteSchema, octaveSchema, parseSwaralipi, partSchema, rowSchema, safeParseSwaralipi, svaraLetterSchema, svaraSchema, swaralipiSchema, taalSchema };
|
|
121
|
-
//# sourceMappingURL=chunk-
|
|
122
|
-
//# sourceMappingURL=chunk-
|
|
121
|
+
//# sourceMappingURL=chunk-RTKWFJFI.js.map
|
|
122
|
+
//# sourceMappingURL=chunk-RTKWFJFI.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/spec/schema.ts","../src/spec/index.ts"],"names":[],"mappings":";;;AAMO,IAAM,YAAA,GAAe,EAAE,IAAA,CAAK;AAAA,EACjC,YAAA;AAAA;AAAA,EACA,QAAA;AAAA;AAAA,EACA,SAAA;AAAA;AAAA,EACA,MAAA;AAAA;AAAA,EACA;AAAA;AACF,CAAC;AAOM,IAAM,iBAAA,GAAoB,CAAA,CAAE,IAAA,CAAK,CAAC,GAAA,EAAK,GAAA,EAAK,GAAA,EAAK,GAAA,EAAK,GAAA,EAAK,GAAA,EAAK,GAAG,CAAC;AAIpE,IAAM,cAAc,CAAA,CAAE,KAAA,CAAM,CAAC,YAAA,EAAc,iBAAiB,CAAC;AAI7D,IAAM,kBAAkB,CAAA,CAAE,IAAA,CAAK,CAAC,WAAA,EAAa,UAAU,CAAC;AAWxD,IAAM,SAAA,GAAY,EAAE,IAAA,CAAK,CAAC,QAAQ,QAAA,EAAU,QAAA,EAAU,MAAM,CAAC;AAS7D,IAAM,aAAA,GAAgB,EAAE,MAAA,CAAO;AAAA,EACpC,MAAM,CAAA,CAAE,IAAA,CAAK,CAAC,QAAA,EAAU,MAAA,EAAQ,KAAK,CAAC,CAAA;AAAA,EACtC,MAAM,CAAA,CAAE,IAAA,CAAK,CAAC,MAAA,EAAQ,OAAO,CAAC;AAChC,CAAC;AAwDM,IAAM,aAA8B,CAAA,CAAE,IAAA;AAAA,EAAK,MAChD,EACG,MAAA,CAAO;AAAA,IACN,KAAA,EAAO,YAAY,QAAA,EAAS;AAAA,IAC5B,KAAA,EAAO,CAAA,CAAE,OAAA,EAAQ,CAAE,QAAA,EAAS;AAAA,IAC5B,KAAA,EAAO,CAAA,CAAE,OAAA,EAAQ,CAAE,QAAA,EAAS;AAAA,IAC5B,SAAA,EAAW,gBAAgB,QAAA,EAAS;AAAA,IACpC,eAAe,CAAA,CAAE,MAAA,EAAO,CAAE,QAAA,GAAW,QAAA,EAAS;AAAA,IAC9C,OAAA,EAAS,CAAA,CAAE,OAAA,EAAQ,CAAE,QAAA,EAAS;AAAA,IAC9B,IAAA,EAAM,CAAA,CAAE,OAAA,EAAQ,CAAE,QAAA,EAAS;AAAA,IAC3B,GAAA,EAAK,YAAY,QAAA,EAAS;AAAA,IAC1B,KAAA,EAAO,EAAE,IAAA,CAAK,CAAC,SAAS,KAAK,CAAC,EAAE,QAAA,EAAS;AAAA,IACzC,GAAA,EAAK,UAAU,QAAA,EAAS;AAAA,IACxB,QAAA,EAAU,CAAA,CAAE,KAAA,CAAM,aAAa,EAAE,QAAA,EAAS;AAAA,IAC1C,KAAA,EAAO,CAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,IAC3B,GAAA,EAAK,CAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,IACzB,KAAA,EAAO,CAAA,CAAE,KAAA,CAAM,UAAU,EAAE,QAAA,EAAS;AAAA,IACpC,KAAA,EAAO,CAAA,CAAE,KAAA,CAAM,UAAU,EAAE,QAAA;AAAS,GACrC,CAAA,CACA,MAAA;AAAA,IACC,CAAC,CAAA,KACC,CAAA,CAAE,KAAA,KAAU,MAAA,IACZ,EAAE,IAAA,KAAS,IAAA,IACX,CAAA,CAAE,OAAA,KAAY,QACd,CAAA,CAAE,GAAA,KAAQ,UACV,CAAA,CAAE,GAAA,KAAQ,UACT,CAAA,CAAE,QAAA,KAAa,MAAA,IAAa,CAAA,CAAE,SAAS,MAAA,GAAS,CAAA,IAChD,EAAE,KAAA,KAAU,MAAA,IAAa,EAAE,KAAA,CAAM,MAAA,GAAS,CAAA,IAC1C,CAAA,CAAE,UAAU,MAAA,IAAa,CAAA,CAAE,MAAM,MAAA,GAAS,CAAA,IAC3C,EAAE,KAAA,KAAU,MAAA;AAAA,IACd;AAAA,MACE,OAAA,EACE;AAAA;AACJ;AAEN;AAGO,IAAM,SAAA,GAAY,EAAE,MAAA,CAAO;AAAA;AAAA,EAEhC,KAAA,EAAO,CAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EAC3B,KAAA,EAAO,CAAA,CAAE,KAAA,CAAM,UAAU;AAC3B,CAAC;AAIM,IAAM,UAAA,GAAa,EAAE,MAAA,CAAO;AAAA,EACjC,IAAA,EAAM,CAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EAC1B,IAAA,EAAM,CAAA,CAAE,KAAA,CAAM,SAAS;AACzB,CAAC;AAOM,IAAM,UAAA,GAAa,EACvB,MAAA,CAAO;AAAA;AAAA,EAEN,EAAA,EAAI,EAAE,MAAA,EAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOb,SAAA,EAAW,CAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EAC/B,UAAU,CAAA,CAAE,MAAA,EAAO,CAAE,GAAA,GAAM,QAAA,EAAS;AAAA;AAAA,EAEpC,MAAA,EAAQ,CAAA,CAAE,KAAA,CAAM,CAAA,CAAE,MAAA,EAAO,CAAE,GAAA,EAAI,CAAE,QAAA,EAAU,CAAA,CAAE,QAAA,EAAS;AAAA;AAAA,EAEtD,GAAA,EAAK,EAAE,MAAA,EAAO,CAAE,KAAI,CAAE,WAAA,GAAc,QAAA,EAAS;AAAA;AAAA,EAE7C,MAAA,EAAQ,CAAA,CAAE,KAAA,CAAM,CAAA,CAAE,MAAA,EAAO,CAAE,GAAA,EAAI,CAAE,WAAA,EAAa,CAAA,CAAE,QAAA;AAClD,CAAC,EACA,MAAA,CAAO,CAAC,MAAM,CAAA,CAAE,MAAA,KAAW,UAAa,CAAA,CAAE,MAAA,CAAO,MAAA,CAAO,CAAC,GAAG,CAAA,KAAM,CAAA,GAAI,GAAG,CAAC,CAAA,KAAM,EAAE,QAAA,EAAU;AAAA,EAC3F,OAAA,EAAS;AACX,CAAC;AAII,IAAM,UAAA,GAAa,EAAE,MAAA,CAAO;AAAA,EACjC,KAAA,EAAO,EAAE,MAAA,EAAO;AAAA;AAAA,EAEhB,MAAA,EAAQ,CAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA;AAAA,EAE5B,QAAQ,CAAA,CAAE,MAAA,EAAO,CAAE,GAAA,GAAM,QAAA,EAAS;AAAA,EAClC,IAAA,EAAM,WAAW,QAAA,EAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAM1B,QAAA,EAAU,CAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA;AAAA,EAE9B,KAAA,EAAO,CAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA;AAAA;AAAA;AAAA,EAI3B,GAAA,EAAK,EAAE,MAAA,EAAO,CAAE,UAAS,CAAE,QAAA,GAAW,QAAA,EAAS;AAAA,EAC/C,IAAA,EAAM,CAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA;AAAA,EAE1B,OAAA,EAAS,EAAE,MAAA,EAAO,CAAE,KAAI,CAAE,QAAA,GAAW,QAAA,EAAS;AAAA;AAAA,EAE9C,UAAA,EAAY,CAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA;AAAA,EAEhC,MAAA,EAAQ,CAAA,CAAE,MAAA,EAAO,CAAE,QAAA;AACrB,CAAC;AAIM,IAAM,eAAA,GAAkB,EAAE,MAAA,CAAO;AAAA;AAAA,EAEtC,OAAA,EAAS,EAAE,MAAA,EAAO;AAAA,EAClB,IAAA,EAAM,UAAA;AAAA,EACN,KAAA,EAAO,CAAA,CAAE,KAAA,CAAM,UAAU;AAC3B,CAAC;;;ACtNM,IAAM,YAAA,GAAe;AAmCrB,SAAS,eAAe,IAAA,EAA0B;AACvD,EAAA,OAAO,eAAA,CAAgB,MAAM,IAAI,CAAA;AACnC;AAGO,SAAS,mBAAmB,IAAA,EAAe;AAChD,EAAA,OAAO,eAAA,CAAgB,UAAU,IAAI,CAAA;AACvC","file":"chunk-IG2CIUTP.js","sourcesContent":["import { z } from 'zod';\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 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 /** কণ স্বর: a grace note attached before this note. */\n kan?: Svara;\n /** মীড় (glide/slur) endpoint. */\n meend?: 'start' | 'end';\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: svaraSchema.optional(),\n meend: z.enum(['start', 'end']).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/** 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 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/**\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/** 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 exactly as printed in the source (e.g. `তালমুক্ত`,\n * `ষষ্ঠী(২/৪)`). Always set by the NLTR converter; `taal` is set only\n * when the name resolves to a known 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 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.3.4';\n\nexport {\n octaveSchema,\n svaraLetterSchema,\n svaraSchema,\n microtoneSchema,\n barSchema,\n bracketSchema,\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 Note,\n Row,\n Part,\n Taal,\n Meta,\n Swaralipi,\n} from './schema.js';\n\nexport { TAALS, type TaalId } from './taals.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/index.ts"],"names":[],"mappings":"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","file":"chunk-RTKWFJFI.js","sourcesContent":["import { z } from 'zod';\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 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 /** কণ স্বর: a grace note attached before this note. */\n kan?: Svara;\n /** মীড় (glide/slur) endpoint. */\n meend?: 'start' | 'end';\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: svaraSchema.optional(),\n meend: z.enum(['start', 'end']).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/** 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 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/**\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/** 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 exactly as printed in the source (e.g. `তালমুক্ত`,\n * `ষষ্ঠী(২/৪)`). Always set by the NLTR converter; `taal` is set only\n * when the name resolves to a known 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 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.4.0';\n\nexport {\n octaveSchema,\n svaraLetterSchema,\n svaraSchema,\n microtoneSchema,\n barSchema,\n bracketSchema,\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 Note,\n Row,\n Part,\n Taal,\n Meta,\n Swaralipi,\n} from './schema.js';\n\nexport { TAALS, type TaalId } from './taals.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,4 +1,4 @@
|
|
|
1
|
-
import { swaralipiSchema, SPEC_VERSION } from './chunk-
|
|
1
|
+
import { swaralipiSchema, SPEC_VERSION } from './chunk-RTKWFJFI.js';
|
|
2
2
|
import { TAALS } from './chunk-6ETPFHZ6.js';
|
|
3
3
|
|
|
4
4
|
// src/convert/codec.ts
|
|
@@ -589,5 +589,5 @@ function convertNltrHtml(html, opts = {}) {
|
|
|
589
589
|
}
|
|
590
590
|
|
|
591
591
|
export { ExtractError, aggregate, assemble, bnInt, buildSystems, convertNltrHtml, decodeCell, deriveGeometry, extractPage, formatSummary, resolveTaal, splitLyric };
|
|
592
|
-
//# sourceMappingURL=chunk-
|
|
593
|
-
//# sourceMappingURL=chunk-
|
|
592
|
+
//# sourceMappingURL=chunk-ZS43BDP7.js.map
|
|
593
|
+
//# sourceMappingURL=chunk-ZS43BDP7.js.map
|