@tspro/web-music-score 5.2.0 → 5.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/README.md +15 -12
  3. package/dist/audio/index.d.mts +1 -1
  4. package/dist/audio/index.d.ts +1 -1
  5. package/dist/audio/index.js +3 -3
  6. package/dist/audio/index.mjs +6 -6
  7. package/dist/audio-cg/index.js +1 -1
  8. package/dist/audio-cg/index.mjs +3 -3
  9. package/dist/audio-synth/index.js +1 -1
  10. package/dist/audio-synth/index.mjs +3 -3
  11. package/dist/{chunk-LC5JMIVF.mjs → chunk-AUT4C6TY.mjs} +2 -2
  12. package/dist/{chunk-XUGM7SCC.mjs → chunk-MHDBTCVG.mjs} +21 -21
  13. package/dist/{chunk-6S5BDSCM.mjs → chunk-QGMOI7AP.mjs} +2 -2
  14. package/dist/chunk-ZWUBO5EW.mjs +37 -0
  15. package/dist/core/index.js +2 -2
  16. package/dist/core/index.mjs +6 -31
  17. package/dist/{guitar-BsSayRsH.d.ts → guitar-CarHGDAt.d.ts} +1 -1
  18. package/dist/{guitar-DdexKdN6.d.mts → guitar-DXlB-9vK.d.mts} +1 -1
  19. package/dist/iife/audio-cg.global.js +1 -1
  20. package/dist/iife/index.global.js +18 -11
  21. package/dist/{music-objects-CwPOlqFi.d.ts → music-objects-3Esbz7ij.d.ts} +261 -381
  22. package/dist/{music-objects-CB05XryE.d.mts → music-objects-ONIuVUgs.d.mts} +261 -381
  23. package/dist/{note-CgCIBwvR.d.ts → note-CJuq5aBy.d.ts} +13 -1
  24. package/dist/{note-eA2xPPiG.d.mts → note-RVXvpfyV.d.mts} +13 -1
  25. package/dist/pieces/index.d.mts +13 -4
  26. package/dist/pieces/index.d.ts +13 -4
  27. package/dist/pieces/index.js +20 -9
  28. package/dist/pieces/index.mjs +20 -10
  29. package/dist/react-ui/index.d.mts +10 -10
  30. package/dist/react-ui/index.d.ts +10 -10
  31. package/dist/react-ui/index.js +19 -21
  32. package/dist/react-ui/index.mjs +23 -25
  33. package/dist/{scale-CBW4eTz7.d.ts → scale-C8gHC448.d.mts} +3 -3
  34. package/dist/{scale-DQP3b9Zx.d.mts → scale-DulPFco_.d.ts} +3 -3
  35. package/dist/score/index.d.mts +235 -7
  36. package/dist/score/index.d.ts +235 -7
  37. package/dist/score/index.js +2064 -1807
  38. package/dist/score/index.mjs +1897 -1671
  39. package/dist/{tempo-dkctPkCS.d.mts → tempo-BlCGZuYg.d.mts} +14 -2
  40. package/dist/{tempo-DMt3iwz9.d.ts → tempo-BnUjm25M.d.ts} +14 -2
  41. package/dist/theory/index.d.mts +6 -6
  42. package/dist/theory/index.d.ts +6 -6
  43. package/dist/theory/index.js +88 -86
  44. package/dist/theory/index.mjs +85 -81
  45. package/package.json +5 -4
@@ -1,4 +1,4 @@
1
- import { N as Note, A as Accidental } from './note-eA2xPPiG.mjs';
1
+ import { N as Note, A as Accidental } from './note-RVXvpfyV.mjs';
2
2
 
3
3
  /** Mode enum. */
4
4
  declare enum Mode {
@@ -162,6 +162,12 @@ declare enum NoteLength {
162
162
  }
163
163
  /** String values type of note length enum. */
164
164
  type NoteLengthStr = `${NoteLength}`;
165
+ /**
166
+ * Test if given argument is note length.
167
+ * @param noteLength - Note length to validate.
168
+ * @returns - True/false.
169
+ */
170
+ declare function isNoteLength(noteLength: unknown): noteLength is NoteLength;
165
171
  /**
166
172
  * Validate if given argument is note length.
167
173
  * @param noteLength - Note length to validate.
@@ -231,6 +237,12 @@ interface TupletRatio {
231
237
  /** Played int time of (notes). */
232
238
  inTimeOf: number;
233
239
  }
240
+ /**
241
+ * Test if given argument is tuplet ratio.
242
+ * @param tupletRatio - Tuplet ratio to validate.
243
+ * @returns - True/false.
244
+ */
245
+ declare function isTupletRatio(tupletRatio: unknown): tupletRatio is TupletRatio;
234
246
  /**
235
247
  * Validate if given argument is tuplet ratio.
236
248
  * @param tupletRatio - Tuplet ratio to validate.
@@ -398,4 +410,4 @@ declare function getTempoString(tempo: Tempo): string;
398
410
  */
399
411
  declare function alterTempoSpeed(tempo: Tempo, speed: number): Tempo;
400
412
 
401
- export { AccidentalType as A, BeamGrouping as B, KeySignature as K, Mode as M, NoteLength as N, RhythmProps as R, TimeSignatures as T, type TimeSignatureString as a, TimeSignature as b, getDefaultTimeSignature as c, type Tempo as d, getDefaultTempo as e, getTempoString as f, getDefaultKeySignature as g, alterTempoSpeed as h, type NoteLengthStr as i, NoteLengthProps as j, type TupletRatio as k, validateTupletRatio as l, Tuplet as m, validateNoteLength as v };
413
+ export { AccidentalType as A, BeamGrouping as B, KeySignature as K, Mode as M, NoteLength as N, RhythmProps as R, TimeSignatures as T, type TimeSignatureString as a, TimeSignature as b, getDefaultTimeSignature as c, type Tempo as d, getDefaultTempo as e, getTempoString as f, getDefaultKeySignature as g, alterTempoSpeed as h, type NoteLengthStr as i, isNoteLength as j, NoteLengthProps as k, type TupletRatio as l, isTupletRatio as m, validateTupletRatio as n, Tuplet as o, validateNoteLength as v };
@@ -1,4 +1,4 @@
1
- import { N as Note, A as Accidental } from './note-CgCIBwvR.js';
1
+ import { N as Note, A as Accidental } from './note-CJuq5aBy.js';
2
2
 
