@ugfoundation/swaralipi-js 0.2.1 → 0.3.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.
- package/dist/{batch-SCSIUDB3.js → batch-TVEIT2OJ.js} +4 -4
- package/dist/{batch-SCSIUDB3.js.map → batch-TVEIT2OJ.js.map} +1 -1
- package/dist/{chunk-KYNCQ7OF.js → chunk-HDN3YZ6K.js} +3 -3
- package/dist/{chunk-KYNCQ7OF.js.map → chunk-HDN3YZ6K.js.map} +1 -1
- package/dist/chunk-V5ZSUJCA.js +354 -0
- package/dist/chunk-V5ZSUJCA.js.map +1 -0
- package/dist/{chunk-DINRYGRI.js → chunk-WBSIKYWB.js} +3 -3
- package/dist/{chunk-DINRYGRI.js.map → chunk-WBSIKYWB.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 +117 -20
- package/dist/player/index.cjs.map +1 -1
- package/dist/player/index.d.cts +24 -164
- package/dist/player/index.d.ts +24 -164
- package/dist/player/index.js +91 -343
- package/dist/player/index.js.map +1 -1
- package/dist/schedule-BhiP_maG.d.ts +167 -0
- package/dist/schedule-Dsb2paUE.d.cts +167 -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 +584 -54
- package/dist/viewer/index.cjs.map +1 -1
- package/dist/viewer/index.d.cts +177 -18
- package/dist/viewer/index.d.ts +177 -18
- package/dist/viewer/index.js +322 -30
- package/dist/viewer/index.js.map +1 -1
- package/package.json +7 -2
package/dist/viewer/index.cjs
CHANGED
|
@@ -11,6 +11,30 @@ var __export = (target, all) => {
|
|
|
11
11
|
for (var name in all)
|
|
12
12
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
13
13
|
};
|
|
14
|
+
|
|
15
|
+
// src/spec/taals.ts
|
|
16
|
+
var TAALS;
|
|
17
|
+
var init_taals = __esm({
|
|
18
|
+
"src/spec/taals.ts"() {
|
|
19
|
+
TAALS = {
|
|
20
|
+
dadra: { id: "dadra", numBeats: 6, bhaags: [3, 3], sam: 0, khaali: [3] },
|
|
21
|
+
kehrwa: { id: "kehrwa", numBeats: 8, bhaags: [4, 4], sam: 0, khaali: [4] },
|
|
22
|
+
rupak: { id: "rupak", numBeats: 7, bhaags: [3, 2, 2], sam: 0, khaali: [0] },
|
|
23
|
+
jhaptaal: { id: "jhaptaal", numBeats: 10, bhaags: [2, 3, 2, 3], sam: 0, khaali: [5] },
|
|
24
|
+
ektaal: { id: "ektaal", numBeats: 12, bhaags: [2, 2, 2, 2, 2, 2], sam: 0, khaali: [2, 6] },
|
|
25
|
+
adachautaal: { id: "adachautaal", numBeats: 14, sam: 0 },
|
|
26
|
+
choutaal: { id: "choutaal", numBeats: 12, bhaags: [2, 2, 2, 2, 2, 2], sam: 0, khaali: [2, 6] },
|
|
27
|
+
// চৌতাল
|
|
28
|
+
shashthi: { id: "shashthi", numBeats: 6, bhaags: [2, 4], sam: 0 },
|
|
29
|
+
// ষষ্ঠী
|
|
30
|
+
teora: { id: "teora", numBeats: 7, bhaags: [3, 2, 2], sam: 0 },
|
|
31
|
+
// টেওরা
|
|
32
|
+
teentaal: { id: "teentaal", numBeats: 16, bhaags: [4, 4, 4, 4], sam: 0, khaali: [8] },
|
|
33
|
+
aratheka: { id: "aratheka", numBeats: 16, bhaags: [4, 4, 4, 4], sam: 0, khaali: [8] }
|
|
34
|
+
// আড়াঠেকা
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
});
|
|
14
38
|
var octaveSchema, svaraLetterSchema, svaraSchema, microtoneSchema, barSchema, bracketSchema, noteSchema, rowSchema, partSchema, taalSchema, metaSchema, swaralipiSchema;
|
|
15
39
|
var init_schema = __esm({
|
|
16
40
|
"src/spec/schema.ts"() {
|
|
@@ -123,30 +147,6 @@ var init_schema = __esm({
|
|
|
123
147
|
}
|
|
124
148
|
});
|
|
125
149
|
|
|
126
|
-
// src/spec/taals.ts
|
|
127
|
-
var TAALS;
|
|
128
|
-
var init_taals = __esm({
|
|
129
|
-
"src/spec/taals.ts"() {
|
|
130
|
-
TAALS = {
|
|
131
|
-
dadra: { id: "dadra", numBeats: 6, bhaags: [3, 3], sam: 0, khaali: [3] },
|
|
132
|
-
kehrwa: { id: "kehrwa", numBeats: 8, bhaags: [4, 4], sam: 0, khaali: [4] },
|
|
133
|
-
rupak: { id: "rupak", numBeats: 7, bhaags: [3, 2, 2], sam: 0, khaali: [0] },
|
|
134
|
-
jhaptaal: { id: "jhaptaal", numBeats: 10, bhaags: [2, 3, 2, 3], sam: 0, khaali: [5] },
|
|
135
|
-
ektaal: { id: "ektaal", numBeats: 12, bhaags: [2, 2, 2, 2, 2, 2], sam: 0, khaali: [2, 6] },
|
|
136
|
-
adachautaal: { id: "adachautaal", numBeats: 14, sam: 0 },
|
|
137
|
-
choutaal: { id: "choutaal", numBeats: 12, bhaags: [2, 2, 2, 2, 2, 2], sam: 0, khaali: [2, 6] },
|
|
138
|
-
// চৌতাল
|
|
139
|
-
shashthi: { id: "shashthi", numBeats: 6, bhaags: [2, 4], sam: 0 },
|
|
140
|
-
// ষষ্ঠী
|
|
141
|
-
teora: { id: "teora", numBeats: 7, bhaags: [3, 2, 2], sam: 0 },
|
|
142
|
-
// টেওরা
|
|
143
|
-
teentaal: { id: "teentaal", numBeats: 16, bhaags: [4, 4, 4, 4], sam: 0, khaali: [8] },
|
|
144
|
-
aratheka: { id: "aratheka", numBeats: 16, bhaags: [4, 4, 4, 4], sam: 0, khaali: [8] }
|
|
145
|
-
// আড়াঠেকা
|
|
146
|
-
};
|
|
147
|
-
}
|
|
148
|
-
});
|
|
149
|
-
|
|
150
150
|
// src/spec/index.ts
|
|
151
151
|
var spec_exports = {};
|
|
152
152
|
__export(spec_exports, {
|
|
@@ -179,7 +179,7 @@ var init_spec = __esm({
|
|
|
179
179
|
init_schema();
|
|
180
180
|
init_schema();
|
|
181
181
|
init_taals();
|
|
182
|
-
SPEC_VERSION = "0.
|
|
182
|
+
SPEC_VERSION = "0.3.1";
|
|
183
183
|
}
|
|
184
184
|
});
|
|
185
185
|
|
|
@@ -221,9 +221,9 @@ var MARKS = {
|
|
|
221
221
|
en: { hyphen: "-", melisma: "\xB7", cut: ":" }
|
|
222
222
|
};
|
|
223
223
|
var LABELS = {
|
|
224
|
-
bn: { title: "\u09A8\u09BE\u09AE", taal: "\u09A4\u09BE\u09B2", raag: "\u09B0\u09BE\u0997", avartan: "\u0986\u09AC\u09B0\u09CD\u09A4\u09A8", notationBy: "\u09B8\u09CD\u09AC\u09B0\u09B2\u09BF\u09AA\u09BF" },
|
|
225
|
-
hi: { title: "\u0928\u093E\u092E", taal: "\u0924\u093E\u0932", raag: "\u0930\u093E\u0917", avartan: "\u0906\u0935\u0930\u094D\u0924\u0928", notationBy: "\u0938\u094D\u0935\u0930\u0932\u093F\u092A\u093F" },
|
|
226
|
-
en: { title: "Song", taal: "Taal", raag: "Raag", avartan: "Avartan", notationBy: "
|
|
224
|
+
bn: { title: "\u09A8\u09BE\u09AE", taal: "\u09A4\u09BE\u09B2", raag: "\u09B0\u09BE\u0997", avartan: "\u0986\u09AC\u09B0\u09CD\u09A4\u09A8", notationBy: "\u09B8\u09CD\u09AC\u09B0\u09B2\u09BF\u09AA\u09BF\u0995\u09BE\u09B0" },
|
|
225
|
+
hi: { title: "\u0928\u093E\u092E", taal: "\u0924\u093E\u0932", raag: "\u0930\u093E\u0917", avartan: "\u0906\u0935\u0930\u094D\u0924\u0928", notationBy: "\u0938\u094D\u0935\u0930\u0932\u093F\u092A\u093F\u0915\u093E\u0930" },
|
|
226
|
+
en: { title: "Song", taal: "Taal", raag: "Raag", avartan: "Avartan", notationBy: "Notator" }
|
|
227
227
|
};
|
|
228
228
|
function composeCluster(letter, opts) {
|
|
229
229
|
const classes = [];
|
|
@@ -506,21 +506,24 @@ function renderRow(row, partIdx, rowIdx, ctx) {
|
|
|
506
506
|
return `<div class="sw-row">${label}<div class="sw-grid">${above.join("")}${notation.join("")}${below.join("")}${lyric.join("")}</div></div>`;
|
|
507
507
|
}
|
|
508
508
|
function renderHeader(meta, ctx) {
|
|
509
|
-
|
|
509
|
+
return renderMetaHeader(meta, ctx.lang, ctx.tr);
|
|
510
|
+
}
|
|
511
|
+
function renderMetaHeader(meta, lang, tr = (s) => s) {
|
|
512
|
+
const L = LABELS[lang];
|
|
510
513
|
const rows = [];
|
|
511
514
|
const add = (label, value) => rows.push(
|
|
512
515
|
`<div class="sw-meta-row"><span class="sw-meta-label">${escapeHtml(label)}</span><span class="sw-meta-value">${escapeHtml(value)}</span></div>`
|
|
513
516
|
);
|
|
514
|
-
add(L.title,
|
|
517
|
+
add(L.title, tr(meta.title));
|
|
515
518
|
const taal = meta.taalName ?? meta.taal?.id;
|
|
516
|
-
if (taal !== void 0) add(L.taal,
|
|
517
|
-
if (meta.raag !== void 0) add(L.raag,
|
|
518
|
-
if (meta.avartan !== void 0) add(L.avartan, localizeDigits(String(meta.avartan),
|
|
519
|
-
if (meta.notationBy !== void 0) add(L.notationBy,
|
|
519
|
+
if (taal !== void 0) add(L.taal, tr(taal));
|
|
520
|
+
if (meta.raag !== void 0) add(L.raag, tr(meta.raag));
|
|
521
|
+
if (meta.avartan !== void 0) add(L.avartan, localizeDigits(String(meta.avartan), lang));
|
|
522
|
+
if (meta.notationBy !== void 0) add(L.notationBy, tr(meta.notationBy));
|
|
520
523
|
return `<header class="sw-header">${rows.join("")}</header>`;
|
|
521
524
|
}
|
|
522
525
|
function renderToHtml(doc, opts = {}) {
|
|
523
|
-
const lang = opts.lang
|
|
526
|
+
const lang = opts.lang === "hi" || opts.lang === "en" ? opts.lang : "bn";
|
|
524
527
|
const tr = lang !== "bn" && opts.transliterate ? opts.transliterate : (s) => s;
|
|
525
528
|
const ctx = { lang, marks: MARKS[lang], tr };
|
|
526
529
|
const out = [`<div class="sw-sheet" lang="${lang}">`];
|
|
@@ -538,9 +541,9 @@ function renderToHtml(doc, opts = {}) {
|
|
|
538
541
|
|
|
539
542
|
// src/viewer/styles.ts
|
|
540
543
|
var NOTATION_FONT_URLS = {
|
|
541
|
-
Swarabitan: "https://
|
|
542
|
-
ome_bhatkhande_hindi: "https://
|
|
543
|
-
ome_bhatkhande_english: "https://
|
|
544
|
+
Swarabitan: "https://webfonts-4qq.pages.dev/swarabitan/Swarabitan.ttf",
|
|
545
|
+
ome_bhatkhande_hindi: "https://webfonts-4qq.pages.dev/ome-bhatkhande/OmeBhatkhandeHindi.ttf",
|
|
546
|
+
ome_bhatkhande_english: "https://webfonts-4qq.pages.dev/ome-bhatkhande/OmeBhatkhandeEnglish.ttf"
|
|
544
547
|
};
|
|
545
548
|
NOTATION_FONT_URLS.Swarabitan;
|
|
546
549
|
var FONT_FACES = Object.entries(NOTATION_FONT_URLS).map(
|
|
@@ -690,6 +693,9 @@ ${FONT_FACES}
|
|
|
690
693
|
|
|
691
694
|
/* ---- player sync (P2.3) ---- */
|
|
692
695
|
.sw-hl { background: var(--sw-hl, rgba(255, 196, 64, 0.45)); border-radius: 0.15em; }
|
|
696
|
+
/* Staff notes are SVG <g> \u2014 background doesn't paint there, so recolour the
|
|
697
|
+
glyph fill/stroke instead (abcjs draws note heads/stems as filled paths). */
|
|
698
|
+
.sw-staff .sw-hl, .sw-staff .sw-hl * { fill: var(--sw-hl-note, #d68400); stroke: var(--sw-hl-note, #d68400); }
|
|
693
699
|
|
|
694
700
|
/* ---- element error box ---- */
|
|
695
701
|
.sw-error {
|
|
@@ -705,27 +711,500 @@ ${FONT_FACES}
|
|
|
705
711
|
var SWARALIPI_PRINT_CSS = `
|
|
706
712
|
@page { margin: 16mm; }
|
|
707
713
|
@media print {
|
|
708
|
-
.sw-sheet { -webkit-print-color-adjust: exact; print-color-adjust: exact; color: #000; }
|
|
714
|
+
.sw-sheet, .sw-staff { -webkit-print-color-adjust: exact; print-color-adjust: exact; color: #000; }
|
|
709
715
|
.sw-row { overflow: visible !important; break-inside: avoid; page-break-inside: avoid; }
|
|
710
716
|
.sw-part { break-inside: auto; }
|
|
711
717
|
.sw-part-name, .sw-header { break-after: avoid-page; page-break-after: avoid; }
|
|
712
718
|
.sw-hl { background: none !important; }
|
|
719
|
+
/* Keep each engraved staff system whole across a page break (the abcjs line
|
|
720
|
+
is a <div> wrapping the <svg>, so the break rule must sit on the div). */
|
|
721
|
+
.sw-staff-lines > div { break-inside: avoid; page-break-inside: avoid; }
|
|
722
|
+
.sw-staff-meta { break-after: avoid-page; page-break-after: avoid; }
|
|
713
723
|
}
|
|
714
724
|
`;
|
|
725
|
+
var SWARALIPI_STAFF_CSS = `
|
|
726
|
+
.sw-staff { color: currentColor; }
|
|
727
|
+
.sw-staff-meta { display: flex; gap: 1.25em; align-items: baseline; margin: 0 0 .5em; font-size: .95em; opacity: .85; }
|
|
728
|
+
.sw-staff-instrument { font-weight: 600; }
|
|
729
|
+
.sw-staff-drums { opacity: .75; }
|
|
730
|
+
.sw-staff-tempo { font-variant-numeric: tabular-nums; }
|
|
731
|
+
/* abcjs (oneSvgPerLine) wraps the music into one <div><svg> per system; stack
|
|
732
|
+
them as short, swaralipi-style lines. abcjs sets a fixed pixel height +
|
|
733
|
+
overflow:hidden on each wrapper div \u2014 neutralise it so the viewBox'd SVG can
|
|
734
|
+
scale to the container (and to the print page) instead of being clipped. */
|
|
735
|
+
.sw-staff-lines > div { margin: 0 0 .35em; height: auto !important; overflow: visible !important; }
|
|
736
|
+
/* Fill up to the engraved (staffwidth) size \u2014 shrink to fit a narrow container,
|
|
737
|
+
but never stretch past natural width (abcToSvg pins per-SVG max-width in px),
|
|
738
|
+
else a short last system balloons. */
|
|
739
|
+
.sw-staff-lines svg { display: block; width: 100%; height: auto; }
|
|
740
|
+
.sw-staff-missing { padding: 1em; border: 1px dashed currentColor; border-radius: 6px; opacity: .8; font-size: .9em; }
|
|
741
|
+
.sw-staff-title { font-size: 1.15em; font-weight: 700; }
|
|
742
|
+
.sw-staff-subtitle { opacity: .8; font-size: .95em; margin-top: .15em; }
|
|
743
|
+
`;
|
|
744
|
+
|
|
745
|
+
// src/player/pitch.ts
|
|
746
|
+
var OCTAVE_OFFSET = {
|
|
747
|
+
"ati-mandra": -2,
|
|
748
|
+
mandra: -1,
|
|
749
|
+
madhyam: 0,
|
|
750
|
+
taar: 1,
|
|
751
|
+
"ati-taar": 2
|
|
752
|
+
};
|
|
753
|
+
var SHUDDHA = {
|
|
754
|
+
s: 0,
|
|
755
|
+
r: 2,
|
|
756
|
+
g: 4,
|
|
757
|
+
m: 5,
|
|
758
|
+
p: 7,
|
|
759
|
+
d: 9,
|
|
760
|
+
n: 11
|
|
761
|
+
};
|
|
762
|
+
var SHARP_NAMES = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"];
|
|
763
|
+
var PITCH_CLASS = {
|
|
764
|
+
c: 0,
|
|
765
|
+
"c#": 1,
|
|
766
|
+
db: 1,
|
|
767
|
+
d: 2,
|
|
768
|
+
"d#": 3,
|
|
769
|
+
eb: 3,
|
|
770
|
+
e: 4,
|
|
771
|
+
"e#": 5,
|
|
772
|
+
fb: 4,
|
|
773
|
+
f: 5,
|
|
774
|
+
"f#": 6,
|
|
775
|
+
gb: 6,
|
|
776
|
+
g: 7,
|
|
777
|
+
"g#": 8,
|
|
778
|
+
ab: 8,
|
|
779
|
+
a: 9,
|
|
780
|
+
"a#": 10,
|
|
781
|
+
bb: 10,
|
|
782
|
+
b: 11,
|
|
783
|
+
"b#": 0,
|
|
784
|
+
cb: 11
|
|
785
|
+
};
|
|
786
|
+
function parseTonic(tonic) {
|
|
787
|
+
if (!tonic) return 0;
|
|
788
|
+
const key = tonic.trim().toLowerCase().replace(/s/g, "#");
|
|
789
|
+
return PITCH_CLASS[key] ?? 0;
|
|
790
|
+
}
|
|
791
|
+
function svaraSemitone(note) {
|
|
792
|
+
if (note.svara === void 0) return null;
|
|
793
|
+
const [, letter] = note.svara;
|
|
794
|
+
let semi = SHUDDHA[letter];
|
|
795
|
+
if (note.komal === true || note.microtone !== void 0) semi -= 1;
|
|
796
|
+
if (note.tivra === true) semi += 1;
|
|
797
|
+
return semi;
|
|
798
|
+
}
|
|
799
|
+
function svaraToMidi(note, tonicPc, baseOctave = 4) {
|
|
800
|
+
const semi = svaraSemitone(note);
|
|
801
|
+
if (semi === null || note.svara === void 0) return null;
|
|
802
|
+
const [octave] = note.svara;
|
|
803
|
+
return (baseOctave + 1 + OCTAVE_OFFSET[octave]) * 12 + tonicPc + semi;
|
|
804
|
+
}
|
|
805
|
+
function kanToMidi(svara, tonicPc, baseOctave = 4) {
|
|
806
|
+
if (svara === void 0) return null;
|
|
807
|
+
const [octave, letter] = svara;
|
|
808
|
+
return (baseOctave + 1 + OCTAVE_OFFSET[octave]) * 12 + tonicPc + SHUDDHA[letter];
|
|
809
|
+
}
|
|
810
|
+
function midiToSampleName(midi) {
|
|
811
|
+
const pc = (midi % 12 + 12) % 12;
|
|
812
|
+
const octave = Math.floor(midi / 12) - 1;
|
|
813
|
+
return `${SHARP_NAMES[pc]}${octave}`;
|
|
814
|
+
}
|
|
815
|
+
function sampleFileName(midi) {
|
|
816
|
+
return midiToSampleName(midi).toLowerCase().replace("#", "s");
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
// src/player/schedule.ts
|
|
820
|
+
var isSilent = (n) => n.svara === void 0 && n.rest !== true && n.sustain !== true;
|
|
821
|
+
function buildSchedule(doc, opts = {}) {
|
|
822
|
+
const tonicPc = parseTonic(opts.tonic ?? doc.meta.tonic);
|
|
823
|
+
const baseOctave = opts.baseOctave ?? 4;
|
|
824
|
+
const events = [];
|
|
825
|
+
let cursor = 0;
|
|
826
|
+
let lastPitched = -1;
|
|
827
|
+
doc.parts.forEach((part, p) => {
|
|
828
|
+
part.rows.forEach((row, r) => {
|
|
829
|
+
row.notes.forEach((note, i) => {
|
|
830
|
+
if (note.bar !== void 0 || isSilent(note)) return;
|
|
831
|
+
const path = `${p}.${r}.${i}`;
|
|
832
|
+
const dur = note.durationMatra ?? 1;
|
|
833
|
+
if (note.svara !== void 0) {
|
|
834
|
+
events.push({
|
|
835
|
+
beat: cursor,
|
|
836
|
+
durationBeats: dur,
|
|
837
|
+
midi: svaraToMidi(note, tonicPc, baseOctave),
|
|
838
|
+
kan: kanToMidi(note.kan, tonicPc, baseOctave),
|
|
839
|
+
path,
|
|
840
|
+
kind: note.sustain === true ? "sustain" : "note"
|
|
841
|
+
});
|
|
842
|
+
lastPitched = events.length - 1;
|
|
843
|
+
} else if (note.sustain === true) {
|
|
844
|
+
if (lastPitched >= 0) events[lastPitched].durationBeats += dur;
|
|
845
|
+
events.push({ beat: cursor, durationBeats: dur, midi: null, kan: null, path, kind: "sustain" });
|
|
846
|
+
} else {
|
|
847
|
+
events.push({ beat: cursor, durationBeats: dur, midi: null, kan: null, path, kind: "rest" });
|
|
848
|
+
}
|
|
849
|
+
cursor += dur;
|
|
850
|
+
});
|
|
851
|
+
});
|
|
852
|
+
});
|
|
853
|
+
return { events, totalBeats: cursor };
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
// src/viewer/staff.ts
|
|
857
|
+
init_taals();
|
|
858
|
+
|
|
859
|
+
// src/player/instruments.ts
|
|
860
|
+
init_taals();
|
|
861
|
+
function keyMap(keys) {
|
|
862
|
+
const m = {};
|
|
863
|
+
for (const k of keys) m[k] = `${k.replace("#", "s")}.mp3`;
|
|
864
|
+
return m;
|
|
865
|
+
}
|
|
866
|
+
var PIANO_KEYS = [
|
|
867
|
+
"A0",
|
|
868
|
+
"C1",
|
|
869
|
+
"D#1",
|
|
870
|
+
"F#1",
|
|
871
|
+
"A1",
|
|
872
|
+
"C2",
|
|
873
|
+
"D#2",
|
|
874
|
+
"F#2",
|
|
875
|
+
"A2",
|
|
876
|
+
"C3",
|
|
877
|
+
"D#3",
|
|
878
|
+
"F#3",
|
|
879
|
+
"A3",
|
|
880
|
+
"C4",
|
|
881
|
+
"D#4",
|
|
882
|
+
"F#4",
|
|
883
|
+
"A4",
|
|
884
|
+
"C5",
|
|
885
|
+
"D#5",
|
|
886
|
+
"F#5",
|
|
887
|
+
"A5",
|
|
888
|
+
"C6",
|
|
889
|
+
"D#6",
|
|
890
|
+
"F#6",
|
|
891
|
+
"A6",
|
|
892
|
+
"C7",
|
|
893
|
+
"D#7",
|
|
894
|
+
"F#7",
|
|
895
|
+
"A7",
|
|
896
|
+
"C8"
|
|
897
|
+
];
|
|
898
|
+
var HARMONIUM_KEYS = [
|
|
899
|
+
"C2",
|
|
900
|
+
"C#2",
|
|
901
|
+
"D2",
|
|
902
|
+
"D#2",
|
|
903
|
+
"E2",
|
|
904
|
+
"F2",
|
|
905
|
+
"F#2",
|
|
906
|
+
"G2",
|
|
907
|
+
"G#2",
|
|
908
|
+
"A2",
|
|
909
|
+
"A#2",
|
|
910
|
+
"C3",
|
|
911
|
+
"C#3",
|
|
912
|
+
"D3",
|
|
913
|
+
"D#3",
|
|
914
|
+
"E3",
|
|
915
|
+
"F3",
|
|
916
|
+
"F#3",
|
|
917
|
+
"G3",
|
|
918
|
+
"G#3",
|
|
919
|
+
"A3",
|
|
920
|
+
"A#3",
|
|
921
|
+
"C4",
|
|
922
|
+
"C#4",
|
|
923
|
+
"D4",
|
|
924
|
+
"D#4",
|
|
925
|
+
"E4",
|
|
926
|
+
"F4",
|
|
927
|
+
"F#4",
|
|
928
|
+
"G4",
|
|
929
|
+
"G#4",
|
|
930
|
+
"A4",
|
|
931
|
+
"A#4",
|
|
932
|
+
"C5",
|
|
933
|
+
"C#5",
|
|
934
|
+
"D5"
|
|
935
|
+
];
|
|
936
|
+
var VIOLIN_KEYS = ["A3", "C4", "E4", "G4", "A4", "C5", "E5", "G5", "A5", "C6", "E6", "G6", "A6", "C7"];
|
|
937
|
+
var FLUTE_KEYS = ["C4", "E4", "A4", "C5", "E5", "A5", "C6", "E6", "A6", "C7"];
|
|
938
|
+
({
|
|
939
|
+
piano: { urls: keyMap(PIANO_KEYS)},
|
|
940
|
+
santoor: { urls: santoorUrls()},
|
|
941
|
+
harmonium: { urls: keyMap(HARMONIUM_KEYS)},
|
|
942
|
+
violin: { urls: keyMap(VIOLIN_KEYS)},
|
|
943
|
+
flute: { urls: keyMap(FLUTE_KEYS)}
|
|
944
|
+
});
|
|
945
|
+
new Set(
|
|
946
|
+
Object.keys(TAALS)
|
|
947
|
+
);
|
|
948
|
+
Array.from({ length: 17 }, (_, i) => 60 + i * 15);
|
|
949
|
+
function santoorUrls() {
|
|
950
|
+
const urls = {};
|
|
951
|
+
const add = (midi) => {
|
|
952
|
+
const stem = sampleFileName(midi);
|
|
953
|
+
const name = stem.replace("s", "#").replace(/^(.)/, (c) => c.toUpperCase());
|
|
954
|
+
urls[name] = `${stem}.mp3`;
|
|
955
|
+
};
|
|
956
|
+
for (let midi = 60; midi <= 95; midi++) add(midi);
|
|
957
|
+
add(96);
|
|
958
|
+
return urls;
|
|
959
|
+
}
|
|
960
|
+
function drumPattern(taal) {
|
|
961
|
+
const n = taal.numBeats;
|
|
962
|
+
const sam = taal.sam ?? 0;
|
|
963
|
+
const khaali = new Set(taal.khaali ?? []);
|
|
964
|
+
const bhaags = taal.bhaags ?? [n];
|
|
965
|
+
const pattern = new Array(n).fill("hihat");
|
|
966
|
+
let pos = 0;
|
|
967
|
+
for (const len of bhaags) {
|
|
968
|
+
pattern[pos] = khaali.has(pos) ? "hihat" : "snare";
|
|
969
|
+
pos += len;
|
|
970
|
+
}
|
|
971
|
+
pattern[sam] = "kick";
|
|
972
|
+
return pattern;
|
|
973
|
+
}
|
|
974
|
+
|
|
975
|
+
// src/viewer/staff.ts
|
|
976
|
+
var ABC_SHARP = ["C", "^C", "D", "^D", "E", "F", "^F", "G", "^G", "A", "^A", "B"];
|
|
977
|
+
function midiToAbc(midi) {
|
|
978
|
+
const pc = (midi % 12 + 12) % 12;
|
|
979
|
+
const octave = Math.floor(midi / 12) - 1;
|
|
980
|
+
const token = ABC_SHARP[pc];
|
|
981
|
+
const acc = token[0] === "^" ? "^" : "";
|
|
982
|
+
const letter = acc ? token[1] : token[0];
|
|
983
|
+
return octave >= 5 ? acc + letter.toLowerCase() + "'".repeat(octave - 5) : acc + letter + ",".repeat(4 - octave);
|
|
984
|
+
}
|
|
985
|
+
function abcDuration(beats) {
|
|
986
|
+
if (Math.abs(beats - 1) < 1e-6) return "";
|
|
987
|
+
if (Math.abs(beats - Math.round(beats)) < 1e-6) return String(Math.round(beats));
|
|
988
|
+
const inv = 1 / beats;
|
|
989
|
+
if (Math.abs(inv - Math.round(inv)) < 1e-6) return `/${Math.round(inv)}`;
|
|
990
|
+
const sixteenths = Math.max(1, Math.round(beats * 4));
|
|
991
|
+
return `${sixteenths}/4`;
|
|
992
|
+
}
|
|
993
|
+
function abcNote(ev) {
|
|
994
|
+
const grace = ev.kan !== null ? `{${midiToAbc(ev.kan)}}` : "";
|
|
995
|
+
return `${grace}${midiToAbc(ev.midi)}${abcDuration(ev.durationBeats)}`;
|
|
996
|
+
}
|
|
997
|
+
function eventPaths(schedule) {
|
|
998
|
+
const paths = [];
|
|
999
|
+
for (const ev of schedule.events) {
|
|
1000
|
+
if (ev.midi !== null || ev.kind === "rest") paths.push(ev.path);
|
|
1001
|
+
}
|
|
1002
|
+
return paths;
|
|
1003
|
+
}
|
|
1004
|
+
function abcText(s) {
|
|
1005
|
+
return s.replace(/[\r\n]+/g, " ").trim();
|
|
1006
|
+
}
|
|
1007
|
+
function buildAbc(schedule, lyricOf, opts) {
|
|
1008
|
+
const beatsPerBar = opts.beatsPerBar > 0 ? opts.beatsPerBar : 4;
|
|
1009
|
+
const tokens = [];
|
|
1010
|
+
const words = [];
|
|
1011
|
+
let barPos = 0;
|
|
1012
|
+
const EPS2 = 1e-6;
|
|
1013
|
+
const advance = (dur) => {
|
|
1014
|
+
barPos += dur;
|
|
1015
|
+
while (barPos >= beatsPerBar - EPS2) {
|
|
1016
|
+
tokens.push("|");
|
|
1017
|
+
words.push("|");
|
|
1018
|
+
barPos -= beatsPerBar;
|
|
1019
|
+
}
|
|
1020
|
+
};
|
|
1021
|
+
for (const ev of schedule.events) {
|
|
1022
|
+
if (ev.midi === null) {
|
|
1023
|
+
if (ev.kind === "rest") {
|
|
1024
|
+
tokens.push(`z${abcDuration(ev.durationBeats)}`);
|
|
1025
|
+
words.push("*");
|
|
1026
|
+
advance(ev.durationBeats);
|
|
1027
|
+
}
|
|
1028
|
+
continue;
|
|
1029
|
+
}
|
|
1030
|
+
tokens.push(abcNote(ev));
|
|
1031
|
+
const lyr = lyricOf(ev);
|
|
1032
|
+
words.push(lyr ? abcText(lyr).replace(/\s+/g, "~") : "*");
|
|
1033
|
+
advance(ev.durationBeats);
|
|
1034
|
+
}
|
|
1035
|
+
if (tokens.length && tokens[tokens.length - 1] !== "|") tokens.push("|]");
|
|
1036
|
+
else if (tokens.length) tokens[tokens.length - 1] = "|]";
|
|
1037
|
+
const meter = ratioMeter(beatsPerBar);
|
|
1038
|
+
const head = ["X:1", `M:${meter}`, "L:1/4", `Q:1/4=${Math.round(opts.bpm)}`];
|
|
1039
|
+
if (opts.drums) head.push(...percMapLines(opts.drums));
|
|
1040
|
+
head.push("K:C treble");
|
|
1041
|
+
const melodyBody = tokens.length ? tokens.join(" ") : "z |]";
|
|
1042
|
+
const lines = [...head];
|
|
1043
|
+
if (opts.drums) {
|
|
1044
|
+
lines.push("V:1", melodyBody);
|
|
1045
|
+
if (opts.lyrics && words.some((w) => w !== "*" && w !== "|")) lines.push(`w: ${words.join(" ")}`);
|
|
1046
|
+
lines.push("V:2 clef=perc stem=up", buildDrumVoice(schedule.totalBeats, beatsPerBar, opts.drums));
|
|
1047
|
+
} else {
|
|
1048
|
+
lines.push(melodyBody);
|
|
1049
|
+
if (opts.lyrics && words.some((w) => w !== "*" && w !== "|")) lines.push(`w: ${words.join(" ")}`);
|
|
1050
|
+
}
|
|
1051
|
+
return lines.join("\n");
|
|
1052
|
+
}
|
|
1053
|
+
function ratioMeter(beats) {
|
|
1054
|
+
return `${Math.max(1, Math.round(beats))}/4`;
|
|
1055
|
+
}
|
|
1056
|
+
var DRUM_ABC = {
|
|
1057
|
+
kick: { note: "F,", gm: "bass-drum-1" },
|
|
1058
|
+
snare: { note: "C", gm: "acoustic-snare" },
|
|
1059
|
+
hihat: { note: "g", gm: "closed-hi-hat" },
|
|
1060
|
+
tom1: { note: "E", gm: "high-tom" },
|
|
1061
|
+
tom2: { note: "A,", gm: "low-mid-tom" },
|
|
1062
|
+
tom3: { note: "D,", gm: "low-floor-tom" }
|
|
1063
|
+
};
|
|
1064
|
+
function percMapLines(voices) {
|
|
1065
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1066
|
+
const lines = [];
|
|
1067
|
+
for (const v of voices) {
|
|
1068
|
+
if (seen.has(v)) continue;
|
|
1069
|
+
seen.add(v);
|
|
1070
|
+
const { note, gm } = DRUM_ABC[v];
|
|
1071
|
+
lines.push(`%%percmap ${note} ${gm}`);
|
|
1072
|
+
}
|
|
1073
|
+
return lines;
|
|
1074
|
+
}
|
|
1075
|
+
function buildDrumVoice(totalBeats, beatsPerBar, pattern) {
|
|
1076
|
+
const n = Math.max(1, Math.ceil(totalBeats));
|
|
1077
|
+
const tokens = [];
|
|
1078
|
+
for (let beat = 0; beat < n; beat++) {
|
|
1079
|
+
tokens.push(DRUM_ABC[pattern[beat % pattern.length]].note);
|
|
1080
|
+
if ((beat + 1) % beatsPerBar === 0) tokens.push("|");
|
|
1081
|
+
}
|
|
1082
|
+
if (tokens.length === 0 || tokens[tokens.length - 1] !== "|") tokens.push("|]");
|
|
1083
|
+
else tokens[tokens.length - 1] = "|]";
|
|
1084
|
+
return tokens.join(" ");
|
|
1085
|
+
}
|
|
1086
|
+
function lyricLookup(doc) {
|
|
1087
|
+
return (ev) => {
|
|
1088
|
+
const [p, r, i] = ev.path.split(".").map(Number);
|
|
1089
|
+
return doc.parts[p]?.rows[r]?.notes[i]?.lyric;
|
|
1090
|
+
};
|
|
1091
|
+
}
|
|
1092
|
+
function resolveDrumTaal(doc) {
|
|
1093
|
+
const id = doc.meta.taal?.id;
|
|
1094
|
+
return id !== void 0 && id in TAALS ? TAALS[id] : { numBeats: 4, sam: 0 };
|
|
1095
|
+
}
|
|
1096
|
+
function docToAbc(doc, opts = {}) {
|
|
1097
|
+
const schedule = buildSchedule(doc, { tonic: opts.tonic, baseOctave: opts.baseOctave });
|
|
1098
|
+
const bpm = opts.bpm ?? doc.meta.bpm ?? 90;
|
|
1099
|
+
const beatsPerBar = opts.beatsPerBar ?? doc.meta.taal?.numBeats ?? 4;
|
|
1100
|
+
const drums = opts.drums ? drumPattern(resolveDrumTaal(doc)) : void 0;
|
|
1101
|
+
return buildAbc(schedule, lyricLookup(doc), { bpm, lyrics: opts.lyrics !== false, beatsPerBar, drums });
|
|
1102
|
+
}
|
|
1103
|
+
async function abcToSvg(abc, opts = {}, notePaths) {
|
|
1104
|
+
if (typeof document === "undefined") {
|
|
1105
|
+
throw new Error("abcToSvg requires a DOM; render staff notation in the browser or print iframe");
|
|
1106
|
+
}
|
|
1107
|
+
let ABCJS;
|
|
1108
|
+
try {
|
|
1109
|
+
const mod = await import('abcjs');
|
|
1110
|
+
ABCJS = mod.default ?? mod;
|
|
1111
|
+
} catch {
|
|
1112
|
+
return `<div class="sw-staff-missing">Staff notation needs the optional <code>abcjs</code> package.</div>`;
|
|
1113
|
+
}
|
|
1114
|
+
const host = document.createElement("div");
|
|
1115
|
+
host.style.cssText = "position:fixed; left:-10000px; top:0; width:720px; visibility:hidden;";
|
|
1116
|
+
const mount = document.body ?? document.documentElement;
|
|
1117
|
+
mount.appendChild(host);
|
|
1118
|
+
try {
|
|
1119
|
+
ABCJS.renderAbc(host, abc, {
|
|
1120
|
+
add_classes: true,
|
|
1121
|
+
staffwidth: opts.staffwidth ?? 680,
|
|
1122
|
+
scale: opts.scale ?? 1,
|
|
1123
|
+
// Reflow into short lines. staffwidth is the width budget;
|
|
1124
|
+
// preferredMeasuresPerLine keeps systems swaralipi-short.
|
|
1125
|
+
// (Not `responsive: resize` — its absolute-positioned aspect-ratio wrapper
|
|
1126
|
+
// overlaps the header and mis-sizes on the print page.)
|
|
1127
|
+
wrap: { minSpacing: 1.8, maxSpacing: 2.7, preferredMeasuresPerLine: opts.measuresPerLine ?? 4 },
|
|
1128
|
+
// CRUCIAL: put each wrapped system in its OWN <svg> (default is all systems
|
|
1129
|
+
// stacked in one tall SVG, which is atomic and can't page-break — that was
|
|
1130
|
+
// the near-blank-first-page / mid-staff-cutoff print bug). One SVG per line
|
|
1131
|
+
// lets `break-inside: avoid` keep each staff whole while pages fill.
|
|
1132
|
+
oneSvgPerLine: true
|
|
1133
|
+
});
|
|
1134
|
+
for (const svg of host.querySelectorAll("svg")) {
|
|
1135
|
+
const w = parseFloat(svg.getAttribute("width") ?? "");
|
|
1136
|
+
const h = parseFloat(svg.getAttribute("height") ?? "");
|
|
1137
|
+
if (w > 0 && h > 0) {
|
|
1138
|
+
if (!svg.getAttribute("viewBox")) svg.setAttribute("viewBox", `0 0 ${w} ${h}`);
|
|
1139
|
+
svg.setAttribute("preserveAspectRatio", "xMinYMin meet");
|
|
1140
|
+
svg.removeAttribute("width");
|
|
1141
|
+
svg.removeAttribute("height");
|
|
1142
|
+
svg.setAttribute("style", `max-width:${w}px`);
|
|
1143
|
+
}
|
|
1144
|
+
}
|
|
1145
|
+
if (notePaths) {
|
|
1146
|
+
const melody = host.querySelectorAll(".abcjs-v0.abcjs-note, .abcjs-v0.abcjs-rest");
|
|
1147
|
+
let i = 0;
|
|
1148
|
+
for (const el of melody) {
|
|
1149
|
+
const path = notePaths[i++];
|
|
1150
|
+
if (path !== void 0) el.setAttribute("data-note", path);
|
|
1151
|
+
}
|
|
1152
|
+
}
|
|
1153
|
+
return host.innerHTML;
|
|
1154
|
+
} finally {
|
|
1155
|
+
host.remove();
|
|
1156
|
+
}
|
|
1157
|
+
}
|
|
1158
|
+
async function renderStaffHtml(doc, opts = {}) {
|
|
1159
|
+
const bpm = opts.bpm ?? doc.meta.bpm ?? 90;
|
|
1160
|
+
const abc = docToAbc(doc, { ...opts, bpm });
|
|
1161
|
+
const schedule = buildSchedule(doc, { tonic: opts.tonic, baseOctave: opts.baseOctave });
|
|
1162
|
+
const engraved = await abcToSvg(abc, opts, eventPaths(schedule));
|
|
1163
|
+
const lines = engraved.includes("sw-staff-missing") ? engraved : `<div class="sw-staff-lines">${engraved}</div>`;
|
|
1164
|
+
const header = opts.showHeader === false ? "" : renderMetaHeader(doc.meta, opts.headerLang ?? "en", opts.transliterate);
|
|
1165
|
+
const metaParts = [];
|
|
1166
|
+
if (opts.instrument) metaParts.push(`<span class="sw-staff-instrument">${escapeAttr(opts.instrument)}</span>`);
|
|
1167
|
+
if (opts.drums) metaParts.push(`<span class="sw-staff-drums">+ drums</span>`);
|
|
1168
|
+
const meta = metaParts.length ? `<div class="sw-staff-meta">${metaParts.join("")}</div>` : "";
|
|
1169
|
+
return `<div class="sw-staff">${header}${meta}${lines}</div>`;
|
|
1170
|
+
}
|
|
1171
|
+
function escapeAttr(s) {
|
|
1172
|
+
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
1173
|
+
}
|
|
715
1174
|
|
|
716
1175
|
// src/viewer/print.ts
|
|
1176
|
+
var DEFAULT_WATERMARK = "www.gitabitan.io";
|
|
1177
|
+
var DEFAULT_NOTATOR = "gitabitan.io Team";
|
|
717
1178
|
function escapeHtml2(s) {
|
|
718
1179
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
719
1180
|
}
|
|
720
|
-
function
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
1181
|
+
function watermarkCss(text) {
|
|
1182
|
+
if (!text) return "";
|
|
1183
|
+
return `
|
|
1184
|
+
.sw-watermark {
|
|
1185
|
+
position: fixed; inset: 0; z-index: 0; pointer-events: none;
|
|
1186
|
+
display: flex; align-items: center; justify-content: center;
|
|
1187
|
+
overflow: hidden;
|
|
1188
|
+
-webkit-print-color-adjust: exact; print-color-adjust: exact;
|
|
1189
|
+
}
|
|
1190
|
+
.sw-watermark span {
|
|
1191
|
+
font-size: 11vw; font-weight: 700; letter-spacing: .08em;
|
|
1192
|
+
color: rgba(0,0,0,0.07); transform: rotate(-35deg); white-space: nowrap;
|
|
1193
|
+
}
|
|
1194
|
+
body > .sw-sheet, body > .sw-footer { position: relative; z-index: 1; }
|
|
1195
|
+
`;
|
|
1196
|
+
}
|
|
1197
|
+
function chrome(text, notator) {
|
|
1198
|
+
const top = text ? `<div class="sw-watermark" aria-hidden="true"><span>${escapeHtml2(text)}</span></div>` : "";
|
|
1199
|
+
const bottom = notator ? `<footer class="sw-footer">${escapeHtml2(notator)}</footer>` : "";
|
|
1200
|
+
return { top, bottom };
|
|
1201
|
+
}
|
|
1202
|
+
function resolveNotator(doc, opts) {
|
|
1203
|
+
return doc.meta.notationBy ?? opts.notator ?? DEFAULT_NOTATOR;
|
|
1204
|
+
}
|
|
1205
|
+
function pageHtml(lang, title, bodyHtml, opts, doc) {
|
|
1206
|
+
const watermark = opts.watermark ?? DEFAULT_WATERMARK;
|
|
1207
|
+
const { top, bottom } = chrome(watermark, resolveNotator(doc, opts));
|
|
729
1208
|
return `<!doctype html>
|
|
730
1209
|
<html lang="${escapeHtml2(lang)}">
|
|
731
1210
|
<head>
|
|
@@ -734,20 +1213,42 @@ function renderPrintDocument(doc, opts = {}) {
|
|
|
734
1213
|
<title>${escapeHtml2(title)}</title>
|
|
735
1214
|
<style>
|
|
736
1215
|
${SWARALIPI_CSS}
|
|
1216
|
+
${SWARALIPI_STAFF_CSS}
|
|
737
1217
|
${SWARALIPI_PRINT_CSS}
|
|
1218
|
+
${watermarkCss(watermark)}
|
|
738
1219
|
html, body { margin: 0; }
|
|
739
1220
|
body { color: #111; background: #fff; padding: 16px; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
|
|
740
1221
|
.sw-sheet { max-width: 100%; }
|
|
1222
|
+
.sw-footer { margin-top: 12px; padding-top: 6px; border-top: 1px solid #ddd; font-size: 12px; color: #555; text-align: right; }
|
|
741
1223
|
</style>
|
|
742
1224
|
</head>
|
|
743
|
-
<body>${
|
|
1225
|
+
<body>${top}${bodyHtml}${bottom}</body>
|
|
744
1226
|
</html>`;
|
|
745
1227
|
}
|
|
1228
|
+
function renderPrintDocument(doc, opts = {}) {
|
|
1229
|
+
const lang = opts.lang === "staff" ? "bn" : opts.lang ?? "bn";
|
|
1230
|
+
const tr = lang !== "bn" && opts.transliterate ? opts.transliterate : (s) => s;
|
|
1231
|
+
const title = opts.title ?? tr(doc.meta.title);
|
|
1232
|
+
const body = renderToHtml(doc, { lang, showHeader: opts.showHeader, transliterate: opts.transliterate });
|
|
1233
|
+
return pageHtml(lang, title, body, opts, doc);
|
|
1234
|
+
}
|
|
1235
|
+
async function renderStaffPrintDocument(doc, opts = {}) {
|
|
1236
|
+
if (opts.lang !== "staff") return renderPrintDocument(doc, opts);
|
|
1237
|
+
const title = opts.title ?? doc.meta.title;
|
|
1238
|
+
const staff = await renderStaffHtml(doc, opts);
|
|
1239
|
+
return pageHtml("en", title, staff, opts, doc);
|
|
1240
|
+
}
|
|
746
1241
|
function printSwaralipi(doc, opts = {}) {
|
|
747
1242
|
if (typeof document === "undefined") {
|
|
748
1243
|
throw new Error("printSwaralipi requires a DOM; use renderPrintDocument() for server-side PDF");
|
|
749
1244
|
}
|
|
750
|
-
|
|
1245
|
+
if (opts.lang === "staff") {
|
|
1246
|
+
void renderStaffPrintDocument(doc, opts).then(printHtmlInIframe);
|
|
1247
|
+
} else {
|
|
1248
|
+
printHtmlInIframe(renderPrintDocument(doc, opts));
|
|
1249
|
+
}
|
|
1250
|
+
}
|
|
1251
|
+
function printHtmlInIframe(html) {
|
|
751
1252
|
const iframe = document.createElement("iframe");
|
|
752
1253
|
iframe.setAttribute("aria-hidden", "true");
|
|
753
1254
|
iframe.style.cssText = "position:fixed; left:-10000px; top:0; width:800px; height:600px; border:0;";
|
|
@@ -789,7 +1290,7 @@ var TARGET = {
|
|
|
789
1290
|
en: "iast"
|
|
790
1291
|
};
|
|
791
1292
|
async function loadLyricTransliterator(lang) {
|
|
792
|
-
if (lang === "bn") return void 0;
|
|
1293
|
+
if (lang === "bn" || lang === "staff") return void 0;
|
|
793
1294
|
const mod = await import('@indic-transliteration/sanscript');
|
|
794
1295
|
const sanscript = mod.default ?? mod;
|
|
795
1296
|
const target = TARGET[lang];
|
|
@@ -797,7 +1298,7 @@ async function loadLyricTransliterator(lang) {
|
|
|
797
1298
|
}
|
|
798
1299
|
|
|
799
1300
|
// src/viewer/element.ts
|
|
800
|
-
var LANGS = /* @__PURE__ */ new Set(["bn", "hi", "en"]);
|
|
1301
|
+
var LANGS = /* @__PURE__ */ new Set(["bn", "hi", "en", "staff"]);
|
|
801
1302
|
function ensureNotationFonts() {
|
|
802
1303
|
if (typeof FontFace === "undefined" || typeof document === "undefined") return;
|
|
803
1304
|
const present = /* @__PURE__ */ new Set();
|
|
@@ -817,6 +1318,8 @@ function createElementClass() {
|
|
|
817
1318
|
#abort;
|
|
818
1319
|
#translit;
|
|
819
1320
|
#translitLang;
|
|
1321
|
+
#renderSeq = 0;
|
|
1322
|
+
#staffOptions = {};
|
|
820
1323
|
validate = false;
|
|
821
1324
|
constructor() {
|
|
822
1325
|
super();
|
|
@@ -824,7 +1327,7 @@ function createElementClass() {
|
|
|
824
1327
|
if (typeof CSSStyleSheet !== "undefined" && "replaceSync" in CSSStyleSheet.prototype && "adoptedStyleSheets" in this.#root) {
|
|
825
1328
|
if (!sharedSheet) {
|
|
826
1329
|
sharedSheet = new CSSStyleSheet();
|
|
827
|
-
sharedSheet.replaceSync(SWARALIPI_CSS);
|
|
1330
|
+
sharedSheet.replaceSync(SWARALIPI_CSS + SWARALIPI_STAFF_CSS);
|
|
828
1331
|
}
|
|
829
1332
|
this.#root.adoptedStyleSheets = [...this.#root.adoptedStyleSheets, sharedSheet];
|
|
830
1333
|
this.#adopted = true;
|
|
@@ -843,6 +1346,13 @@ function createElementClass() {
|
|
|
843
1346
|
}
|
|
844
1347
|
this.#render();
|
|
845
1348
|
}
|
|
1349
|
+
get staffOptions() {
|
|
1350
|
+
return this.#staffOptions;
|
|
1351
|
+
}
|
|
1352
|
+
set staffOptions(value) {
|
|
1353
|
+
this.#staffOptions = value;
|
|
1354
|
+
if (this.#lang === "staff") this.#render();
|
|
1355
|
+
}
|
|
846
1356
|
get #lang() {
|
|
847
1357
|
const attr = this.getAttribute("lang");
|
|
848
1358
|
return attr !== null && LANGS.has(attr) ? attr : "bn";
|
|
@@ -889,14 +1399,22 @@ function createElementClass() {
|
|
|
889
1399
|
}).catch(() => void 0);
|
|
890
1400
|
}
|
|
891
1401
|
#styleFallback() {
|
|
892
|
-
return this.#adopted ? "" : `<style>${SWARALIPI_CSS}</style>`;
|
|
1402
|
+
return this.#adopted ? "" : `<style>${SWARALIPI_CSS}${SWARALIPI_STAFF_CSS}</style>`;
|
|
893
1403
|
}
|
|
894
1404
|
#render() {
|
|
1405
|
+
const seq = ++this.#renderSeq;
|
|
895
1406
|
if (this.#doc === void 0) {
|
|
896
1407
|
this.#root.innerHTML = this.#styleFallback();
|
|
897
1408
|
return;
|
|
898
1409
|
}
|
|
899
1410
|
const lang = this.#lang;
|
|
1411
|
+
if (lang === "staff") {
|
|
1412
|
+
const doc = this.#doc;
|
|
1413
|
+
void renderStaffHtml(doc, this.staffOptions).then((html2) => {
|
|
1414
|
+
if (seq === this.#renderSeq) this.#root.innerHTML = this.#styleFallback() + html2;
|
|
1415
|
+
}).catch(() => void 0);
|
|
1416
|
+
return;
|
|
1417
|
+
}
|
|
900
1418
|
const html = renderToHtml(this.#doc, {
|
|
901
1419
|
lang,
|
|
902
1420
|
showHeader: !this.hasAttribute("hide-header"),
|
|
@@ -927,6 +1445,7 @@ function createElementClass() {
|
|
|
927
1445
|
lang,
|
|
928
1446
|
showHeader: !this.hasAttribute("hide-header"),
|
|
929
1447
|
transliterate: this.#translitLang === lang ? this.#translit : void 0,
|
|
1448
|
+
...lang === "staff" ? this.staffOptions : {},
|
|
930
1449
|
...options
|
|
931
1450
|
});
|
|
932
1451
|
}
|
|
@@ -946,19 +1465,30 @@ function defineSwaralipiSheet(tagName = "swaralipi-sheet") {
|
|
|
946
1465
|
return ctor;
|
|
947
1466
|
}
|
|
948
1467
|
|
|
1468
|
+
exports.DEFAULT_NOTATOR = DEFAULT_NOTATOR;
|
|
1469
|
+
exports.DEFAULT_WATERMARK = DEFAULT_WATERMARK;
|
|
949
1470
|
exports.DIGITS = DIGITS;
|
|
950
1471
|
exports.LABELS = LABELS;
|
|
951
1472
|
exports.MARKS = MARKS;
|
|
952
1473
|
exports.NOTATION_FONT_URLS = NOTATION_FONT_URLS;
|
|
953
1474
|
exports.SWARALIPI_CSS = SWARALIPI_CSS;
|
|
954
1475
|
exports.SWARALIPI_PRINT_CSS = SWARALIPI_PRINT_CSS;
|
|
1476
|
+
exports.SWARALIPI_STAFF_CSS = SWARALIPI_STAFF_CSS;
|
|
1477
|
+
exports.abcDuration = abcDuration;
|
|
1478
|
+
exports.abcToSvg = abcToSvg;
|
|
1479
|
+
exports.buildAbc = buildAbc;
|
|
955
1480
|
exports.composeCluster = composeCluster;
|
|
956
1481
|
exports.defineSwaralipiSheet = defineSwaralipiSheet;
|
|
1482
|
+
exports.docToAbc = docToAbc;
|
|
957
1483
|
exports.groupRowIntoCells = groupRowIntoCells;
|
|
958
1484
|
exports.loadLyricTransliterator = loadLyricTransliterator;
|
|
959
1485
|
exports.localizeDigits = localizeDigits;
|
|
1486
|
+
exports.midiToAbc = midiToAbc;
|
|
960
1487
|
exports.printSwaralipi = printSwaralipi;
|
|
1488
|
+
exports.renderMetaHeader = renderMetaHeader;
|
|
961
1489
|
exports.renderPrintDocument = renderPrintDocument;
|
|
1490
|
+
exports.renderStaffHtml = renderStaffHtml;
|
|
1491
|
+
exports.renderStaffPrintDocument = renderStaffPrintDocument;
|
|
962
1492
|
exports.renderToHtml = renderToHtml;
|
|
963
1493
|
exports.resolveArcs = resolveArcs;
|
|
964
1494
|
//# sourceMappingURL=index.cjs.map
|