vector-score 1.0.3 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -2
- package/dist/classes/MusicStaff.d.ts +2 -0
- package/dist/helpers/keySignatures.d.ts +9 -0
- package/dist/helpers/notehelpers.d.ts +1 -2
- package/dist/strategies/GrandStaffStrategy.d.ts +3 -1
- package/dist/strategies/SingleStaffStrategy.d.ts +2 -1
- package/dist/strategies/StrategyInterface.d.ts +2 -1
- package/dist/types.d.ts +5 -0
- package/dist/vector-score.js +257 -194
- package/dist/vector-score.umd.cjs +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
# Vector Score
|
|
4
4
|

|
|
5
5
|
[](https://bundlephobia.com/package/vector-score)
|
|
6
|
+

|
|
6
7
|
|
|
7
8
|
A lightweight, SVG-based TypeScript library for rendering musical staves, notes, and rhythm patterns in the browser.
|
|
8
9
|
|
|
@@ -58,7 +59,8 @@ const staff = new MusicStaff(container, {
|
|
|
58
59
|
staffType: 'treble', // 'treble', 'bass', 'alto', or 'grand'
|
|
59
60
|
width: 400,
|
|
60
61
|
scale: 1.2,
|
|
61
|
-
spaceBelow: 1
|
|
62
|
+
spaceBelow: 1,
|
|
63
|
+
keySignature: "Bb"
|
|
62
64
|
});
|
|
63
65
|
|
|
64
66
|
// Draw a C Minor scale (quarter notes)
|
|
@@ -226,10 +228,11 @@ Notes are defined using a specific string format parsed by the library:
|
|
|
226
228
|
### MusicStaffOptions
|
|
227
229
|
* `width`: Total width of the SVG in pixels.
|
|
228
230
|
* `scale`: Zoom factor (default: 1).
|
|
229
|
-
* `noteStartX`: Position where notes start to draw.
|
|
230
231
|
* `staffType`: `'treble' | 'bass' | 'alto' | 'grand'`.
|
|
232
|
+
* `keySignature`: Change key signature to display on the staff.
|
|
231
233
|
* `spaceAbove`: Padding units above the staff (in staff line spaces).
|
|
232
234
|
* `spaceBelow`: Padding units below the staff (in staff line spaces).
|
|
235
|
+
* `noteStartX`: Position where notes start to draw.
|
|
233
236
|
* `staffColor`: CSS color string for lines and notes.
|
|
234
237
|
* `staffBackgroundColor`: CSS color string for background.
|
|
235
238
|
|
|
@@ -4,6 +4,7 @@ export type MusicStaffOptions = {
|
|
|
4
4
|
scale?: number;
|
|
5
5
|
noteStartX?: number;
|
|
6
6
|
staffType?: StaffTypes;
|
|
7
|
+
keySignature?: string;
|
|
7
8
|
spaceAbove?: number;
|
|
8
9
|
spaceBelow?: number;
|
|
9
10
|
staffColor?: string;
|
|
@@ -24,6 +25,7 @@ export default class MusicStaff {
|
|
|
24
25
|
* @param options - Optional configuration settings. Can adjust staff type (treble, bass, alto, grand), width, scale, spaces above/below, etc. All config options are in the type MusicStaffOptions
|
|
25
26
|
*/
|
|
26
27
|
constructor(rootElementCtx: HTMLElement, options?: MusicStaffOptions);
|
|
28
|
+
private createKeySignature;
|
|
27
29
|
/**
|
|
28
30
|
* Draws a note on the staff.
|
|
29
31
|
* @param notes - A single string OR array of note strings in the format `[Root][Accidental?][Octave][Duration?]`.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { default as SVGRenderer } from '../classes/SVGRenderer';
|
|
2
|
+
import { StaffStrategy } from '../strategies/StrategyInterface';
|
|
3
|
+
import { AccidentalType, KeySignatureDef, NoteNames, StaffTypes } from '../types';
|
|
4
|
+
export declare const KEY_SIGNATURE_START_X = 40;
|
|
5
|
+
export declare const KEY_SIGNATURE_ORDER: Record<AccidentalType, NoteNames[]>;
|
|
6
|
+
export declare const KEY_SIGNATURES: Record<string, KeySignatureDef>;
|
|
7
|
+
export declare const KEY_SIG_OCTAVES: Record<StaffTypes, Record<AccidentalType, number[]>>;
|
|
8
|
+
export declare function parseKeySignature(key: string): KeySignatureDef;
|
|
9
|
+
export declare function drawKeySignature(svgRenderer: SVGRenderer, strategy: StaffStrategy, key: string, startX: number): number;
|
|
@@ -4,6 +4,5 @@ export declare function parseNoteString(noteString: string): NoteObj;
|
|
|
4
4
|
export declare function parseDurationNoteString(note: string): Durations;
|
|
5
5
|
export declare function parseRestString(rest: string): Durations;
|
|
6
6
|
export declare function getGlyphNameByClef(clef: string): GlyphNames;
|
|
7
|
-
export declare function getNoteSpacingFromReference(referenceNote: NoteObj, targetNote: NoteObj): number;
|
|
8
7
|
export declare function noteToAbsoluteSemitone(note: NoteObj): number;
|
|
9
|
-
export declare function
|
|
8
|
+
export declare function getNoteSpacingFromReference(referenceNote: Pick<NoteObj, "name" | "octave">, targetNote: Pick<NoteObj, "name" | "octave">): number;
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import { default as SVGRenderer } from '../classes/SVGRenderer';
|
|
2
|
-
import { NoteObj, StaffTypes } from '../types';
|
|
2
|
+
import { AccidentalType, NoteObj, StaffTypes } from '../types';
|
|
3
3
|
import { LedgerLineEntry, StaffStrategy } from './StrategyInterface';
|
|
4
4
|
export default class GrandStaffStrategy implements StaffStrategy {
|
|
5
5
|
private params;
|
|
6
6
|
private rendererRef;
|
|
7
7
|
private width;
|
|
8
|
+
private trebleStaffHeight;
|
|
8
9
|
constructor(rendererRef: SVGRenderer, staffType: StaffTypes);
|
|
9
10
|
private drawStaffLines;
|
|
10
11
|
drawStaff: (width: number) => void;
|
|
11
12
|
shouldNoteFlip(noteYPos: number): boolean;
|
|
12
13
|
getLedgerLinesX(note: Omit<NoteObj, "accidental">, yPos: number): LedgerLineEntry[];
|
|
13
14
|
calculateNoteYPos: (note: Omit<NoteObj, "accidental">) => number;
|
|
15
|
+
getKeySignatureYPositions(type: AccidentalType, count: number): number[][];
|
|
14
16
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { default as SVGRenderer } from '../classes/SVGRenderer';
|
|
2
|
-
import { NoteObj, StaffTypes } from '../types';
|
|
2
|
+
import { AccidentalType, NoteObj, StaffTypes } from '../types';
|
|
3
3
|
import { LedgerLineEntry, StaffStrategy } from './StrategyInterface';
|
|
4
4
|
export default class SingleStaffStrategy implements StaffStrategy {
|
|
5
5
|
private params;
|
|
@@ -9,4 +9,5 @@ export default class SingleStaffStrategy implements StaffStrategy {
|
|
|
9
9
|
shouldNoteFlip(noteYPos: number): boolean;
|
|
10
10
|
getLedgerLinesX(note: Omit<NoteObj, "accidental">, yPos: number): LedgerLineEntry[];
|
|
11
11
|
calculateNoteYPos: (note: Omit<NoteObj, "accidental">) => number;
|
|
12
|
+
getKeySignatureYPositions(type: AccidentalType, count: number): number[][];
|
|
12
13
|
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { NoteObj, StaffTypes } from '../types';
|
|
1
|
+
import { AccidentalType, NoteObj, StaffTypes } from '../types';
|
|
2
2
|
export interface StaffStrategy {
|
|
3
3
|
drawStaff(width: number): void;
|
|
4
4
|
calculateNoteYPos(note: Omit<NoteObj, "accidental">): number;
|
|
5
5
|
getLedgerLinesX(note: Omit<NoteObj, "accidental">, yPos: number): LedgerLineEntry[];
|
|
6
6
|
shouldNoteFlip(noteYPos: number): boolean;
|
|
7
|
+
getKeySignatureYPositions(type: AccidentalType, count: number): number[][];
|
|
7
8
|
}
|
|
8
9
|
export type StaffParams = {
|
|
9
10
|
staffType: StaffTypes;
|
package/dist/types.d.ts
CHANGED
|
@@ -9,3 +9,8 @@ export type NoteNames = 'C' | 'D' | 'E' | 'F' | 'G' | 'A' | 'B';
|
|
|
9
9
|
export type Durations = 'w' | 'h' | 'q' | 'e' | 's';
|
|
10
10
|
export type Accidentals = '#' | 'b' | '##' | 'bb' | 'n';
|
|
11
11
|
export type DurationsBeatValues = 4 | 2 | 1 | 0.5;
|
|
12
|
+
export type AccidentalType = "sharp" | "flat";
|
|
13
|
+
export type KeySignatureDef = {
|
|
14
|
+
type: AccidentalType;
|
|
15
|
+
count: number;
|
|
16
|
+
};
|
package/dist/vector-score.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const
|
|
1
|
+
const I = {
|
|
2
2
|
treble: {
|
|
3
3
|
staffType: "treble",
|
|
4
4
|
paddingTop: 13,
|
|
@@ -31,13 +31,66 @@ const B = {
|
|
|
31
31
|
topLineYPos: 0,
|
|
32
32
|
bottomLineYPos: 110
|
|
33
33
|
}
|
|
34
|
-
},
|
|
34
|
+
}, E = {
|
|
35
35
|
w: 4,
|
|
36
36
|
h: 2,
|
|
37
37
|
q: 1,
|
|
38
38
|
e: 0.5,
|
|
39
39
|
s: 0.25
|
|
40
|
-
}, X = {
|
|
40
|
+
}, w = 8, M = 40, X = {
|
|
41
|
+
sharp: ["F", "C", "G", "D", "A", "E", "B"],
|
|
42
|
+
flat: ["B", "E", "A", "D", "G", "C", "F"]
|
|
43
|
+
}, G = {
|
|
44
|
+
C: { type: "sharp", count: 0 },
|
|
45
|
+
G: { type: "sharp", count: 1 },
|
|
46
|
+
D: { type: "sharp", count: 2 },
|
|
47
|
+
A: { type: "sharp", count: 3 },
|
|
48
|
+
E: { type: "sharp", count: 4 },
|
|
49
|
+
B: { type: "sharp", count: 5 },
|
|
50
|
+
"F#": { type: "sharp", count: 6 },
|
|
51
|
+
F: { type: "flat", count: 1 },
|
|
52
|
+
Bb: { type: "flat", count: 2 },
|
|
53
|
+
Eb: { type: "flat", count: 3 },
|
|
54
|
+
Ab: { type: "flat", count: 4 },
|
|
55
|
+
Db: { type: "flat", count: 5 },
|
|
56
|
+
Gb: { type: "flat", count: 6 }
|
|
57
|
+
}, L = {
|
|
58
|
+
treble: {
|
|
59
|
+
sharp: [5, 5, 5, 5, 4, 5, 4],
|
|
60
|
+
// F5 C5 G5 D5 A4 E5 B4
|
|
61
|
+
flat: [4, 5, 4, 5, 4, 5, 4]
|
|
62
|
+
// B4 E5 A4 D5 G4 C5 F4
|
|
63
|
+
},
|
|
64
|
+
bass: {
|
|
65
|
+
sharp: [3, 3, 3, 3, 2, 3, 2],
|
|
66
|
+
// F3 C3 G3 D3 A2 E3 B2
|
|
67
|
+
flat: [2, 3, 2, 3, 2, 3, 3]
|
|
68
|
+
// B2 E3 A2 D3 G2 C3 F3
|
|
69
|
+
},
|
|
70
|
+
alto: {
|
|
71
|
+
sharp: [4, 4, 4, 4, 3, 4, 4],
|
|
72
|
+
// F5 C5 G5 D5 A4 E5 B4
|
|
73
|
+
flat: [4, 5, 4, 5, 4, 5, 4]
|
|
74
|
+
// B4 E5 A4 D5 G4 C5 F4
|
|
75
|
+
},
|
|
76
|
+
grand: { sharp: [], flat: [] }
|
|
77
|
+
};
|
|
78
|
+
function Y(h) {
|
|
79
|
+
const e = G[h];
|
|
80
|
+
if (!e) throw new Error(`Unknown key signature "${h}". Valid keys: ${Object.keys(G).join(", ")}`);
|
|
81
|
+
return e;
|
|
82
|
+
}
|
|
83
|
+
function k(h, e, t, s) {
|
|
84
|
+
const r = Y(t);
|
|
85
|
+
if (r.count === 0) return 0;
|
|
86
|
+
const n = r.type === "sharp" ? "ACCIDENTAL_SHARP" : "ACCIDENTAL_FLAT", o = h.getLayerByName("staff");
|
|
87
|
+
return e.getKeySignatureYPositions(r.type, r.count).forEach((i) => {
|
|
88
|
+
i.forEach((c, l) => {
|
|
89
|
+
h.drawGlyph(n, o, { xOffset: s + l * w, yOffset: c });
|
|
90
|
+
});
|
|
91
|
+
}), r.count * w;
|
|
92
|
+
}
|
|
93
|
+
const $ = {
|
|
41
94
|
CLEF_TREBLE: {
|
|
42
95
|
path: "m150 273 10 58c2 7 2 7 12 7 59 0 96 46 96 97 0 45-26 79-67 95-5 2-6 2-5 7 4 25 12 63 12 85 0 68-52 80-79 80-61 0-76-39-76-65 0-25 16-46 43-46 24 0 38 19 38 41 0 23-14 34-27 38-9 2-13 4-13 6 0 6 11 12 32 12 24 0 64-7 64-66 0-19-6-54-11-81-1-5-1-4-6-3l-27 2C48 540 0 474 0 404c0-80 61-138 119-185 5-4 4-5 3-10-2-16-5-42-5-65 0-42 9-92 39-125 8-9 20-19 26-19 4 0 15 11 21 20 16 24 26 58 26 93 0 61-33 112-76 153-3 2-3 2-3 7Zm38-211c-24 0-53 38-53 101l2 37c1 5 3 5 5 3 32-28 70-64 70-108 0-22-11-33-24-33Zm-44 272-8-51c-1-4-2-5-6-1-18 15-37 30-61 56-33 38-37 70-37 93 0 56 45 95 115 95l23-2c6-2 6-2 5-6l-20-119c-1-5-1-5-8-3-24 6-40 24-40 46 0 19 12 36 29 43 3 1 6 3 6 5 0 3-2 5-5 5l-11-3c-27-9-46-34-46-70 0-34 23-66 58-78 8-2 8-2 6-10Zm28 64 20 114c0 5 1 5 6 2 22-11 38-31 38-56 0-36-27-63-60-66-4 0-5 1-4 6Z",
|
|
43
96
|
xOffset: 0,
|
|
@@ -133,30 +186,26 @@ const B = {
|
|
|
133
186
|
xOffset: 0,
|
|
134
187
|
yOffset: 0
|
|
135
188
|
}
|
|
136
|
-
},
|
|
137
|
-
function
|
|
138
|
-
const e = h.match(
|
|
189
|
+
}, W = /^(?<name>[A-Ga-g])(?<accidental>##|bb|[#bn]?)(?<octave>\d)(?<duration>[whqeWHQE]?)$/, Z = /^[whqeWHQE]$/, y = ["C", "D", "E", "F", "G", "A", "B"];
|
|
190
|
+
function O(h) {
|
|
191
|
+
const e = h.match(W);
|
|
139
192
|
if (!e || !e.groups)
|
|
140
193
|
throw new Error(`Invalid note string format: ${h}. Expected format: [A-Ga-g][#|b]?[0-9][w|h|q|e].`);
|
|
141
|
-
let { name: t, accidental: s, octave: r, duration:
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
if (!r)
|
|
145
|
-
throw new Error(`Invalid octave: ${r}. Octave must be a number between 0 and 9.`);
|
|
146
|
-
o || (o = "w");
|
|
147
|
-
const n = {
|
|
194
|
+
let { name: t, accidental: s, octave: r, duration: n } = e.groups;
|
|
195
|
+
t = t.toUpperCase(), n = n.toLowerCase(), n || (n = "w");
|
|
196
|
+
const o = {
|
|
148
197
|
name: t,
|
|
149
198
|
octave: parseInt(r),
|
|
150
|
-
duration:
|
|
199
|
+
duration: n
|
|
151
200
|
};
|
|
152
|
-
return s && (
|
|
201
|
+
return s && (o.accidental = s), o;
|
|
153
202
|
}
|
|
154
|
-
function
|
|
155
|
-
const e = h.match(
|
|
203
|
+
function N(h) {
|
|
204
|
+
const e = h.match(Z);
|
|
156
205
|
if (!e) throw new Error(`Invalid note duration '${h}'. Use w | h | q | e.`);
|
|
157
|
-
return e.toString().toLowerCase();
|
|
206
|
+
return e[0].toString().toLowerCase();
|
|
158
207
|
}
|
|
159
|
-
function
|
|
208
|
+
function R(h) {
|
|
160
209
|
let e;
|
|
161
210
|
switch (h) {
|
|
162
211
|
case "treble":
|
|
@@ -172,26 +221,22 @@ function S(h) {
|
|
|
172
221
|
if (!e) throw new Error(`Invalid clef type: ${h}. Valid clef types are: treble, bass, alto.`);
|
|
173
222
|
return e;
|
|
174
223
|
}
|
|
175
|
-
function
|
|
176
|
-
|
|
177
|
-
let s = h.octave - e.octave;
|
|
178
|
-
return s *= 7, t + s;
|
|
179
|
-
}
|
|
180
|
-
function R(h) {
|
|
181
|
-
let e = I.indexOf(h.name);
|
|
224
|
+
function F(h) {
|
|
225
|
+
let e = y.indexOf(h.name);
|
|
182
226
|
return e += h.octave * 12, e;
|
|
183
227
|
}
|
|
184
|
-
function
|
|
185
|
-
return
|
|
228
|
+
function _(h, e) {
|
|
229
|
+
return y.indexOf(h.name) - y.indexOf(e.name) + (h.octave - e.octave) * 7;
|
|
186
230
|
}
|
|
187
|
-
const
|
|
188
|
-
class
|
|
231
|
+
const C = 48, v = 40 + 30 / 2, D = 20, B = 90;
|
|
232
|
+
class x {
|
|
189
233
|
params;
|
|
190
234
|
rendererRef;
|
|
191
235
|
width = 0;
|
|
236
|
+
trebleStaffHeight = 0;
|
|
192
237
|
constructor(e, t) {
|
|
193
238
|
this.rendererRef = e;
|
|
194
|
-
const s =
|
|
239
|
+
const s = I[t];
|
|
195
240
|
if (!s) throw new Error(`Staff type ${t} is not supported`);
|
|
196
241
|
this.params = s;
|
|
197
242
|
}
|
|
@@ -205,52 +250,60 @@ class H {
|
|
|
205
250
|
this.width = e;
|
|
206
251
|
const t = this.rendererRef.getLayerByName("staff");
|
|
207
252
|
let s = this.drawStaffLines(0, t), r = this.drawStaffLines(s + 30, t);
|
|
208
|
-
this.rendererRef.drawLine(0, 0, 0, r, t), this.rendererRef.drawLine(this.width, 0, this.width, r, t);
|
|
209
|
-
let
|
|
210
|
-
const a =
|
|
211
|
-
this.rendererRef.drawGlyph(a, t), this.rendererRef.drawGlyph(i, t, { yOffset: s + 30 }),
|
|
253
|
+
this.rendererRef.drawLine(0, 0, 0, r, t), this.rendererRef.drawLine(this.width, 0, this.width, r, t), this.trebleStaffHeight = s;
|
|
254
|
+
let n = r, o = 1;
|
|
255
|
+
const a = R("treble"), i = R("bass");
|
|
256
|
+
this.rendererRef.drawGlyph(a, t), this.rendererRef.drawGlyph(i, t, { yOffset: s + 30 }), n += this.params.paddingBottom + 1, o += this.params.paddingTop, this.rendererRef.addTotalRootSvgHeight(n), this.rendererRef.addTotalRootSvgYOffset(o);
|
|
212
257
|
};
|
|
213
258
|
shouldNoteFlip(e) {
|
|
214
|
-
const t = Math.abs(e -
|
|
215
|
-
return e ===
|
|
259
|
+
const t = Math.abs(e - B), s = Math.abs(e - D);
|
|
260
|
+
return e === v ? !1 : t <= s ? !(e >= B) : e <= D;
|
|
216
261
|
}
|
|
217
262
|
getLedgerLinesX(e, t) {
|
|
218
|
-
const s = [], r =
|
|
219
|
-
let
|
|
220
|
-
if (r ===
|
|
221
|
-
return s.push({ x1: -2, x2:
|
|
263
|
+
const s = [], r = F(e);
|
|
264
|
+
let n = e.duration === "w" ? 17 : 12.5;
|
|
265
|
+
if (r === C)
|
|
266
|
+
return s.push({ x1: -2, x2: n, yPos: 0 }), s;
|
|
222
267
|
if (t < this.params.topLineYPos) {
|
|
223
|
-
let
|
|
224
|
-
for (;
|
|
268
|
+
let o = this.params.topLineYPos - 10;
|
|
269
|
+
for (; o >= t; )
|
|
225
270
|
s.push({
|
|
226
271
|
x1: -2,
|
|
227
|
-
x2:
|
|
228
|
-
yPos:
|
|
229
|
-
}),
|
|
272
|
+
x2: n,
|
|
273
|
+
yPos: o - t
|
|
274
|
+
}), o -= 10;
|
|
230
275
|
} else if (t > this.params.bottomLineYPos) {
|
|
231
|
-
let
|
|
232
|
-
for (;
|
|
276
|
+
let o = this.params.bottomLineYPos + 10;
|
|
277
|
+
for (; o <= t; )
|
|
233
278
|
s.push({
|
|
234
279
|
x1: -2,
|
|
235
|
-
x2:
|
|
236
|
-
yPos:
|
|
237
|
-
}),
|
|
280
|
+
x2: n,
|
|
281
|
+
yPos: o - t
|
|
282
|
+
}), o += 10;
|
|
238
283
|
}
|
|
239
284
|
return s;
|
|
240
285
|
}
|
|
241
286
|
calculateNoteYPos = (e) => {
|
|
242
|
-
let s =
|
|
243
|
-
const r =
|
|
244
|
-
return r <
|
|
287
|
+
let s = _(this.params.topLineNote, e) * (10 / 2);
|
|
288
|
+
const r = F(e);
|
|
289
|
+
return r < C ? s += 10 : r === C && (s = v), s;
|
|
245
290
|
};
|
|
291
|
+
getKeySignatureYPositions(e, t) {
|
|
292
|
+
const s = X[e].slice(0, t), r = L.treble[e], n = L.bass[e], o = s.map(
|
|
293
|
+
(i, c) => _(I.treble.topLineNote, { name: i, octave: r[c] }) * (10 / 2)
|
|
294
|
+
), a = s.map(
|
|
295
|
+
(i, c) => _(I.bass.topLineNote, { name: i, octave: n[c] }) * (10 / 2) + this.trebleStaffHeight + 30
|
|
296
|
+
);
|
|
297
|
+
return [o, a];
|
|
298
|
+
}
|
|
246
299
|
}
|
|
247
|
-
const
|
|
300
|
+
const V = 20;
|
|
248
301
|
class A {
|
|
249
302
|
params;
|
|
250
303
|
rendererRef;
|
|
251
304
|
constructor(e, t) {
|
|
252
305
|
this.rendererRef = e;
|
|
253
|
-
const s =
|
|
306
|
+
const s = I[t];
|
|
254
307
|
if (!s) throw new Error(`Staff type ${t} is not supported`);
|
|
255
308
|
this.params = s;
|
|
256
309
|
}
|
|
@@ -260,38 +313,44 @@ class A {
|
|
|
260
313
|
for (let a = 0; a < 5; a++)
|
|
261
314
|
this.rendererRef.drawLine(0, s, e, s, t), s += 10;
|
|
262
315
|
this.rendererRef.drawLine(0, 0, 0, s - 10, t), this.rendererRef.drawLine(e, 0, e, s - 10, t);
|
|
263
|
-
let r = s - 10 + 1,
|
|
264
|
-
const
|
|
265
|
-
this.rendererRef.drawGlyph(
|
|
316
|
+
let r = s - 10 + 1, n = 1;
|
|
317
|
+
const o = R(this.params.staffType);
|
|
318
|
+
this.rendererRef.drawGlyph(o, t), r += this.params.paddingTop + this.params.paddingBottom, n += this.params.paddingTop, this.rendererRef.addTotalRootSvgHeight(r), this.rendererRef.addTotalRootSvgYOffset(n);
|
|
266
319
|
};
|
|
267
320
|
shouldNoteFlip(e) {
|
|
268
|
-
return e <=
|
|
321
|
+
return e <= V;
|
|
269
322
|
}
|
|
270
323
|
getLedgerLinesX(e, t) {
|
|
271
324
|
const s = [];
|
|
272
325
|
let r = e.duration === "w" ? 17 : 12.5;
|
|
273
326
|
if (t < this.params.topLineYPos) {
|
|
274
|
-
let
|
|
275
|
-
for (;
|
|
327
|
+
let n = this.params.topLineYPos - 10;
|
|
328
|
+
for (; n >= t; )
|
|
276
329
|
s.push({
|
|
277
330
|
x1: -2,
|
|
278
331
|
x2: r,
|
|
279
|
-
yPos:
|
|
280
|
-
}),
|
|
332
|
+
yPos: n - t
|
|
333
|
+
}), n -= 10;
|
|
281
334
|
} else if (t > this.params.bottomLineYPos) {
|
|
282
|
-
let
|
|
283
|
-
for (;
|
|
335
|
+
let n = this.params.bottomLineYPos + 10;
|
|
336
|
+
for (; n <= t; )
|
|
284
337
|
s.push({
|
|
285
338
|
x1: -2,
|
|
286
339
|
x2: r,
|
|
287
|
-
yPos:
|
|
288
|
-
}),
|
|
340
|
+
yPos: n - t
|
|
341
|
+
}), n += 10;
|
|
289
342
|
}
|
|
290
343
|
return s;
|
|
291
344
|
}
|
|
292
|
-
calculateNoteYPos = (e) =>
|
|
345
|
+
calculateNoteYPos = (e) => _(this.params.topLineNote, e) * (10 / 2);
|
|
346
|
+
getKeySignatureYPositions(e, t) {
|
|
347
|
+
const s = X[e].slice(0, t), r = L[this.params.staffType][e];
|
|
348
|
+
return [s.map(
|
|
349
|
+
(o, a) => this.calculateNoteYPos({ name: o, octave: r[a] })
|
|
350
|
+
)];
|
|
351
|
+
}
|
|
293
352
|
}
|
|
294
|
-
class
|
|
353
|
+
class U {
|
|
295
354
|
svgRendererInstance;
|
|
296
355
|
strategyInstance;
|
|
297
356
|
constructor(e, t) {
|
|
@@ -302,10 +361,10 @@ class P {
|
|
|
302
361
|
}
|
|
303
362
|
chordOffsetConsecutiveAccidentals(e) {
|
|
304
363
|
let t = 0, s = 0, r = 0;
|
|
305
|
-
for (let
|
|
306
|
-
const
|
|
307
|
-
if (
|
|
308
|
-
const i = Array.from(
|
|
364
|
+
for (let n = 0; n < e.length; n++) {
|
|
365
|
+
const o = e[n];
|
|
366
|
+
if (o.noteObj.accidental && r < 3 ? (t += -8, s = Math.min(s, t), r++) : o.noteObj.accidental && r <= 3 ? (t = -8, r = 1) : (t = 0, r = 0), t !== 0) {
|
|
367
|
+
const i = Array.from(o.noteGroup.getElementsByTagName("use")).find((c) => c.getAttribute("href")?.includes("ACCIDENTAL"));
|
|
309
368
|
if (!i) continue;
|
|
310
369
|
i.setAttribute("transform", `translate(${t + 8}, 0)`);
|
|
311
370
|
}
|
|
@@ -315,10 +374,10 @@ class P {
|
|
|
315
374
|
chordOffsetCloseNotes(e) {
|
|
316
375
|
let t = e[0], s = 0;
|
|
317
376
|
for (let r = 1; r < e.length; r++) {
|
|
318
|
-
const
|
|
319
|
-
if (
|
|
320
|
-
s = 28 / 2,
|
|
321
|
-
const i = Array.from(
|
|
377
|
+
const n = e[r];
|
|
378
|
+
if (-_(t.noteObj, n.noteObj) === 1) {
|
|
379
|
+
s = 28 / 2, n.noteGroup.setAttribute("transform", `translate(${s}, ${n.noteYPos})`);
|
|
380
|
+
const i = Array.from(n.noteGroup.getElementsByTagName("use")).find((c) => c.getAttribute("href")?.includes("ACCIDENTAL"));
|
|
322
381
|
if (i) {
|
|
323
382
|
const c = i.getAttribute("transform")?.match(/([-]?\d+)/), l = c && c[0];
|
|
324
383
|
let f = -s;
|
|
@@ -327,46 +386,46 @@ class P {
|
|
|
327
386
|
r++, t = e[r];
|
|
328
387
|
continue;
|
|
329
388
|
}
|
|
330
|
-
t =
|
|
389
|
+
t = n;
|
|
331
390
|
}
|
|
332
391
|
return s;
|
|
333
392
|
}
|
|
334
393
|
// Handles drawing the glyphs to internal group, applies the xPositioning to note Cursor X
|
|
335
394
|
renderNote(e) {
|
|
336
|
-
const t = this.svgRendererInstance.createGroup("note"), s =
|
|
395
|
+
const t = this.svgRendererInstance.createGroup("note"), s = O(e), r = this.strategyInstance.calculateNoteYPos({
|
|
337
396
|
name: s.name,
|
|
338
397
|
octave: s.octave
|
|
339
398
|
});
|
|
340
|
-
let
|
|
399
|
+
let n = this.strategyInstance.shouldNoteFlip(r);
|
|
341
400
|
switch (s.duration) {
|
|
342
401
|
case "h":
|
|
343
|
-
this.svgRendererInstance.drawGlyph("NOTE_HEAD_HALF", t), this.drawStem(t,
|
|
402
|
+
this.svgRendererInstance.drawGlyph("NOTE_HEAD_HALF", t), this.drawStem(t, n);
|
|
344
403
|
break;
|
|
345
404
|
case "q":
|
|
346
|
-
this.svgRendererInstance.drawGlyph("NOTE_HEAD_QUARTER", t), this.drawStem(t,
|
|
405
|
+
this.svgRendererInstance.drawGlyph("NOTE_HEAD_QUARTER", t), this.drawStem(t, n);
|
|
347
406
|
break;
|
|
348
407
|
case "e":
|
|
349
|
-
|
|
408
|
+
n ? this.svgRendererInstance.drawGlyph("EIGHTH_NOTE_FLIPPED", t) : this.svgRendererInstance.drawGlyph("EIGHTH_NOTE", t);
|
|
350
409
|
break;
|
|
351
410
|
default:
|
|
352
411
|
this.svgRendererInstance.drawGlyph("NOTE_HEAD_WHOLE", t);
|
|
353
412
|
}
|
|
354
|
-
let
|
|
413
|
+
let o = 0;
|
|
355
414
|
switch (s.accidental) {
|
|
356
415
|
case "#":
|
|
357
|
-
this.svgRendererInstance.drawGlyph("ACCIDENTAL_SHARP", t),
|
|
416
|
+
this.svgRendererInstance.drawGlyph("ACCIDENTAL_SHARP", t), o -= -8;
|
|
358
417
|
break;
|
|
359
418
|
case "b":
|
|
360
|
-
this.svgRendererInstance.drawGlyph("ACCIDENTAL_FLAT", t),
|
|
419
|
+
this.svgRendererInstance.drawGlyph("ACCIDENTAL_FLAT", t), o -= -8;
|
|
361
420
|
break;
|
|
362
421
|
case "n":
|
|
363
|
-
this.svgRendererInstance.drawGlyph("ACCIDENTAL_NATURAL", t),
|
|
422
|
+
this.svgRendererInstance.drawGlyph("ACCIDENTAL_NATURAL", t), o -= -8;
|
|
364
423
|
break;
|
|
365
424
|
case "##":
|
|
366
|
-
this.svgRendererInstance.drawGlyph("ACCIDENTAL_DOUBLE_SHARP", t),
|
|
425
|
+
this.svgRendererInstance.drawGlyph("ACCIDENTAL_DOUBLE_SHARP", t), o -= -10;
|
|
367
426
|
break;
|
|
368
427
|
case "bb":
|
|
369
|
-
this.svgRendererInstance.drawGlyph("ACCIDENTAL_DOUBLE_FLAT", t),
|
|
428
|
+
this.svgRendererInstance.drawGlyph("ACCIDENTAL_DOUBLE_FLAT", t), o -= -14;
|
|
370
429
|
break;
|
|
371
430
|
}
|
|
372
431
|
return this.strategyInstance.getLedgerLinesX(s, r).forEach((i) => {
|
|
@@ -375,14 +434,14 @@ class P {
|
|
|
375
434
|
noteGroup: t,
|
|
376
435
|
noteObj: s,
|
|
377
436
|
noteYPos: r,
|
|
378
|
-
accidentalOffset:
|
|
437
|
+
accidentalOffset: o,
|
|
379
438
|
cursorOffset: 0
|
|
380
439
|
};
|
|
381
440
|
}
|
|
382
441
|
renderChord(e) {
|
|
383
442
|
const t = this.svgRendererInstance.createGroup("chord"), s = [];
|
|
384
|
-
for (const
|
|
385
|
-
const a = this.renderNote(
|
|
443
|
+
for (const o of e) {
|
|
444
|
+
const a = this.renderNote(o);
|
|
386
445
|
a.noteGroup.setAttribute("transform", `translate(0, ${a.noteYPos})`), t.appendChild(a.noteGroup), s.push({
|
|
387
446
|
noteGroup: a.noteGroup,
|
|
388
447
|
noteObj: a.noteObj,
|
|
@@ -391,18 +450,18 @@ class P {
|
|
|
391
450
|
accidentalOffset: 0
|
|
392
451
|
});
|
|
393
452
|
}
|
|
394
|
-
const r = this.chordOffsetConsecutiveAccidentals(s),
|
|
453
|
+
const r = this.chordOffsetConsecutiveAccidentals(s), n = this.chordOffsetCloseNotes(s);
|
|
395
454
|
return {
|
|
396
455
|
noteGroup: t,
|
|
397
456
|
noteObj: s[0].noteObj,
|
|
398
457
|
noteYPos: 0,
|
|
399
458
|
accidentalOffset: r,
|
|
400
|
-
cursorOffset:
|
|
459
|
+
cursorOffset: n
|
|
401
460
|
};
|
|
402
461
|
}
|
|
403
462
|
}
|
|
404
|
-
const u = "http://www.w3.org/2000/svg",
|
|
405
|
-
class
|
|
463
|
+
const u = "http://www.w3.org/2000/svg", q = 0.1, S = 1200;
|
|
464
|
+
class b {
|
|
406
465
|
rootElementRef;
|
|
407
466
|
svgElementRef;
|
|
408
467
|
// Layers
|
|
@@ -420,14 +479,14 @@ class O {
|
|
|
420
479
|
// from get rootSvgElement().
|
|
421
480
|
// HEIGHT and YOfsset should be set externally, values are calculated internally.
|
|
422
481
|
constructor(e, t) {
|
|
423
|
-
this.rootElementRef = e, this.width = t.width, this.scale = t.scale, this.width >
|
|
482
|
+
this.rootElementRef = e, this.width = t.width, this.scale = t.scale, this.width > S && (this.width = S, console.warn(`Width provided for the staff ${this.width} exceeds the limit ${S}. Please use this value to fix positioning issues.`)), this.svgElementRef = document.createElementNS(u, "svg"), this.svgElementRef.classList.add("vs-svg-renderer-root"), this.svgElementRef.style.maxWidth = "100%", this.svgElementRef.style.height = "auto", this.svgElementRef.style.display = "block", this.svgElementRef.setAttribute("color", t.staffColor), this.svgElementRef.style.backgroundColor = t.staffBackgroundColor, this.makeGlyphDefs(t.useGlyphs), this.parentGroupContainer = this.createGroup("svg-renderer-parent"), this.svgElementRef.appendChild(this.parentGroupContainer), this.musicStaffLayer = this.createGroup("music-staff-layer"), this.musicNotesLayer = this.createGroup("music-notes-layer"), this.musicUILayer = this.createGroup("music-ui-layer"), this.parentGroupContainer.appendChild(this.musicStaffLayer), this.parentGroupContainer.appendChild(this.musicNotesLayer), this.parentGroupContainer.appendChild(this.musicUILayer);
|
|
424
483
|
}
|
|
425
484
|
// Creates SVG defs for all glyphs in GLYPH_ENTRIES, applies global scale and offsets, appends to root SVG
|
|
426
485
|
makeGlyphDefs(e) {
|
|
427
486
|
const t = document.createElementNS(u, "defs");
|
|
428
|
-
Object.entries(
|
|
429
|
-
const
|
|
430
|
-
|
|
487
|
+
Object.entries($).filter(([r]) => e.includes(r)).forEach(([r, n]) => {
|
|
488
|
+
const o = document.createElementNS(u, "path");
|
|
489
|
+
o.setAttribute("id", `glyph-${r}`), o.setAttribute("d", n.path), o.setAttribute("fill", "currentColor"), o.setAttribute("transform", `translate(${n.xOffset}, ${n.yOffset}) scale(${q})`), t.appendChild(o);
|
|
431
490
|
}), this.rootSvgElement.appendChild(t);
|
|
432
491
|
}
|
|
433
492
|
createGroup(e) {
|
|
@@ -471,13 +530,13 @@ class O {
|
|
|
471
530
|
return this.parentGroupContainer;
|
|
472
531
|
}
|
|
473
532
|
// Drawing Methods
|
|
474
|
-
drawLine(e, t, s, r,
|
|
475
|
-
const
|
|
476
|
-
|
|
533
|
+
drawLine(e, t, s, r, n) {
|
|
534
|
+
const o = document.createElementNS(u, "line");
|
|
535
|
+
o.setAttribute("x1", e.toString()), o.setAttribute("y1", t.toString()), o.setAttribute("x2", s.toString()), o.setAttribute("y2", r.toString()), o.setAttribute("stroke", "currentColor"), o.setAttribute("stroke-width", "1"), n.appendChild(o);
|
|
477
536
|
}
|
|
478
537
|
drawRect(e, t, s, r) {
|
|
479
|
-
const
|
|
480
|
-
return
|
|
538
|
+
const n = document.createElementNS(u, "rect");
|
|
539
|
+
return n.setAttribute("width", e.toString()), n.setAttribute("height", t.toString()), n.setAttribute("x", (r?.x ?? 0).toString()), n.setAttribute("y", (r?.y ?? 0).toString()), r?.fill ? n.setAttribute("fill", r.fill) : n.setAttribute("fill", "currentColor"), s.appendChild(n), n;
|
|
481
540
|
}
|
|
482
541
|
drawGlyph(e, t, s) {
|
|
483
542
|
s = {
|
|
@@ -492,7 +551,7 @@ class O {
|
|
|
492
551
|
this.rootElementRef && this.svgElementRef && this.rootElementRef.contains(this.svgElementRef) && this.rootElementRef.removeChild(this.svgElementRef);
|
|
493
552
|
}
|
|
494
553
|
}
|
|
495
|
-
const
|
|
554
|
+
const j = [
|
|
496
555
|
"CLEF_TREBLE",
|
|
497
556
|
"CLEF_BASS",
|
|
498
557
|
"CLEF_ALTO",
|
|
@@ -507,7 +566,7 @@ const $ = [
|
|
|
507
566
|
"ACCIDENTAL_DOUBLE_SHARP",
|
|
508
567
|
"ACCIDENTAL_DOUBLE_FLAT"
|
|
509
568
|
];
|
|
510
|
-
class
|
|
569
|
+
class et {
|
|
511
570
|
svgRendererInstance;
|
|
512
571
|
strategyInstance;
|
|
513
572
|
noteRendererInstance;
|
|
@@ -532,18 +591,18 @@ class j {
|
|
|
532
591
|
staffColor: "black",
|
|
533
592
|
staffBackgroundColor: "transparent",
|
|
534
593
|
...t
|
|
535
|
-
}, this.svgRendererInstance = new
|
|
594
|
+
}, this.svgRendererInstance = new b(e, {
|
|
536
595
|
width: this.options.width,
|
|
537
596
|
height: 100,
|
|
538
597
|
scale: this.options.scale,
|
|
539
598
|
staffColor: this.options.staffColor,
|
|
540
599
|
staffBackgroundColor: this.options.staffBackgroundColor,
|
|
541
|
-
useGlyphs:
|
|
600
|
+
useGlyphs: j
|
|
542
601
|
});
|
|
543
602
|
const s = this.svgRendererInstance.rootSvgElement;
|
|
544
603
|
switch (this.options.staffType) {
|
|
545
604
|
case "grand":
|
|
546
|
-
this.strategyInstance = new
|
|
605
|
+
this.strategyInstance = new x(this.svgRendererInstance, "grand");
|
|
547
606
|
break;
|
|
548
607
|
case "bass":
|
|
549
608
|
this.strategyInstance = new A(this.svgRendererInstance, "bass");
|
|
@@ -557,15 +616,19 @@ class j {
|
|
|
557
616
|
default:
|
|
558
617
|
throw new Error(`The staff type ${this.options.staffType} is not supported. Please use "treble", "bass", "alto", or "grand".`);
|
|
559
618
|
}
|
|
560
|
-
if (this.strategyInstance.drawStaff(this.options.width), this.noteRendererInstance = new
|
|
561
|
-
const
|
|
562
|
-
this.svgRendererInstance.addTotalRootSvgYOffset(
|
|
619
|
+
if (this.strategyInstance.drawStaff(this.options.width), this.noteRendererInstance = new U(this.svgRendererInstance, this.strategyInstance), this.options.spaceAbove) {
|
|
620
|
+
const n = this.options.spaceAbove * 10;
|
|
621
|
+
this.svgRendererInstance.addTotalRootSvgYOffset(n);
|
|
563
622
|
}
|
|
564
623
|
if (this.options.spaceBelow) {
|
|
565
|
-
let
|
|
566
|
-
this.options.staffType === "grand" && (
|
|
624
|
+
let n = this.options.spaceBelow * 10;
|
|
625
|
+
this.options.staffType === "grand" && (n -= 10 / 2), this.svgRendererInstance.addTotalRootSvgHeight(n);
|
|
567
626
|
}
|
|
568
|
-
|
|
627
|
+
let r = 0;
|
|
628
|
+
this.options.keySignature && (r = this.createKeySignature(this.options.keySignature)), this.noteStartX = 38 + this.options.noteStartX + r, this.svgRendererInstance.getLayerByName("notes").setAttribute("transform", `translate(${this.noteStartX}, 0)`), this.svgRendererInstance.applySizingToRootSvg(), this.svgRendererInstance.commitElementsToDOM(s);
|
|
629
|
+
}
|
|
630
|
+
createKeySignature(e) {
|
|
631
|
+
return k(this.svgRendererInstance, this.strategyInstance, e, M);
|
|
569
632
|
}
|
|
570
633
|
/**
|
|
571
634
|
* Draws a note on the staff.
|
|
@@ -589,20 +652,20 @@ class j {
|
|
|
589
652
|
*/
|
|
590
653
|
drawNote(e) {
|
|
591
654
|
const t = Array.isArray(e) ? e : [e], s = this.svgRendererInstance.getLayerByName("notes"), r = [];
|
|
592
|
-
for (const
|
|
593
|
-
let
|
|
655
|
+
for (const n of t) {
|
|
656
|
+
let o;
|
|
594
657
|
try {
|
|
595
|
-
|
|
658
|
+
o = this.noteRendererInstance.renderNote(n);
|
|
596
659
|
} catch (a) {
|
|
597
660
|
throw r.length > 0 && this.svgRendererInstance.commitElementsToDOM(r, s), a;
|
|
598
661
|
}
|
|
599
|
-
|
|
600
|
-
gElement:
|
|
601
|
-
note:
|
|
602
|
-
xPos: this.noteCursorX +
|
|
603
|
-
yPos:
|
|
604
|
-
accidentalXOffset:
|
|
605
|
-
}), this.noteCursorX += 28 +
|
|
662
|
+
o.noteGroup.setAttribute("transform", `translate(${this.noteCursorX + o.accidentalOffset}, ${o.noteYPos})`), this.noteEntries.push({
|
|
663
|
+
gElement: o.noteGroup,
|
|
664
|
+
note: o.noteObj,
|
|
665
|
+
xPos: this.noteCursorX + o.accidentalOffset,
|
|
666
|
+
yPos: o.noteYPos,
|
|
667
|
+
accidentalXOffset: o.accidentalOffset
|
|
668
|
+
}), this.noteCursorX += 28 + o.accidentalOffset, r.push(o.noteGroup);
|
|
606
669
|
}
|
|
607
670
|
this.svgRendererInstance.commitElementsToDOM(r, s);
|
|
608
671
|
}
|
|
@@ -626,7 +689,7 @@ class j {
|
|
|
626
689
|
const t = this.svgRendererInstance.getLayerByName("notes"), s = this.noteRendererInstance.renderChord(e);
|
|
627
690
|
s.noteGroup.setAttribute("transform", `translate(${this.noteCursorX + s.accidentalOffset}, 0)`), this.noteEntries.push({
|
|
628
691
|
gElement: s.noteGroup,
|
|
629
|
-
note:
|
|
692
|
+
note: O(e[0]),
|
|
630
693
|
xPos: this.noteCursorX + s.accidentalOffset,
|
|
631
694
|
yPos: 0,
|
|
632
695
|
accidentalXOffset: s.accidentalOffset
|
|
@@ -637,19 +700,19 @@ class j {
|
|
|
637
700
|
* @returns Returns early if no notes are on the staff
|
|
638
701
|
*/
|
|
639
702
|
justifyNotes() {
|
|
640
|
-
const e = this.options.width -
|
|
703
|
+
const e = this.options.width - this.noteStartX, t = this.noteEntries.length;
|
|
641
704
|
if (t <= 0 || e <= 0) return;
|
|
642
705
|
const s = Math.round(e / t);
|
|
643
|
-
this.noteEntries.map((
|
|
644
|
-
const a = (
|
|
706
|
+
this.noteEntries.map((n, o) => {
|
|
707
|
+
const a = (o + 0.5) * s, i = n.gElement.getBBox(), c = a - i.width / 2 - i.x, l = Math.round(c * 10) / 10;
|
|
645
708
|
return {
|
|
646
|
-
entry:
|
|
709
|
+
entry: n,
|
|
647
710
|
newX: l,
|
|
648
|
-
isChord:
|
|
711
|
+
isChord: n.gElement.classList.contains("chord")
|
|
649
712
|
};
|
|
650
|
-
}).forEach((
|
|
651
|
-
const { entry:
|
|
652
|
-
i ?
|
|
713
|
+
}).forEach((n) => {
|
|
714
|
+
const { entry: o, newX: a, isChord: i } = n;
|
|
715
|
+
i ? o.gElement.setAttribute("transform", `translate(${a}, 0)`) : o.gElement.setAttribute("transform", `translate(${a}, ${o.yPos})`), o.xPos = a;
|
|
653
716
|
});
|
|
654
717
|
}
|
|
655
718
|
/**
|
|
@@ -677,11 +740,11 @@ class j {
|
|
|
677
740
|
*/
|
|
678
741
|
changeNoteByIndex(e, t) {
|
|
679
742
|
if (t >= this.noteEntries.length) throw new Error("Note index was out of bounds.");
|
|
680
|
-
const s = this.noteEntries[t], r = this.noteRendererInstance.renderNote(e),
|
|
681
|
-
r.noteGroup.setAttribute("transform", `translate(${
|
|
743
|
+
const s = this.noteEntries[t], r = this.noteRendererInstance.renderNote(e), o = s.xPos - s.accidentalXOffset + r.accidentalOffset;
|
|
744
|
+
r.noteGroup.setAttribute("transform", `translate(${o}, ${r.noteYPos})`), this.svgRendererInstance.getLayerByName("notes").replaceChild(r.noteGroup, s.gElement), this.noteEntries[t] = {
|
|
682
745
|
gElement: r.noteGroup,
|
|
683
746
|
note: r.noteObj,
|
|
684
|
-
xPos:
|
|
747
|
+
xPos: o,
|
|
685
748
|
yPos: r.noteYPos,
|
|
686
749
|
accidentalXOffset: r.accidentalOffset
|
|
687
750
|
};
|
|
@@ -705,11 +768,11 @@ class j {
|
|
|
705
768
|
changeChordByIndex(e, t) {
|
|
706
769
|
if (t >= this.noteEntries.length) throw new Error("Chord index was out of bounds.");
|
|
707
770
|
if (e.length < 2) throw new Error("Notes provided need to be more than one to be considered a chord.");
|
|
708
|
-
const s = this.noteEntries[t], r = this.noteRendererInstance.renderChord(e),
|
|
709
|
-
r.noteGroup.setAttribute("transform", `translate(${
|
|
771
|
+
const s = this.noteEntries[t], r = this.noteRendererInstance.renderChord(e), o = s.xPos - s.accidentalXOffset + r.accidentalOffset;
|
|
772
|
+
r.noteGroup.setAttribute("transform", `translate(${o}, 0)`), this.svgRendererInstance.getLayerByName("notes").replaceChild(r.noteGroup, s.gElement), this.noteEntries[t] = {
|
|
710
773
|
gElement: r.noteGroup,
|
|
711
|
-
note:
|
|
712
|
-
xPos:
|
|
774
|
+
note: O(e[0]),
|
|
775
|
+
xPos: o,
|
|
713
776
|
yPos: 0,
|
|
714
777
|
accidentalXOffset: r.accidentalOffset
|
|
715
778
|
};
|
|
@@ -744,7 +807,7 @@ class j {
|
|
|
744
807
|
this.noteEntries = [], this.svgRendererInstance.destroy();
|
|
745
808
|
}
|
|
746
809
|
}
|
|
747
|
-
const
|
|
810
|
+
const d = 30, H = 19, g = 12, K = 4, Q = 6, P = 1, m = 38, z = [
|
|
748
811
|
"TIME_4",
|
|
749
812
|
"TIME_3",
|
|
750
813
|
"NOTE_HEAD_WHOLE",
|
|
@@ -756,7 +819,7 @@ const E = 30, v = 19, C = 12, k = 4, W = 6, G = 1, L = 38, Z = [
|
|
|
756
819
|
"REST_QUARTER",
|
|
757
820
|
"REST_EIGHTH"
|
|
758
821
|
];
|
|
759
|
-
class
|
|
822
|
+
class st {
|
|
760
823
|
rendererInstance;
|
|
761
824
|
options;
|
|
762
825
|
barSpacing;
|
|
@@ -767,7 +830,7 @@ class Q {
|
|
|
767
830
|
currentBeatCount = 0;
|
|
768
831
|
currentBeatUICount = 0;
|
|
769
832
|
currentBeatUIElement = null;
|
|
770
|
-
currentBeatUIXPos =
|
|
833
|
+
currentBeatUIXPos = m;
|
|
771
834
|
/**
|
|
772
835
|
* Creates an instance of a RhythmStaff, A single staff that will automatically apply positioning of elements based on the duration of a note.
|
|
773
836
|
*
|
|
@@ -787,13 +850,13 @@ class Q {
|
|
|
787
850
|
staffBackgroundColor: "white",
|
|
788
851
|
currentBeatUIColor: "#24ff7450",
|
|
789
852
|
...t
|
|
790
|
-
}, this.rendererInstance = new
|
|
853
|
+
}, this.rendererInstance = new b(e, {
|
|
791
854
|
width: this.options.width,
|
|
792
855
|
height: 100,
|
|
793
856
|
scale: this.options.scale,
|
|
794
857
|
staffColor: this.options.staffColor,
|
|
795
858
|
staffBackgroundColor: this.options.staffBackgroundColor,
|
|
796
|
-
useGlyphs:
|
|
859
|
+
useGlyphs: z
|
|
797
860
|
});
|
|
798
861
|
const s = this.rendererInstance.rootSvgElement;
|
|
799
862
|
let r = "TIME_4";
|
|
@@ -816,34 +879,34 @@ class Q {
|
|
|
816
879
|
let p = this.options.spaceBelow * 10;
|
|
817
880
|
this.rendererInstance.addTotalRootSvgHeight(p);
|
|
818
881
|
}
|
|
819
|
-
const
|
|
820
|
-
this.rendererInstance.addTotalRootSvgHeight(
|
|
821
|
-
const
|
|
822
|
-
|
|
823
|
-
const a =
|
|
824
|
-
this.rendererInstance.drawGlyph(r,
|
|
882
|
+
const n = this.rendererInstance.getLayerByName("staff");
|
|
883
|
+
this.rendererInstance.addTotalRootSvgHeight(d * 2);
|
|
884
|
+
const o = this.rendererInstance.createGroup("time-signature");
|
|
885
|
+
n.appendChild(o);
|
|
886
|
+
const a = d - H;
|
|
887
|
+
this.rendererInstance.drawGlyph(r, o), this.rendererInstance.drawGlyph("TIME_4", o, { yOffset: H }), o.setAttribute("transform", `translate(0, ${a})`);
|
|
825
888
|
let i = this.options.width - 38;
|
|
826
|
-
this.options.barsCount > 1 && (i -= (this.options.barsCount - 1) *
|
|
889
|
+
this.options.barsCount > 1 && (i -= (this.options.barsCount - 1) * g), i -= P, this.rendererInstance.drawLine(0, d, this.options.width - P, d, n), this.barSpacing = i / this.options.barsCount, this.quarterNoteSpacing = Math.round(this.barSpacing / this.options.topNumber), this.maxBeatCount = this.options.barsCount * this.options.topNumber;
|
|
827
890
|
let c = this.barSpacing + 38;
|
|
828
|
-
const l =
|
|
891
|
+
const l = d / 2, f = d + l;
|
|
829
892
|
for (let p = 0; p < this.options.barsCount - 1; p++)
|
|
830
|
-
this.rendererInstance.drawLine(c, l, c, f,
|
|
831
|
-
this.rendererInstance.getLayerByName("notes").setAttribute("transform", `translate(38, ${
|
|
893
|
+
this.rendererInstance.drawLine(c, l, c, f, n), c += this.barSpacing;
|
|
894
|
+
this.rendererInstance.getLayerByName("notes").setAttribute("transform", `translate(38, ${d})`), this.rendererInstance.applySizingToRootSvg(), this.rendererInstance.commitElementsToDOM(s);
|
|
832
895
|
}
|
|
833
896
|
createBeatUIElement() {
|
|
834
897
|
const e = this.rendererInstance.getLayerByName("ui");
|
|
835
898
|
this.currentBeatUIElement = this.rendererInstance.drawRect(
|
|
836
899
|
this.quarterNoteSpacing / 2,
|
|
837
|
-
|
|
900
|
+
d * 2,
|
|
838
901
|
e,
|
|
839
902
|
{
|
|
840
|
-
x:
|
|
903
|
+
x: m,
|
|
841
904
|
fill: this.options.currentBeatUIColor
|
|
842
905
|
}
|
|
843
906
|
);
|
|
844
907
|
}
|
|
845
908
|
handleNewBar() {
|
|
846
|
-
this.noteCursorX +=
|
|
909
|
+
this.noteCursorX += g;
|
|
847
910
|
}
|
|
848
911
|
// Translates group, returns cursor increment amount
|
|
849
912
|
translateGroupByDuration(e, t) {
|
|
@@ -902,15 +965,15 @@ class Q {
|
|
|
902
965
|
let s = e;
|
|
903
966
|
for (; s > 0; ) {
|
|
904
967
|
const r = this.rendererInstance.createGroup("rest");
|
|
905
|
-
let
|
|
906
|
-
s -
|
|
968
|
+
let n = 0;
|
|
969
|
+
s - E.h >= 0 ? (this.rendererInstance.drawGlyph("REST_HALF", r), n = E.h) : s - E.q >= 0 ? (this.rendererInstance.drawGlyph("REST_QUARTER", r), n = E.q) : (this.rendererInstance.drawGlyph("REST_EIGHTH", r), n = E.e), s -= n, this.currentBeatCount += n, r.setAttribute("transform", `translate(${this.noteCursorX}, 0)`), this.noteCursorX += n * this.quarterNoteSpacing, t.push(r);
|
|
907
970
|
}
|
|
908
971
|
return t;
|
|
909
972
|
}
|
|
910
973
|
renderBeamRect(e, t, s, r) {
|
|
911
974
|
this.rendererInstance.drawRect(
|
|
912
975
|
e - t,
|
|
913
|
-
|
|
976
|
+
K,
|
|
914
977
|
s,
|
|
915
978
|
{
|
|
916
979
|
x: 10,
|
|
@@ -939,14 +1002,14 @@ class Q {
|
|
|
939
1002
|
*/
|
|
940
1003
|
drawNote(e) {
|
|
941
1004
|
const t = Array.isArray(e) ? e : [e], s = this.rendererInstance.getLayerByName("notes"), r = [];
|
|
942
|
-
for (const
|
|
943
|
-
let
|
|
1005
|
+
for (const n of t) {
|
|
1006
|
+
let o = "w";
|
|
944
1007
|
try {
|
|
945
|
-
|
|
1008
|
+
o = N(n);
|
|
946
1009
|
} catch (f) {
|
|
947
1010
|
throw r.length > 0 && this.rendererInstance.commitElementsToDOM(r, s), f;
|
|
948
1011
|
}
|
|
949
|
-
const a =
|
|
1012
|
+
const a = E[o];
|
|
950
1013
|
if (this.currentBeatCount >= this.maxBeatCount)
|
|
951
1014
|
throw r.length > 0 && this.rendererInstance.commitElementsToDOM(r, s), new Error("Max beat count reached. Can't add additional notes.");
|
|
952
1015
|
this.checkAndCreateNewBar();
|
|
@@ -955,7 +1018,7 @@ class Q {
|
|
|
955
1018
|
r.push(f), this.noteEntries.push(f);
|
|
956
1019
|
});
|
|
957
1020
|
const c = this.rendererInstance.createGroup("note"), l = this.translateGroupByDuration(a, c);
|
|
958
|
-
this.noteCursorX += l, this.currentBeatCount += a, this.renderNote(
|
|
1021
|
+
this.noteCursorX += l, this.currentBeatCount += a, this.renderNote(o, c), r.push(c), this.noteEntries.push(c);
|
|
959
1022
|
}
|
|
960
1023
|
this.rendererInstance.commitElementsToDOM(r, s);
|
|
961
1024
|
}
|
|
@@ -979,21 +1042,21 @@ class Q {
|
|
|
979
1042
|
*/
|
|
980
1043
|
drawRest(e) {
|
|
981
1044
|
const t = Array.isArray(e) ? e : [e], s = this.rendererInstance.getLayerByName("notes"), r = [];
|
|
982
|
-
for (const
|
|
983
|
-
let
|
|
1045
|
+
for (const n of t) {
|
|
1046
|
+
let o = "w";
|
|
984
1047
|
try {
|
|
985
|
-
|
|
1048
|
+
o = N(n);
|
|
986
1049
|
} catch (f) {
|
|
987
1050
|
throw r.length > 0 && this.rendererInstance.commitElementsToDOM(r, s), f;
|
|
988
1051
|
}
|
|
989
|
-
const a = this.rendererInstance.createGroup("rest"), i =
|
|
1052
|
+
const a = this.rendererInstance.createGroup("rest"), i = E[o], c = i * this.quarterNoteSpacing;
|
|
990
1053
|
if (this.currentBeatCount >= this.maxBeatCount)
|
|
991
1054
|
throw r.length > 0 && this.rendererInstance.commitElementsToDOM(r, s), new Error("Max beat count reached. Can't add additional notes.");
|
|
992
1055
|
this.checkAndCreateNewBar();
|
|
993
1056
|
const l = this.checkAndFillBarWithRests(i);
|
|
994
1057
|
l && l.forEach((f) => {
|
|
995
1058
|
r.push(f), this.noteEntries.push(f);
|
|
996
|
-
}), this.renderRest(
|
|
1059
|
+
}), this.renderRest(o, a), a.setAttribute("transform", `translate(${this.noteCursorX}, 0)`), this.noteCursorX += c, this.currentBeatCount += i, r.push(a), this.noteEntries.push(a);
|
|
997
1060
|
}
|
|
998
1061
|
this.rendererInstance.commitElementsToDOM(r, s);
|
|
999
1062
|
}
|
|
@@ -1020,13 +1083,13 @@ class Q {
|
|
|
1020
1083
|
if (this.currentBeatCount >= this.maxBeatCount)
|
|
1021
1084
|
throw new Error("Max beat count reached. Can't add additional beamed note.");
|
|
1022
1085
|
let s = "s";
|
|
1023
|
-
e === "s" ? s = "s" : s =
|
|
1024
|
-
const r = this.rendererInstance.getLayerByName("notes"),
|
|
1086
|
+
e === "s" ? s = "s" : s = N(e), this.checkAndCreateNewBar();
|
|
1087
|
+
const r = this.rendererInstance.getLayerByName("notes"), n = E[s], o = n * this.quarterNoteSpacing, a = this.options.topNumber - this.currentBeatCount % this.options.topNumber, i = Math.min(t, a / n), c = this.rendererInstance.createGroup("beamed-note");
|
|
1025
1088
|
c.setAttribute("transform", `translate(${this.noteCursorX}, 0)`);
|
|
1026
1089
|
let l = 0;
|
|
1027
1090
|
for (let f = 0; f < i; f++)
|
|
1028
|
-
this.rendererInstance.drawGlyph("NOTE_HEAD_QUARTER", c, { xOffset: l }), this.drawStem(c, l), l +=
|
|
1029
|
-
this.renderBeamRect(l,
|
|
1091
|
+
this.rendererInstance.drawGlyph("NOTE_HEAD_QUARTER", c, { xOffset: l }), this.drawStem(c, l), l += o, this.currentBeatCount += n;
|
|
1092
|
+
this.renderBeamRect(l, o, c), e === "s" && this.renderBeamRect(l, o, c, Q), this.noteCursorX += l, this.noteEntries.push(c), this.rendererInstance.commitElementsToDOM(c, r);
|
|
1030
1093
|
}
|
|
1031
1094
|
/**
|
|
1032
1095
|
* Will increment the UI showing the current beat in quarters. Once exceeded, must be reset with `resetCurrentBeatUI()`
|
|
@@ -1037,14 +1100,14 @@ class Q {
|
|
|
1037
1100
|
this.currentBeatUIElement.setAttribute("display", "none");
|
|
1038
1101
|
return;
|
|
1039
1102
|
}
|
|
1040
|
-
this.currentBeatUIElement?.getAttribute("display") === "none" && this.currentBeatUIElement.removeAttribute("display"), this.currentBeatUICount++, this.currentBeatUICount > this.options.topNumber && this.currentBeatUICount % this.options.topNumber === 1 && (this.currentBeatUIXPos +=
|
|
1103
|
+
this.currentBeatUIElement?.getAttribute("display") === "none" && this.currentBeatUIElement.removeAttribute("display"), this.currentBeatUICount++, this.currentBeatUICount > this.options.topNumber && this.currentBeatUICount % this.options.topNumber === 1 && (this.currentBeatUIXPos += g), this.currentBeatUICount > 1 && (this.currentBeatUIXPos += this.quarterNoteSpacing), this.currentBeatUIElement.setAttribute("x", this.currentBeatUIXPos.toString());
|
|
1041
1104
|
}
|
|
1042
1105
|
/**
|
|
1043
1106
|
* Resets the ui showing the current beat value.
|
|
1044
1107
|
* @returns void
|
|
1045
1108
|
*/
|
|
1046
1109
|
resetCurrentBeatUI() {
|
|
1047
|
-
this.currentBeatUICount = 0, this.currentBeatUIXPos =
|
|
1110
|
+
this.currentBeatUICount = 0, this.currentBeatUIXPos = m, this.currentBeatUIElement && (this.currentBeatUIElement.setAttribute("display", "none"), this.currentBeatUIElement.setAttribute("x", this.currentBeatUIXPos.toString()));
|
|
1048
1111
|
}
|
|
1049
1112
|
/**
|
|
1050
1113
|
* Clears staff of notes and resets internal positioning.
|
|
@@ -1061,7 +1124,7 @@ class Q {
|
|
|
1061
1124
|
this.noteEntries = [], this.rendererInstance.destroy();
|
|
1062
1125
|
}
|
|
1063
1126
|
}
|
|
1064
|
-
const
|
|
1127
|
+
const J = [
|
|
1065
1128
|
"CLEF_TREBLE",
|
|
1066
1129
|
"CLEF_BASS",
|
|
1067
1130
|
"CLEF_ALTO",
|
|
@@ -1075,8 +1138,8 @@ const V = [
|
|
|
1075
1138
|
"ACCIDENTAL_NATURAL",
|
|
1076
1139
|
"ACCIDENTAL_DOUBLE_SHARP",
|
|
1077
1140
|
"ACCIDENTAL_DOUBLE_FLAT"
|
|
1078
|
-
],
|
|
1079
|
-
class
|
|
1141
|
+
], T = 60, tt = T;
|
|
1142
|
+
class rt {
|
|
1080
1143
|
svgRendererInstance;
|
|
1081
1144
|
strategyInstance;
|
|
1082
1145
|
noteRendererInstance;
|
|
@@ -1103,18 +1166,18 @@ class z {
|
|
|
1103
1166
|
staffColor: "black",
|
|
1104
1167
|
staffBackgroundColor: "transparent",
|
|
1105
1168
|
...t
|
|
1106
|
-
}, this.svgRendererInstance = new
|
|
1169
|
+
}, this.svgRendererInstance = new b(e, {
|
|
1107
1170
|
width: this.options.width,
|
|
1108
1171
|
height: 100,
|
|
1109
1172
|
scale: this.options.scale,
|
|
1110
1173
|
staffColor: this.options.staffColor,
|
|
1111
1174
|
staffBackgroundColor: this.options.staffBackgroundColor,
|
|
1112
|
-
useGlyphs:
|
|
1175
|
+
useGlyphs: J
|
|
1113
1176
|
});
|
|
1114
1177
|
const s = this.svgRendererInstance.rootSvgElement;
|
|
1115
1178
|
switch (this.options.staffType) {
|
|
1116
1179
|
case "grand":
|
|
1117
|
-
this.strategyInstance = new
|
|
1180
|
+
this.strategyInstance = new x(this.svgRendererInstance, "grand");
|
|
1118
1181
|
break;
|
|
1119
1182
|
case "bass":
|
|
1120
1183
|
this.strategyInstance = new A(this.svgRendererInstance, "bass");
|
|
@@ -1128,7 +1191,7 @@ class z {
|
|
|
1128
1191
|
default:
|
|
1129
1192
|
throw new Error(`The staff type ${this.options.staffType} is not supported. Please use "treble", "bass", "alto", or "grand".`);
|
|
1130
1193
|
}
|
|
1131
|
-
if (this.strategyInstance.drawStaff(this.options.width), this.noteRendererInstance = new
|
|
1194
|
+
if (this.strategyInstance.drawStaff(this.options.width), this.noteRendererInstance = new U(this.svgRendererInstance, this.strategyInstance), this.options.spaceAbove) {
|
|
1132
1195
|
const r = this.options.spaceAbove * 10;
|
|
1133
1196
|
this.svgRendererInstance.addTotalRootSvgYOffset(r);
|
|
1134
1197
|
}
|
|
@@ -1139,10 +1202,10 @@ class z {
|
|
|
1139
1202
|
this.notesLayer = this.svgRendererInstance.getLayerByName("notes"), this.notesLayer.classList.add("vs-scrolling-notes-layer"), this.noteStartX = 38 + this.options.noteStartX, this.svgRendererInstance.getLayerByName("notes").setAttribute("transform", `translate(${this.noteStartX}, 0)`), this.svgRendererInstance.applySizingToRootSvg(), this.svgRendererInstance.commitElementsToDOM(s);
|
|
1140
1203
|
}
|
|
1141
1204
|
renderFirstNoteGroups() {
|
|
1142
|
-
const e = this.options.width - this.options.noteStartX +
|
|
1205
|
+
const e = this.options.width - this.options.noteStartX + tt;
|
|
1143
1206
|
for (; this.noteBuffer.length > 0 && this.noteCursorX < e; )
|
|
1144
|
-
this.renderNextNote(), this.noteCursorX +=
|
|
1145
|
-
this.activeEntries.length > 1 && (this.noteCursorX -=
|
|
1207
|
+
this.renderNextNote(), this.noteCursorX += T;
|
|
1208
|
+
this.activeEntries.length > 1 && (this.noteCursorX -= T);
|
|
1146
1209
|
}
|
|
1147
1210
|
renderNextNote() {
|
|
1148
1211
|
if (this.noteBuffer.length < 1) return;
|
|
@@ -1201,7 +1264,7 @@ class z {
|
|
|
1201
1264
|
return;
|
|
1202
1265
|
}
|
|
1203
1266
|
this.activeEntries.forEach((t) => {
|
|
1204
|
-
t.xPos -=
|
|
1267
|
+
t.xPos -= T, t.noteWrapper.style.transform = `translate(${t.xPos}px, 0px)`;
|
|
1205
1268
|
});
|
|
1206
1269
|
const e = this.activeEntries[0];
|
|
1207
1270
|
e.xPos <= 0 && (this.notesLayer.removeChild(e.noteWrapper), this.activeEntries.shift()), this.renderNextNote();
|
|
@@ -1222,7 +1285,7 @@ class z {
|
|
|
1222
1285
|
}
|
|
1223
1286
|
}
|
|
1224
1287
|
export {
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1288
|
+
et as MusicStaff,
|
|
1289
|
+
st as RhythmStaff,
|
|
1290
|
+
rt as ScrollingStaff
|
|
1228
1291
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
(function(d,I){typeof exports=="object"&&typeof module<"u"?I(exports):typeof define=="function"&&define.amd?define(["exports"],I):(d=typeof globalThis<"u"?globalThis:d||self,I(d.VectorScore={}))})(this,(function(d){"use strict";const w={treble:{staffType:"treble",paddingTop:13,paddingBottom:3,topLineNote:{name:"F",octave:5},topLineYPos:0,bottomLineYPos:40},bass:{staffType:"bass",paddingTop:0,paddingBottom:0,topLineNote:{name:"A",octave:3},topLineYPos:0,bottomLineYPos:40},alto:{staffType:"alto",paddingTop:0,paddingBottom:0,topLineNote:{name:"G",octave:4},topLineYPos:0,bottomLineYPos:40},grand:{staffType:"grand",paddingTop:13,paddingBottom:0,topLineNote:{name:"F",octave:5},topLineYPos:0,bottomLineYPos:110}},E={w:4,h:2,q:1,e:.5,s:.25},U={CLEF_TREBLE:{path:"m150 273 10 58c2 7 2 7 12 7 59 0 96 46 96 97 0 45-26 79-67 95-5 2-6 2-5 7 4 25 12 63 12 85 0 68-52 80-79 80-61 0-76-39-76-65 0-25 16-46 43-46 24 0 38 19 38 41 0 23-14 34-27 38-9 2-13 4-13 6 0 6 11 12 32 12 24 0 64-7 64-66 0-19-6-54-11-81-1-5-1-4-6-3l-27 2C48 540 0 474 0 404c0-80 61-138 119-185 5-4 4-5 3-10-2-16-5-42-5-65 0-42 9-92 39-125 8-9 20-19 26-19 4 0 15 11 21 20 16 24 26 58 26 93 0 61-33 112-76 153-3 2-3 2-3 7Zm38-211c-24 0-53 38-53 101l2 37c1 5 3 5 5 3 32-28 70-64 70-108 0-22-11-33-24-33Zm-44 272-8-51c-1-4-2-5-6-1-18 15-37 30-61 56-33 38-37 70-37 93 0 56 45 95 115 95l23-2c6-2 6-2 5-6l-20-119c-1-5-1-5-8-3-24 6-40 24-40 46 0 19 12 36 29 43 3 1 6 3 6 5 0 3-2 5-5 5l-11-3c-27-9-46-34-46-70 0-34 23-66 58-78 8-2 8-2 6-10Zm28 64 20 114c0 5 1 5 6 2 22-11 38-31 38-56 0-36-27-63-60-66-4 0-5 1-4 6Z",xOffset:0,yOffset:-14},CLEF_BASS:{path:"M101 0c68 0 110 46 110 114 0 120-102 190-199 237l-7 2c-3 0-5-2-5-5s2-5 6-7c92-52 146-114 146-223 0-62-18-103-60-103-40 0-64 29-64 44 0 4 1 8 7 8 5 0 9-3 19-3 20 0 38 15 38 41 0 24-17 41-42 41-32 0-48-27-48-58C2 50 33 0 101 0Zm148 32c13 0 22 10 22 22s-9 22-22 22c-12 0-21-10-21-22s9-22 21-22Zm1 99c12 0 21 9 21 21s-9 22-21 22-21-10-21-22 9-21 21-21Z",xOffset:0,yOffset:0},CLEF_ALTO:{path:"M91 9v174c0 3 2 2 3 2 11-3 27-13 36-58 1-6 3-10 7-10s6 4 8 11c5 17 15 37 43 37 25 0 32-25 32-77s-9-75-42-75c-5 0-33 2-33 10 0 2 6 5 11 6 7 3 15 11 15 26 0 17-11 27-26 27-17 0-31-11-31-32 0-25 22-50 69-50 65 0 93 45 93 87 0 54-30 92-83 92-11 0-18-2-24-4-4-1-8-1-11 1-6 3-14 16-14 24s8 21 14 24c3 2 7 2 11 1 6-2 13-4 24-4 53 0 83 38 83 92 0 42-28 87-93 87-47 0-69-25-69-50 0-21 14-32 31-32 15 0 26 10 26 27 0 15-8 23-15 26-5 1-11 4-11 6 0 8 28 10 33 10 33 0 42-23 42-75s-7-77-32-77c-28 0-38 20-43 37-2 7-4 11-8 11s-6-4-7-10c-9-45-25-55-36-58-1 0-3-1-3 2v174c0 5-3 8-8 8h-1c-5 0-8-3-8-8V9c0-5 3-8 8-8h1c5 0 8 3 8 8ZM8 1h34c6 0 9 3 9 8v382c0 5-3 8-9 8H8c-5 0-8-3-8-8V9c0-5 3-8 8-8Z",xOffset:0,yOffset:0},NOTE_HEAD_WHOLE:{path:"M77 0c34 0 74 19 74 45 0 24-19 45-77 45C21 90 0 68 0 45 0 20 30 0 77 0Zm-9 8c-17 0-30 5-30 24 0 22 23 50 47 50 16 0 28-8 28-26 0-21-20-48-45-48Z",xOffset:0,yOffset:-4.5},NOTE_HEAD_HALF:{path:"M35 90C15 90 0 79 0 60 0 42 17 0 70 0c21 0 36 12 36 30 0 12-12 60-71 60Zm-8-14c18 0 68-31 68-47l-2-6c-3-5-7-8-14-8-17 0-68 29-68 46l2 7c2 4 7 8 14 8Z",xOffset:0,yOffset:-4.5},NOTE_HEAD_QUARTER:{path:"M35 90C16 90 0 79 0 60 0 29 32 0 71 0c20 0 35 12 35 30 0 30-40 60-71 60Z",xOffset:0,yOffset:-4.5},EIGHTH_NOTE:{path:"M142 89c20 32 36 70 36 110 0 25-8 55-8 55-2 5-5 7-8 6h-1c-2-1-5-4-5-9l1-5c5-14 8-29 8-44 0-19-3-37-8-48-10-23-33-58-53-70v179c0 30-38 60-70 60-19 0-34-11-34-30 0-31 31-60 70-60 11 0 19 3 25 8V3c0-2 2-3 3-3 6 0 9 2 10 7 5 31 18 57 34 82Z",xOffset:0,yOffset:-28},EIGHTH_NOTE_FLIPPED:{path:"M9 323H0V60C0 29 32 0 71 0c20 0 35 12 35 30 0 30-40 60-71 60-19 0-26-9-26-9v158s58-56 58-89c0 0 0-25-8-43-5-12 10-17 14-6 13 34 9 48 9 48 0 39-41 97-41 97-20 27-32 77-32 77Z",xOffset:0,yOffset:-4},REST_WHOLE:{path:"M0 0h104v53H0V0Z",xOffset:0,yOffset:0},REST_HALF:{path:"M0 0h104v53H0V0Z",xOffset:0,yOffset:-5},REST_QUARTER:{path:"m28 151-18-22s-3-4-3-9c0-3 1-7 5-11 16-17 22-33 22-46 0-27-21-45-23-49l-1-6c0-5 4-8 7-8s5 1 7 3l61 71 1 7-1 5c-10 15-23 34-25 55v3c0 20 11 35 25 52 4 4 14 16 14 20 0 2-2 2-5 1-6-2-19-6-29-6-16 0-23 12-23 27 0 8 5 22 11 22 3 3 6 6 6 9s-2 5-7 5l-9-3c-27-21-43-39-43-57s13-35 32-35c3 0 10 3 14 0l-2-6-16-22Z",xOffset:0,yOffset:-16},REST_EIGHTH:{path:"M61 35c18 0 41-35 47-32 0 1 5 3 5 8l-5 17S64 189 62 190c-4 4-11 5-16 5-3 0-13 0-13-6 8-30 41-122 42-128 1-5 1-10-1-10-4 0-3 3-19 8C16 71 0 46 0 31 0 14 14 0 31 0c5 0 30 1 30 35Z",xOffset:0,yOffset:-10},ACCIDENTAL_SHARP:{path:"m67 66-8 3c-2 0-3 6-3 8v26c0 4 2 5 3 5l8-2 1-1c1 0 2 1 2 3v20c0 1-1 4-3 4l-8 4c-2 0-3 4-3 6v40c0 2-2 4-5 4-2 0-4-2-4-4v-35c0-2-1-5-4-5h-1l-17 7c-1 1-3 3-3 6v40c0 2-1 3-4 3-2 0-4-1-4-3v-35c0-1-1-5-3-5l-1 1-7 2v1c-2 0-3-1-3-3v-20c0-2 1-4 3-5l8-3c2-1 3-3 3-6V94c0-3-2-5-4-5l-7 3c-2 0-3-1-3-3V69l3-4 8-3c1-1 3-4 3-8V16c0-2 2-4 5-4 2 0 3 2 3 4v34c0 2 1 5 4 5l18-7c2-1 3-5 3-8V3c0-2 2-3 5-3 2 0 4 1 4 3v35c0 2 2 3 4 3l7-2h1c1 0 2 0 2 2v20c0 2-1 4-3 5Zm-20 46c2-11 2-23 0-34l-4-2c-7 0-20 6-21 11v35l4 1c6 0 20-5 21-11Z",xOffset:-8,yOffset:-10},ACCIDENTAL_FLAT:{path:"M4 196C1 193 0 9 0 9c0-6 5-9 10-9 3 0 6 2 6 5l-2 91c0 3 1 5 3 6h2l7-4c5-3 12-6 18-6 15 1 29 13 29 31 0 15-10 35-39 55-8 5-16 14-25 19l-2 1c-1 0-2 0-3-2Zm11-28c0 1 1 5 4 5l3-1c14-9 29-27 29-44 0-8-4-19-14-19-7 0-20 10-22 16l-1 10 1 33Z",xOffset:-8,yOffset:-14},ACCIDENTAL_NATURAL:{path:"m41 47 5-2h1l2 2v147c0 3-2 4-3 4h-4c-2 0-4-1-4-4v-43c0-2-2-3-5-3-8 0-25 7-29 8l-1 1c-2 0-3-1-3-3V4c0-3 1-4 4-4h3c2 0 4 1 4 4v48c0 2 1 2 3 2 7 0 26-7 26-7h1ZM11 88v31l3 1c8 0 24-6 24-12V78l-2-1c-7 0-25 7-25 11Z",xOffset:-8,yOffset:-10},ACCIDENTAL_DOUBLE_SHARP:{path:"M68 33h3c6 0 13 0 15-2l2-15C88 4 86 0 72 0c-6 0-12 1-14 4-2 1-2 7-2 13-1 5-8 17-12 17-5 0-9-10-11-15l-1-2c0-6-1-12-3-13-2-3-8-4-13-4C10 0 4 1 2 4L0 17l2 14c2 2 9 2 15 2h4c5 2 16 8 16 12 0 3-13 10-17 12h-3c-6 0-13 1-15 3L0 74l2 14 14 2 13-2c2-2 3-8 3-14 1-5 7-17 12-17 4 0 10 13 12 17 0 6 0 12 2 14l14 2c15 0 16-2 16-17l-2-13c-4-2-11-3-15-3h-3c-5-2-17-7-17-12 0-2 13-10 17-12Z",xOffset:-10,yOffset:-4},ACCIDENTAL_DOUBLE_FLAT:{path:"M102 93h2c15 0 29 12 29 30 0 15-10 35-39 55-8 5-16 14-26 19l-2 1-2-2-3-43c-6 7-15 16-27 25-7 5-15 14-25 19l-2 1c-1 0-2 0-3-2C2 193 0 8 0 8c0-5 6-8 10-8 3 0 6 2 6 5l-2 91c0 3 1 5 3 6h2c3 0 5-3 8-4 5-3 9-5 15-5h2c6 0 12 1 17 5L60 8c0-5 5-8 10-8 3 0 6 2 6 5l-2 91c0 3 1 5 3 6h2c3 0 5-3 7-4 6-3 10-5 16-5Zm-80 78c14-9 29-25 29-43 0-8-3-19-13-19-8 0-21 10-23 16l-1 11 1 31c0 2 1 5 4 5l3-1Zm59 0c15-9 29-25 29-43 0-6-2-12-5-16-2-2-4-3-8-3-7 0-21 10-23 16v8l1 34c0 2 1 5 3 5l3-1Z",xOffset:-14,yOffset:-14},TIME_4:{path:"M53 0h66S70 76 20 124h61V86l47-50v89h22v19h-22v27c0 9 13 9 13 9h9v10H61v-10h10s10 0 10-10v-26H0v-20S54 67 53 0Z",xOffset:0,yOffset:0},TIME_3:{path:"M2 43c0 21 15 30 30 30 5 0 28-2 28-27 0-11-16-20-16-24 0-14 56-15 56 26 0 26-19 38-31 38H45v13h24c12 0 33 15 33 41 0 38-54 40-54 25 0-3 10-11 10-21 0-20-15-27-27-27-17 0-32 8-31 30 1 30 36 43 75 43 36 0 75-19 75-50 0-34-23-47-37-47v-2c4 0 35-13 35-39 0-37-35-52-75-52C39 0 3 14 2 43Z",xOffset:0,yOffset:0}},M=/^(?<name>[A-Ga-g])(?<accidental>##|bb|[#bn]?)(?<octave>\d)(?<duration>[whqeWHQE]?)$/,Y=/^[whqeWHQE]$/,T=["C","D","E","F","G","A","B"];function m(h){const e=h.match(M);if(!e||!e.groups)throw new Error(`Invalid note string format: ${h}. Expected format: [A-Ga-g][#|b]?[0-9][w|h|q|e].`);let{name:t,accidental:s,octave:r,duration:o}=e.groups;if(t=t.toUpperCase(),o=o.toLowerCase(),!t)throw new Error(`Invalid note name: ${t}. Valid note names are: C, D, E, F, G, A, B.`);if(!r)throw new Error(`Invalid octave: ${r}. Octave must be a number between 0 and 9.`);o||(o="w");const n={name:t,octave:parseInt(r),duration:o};return s&&(n.accidental=s),n}function C(h){const e=h.match(Y);if(!e)throw new Error(`Invalid note duration '${h}'. Use w | h | q | e.`);return e.toString().toLowerCase()}function L(h){let e;switch(h){case"treble":e="CLEF_TREBLE";break;case"bass":e="CLEF_BASS";break;case"alto":e="CLEF_ALTO";break}if(!e)throw new Error(`Invalid clef type: ${h}. Valid clef types are: treble, bass, alto.`);return e}function b(h,e){const t=T.indexOf(h.name)-T.indexOf(e.name);let s=h.octave-e.octave;return s*=7,t+s}function F(h){let e=T.indexOf(h.name);return e+=h.octave*12,e}function v(h,e){return T.findIndex(s=>s===h)+1+e*7}const g=48,G=40+30/2,B=20,D=90;class H{params;rendererRef;width=0;constructor(e,t){this.rendererRef=e;const s=w[t];if(!s)throw new Error(`Staff type ${t} is not supported`);this.params=s}drawStaffLines=(e,t)=>{let s=e;for(let r=0;r<5;r++)this.rendererRef.drawLine(0,s,this.width,s,t),s+=10;return s-10};drawStaff=e=>{this.width=e;const t=this.rendererRef.getLayerByName("staff");let s=this.drawStaffLines(0,t),r=this.drawStaffLines(s+30,t);this.rendererRef.drawLine(0,0,0,r,t),this.rendererRef.drawLine(this.width,0,this.width,r,t);let o=r,n=1;const a=L("treble"),i=L("bass");this.rendererRef.drawGlyph(a,t),this.rendererRef.drawGlyph(i,t,{yOffset:s+30}),o+=this.params.paddingBottom+1,n+=this.params.paddingTop,this.rendererRef.addTotalRootSvgHeight(o),this.rendererRef.addTotalRootSvgYOffset(n)};shouldNoteFlip(e){const t=Math.abs(e-D),s=Math.abs(e-B);return e===G?!1:t<=s?!(e>=D):e<=B}getLedgerLinesX(e,t){const s=[],r=F(e);let o=e.duration==="w"?17:12.5;if(r===g)return s.push({x1:-2,x2:o,yPos:0}),s;if(t<this.params.topLineYPos){let n=this.params.topLineYPos-10;for(;n>=t;)s.push({x1:-2,x2:o,yPos:n-t}),n-=10}else if(t>this.params.bottomLineYPos){let n=this.params.bottomLineYPos+10;for(;n<=t;)s.push({x1:-2,x2:o,yPos:n-t}),n+=10}return s}calculateNoteYPos=e=>{let s=b(this.params.topLineNote,e)*(10/2);const r=F(e);return r<g?s+=10:r===g&&(s=G),s}}const $=20;class A{params;rendererRef;constructor(e,t){this.rendererRef=e;const s=w[t];if(!s)throw new Error(`Staff type ${t} is not supported`);this.params=s}drawStaff=e=>{const t=this.rendererRef.getLayerByName("staff");let s=0;for(let a=0;a<5;a++)this.rendererRef.drawLine(0,s,e,s,t),s+=10;this.rendererRef.drawLine(0,0,0,s-10,t),this.rendererRef.drawLine(e,0,e,s-10,t);let r=s-10+1,o=1;const n=L(this.params.staffType);this.rendererRef.drawGlyph(n,t),r+=this.params.paddingTop+this.params.paddingBottom,o+=this.params.paddingTop,this.rendererRef.addTotalRootSvgHeight(r),this.rendererRef.addTotalRootSvgYOffset(o)};shouldNoteFlip(e){return e<=$}getLedgerLinesX(e,t){const s=[];let r=e.duration==="w"?17:12.5;if(t<this.params.topLineYPos){let o=this.params.topLineYPos-10;for(;o>=t;)s.push({x1:-2,x2:r,yPos:o-t}),o-=10}else if(t>this.params.bottomLineYPos){let o=this.params.bottomLineYPos+10;for(;o<=t;)s.push({x1:-2,x2:r,yPos:o-t}),o+=10}return s}calculateNoteYPos=e=>b(this.params.topLineNote,e)*(10/2)}class P{svgRendererInstance;strategyInstance;constructor(e,t){this.svgRendererInstance=e,this.strategyInstance=t}drawStem(e,t){t?this.svgRendererInstance.drawLine(0,0,0,28,e):this.svgRendererInstance.drawLine(10,0,10,-28,e)}chordOffsetConsecutiveAccidentals(e){let t=0,s=0,r=0;for(let o=0;o<e.length;o++){const n=e[o];if(n.noteObj.accidental&&r<3?(t+=-8,s=Math.min(s,t),r++):n.noteObj.accidental&&r<=3?(t=-8,r=1):(t=0,r=0),t!==0){const i=Array.from(n.noteGroup.getElementsByTagName("use")).find(c=>c.getAttribute("href")?.includes("ACCIDENTAL"));if(!i)continue;i.setAttribute("transform",`translate(${t+8}, 0)`)}}return-s}chordOffsetCloseNotes(e){let t=e[0],s=0;for(let r=1;r<e.length;r++){const o=e[r];if(v(o.noteObj.name,o.noteObj.octave)-v(t.noteObj.name,t.noteObj.octave)===1){s=28/2,o.noteGroup.setAttribute("transform",`translate(${s}, ${o.noteYPos})`);const i=Array.from(o.noteGroup.getElementsByTagName("use")).find(c=>c.getAttribute("href")?.includes("ACCIDENTAL"));if(i){const c=i.getAttribute("transform")?.match(/([-]?\d+)/),l=c&&c[0];let f=-s;l&&(f+=Number(l)),i.setAttribute("transform",`translate(${f}, 0)`)}r++,t=e[r];continue}t=o}return s}renderNote(e){const t=this.svgRendererInstance.createGroup("note"),s=m(e),r=this.strategyInstance.calculateNoteYPos({name:s.name,octave:s.octave});let o=this.strategyInstance.shouldNoteFlip(r);switch(s.duration){case"h":this.svgRendererInstance.drawGlyph("NOTE_HEAD_HALF",t),this.drawStem(t,o);break;case"q":this.svgRendererInstance.drawGlyph("NOTE_HEAD_QUARTER",t),this.drawStem(t,o);break;case"e":o?this.svgRendererInstance.drawGlyph("EIGHTH_NOTE_FLIPPED",t):this.svgRendererInstance.drawGlyph("EIGHTH_NOTE",t);break;default:this.svgRendererInstance.drawGlyph("NOTE_HEAD_WHOLE",t)}let n=0;switch(s.accidental){case"#":this.svgRendererInstance.drawGlyph("ACCIDENTAL_SHARP",t),n-=-8;break;case"b":this.svgRendererInstance.drawGlyph("ACCIDENTAL_FLAT",t),n-=-8;break;case"n":this.svgRendererInstance.drawGlyph("ACCIDENTAL_NATURAL",t),n-=-8;break;case"##":this.svgRendererInstance.drawGlyph("ACCIDENTAL_DOUBLE_SHARP",t),n-=-10;break;case"bb":this.svgRendererInstance.drawGlyph("ACCIDENTAL_DOUBLE_FLAT",t),n-=-14;break}return this.strategyInstance.getLedgerLinesX(s,r).forEach(i=>{this.svgRendererInstance.drawLine(i.x1,i.yPos,i.x2,i.yPos,t)}),{noteGroup:t,noteObj:s,noteYPos:r,accidentalOffset:n,cursorOffset:0}}renderChord(e){const t=this.svgRendererInstance.createGroup("chord"),s=[];for(const n of e){const a=this.renderNote(n);a.noteGroup.setAttribute("transform",`translate(0, ${a.noteYPos})`),t.appendChild(a.noteGroup),s.push({noteGroup:a.noteGroup,noteObj:a.noteObj,noteYPos:a.noteYPos,cursorOffset:0,accidentalOffset:0})}const r=this.chordOffsetConsecutiveAccidentals(s),o=this.chordOffsetCloseNotes(s);return{noteGroup:t,noteObj:s[0].noteObj,noteYPos:0,accidentalOffset:r,cursorOffset:o}}}const p="http://www.w3.org/2000/svg",k=.1,S=1200;class O{rootElementRef;svgElementRef;parentGroupContainer;musicStaffLayer;musicNotesLayer;musicUILayer;width;scale;totalYOffset=0;totalHeight=0;constructor(e,t){this.rootElementRef=e,this.width=t.width,this.scale=t.scale,this.width>S&&(this.width=S,console.warn(`Width provided for the staff ${this.width} exceeds the limit ${S}. Please use this value to fix positioning issues.`)),this.svgElementRef=document.createElementNS(p,"svg"),this.svgElementRef.classList.add("vs-svg-renderer-root"),this.svgElementRef.style.maxWidth="100%",this.svgElementRef.style.height="auto",this.svgElementRef.style.display="block",this.svgElementRef.setAttribute("color",t.staffColor),this.svgElementRef.style.backgroundColor=t.staffBackgroundColor,this.makeGlyphDefs(t.useGlyphs),this.parentGroupContainer=this.createGroup("svg-renderer-parent"),this.svgElementRef.appendChild(this.parentGroupContainer),this.musicStaffLayer=this.createGroup("music-staff-layer"),this.musicNotesLayer=this.createGroup("music-notes-layer"),this.musicUILayer=this.createGroup("music-ui-layer"),this.parentGroupContainer.appendChild(this.musicStaffLayer),this.parentGroupContainer.appendChild(this.musicNotesLayer),this.parentGroupContainer.appendChild(this.musicUILayer)}makeGlyphDefs(e){const t=document.createElementNS(p,"defs");Object.entries(U).filter(([r])=>e.includes(r)).forEach(([r,o])=>{const n=document.createElementNS(p,"path");n.setAttribute("id",`glyph-${r}`),n.setAttribute("d",o.path),n.setAttribute("fill","currentColor"),n.setAttribute("transform",`translate(${o.xOffset}, ${o.yOffset}) scale(${k})`),t.appendChild(n)}),this.rootSvgElement.appendChild(t)}createGroup(e){const t=document.createElementNS(p,"g");return e&&t.classList.add(`vs-${e}`),t}commitElementsToDOM(e,t=this.rootElementRef){const s=document.createDocumentFragment();Array.isArray(e)?e.forEach(r=>{s.appendChild(r)}):s.appendChild(e),t.appendChild(s)}getLayerByName(e){switch(e){case"staff":return this.musicStaffLayer;case"notes":return this.musicNotesLayer;case"ui":return this.musicUILayer;default:throw new Error(`Layer with name '${e}' does not exist.`)}}addTotalRootSvgHeight(e){this.totalHeight+=e}addTotalRootSvgYOffset(e){this.totalYOffset+=e}applySizingToRootSvg(){this.parentGroupContainer.setAttribute("transform",`translate(0, ${this.totalYOffset})`);let e=this.width*this.scale;const t=(this.totalHeight+this.totalYOffset)*this.scale;e+=2,this.svgElementRef.setAttribute("width",e.toString()),this.svgElementRef.setAttribute("height",t.toString()),this.svgElementRef.setAttribute("viewBox",`0 0 ${this.width} ${this.totalHeight+this.totalYOffset}`)}get rootSvgElement(){return this.svgElementRef}get parentGroupElement(){return this.parentGroupContainer}drawLine(e,t,s,r,o){const n=document.createElementNS(p,"line");n.setAttribute("x1",e.toString()),n.setAttribute("y1",t.toString()),n.setAttribute("x2",s.toString()),n.setAttribute("y2",r.toString()),n.setAttribute("stroke","currentColor"),n.setAttribute("stroke-width","1"),o.appendChild(n)}drawRect(e,t,s,r){const o=document.createElementNS(p,"rect");return o.setAttribute("width",e.toString()),o.setAttribute("height",t.toString()),o.setAttribute("x",(r?.x??0).toString()),o.setAttribute("y",(r?.y??0).toString()),r?.fill?o.setAttribute("fill",r.fill):o.setAttribute("fill","currentColor"),s.appendChild(o),o}drawGlyph(e,t,s){s={xOffset:0,yOffset:0,...s};const r=document.createElementNS(p,"use");r.setAttribute("href",`#glyph-${e}`),(s.xOffset||s.yOffset)&&r.setAttribute("transform",`translate(${s.xOffset}, ${s.yOffset})`),t.appendChild(r)}destroy(){this.rootElementRef&&this.svgElementRef&&this.rootElementRef.contains(this.svgElementRef)&&this.rootElementRef.removeChild(this.svgElementRef)}}const W=["CLEF_TREBLE","CLEF_BASS","CLEF_ALTO","NOTE_HEAD_WHOLE","NOTE_HEAD_HALF","NOTE_HEAD_QUARTER","EIGHTH_NOTE","EIGHTH_NOTE_FLIPPED","ACCIDENTAL_SHARP","ACCIDENTAL_FLAT","ACCIDENTAL_NATURAL","ACCIDENTAL_DOUBLE_SHARP","ACCIDENTAL_DOUBLE_FLAT"];class Z{svgRendererInstance;strategyInstance;noteRendererInstance;options;noteEntries=[];noteCursorX=0;noteStartX;constructor(e,t){this.options={width:300,scale:1,noteStartX:0,staffType:"treble",spaceAbove:0,spaceBelow:0,staffColor:"black",staffBackgroundColor:"transparent",...t},this.svgRendererInstance=new O(e,{width:this.options.width,height:100,scale:this.options.scale,staffColor:this.options.staffColor,staffBackgroundColor:this.options.staffBackgroundColor,useGlyphs:W});const s=this.svgRendererInstance.rootSvgElement;switch(this.options.staffType){case"grand":this.strategyInstance=new H(this.svgRendererInstance,"grand");break;case"bass":this.strategyInstance=new A(this.svgRendererInstance,"bass");break;case"treble":this.strategyInstance=new A(this.svgRendererInstance,"treble");break;case"alto":this.strategyInstance=new A(this.svgRendererInstance,"alto");break;default:throw new Error(`The staff type ${this.options.staffType} is not supported. Please use "treble", "bass", "alto", or "grand".`)}if(this.strategyInstance.drawStaff(this.options.width),this.noteRendererInstance=new P(this.svgRendererInstance,this.strategyInstance),this.options.spaceAbove){const r=this.options.spaceAbove*10;this.svgRendererInstance.addTotalRootSvgYOffset(r)}if(this.options.spaceBelow){let r=this.options.spaceBelow*10;this.options.staffType==="grand"&&(r-=10/2),this.svgRendererInstance.addTotalRootSvgHeight(r)}this.noteStartX=38+this.options.noteStartX,this.svgRendererInstance.getLayerByName("notes").setAttribute("transform",`translate(${this.noteStartX}, 0)`),this.svgRendererInstance.applySizingToRootSvg(),this.svgRendererInstance.commitElementsToDOM(s)}drawNote(e){const t=Array.isArray(e)?e:[e],s=this.svgRendererInstance.getLayerByName("notes"),r=[];for(const o of t){let n;try{n=this.noteRendererInstance.renderNote(o)}catch(a){throw r.length>0&&this.svgRendererInstance.commitElementsToDOM(r,s),a}n.noteGroup.setAttribute("transform",`translate(${this.noteCursorX+n.accidentalOffset}, ${n.noteYPos})`),this.noteEntries.push({gElement:n.noteGroup,note:n.noteObj,xPos:this.noteCursorX+n.accidentalOffset,yPos:n.noteYPos,accidentalXOffset:n.accidentalOffset}),this.noteCursorX+=28+n.accidentalOffset,r.push(n.noteGroup)}this.svgRendererInstance.commitElementsToDOM(r,s)}drawChord(e){if(e.length<2)throw new Error("Provide more than one note for a chord.");const t=this.svgRendererInstance.getLayerByName("notes"),s=this.noteRendererInstance.renderChord(e);s.noteGroup.setAttribute("transform",`translate(${this.noteCursorX+s.accidentalOffset}, 0)`),this.noteEntries.push({gElement:s.noteGroup,note:m(e[0]),xPos:this.noteCursorX+s.accidentalOffset,yPos:0,accidentalXOffset:s.accidentalOffset}),this.noteCursorX+=28+s.accidentalOffset+s.cursorOffset,this.svgRendererInstance.commitElementsToDOM(s.noteGroup,t)}justifyNotes(){const e=this.options.width-38,t=this.noteEntries.length;if(t<=0||e<=0)return;const s=Math.round(e/t);this.noteEntries.map((o,n)=>{const a=(n+.5)*s,i=o.gElement.getBBox(),c=a-i.width/2-i.x,l=Math.round(c*10)/10;return{entry:o,newX:l,isChord:o.gElement.classList.contains("chord")}}).forEach(o=>{const{entry:n,newX:a,isChord:i}=o;i?n.gElement.setAttribute("transform",`translate(${a}, 0)`):n.gElement.setAttribute("transform",`translate(${a}, ${n.yPos})`),n.xPos=a})}clearAllNotes(){this.noteCursorX=0,this.svgRendererInstance.getLayerByName("notes").replaceChildren(),this.noteEntries=[]}changeNoteByIndex(e,t){if(t>=this.noteEntries.length)throw new Error("Note index was out of bounds.");const s=this.noteEntries[t],r=this.noteRendererInstance.renderNote(e),n=s.xPos-s.accidentalXOffset+r.accidentalOffset;r.noteGroup.setAttribute("transform",`translate(${n}, ${r.noteYPos})`),this.svgRendererInstance.getLayerByName("notes").replaceChild(r.noteGroup,s.gElement),this.noteEntries[t]={gElement:r.noteGroup,note:r.noteObj,xPos:n,yPos:r.noteYPos,accidentalXOffset:r.accidentalOffset}}changeChordByIndex(e,t){if(t>=this.noteEntries.length)throw new Error("Chord index was out of bounds.");if(e.length<2)throw new Error("Notes provided need to be more than one to be considered a chord.");const s=this.noteEntries[t],r=this.noteRendererInstance.renderChord(e),n=s.xPos-s.accidentalXOffset+r.accidentalOffset;r.noteGroup.setAttribute("transform",`translate(${n}, 0)`),this.svgRendererInstance.getLayerByName("notes").replaceChild(r.noteGroup,s.gElement),this.noteEntries[t]={gElement:r.noteGroup,note:m(e[0]),xPos:n,yPos:0,accidentalXOffset:r.accidentalOffset}}addClassToNoteByIndex(e,t){if(t>=this.noteEntries.length)throw new Error("Note index was out of bounds.");this.noteEntries[t].gElement.classList.add(e)}removeClassToNoteByIndex(e,t){if(t>=this.noteEntries.length)throw new Error("Note index was out of bounds.");this.noteEntries[t].gElement.classList.remove(e)}destroy(){this.noteEntries=[],this.svgRendererInstance.destroy()}}const u=30,X=19,y=12,V=4,j=6,x=1,R=38,q=["TIME_4","TIME_3","NOTE_HEAD_WHOLE","NOTE_HEAD_HALF","NOTE_HEAD_QUARTER","EIGHTH_NOTE","REST_WHOLE","REST_HALF","REST_QUARTER","REST_EIGHTH"];class Q{rendererInstance;options;barSpacing;quarterNoteSpacing;noteCursorX=0;noteEntries=[];maxBeatCount;currentBeatCount=0;currentBeatUICount=0;currentBeatUIElement=null;currentBeatUIXPos=R;constructor(e,t){this.options={width:300,scale:1,topNumber:4,barsCount:2,spaceAbove:0,spaceBelow:0,staffColor:"black",staffBackgroundColor:"white",currentBeatUIColor:"#24ff7450",...t},this.rendererInstance=new O(e,{width:this.options.width,height:100,scale:this.options.scale,staffColor:this.options.staffColor,staffBackgroundColor:this.options.staffBackgroundColor,useGlyphs:q});const s=this.rendererInstance.rootSvgElement;let r="TIME_4";switch(this.options.topNumber){case 3:r="TIME_3";break;case 4:r="TIME_4";break;default:throw new Error(`Time signature ${this.options.topNumber} not supported. Please use either 3 or 4.`)}if(this.options.barsCount<1||this.options.barsCount>3)throw new Error(`Bars count ${this.options.barsCount} not supported. Please use 1 - 3`);if(this.options.spaceAbove){const _=this.options.spaceAbove*10;this.rendererInstance.addTotalRootSvgYOffset(_)}if(this.options.spaceBelow){let _=this.options.spaceBelow*10;this.rendererInstance.addTotalRootSvgHeight(_)}const o=this.rendererInstance.getLayerByName("staff");this.rendererInstance.addTotalRootSvgHeight(u*2);const n=this.rendererInstance.createGroup("time-signature");o.appendChild(n);const a=u-X;this.rendererInstance.drawGlyph(r,n),this.rendererInstance.drawGlyph("TIME_4",n,{yOffset:X}),n.setAttribute("transform",`translate(0, ${a})`);let i=this.options.width-38;this.options.barsCount>1&&(i-=(this.options.barsCount-1)*y),i-=x,this.rendererInstance.drawLine(0,u,this.options.width-x,u,o),this.barSpacing=i/this.options.barsCount,this.quarterNoteSpacing=Math.round(this.barSpacing/this.options.topNumber),this.maxBeatCount=this.options.barsCount*this.options.topNumber;let c=this.barSpacing+38;const l=u/2,f=u+l;for(let _=0;_<this.options.barsCount-1;_++)this.rendererInstance.drawLine(c,l,c,f,o),c+=this.barSpacing;this.rendererInstance.getLayerByName("notes").setAttribute("transform",`translate(38, ${u})`),this.rendererInstance.applySizingToRootSvg(),this.rendererInstance.commitElementsToDOM(s)}createBeatUIElement(){const e=this.rendererInstance.getLayerByName("ui");this.currentBeatUIElement=this.rendererInstance.drawRect(this.quarterNoteSpacing/2,u*2,e,{x:R,fill:this.options.currentBeatUIColor})}handleNewBar(){this.noteCursorX+=y}translateGroupByDuration(e,t){return t.setAttribute("transform",`translate(${this.noteCursorX}, 0)`),this.quarterNoteSpacing*e}drawStem(e,t){this.rendererInstance.drawLine(10+(t??0),0,10+(t??0),-28,e)}renderNote(e,t){switch(e){case"w":this.rendererInstance.drawGlyph("NOTE_HEAD_WHOLE",t);break;case"h":this.rendererInstance.drawGlyph("NOTE_HEAD_HALF",t),this.drawStem(t);break;case"q":this.rendererInstance.drawGlyph("NOTE_HEAD_QUARTER",t),this.drawStem(t);break;case"e":this.rendererInstance.drawGlyph("EIGHTH_NOTE",t),this.drawStem(t);break}}renderRest(e,t){switch(e){case"w":this.rendererInstance.drawGlyph("REST_WHOLE",t);break;case"h":this.rendererInstance.drawGlyph("REST_HALF",t);break;case"q":this.rendererInstance.drawGlyph("REST_QUARTER",t);break;case"e":this.rendererInstance.drawGlyph("REST_EIGHTH",t);break}}checkAndCreateNewBar(){const e=this.currentBeatCount>0&&this.currentBeatCount%this.options.topNumber===0,t=this.currentBeatCount<this.maxBeatCount;e&&t&&this.handleNewBar()}checkAndFillBarWithRests(e){const t=this.options.topNumber-this.currentBeatCount%this.options.topNumber;if(e>t){const s=this.createRemainingRests(t);return this.handleNewBar(),s}return null}createRemainingRests(e){const t=[];let s=e;for(;s>0;){const r=this.rendererInstance.createGroup("rest");let o=0;s-E.h>=0?(this.rendererInstance.drawGlyph("REST_HALF",r),o=E.h):s-E.q>=0?(this.rendererInstance.drawGlyph("REST_QUARTER",r),o=E.q):(this.rendererInstance.drawGlyph("REST_EIGHTH",r),o=E.e),s-=o,this.currentBeatCount+=o,r.setAttribute("transform",`translate(${this.noteCursorX}, 0)`),this.noteCursorX+=o*this.quarterNoteSpacing,t.push(r)}return t}renderBeamRect(e,t,s,r){this.rendererInstance.drawRect(e-t,V,s,{x:10,y:-28+(r??0),fill:this.options.staffColor})}drawNote(e){const t=Array.isArray(e)?e:[e],s=this.rendererInstance.getLayerByName("notes"),r=[];for(const o of t){let n="w";try{n=C(o)}catch(f){throw r.length>0&&this.rendererInstance.commitElementsToDOM(r,s),f}const a=E[n];if(this.currentBeatCount>=this.maxBeatCount)throw r.length>0&&this.rendererInstance.commitElementsToDOM(r,s),new Error("Max beat count reached. Can't add additional notes.");this.checkAndCreateNewBar();const i=this.checkAndFillBarWithRests(a);i&&i.forEach(f=>{r.push(f),this.noteEntries.push(f)});const c=this.rendererInstance.createGroup("note"),l=this.translateGroupByDuration(a,c);this.noteCursorX+=l,this.currentBeatCount+=a,this.renderNote(n,c),r.push(c),this.noteEntries.push(c)}this.rendererInstance.commitElementsToDOM(r,s)}drawRest(e){const t=Array.isArray(e)?e:[e],s=this.rendererInstance.getLayerByName("notes"),r=[];for(const o of t){let n="w";try{n=C(o)}catch(f){throw r.length>0&&this.rendererInstance.commitElementsToDOM(r,s),f}const a=this.rendererInstance.createGroup("rest"),i=E[n],c=i*this.quarterNoteSpacing;if(this.currentBeatCount>=this.maxBeatCount)throw r.length>0&&this.rendererInstance.commitElementsToDOM(r,s),new Error("Max beat count reached. Can't add additional notes.");this.checkAndCreateNewBar();const l=this.checkAndFillBarWithRests(i);l&&l.forEach(f=>{r.push(f),this.noteEntries.push(f)}),this.renderRest(n,a),a.setAttribute("transform",`translate(${this.noteCursorX}, 0)`),this.noteCursorX+=c,this.currentBeatCount+=i,r.push(a),this.noteEntries.push(a)}this.rendererInstance.commitElementsToDOM(r,s)}drawBeamedNotes(e,t){if(t<2)throw new Error("Must provide a value greater than 2 for beamed note.");if(this.currentBeatCount>=this.maxBeatCount)throw new Error("Max beat count reached. Can't add additional beamed note.");let s="s";e==="s"?s="s":s=C(e),this.checkAndCreateNewBar();const r=this.rendererInstance.getLayerByName("notes"),o=E[s],n=o*this.quarterNoteSpacing,a=this.options.topNumber-this.currentBeatCount%this.options.topNumber,i=Math.min(t,a/o),c=this.rendererInstance.createGroup("beamed-note");c.setAttribute("transform",`translate(${this.noteCursorX}, 0)`);let l=0;for(let f=0;f<i;f++)this.rendererInstance.drawGlyph("NOTE_HEAD_QUARTER",c,{xOffset:l}),this.drawStem(c,l),l+=n,this.currentBeatCount+=o;this.renderBeamRect(l,n,c),e==="s"&&this.renderBeamRect(l,n,c,j),this.noteCursorX+=l,this.noteEntries.push(c),this.rendererInstance.commitElementsToDOM(c,r)}incrementCurrentBeatUI(){if(this.currentBeatUIElement||this.createBeatUIElement(),this.currentBeatUICount>=this.maxBeatCount){this.currentBeatUIElement.setAttribute("display","none");return}this.currentBeatUIElement?.getAttribute("display")==="none"&&this.currentBeatUIElement.removeAttribute("display"),this.currentBeatUICount++,this.currentBeatUICount>this.options.topNumber&&this.currentBeatUICount%this.options.topNumber===1&&(this.currentBeatUIXPos+=y),this.currentBeatUICount>1&&(this.currentBeatUIXPos+=this.quarterNoteSpacing),this.currentBeatUIElement.setAttribute("x",this.currentBeatUIXPos.toString())}resetCurrentBeatUI(){this.currentBeatUICount=0,this.currentBeatUIXPos=R,this.currentBeatUIElement&&(this.currentBeatUIElement.setAttribute("display","none"),this.currentBeatUIElement.setAttribute("x",this.currentBeatUIXPos.toString()))}clearAllNotes(){this.noteCursorX=0,this.currentBeatCount=0,this.rendererInstance.getLayerByName("notes").replaceChildren(),this.noteEntries=[]}destroy(){this.noteEntries=[],this.rendererInstance.destroy()}}const z=["CLEF_TREBLE","CLEF_BASS","CLEF_ALTO","NOTE_HEAD_WHOLE","NOTE_HEAD_HALF","NOTE_HEAD_QUARTER","EIGHTH_NOTE","EIGHTH_NOTE_FLIPPED","ACCIDENTAL_SHARP","ACCIDENTAL_FLAT","ACCIDENTAL_NATURAL","ACCIDENTAL_DOUBLE_SHARP","ACCIDENTAL_DOUBLE_FLAT"],N=60,K=N;class J{svgRendererInstance;strategyInstance;noteRendererInstance;options;activeEntries=[];noteBuffer=[];notesLayer;noteCursorX=0;noteStartX;constructor(e,t){this.options={width:300,scale:1,noteStartX:0,staffType:"treble",spaceAbove:0,spaceBelow:0,staffColor:"black",staffBackgroundColor:"transparent",...t},this.svgRendererInstance=new O(e,{width:this.options.width,height:100,scale:this.options.scale,staffColor:this.options.staffColor,staffBackgroundColor:this.options.staffBackgroundColor,useGlyphs:z});const s=this.svgRendererInstance.rootSvgElement;switch(this.options.staffType){case"grand":this.strategyInstance=new H(this.svgRendererInstance,"grand");break;case"bass":this.strategyInstance=new A(this.svgRendererInstance,"bass");break;case"treble":this.strategyInstance=new A(this.svgRendererInstance,"treble");break;case"alto":this.strategyInstance=new A(this.svgRendererInstance,"alto");break;default:throw new Error(`The staff type ${this.options.staffType} is not supported. Please use "treble", "bass", "alto", or "grand".`)}if(this.strategyInstance.drawStaff(this.options.width),this.noteRendererInstance=new P(this.svgRendererInstance,this.strategyInstance),this.options.spaceAbove){const r=this.options.spaceAbove*10;this.svgRendererInstance.addTotalRootSvgYOffset(r)}if(this.options.spaceBelow){let r=this.options.spaceBelow*10;this.options.staffType==="grand"&&(r-=10/2),this.svgRendererInstance.addTotalRootSvgHeight(r)}this.notesLayer=this.svgRendererInstance.getLayerByName("notes"),this.notesLayer.classList.add("vs-scrolling-notes-layer"),this.noteStartX=38+this.options.noteStartX,this.svgRendererInstance.getLayerByName("notes").setAttribute("transform",`translate(${this.noteStartX}, 0)`),this.svgRendererInstance.applySizingToRootSvg(),this.svgRendererInstance.commitElementsToDOM(s)}renderFirstNoteGroups(){const e=this.options.width-this.options.noteStartX+K;for(;this.noteBuffer.length>0&&this.noteCursorX<e;)this.renderNextNote(),this.noteCursorX+=N;this.activeEntries.length>1&&(this.noteCursorX-=N)}renderNextNote(){if(this.noteBuffer.length<1)return;const e=this.noteBuffer[0],t=this.svgRendererInstance.createGroup("note-wrapper");if(e.type==="chord"){const s=this.noteRendererInstance.renderChord(e.notes);s.noteGroup.setAttribute("transform",`translate(0, ${s.noteYPos})`),t.appendChild(s.noteGroup)}else{const s=this.noteRendererInstance.renderNote(e.notes[0]);s.noteGroup.setAttribute("transform",`translate(0, ${s.noteYPos})`),t.appendChild(s.noteGroup)}t.style.transform=`translate(${this.noteCursorX}px, 0px)`,this.activeEntries.push({noteWrapper:t,xPos:this.noteCursorX}),this.noteBuffer.shift(),this.notesLayer.appendChild(t)}queueNotes(e){this.clearAllNotes();for(const t of e)Array.isArray(t)?this.noteBuffer.push({type:"chord",notes:t}):this.noteBuffer.push({type:"note",notes:[t]});this.renderFirstNoteGroups()}advanceNotes(){if(this.activeEntries.length<=0){this.clearAllNotes(),this.options.onNotesOut&&this.options.onNotesOut();return}this.activeEntries.forEach(t=>{t.xPos-=N,t.noteWrapper.style.transform=`translate(${t.xPos}px, 0px)`});const e=this.activeEntries[0];e.xPos<=0&&(this.notesLayer.removeChild(e.noteWrapper),this.activeEntries.shift()),this.renderNextNote()}clearAllNotes(){this.noteCursorX=0,this.notesLayer.replaceChildren(),this.activeEntries=[],this.noteBuffer=[]}destroy(){this.svgRendererInstance.destroy(),this.activeEntries=[],this.noteBuffer=[]}}d.MusicStaff=Z,d.RhythmStaff=Q,d.ScrollingStaff=J,Object.defineProperty(d,Symbol.toStringTag,{value:"Module"})}));
|
|
1
|
+
(function(d,T){typeof exports=="object"&&typeof module<"u"?T(exports):typeof define=="function"&&define.amd?define(["exports"],T):(d=typeof globalThis<"u"?globalThis:d||self,T(d.VectorScore={}))})(this,(function(d){"use strict";const N={treble:{staffType:"treble",paddingTop:13,paddingBottom:3,topLineNote:{name:"F",octave:5},topLineYPos:0,bottomLineYPos:40},bass:{staffType:"bass",paddingTop:0,paddingBottom:0,topLineNote:{name:"A",octave:3},topLineYPos:0,bottomLineYPos:40},alto:{staffType:"alto",paddingTop:0,paddingBottom:0,topLineNote:{name:"G",octave:4},topLineYPos:0,bottomLineYPos:40},grand:{staffType:"grand",paddingTop:13,paddingBottom:0,topLineNote:{name:"F",octave:5},topLineYPos:0,bottomLineYPos:110}},E={w:4,h:2,q:1,e:.5,s:.25},F=8,k=40,v={sharp:["F","C","G","D","A","E","B"],flat:["B","E","A","D","G","C","F"]},D={C:{type:"sharp",count:0},G:{type:"sharp",count:1},D:{type:"sharp",count:2},A:{type:"sharp",count:3},E:{type:"sharp",count:4},B:{type:"sharp",count:5},"F#":{type:"sharp",count:6},F:{type:"flat",count:1},Bb:{type:"flat",count:2},Eb:{type:"flat",count:3},Ab:{type:"flat",count:4},Db:{type:"flat",count:5},Gb:{type:"flat",count:6}},C={treble:{sharp:[5,5,5,5,4,5,4],flat:[4,5,4,5,4,5,4]},bass:{sharp:[3,3,3,3,2,3,2],flat:[2,3,2,3,2,3,3]},alto:{sharp:[4,4,4,4,3,4,4],flat:[4,5,4,5,4,5,4]},grand:{sharp:[],flat:[]}};function $(h){const e=D[h];if(!e)throw new Error(`Unknown key signature "${h}". Valid keys: ${Object.keys(D).join(", ")}`);return e}function W(h,e,t,s){const n=$(t);if(n.count===0)return 0;const r=n.type==="sharp"?"ACCIDENTAL_SHARP":"ACCIDENTAL_FLAT",o=h.getLayerByName("staff");return e.getKeySignatureYPositions(n.type,n.count).forEach(i=>{i.forEach((c,l)=>{h.drawGlyph(r,o,{xOffset:s+l*F,yOffset:c})})}),n.count*F}const Z={CLEF_TREBLE:{path:"m150 273 10 58c2 7 2 7 12 7 59 0 96 46 96 97 0 45-26 79-67 95-5 2-6 2-5 7 4 25 12 63 12 85 0 68-52 80-79 80-61 0-76-39-76-65 0-25 16-46 43-46 24 0 38 19 38 41 0 23-14 34-27 38-9 2-13 4-13 6 0 6 11 12 32 12 24 0 64-7 64-66 0-19-6-54-11-81-1-5-1-4-6-3l-27 2C48 540 0 474 0 404c0-80 61-138 119-185 5-4 4-5 3-10-2-16-5-42-5-65 0-42 9-92 39-125 8-9 20-19 26-19 4 0 15 11 21 20 16 24 26 58 26 93 0 61-33 112-76 153-3 2-3 2-3 7Zm38-211c-24 0-53 38-53 101l2 37c1 5 3 5 5 3 32-28 70-64 70-108 0-22-11-33-24-33Zm-44 272-8-51c-1-4-2-5-6-1-18 15-37 30-61 56-33 38-37 70-37 93 0 56 45 95 115 95l23-2c6-2 6-2 5-6l-20-119c-1-5-1-5-8-3-24 6-40 24-40 46 0 19 12 36 29 43 3 1 6 3 6 5 0 3-2 5-5 5l-11-3c-27-9-46-34-46-70 0-34 23-66 58-78 8-2 8-2 6-10Zm28 64 20 114c0 5 1 5 6 2 22-11 38-31 38-56 0-36-27-63-60-66-4 0-5 1-4 6Z",xOffset:0,yOffset:-14},CLEF_BASS:{path:"M101 0c68 0 110 46 110 114 0 120-102 190-199 237l-7 2c-3 0-5-2-5-5s2-5 6-7c92-52 146-114 146-223 0-62-18-103-60-103-40 0-64 29-64 44 0 4 1 8 7 8 5 0 9-3 19-3 20 0 38 15 38 41 0 24-17 41-42 41-32 0-48-27-48-58C2 50 33 0 101 0Zm148 32c13 0 22 10 22 22s-9 22-22 22c-12 0-21-10-21-22s9-22 21-22Zm1 99c12 0 21 9 21 21s-9 22-21 22-21-10-21-22 9-21 21-21Z",xOffset:0,yOffset:0},CLEF_ALTO:{path:"M91 9v174c0 3 2 2 3 2 11-3 27-13 36-58 1-6 3-10 7-10s6 4 8 11c5 17 15 37 43 37 25 0 32-25 32-77s-9-75-42-75c-5 0-33 2-33 10 0 2 6 5 11 6 7 3 15 11 15 26 0 17-11 27-26 27-17 0-31-11-31-32 0-25 22-50 69-50 65 0 93 45 93 87 0 54-30 92-83 92-11 0-18-2-24-4-4-1-8-1-11 1-6 3-14 16-14 24s8 21 14 24c3 2 7 2 11 1 6-2 13-4 24-4 53 0 83 38 83 92 0 42-28 87-93 87-47 0-69-25-69-50 0-21 14-32 31-32 15 0 26 10 26 27 0 15-8 23-15 26-5 1-11 4-11 6 0 8 28 10 33 10 33 0 42-23 42-75s-7-77-32-77c-28 0-38 20-43 37-2 7-4 11-8 11s-6-4-7-10c-9-45-25-55-36-58-1 0-3-1-3 2v174c0 5-3 8-8 8h-1c-5 0-8-3-8-8V9c0-5 3-8 8-8h1c5 0 8 3 8 8ZM8 1h34c6 0 9 3 9 8v382c0 5-3 8-9 8H8c-5 0-8-3-8-8V9c0-5 3-8 8-8Z",xOffset:0,yOffset:0},NOTE_HEAD_WHOLE:{path:"M77 0c34 0 74 19 74 45 0 24-19 45-77 45C21 90 0 68 0 45 0 20 30 0 77 0Zm-9 8c-17 0-30 5-30 24 0 22 23 50 47 50 16 0 28-8 28-26 0-21-20-48-45-48Z",xOffset:0,yOffset:-4.5},NOTE_HEAD_HALF:{path:"M35 90C15 90 0 79 0 60 0 42 17 0 70 0c21 0 36 12 36 30 0 12-12 60-71 60Zm-8-14c18 0 68-31 68-47l-2-6c-3-5-7-8-14-8-17 0-68 29-68 46l2 7c2 4 7 8 14 8Z",xOffset:0,yOffset:-4.5},NOTE_HEAD_QUARTER:{path:"M35 90C16 90 0 79 0 60 0 29 32 0 71 0c20 0 35 12 35 30 0 30-40 60-71 60Z",xOffset:0,yOffset:-4.5},EIGHTH_NOTE:{path:"M142 89c20 32 36 70 36 110 0 25-8 55-8 55-2 5-5 7-8 6h-1c-2-1-5-4-5-9l1-5c5-14 8-29 8-44 0-19-3-37-8-48-10-23-33-58-53-70v179c0 30-38 60-70 60-19 0-34-11-34-30 0-31 31-60 70-60 11 0 19 3 25 8V3c0-2 2-3 3-3 6 0 9 2 10 7 5 31 18 57 34 82Z",xOffset:0,yOffset:-28},EIGHTH_NOTE_FLIPPED:{path:"M9 323H0V60C0 29 32 0 71 0c20 0 35 12 35 30 0 30-40 60-71 60-19 0-26-9-26-9v158s58-56 58-89c0 0 0-25-8-43-5-12 10-17 14-6 13 34 9 48 9 48 0 39-41 97-41 97-20 27-32 77-32 77Z",xOffset:0,yOffset:-4},REST_WHOLE:{path:"M0 0h104v53H0V0Z",xOffset:0,yOffset:0},REST_HALF:{path:"M0 0h104v53H0V0Z",xOffset:0,yOffset:-5},REST_QUARTER:{path:"m28 151-18-22s-3-4-3-9c0-3 1-7 5-11 16-17 22-33 22-46 0-27-21-45-23-49l-1-6c0-5 4-8 7-8s5 1 7 3l61 71 1 7-1 5c-10 15-23 34-25 55v3c0 20 11 35 25 52 4 4 14 16 14 20 0 2-2 2-5 1-6-2-19-6-29-6-16 0-23 12-23 27 0 8 5 22 11 22 3 3 6 6 6 9s-2 5-7 5l-9-3c-27-21-43-39-43-57s13-35 32-35c3 0 10 3 14 0l-2-6-16-22Z",xOffset:0,yOffset:-16},REST_EIGHTH:{path:"M61 35c18 0 41-35 47-32 0 1 5 3 5 8l-5 17S64 189 62 190c-4 4-11 5-16 5-3 0-13 0-13-6 8-30 41-122 42-128 1-5 1-10-1-10-4 0-3 3-19 8C16 71 0 46 0 31 0 14 14 0 31 0c5 0 30 1 30 35Z",xOffset:0,yOffset:-10},ACCIDENTAL_SHARP:{path:"m67 66-8 3c-2 0-3 6-3 8v26c0 4 2 5 3 5l8-2 1-1c1 0 2 1 2 3v20c0 1-1 4-3 4l-8 4c-2 0-3 4-3 6v40c0 2-2 4-5 4-2 0-4-2-4-4v-35c0-2-1-5-4-5h-1l-17 7c-1 1-3 3-3 6v40c0 2-1 3-4 3-2 0-4-1-4-3v-35c0-1-1-5-3-5l-1 1-7 2v1c-2 0-3-1-3-3v-20c0-2 1-4 3-5l8-3c2-1 3-3 3-6V94c0-3-2-5-4-5l-7 3c-2 0-3-1-3-3V69l3-4 8-3c1-1 3-4 3-8V16c0-2 2-4 5-4 2 0 3 2 3 4v34c0 2 1 5 4 5l18-7c2-1 3-5 3-8V3c0-2 2-3 5-3 2 0 4 1 4 3v35c0 2 2 3 4 3l7-2h1c1 0 2 0 2 2v20c0 2-1 4-3 5Zm-20 46c2-11 2-23 0-34l-4-2c-7 0-20 6-21 11v35l4 1c6 0 20-5 21-11Z",xOffset:-8,yOffset:-10},ACCIDENTAL_FLAT:{path:"M4 196C1 193 0 9 0 9c0-6 5-9 10-9 3 0 6 2 6 5l-2 91c0 3 1 5 3 6h2l7-4c5-3 12-6 18-6 15 1 29 13 29 31 0 15-10 35-39 55-8 5-16 14-25 19l-2 1c-1 0-2 0-3-2Zm11-28c0 1 1 5 4 5l3-1c14-9 29-27 29-44 0-8-4-19-14-19-7 0-20 10-22 16l-1 10 1 33Z",xOffset:-8,yOffset:-14},ACCIDENTAL_NATURAL:{path:"m41 47 5-2h1l2 2v147c0 3-2 4-3 4h-4c-2 0-4-1-4-4v-43c0-2-2-3-5-3-8 0-25 7-29 8l-1 1c-2 0-3-1-3-3V4c0-3 1-4 4-4h3c2 0 4 1 4 4v48c0 2 1 2 3 2 7 0 26-7 26-7h1ZM11 88v31l3 1c8 0 24-6 24-12V78l-2-1c-7 0-25 7-25 11Z",xOffset:-8,yOffset:-10},ACCIDENTAL_DOUBLE_SHARP:{path:"M68 33h3c6 0 13 0 15-2l2-15C88 4 86 0 72 0c-6 0-12 1-14 4-2 1-2 7-2 13-1 5-8 17-12 17-5 0-9-10-11-15l-1-2c0-6-1-12-3-13-2-3-8-4-13-4C10 0 4 1 2 4L0 17l2 14c2 2 9 2 15 2h4c5 2 16 8 16 12 0 3-13 10-17 12h-3c-6 0-13 1-15 3L0 74l2 14 14 2 13-2c2-2 3-8 3-14 1-5 7-17 12-17 4 0 10 13 12 17 0 6 0 12 2 14l14 2c15 0 16-2 16-17l-2-13c-4-2-11-3-15-3h-3c-5-2-17-7-17-12 0-2 13-10 17-12Z",xOffset:-10,yOffset:-4},ACCIDENTAL_DOUBLE_FLAT:{path:"M102 93h2c15 0 29 12 29 30 0 15-10 35-39 55-8 5-16 14-26 19l-2 1-2-2-3-43c-6 7-15 16-27 25-7 5-15 14-25 19l-2 1c-1 0-2 0-3-2C2 193 0 8 0 8c0-5 6-8 10-8 3 0 6 2 6 5l-2 91c0 3 1 5 3 6h2c3 0 5-3 8-4 5-3 9-5 15-5h2c6 0 12 1 17 5L60 8c0-5 5-8 10-8 3 0 6 2 6 5l-2 91c0 3 1 5 3 6h2c3 0 5-3 7-4 6-3 10-5 16-5Zm-80 78c14-9 29-25 29-43 0-8-3-19-13-19-8 0-21 10-23 16l-1 11 1 31c0 2 1 5 4 5l3-1Zm59 0c15-9 29-25 29-43 0-6-2-12-5-16-2-2-4-3-8-3-7 0-21 10-23 16v8l1 34c0 2 1 5 3 5l3-1Z",xOffset:-14,yOffset:-14},TIME_4:{path:"M53 0h66S70 76 20 124h61V86l47-50v89h22v19h-22v27c0 9 13 9 13 9h9v10H61v-10h10s10 0 10-10v-26H0v-20S54 67 53 0Z",xOffset:0,yOffset:0},TIME_3:{path:"M2 43c0 21 15 30 30 30 5 0 28-2 28-27 0-11-16-20-16-24 0-14 56-15 56 26 0 26-19 38-31 38H45v13h24c12 0 33 15 33 41 0 38-54 40-54 25 0-3 10-11 10-21 0-20-15-27-27-27-17 0-32 8-31 30 1 30 36 43 75 43 36 0 75-19 75-50 0-34-23-47-37-47v-2c4 0 35-13 35-39 0-37-35-52-75-52C39 0 3 14 2 43Z",xOffset:0,yOffset:0}},V=/^(?<name>[A-Ga-g])(?<accidental>##|bb|[#bn]?)(?<octave>\d)(?<duration>[whqeWHQE]?)$/,j=/^[whqeWHQE]$/,g=["C","D","E","F","G","A","B"];function m(h){const e=h.match(V);if(!e||!e.groups)throw new Error(`Invalid note string format: ${h}. Expected format: [A-Ga-g][#|b]?[0-9][w|h|q|e].`);let{name:t,accidental:s,octave:n,duration:r}=e.groups;t=t.toUpperCase(),r=r.toLowerCase(),r||(r="w");const o={name:t,octave:parseInt(n),duration:r};return s&&(o.accidental=s),o}function L(h){const e=h.match(j);if(!e)throw new Error(`Invalid note duration '${h}'. Use w | h | q | e.`);return e[0].toString().toLowerCase()}function y(h){let e;switch(h){case"treble":e="CLEF_TREBLE";break;case"bass":e="CLEF_BASS";break;case"alto":e="CLEF_ALTO";break}if(!e)throw new Error(`Invalid clef type: ${h}. Valid clef types are: treble, bass, alto.`);return e}function B(h){let e=g.indexOf(h.name);return e+=h.octave*12,e}function I(h,e){return g.indexOf(h.name)-g.indexOf(e.name)+(h.octave-e.octave)*7}const O=48,H=40+30/2,P=20,X=90;class x{params;rendererRef;width=0;trebleStaffHeight=0;constructor(e,t){this.rendererRef=e;const s=N[t];if(!s)throw new Error(`Staff type ${t} is not supported`);this.params=s}drawStaffLines=(e,t)=>{let s=e;for(let n=0;n<5;n++)this.rendererRef.drawLine(0,s,this.width,s,t),s+=10;return s-10};drawStaff=e=>{this.width=e;const t=this.rendererRef.getLayerByName("staff");let s=this.drawStaffLines(0,t),n=this.drawStaffLines(s+30,t);this.rendererRef.drawLine(0,0,0,n,t),this.rendererRef.drawLine(this.width,0,this.width,n,t),this.trebleStaffHeight=s;let r=n,o=1;const a=y("treble"),i=y("bass");this.rendererRef.drawGlyph(a,t),this.rendererRef.drawGlyph(i,t,{yOffset:s+30}),r+=this.params.paddingBottom+1,o+=this.params.paddingTop,this.rendererRef.addTotalRootSvgHeight(r),this.rendererRef.addTotalRootSvgYOffset(o)};shouldNoteFlip(e){const t=Math.abs(e-X),s=Math.abs(e-P);return e===H?!1:t<=s?!(e>=X):e<=P}getLedgerLinesX(e,t){const s=[],n=B(e);let r=e.duration==="w"?17:12.5;if(n===O)return s.push({x1:-2,x2:r,yPos:0}),s;if(t<this.params.topLineYPos){let o=this.params.topLineYPos-10;for(;o>=t;)s.push({x1:-2,x2:r,yPos:o-t}),o-=10}else if(t>this.params.bottomLineYPos){let o=this.params.bottomLineYPos+10;for(;o<=t;)s.push({x1:-2,x2:r,yPos:o-t}),o+=10}return s}calculateNoteYPos=e=>{let s=I(this.params.topLineNote,e)*(10/2);const n=B(e);return n<O?s+=10:n===O&&(s=H),s};getKeySignatureYPositions(e,t){const s=v[e].slice(0,t),n=C.treble[e],r=C.bass[e],o=s.map((i,c)=>I(N.treble.topLineNote,{name:i,octave:n[c]})*(10/2)),a=s.map((i,c)=>I(N.bass.topLineNote,{name:i,octave:r[c]})*(10/2)+this.trebleStaffHeight+30);return[o,a]}}const q=20;class A{params;rendererRef;constructor(e,t){this.rendererRef=e;const s=N[t];if(!s)throw new Error(`Staff type ${t} is not supported`);this.params=s}drawStaff=e=>{const t=this.rendererRef.getLayerByName("staff");let s=0;for(let a=0;a<5;a++)this.rendererRef.drawLine(0,s,e,s,t),s+=10;this.rendererRef.drawLine(0,0,0,s-10,t),this.rendererRef.drawLine(e,0,e,s-10,t);let n=s-10+1,r=1;const o=y(this.params.staffType);this.rendererRef.drawGlyph(o,t),n+=this.params.paddingTop+this.params.paddingBottom,r+=this.params.paddingTop,this.rendererRef.addTotalRootSvgHeight(n),this.rendererRef.addTotalRootSvgYOffset(r)};shouldNoteFlip(e){return e<=q}getLedgerLinesX(e,t){const s=[];let n=e.duration==="w"?17:12.5;if(t<this.params.topLineYPos){let r=this.params.topLineYPos-10;for(;r>=t;)s.push({x1:-2,x2:n,yPos:r-t}),r-=10}else if(t>this.params.bottomLineYPos){let r=this.params.bottomLineYPos+10;for(;r<=t;)s.push({x1:-2,x2:n,yPos:r-t}),r+=10}return s}calculateNoteYPos=e=>I(this.params.topLineNote,e)*(10/2);getKeySignatureYPositions(e,t){const s=v[e].slice(0,t),n=C[this.params.staffType][e];return[s.map((o,a)=>this.calculateNoteYPos({name:o,octave:n[a]}))]}}class U{svgRendererInstance;strategyInstance;constructor(e,t){this.svgRendererInstance=e,this.strategyInstance=t}drawStem(e,t){t?this.svgRendererInstance.drawLine(0,0,0,28,e):this.svgRendererInstance.drawLine(10,0,10,-28,e)}chordOffsetConsecutiveAccidentals(e){let t=0,s=0,n=0;for(let r=0;r<e.length;r++){const o=e[r];if(o.noteObj.accidental&&n<3?(t+=-8,s=Math.min(s,t),n++):o.noteObj.accidental&&n<=3?(t=-8,n=1):(t=0,n=0),t!==0){const i=Array.from(o.noteGroup.getElementsByTagName("use")).find(c=>c.getAttribute("href")?.includes("ACCIDENTAL"));if(!i)continue;i.setAttribute("transform",`translate(${t+8}, 0)`)}}return-s}chordOffsetCloseNotes(e){let t=e[0],s=0;for(let n=1;n<e.length;n++){const r=e[n];if(-I(t.noteObj,r.noteObj)===1){s=28/2,r.noteGroup.setAttribute("transform",`translate(${s}, ${r.noteYPos})`);const i=Array.from(r.noteGroup.getElementsByTagName("use")).find(c=>c.getAttribute("href")?.includes("ACCIDENTAL"));if(i){const c=i.getAttribute("transform")?.match(/([-]?\d+)/),l=c&&c[0];let f=-s;l&&(f+=Number(l)),i.setAttribute("transform",`translate(${f}, 0)`)}n++,t=e[n];continue}t=r}return s}renderNote(e){const t=this.svgRendererInstance.createGroup("note"),s=m(e),n=this.strategyInstance.calculateNoteYPos({name:s.name,octave:s.octave});let r=this.strategyInstance.shouldNoteFlip(n);switch(s.duration){case"h":this.svgRendererInstance.drawGlyph("NOTE_HEAD_HALF",t),this.drawStem(t,r);break;case"q":this.svgRendererInstance.drawGlyph("NOTE_HEAD_QUARTER",t),this.drawStem(t,r);break;case"e":r?this.svgRendererInstance.drawGlyph("EIGHTH_NOTE_FLIPPED",t):this.svgRendererInstance.drawGlyph("EIGHTH_NOTE",t);break;default:this.svgRendererInstance.drawGlyph("NOTE_HEAD_WHOLE",t)}let o=0;switch(s.accidental){case"#":this.svgRendererInstance.drawGlyph("ACCIDENTAL_SHARP",t),o-=-8;break;case"b":this.svgRendererInstance.drawGlyph("ACCIDENTAL_FLAT",t),o-=-8;break;case"n":this.svgRendererInstance.drawGlyph("ACCIDENTAL_NATURAL",t),o-=-8;break;case"##":this.svgRendererInstance.drawGlyph("ACCIDENTAL_DOUBLE_SHARP",t),o-=-10;break;case"bb":this.svgRendererInstance.drawGlyph("ACCIDENTAL_DOUBLE_FLAT",t),o-=-14;break}return this.strategyInstance.getLedgerLinesX(s,n).forEach(i=>{this.svgRendererInstance.drawLine(i.x1,i.yPos,i.x2,i.yPos,t)}),{noteGroup:t,noteObj:s,noteYPos:n,accidentalOffset:o,cursorOffset:0}}renderChord(e){const t=this.svgRendererInstance.createGroup("chord"),s=[];for(const o of e){const a=this.renderNote(o);a.noteGroup.setAttribute("transform",`translate(0, ${a.noteYPos})`),t.appendChild(a.noteGroup),s.push({noteGroup:a.noteGroup,noteObj:a.noteObj,noteYPos:a.noteYPos,cursorOffset:0,accidentalOffset:0})}const n=this.chordOffsetConsecutiveAccidentals(s),r=this.chordOffsetCloseNotes(s);return{noteGroup:t,noteObj:s[0].noteObj,noteYPos:0,accidentalOffset:n,cursorOffset:r}}}const p="http://www.w3.org/2000/svg",K=.1,R=1200;class b{rootElementRef;svgElementRef;parentGroupContainer;musicStaffLayer;musicNotesLayer;musicUILayer;width;scale;totalYOffset=0;totalHeight=0;constructor(e,t){this.rootElementRef=e,this.width=t.width,this.scale=t.scale,this.width>R&&(this.width=R,console.warn(`Width provided for the staff ${this.width} exceeds the limit ${R}. Please use this value to fix positioning issues.`)),this.svgElementRef=document.createElementNS(p,"svg"),this.svgElementRef.classList.add("vs-svg-renderer-root"),this.svgElementRef.style.maxWidth="100%",this.svgElementRef.style.height="auto",this.svgElementRef.style.display="block",this.svgElementRef.setAttribute("color",t.staffColor),this.svgElementRef.style.backgroundColor=t.staffBackgroundColor,this.makeGlyphDefs(t.useGlyphs),this.parentGroupContainer=this.createGroup("svg-renderer-parent"),this.svgElementRef.appendChild(this.parentGroupContainer),this.musicStaffLayer=this.createGroup("music-staff-layer"),this.musicNotesLayer=this.createGroup("music-notes-layer"),this.musicUILayer=this.createGroup("music-ui-layer"),this.parentGroupContainer.appendChild(this.musicStaffLayer),this.parentGroupContainer.appendChild(this.musicNotesLayer),this.parentGroupContainer.appendChild(this.musicUILayer)}makeGlyphDefs(e){const t=document.createElementNS(p,"defs");Object.entries(Z).filter(([n])=>e.includes(n)).forEach(([n,r])=>{const o=document.createElementNS(p,"path");o.setAttribute("id",`glyph-${n}`),o.setAttribute("d",r.path),o.setAttribute("fill","currentColor"),o.setAttribute("transform",`translate(${r.xOffset}, ${r.yOffset}) scale(${K})`),t.appendChild(o)}),this.rootSvgElement.appendChild(t)}createGroup(e){const t=document.createElementNS(p,"g");return e&&t.classList.add(`vs-${e}`),t}commitElementsToDOM(e,t=this.rootElementRef){const s=document.createDocumentFragment();Array.isArray(e)?e.forEach(n=>{s.appendChild(n)}):s.appendChild(e),t.appendChild(s)}getLayerByName(e){switch(e){case"staff":return this.musicStaffLayer;case"notes":return this.musicNotesLayer;case"ui":return this.musicUILayer;default:throw new Error(`Layer with name '${e}' does not exist.`)}}addTotalRootSvgHeight(e){this.totalHeight+=e}addTotalRootSvgYOffset(e){this.totalYOffset+=e}applySizingToRootSvg(){this.parentGroupContainer.setAttribute("transform",`translate(0, ${this.totalYOffset})`);let e=this.width*this.scale;const t=(this.totalHeight+this.totalYOffset)*this.scale;e+=2,this.svgElementRef.setAttribute("width",e.toString()),this.svgElementRef.setAttribute("height",t.toString()),this.svgElementRef.setAttribute("viewBox",`0 0 ${this.width} ${this.totalHeight+this.totalYOffset}`)}get rootSvgElement(){return this.svgElementRef}get parentGroupElement(){return this.parentGroupContainer}drawLine(e,t,s,n,r){const o=document.createElementNS(p,"line");o.setAttribute("x1",e.toString()),o.setAttribute("y1",t.toString()),o.setAttribute("x2",s.toString()),o.setAttribute("y2",n.toString()),o.setAttribute("stroke","currentColor"),o.setAttribute("stroke-width","1"),r.appendChild(o)}drawRect(e,t,s,n){const r=document.createElementNS(p,"rect");return r.setAttribute("width",e.toString()),r.setAttribute("height",t.toString()),r.setAttribute("x",(n?.x??0).toString()),r.setAttribute("y",(n?.y??0).toString()),n?.fill?r.setAttribute("fill",n.fill):r.setAttribute("fill","currentColor"),s.appendChild(r),r}drawGlyph(e,t,s){s={xOffset:0,yOffset:0,...s};const n=document.createElementNS(p,"use");n.setAttribute("href",`#glyph-${e}`),(s.xOffset||s.yOffset)&&n.setAttribute("transform",`translate(${s.xOffset}, ${s.yOffset})`),t.appendChild(n)}destroy(){this.rootElementRef&&this.svgElementRef&&this.rootElementRef.contains(this.svgElementRef)&&this.rootElementRef.removeChild(this.svgElementRef)}}const Q=["CLEF_TREBLE","CLEF_BASS","CLEF_ALTO","NOTE_HEAD_WHOLE","NOTE_HEAD_HALF","NOTE_HEAD_QUARTER","EIGHTH_NOTE","EIGHTH_NOTE_FLIPPED","ACCIDENTAL_SHARP","ACCIDENTAL_FLAT","ACCIDENTAL_NATURAL","ACCIDENTAL_DOUBLE_SHARP","ACCIDENTAL_DOUBLE_FLAT"];class z{svgRendererInstance;strategyInstance;noteRendererInstance;options;noteEntries=[];noteCursorX=0;noteStartX;constructor(e,t){this.options={width:300,scale:1,noteStartX:0,staffType:"treble",spaceAbove:0,spaceBelow:0,staffColor:"black",staffBackgroundColor:"transparent",...t},this.svgRendererInstance=new b(e,{width:this.options.width,height:100,scale:this.options.scale,staffColor:this.options.staffColor,staffBackgroundColor:this.options.staffBackgroundColor,useGlyphs:Q});const s=this.svgRendererInstance.rootSvgElement;switch(this.options.staffType){case"grand":this.strategyInstance=new x(this.svgRendererInstance,"grand");break;case"bass":this.strategyInstance=new A(this.svgRendererInstance,"bass");break;case"treble":this.strategyInstance=new A(this.svgRendererInstance,"treble");break;case"alto":this.strategyInstance=new A(this.svgRendererInstance,"alto");break;default:throw new Error(`The staff type ${this.options.staffType} is not supported. Please use "treble", "bass", "alto", or "grand".`)}if(this.strategyInstance.drawStaff(this.options.width),this.noteRendererInstance=new U(this.svgRendererInstance,this.strategyInstance),this.options.spaceAbove){const r=this.options.spaceAbove*10;this.svgRendererInstance.addTotalRootSvgYOffset(r)}if(this.options.spaceBelow){let r=this.options.spaceBelow*10;this.options.staffType==="grand"&&(r-=10/2),this.svgRendererInstance.addTotalRootSvgHeight(r)}let n=0;this.options.keySignature&&(n=this.createKeySignature(this.options.keySignature)),this.noteStartX=38+this.options.noteStartX+n,this.svgRendererInstance.getLayerByName("notes").setAttribute("transform",`translate(${this.noteStartX}, 0)`),this.svgRendererInstance.applySizingToRootSvg(),this.svgRendererInstance.commitElementsToDOM(s)}createKeySignature(e){return W(this.svgRendererInstance,this.strategyInstance,e,k)}drawNote(e){const t=Array.isArray(e)?e:[e],s=this.svgRendererInstance.getLayerByName("notes"),n=[];for(const r of t){let o;try{o=this.noteRendererInstance.renderNote(r)}catch(a){throw n.length>0&&this.svgRendererInstance.commitElementsToDOM(n,s),a}o.noteGroup.setAttribute("transform",`translate(${this.noteCursorX+o.accidentalOffset}, ${o.noteYPos})`),this.noteEntries.push({gElement:o.noteGroup,note:o.noteObj,xPos:this.noteCursorX+o.accidentalOffset,yPos:o.noteYPos,accidentalXOffset:o.accidentalOffset}),this.noteCursorX+=28+o.accidentalOffset,n.push(o.noteGroup)}this.svgRendererInstance.commitElementsToDOM(n,s)}drawChord(e){if(e.length<2)throw new Error("Provide more than one note for a chord.");const t=this.svgRendererInstance.getLayerByName("notes"),s=this.noteRendererInstance.renderChord(e);s.noteGroup.setAttribute("transform",`translate(${this.noteCursorX+s.accidentalOffset}, 0)`),this.noteEntries.push({gElement:s.noteGroup,note:m(e[0]),xPos:this.noteCursorX+s.accidentalOffset,yPos:0,accidentalXOffset:s.accidentalOffset}),this.noteCursorX+=28+s.accidentalOffset+s.cursorOffset,this.svgRendererInstance.commitElementsToDOM(s.noteGroup,t)}justifyNotes(){const e=this.options.width-this.noteStartX,t=this.noteEntries.length;if(t<=0||e<=0)return;const s=Math.round(e/t);this.noteEntries.map((r,o)=>{const a=(o+.5)*s,i=r.gElement.getBBox(),c=a-i.width/2-i.x,l=Math.round(c*10)/10;return{entry:r,newX:l,isChord:r.gElement.classList.contains("chord")}}).forEach(r=>{const{entry:o,newX:a,isChord:i}=r;i?o.gElement.setAttribute("transform",`translate(${a}, 0)`):o.gElement.setAttribute("transform",`translate(${a}, ${o.yPos})`),o.xPos=a})}clearAllNotes(){this.noteCursorX=0,this.svgRendererInstance.getLayerByName("notes").replaceChildren(),this.noteEntries=[]}changeNoteByIndex(e,t){if(t>=this.noteEntries.length)throw new Error("Note index was out of bounds.");const s=this.noteEntries[t],n=this.noteRendererInstance.renderNote(e),o=s.xPos-s.accidentalXOffset+n.accidentalOffset;n.noteGroup.setAttribute("transform",`translate(${o}, ${n.noteYPos})`),this.svgRendererInstance.getLayerByName("notes").replaceChild(n.noteGroup,s.gElement),this.noteEntries[t]={gElement:n.noteGroup,note:n.noteObj,xPos:o,yPos:n.noteYPos,accidentalXOffset:n.accidentalOffset}}changeChordByIndex(e,t){if(t>=this.noteEntries.length)throw new Error("Chord index was out of bounds.");if(e.length<2)throw new Error("Notes provided need to be more than one to be considered a chord.");const s=this.noteEntries[t],n=this.noteRendererInstance.renderChord(e),o=s.xPos-s.accidentalXOffset+n.accidentalOffset;n.noteGroup.setAttribute("transform",`translate(${o}, 0)`),this.svgRendererInstance.getLayerByName("notes").replaceChild(n.noteGroup,s.gElement),this.noteEntries[t]={gElement:n.noteGroup,note:m(e[0]),xPos:o,yPos:0,accidentalXOffset:n.accidentalOffset}}addClassToNoteByIndex(e,t){if(t>=this.noteEntries.length)throw new Error("Note index was out of bounds.");this.noteEntries[t].gElement.classList.add(e)}removeClassToNoteByIndex(e,t){if(t>=this.noteEntries.length)throw new Error("Note index was out of bounds.");this.noteEntries[t].gElement.classList.remove(e)}destroy(){this.noteEntries=[],this.svgRendererInstance.destroy()}}const u=30,M=19,w=12,J=4,tt=6,Y=1,G=38,et=["TIME_4","TIME_3","NOTE_HEAD_WHOLE","NOTE_HEAD_HALF","NOTE_HEAD_QUARTER","EIGHTH_NOTE","REST_WHOLE","REST_HALF","REST_QUARTER","REST_EIGHTH"];class st{rendererInstance;options;barSpacing;quarterNoteSpacing;noteCursorX=0;noteEntries=[];maxBeatCount;currentBeatCount=0;currentBeatUICount=0;currentBeatUIElement=null;currentBeatUIXPos=G;constructor(e,t){this.options={width:300,scale:1,topNumber:4,barsCount:2,spaceAbove:0,spaceBelow:0,staffColor:"black",staffBackgroundColor:"white",currentBeatUIColor:"#24ff7450",...t},this.rendererInstance=new b(e,{width:this.options.width,height:100,scale:this.options.scale,staffColor:this.options.staffColor,staffBackgroundColor:this.options.staffBackgroundColor,useGlyphs:et});const s=this.rendererInstance.rootSvgElement;let n="TIME_4";switch(this.options.topNumber){case 3:n="TIME_3";break;case 4:n="TIME_4";break;default:throw new Error(`Time signature ${this.options.topNumber} not supported. Please use either 3 or 4.`)}if(this.options.barsCount<1||this.options.barsCount>3)throw new Error(`Bars count ${this.options.barsCount} not supported. Please use 1 - 3`);if(this.options.spaceAbove){const _=this.options.spaceAbove*10;this.rendererInstance.addTotalRootSvgYOffset(_)}if(this.options.spaceBelow){let _=this.options.spaceBelow*10;this.rendererInstance.addTotalRootSvgHeight(_)}const r=this.rendererInstance.getLayerByName("staff");this.rendererInstance.addTotalRootSvgHeight(u*2);const o=this.rendererInstance.createGroup("time-signature");r.appendChild(o);const a=u-M;this.rendererInstance.drawGlyph(n,o),this.rendererInstance.drawGlyph("TIME_4",o,{yOffset:M}),o.setAttribute("transform",`translate(0, ${a})`);let i=this.options.width-38;this.options.barsCount>1&&(i-=(this.options.barsCount-1)*w),i-=Y,this.rendererInstance.drawLine(0,u,this.options.width-Y,u,r),this.barSpacing=i/this.options.barsCount,this.quarterNoteSpacing=Math.round(this.barSpacing/this.options.topNumber),this.maxBeatCount=this.options.barsCount*this.options.topNumber;let c=this.barSpacing+38;const l=u/2,f=u+l;for(let _=0;_<this.options.barsCount-1;_++)this.rendererInstance.drawLine(c,l,c,f,r),c+=this.barSpacing;this.rendererInstance.getLayerByName("notes").setAttribute("transform",`translate(38, ${u})`),this.rendererInstance.applySizingToRootSvg(),this.rendererInstance.commitElementsToDOM(s)}createBeatUIElement(){const e=this.rendererInstance.getLayerByName("ui");this.currentBeatUIElement=this.rendererInstance.drawRect(this.quarterNoteSpacing/2,u*2,e,{x:G,fill:this.options.currentBeatUIColor})}handleNewBar(){this.noteCursorX+=w}translateGroupByDuration(e,t){return t.setAttribute("transform",`translate(${this.noteCursorX}, 0)`),this.quarterNoteSpacing*e}drawStem(e,t){this.rendererInstance.drawLine(10+(t??0),0,10+(t??0),-28,e)}renderNote(e,t){switch(e){case"w":this.rendererInstance.drawGlyph("NOTE_HEAD_WHOLE",t);break;case"h":this.rendererInstance.drawGlyph("NOTE_HEAD_HALF",t),this.drawStem(t);break;case"q":this.rendererInstance.drawGlyph("NOTE_HEAD_QUARTER",t),this.drawStem(t);break;case"e":this.rendererInstance.drawGlyph("EIGHTH_NOTE",t),this.drawStem(t);break}}renderRest(e,t){switch(e){case"w":this.rendererInstance.drawGlyph("REST_WHOLE",t);break;case"h":this.rendererInstance.drawGlyph("REST_HALF",t);break;case"q":this.rendererInstance.drawGlyph("REST_QUARTER",t);break;case"e":this.rendererInstance.drawGlyph("REST_EIGHTH",t);break}}checkAndCreateNewBar(){const e=this.currentBeatCount>0&&this.currentBeatCount%this.options.topNumber===0,t=this.currentBeatCount<this.maxBeatCount;e&&t&&this.handleNewBar()}checkAndFillBarWithRests(e){const t=this.options.topNumber-this.currentBeatCount%this.options.topNumber;if(e>t){const s=this.createRemainingRests(t);return this.handleNewBar(),s}return null}createRemainingRests(e){const t=[];let s=e;for(;s>0;){const n=this.rendererInstance.createGroup("rest");let r=0;s-E.h>=0?(this.rendererInstance.drawGlyph("REST_HALF",n),r=E.h):s-E.q>=0?(this.rendererInstance.drawGlyph("REST_QUARTER",n),r=E.q):(this.rendererInstance.drawGlyph("REST_EIGHTH",n),r=E.e),s-=r,this.currentBeatCount+=r,n.setAttribute("transform",`translate(${this.noteCursorX}, 0)`),this.noteCursorX+=r*this.quarterNoteSpacing,t.push(n)}return t}renderBeamRect(e,t,s,n){this.rendererInstance.drawRect(e-t,J,s,{x:10,y:-28+(n??0),fill:this.options.staffColor})}drawNote(e){const t=Array.isArray(e)?e:[e],s=this.rendererInstance.getLayerByName("notes"),n=[];for(const r of t){let o="w";try{o=L(r)}catch(f){throw n.length>0&&this.rendererInstance.commitElementsToDOM(n,s),f}const a=E[o];if(this.currentBeatCount>=this.maxBeatCount)throw n.length>0&&this.rendererInstance.commitElementsToDOM(n,s),new Error("Max beat count reached. Can't add additional notes.");this.checkAndCreateNewBar();const i=this.checkAndFillBarWithRests(a);i&&i.forEach(f=>{n.push(f),this.noteEntries.push(f)});const c=this.rendererInstance.createGroup("note"),l=this.translateGroupByDuration(a,c);this.noteCursorX+=l,this.currentBeatCount+=a,this.renderNote(o,c),n.push(c),this.noteEntries.push(c)}this.rendererInstance.commitElementsToDOM(n,s)}drawRest(e){const t=Array.isArray(e)?e:[e],s=this.rendererInstance.getLayerByName("notes"),n=[];for(const r of t){let o="w";try{o=L(r)}catch(f){throw n.length>0&&this.rendererInstance.commitElementsToDOM(n,s),f}const a=this.rendererInstance.createGroup("rest"),i=E[o],c=i*this.quarterNoteSpacing;if(this.currentBeatCount>=this.maxBeatCount)throw n.length>0&&this.rendererInstance.commitElementsToDOM(n,s),new Error("Max beat count reached. Can't add additional notes.");this.checkAndCreateNewBar();const l=this.checkAndFillBarWithRests(i);l&&l.forEach(f=>{n.push(f),this.noteEntries.push(f)}),this.renderRest(o,a),a.setAttribute("transform",`translate(${this.noteCursorX}, 0)`),this.noteCursorX+=c,this.currentBeatCount+=i,n.push(a),this.noteEntries.push(a)}this.rendererInstance.commitElementsToDOM(n,s)}drawBeamedNotes(e,t){if(t<2)throw new Error("Must provide a value greater than 2 for beamed note.");if(this.currentBeatCount>=this.maxBeatCount)throw new Error("Max beat count reached. Can't add additional beamed note.");let s="s";e==="s"?s="s":s=L(e),this.checkAndCreateNewBar();const n=this.rendererInstance.getLayerByName("notes"),r=E[s],o=r*this.quarterNoteSpacing,a=this.options.topNumber-this.currentBeatCount%this.options.topNumber,i=Math.min(t,a/r),c=this.rendererInstance.createGroup("beamed-note");c.setAttribute("transform",`translate(${this.noteCursorX}, 0)`);let l=0;for(let f=0;f<i;f++)this.rendererInstance.drawGlyph("NOTE_HEAD_QUARTER",c,{xOffset:l}),this.drawStem(c,l),l+=o,this.currentBeatCount+=r;this.renderBeamRect(l,o,c),e==="s"&&this.renderBeamRect(l,o,c,tt),this.noteCursorX+=l,this.noteEntries.push(c),this.rendererInstance.commitElementsToDOM(c,n)}incrementCurrentBeatUI(){if(this.currentBeatUIElement||this.createBeatUIElement(),this.currentBeatUICount>=this.maxBeatCount){this.currentBeatUIElement.setAttribute("display","none");return}this.currentBeatUIElement?.getAttribute("display")==="none"&&this.currentBeatUIElement.removeAttribute("display"),this.currentBeatUICount++,this.currentBeatUICount>this.options.topNumber&&this.currentBeatUICount%this.options.topNumber===1&&(this.currentBeatUIXPos+=w),this.currentBeatUICount>1&&(this.currentBeatUIXPos+=this.quarterNoteSpacing),this.currentBeatUIElement.setAttribute("x",this.currentBeatUIXPos.toString())}resetCurrentBeatUI(){this.currentBeatUICount=0,this.currentBeatUIXPos=G,this.currentBeatUIElement&&(this.currentBeatUIElement.setAttribute("display","none"),this.currentBeatUIElement.setAttribute("x",this.currentBeatUIXPos.toString()))}clearAllNotes(){this.noteCursorX=0,this.currentBeatCount=0,this.rendererInstance.getLayerByName("notes").replaceChildren(),this.noteEntries=[]}destroy(){this.noteEntries=[],this.rendererInstance.destroy()}}const nt=["CLEF_TREBLE","CLEF_BASS","CLEF_ALTO","NOTE_HEAD_WHOLE","NOTE_HEAD_HALF","NOTE_HEAD_QUARTER","EIGHTH_NOTE","EIGHTH_NOTE_FLIPPED","ACCIDENTAL_SHARP","ACCIDENTAL_FLAT","ACCIDENTAL_NATURAL","ACCIDENTAL_DOUBLE_SHARP","ACCIDENTAL_DOUBLE_FLAT"],S=60,rt=S;class ot{svgRendererInstance;strategyInstance;noteRendererInstance;options;activeEntries=[];noteBuffer=[];notesLayer;noteCursorX=0;noteStartX;constructor(e,t){this.options={width:300,scale:1,noteStartX:0,staffType:"treble",spaceAbove:0,spaceBelow:0,staffColor:"black",staffBackgroundColor:"transparent",...t},this.svgRendererInstance=new b(e,{width:this.options.width,height:100,scale:this.options.scale,staffColor:this.options.staffColor,staffBackgroundColor:this.options.staffBackgroundColor,useGlyphs:nt});const s=this.svgRendererInstance.rootSvgElement;switch(this.options.staffType){case"grand":this.strategyInstance=new x(this.svgRendererInstance,"grand");break;case"bass":this.strategyInstance=new A(this.svgRendererInstance,"bass");break;case"treble":this.strategyInstance=new A(this.svgRendererInstance,"treble");break;case"alto":this.strategyInstance=new A(this.svgRendererInstance,"alto");break;default:throw new Error(`The staff type ${this.options.staffType} is not supported. Please use "treble", "bass", "alto", or "grand".`)}if(this.strategyInstance.drawStaff(this.options.width),this.noteRendererInstance=new U(this.svgRendererInstance,this.strategyInstance),this.options.spaceAbove){const n=this.options.spaceAbove*10;this.svgRendererInstance.addTotalRootSvgYOffset(n)}if(this.options.spaceBelow){let n=this.options.spaceBelow*10;this.options.staffType==="grand"&&(n-=10/2),this.svgRendererInstance.addTotalRootSvgHeight(n)}this.notesLayer=this.svgRendererInstance.getLayerByName("notes"),this.notesLayer.classList.add("vs-scrolling-notes-layer"),this.noteStartX=38+this.options.noteStartX,this.svgRendererInstance.getLayerByName("notes").setAttribute("transform",`translate(${this.noteStartX}, 0)`),this.svgRendererInstance.applySizingToRootSvg(),this.svgRendererInstance.commitElementsToDOM(s)}renderFirstNoteGroups(){const e=this.options.width-this.options.noteStartX+rt;for(;this.noteBuffer.length>0&&this.noteCursorX<e;)this.renderNextNote(),this.noteCursorX+=S;this.activeEntries.length>1&&(this.noteCursorX-=S)}renderNextNote(){if(this.noteBuffer.length<1)return;const e=this.noteBuffer[0],t=this.svgRendererInstance.createGroup("note-wrapper");if(e.type==="chord"){const s=this.noteRendererInstance.renderChord(e.notes);s.noteGroup.setAttribute("transform",`translate(0, ${s.noteYPos})`),t.appendChild(s.noteGroup)}else{const s=this.noteRendererInstance.renderNote(e.notes[0]);s.noteGroup.setAttribute("transform",`translate(0, ${s.noteYPos})`),t.appendChild(s.noteGroup)}t.style.transform=`translate(${this.noteCursorX}px, 0px)`,this.activeEntries.push({noteWrapper:t,xPos:this.noteCursorX}),this.noteBuffer.shift(),this.notesLayer.appendChild(t)}queueNotes(e){this.clearAllNotes();for(const t of e)Array.isArray(t)?this.noteBuffer.push({type:"chord",notes:t}):this.noteBuffer.push({type:"note",notes:[t]});this.renderFirstNoteGroups()}advanceNotes(){if(this.activeEntries.length<=0){this.clearAllNotes(),this.options.onNotesOut&&this.options.onNotesOut();return}this.activeEntries.forEach(t=>{t.xPos-=S,t.noteWrapper.style.transform=`translate(${t.xPos}px, 0px)`});const e=this.activeEntries[0];e.xPos<=0&&(this.notesLayer.removeChild(e.noteWrapper),this.activeEntries.shift()),this.renderNextNote()}clearAllNotes(){this.noteCursorX=0,this.notesLayer.replaceChildren(),this.activeEntries=[],this.noteBuffer=[]}destroy(){this.svgRendererInstance.destroy(),this.activeEntries=[],this.noteBuffer=[]}}d.MusicStaff=z,d.RhythmStaff=st,d.ScrollingStaff=ot,Object.defineProperty(d,Symbol.toStringTag,{value:"Module"})}));
|