3
3
  /** Mode enum. */
4
4
  declare enum Mode {
@@ -162,6 +162,12 @@ declare enum NoteLength {
162
162
  }
163
163
  /** String values type of note length enum. */
164
164
  type NoteLengthStr = `${NoteLength}`;
165
+ /**
166
+ * Test if given argument is note length.
167
+ * @param noteLength - Note length to validate.
168
+ * @returns - True/false.
169
+ */
170
+ declare function isNoteLength(noteLength: unknown): noteLength is NoteLength;
165
171
  /**
166
172
  * Validate if given argument is note length.
167
173
  * @param noteLength - Note length to validate.
@@ -231,6 +237,12 @@ interface TupletRatio {
231
237
  /** Played int time of (notes). */
232
238
  inTimeOf: number;
233
239
  }
240
+ /**
241
+ * Test if given argument is tuplet ratio.
242
+ * @param tupletRatio - Tuplet ratio to validate.
243
+ * @returns - True/false.
244
+ */
245
+ declare function isTupletRatio(tupletRatio: unknown): tupletRatio is TupletRatio;
234
246
  /**
235
247
  * Validate if given argument is tuplet ratio.
236
248
  * @param tupletRatio - Tuplet ratio to validate.
@@ -398,4 +410,4 @@ declare function getTempoString(tempo: Tempo): string;
398
410
  */
399
411
  declare function alterTempoSpeed(tempo: Tempo, speed: number): Tempo;
400
412
 
401
- export { AccidentalType as A, BeamGrouping as B, KeySignature as K, Mode as M, NoteLength as N, RhythmProps as R, TimeSignatures as T, type TimeSignatureString as a, TimeSignature as b, getDefaultTimeSignature as c, type Tempo as d, getDefaultTempo as e, getTempoString as f, getDefaultKeySignature as g, alterTempoSpeed as h, type NoteLengthStr as i, NoteLengthProps as j, type TupletRatio as k, validateTupletRatio as l, Tuplet as m, validateNoteLength as v };
413
+ export { AccidentalType as A, BeamGrouping as B, KeySignature as K, Mode as M, NoteLength as N, RhythmProps as R, TimeSignatures as T, type TimeSignatureString as a, TimeSignature as b, getDefaultTimeSignature as c, type Tempo as d, getDefaultTempo as e, getTempoString as f, getDefaultKeySignature as g, alterTempoSpeed as h, type NoteLengthStr as i, isNoteLength as j, NoteLengthProps as k, type TupletRatio as l, isTupletRatio as m, validateTupletRatio as n, Tuplet as o, validateNoteLength as v };
@@ -1,9 +1,9 @@
1
- import { N as Note } from '../note-eA2xPPiG.mjs';
2
- export { A as Accidental, d as DefaultGuitarNoteLabel, D as DefaultPitchNotation, G as GuitarNoteLabel, e as GuitarNoteLabelList, a as NoteLetter, P as ParsedNote, b as PitchNotation, c as PitchNotationList, S as SymbolSet, g as getPitchNotationName, f as validateGuitarNoteLabel, v as validatePitchNotation } from '../note-eA2xPPiG.mjs';
3
- import { D as Degree } from '../scale-DQP3b9Zx.mjs';
4
- export { b as Interval, I as IntervalDirection, a as IntervalQuality, c as Scale, d as ScaleFactory, S as ScaleType, i as getDefaultScale, h as getScale, e as getScaleFactory, g as getScaleFactoryList, v as validateIntervalQuality, f as validateScaleType } from '../scale-DQP3b9Zx.mjs';
5
- export { D as DefaultHandedness, a as DefaultTuningName, H as Handedness, T as TuningNameList, g as getTuningStrings, v as validateHandedness, b as validateTuningName } from '../guitar-DdexKdN6.mjs';
6
- export { A as AccidentalType, B as BeamGrouping, K as KeySignature, M as Mode, N as NoteLength, j as NoteLengthProps, i as NoteLengthStr, R as RhythmProps, d as Tempo, b as TimeSignature, a as TimeSignatureString, T as TimeSignatures, m as Tuplet, k as TupletRatio, h as alterTempoSpeed, g as getDefaultKeySignature, e as getDefaultTempo, c as getDefaultTimeSignature, f as getTempoString, v as validateNoteLength, l as validateTupletRatio } from '../tempo-dkctPkCS.mjs';
1
+ import { N as Note } from '../note-RVXvpfyV.mjs';
2
+ export { A as Accidental, d as DefaultGuitarNoteLabel, D as DefaultPitchNotation, G as GuitarNoteLabel, e as GuitarNoteLabelList, a as NoteLetter, P as ParsedNote, b as PitchNotation, c as PitchNotationList, S as SymbolSet, g as getPitchNotationName, f as validateGuitarNoteLabel, v as validatePitchNotation } from '../note-RVXvpfyV.mjs';
3
+ import { D as Degree } from '../scale-C8gHC448.mjs';
4
+ export { b as Interval, I as IntervalDirection, a as IntervalQuality, c as Scale, d as ScaleFactory, S as ScaleType, i as getDefaultScale, h as getScale, e as getScaleFactory, g as getScaleFactoryList, v as validateIntervalQuality, f as validateScaleType } from '../scale-C8gHC448.mjs';
5
+ export { D as DefaultHandedness, a as DefaultTuningName, H as Handedness, T as TuningNameList, g as getTuningStrings, v as validateHandedness, b as validateTuningName } from '../guitar-DXlB-9vK.mjs';
6
+ export { A as AccidentalType, B as BeamGrouping, K as KeySignature, M as Mode, N as NoteLength, k as NoteLengthProps, i as NoteLengthStr, R as RhythmProps, d as Tempo, b as TimeSignature, a as TimeSignatureString, T as TimeSignatures, o as Tuplet, l as TupletRatio, h as alterTempoSpeed, g as getDefaultKeySignature, e as getDefaultTempo, c as getDefaultTimeSignature, f as getTempoString, j as isNoteLength, m as isTupletRatio, v as validateNoteLength, n as validateTupletRatio } from '../tempo-BlCGZuYg.mjs';
7
7
 
8
8
  /** Chord info type. */
9
9
  type ChordInfo = {
@@ -1,9 +1,9 @@
1
- import { N as Note } from '../note-CgCIBwvR.js';
2
- export { A as Accidental, d as DefaultGuitarNoteLabel, D as DefaultPitchNotation, G as GuitarNoteLabel, e as GuitarNoteLabelList, a as NoteLetter, P as ParsedNote, b as PitchNotation, c as PitchNotationList, S as SymbolSet, g as getPitchNotationName, f as validateGuitarNoteLabel, v as validatePitchNotation } from '../note-CgCIBwvR.js';
3
- import { D as Degree } from '../scale-CBW4eTz7.js';
4
- export { b as Interval, I as IntervalDirection, a as IntervalQuality, c as Scale, d as ScaleFactory, S as ScaleType, i as getDefaultScale, h as getScale, e as getScaleFactory, g as getScaleFactoryList, v as validateIntervalQuality, f as validateScaleType } from '../scale-CBW4eTz7.js';
5
- export { D as DefaultHandedness, a as DefaultTuningName, H as Handedness, T as TuningNameList, g as getTuningStrings, v as validateHandedness, b as validateTuningName } from '../guitar-BsSayRsH.js';
6
- export { A as AccidentalType, B as BeamGrouping, K as KeySignature, M as Mode, N as NoteLength, j as NoteLengthProps, i as NoteLengthStr, R as RhythmProps, d as Tempo, b as TimeSignature, a as TimeSignatureString, T as TimeSignatures, m as Tuplet, k as TupletRatio, h as alterTempoSpeed, g as getDefaultKeySignature, e as getDefaultTempo, c as getDefaultTimeSignature, f as getTempoString, v as validateNoteLength, l as validateTupletRatio } from '../tempo-DMt3iwz9.js';
1
+ import { N as Note } from '../note-CJuq5aBy.js';
2
+ export { A as Accidental, d as DefaultGuitarNoteLabel, D as DefaultPitchNotation, G as GuitarNoteLabel, e as GuitarNoteLabelList, a as NoteLetter, P as ParsedNote, b as PitchNotation, c as PitchNotationList, S as SymbolSet, g as getPitchNotationName, f as validateGuitarNoteLabel, v as validatePitchNotation } from '../note-CJuq5aBy.js';
3
+ import { D as Degree } from '../scale-DulPFco_.js';
4
+ export { b as Interval, I as IntervalDirection, a as IntervalQuality, c as Scale, d as ScaleFactory, S as ScaleType, i as getDefaultScale, h as getScale, e as getScaleFactory, g as getScaleFactoryList, v as validateIntervalQuality, f as validateScaleType } from '../scale-DulPFco_.js';
5
+ export { D as DefaultHandedness, a as DefaultTuningName, H as Handedness, T as TuningNameList, g as getTuningStrings, v as validateHandedness, b as validateTuningName } from '../guitar-CarHGDAt.js';
6
+ export { A as AccidentalType, B as BeamGrouping, K as KeySignature, M as Mode, N as NoteLength, k as NoteLengthProps, i as NoteLengthStr, R as RhythmProps, d as Tempo, b as TimeSignature, a as TimeSignatureString, T as TimeSignatures, o as Tuplet, l as TupletRatio, h as alterTempoSpeed, g as getDefaultKeySignature, e as getDefaultTempo, c as getDefaultTimeSignature, f as getTempoString, j as isNoteLength, m as isTupletRatio, v as validateNoteLength, n as validateTupletRatio } from '../tempo-BnUjm25M.js';
7
7
 
8
8
  /** Chord info type. */
9
9
  type ChordInfo = {
@@ -1,4 +1,4 @@
1
- /* WebMusicScore v5.2.0 | (c) 2023 PahkaSoft | MIT License | Includes: Tone.js (MIT License) */
1
+ /* WebMusicScore v5.4.0 | (c) 2023 PahkaSoft | MIT License | Includes: Tone.js (MIT License) */
2
2
  "use strict";
3
3
  var __defProp = Object.defineProperty;
4
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -61,6 +61,8 @@ __export(theory_exports, {
61
61
  getScaleFactoryList: () => getScaleFactoryList,
62
62
  getTempoString: () => getTempoString,
63
63
  getTuningStrings: () => getTuningStrings,
64
+ isNoteLength: () => isNoteLength,
65
+ isTupletRatio: () => isTupletRatio,
64
66
  validateGuitarNoteLabel: () => validateGuitarNoteLabel,
65
67
  validateHandedness: () => validateHandedness,
66
68
  validateIntervalQuality: () => validateIntervalQuality,
@@ -94,7 +96,7 @@ var PitchNotation = /* @__PURE__ */ ((PitchNotation2) => {
94
96
  var PitchNotationList = import_ts_utils_lib.Utils.Enum.getEnumValues(PitchNotation);
95
97
  var DefaultPitchNotation = 0 /* Scientific */;
96
98
  function validatePitchNotation(pn) {
97
- if (import_ts_utils_lib.Utils.Is.isEnumValue(pn, PitchNotation)) {
99
+ if (import_ts_utils_lib.Guard.isEnumValue(pn, PitchNotation)) {
98
100
  return pn;
99
101
  } else {
100
102
  throw new import_core.MusicError(import_core.MusicErrorType.InvalidArg, `Invalid pitchNotation: ${pn}`);
@@ -112,7 +114,7 @@ var GuitarNoteLabel = /* @__PURE__ */ ((GuitarNoteLabel2) => {
112
114
  var DefaultGuitarNoteLabel = "Default" /* Default */;
113
115
  var GuitarNoteLabelList = import_ts_utils_lib.Utils.Enum.getEnumValues(GuitarNoteLabel);
114
116
  function validateGuitarNoteLabel(label) {
115
- if (import_ts_utils_lib.Utils.Is.isEnumValue(label, GuitarNoteLabel)) {
117
+ if (import_ts_utils_lib.Guard.isEnumValue(label, GuitarNoteLabel)) {
116
118
  return label;
117
119
  } else {
118
120
  throw new import_core.MusicError(import_core.MusicErrorType.Timesignature, `Invalid guitarNoteLabel: ${label}`);
@@ -212,19 +214,32 @@ var _Note = class _Note {
212
214
  * @returns - Note.
213
215
  */
214
216
  static getNote(noteName) {
215
- let note = this.noteByNameCache.get(noteName);
216
- if (note === void 0) {
217
+ return this.noteCache.getOrCreate(noteName, () => {
217
218
  let p = _Note.parseNote(noteName);
218
- if (!p) {
219
- throw new import_core2.MusicError(import_core2.MusicErrorType.Note, `Invalid noteName: ${noteName}`);
220
- }
221
- if (p.octave === void 0) {
222
- throw new import_core2.MusicError(import_core2.MusicErrorType.Note, `Octave is required for note.`);
223
- }
224
- note = new _Note(p.noteLetter, p.accidental, p.octave);
225
- this.noteByNameCache.set(noteName, note);
226
- }
227
- return note;
219
+ if (!p)
220
+ throw new import_core2.MusicError(import_core2.MusicErrorType.Note, `Invalid note "${noteName}".`);
221
+ if (p.octave === void 0)
222
+ throw new import_core2.MusicError(import_core2.MusicErrorType.Note, `Invalid note "${noteName}" (missing octave).`);
223
+ return new _Note(p.noteLetter, p.accidental, p.octave);
224
+ });
225
+ }
226
+ /**
227
+ * Test if given note name valid.
228
+ * @param noteName - Note name.
229
+ * @returns - True/false.
230
+ */
231
+ static isNote(noteName) {
232
+ let p = _Note.parseNote(noteName);
233
+ return p !== void 0 && p.octave !== void 0;
234
+ }
235
+ /**
236
+ * Validate given note name.
237
+ * @param noteName - Note name.
238
+ * @returns - True or throws.
239
+ */
240
+ static validateNote(noteName) {
241
+ if (this.isNote(noteName)) return true;
242
+ throw new import_core2.MusicError(import_core2.MusicErrorType.Note, `Invalid note "${noteName}"`);
228
243
  }
229
244
  /**
230
245
  * Get chromatic note. There are number of alternatives, this function uses simple logic to choose one.
@@ -232,21 +247,11 @@ var _Note = class _Note {
232
247
  * @returns - Note.
233
248
  */
234
249
  static getChromaticNote(chromaticId) {
235
- let note = this.chromaticNoteCache.get(chromaticId);
236
- if (note === void 0) {
250
+ return this.chromaticNoteCache.getOrCreate(chromaticId, () => {
237
251
  const NoteNameList = ["C/B#", "C#/Db", "D", "D#/Eb", "E/Fb", "F/E#", "F#/Gb", "G", "G#/Ab", "A", "A#/Bb", "B/Cb"];
238
252
  let noteName = NoteNameList[_Note.getChromaticClass(chromaticId)].split("/")[0] + _Note.getOctaveFromChromaticId(chromaticId);
239
- let p = _Note.parseNote(noteName);
240
- if (!p) {
241
- throw new import_core2.MusicError(import_core2.MusicErrorType.Note, `Invalid noteName: ${noteName}`);
242
- }
243
- if (p.octave === void 0) {
244
- throw new import_core2.MusicError(import_core2.MusicErrorType.Note, `Octave is required for note.`);
245
- }
246
- note = new _Note(p.noteLetter, p.accidental, p.octave);
247
- this.chromaticNoteCache.set(chromaticId, note);
248
- }
249
- return note;
253
+ return _Note.getNote(noteName);
254
+ });
250
255
  }
251
256
  static getDiatonicClass(arg) {
252
257
  if (typeof arg === "number") {
@@ -415,7 +420,7 @@ var _Note = class _Note {
415
420
  * @returns - Valid diatonic id or throws.
416
421
  */
417
422
  static validateDiatonicId(diatonicId) {
418
- if (import_ts_utils_lib2.Utils.Is.isInteger(diatonicId)) {
423
+ if (import_ts_utils_lib2.Guard.isInteger(diatonicId)) {
419
424
  return diatonicId;
420
425
  } else {
421
426
  throw new import_core2.MusicError(import_core2.MusicErrorType.Note, `Invalid diatonicId: ${diatonicId}`);
@@ -427,7 +432,7 @@ var _Note = class _Note {
427
432
  * @returns - Valid diatonic class or throws.
428
433
  */
429
434
  static validateDiatonicClass(diatonicClass) {
430
- if (import_ts_utils_lib2.Utils.Is.isIntegerBetween(diatonicClass, 0, 6)) {
435
+ if (import_ts_utils_lib2.Guard.isIntegerBetween(diatonicClass, 0, 6)) {
431
436
  return diatonicClass;
432
437
  } else {
433
438
  throw new import_core2.MusicError(import_core2.MusicErrorType.Note, `Invalid diatonicClass: ${diatonicClass}`);
@@ -439,7 +444,7 @@ var _Note = class _Note {
439
444
  * @returns - Valid chromatic id, or throws.
440
445
  */
441
446
  static validateChromaticId(chromaticId) {
442
- if (import_ts_utils_lib2.Utils.Is.isInteger(chromaticId)) {
447
+ if (import_ts_utils_lib2.Guard.isInteger(chromaticId)) {
443
448
  return chromaticId;
444
449
  } else {
445
450
  throw new import_core2.MusicError(import_core2.MusicErrorType.Note, `Invalid chromaticId: ${chromaticId}`);
@@ -451,7 +456,7 @@ var _Note = class _Note {
451
456
  * @returns - Valid chromatic class, or throws.
452
457
  */
453
458
  static validatechromaticClass(chromaticClass) {
454
- if (import_ts_utils_lib2.Utils.Is.isIntegerBetween(chromaticClass, 0, 11)) {
459
+ if (import_ts_utils_lib2.Guard.isIntegerBetween(chromaticClass, 0, 11)) {
455
460
  return chromaticClass;
456
461
  } else {
457
462
  throw new import_core2.MusicError(import_core2.MusicErrorType.Note, `Invalid chromaticClass: ${chromaticClass}`);
@@ -475,7 +480,7 @@ var _Note = class _Note {
475
480
  * @returns - Valid octave or throws.
476
481
  */
477
482
  static validateOctave(octave) {
478
- if (import_ts_utils_lib2.Utils.Is.isInteger(octave)) {
483
+ if (import_ts_utils_lib2.Guard.isInteger(octave)) {
479
484
  return octave;
480
485
  } else {
481
486
  throw new import_core2.MusicError(import_core2.MusicErrorType.Note, `Invalid octave: ${octave}`);
@@ -487,7 +492,7 @@ var _Note = class _Note {
487
492
  * @returns - Valid accidental or thorws.
488
493
  */
489
494
  static validateAccidental(acc) {
490
- if (import_ts_utils_lib2.Utils.Is.isIntegerBetween(acc, -2, 2)) {
495
+ if (import_ts_utils_lib2.Guard.isIntegerBetween(acc, -2, 2)) {
491
496
  return acc;
492
497
  } else {
493
498
  throw new import_core2.MusicError(import_core2.MusicErrorType.Note, `Invalid accidental: ${acc}`);
@@ -537,8 +542,8 @@ var _Note = class _Note {
537
542
  }
538
543
  }
539
544
  };
540
- __publicField(_Note, "noteByNameCache", /* @__PURE__ */ new Map());
541
- __publicField(_Note, "chromaticNoteCache", /* @__PURE__ */ new Map());
545
+ __publicField(_Note, "noteCache", new import_ts_utils_lib2.UniMap());
546
+ __publicField(_Note, "chromaticNoteCache", new import_ts_utils_lib2.UniMap());
542
547
  var Note = _Note;
543
548
 
544
549
  // src/theory/scale.ts
@@ -566,7 +571,7 @@ function parseDegree(degree) {
566
571
  }
567
572
  let acc = (_b = Note.getAccidental((_a = m[1]) != null ? _a : "")) != null ? _b : 0;
568
573
  let deg = +m[2];
569
- if (!import_ts_utils_lib3.Utils.Is.isInteger(acc) || acc < -2 || acc > 2 || !import_ts_utils_lib3.Utils.Is.isInteger(deg) || deg < 1) {
574
+ if (!import_ts_utils_lib3.Guard.isInteger(acc) || acc < -2 || acc > 2 || !import_ts_utils_lib3.Guard.isInteger(deg) || deg < 1) {
570
575
  throw new import_core3.MusicError(import_core3.MusicErrorType.KeySignature, `Invalid degree: ${degree}`);
571
576
  } else {
572
577
  return { deg, acc };
@@ -602,7 +607,7 @@ var _KeySignature = class _KeySignature {
602
607
  __publicField(this, "naturalScaleNotes");
603
608
  __publicField(this, "accidentalByDiatonicClass");
604
609
  __publicField(this, "orderedAccidentedNotes");
605
- if (!import_ts_utils_lib3.Utils.Is.isEnumValue(mode, Mode)) {
610
+ if (!import_ts_utils_lib3.Guard.isEnumValue(mode, Mode)) {
606
611
  throw new import_core3.MusicError(import_core3.MusicErrorType.KeySignature, `Invalid mode: ${mode}`);
607
612
  }
608
613
  let intervals = [2, 2, 1, 2, 2, 2, 1];
@@ -722,7 +727,7 @@ var KeySignature = _KeySignature;
722
727
  // src/theory/interval.ts
723
728
  var import_ts_utils_lib4 = require("@tspro/ts-utils-lib");
724
729
  var import_core4 = require("@tspro/web-music-score/core");
725
- var IntervalQualityAbbrMap = /* @__PURE__ */ new Map([
730
+ var IntervalQualityAbbrMap = new import_ts_utils_lib4.UniMap([
726
731
  ["Major", "M"],
727
732
  ["minor", "m"],
728
733
  ["Perfect", "P"],
@@ -825,7 +830,7 @@ function validateIntervalQuality(q) {
825
830
  }
826
831
  }
827
832
  function formatQuantity(q) {
828
- if (!import_ts_utils_lib4.Utils.Is.isIntegerGte(q, 1)) {
833
+ if (!import_ts_utils_lib4.Guard.isIntegerGte(q, 1)) {
829
834
  throw new import_core4.MusicError(import_core4.MusicErrorType.InvalidArg, `Invalid interval quantity: ${q}`);
830
835
  } else {
831
836
  return import_ts_utils_lib4.Utils.Math.toOrdinalNumber(q);
@@ -898,9 +903,8 @@ var Interval = class _Interval {
898
903
  * @returns - Interval abbrevated string.
899
904
  */
900
905
  toAbbrString() {
901
- var _a;
902
906
  let direction = this.direction === "Descending" ? "\u2193" : "";
903
- let quality = (_a = IntervalQualityAbbrMap.get(this.quality)) != null ? _a : "?";
907
+ let quality = IntervalQualityAbbrMap.getOrDefault(this.quality, "?");
904
908
  let quantity = this.quantity;
905
909
  return direction + quality + quantity;
906
910
  }
@@ -1006,7 +1010,7 @@ var Scale = class extends KeySignature {
1006
1010
  __publicField(this, "scaleNotes");
1007
1011
  /** Degrees (or undefined) of chromatic classes. */
1008
1012
  __publicField(this, "chromaticClassDegree");
1009
- __publicField(this, "preferredChromaticNoteCache", /* @__PURE__ */ new Map());
1013
+ __publicField(this, "preferredChromaticIdNoteCache", new import_ts_utils_lib5.SignedIndexArray());
1010
1014
  switch (scaleType) {
1011
1015
  case "Harmonic Minor" /* HarmonicMinor */:
1012
1016
  this.scaleDegrees = [1, 2, 3, 4, 5, 6, "#7"];
@@ -1071,7 +1075,7 @@ var Scale = class extends KeySignature {
1071
1075
  * @returns - Array of scale notes.
1072
1076
  */
1073
1077
  getScaleNotes(bottomNote, numOctaves) {
1074
- if (!import_ts_utils_lib5.Utils.Is.isIntegerGte(numOctaves, 1)) {
1078
+ if (!import_ts_utils_lib5.Guard.isIntegerGte(numOctaves, 1)) {
1075
1079
  throw new import_core5.MusicError(import_core5.MusicErrorType.Scale, `Invalid numOctaves: ${numOctaves}`);
1076
1080
  }
1077
1081
  let scaleNoteList = [];
@@ -1147,6 +1151,7 @@ var Scale = class extends KeySignature {
1147
1151
  return interval;
1148
1152
  }
1149
1153
  }
1154
+ // Can it be negative case?
1150
1155
  /**
1151
1156
  * Get preferred chromatic note from given chromatic id.
1152
1157
  * @param chromaticId - Chromatic id.
@@ -1154,7 +1159,7 @@ var Scale = class extends KeySignature {
1154
1159
  */
1155
1160
  getPreferredChromaticNote(chromaticId) {
1156
1161
  Note.validateChromaticId(chromaticId);
1157
- let note = this.preferredChromaticNoteCache.get(chromaticId);
1162
+ let note = this.preferredChromaticIdNoteCache.get(chromaticId);
1158
1163
  if (note) {
1159
1164
  return note;
1160
1165
  }
@@ -1170,7 +1175,7 @@ var Scale = class extends KeySignature {
1170
1175
  });
1171
1176
  note = scaleNotes.find((note2) => Note.getChromaticClass(chromaticId) === note2.chromaticClass);
1172
1177
  if (note) {
1173
- this.preferredChromaticNoteCache.set(chromaticId, note);
1178
+ this.preferredChromaticIdNoteCache.set(chromaticId, note);
1174
1179
  return note;
1175
1180
  }
1176
1181
  let diatonicIdMid = getNaturalDiatonicId(chromaticId);
@@ -1183,13 +1188,13 @@ var Scale = class extends KeySignature {
1183
1188
  for (let diatonicId = Math.max(0, diatonicIdStart); diatonicId <= diatonicIdEnd; diatonicId++) {
1184
1189
  note = new Note(diatonicId, acc);
1185
1190
  if (chromaticId === note.chromaticId) {
1186
- this.preferredChromaticNoteCache.set(chromaticId, note);
1191
+ this.preferredChromaticIdNoteCache.set(chromaticId, note);
1187
1192
  return note;
1188
1193
  }
1189
1194
  }
1190
1195
  }
1191
1196
  note = Note.getChromaticNote(chromaticId);
1192
- this.preferredChromaticNoteCache.set(chromaticId, note);
1197
+ this.preferredChromaticIdNoteCache.set(chromaticId, note);
1193
1198
  return note;
1194
1199
  }
1195
1200
  };
@@ -1309,7 +1314,7 @@ var ScaleFactoryList = [
1309
1314
  function getScaleFactoryList() {
1310
1315
  return ScaleFactoryList;
1311
1316
  }
1312
- var ScaleFactoryMap = /* @__PURE__ */ new Map();
1317
+ var ScaleFactoryMap = new import_ts_utils_lib5.UniMap();
1313
1318
  ScaleFactoryList.forEach((factory) => {
1314
1319
  if (factory instanceof ScaleFactory) {
1315
1320
  ScaleFactoryMap.set(factory.getType(), factory);
@@ -1324,7 +1329,7 @@ function getScaleFactory(scaleType) {
1324
1329
  }
1325
1330
  }
1326
1331
  function validateScaleType(scaleType) {
1327
- if (import_ts_utils_lib5.Utils.Is.isEnumValue(scaleType, ScaleType)) {
1332
+ if (import_ts_utils_lib5.Guard.isEnumValue(scaleType, ScaleType)) {
1328
1333
  return scaleType;
1329
1334
  } else {
1330
1335
  throw new import_core5.MusicError(import_core5.MusicErrorType.Scale, `Invalid scaleType: "${scaleType}"`);
@@ -1368,18 +1373,15 @@ var OkayRootNoteList = [
1368
1373
  "B",
1369
1374
  "Cb"
1370
1375
  ].map((noteName) => Note.getNote(noteName + "0"));
1371
- var okayRootNoteCache = /* @__PURE__ */ new Map();
1376
+ var okayRootNoteCache = new import_ts_utils_lib6.IndexArray();
1372
1377
  function getOkayRootNote(wantedRootNote) {
1373
- let cacheKey = wantedRootNote.chromaticClass;
1374
- let rootNote = okayRootNoteCache.get(cacheKey);
1375
- if (!rootNote) {
1376
- rootNote = OkayRootNoteList.find((note) => isEqualNote(note, wantedRootNote));
1378
+ return okayRootNoteCache.getOrCreate(wantedRootNote.chromaticClass, () => {
1379
+ let rootNote = OkayRootNoteList.find((note) => isEqualNote(note, wantedRootNote));
1377
1380
  if (!rootNote) {
1378
1381
  throw new import_core6.MusicError(import_core6.MusicErrorType.InvalidArg, `Invalid chord root note: ${wantedRootNote.formatOmitOctave(1 /* Unicode */)}`);
1379
1382
  }
1380
- okayRootNoteCache.set(cacheKey, rootNote);
1381
- }
1382
- return rootNote;
1383
+ return rootNote;
1384
+ });
1383
1385
  }
1384
1386
  function getChordNoteByDegree(chordRootNote, degree) {
1385
1387
  let chordRootNoteStr = chordRootNote.formatOmitOctave(0 /* Ascii */);
@@ -1387,7 +1389,7 @@ function getChordNoteByDegree(chordRootNote, degree) {
1387
1389
  return ks.getNoteByDegree(degree);
1388
1390
  }
1389
1391
  function removeNoteDuplicates(notes) {
1390
- return import_ts_utils_lib6.Utils.Arr.removeDuplicatesCmp(notes, isEqualNote);
1392
+ return import_ts_utils_lib6.Utils.Arr.removeDuplicates(notes, isEqualNote);
1391
1393
  }
1392
1394
  var ChordInfoList = [
1393
1395
  // Power chord
@@ -1844,7 +1846,7 @@ var Handedness = /* @__PURE__ */ ((Handedness2) => {
1844
1846
  })(Handedness || {});
1845
1847
  var DefaultHandedness = 0 /* RightHanded */;
1846
1848
  function validateHandedness(h) {
1847
- if (import_ts_utils_lib7.Utils.Is.isEnumValue(h, Handedness)) {
1849
+ if (import_ts_utils_lib7.Guard.isEnumValue(h, Handedness)) {
1848
1850
  return h;
1849
1851
  } else {
1850
1852
  throw new import_core7.MusicError(import_core7.MusicErrorType.InvalidArg, `Invalid handedness: ${h}`);
@@ -1868,7 +1870,7 @@ function getTuningStrings(tuningName) {
1868
1870
  throw new import_core7.MusicError(import_core7.MusicErrorType.InvalidArg, `Invalid tuningName: ${tuningName}`);
1869
1871
  }
1870
1872
  tuningStrings = tuningData.strings.slice().reverse().map((noteName) => Note.getNote(noteName));
1871
- if (!import_ts_utils_lib7.Utils.Is.isIntegerEq(tuningStrings.length, 6)) {
1873
+ if (!import_ts_utils_lib7.Guard.isIntegerEq(tuningStrings.length, 6)) {
1872
1874
  throw new import_core7.MusicError(import_core7.MusicErrorType.Unknown, `Tuning has ${tuningStrings.length} strings.`);
1873
1875
  }
1874
1876
  TuningStringsCache.set(tuningName, tuningStrings);
@@ -1923,8 +1925,11 @@ var NoteLength = /* @__PURE__ */ ((NoteLength3) => {
1923
1925
  NoteLength3["SixtyFourthTriplet"] = "64t";
1924
1926
  return NoteLength3;
1925
1927
  })(NoteLength || {});
1928
+ function isNoteLength(noteLength) {
1929
+ return import_ts_utils_lib8.Guard.isEnumValue(noteLength, NoteLength);
1930
+ }
1926
1931
  function validateNoteLength(noteLength) {
1927
- if (import_ts_utils_lib8.Utils.Is.isEnumValue(noteLength, NoteLength)) {
1932
+ if (isNoteLength(noteLength)) {
1928
1933
  return noteLength;
1929
1934
  } else {
1930
1935
  throw new import_core8.MusicError(import_core8.MusicErrorType.InvalidArg, `Invalid noteLength: ${noteLength}`);
@@ -1971,11 +1976,7 @@ var _NoteLengthProps = class _NoteLengthProps {
1971
1976
  * @returns - Note length props.
1972
1977
  */
1973
1978
  static get(noteLength) {
1974
- let p = this.cache.get(noteLength);
1975
- if (!p) {
1976
- this.cache.set(noteLength, p = new _NoteLengthProps(noteLength));
1977
- }
1978
- return p;
1979
+ return this.cache.getOrCreate(noteLength, () => new _NoteLengthProps(noteLength));
1979
1980
  }
1980
1981
  /**
1981
1982
  * Create note length props.
@@ -1985,7 +1986,7 @@ var _NoteLengthProps = class _NoteLengthProps {
1985
1986
  */
1986
1987
  static create(noteLength, dotCount = 0) {
1987
1988
  let noteSize = typeof noteLength === "number" ? noteLength : this.get(noteLength).noteSize;
1988
- return this.get(noteSize + (import_ts_utils_lib8.Utils.Is.isIntegerGte(dotCount, 1) ? ".".repeat(dotCount) : "n"));
1989
+ return this.get(noteSize + (import_ts_utils_lib8.Guard.isIntegerGte(dotCount, 1) ? ".".repeat(dotCount) : "n"));
1989
1990
  }
1990
1991
  /**
1991
1992
  * Compare note lengths/sizes. Whole (1) > half (2) > quarter (4), etc.
@@ -2016,10 +2017,13 @@ var _NoteLengthProps = class _NoteLengthProps {
2016
2017
  __publicField(_NoteLengthProps, "LongestNoteSize", Math.min(...import_ts_utils_lib8.Utils.Enum.getEnumValues(NoteLength).map((noteLength) => parseInt(noteLength))));
2017
2018
  /** Shortest note size (e.g. 64 = sixtyfourth note). */
2018
2019
  __publicField(_NoteLengthProps, "ShortestNoteSize", Math.max(...import_ts_utils_lib8.Utils.Enum.getEnumValues(NoteLength).map((noteLength) => parseInt(noteLength))));
2019
- __publicField(_NoteLengthProps, "cache", /* @__PURE__ */ new Map());
2020
+ __publicField(_NoteLengthProps, "cache", new import_ts_utils_lib8.UniMap());
2020
2021
  var NoteLengthProps = _NoteLengthProps;
2022
+ function isTupletRatio(tupletRatio) {
2023
+ return import_ts_utils_lib8.Guard.isObject(tupletRatio) && import_ts_utils_lib8.Guard.isIntegerBetween(tupletRatio.parts, 2, MaxTupletRatioValue) && import_ts_utils_lib8.Guard.isIntegerBetween(tupletRatio.inTimeOf, 2, MaxTupletRatioValue);
2024
+ }
2021
2025
  function validateTupletRatio(tupletRatio) {
2022
- if (import_ts_utils_lib8.Utils.Is.isObject(tupletRatio) && import_ts_utils_lib8.Utils.Is.isIntegerBetween(tupletRatio.parts, 2, MaxTupletRatioValue) && import_ts_utils_lib8.Utils.Is.isIntegerBetween(tupletRatio.inTimeOf, 2, MaxTupletRatioValue)) {
2026
+ if (isTupletRatio(tupletRatio)) {
2023
2027
  return tupletRatio;
2024
2028
  } else {
2025
2029
  throw new import_core8.MusicError(import_core8.MusicErrorType.Note, `Invalid tupletRatio ${JSON.stringify(tupletRatio)}`);
@@ -2059,7 +2063,7 @@ var _RhythmProps = class _RhythmProps {
2059
2063
  this.dotCount = dotCount != null ? dotCount : p.dotCount;
2060
2064
  this.hasStem = p.hasStem;
2061
2065
  this.isSolidNoteHead = p.isSolid;
2062
- if (import_ts_utils_lib8.Utils.Is.isObject(tupletRatio)) {
2066
+ if (import_ts_utils_lib8.Guard.isObject(tupletRatio)) {
2063
2067
  this.tupletRatio = validateTupletRatio(tupletRatio);
2064
2068
  } else if (p.isTriplet) {
2065
2069
  this.tupletRatio = Tuplet.Triplet;
@@ -2098,11 +2102,7 @@ var _RhythmProps = class _RhythmProps {
2098
2102
  if (dotCount !== void 0 || tupletRatio !== void 0) {
2099
2103
  return new _RhythmProps(noteLength, dotCount, tupletRatio);
2100
2104
  } else {
2101
- let rhythmProps = this.cache.get(noteLength);
2102
- if (!rhythmProps) {
2103
- this.cache.set(noteLength, rhythmProps = new _RhythmProps(noteLength));
2104
- }
2105
- return rhythmProps;
2105
+ return this.cache.getOrCreate(noteLength, () => new _RhythmProps(noteLength));
2106
2106
  }
2107
2107
  }
2108
2108
  /**
@@ -2124,8 +2124,8 @@ var _RhythmProps = class _RhythmProps {
2124
2124
  return a.ticks === b.ticks;
2125
2125
  }
2126
2126
  };
2127
- __publicField(_RhythmProps, "NoteSymbolMap", /* @__PURE__ */ new Map([[1, "\u{1D15D}"], [2, "\u{1D15E}"], [4, "\u{1D15F}"], [8, "\u{1D160}"], [16, "\u{1D161}"], [32, "\u{1D162}"], [64, "\u{1D163}"], [128, "\u{1D164}"]]));
2128
- __publicField(_RhythmProps, "cache", /* @__PURE__ */ new Map());
2127
+ __publicField(_RhythmProps, "NoteSymbolMap", new import_ts_utils_lib8.IndexArray([[1, "\u{1D15D}"], [2, "\u{1D15E}"], [4, "\u{1D15F}"], [8, "\u{1D160}"], [16, "\u{1D161}"], [32, "\u{1D162}"], [64, "\u{1D163}"], [128, "\u{1D164}"]]));
2128
+ __publicField(_RhythmProps, "cache", new import_ts_utils_lib8.UniMap());
2129
2129
  var RhythmProps = _RhythmProps;
2130
2130
 
2131
2131
  // src/theory/time-signature.ts
@@ -2162,25 +2162,25 @@ var TimeSignature = class {
2162
2162
  /** Beam groups (e.g. [[2], [2]] or [[2, 2], [2, 2]] (first try as [[4], [4]])). */
2163
2163
  __publicField(this, "beamGroupSizes", []);
2164
2164
  let beamGrouping;
2165
- if (import_ts_utils_lib9.Utils.Is.isEnumValue(args[0], TimeSignatures)) {
2165
+ if (import_ts_utils_lib9.Guard.isEnumValue(args[0], TimeSignatures)) {
2166
2166
  let parts = args[0].split("/");
2167
2167
  this.beatCount = +parts[0];
2168
2168
  this.beatSize = +parts[1];
2169
- if (import_ts_utils_lib9.Utils.Is.isEnumValue(args[1], BeamGrouping)) {
2169
+ if (import_ts_utils_lib9.Guard.isEnumValue(args[1], BeamGrouping)) {
2170
2170
  beamGrouping = args[1];
2171
2171
  }
2172
- } else if (import_ts_utils_lib9.Utils.Is.isIntegerGte(args[0], 2) && import_ts_utils_lib9.Utils.Is.isIntegerGte(args[1], 2)) {
2172
+ } else if (import_ts_utils_lib9.Guard.isIntegerGte(args[0], 2) && import_ts_utils_lib9.Guard.isIntegerGte(args[1], 2)) {
2173
2173
  this.beatCount = args[0];
2174
2174
  this.beatSize = args[1];
2175
- if (import_ts_utils_lib9.Utils.Is.isEnumValue(args[2], BeamGrouping)) {
2175
+ if (import_ts_utils_lib9.Guard.isEnumValue(args[2], BeamGrouping)) {
2176
2176
  beamGrouping = args[2];
2177
2177
  }
2178
2178
  } else {
2179
2179
  throw new import_core9.MusicError(import_core9.MusicErrorType.Timesignature, `Invalid args: ${args}`);
2180
2180
  }
2181
- if (!import_ts_utils_lib9.Utils.Is.isIntegerGte(this.beatCount, 1)) {
2181
+ if (!import_ts_utils_lib9.Guard.isIntegerGte(this.beatCount, 1)) {
2182
2182
  throw new import_core9.MusicError(import_core9.MusicErrorType.Timesignature, `Invalid beatCount: ${this.beatCount}`);
2183
- } else if (!import_ts_utils_lib9.Utils.Is.isIntegerGte(this.beatSize, 1)) {
2183
+ } else if (!import_ts_utils_lib9.Guard.isIntegerGte(this.beatSize, 1)) {
2184
2184
  throw new import_core9.MusicError(import_core9.MusicErrorType.Timesignature, `Invalid beatSize: ${this.beatSize}`);
2185
2185
  }
2186
2186
  let { noteLength, ticks } = NoteLengthProps.create(this.beatSize);
@@ -2195,7 +2195,7 @@ var TimeSignature = class {
2195
2195
  } else if (this.is(3, 8)) {
2196
2196
  this.beamGroupSizes = [[3]];
2197
2197
  } else if (this.is(5, 8)) {
2198
- if (!import_ts_utils_lib9.Utils.Is.isUndefined(beamGrouping) && beamGrouping !== "2-3" /* _2_3 */ && beamGrouping !== "3-2" /* _3_2 */) {
2198
+ if (!import_ts_utils_lib9.Guard.isUndefined(beamGrouping) && beamGrouping !== "2-3" /* _2_3 */ && beamGrouping !== "3-2" /* _3_2 */) {
2199
2199
  throw new import_core9.MusicError(import_core9.MusicErrorType.Timesignature, `Invalid beam grouping "${beamGrouping}" for time signature "${this.toString()}".`);
2200
2200
  } else {
2201
2201
  this.beamGroupSizes = beamGrouping === "3-2" /* _3_2 */ ? [[3], [2]] : [[2], [3]];
@@ -2204,7 +2204,7 @@ var TimeSignature = class {
2204
2204
  } else if (this.is(6, 8)) {
2205
2205
  this.beamGroupSizes = [[3], [3]];
2206
2206
  } else if (this.is(7, 8)) {
2207
- if (!import_ts_utils_lib9.Utils.Is.isUndefined(beamGrouping) && beamGrouping !== "2-2-3" /* _2_2_3 */ && beamGrouping !== "3-2-2" /* _3_2_2 */) {
2207
+ if (!import_ts_utils_lib9.Guard.isUndefined(beamGrouping) && beamGrouping !== "2-2-3" /* _2_2_3 */ && beamGrouping !== "3-2-2" /* _3_2_2 */) {
2208
2208
  throw new import_core9.MusicError(import_core9.MusicErrorType.Timesignature, `Invalid beam grouping "${beamGrouping}" for time signature "${this.toString()}".`);
2209
2209
  } else {
2210
2210
  this.beamGroupSizes = beamGrouping === "3-2-2" /* _3_2_2 */ ? [[3], [2], [2]] : [[2], [2], [3]];
@@ -2307,6 +2307,8 @@ var import_core10 = require("@tspro/web-music-score/core");
2307
2307
  getScaleFactoryList,
2308
2308
  getTempoString,
2309
2309
  getTuningStrings,
2310
+ isNoteLength,
2311
+ isTupletRatio,
2310
2312
  validateGuitarNoteLabel,
2311
2313
  validateHandedness,
2312
2314
  validateIntervalQuality,