@libraz/libcantus 1.0.1 → 1.2.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 (142) hide show
  1. package/README.md +27 -65
  2. package/README_ja.md +28 -66
  3. package/dist/analyze/index.cjs +11 -7
  4. package/dist/analyze/index.cjs.map +1 -1
  5. package/dist/analyze/index.d.cts +79 -144
  6. package/dist/analyze/index.d.ts +79 -144
  7. package/dist/analyze/index.js +20 -16
  8. package/dist/chunk-35NBV2FT.cjs +145 -0
  9. package/dist/chunk-35NBV2FT.cjs.map +1 -0
  10. package/dist/{chunk-UADYAYAT.cjs → chunk-3R3QVKY5.cjs} +1353 -580
  11. package/dist/chunk-3R3QVKY5.cjs.map +1 -0
  12. package/dist/{chunk-WWURE4XT.cjs → chunk-76ZBTRG2.cjs} +624 -729
  13. package/dist/chunk-76ZBTRG2.cjs.map +1 -0
  14. package/dist/{chunk-FVSI36UV.js → chunk-7KG3RTYS.js} +197 -110
  15. package/dist/chunk-7KG3RTYS.js.map +1 -0
  16. package/dist/{chunk-VTI6FOLB.js → chunk-AGOVW7U6.js} +709 -133
  17. package/dist/chunk-AGOVW7U6.js.map +1 -0
  18. package/dist/{chunk-E3F4AHAH.cjs → chunk-CGBADIO5.cjs} +221 -134
  19. package/dist/chunk-CGBADIO5.cjs.map +1 -0
  20. package/dist/{chunk-6XH6QZYQ.cjs → chunk-DSMJRXCZ.cjs} +1455 -849
  21. package/dist/chunk-DSMJRXCZ.cjs.map +1 -0
  22. package/dist/{chunk-PKFNUHDY.js → chunk-FBH75DAY.js} +1218 -612
  23. package/dist/chunk-FBH75DAY.js.map +1 -0
  24. package/dist/chunk-H2KJHBW4.js +3329 -0
  25. package/dist/chunk-H2KJHBW4.js.map +1 -0
  26. package/dist/chunk-HPVSH7SF.cjs +2294 -0
  27. package/dist/chunk-HPVSH7SF.cjs.map +1 -0
  28. package/dist/{chunk-MXO72PLY.cjs → chunk-HWHGOVO6.cjs} +21 -19
  29. package/dist/chunk-HWHGOVO6.cjs.map +1 -0
  30. package/dist/chunk-HYJJ2V2I.js +2294 -0
  31. package/dist/chunk-HYJJ2V2I.js.map +1 -0
  32. package/dist/{chunk-AFM2ULJH.cjs → chunk-J7FHVZII.cjs} +1567 -1067
  33. package/dist/chunk-J7FHVZII.cjs.map +1 -0
  34. package/dist/chunk-K6OZXIR6.js +1 -0
  35. package/dist/{chunk-H3VORETI.js → chunk-M5RYMAFI.js} +487 -592
  36. package/dist/chunk-M5RYMAFI.js.map +1 -0
  37. package/dist/chunk-NB25P3EH.js +363 -0
  38. package/dist/chunk-NB25P3EH.js.map +1 -0
  39. package/dist/{chunk-TTCLJX6D.js → chunk-NFJ4P6ZZ.js} +10 -8
  40. package/dist/chunk-NFJ4P6ZZ.js.map +1 -0
  41. package/dist/chunk-NM7UAMC3.cjs +457 -0
  42. package/dist/chunk-NM7UAMC3.cjs.map +1 -0
  43. package/dist/chunk-PM4XJE2Y.cjs +363 -0
  44. package/dist/chunk-PM4XJE2Y.cjs.map +1 -0
  45. package/dist/chunk-PUKJP2Z5.js +145 -0
  46. package/dist/chunk-PUKJP2Z5.js.map +1 -0
  47. package/dist/{chunk-VOHZB45S.js → chunk-Q6LFSAKV.js} +1321 -821
  48. package/dist/chunk-Q6LFSAKV.js.map +1 -0
  49. package/dist/{chunk-INHVXP6Z.js → chunk-RFIBF2RR.js} +1203 -430
  50. package/dist/chunk-RFIBF2RR.js.map +1 -0
  51. package/dist/{chunk-Q2WGKJNN.cjs → chunk-S5BKZZGM.cjs} +699 -123
  52. package/dist/chunk-S5BKZZGM.cjs.map +1 -0
  53. package/dist/chunk-SGLEQVJH.cjs +3329 -0
  54. package/dist/chunk-SGLEQVJH.cjs.map +1 -0
  55. package/dist/chunk-UGLFDG7L.cjs +1 -0
  56. package/dist/chunk-UGLFDG7L.cjs.map +1 -0
  57. package/dist/{chunk-YH3BIKHH.js → chunk-UMWZ4ZET.js} +146 -49
  58. package/dist/chunk-UMWZ4ZET.js.map +1 -0
  59. package/dist/{index-szBv3496.d.ts → coerce-DP0vYu-x.d.ts} +286 -199
  60. package/dist/{index-C_8o--VE.d.cts → coerce-DRERzdve.d.cts} +286 -199
  61. package/dist/core/index.cjs +9 -5
  62. package/dist/core/index.cjs.map +1 -1
  63. package/dist/core/index.d.cts +122 -108
  64. package/dist/core/index.d.ts +122 -108
  65. package/dist/core/index.js +32 -28
  66. package/dist/generate/index.cjs +8 -8
  67. package/dist/generate/index.d.cts +168 -84
  68. package/dist/generate/index.d.ts +168 -84
  69. package/dist/generate/index.js +7 -7
  70. package/dist/{index-CGpRv5sl.d.cts → index-9eoQs2C1.d.ts} +34 -19
  71. package/dist/{index-CCNJRG-P.d.cts → index-B9QLziDe.d.cts} +293 -56
  72. package/dist/{index-Dzr13q3d.d.cts → index-BBWNZS0f.d.cts} +135 -58
  73. package/dist/{index-9wcMhG73.d.ts → index-BHIUyjhZ.d.ts} +293 -56
  74. package/dist/{index-BGFW-8P2.d.cts → index-BJgP97N1.d.ts} +196 -114
  75. package/dist/{index-CunYKLiu.d.ts → index-BL5N2Oyz.d.cts} +1 -1
  76. package/dist/{index-Cj49F892.d.ts → index-BMweUlm5.d.cts} +63 -23
  77. package/dist/{index-CgHqxdps.d.ts → index-BNSM-DSk.d.cts} +196 -114
  78. package/dist/{index-D57QRbVn.d.ts → index-BRMbPkHE.d.ts} +480 -254
  79. package/dist/{index-Chbst3Jx.d.ts → index-CJBBiAmU.d.ts} +135 -58
  80. package/dist/{index-BkGmlyI3.d.cts → index-CL4b4gUQ.d.ts} +63 -23
  81. package/dist/{index-B9MNZboQ.d.ts → index-Cy15oTvh.d.cts} +52 -22
  82. package/dist/{index-B9MNZboQ.d.cts → index-Cy15oTvh.d.ts} +52 -22
  83. package/dist/{index-BO6xE9YU.d.cts → index-DGCNKAUr.d.cts} +480 -254
  84. package/dist/{index-B4o55NDr.d.cts → index-Dw2DP7vm.d.ts} +1 -1
  85. package/dist/{index-G1uwGGWQ.d.ts → index-cHvbYgJI.d.cts} +34 -19
  86. package/dist/index.cjs +42 -14
  87. package/dist/index.cjs.map +1 -1
  88. package/dist/index.d.cts +14 -14
  89. package/dist/index.d.ts +14 -14
  90. package/dist/index.js +82 -54
  91. package/dist/{masks-DYbE485J.d.cts → masks-Cc7-MzzY.d.ts} +49 -2
  92. package/dist/{masks-DYbE485J.d.ts → masks-pADfTOiD.d.cts} +49 -2
  93. package/dist/model/index.cjs +19 -12
  94. package/dist/model/index.cjs.map +1 -1
  95. package/dist/model/index.d.cts +504 -182
  96. package/dist/model/index.d.ts +504 -182
  97. package/dist/model/index.js +18 -11
  98. package/dist/{positional-Cptlj-xs.d.ts → positional-DJgs6ltD.d.ts} +85 -8
  99. package/dist/{positional-DvH_sd8u.d.cts → positional-DMZer-FM.d.cts} +85 -8
  100. package/dist/theory/index.cjs +35 -6
  101. package/dist/theory/index.cjs.map +1 -1
  102. package/dist/theory/index.d.cts +257 -62
  103. package/dist/theory/index.d.ts +257 -62
  104. package/dist/theory/index.js +41 -12
  105. package/package.json +7 -5
  106. package/dist/chunk-2LCPM3EG.js +0 -3224
  107. package/dist/chunk-2LCPM3EG.js.map +0 -1
  108. package/dist/chunk-6XH6QZYQ.cjs.map +0 -1
  109. package/dist/chunk-6XPTBE7Y.cjs +0 -49
  110. package/dist/chunk-6XPTBE7Y.cjs.map +0 -1
  111. package/dist/chunk-AFM2ULJH.cjs.map +0 -1
  112. package/dist/chunk-B6XNKWZV.cjs +0 -3224
  113. package/dist/chunk-B6XNKWZV.cjs.map +0 -1
  114. package/dist/chunk-E3F4AHAH.cjs.map +0 -1
  115. package/dist/chunk-ELCTZUJJ.js +0 -379
  116. package/dist/chunk-ELCTZUJJ.js.map +0 -1
  117. package/dist/chunk-FVSI36UV.js.map +0 -1
  118. package/dist/chunk-H3VORETI.js.map +0 -1
  119. package/dist/chunk-H42UHPYW.js +0 -1577
  120. package/dist/chunk-H42UHPYW.js.map +0 -1
  121. package/dist/chunk-HFPS7JFD.js +0 -1
  122. package/dist/chunk-INHVXP6Z.js.map +0 -1
  123. package/dist/chunk-K4ZJUGF4.cjs +0 -379
  124. package/dist/chunk-K4ZJUGF4.cjs.map +0 -1
  125. package/dist/chunk-KNJEKLKV.js +0 -49
  126. package/dist/chunk-KNJEKLKV.js.map +0 -1
  127. package/dist/chunk-MXO72PLY.cjs.map +0 -1
  128. package/dist/chunk-NLEU4QSE.cjs +0 -360
  129. package/dist/chunk-NLEU4QSE.cjs.map +0 -1
  130. package/dist/chunk-OE6WK2Y2.cjs +0 -1577
  131. package/dist/chunk-OE6WK2Y2.cjs.map +0 -1
  132. package/dist/chunk-PKFNUHDY.js.map +0 -1
  133. package/dist/chunk-Q2WGKJNN.cjs.map +0 -1
  134. package/dist/chunk-RHIJ3S4I.cjs +0 -1
  135. package/dist/chunk-RHIJ3S4I.cjs.map +0 -1
  136. package/dist/chunk-TTCLJX6D.js.map +0 -1
  137. package/dist/chunk-UADYAYAT.cjs.map +0 -1
  138. package/dist/chunk-VOHZB45S.js.map +0 -1
  139. package/dist/chunk-VTI6FOLB.js.map +0 -1
  140. package/dist/chunk-WWURE4XT.cjs.map +0 -1
  141. package/dist/chunk-YH3BIKHH.js.map +0 -1
  142. /package/dist/{chunk-HFPS7JFD.js.map → chunk-K6OZXIR6.js.map} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/errors/index.ts","../src/core/instrument/articulation.ts","../src/core/meter/internal.ts","../src/core/validation/index.ts","../src/core/pitch/naming.ts","../src/core/pitch/index.ts","../src/core/interval/index.ts","../src/core/meter/index.ts"],"sourcesContent":["/**\n * The library's error taxonomy.\n *\n * Every failure this library raises falls into one of three kinds, and the kind\n * decides what a caller can do about it. Batch-voicing a lead sheet, for\n * instance, has to tell \"fix the input\" apart from \"loosen the constraints\",\n * and a message string is not a contract.\n *\n * The classes extend the built-in error types a caller would otherwise catch —\n * a rejected argument is still a `RangeError` — so the `code` narrows an\n * existing category rather than replacing it.\n */\n\n/**\n * What kind of failure an error reports.\n *\n * - `INVALID_INPUT`: an argument is malformed or out of range. The caller's\n * input must change.\n * - `NO_SOLUTION`: the input is valid but nothing satisfies the constraints.\n * The constraints must change, or the failure must be accepted.\n * - `BUDGET_EXCEEDED`: the requested work is larger than the synchronous\n * generation budget. The request must be smaller, or the budget larger.\n *\n * @category Core\n */\nexport type LibcantusErrorCode = 'INVALID_INPUT' | 'NO_SOLUTION' | 'BUDGET_EXCEEDED';\n\n/**\n * Any error this library raises, as a union of its three classes.\n *\n * The type a non-throwing entry point reports its failure as: a caller that\n * holds one of these already knows it carries a {@link LibcantusErrorCode} and\n * a message worth showing.\n *\n * @category Core\n */\nexport type LibcantusError = InvalidInputError | NoSolutionError | BudgetExceededError;\n\n/**\n * The outcome of a parse that reports failure instead of throwing it.\n *\n * A text field is parsed on every keystroke, and most of those keystrokes are\n * halfway through a valid symbol, so failure is the normal case rather than an\n * exceptional one. The error travels in the result — not as `null` — because an\n * input field has to say what is wrong with what was typed.\n *\n * @typeParam T The value a successful parse produces.\n * @category Core\n * @example\n * ```ts\n * import { tryParseChordSymbol } from '@libraz/libcantus';\n * const result = tryParseChordSymbol('Cmaj');\n * const label = result.ok ? result.value.quality : result.error.message;\n * ```\n */\nexport type ParseResult<T> = { ok: true; value: T } | { ok: false; error: LibcantusError };\n\n/**\n * Report a caught value as a failed parse, or re-throw what is not ours.\n *\n * Not part of the package's public surface: the non-throwing parsers share it\n * so that a bug inside one of them surfaces as the crash it is instead of being\n * reported as invalid input.\n *\n * @param error The caught value.\n * @returns The failed parse result.\n */\nexport function parseFailure(error: unknown): { ok: false; error: LibcantusError } {\n if (isLibcantusError(error)) {\n return { ok: false, error };\n }\n throw error;\n}\n\n/**\n * Read a parse result, throwing its error when it failed.\n *\n * Not part of the package's public surface: it is how each throwing parser is\n * written on top of its non-throwing sibling, so the two cannot disagree about\n * what is valid.\n *\n * @param result The result to read.\n * @returns The parsed value.\n * @throws The result's own error when the parse failed.\n */\nexport function unwrapParse<T>(result: ParseResult<T>): T {\n if (result.ok) {\n return result.value;\n }\n throw result.error;\n}\n\n/**\n * A rejected argument: malformed, out of range, or naming something unknown.\n *\n * @category Core\n */\nexport class InvalidInputError extends RangeError {\n readonly code = 'INVALID_INPUT' as const;\n override readonly name = 'InvalidInputError';\n}\n\n/**\n * A valid request with no answer: no voicing fits the given ranges, no chord\n * matches the pitches, no preset claims the style.\n *\n * @category Core\n */\nexport class NoSolutionError extends Error {\n readonly code = 'NO_SOLUTION' as const;\n override readonly name = 'NoSolutionError';\n\n /**\n * Where in a sequence the failure occurred, when the operation was working\n * through one — the chord index of a progression, say.\n */\n readonly at: number | undefined;\n\n constructor(message: string, options: { at?: number } = {}) {\n super(message);\n this.at = options.at;\n }\n}\n\n/**\n * Work that would exceed the synchronous generation budget.\n *\n * @category Core\n */\nexport class BudgetExceededError extends RangeError {\n readonly code = 'BUDGET_EXCEEDED' as const;\n override readonly name = 'BudgetExceededError';\n}\n\n/**\n * Whether a caught value is one of this library's coded errors.\n *\n * @param value The caught value.\n * @returns True when it carries a {@link LibcantusErrorCode}.\n * @example\n * ```ts\n * import { isLibcantusError, voiceChord, parseChordSymbol } from '@libraz/libcantus';\n * try {\n * voiceChord(parseChordSymbol('C'), { ranges: [] });\n * } catch (error) {\n * if (isLibcantusError(error) && error.code === 'NO_SOLUTION') {\n * // loosen the constraints rather than blaming the input\n * }\n * }\n * ```\n * @category Core\n */\nexport function isLibcantusError(\n value: unknown,\n): value is InvalidInputError | NoSolutionError | BudgetExceededError {\n if (typeof value !== 'object' || value === null || !('code' in value)) {\n return false;\n }\n const code = value.code;\n return code === 'INVALID_INPUT' || code === 'NO_SOLUTION' || code === 'BUDGET_EXCEEDED';\n}\n","/**\n * Every playing technique a note can carry, in declaration order.\n *\n * These name intent, not a rendering: how `flam` becomes a grace stroke or\n * `slide` becomes pitch bend is the caller's decision, because it depends on the\n * sampler, key switches, and controller layout in use. Carrying the intent\n * instead of a baked note pair is what lets any phrase be flammed, ghosted, or\n * muted without the generator having to know how it will be voiced.\n *\n * @category Core\n */\nexport const ARTICULATIONS = Object.freeze([\n 'accent',\n 'ghost',\n 'staccato',\n 'legato',\n 'slide',\n 'hammer',\n 'mute',\n 'flam',\n 'drag',\n 'roll',\n 'choke',\n 'open',\n] as const);\n\n/**\n * How a note is played, independent of its pitch and length.\n *\n * @category Core\n */\nexport type Articulation = (typeof ARTICULATIONS)[number];\n","/**\n * Meter arithmetic shared by the meter module and the validation guards.\n *\n * These helpers never validate: they are the single definition of how a time\n * signature is read, so the guard that rejects a malformed signature and the\n * functions that use a validated one cannot drift apart. Everything here is\n * integer arithmetic on the numerator, so a bar's pulse count is exact rather\n * than the result of dividing two floats.\n */\n\nimport type { MeterChange, MeterMap, TimeSignature } from './index.js';\n\n/**\n * A meter in the plain data the library reads it as: one signature, or the map\n * of a piece that changes meter.\n *\n * What {@link MeterLike} resolves to, and the type every function below the\n * entry points works in — the text form is read once, at the boundary.\n *\n * @category Rhythm & Meter\n */\nexport type MeterData = TimeSignature | MeterMap;\n\n/**\n * Largest difference between two beats that are the same beat.\n *\n * Float residue rather than playing: it is what arithmetic over beat positions\n * leaves behind — a bar length times a bar count, a grid origin plus a whole\n * number of steps — and nothing musical is measured in it. A bar boundary\n * reached by accumulating tuplet durations lands an epsilon short of it, and a\n * beat an epsilon short of a bar line belongs to the bar it is arriving at\n * rather than to the one it is leaving.\n *\n * Declared here because the meter layer is below every other reader of the beat\n * axis; the analysis layer's `BEAT_EPS` is this number, re-exported, so the\n * single-signature path and the map path cannot come to differ by a tolerance.\n */\nexport const BEAT_EPS = 1e-9;\n\n/** Length of one denominator unit in quarter-note beats. */\nexport function unitBeatsOf(ts: TimeSignature): number {\n return 4 / ts.denominator;\n}\n\n/**\n * Whether a numerator reads as compound: a multiple of three greater than\n * three, so its main pulses each divide into three.\n */\nexport function isCompoundNumerator(numerator: number): boolean {\n return numerator % 3 === 0 && numerator > 3;\n}\n\n/** Sum of an additive grouping, or undefined when there is none. */\nexport function groupingSumOf(ts: TimeSignature): number | undefined {\n const grouping = ts.grouping;\n if (grouping === undefined) {\n return undefined;\n }\n let sum = 0;\n for (const entry of grouping) {\n sum += entry;\n }\n return sum;\n}\n\n/**\n * Whether the signature's grouping counts denominator units rather than\n * compound pulses.\n *\n * A compound numerator normally groups into pulses of three — 9/8 is three\n * dotted-quarter pulses — but the same signature is also how additive metres\n * are written, where 9/8 means 2+2+2+3 quavers. A grouping that sums to the\n * numerator is written in units and selects that additive reading, with one\n * exception: groups of nothing but threes spell the compound division itself\n * (9/8 as [3, 3, 3], 6/8 as [3, 3]), so they keep the compound reading rather\n * than flattening the bar into equal quaver pulses.\n */\nexport function isAdditiveReading(ts: TimeSignature): boolean {\n const grouping = ts.grouping;\n const sum = groupingSumOf(ts);\n if (grouping === undefined || sum === undefined || sum === 0) {\n return false;\n }\n if (!isCompoundNumerator(ts.numerator) || sum !== ts.numerator) {\n return false;\n }\n return !grouping.every((entry) => entry === 3);\n}\n\n/** Number of main pulses per bar under the signature's effective reading. */\nexport function pulseCountOf(ts: TimeSignature): number {\n if (isAdditiveReading(ts)) {\n return ts.numerator;\n }\n return isCompoundNumerator(ts.numerator) ? ts.numerator / 3 : ts.numerator;\n}\n\n/** Length of one main pulse in quarter-note beats, under the same reading. */\nexport function pulseBeatsOf(ts: TimeSignature): number {\n return (ts.numerator * unitBeatsOf(ts)) / pulseCountOf(ts);\n}\n\n/**\n * The signature's grouping measured in main pulses, or undefined when it has\n * none.\n *\n * A grouping is written either in main pulses (9/8 as [1, 1, 1], 7/8 as\n * [2, 2, 3]) or in denominator units (9/8 as [3, 3, 3] or [2, 2, 2, 3]), and\n * the two coincide wherever a pulse is one unit. Group heads are found by\n * counting pulses, so the unit spelling of a compound bar is divided down to\n * the pulses it describes.\n */\nexport function pulseGroupingOf(ts: TimeSignature): number[] | undefined {\n const grouping = ts.grouping;\n if (grouping === undefined) {\n return undefined;\n }\n const pulses = pulseCountOf(ts);\n if (groupingSumOf(ts) === pulses) {\n return grouping;\n }\n // The only accepted grouping that does not count pulses is the all-threes\n // spelling of a compound bar, whose groups are three units to the pulse.\n return grouping.map((entry) => entry / 3);\n}\n\n/** Length of a bar in quarter-note beats. */\nexport function barBeatsOf(ts: TimeSignature): number {\n return ts.numerator * unitBeatsOf(ts);\n}\n\n/** Whether a meter argument is a map of changes rather than one signature. */\nexport function isMeterMap(meter: MeterData): meter is MeterMap {\n return Array.isArray(meter);\n}\n\n/** A fresh signature, sharing neither its object nor its grouping array. */\nexport function copyTimeSignature(ts: TimeSignature): TimeSignature {\n return ts.grouping === undefined\n ? { numerator: ts.numerator, denominator: ts.denominator }\n : { numerator: ts.numerator, denominator: ts.denominator, grouping: [...ts.grouping] };\n}\n\n/** A fresh map, sharing no entry and no signature with the one given. */\nexport function copyMeterMap(map: MeterMap): MeterMap {\n const copy: MeterMap = new Array<MeterChange>(map.length);\n for (let i = 0; i < map.length; i += 1) {\n const entry = map[i];\n copy[i] =\n entry === undefined\n ? { startBeat: 0, ts: { numerator: 4, denominator: 4 } }\n : { startBeat: entry.startBeat, ts: copyTimeSignature(entry.ts) };\n }\n return copy;\n}\n\n/** A fresh copy of whichever meter shape the data is. */\nexport function copyMeterData(data: MeterData): MeterData {\n return isMeterMap(data) ? copyMeterMap(data) : copyTimeSignature(data);\n}\n\n/**\n * The bar arithmetic of one meter map, precomputed so that a positional question\n * finds its entry by halving the range rather than by re-deriving the bars\n * before it.\n *\n * A per-slot analysis pass asks thousands of positional questions of the same\n * map. Each of them still reads the array, since a caller may write to it\n * between two of them; what none of them repeats is the derivation — the bar\n * lengths, the running bar count and the arrays holding them — which is the part\n * that would make such a pass quadratic in the number of meter changes.\n */\ntype MeterIndex = {\n /** Onsets in map order, as they read when the index was built. */\n startBeats: number[];\n /** Each entry's signature, as it read when the index was built. */\n signatures: TimeSignature[];\n /** Beat each entry's bars are counted from. */\n barAnchors: number[];\n /** Bar length in quarter-note beats of each entry's signature. */\n barBeats: number[];\n /** Bars completed before each entry — the prefix sum of the spans above. */\n barsBefore: number[];\n /** Whether the map had passed validation when the index was built. */\n validated: boolean;\n};\n\n/**\n * Indexes held against the identity of the map they describe.\n *\n * A caller keeps its own array and may write to it after the library has read\n * it, so an index is only trusted while every entry still reads as it did when\n * the index was built — the same onsets and the same signatures, compared by\n * value down to the grouping. Anything else rebuilds, and a map that had passed\n * validation is validated again. The index answers out of one snapshot of the\n * whole array, so a map written to in place mid-analysis never yields a position\n * derived from a cached bar length of one entry and a live signature of another.\n */\nconst INDEX_CACHE = new WeakMap<MeterMap, MeterIndex>();\n\n/**\n * The map last read entry by entry, and the index that read produced.\n *\n * Reading every entry is what a caller's array costs to trust, and one question\n * pays it once: the guard that answers whether the map is valid reads the whole\n * array, and the helpers that then place the bars answer out of the index that\n * read produced rather than reading it again per bar arithmetic. The guard is\n * what writes the mark, never what reads it.\n *\n * The mark itself is a module variable and outlives the question that set it.\n * What makes it safe is not that it is cleared but that every public meter\n * entrance reaches these helpers only after that same call has read the whole\n * array through the guard, and JavaScript hands a caller no window in between.\n * A helper reached without such a read would answer out of a previous reading\n * of the same array, so any new caller belongs behind the guard as well.\n */\nlet readMap: MeterMap | undefined;\nlet readIndex: MeterIndex | undefined;\n\n/** Record the index a full read of `map` produced, and hand it back. */\nfunction rememberRead(map: MeterMap, index: MeterIndex): MeterIndex {\n readMap = map;\n readIndex = index;\n return index;\n}\n\n/** Whether two signatures name the same bar, grouping included. */\nfunction sameSignature(ts: TimeSignature, snapshot: TimeSignature): boolean {\n if (typeof ts !== 'object' || ts === null) {\n return false;\n }\n if (ts.numerator !== snapshot.numerator || ts.denominator !== snapshot.denominator) {\n return false;\n }\n const grouping = ts.grouping;\n const was = snapshot.grouping;\n if (grouping === undefined || was === undefined) {\n return grouping === was;\n }\n if (grouping.length !== was.length) {\n return false;\n }\n for (let i = 0; i < was.length; i += 1) {\n if (grouping[i] !== was[i]) {\n return false;\n }\n }\n return true;\n}\n\n/**\n * Whether a cached index still describes the array it was built from.\n *\n * Every entry is compared, and by value: a signature edited in place keeps both\n * the array's length and its object identities, so anything cheaper reports a\n * map that has changed as one that has not — and the change may be the one that\n * makes the map invalid.\n */\nfunction describesMap(index: MeterIndex, map: MeterMap): boolean {\n if (index.startBeats.length !== map.length) {\n return false;\n }\n for (let i = 0; i < map.length; i += 1) {\n const entry = map[i];\n const signature = index.signatures[i];\n if (\n entry === undefined ||\n entry === null ||\n signature === undefined ||\n entry.startBeat !== index.startBeats[i] ||\n !sameSignature(entry.ts, signature)\n ) {\n return false;\n }\n }\n return true;\n}\n\n/**\n * Build and cache the index of a map.\n *\n * A meter change starts a new bar, so a span that does not divide evenly into\n * its own bars still contributes a whole final bar — an incomplete bar before a\n * change is a bar all the same.\n */\nfunction buildMeterIndex(map: MeterMap, validated: boolean): MeterIndex {\n const startBeats = new Array<number>(map.length);\n const signatures = new Array<TimeSignature>(map.length);\n const barAnchors = new Array<number>(map.length);\n const barBeats = new Array<number>(map.length);\n const barsBefore = new Array<number>(map.length);\n let bars = 0;\n for (let i = 0; i < map.length; i += 1) {\n const entry = map[i];\n const startBeat = entry?.startBeat ?? 0;\n const barLen = entry === undefined ? 0 : barBeatsOf(entry.ts);\n // The opening signature counts its bars from beat 0 rather than from the\n // onset the map is written at: beat 0 is the downbeat, so a map whose first\n // entry sits at the pickup it covers lays its bar lines exactly where the\n // bare signature lays them. Every later entry starts a bar of its own.\n const anchor = i === 0 ? 0 : startBeat;\n startBeats[i] = startBeat;\n signatures[i] =\n entry === undefined ? { numerator: 4, denominator: 4 } : copyTimeSignature(entry.ts);\n barAnchors[i] = anchor;\n barBeats[i] = barLen;\n barsBefore[i] = bars;\n const next = map[i + 1];\n if (next !== undefined && barLen > 0) {\n bars += Math.max(1, Math.ceil((next.startBeat - anchor) / barLen - BEAT_EPS));\n }\n }\n const index: MeterIndex = { startBeats, signatures, barAnchors, barBeats, barsBefore, validated };\n INDEX_CACHE.set(map, index);\n return rememberRead(map, index);\n}\n\n/**\n * The map's index, built on first use and rebuilt when the map has changed.\n *\n * Reached only from a question that has just read the map through the guard\n * below, so the mark that read left is what says the index still describes the\n * array. A map arriving here unread is compared entry by entry as it would be\n * there.\n */\nfunction meterIndexOf(map: MeterMap): MeterIndex {\n if (readMap === map && readIndex !== undefined) {\n return readIndex;\n }\n const cached = INDEX_CACHE.get(map);\n return cached !== undefined && describesMap(cached, map)\n ? rememberRead(map, cached)\n : buildMeterIndex(map, false);\n}\n\n/**\n * Whether the map has already passed validation and is unchanged since.\n *\n * The guard that lets a per-slot pass re-enter a validating entry point without\n * re-deriving the bar arithmetic of the whole map on every slot. What it still\n * pays on every slot is a comparison per entry: an array the caller keeps says\n * nothing about whether it has been written to since, so the only way to know a\n * validated map is still the one that was validated is to read it.\n */\nexport function isValidatedMeterMap(map: MeterMap): boolean {\n const cached = INDEX_CACHE.get(map);\n if (cached?.validated !== true || !describesMap(cached, map)) {\n return false;\n }\n rememberRead(map, cached);\n return true;\n}\n\n/** Record that a map passed validation, and precompute its bar arithmetic. */\nexport function rememberValidatedMeterMap(map: MeterMap): void {\n buildMeterIndex(map, true);\n}\n\n/**\n * Index of the last entry whose key is at or before `value`, at least 0.\n *\n * Both keys a map is searched by — onsets and bars completed — are strictly\n * increasing, so the entry in force is found by halving the range.\n */\nfunction lastAtOrBefore(keys: readonly number[], value: number): number {\n let low = 1;\n let high = keys.length - 1;\n let index = 0;\n while (low <= high) {\n const mid = (low + high) >>> 1;\n if ((keys[mid] ?? Number.POSITIVE_INFINITY) <= value) {\n index = mid;\n low = mid + 1;\n } else {\n high = mid - 1;\n }\n }\n return index;\n}\n\n/**\n * Index of the map entry in force at a beat.\n *\n * The first entry also covers everything before it, so a pickup written at\n * negative beats is read in the signature the piece opens in.\n */\nexport function entryIndexOf(map: MeterMap, beat: number): number {\n return lastAtOrBefore(meterIndexOf(map).startBeats, beat + BEAT_EPS);\n}\n\n/** Absolute beat at which the bar containing `beat` begins. */\nexport function barStartOf(map: MeterMap, beat: number): number {\n const index = meterIndexOf(map);\n const at = lastAtOrBefore(index.startBeats, beat + BEAT_EPS);\n const anchor = index.barAnchors[at];\n const barLen = index.barBeats[at];\n if (anchor === undefined || barLen === undefined || barLen === 0) {\n return 0;\n }\n return anchor + Math.floor((beat - anchor) / barLen + BEAT_EPS) * barLen;\n}\n\n/**\n * Length in quarter-note beats of the bar containing `beat`.\n *\n * A meter change starts a new bar, so the bar it interrupts is shorter than its\n * own signature says: this is that bar's real length, which is what a position\n * display has to count felt beats against.\n */\nexport function barLengthOf(map: MeterMap, beat: number): number {\n const index = meterIndexOf(map);\n const at = lastAtOrBefore(index.startBeats, beat + BEAT_EPS);\n const full = index.barBeats[at];\n if (full === undefined) {\n return 0;\n }\n const next = index.startBeats[at + 1];\n return next === undefined ? full : Math.min(full, next - barStartOf(map, beat));\n}\n\n/**\n * Bar index of a beat, counting the bar that begins at beat 0 as bar 0.\n *\n * Beats before that bar count backwards, which is what numbers a pickup bar as\n * bar -1 rather than folding it into the first full bar.\n */\nexport function barIndexOf(map: MeterMap, beat: number): number {\n const index = meterIndexOf(map);\n const at = lastAtOrBefore(index.startBeats, beat + BEAT_EPS);\n const anchor = index.barAnchors[at];\n const barLen = index.barBeats[at];\n if (anchor === undefined || barLen === undefined || barLen === 0) {\n return 0;\n }\n return (index.barsBefore[at] ?? 0) + Math.floor((beat - anchor) / barLen + BEAT_EPS);\n}\n\n/** Absolute beat at which bar `barIndex` begins. */\nexport function beatOfBarIndex(map: MeterMap, barIndex: number): number {\n const index = meterIndexOf(map);\n const at = lastAtOrBefore(index.barsBefore, barIndex);\n const anchor = index.barAnchors[at];\n const barLen = index.barBeats[at];\n if (anchor === undefined || barLen === undefined) {\n return 0;\n }\n return anchor + (barIndex - (index.barsBefore[at] ?? 0)) * barLen;\n}\n","import { BudgetExceededError, InvalidInputError } from '../errors/index.js';\n// The table itself rather than the instrument barrel: the barrel reaches back\n// into this module, and an articulation name is a bare list with no such tie.\nimport { ARTICULATIONS } from '../instrument/articulation.js';\nimport type { MeterMap, TimeSignature } from '../meter/index.js';\nimport {\n isCompoundNumerator,\n isValidatedMeterMap,\n rememberValidatedMeterMap,\n} from '../meter/internal.js';\nimport type { NoteEvent } from '../types.js';\n\n/**\n * Default upper bound for synchronous event/window/candidate generation.\n *\n * @category Core\n */\nexport const DEFAULT_GENERATION_BUDGET = 1_000_000;\n\n/**\n * Upper bound on the number of changes one meter map may declare.\n *\n * A meter map is read on every slot of an analysis pass, so an unbounded map is\n * an unbounded per-slot cost the way an unbounded event array is an unbounded\n * pass. The bound is far above any notated piece — a change on every bar of a\n * hundred thousand bars — and rejects the map rather than the work built on it.\n */\nconst MAX_METER_CHANGES = 100_000;\n\n/**\n * Longest echo of a rejected value an error message carries.\n *\n * A message is shown to a person and written to a log, so it names what was\n * given without reprinting it: a validated field can hold a pasted document,\n * and repeating that back turns one bad keystroke into a megabyte of log.\n */\nconst MAX_ECHOED_LENGTH = 64;\n\n/**\n * Describe a rejected value for an error message, without ever throwing.\n *\n * The value reaching a validator is untyped by definition — it arrives from\n * JSON, a config file, or a plugin host — so it may be circular, a BigInt, or a\n * pasted document. Only a string is echoed, and only its head; anything else is\n * named by its type, which is the part a caller can act on.\n *\n * Exported for the other modules that build the same kind of message. It is not\n * re-exported from `./core`, because it describes how this library words an\n * error rather than anything a caller decides.\n */\nexport function describeRejected(value: unknown): string {\n if (value === null) {\n return 'null';\n }\n if (typeof value !== 'string') {\n return typeof value;\n }\n return value.length <= MAX_ECHOED_LENGTH\n ? JSON.stringify(value)\n : `${JSON.stringify(value.slice(0, MAX_ECHOED_LENGTH))} (truncated from ${value.length} characters)`;\n}\n\n/**\n * Require a finite JavaScript number and return it unchanged.\n *\n * @category Core\n */\nexport function assertFiniteNumber(value: number, name: string): number {\n if (!Number.isFinite(value)) {\n throw new InvalidInputError(`${name} must be finite; received ${value}`);\n }\n return value;\n}\n\n/**\n * Reject a range whose ends are not numbers.\n *\n * A bound that is not a number compares false against every value, so both\n * halves of `value < min || value > max` are false and the assertion accepts\n * everything — the exact opposite of what asking for a range means. A caller\n * computing a bound from a form field or a project file is the one who ends up\n * with an assertion that no longer asserts, and nothing in the result says so.\n *\n * The check is two `Number.isFinite` calls and builds no message unless it\n * fails, which is what lets it sit on the path every bounded check runs.\n */\nfunction assertBounds(min: number, max: number, name: string): void {\n if (!Number.isFinite(min) || !Number.isFinite(max)) {\n throw new InvalidInputError(\n `${name} must be bounded by finite numbers; received [${describeRejected(min)}, ${describeRejected(max)}]`,\n );\n }\n}\n\n/**\n * Require an integer in the inclusive range `[min, max]`.\n *\n * @category Core\n */\nexport function assertInteger(\n value: number,\n name: string,\n min = Number.MIN_SAFE_INTEGER,\n max = Number.MAX_SAFE_INTEGER,\n): number {\n assertFiniteNumber(value, name);\n assertBounds(min, max, name);\n if (!Number.isSafeInteger(value) || value < min || value > max) {\n throw new InvalidInputError(\n `${name} must be an integer in [${min}, ${max}]; received ${value}`,\n );\n }\n return value;\n}\n\n/** Require an integer MIDI pitch in the inclusive range 0..127. */\nexport function assertMidiPitch(value: number, name = 'MIDI pitch'): number {\n return assertInteger(value, name, 0, 127);\n}\n\n/**\n * Require an integer pitch class in the inclusive range 0..11.\n *\n * A pitch class is read by shifting a mode mask by it, and a shift coerces, so\n * a value outside the range — or one that is no number at all — silently names\n * a pitch class the caller never asked about instead of failing.\n */\nexport function assertPitchClass(value: number, name = 'pitch class'): number {\n return assertInteger(value, name, 0, 11);\n}\n\n/** Clamp an integer MIDI pitch to the inclusive range 0..127. */\nexport function clampToMidi(value: number, name = 'MIDI pitch'): number {\n assertInteger(value, name);\n return Math.min(127, Math.max(0, value));\n}\n\n/**\n * Require a bounded scale/chord degree, counted from 1 the way musicians count\n * degrees: 1 is the tonic, 5 the dominant. Zero and negative degrees name no\n * degree at all and are rejected.\n */\nexport function assertDegree(value: number, name = 'degree'): number {\n return assertInteger(value, name, 1, 1000);\n}\n\n/** Require a finite semitone offset before pitch-class reduction. */\nexport function assertFiniteSemitones(value: number, name = 'semitones'): number {\n return assertFiniteNumber(value, name);\n}\n\n/**\n * Drop the notes that never sound.\n *\n * A MIDI or DAW import routinely carries zero-length artefacts. Every entry\n * point in this library ignores them, but a caller holding such an array still\n * has to decide what to do with it before comparing note counts or indices;\n * this is the one filter to apply.\n *\n * @param events The note events to filter.\n * @returns A new array containing only the notes with a positive duration.\n * @example\n * ```ts\n * import { dropSilentNotes } from '@libraz/libcantus';\n * dropSilentNotes([{ pitch: 60, startBeat: 0, durationBeat: 0 }]); // []\n * ```\n * @category Core\n */\nexport function dropSilentNotes(events: readonly NoteEvent[]): NoteEvent[] {\n return assertArray<NoteEvent>(events, 'events').filter(\n (event) => event !== undefined && event !== null && event.durationBeat > 0,\n );\n}\n\n/** Alias that makes the shared positive-duration policy explicit at API entrances. */\nexport const soundingNotesOnly = dropSilentNotes;\n\n/**\n * Require a value to be an array before anything walks it.\n *\n * The counterpart of {@link assertRecord} for the entrances whose material is a\n * list. A caller working in JavaScript, or restoring a session from a file, can\n * hand any of these entrances a `null` where the list should be; reading it as a\n * list reports the library's own `TypeError`, which names neither the argument\n * nor the caller and does not reach a host's error handling for this library.\n *\n * @param value The value to check.\n * @param name What the value is, for the error message.\n * @returns The value as an array.\n * @throws If the value is not an array.\n * @category Core\n */\nexport function assertArray<T>(value: unknown, name: string): readonly T[] {\n if (!Array.isArray(value)) {\n throw new InvalidInputError(`${name} must be an array; received ${describeRejected(value)}`);\n }\n return value as readonly T[];\n}\n\n/**\n * Require a value to be an object before any field is read off it.\n *\n * The counterpart of {@link assertArray} for the entrances whose material — or\n * whose options — is a record. An entrance that takes a single options object\n * is the common case: `undefined` there is a caller who forgot the argument, and\n * both readings arrive at the same first field access.\n *\n * @param value The value to check.\n * @param name What the value is, for the error message.\n * @returns The value as a record.\n * @throws If the value is not a non-null object, or is an array.\n * @category Core\n */\nexport function assertRecord<T>(value: unknown, name: string): T {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n throw new InvalidInputError(`${name} must be an object; received ${describeRejected(value)}`);\n }\n return value as T;\n}\n\n/**\n * Read an entrance's options bag.\n *\n * An options parameter written `opts: Options = {}` is filled in only for an\n * argument that is absent: an explicit `null` — which is what a JavaScript\n * caller passes on when it has no options to give, and what a restored session\n * holds where an options object was never written — defeats the default and\n * reaches the first field read as itself. Absent is answered with the empty\n * bag, so an entrance reads its options in one place whichever way it declared\n * them, and anything that is not a bag is refused by name.\n *\n * @param value The options as the caller passed them.\n * @param name What the value is, for the error message.\n * @returns The options, or an empty bag when none were given.\n * @throws If the value is present but is not a record.\n * @category Core\n */\nexport function assertOptions<T extends object>(value: T | undefined, name = 'options'): T {\n return value === undefined ? ({} as T) : assertRecord<T>(value, name);\n}\n\n/**\n * Require a value to be a boolean before a branch reads it as one.\n *\n * A flag is the one parameter whose default is not always the falsy reading:\n * where a switch defaults to `true`, a `null` handed in place of it is read as\n * `false` and the entrance answers the opposite of what leaving it out would\n * have answered. Absent stays absent — a flag with a default is filled in by\n * that default, and only a value that is present and is not a boolean is\n * refused.\n *\n * @param value The value to check.\n * @param name What the value is, for the error message.\n * @returns The value as a boolean.\n * @throws If the value is present and is not a boolean.\n * @category Core\n */\nexport function assertFlag(value: boolean, name: string): boolean {\n if (typeof value !== 'boolean') {\n throw new InvalidInputError(`${name} must be a boolean; received ${describeRejected(value)}`);\n }\n return value;\n}\n\n/**\n * Require a value to be callable before an entrance calls it.\n *\n * The third of the shape checks, for the entrances whose material is a callback:\n * which chord sounds at a beat, or which material a part recognises. A caller\n * working in JavaScript reaches these with a value that is not a function, and\n * calling it reports the library's own `TypeError` from inside the walk, naming\n * neither the argument nor the caller.\n *\n * @param value The value to check.\n * @param name What the value is, for the error message.\n * @returns The value as a function.\n * @throws If the value is not callable.\n * @category Core\n */\nexport function assertFunction<T extends (...args: never[]) => unknown>(\n value: unknown,\n name: string,\n): T {\n if (typeof value !== 'function') {\n throw new InvalidInputError(`${name} must be a function; received ${describeRejected(value)}`);\n }\n return value as T;\n}\n\n/**\n * Require a value to be one of a fixed set of names.\n *\n * TypeScript checks string-union options at compile time only, so a value that\n * arrives from JSON, a config file, or a JavaScript caller reaches the engine\n * unchecked and is then read against a table that has no entry for it —\n * producing a silent `undefined`, a NaN velocity, or a crash far from the call.\n *\n * @param value The value to check.\n * @param allowed Every accepted name.\n * @param name What the value is, for the error message.\n * @returns The value, narrowed to the allowed union.\n * @throws If the value is not one of `allowed`. The message names the value by\n * its type unless it is a string, and echoes at most the head of that string,\n * so building it cannot itself fail on a circular object and cannot grow with\n * the size of what was pasted into the field.\n *\n * @category Core\n */\nexport function assertOneOf<const T extends string>(\n value: unknown,\n allowed: readonly T[],\n name: string,\n): T {\n // The allowed set is walked on both paths — the membership test and the\n // message — so it is checked as a list before either. Building the message is\n // the reason this matters: a validator that throws its own `TypeError` while\n // describing what it rejected reports a bug in this library instead of the\n // input, which is the same thing {@link describeRejected} exists to avoid.\n const names = assertArray<T>(allowed, `${name} allowed values`);\n if (typeof value !== 'string' || !(names as readonly string[]).includes(value)) {\n throw new InvalidInputError(\n `${name} must be one of ${names.join(', ')}; received ${describeRejected(value)}`,\n );\n }\n return value as T;\n}\n\n/**\n * Require a positive safe integer, optionally capped by `max`.\n *\n * @category Core\n */\nexport function assertPositiveInt(\n value: number,\n name: string,\n max = DEFAULT_GENERATION_BUDGET,\n): number {\n return assertInteger(value, name, 1, max);\n}\n\n/**\n * Require a finite number in the inclusive range `[min, max]`.\n *\n * @category Core\n */\nexport function assertRange(value: number, min: number, max: number, name: string): number {\n assertFiniteNumber(value, name);\n assertBounds(min, max, name);\n if (value < min || value > max) {\n throw new InvalidInputError(`${name} must be in [${min}, ${max}]; received ${value}`);\n }\n return value;\n}\n\n/**\n * Reject work estimates that would exceed a synchronous generation budget.\n *\n * @category Core\n */\nexport function assertGenerationBudget(\n estimated: number,\n name: string,\n limit: number | undefined = DEFAULT_GENERATION_BUDGET,\n): number {\n // Only an omitted limit means the default one: a null read as absent would\n // charge the work against a budget the caller never chose.\n const cap = limit === undefined ? DEFAULT_GENERATION_BUDGET : limit;\n assertFiniteNumber(estimated, name);\n assertPositiveInt(cap, `${name} limit`, Number.MAX_SAFE_INTEGER);\n if (estimated < 0) {\n throw new InvalidInputError(`${name} must not be negative; received ${estimated}`);\n }\n if (estimated > cap) {\n throw new BudgetExceededError(\n `${name} exceeds the generation budget ${cap}; received ${estimated}`,\n );\n }\n return estimated;\n}\n\n/**\n * Charge a `rows × columns` table against a budget and return its length.\n *\n * A search checks its budget at the entry point and allocates its table deep\n * inside itself, so the two drift apart as the table grows: a call charged for\n * its slots is then handed a table a whole candidate list wider than that, and\n * the budget it passed no longer stands for what it allocates. Charging at the\n * allocation is what keeps them together — a table that cannot be obtained\n * without being charged cannot be obtained uncharged.\n */\nfunction assertTableSize(rows: number, columns: number, name: string, budget?: number): number {\n assertFiniteNumber(rows, `${name} rows`);\n assertFiniteNumber(columns, `${name} columns`);\n return assertGenerationBudget(rows * columns, name, budget);\n}\n\n/**\n * Allocate the score table of a `rows × columns` search, charging its size.\n *\n * @param rows Number of slots the search runs over.\n * @param columns Number of candidates each slot is scored against.\n * @param name What the table is, for the error message.\n * @param budget Upper bound the table's size is charged against.\n * @returns A zeroed table, read at `row * columns + column`.\n */\nexport function allocateCandidateTable(\n rows: number,\n columns: number,\n name: string,\n budget?: number,\n): Float64Array {\n return new Float64Array(assertTableSize(rows, columns, name, budget));\n}\n\n/**\n * Allocate the back-pointer table of a `rows × columns` search, charging it.\n *\n * The companion of {@link allocateCandidateTable}: a dynamic-programming search\n * allocates one of each, and both are charged for the same reason.\n *\n * @param rows Number of slots the search runs over.\n * @param columns Number of candidates each slot is scored against.\n * @param name What the table is, for the error message.\n * @param budget Upper bound the table's size is charged against.\n * @returns A zeroed table, read at `row * columns + column`.\n */\nexport function allocateChoiceTable(\n rows: number,\n columns: number,\n name: string,\n budget?: number,\n): Int32Array {\n return new Int32Array(assertTableSize(rows, columns, name, budget));\n}\n\n/**\n * Validate a time signature, including additive grouping, before any early return.\n *\n * @category Core\n */\nexport function assertTimeSignature(ts: TimeSignature, name = 'time signature'): TimeSignature {\n // The shape is checked before any field is read: a value from JSON or a\n // plugin host may be null or a number, and reading a numerator off it would\n // report the library's own TypeError instead of the caller's bad input.\n if (typeof ts !== 'object' || ts === null) {\n throw new InvalidInputError(\n `${name} must be a time signature; received ${describeRejected(ts)}`,\n );\n }\n assertPositiveInt(ts.numerator, `${name}.numerator`);\n assertPositiveInt(ts.denominator, `${name}.denominator`);\n if (ts.grouping !== undefined) {\n if (!Array.isArray(ts.grouping)) {\n throw new InvalidInputError(\n `${name}.grouping must be an array of group lengths; received ${describeRejected(ts.grouping)}`,\n );\n }\n if (ts.grouping.length === 0) {\n throw new InvalidInputError(`${name}.grouping must not be empty`);\n }\n let sum = 0;\n for (let index = 0; index < ts.grouping.length; index += 1) {\n sum += assertPositiveInt(ts.grouping[index] ?? Number.NaN, `${name}.grouping[${index}]`);\n }\n // A compound numerator accepts either reading: grouping its dotted pulses\n // (9/8 as [1, 1, 1]) or grouping its denominator units additively (9/8 as\n // [2, 2, 2, 3]), which is how aksak and other additive metres are written.\n const pulses = isCompoundNumerator(ts.numerator) ? ts.numerator / 3 : ts.numerator;\n if (sum !== pulses && sum !== ts.numerator) {\n const accepted =\n pulses === ts.numerator ? `${pulses}` : `${pulses} (pulses) or ${ts.numerator} (units)`;\n throw new InvalidInputError(`${name}.grouping must sum to ${accepted}; received ${sum}`);\n }\n }\n return ts;\n}\n\n/**\n * Validate a meter map: a non-empty run of time signatures, each with the beat\n * it takes effect at, in strictly increasing beat order.\n *\n * The first entry also governs everything before it, so a map need not start at\n * beat 0 — that is what lets a pickup at a negative beat be read in the\n * signature the piece opens in. Where the first entry is written does not move\n * the bar lines: the opening signature counts its bars from beat 0 either way,\n * so beat 0 is the downbeat of bar 0 and the pickup before it is bar -1.\n *\n * The map is also bounded, the way an event array is: a map is consulted once\n * per analysed slot, so its length is a per-slot cost and not only a one-time\n * one.\n *\n * @category Core\n */\nexport function assertMeterMap(meters: MeterMap, name = 'meters'): MeterMap {\n if (!Array.isArray(meters)) {\n throw new InvalidInputError(`${name} must be an array; received ${typeof meters}`);\n }\n if (meters.length === 0) {\n throw new InvalidInputError(`${name} must not be empty`);\n }\n assertGenerationBudget(meters.length, `${name} count`, MAX_METER_CHANGES);\n // A map is re-validated on every positional question asked of it, so a pass\n // over a long piece pays for the whole map per slot unless a map it has\n // already read is recognized as one.\n if (isValidatedMeterMap(meters)) {\n return meters;\n }\n let previous = Number.NEGATIVE_INFINITY;\n for (let index = 0; index < meters.length; index += 1) {\n const entry = meters[index];\n // A hole in a sparse array, an explicit null, and a number are all rejected\n // here rather than at the first field read, which would surface as the\n // library's own TypeError instead of as the malformed input it is.\n if (typeof entry !== 'object' || entry === null) {\n throw new InvalidInputError(\n `${name}[${index}] must be a meter change; received ${describeRejected(entry)}`,\n );\n }\n assertFiniteNumber(entry.startBeat, `${name}[${index}].startBeat`);\n if (index > 0 && entry.startBeat <= previous) {\n throw new InvalidInputError(\n `${name}[${index}].startBeat must be greater than ${previous}; received ${entry.startBeat}`,\n );\n }\n previous = entry.startBeat;\n assertTimeSignature(entry.ts, `${name}[${index}].ts`);\n }\n rememberValidatedMeterMap(meters);\n return meters;\n}\n\n/**\n * How strictly {@link assertNoteEvent} and {@link assertNoteEvents} read an\n * event array.\n *\n * @category Core\n */\nexport type NoteEventAssertOptions = {\n /**\n * Accept notes that never sound. The analysis side does, so an array from a\n * MIDI import can be validated before the zero-length artefacts are dropped.\n */\n allowNonPositiveDuration?: boolean;\n /** Upper bound on the event count; defaults to the generation budget. */\n budget?: number;\n /**\n * Earliest accepted onset. Onsets are unbounded below by default, because a\n * pickup sounds before the downbeat and the downbeat is beat 0; pass\n * `-pickupBeats` to reject a note starting earlier than the pickup a caller\n * has declared.\n *\n * @defaultValue `-Number.MAX_SAFE_INTEGER`\n */\n minStartBeat?: number;\n};\n\n/**\n * Validate the finite fields of one timeline note event.\n *\n * @category Core\n */\nexport function assertNoteEvent(\n event: NoteEvent,\n name = 'note event',\n options: NoteEventAssertOptions = {},\n): NoteEvent {\n const asked = assertOptions(options, `${name} options`);\n // The shape is checked before any field is read, so a null or a number from a\n // JSON import is reported as the malformed event it is rather than as the\n // library's own TypeError.\n if (typeof event !== 'object' || event === null) {\n throw new InvalidInputError(\n `${name} must be a note event; received ${describeRejected(event)}`,\n );\n }\n assertMidiPitch(event.pitch, `${name}.pitch`);\n // An onset is not bounded below: the downbeat is beat 0, so a pickup sounds\n // at a negative beat. A nonsensical onset is still rejected — the bound is\n // finite, and a caller that knows its pickup narrows it further.\n const minStartBeat = asked.minStartBeat ?? -Number.MAX_SAFE_INTEGER;\n assertFiniteNumber(minStartBeat, 'minStartBeat');\n assertRange(event.startBeat, minStartBeat, Number.MAX_SAFE_INTEGER, `${name}.startBeat`);\n // The positivity check comes first so the common failure — a zero-length note\n // from a MIDI import — reads as such instead of naming a denormal lower bound.\n assertFiniteNumber(event.durationBeat, `${name}.durationBeat`);\n if (!asked.allowNonPositiveDuration && event.durationBeat <= 0) {\n throw new InvalidInputError(\n `${name}.durationBeat must be positive; received ${event.durationBeat}`,\n );\n }\n assertRange(\n event.durationBeat,\n -Number.MAX_SAFE_INTEGER,\n Number.MAX_SAFE_INTEGER,\n `${name}.durationBeat`,\n );\n if (event.velocity !== undefined) {\n // The same domain as the pitch beside it, and checked the same way: both\n // are documented as MIDI quantities in [0, 127], and a MIDI byte has no\n // fractional value to carry. A velocity that arrives at 63.7 is a rounding\n // left undone upstream, and admitting it here hands the writer a note the\n // format cannot hold rather than the caller an error where it was made.\n assertInteger(event.velocity, `${name}.velocity`, 0, 127);\n }\n // Both optional fields carry a closed domain, so both are checked here. A\n // technique outside the table is a misspelt or unmapped name, and passing it\n // on turns an input error into the musical claim that the instrument cannot\n // play it — a statement about a technique that does not exist.\n if (event.articulation !== undefined) {\n assertOneOf(event.articulation, ARTICULATIONS, `${name}.articulation`);\n }\n return event;\n}\n\n/**\n * Validate an event array and its allocation budget without copying it.\n *\n * @category Core\n */\nexport function assertNoteEvents(\n events: readonly NoteEvent[],\n name = 'note events',\n options: NoteEventAssertOptions = {},\n): NoteEvent[] {\n const asked = assertOptions(options, `${name} options`);\n if (!Array.isArray(events)) {\n throw new InvalidInputError(`${name} must be an array; received ${typeof events}`);\n }\n assertGenerationBudget(events.length, `${name} count`, asked.budget);\n for (let index = 0; index < events.length; index += 1) {\n const event = events[index];\n // A hole in a sparse array, an explicit undefined, and a null are all\n // rejected here: letting any of them through only moves the failure to a\n // later TypeError, or drops the note silently.\n if (typeof event !== 'object' || event === null) {\n throw new InvalidInputError(\n `${name}[${index}] must be a note event; received ${describeRejected(event)}`,\n );\n }\n assertNoteEvent(event, `${name}[${index}]`, asked);\n }\n return events;\n}\n","/**\n * Note-name notation systems.\n *\n * A pitch has one identity but many written names: the note an English score\n * calls `G#` is `gis` in German, `嬰ト` in Japanese and `sol diesis` in Italian.\n * This module holds each system's table — letters, accidental affixes and mode\n * words — so a name can be read and written in the system a source actually\n * uses, and so a name of unknown origin can be attributed to one.\n *\n * The tables live together because attribution needs them together: `B` is a B\n * natural in English but a B flat in German, and only a table that knows both\n * can say so.\n */\n\nimport { InvalidInputError } from '../errors/index.js';\nimport { assertOneOf, assertOptions, describeRejected } from '../validation/index.js';\nimport type { Note } from './index.js';\n\n/**\n * A system of written note names.\n *\n * - `english`: C D E F G A B, `#` sharp and `b` flat (`C#`, `Bb`, `F##`).\n * - `german`: C D E F G A H, `-is` sharp and `-es` flat (`cis`, `des`), with B\n * for B flat and H for B natural.\n * - `japanese`: the katakana 音名 ハ ニ ホ ヘ ト イ ロ, prefixed 嬰 sharp and\n * 変 flat.\n * - `italian`: the solfège syllables do re mi fa sol la si, followed by\n * `diesis` or `bemolle`.\n * - `fixedDo`: the same syllables read as fixed-do note names; identical to\n * `italian`, and named separately because callers ask for it by that name.\n *\n * @category Pitch & Intervals\n */\nexport type NoteNameSystem = 'english' | 'german' | 'japanese' | 'italian' | 'fixedDo';\n\n/** Every system name, for validating a caller-supplied one. */\nconst NOTE_NAME_SYSTEMS = [\n 'english',\n 'german',\n 'japanese',\n 'italian',\n 'fixedDo',\n] as const satisfies readonly NoteNameSystem[];\n\n/**\n * Which notation system to read or write a name in.\n *\n * @category Pitch & Intervals\n */\nexport type NoteNameOptions = {\n /**\n * The system. Omitted on parsing, the system is detected from the name\n * itself; omitted on formatting, the name is written in English.\n */\n system?: NoteNameSystem;\n};\n\n/**\n * A key named the way a score names it: a spelled tonic and a mode.\n *\n * This is what a key *name* carries. It is deliberately not a key/scale: a name\n * fixes the tonic's spelling and says major or minor, and nothing more.\n *\n * @category Scales\n */\nexport type KeyName = {\n /** The spelled tonic, without an octave. */\n tonic: Note;\n /** Which of the two modes the name gives. */\n mode: 'major' | 'minor';\n};\n\n/**\n * The systems auto-detection chooses between, in precedence order.\n *\n * English comes first because it is the only pair with a genuine clash: `B` is\n * a B natural in English and a B flat in German, so a name that either system\n * could read is read as English unless it carries a German-only cue.\n */\nconst DETECTION_ORDER = ['english', 'german', 'japanese', 'italian'] as const;\n\n/** A system with a table of its own; `fixedDo` shares the Italian one. */\ntype NamingTable = (typeof DETECTION_ORDER)[number];\n\n/** The table a system reads from: fixed-do names are the Italian syllables. */\nfunction tableOf(system: NoteNameSystem): NamingTable {\n return system === 'fixedDo' ? 'italian' : system;\n}\n\n/** English letter glyphs, indexed by letter number (0 = C .. 6 = B). */\nconst ENGLISH_LETTERS = ['C', 'D', 'E', 'F', 'G', 'A', 'B'] as const;\n\n/** German letter glyphs; the seventh letter is H, since B is the B flat. */\nconst GERMAN_LETTERS = ['c', 'd', 'e', 'f', 'g', 'a', 'h'] as const;\n\n/** Japanese 音名, written in katakana in the イロハ order. */\nconst JAPANESE_LETTERS = ['ハ', 'ニ', 'ホ', 'ヘ', 'ト', 'イ', 'ロ'] as const;\n\n/** Italian and fixed-do solfège syllables. */\nconst ITALIAN_LETTERS = ['do', 're', 'mi', 'fa', 'sol', 'la', 'si'] as const;\n\n/** Letter numbers whose German flat elides to a bare `s`: E -> es, A -> as. */\nconst GERMAN_ELIDING_LETTERS = [2, 5];\n\n/** Letter number of A, the letter that also writes its double flat as `asas`. */\nconst A_LETTER = 5;\n\n/** Letter number of B, the one letter German and English disagree about. */\nconst B_LETTER = 6;\n\n/** The mode words each system writes, keyed by mode. */\nconst MODE_WORDS: Record<NamingTable, Record<'major' | 'minor', string>> = {\n english: { major: 'major', minor: 'minor' },\n german: { major: 'dur', minor: 'moll' },\n japanese: { major: '長調', minor: '短調' },\n italian: { major: 'maggiore', minor: 'minore' },\n};\n\n/** Japanese accidental marks: 嬰 raises, 変 lowers, 重 doubles the mark it precedes. */\nconst JAPANESE_SHARP = '嬰';\nconst JAPANESE_FLAT = '変';\nconst JAPANESE_DOUBLE = '重';\n\n/** Italian accidental words, and the word that doubles the one after it. */\nconst ITALIAN_SHARP = 'diesis';\nconst ITALIAN_FLAT = 'bemolle';\nconst ITALIAN_DOUBLE = 'doppio';\n\n/**\n * The most accidentals a written name carries.\n *\n * Notation stops at the double accidental, and so does every letter-and-mark\n * name in these tables; past it there is no spelling to read.\n */\nexport const MAX_NAME_ACCIDENTALS = 2;\n\n/** Longest glyph in a table's letters. */\nfunction longestGlyph(glyphs: readonly string[]): number {\n return Math.max(...glyphs.map((glyph) => glyph.length));\n}\n\n/** Longest letter each table writes. */\nconst MAX_LETTER_LENGTH: Record<NamingTable, number> = {\n english: longestGlyph(ENGLISH_LETTERS),\n german: longestGlyph(GERMAN_LETTERS),\n japanese: longestGlyph(JAPANESE_LETTERS),\n italian: longestGlyph(ITALIAN_LETTERS),\n};\n\n/** Longest one accidental takes in each table, its separator included. */\nconst MAX_ACCIDENTAL_LENGTH: Record<NamingTable, number> = {\n /** `#`, `x` and `b`. */\n english: 1,\n /** The `-is` and `-es` affixes, whose first mark may elide to a bare `s`. */\n german: 2,\n /** 嬰 and 変; 重 stands in for the second mark of a double, not beside it. */\n japanese: 1,\n /** A space and the accidental word; `doppio` covers two marks in one word. */\n italian: 1 + Math.max(ITALIAN_SHARP.length, ITALIAN_FLAT.length),\n};\n\n/**\n * The greatest number of characters a bare note name takes in a system.\n *\n * A name is a letter and at most two accidentals, so its length has a ceiling\n * that depends only on the system. A caller looking for a name at the front of\n * a longer text — the root of a chord symbol — offers the prefixes up to this\n * length rather than every prefix the text has.\n *\n * @param system The system the name is written in.\n * @returns The greatest length such a name has.\n */\nexport function maxNoteNameLength(system: NoteNameSystem): number {\n const table = tableOf(assertSystem(system));\n return MAX_LETTER_LENGTH[table] + MAX_NAME_ACCIDENTALS * MAX_ACCIDENTAL_LENGTH[table];\n}\n\n/** Trim and collapse internal whitespace, so `'do diesis'` reads as one name. */\nfunction normalize(text: string): string {\n return text.trim().replace(/\\s+/g, ' ');\n}\n\n/** Reject a system this module has no table for. */\nfunction assertSystem(system: NoteNameSystem): NoteNameSystem {\n return assertOneOf(system, NOTE_NAME_SYSTEMS, 'system');\n}\n\n/**\n * Scientific pitch notation: a letter, any number of same-direction\n * accidentals, an optional octave. `x` is a double sharp; mixing `#` and `b` is\n * refused by the alternation rather than silently cancelling out.\n */\nconst ENGLISH_PATTERN = /^([A-Ga-g])([#x]*|b*)(-?\\d+)?$/;\n\n/** Read an English name, or null when the text is not one. */\nfunction parseEnglish(text: string): Note | null {\n const match = text.match(ENGLISH_PATTERN);\n if (match === null) {\n return null;\n }\n const glyph = (match[1] ?? '').toUpperCase();\n const letter = ENGLISH_LETTERS.indexOf(glyph as (typeof ENGLISH_LETTERS)[number]);\n let alter = 0;\n for (const ch of match[2] ?? '') {\n if (ch === '#') {\n alter += 1;\n } else if (ch === 'x') {\n alter += 2;\n } else if (ch === 'b') {\n alter -= 1;\n }\n }\n const note: Note = { letter, alter };\n if (match[3] !== undefined) {\n note.octave = Number.parseInt(match[3], 10);\n }\n return note;\n}\n\n/** Write an English name, without its octave. */\nfunction formatEnglish(note: Note): string {\n const glyph = ENGLISH_LETTERS[note.letter] ?? 'C';\n if (note.alter > 0) {\n return `${glyph}${'#'.repeat(note.alter)}`;\n }\n return note.alter < 0 ? `${glyph}${'b'.repeat(-note.alter)}` : glyph;\n}\n\n/**\n * How many flats a German flat suffix carries, or null when it is not one.\n *\n * The first mark elides to a bare `s` after E and A (`es`, `as`) and is a full\n * `es` elsewhere (`ces`, `ges`); every further `es` adds another flat, so\n * `eses` is a double flat. After A the doubled form `asas` is read too, since\n * both it and `ases` are written for the A double flat.\n */\nfunction germanFlats(letter: number, suffix: string): number | null {\n let rest = suffix;\n if (GERMAN_ELIDING_LETTERS.includes(letter) && rest.startsWith('s')) {\n rest = rest.slice(1);\n } else if (rest.startsWith('es')) {\n rest = rest.slice(2);\n } else {\n return null;\n }\n let flats = 1;\n while (rest.length > 0) {\n if (rest.startsWith('es') || (letter === A_LETTER && rest.startsWith('as'))) {\n rest = rest.slice(2);\n flats += 1;\n } else {\n return null;\n }\n }\n return flats;\n}\n\n/** Read a German name, or null when the text is not one. */\nfunction parseGerman(text: string): Note | null {\n const lower = text.toLowerCase();\n // B alone is the B flat; every other name on that letter is written on H, so\n // `bis` and `bes` are not German names at all.\n if (lower === 'b') {\n return { letter: B_LETTER, alter: -1 };\n }\n const letter = GERMAN_LETTERS.indexOf(lower.slice(0, 1) as (typeof GERMAN_LETTERS)[number]);\n if (letter < 0) {\n return null;\n }\n const suffix = lower.slice(1);\n if (suffix === '') {\n return { letter, alter: 0 };\n }\n if (/^(?:is)+$/.test(suffix)) {\n return { letter, alter: suffix.length / 2 };\n }\n const flats = germanFlats(letter, suffix);\n return flats === null ? null : { letter, alter: -flats };\n}\n\n/** Write a German name, without its octave. */\nfunction formatGerman(note: Note): string {\n const glyph = GERMAN_LETTERS[note.letter] ?? 'c';\n if (note.alter >= 0) {\n return `${glyph}${'is'.repeat(note.alter)}`;\n }\n const flats = -note.alter;\n if (note.letter === B_LETTER) {\n // The B flat is B; anything flatter is written on H, as heses.\n return flats === 1 ? 'b' : `h${'es'.repeat(flats)}`;\n }\n const first = GERMAN_ELIDING_LETTERS.includes(note.letter) ? `${glyph}s` : `${glyph}es`;\n return `${first}${'es'.repeat(flats - 1)}`;\n}\n\n/** Read a Japanese name, or null when the text is not one. */\nfunction parseJapanese(text: string): Note | null {\n let rest = text;\n let alter = 0;\n let direction = 0;\n while (rest.length > 0) {\n const doubled = rest.startsWith(JAPANESE_DOUBLE);\n const mark = doubled ? rest.slice(1, 2) : rest.slice(0, 1);\n const step = mark === JAPANESE_SHARP ? 1 : mark === JAPANESE_FLAT ? -1 : 0;\n if (step === 0) {\n break;\n }\n // 嬰 and 変 cancelling each other out is not a spelling anyone writes.\n if (direction !== 0 && direction !== step) {\n return null;\n }\n direction = step;\n alter += doubled ? step * 2 : step;\n rest = rest.slice(doubled ? 2 : 1);\n }\n const letter = JAPANESE_LETTERS.indexOf(rest as (typeof JAPANESE_LETTERS)[number]);\n return letter < 0 ? null : { letter, alter };\n}\n\n/** Write a Japanese name, without its octave. */\nfunction formatJapanese(note: Note): string {\n const glyph = JAPANESE_LETTERS[note.letter] ?? 'ハ';\n const marks = Math.abs(note.alter);\n if (marks === 0) {\n return glyph;\n }\n const mark = note.alter > 0 ? JAPANESE_SHARP : JAPANESE_FLAT;\n // 重 is the written form of a double accidental; past that there is no\n // convention to follow, so the mark simply repeats.\n return `${marks === 2 ? `${JAPANESE_DOUBLE}${mark}` : mark.repeat(marks)}${glyph}`;\n}\n\n/** Read an Italian (fixed-do) name, or null when the text is not one. */\nfunction parseItalian(text: string): Note | null {\n const words = text.toLowerCase().split(' ');\n const letter = ITALIAN_LETTERS.indexOf(words[0] as (typeof ITALIAN_LETTERS)[number]);\n if (letter < 0) {\n return null;\n }\n let alter = 0;\n let direction = 0;\n let doubled = false;\n for (const word of words.slice(1)) {\n if (word === ITALIAN_DOUBLE) {\n if (doubled) {\n return null;\n }\n doubled = true;\n continue;\n }\n const step = word === ITALIAN_SHARP ? 1 : word === ITALIAN_FLAT ? -1 : 0;\n if (step === 0 || (direction !== 0 && direction !== step)) {\n return null;\n }\n direction = step;\n alter += doubled ? step * 2 : step;\n doubled = false;\n }\n return doubled ? null : { letter, alter };\n}\n\n/** Write an Italian (fixed-do) name, without its octave. */\nfunction formatItalian(note: Note): string {\n const glyph = ITALIAN_LETTERS[note.letter] ?? 'do';\n const marks = Math.abs(note.alter);\n if (marks === 0) {\n return glyph;\n }\n const word = note.alter > 0 ? ITALIAN_SHARP : ITALIAN_FLAT;\n const accidental =\n marks === 2 ? `${ITALIAN_DOUBLE} ${word}` : Array.from({ length: marks }, () => word).join(' ');\n return `${glyph} ${accidental}`;\n}\n\n/** Whether a character is one of the ten digits an octave is written with. */\nfunction isDigit(ch: string): boolean {\n return ch >= '0' && ch <= '9';\n}\n\n/**\n * Split a trailing scientific octave off a name written in words or glyphs.\n *\n * The digits are scanned backwards from the end, and the minus sign taken by\n * hand, rather than matched by a pattern with a lazy prefix: the pattern reads\n * the same names but restarts at every position of a name that has no octave,\n * which costs the square of the length on text that is not a name at all.\n */\nfunction splitOctave(text: string): { name: string; octave: number | undefined } {\n let start = text.length;\n while (start > 0 && isDigit(text.charAt(start - 1))) {\n start -= 1;\n }\n if (start === text.length) {\n return { name: text, octave: undefined };\n }\n const signed = start > 0 && text.charAt(start - 1) === '-' ? start - 1 : start;\n return { name: text.slice(0, signed), octave: Number.parseInt(text.slice(signed), 10) };\n}\n\n/** Read a name in one system, or null when that system does not accept it. */\nfunction parseIn(text: string, system: NoteNameSystem): Note | null {\n const table = tableOf(system);\n if (table === 'english') {\n return parseEnglish(text);\n }\n const { name, octave } = splitOctave(text);\n const parser =\n table === 'german' ? parseGerman : table === 'japanese' ? parseJapanese : parseItalian;\n const note = parser(name);\n if (note === null) {\n return null;\n }\n return octave === undefined ? note : { ...note, octave };\n}\n\n/**\n * Drop the separators a mode word is written against the tonic with.\n *\n * Scanned backwards rather than matched by an unanchored pattern, which would\n * retry from every position of a text made entirely of separators.\n */\nfunction trimSeparators(text: string): string {\n let end = text.length;\n while (end > 0 && /[\\s-]/.test(text.charAt(end - 1))) {\n end -= 1;\n }\n return text.slice(0, end);\n}\n\n/** A key name split into its tonic text and the mode its mode word gives. */\ntype ModeSplit = {\n tonic: string;\n mode: 'major' | 'minor' | undefined;\n system: NamingTable | undefined;\n};\n\n/**\n * Split a trailing mode word off a key name.\n *\n * Every system's words are tried and the longest match wins, so the mode word\n * also says which system the name is written in. German writes the word against\n * the tonic with a hyphen as often as with a space (`gis-Moll`), so both\n * separators go with it; Japanese writes no separator at all.\n */\nfunction splitModeWord(text: string): ModeSplit {\n const lower = text.toLowerCase();\n let best: { word: string; mode: 'major' | 'minor'; system: NamingTable } | undefined;\n for (const system of DETECTION_ORDER) {\n for (const mode of ['major', 'minor'] as const) {\n const word = MODE_WORDS[system][mode];\n if (lower.endsWith(word) && (best === undefined || word.length > best.word.length)) {\n best = { word, mode, system };\n }\n }\n }\n if (best === undefined) {\n return { tonic: text, mode: undefined, system: undefined };\n }\n return {\n tonic: trimSeparators(text.slice(0, text.length - best.word.length)),\n mode: best.mode,\n system: best.system,\n };\n}\n\n/**\n * Which system a name is written in, or null when no system reads it.\n *\n * A name several systems accept goes to the first of `DETECTION_ORDER`, which\n * is what keeps a bare `B` an English B natural rather than a German B flat. A\n * mode word overrides that, because `dur` and `moll` are cues no other system\n * has — so `B dur` is B flat major. When the mode word belongs to a system that\n * cannot read the tonic, the name mixes two systems and there is nothing to\n * prefer, so it is rejected.\n */\nfunction resolveSystem(text: string): NoteNameSystem | null {\n const { tonic, system: wordSystem } = splitModeWord(text);\n // Each system is asked only until one answers: a name attributed to the first\n // of them says nothing about the rest, and the whole list is needed only to\n // name the systems in the message a mixed name is rejected with.\n if (wordSystem === undefined) {\n for (const system of DETECTION_ORDER) {\n if (parseIn(tonic, system) !== null) {\n return system;\n }\n }\n return null;\n }\n if (parseIn(tonic, wordSystem) !== null) {\n return wordSystem;\n }\n const accepted = DETECTION_ORDER.filter((system) => parseIn(tonic, system) !== null);\n if (accepted.length === 0) {\n return null;\n }\n throw new InvalidInputError(\n `${describeRejected(text)} mixes note-name systems: ${describeRejected(tonic)} is ` +\n `${accepted.join(' or ')} but its mode word is ${wordSystem}`,\n );\n}\n\n/**\n * The notation system a note name or key name is written in.\n *\n * A name several systems could read is attributed to the first of English,\n * German, Japanese, Italian that reads it — so `B` is the English B natural,\n * and German is chosen only for a name carrying a German-only cue (`H`, an\n * `-is`/`-es` ending, or `dur`/`moll`). Because the fixed-do syllables are the\n * Italian ones, detection reports `'italian'` for them; `'fixedDo'` is only ever\n * a system a caller asks for by name.\n *\n * @param text The note name or key name.\n * @returns The system that reads it.\n * @throws If no system reads the name, or the name mixes two systems — a German\n * tonic under an English mode word, say.\n * @example\n * ```ts\n * import { detectNoteNameSystem } from '@libraz/libcantus';\n * detectNoteNameSystem('B'); // 'english' — never the German B flat\n * detectNoteNameSystem('gis moll'); // 'german'\n * detectNoteNameSystem('嬰ト短調'); // 'japanese'\n * ```\n * @category Pitch & Intervals\n */\nexport function detectNoteNameSystem(text: string): NoteNameSystem {\n if (typeof text !== 'string') {\n throw new InvalidInputError(`name must be a string; received ${typeof text}`);\n }\n const system = resolveSystem(normalize(text));\n if (system === null) {\n throw new InvalidInputError(`no note-name system reads ${describeRejected(text)}`);\n }\n return system;\n}\n\n/** Read a note name, in the given system or in the one the name is written in. */\nexport function readNoteName(text: string, opts?: NoteNameOptions): Note {\n const asked = assertOptions(opts, 'opts');\n const name = normalize(text);\n const system = asked.system === undefined ? resolveSystem(name) : assertSystem(asked.system);\n const note = system === null ? null : parseIn(name, system);\n if (note === null) {\n throw new InvalidInputError(`Invalid note: ${describeRejected(text)}`);\n }\n return note;\n}\n\n/**\n * Write a note name in the given system, English by default.\n *\n * The letter must already be reduced to 0..6; the public entry point does that.\n */\nexport function writeNoteName(note: Note, opts?: NoteNameOptions): string {\n const asked = assertOptions(opts, 'opts');\n const system = asked.system === undefined ? 'english' : assertSystem(asked.system);\n const table = tableOf(system);\n const name =\n table === 'german'\n ? formatGerman(note)\n : table === 'japanese'\n ? formatJapanese(note)\n : table === 'italian'\n ? formatItalian(note)\n : formatEnglish(note);\n return note.octave === undefined ? name : `${name}${note.octave}`;\n}\n\n/**\n * The mode a key name with no mode word carries.\n *\n * German writes the mode in the case of the tonic — `C` is C major and `c` is C\n * minor — which is the only convention here that a bare tonic decides.\n * Everywhere else a tonic alone names a major key.\n */\nfunction impliedMode(system: NoteNameSystem, tonic: string): 'major' | 'minor' {\n return tableOf(system) === 'german' && /^[a-h]/.test(tonic) ? 'minor' : 'major';\n}\n\n/** Read a key name, in the given system or in the one the name is written in. */\nexport function readKeyName(text: string, opts?: NoteNameOptions): KeyName {\n const name = normalize(text);\n const asked = assertOptions(opts, 'opts');\n const split = splitModeWord(name);\n const system = asked.system === undefined ? resolveSystem(name) : assertSystem(asked.system);\n if (system !== null && split.system !== undefined && split.system !== tableOf(system)) {\n throw new InvalidInputError(\n `${describeRejected(text)} is not a ${system} key name: its mode word is ${split.system}`,\n );\n }\n const tonic = system === null ? null : parseIn(split.tonic, system);\n if (tonic === null || system === null) {\n throw new InvalidInputError(`Invalid key name: ${describeRejected(text)}`);\n }\n if (tonic.octave !== undefined) {\n throw new InvalidInputError(`a key name carries no octave; received ${describeRejected(text)}`);\n }\n // An explicit mode word outranks the German case convention, so `C moll` is C\n // minor: the word is what the writer said, the case only what they typed.\n return { tonic, mode: split.mode ?? impliedMode(system, split.tonic) };\n}\n\n/**\n * Write a key name in the given system, English by default.\n *\n * The tonic's letter must already be reduced to 0..6 and its octave dropped;\n * the public entry point does both.\n */\nexport function writeKeyName(key: KeyName, opts?: NoteNameOptions): string {\n const asked = assertOptions(opts, 'opts');\n const system = asked.system === undefined ? 'english' : assertSystem(asked.system);\n const table = tableOf(system);\n const word = MODE_WORDS[table][key.mode];\n const tonic = writeNoteName(key.tonic, { system });\n if (table === 'japanese') {\n return `${tonic}${word}`;\n }\n if (table === 'german') {\n // German carries the mode in the case of the tonic as well as in the word.\n const cased =\n key.mode === 'major' ? `${tonic.slice(0, 1).toUpperCase()}${tonic.slice(1)}` : tonic;\n return `${cased} ${word}`;\n }\n return `${tonic} ${word}`;\n}\n","/**\n * Pitch spelling: letter-name notes, enharmonic-aware conversion, and spelled\n * intervals.\n *\n * The rest of the library works in pitch classes (0..11), which cannot tell a\n * G# from an Ab or an augmented fourth from a diminished fifth. This module adds\n * an explicit spelling layer — a note is a diatonic letter plus a chromatic\n * alteration — so interval quality (P/M/m/A/d) and enharmonic identity are\n * preserved.\n */\n\nimport { InvalidInputError, type ParseResult, parseFailure, unwrapParse } from '../errors/index.js';\nimport {\n assertFiniteNumber,\n assertInteger,\n assertMidiPitch,\n assertOneOf,\n assertOptions,\n assertRecord,\n describeRejected,\n} from '../validation/index.js';\nimport type { KeyName, NoteNameOptions } from './naming.js';\nimport { readKeyName, readNoteName, writeKeyName, writeNoteName } from './naming.js';\n\nexport type { KeyName, NoteNameOptions, NoteNameSystem } from './naming.js';\nexport { detectNoteNameSystem } from './naming.js';\n\n/** Semitone offset of each natural letter above C: C D E F G A B. */\nconst LETTER_SEMITONES = [0, 2, 4, 5, 7, 9, 11] as const;\n\n/**\n * Widest alteration a note may carry.\n *\n * Six accidentals already exceeds anything common practice writes, and the\n * bound is what keeps an unvalidated number from reaching `String.repeat`.\n */\nconst MAX_ALTER = 6;\n\n/**\n * Widest octave a spelled note may carry, in either direction.\n *\n * Far beyond the MIDI range on purpose: a note is a spelling, not a playable\n * pitch, so scores that hold their material an octave or two outside the\n * sounding range stay expressible.\n */\nconst MAX_OCTAVE = 100;\n\n/**\n * Validate the fields of a spelled note once, at a public entry point.\n *\n * The letter is required in its own range rather than reduced on the way in:\n * a caller who built a note by letter arithmetic (`base.letter + 2`) would\n * otherwise hold a value that prints like a library-made note but compares\n * unequal to it, so the unreduced letter is refused where it is written rather\n * than where it later fails to match.\n */\nfunction assertNote(note: Note, name: string): Note {\n assertRecord<Note>(note, name);\n assertInteger(note.letter, `${name}.letter`, 0, 6);\n assertInteger(note.alter, `${name}.alter`, -MAX_ALTER, MAX_ALTER);\n if (note.octave !== undefined) {\n assertInteger(note.octave, `${name}.octave`, -MAX_OCTAVE, MAX_OCTAVE);\n }\n return note;\n}\n\n/**\n * A spelled note: a diatonic letter, a chromatic alteration, and an optional\n * octave.\n *\n * - `letter` is 0..6 for C..B.\n * - `alter` is the number of semitones of alteration: -2 double-flat, -1 flat,\n * 0 natural, +1 sharp, +2 double-sharp.\n * - `octave` follows scientific pitch notation (middle C = C4 = MIDI 60). When\n * absent, the note denotes a bare pitch class.\n *\n * @category Pitch & Intervals\n */\nexport type Note = {\n letter: number;\n alter: number;\n octave?: number;\n};\n\n/**\n * The quality label of a spelled interval: perfect, major, minor, or one or\n * more augmentations or diminutions.\n *\n * This names how an interval is *spelled*. It is a different notion from\n * {@link ConsonanceClass}, which classifies how an interval *sounds* against\n * another voice.\n *\n * @see {@link ConsonanceClass}\n * @category Pitch & Intervals\n */\nexport type IntervalQualityLabel = 'P' | 'M' | 'm' | `A${string}` | `d${string}`;\n\n/**\n * A spelled interval: a diatonic number, a quality label, and its semitone span.\n *\n * @category Pitch & Intervals\n */\nexport type SpelledInterval = {\n /** Diatonic size: 1 = unison, 2 = second, ... 8 = octave, and beyond. */\n number: number;\n /** Quality label: 'P', 'M', 'm', or repeated 'A'/'d' for (multiply) aug/dim. */\n quality: IntervalQualityLabel;\n /** Signed semitone distance from the first note to the second. */\n semitones: number;\n /**\n * Whether the diatonic letters move down.\n *\n * Always present, so the direction of a written-down interval is not\n * something a reader can lose: data rebuilt without the key would otherwise\n * come back ascending with nothing to say it had changed. Every producer\n * decides it, and the compiler asks each one to.\n *\n * Not redundant with the sign of the span: a descending unison spans zero\n * semitones, and a letter can rise while the pitch falls — `dd2` climbs a\n * letter and loses a semitone.\n */\n descending: boolean;\n};\n\n/**\n * Reduce a MIDI pitch, a bare pitch class, or any signed offset to a pitch\n * class in [0, 11].\n *\n * This is the library's single definition of pitch-class arithmetic: every\n * layer routes through it so a fractional pitch reduces the same way\n * everywhere. A non-integral input is rounded to the nearest semitone first, so\n * a microtonal 60.6 reads as C# rather than C.\n *\n * @param value A MIDI pitch, pitch class, or signed semitone offset.\n * @returns The pitch class in [0, 11].\n * @example\n * ```ts\n * import { pitchClassOf } from '@libraz/libcantus';\n * pitchClassOf(61); // 1\n * pitchClassOf(-1); // 11\n * pitchClassOf(60.6); // 1\n * ```\n * @category Pitch & Intervals\n */\nexport function pitchClassOf(value: number): number {\n assertFiniteNumber(value, 'pitch');\n return ((Math.round(value) % 12) + 12) % 12;\n}\n\n/** Reduce any integer to a pitch class in [0, 11]. */\nconst mod12 = pitchClassOf;\n\n/**\n * Reduce a letter number or letter offset to a diatonic letter in [0, 6]\n * (0 = C .. 6 = B).\n *\n * @param value A letter number or signed letter offset.\n * @returns The diatonic letter in [0, 6].\n * @category Pitch & Intervals\n */\nexport function diatonicLetterOf(value: number): number {\n assertFiniteNumber(value, 'diatonic letter');\n return ((Math.round(value) % 7) + 7) % 7;\n}\n\n/**\n * The pitch class of a diatonic letter with no accidental (C = 0, D = 2, ...).\n *\n * @param letter A letter number or signed letter offset; reduced to [0, 6].\n * @returns The natural pitch class of that letter.\n * @category Pitch & Intervals\n */\nexport function naturalPitchClassOf(letter: number): number {\n return LETTER_SEMITONES[diatonicLetterOf(letter)] ?? 0;\n}\n\n/** Reduce any integer to [0, 7). */\nconst mod7 = diatonicLetterOf;\n\n/**\n * Parse a note name into a {@link Note}, in any supported notation system.\n *\n * English (the default when a name could be read in more than one system)\n * accepts a letter (case-insensitive) followed by any number of same-direction\n * accidentals and an optional octave, e.g. `\"C\"`, `\"C#4\"`, `\"Bb\"`, `\"F##3\"`,\n * `\"Ebb2\"`. Both `#` and `x` (double-sharp) are accepted for sharps; `b` for\n * flats. Mixing sharps and flats (e.g. `\"C#b\"`) is rejected.\n *\n * Without a `system` the name is attributed by {@link detectNoteNameSystem},\n * which reads a name any two systems could claim as English: `\"B\"` is the B\n * natural, never the German B flat. German is chosen only for a German-only\n * name such as `\"H\"`, `\"fis\"` or `\"es\"`.\n *\n * A scientific octave may follow the name in every system (`\"gis4\"`,\n * `\"嬰ト4\"`), which is what makes formatting and parsing exact inverses for an\n * octave-bearing note.\n *\n * @param text The note name.\n * @param opts `system` reads the name in that notation system instead of\n * detecting it.\n * @returns The parsed note.\n * @throws If the text is not a valid note in the given (or detected) system.\n * Use {@link tryParseNote} where failure is ordinary, such as a note field\n * read on every keystroke.\n * @example\n * ```ts\n * import { parseNote, noteToMidi, noteToPitchClass } from '@libraz/libcantus';\n * noteToMidi(parseNote('C#4')); // 61\n * noteToPitchClass(parseNote('gis')); // 8 — the German G sharp\n * noteToPitchClass(parseNote('B', { system: 'german' })); // 10 — the German B flat\n * ```\n * @category Pitch & Intervals\n */\nexport function parseNote(text: string, opts?: NoteNameOptions): Note {\n return unwrapParse(tryParseNote(text, opts));\n}\n\n/**\n * Parse a note name, reporting failure instead of throwing it.\n *\n * The same reading as {@link parseNote} — that function is this one with its\n * error thrown — for the callers where a name that does not parse yet is the\n * normal state of the input rather than a fault.\n *\n * @param text The note name.\n * @param opts `system` reads the name in that notation system instead of\n * detecting it.\n * @returns The note, or the error explaining why the text is not one.\n * @example\n * ```ts\n * import { tryParseNote } from '@libraz/libcantus';\n * const result = tryParseNote('C#4');\n * result.ok ? result.value.letter : result.error.message;\n * ```\n * @category Pitch & Intervals\n */\nexport function tryParseNote(text: string, opts?: NoteNameOptions): ParseResult<Note> {\n // Read before the try: the options are the caller's own configuration, so a\n // malformed bag is a fault to raise rather than a name that failed to parse.\n const asked = assertOptions(opts, 'opts');\n try {\n if (typeof text !== 'string') {\n throw new InvalidInputError(`note must be a string; received ${typeof text}`);\n }\n return { ok: true, value: assertNote(readNoteName(text, asked), `note ${text}`) };\n } catch (error) {\n return parseFailure(error);\n }\n}\n\n/**\n * Render a {@link Note} as a note name, in any supported notation system.\n *\n * The inverse of {@link parseNote} when both are given the same `system`,\n * including double accidentals and octaves. Without one, {@link parseNote}\n * detects the system and reads a bare `B` as the English B natural, so a German\n * B flat written as `'b'` does not survive a round trip that names no system.\n *\n * @param note The note to format.\n * @param opts `system` writes the name in that notation system instead of\n * English.\n * @returns The note name, including the octave when present.\n * @example\n * ```ts\n * import { formatNote, parseNote } from '@libraz/libcantus';\n * formatNote(parseNote('C#4')); // 'C#4'\n * formatNote(parseNote('G#'), { system: 'german' }); // 'gis'\n * formatNote(parseNote('G#'), { system: 'japanese' }); // '嬰ト'\n * ```\n * @category Pitch & Intervals\n */\nexport function formatNote(note: Note, opts?: NoteNameOptions): string {\n assertNote(note, 'note');\n return writeNoteName({ letter: mod7(note.letter), alter: note.alter, octave: note.octave }, opts);\n}\n\n/**\n * Parse a key name such as `'C major'`, `'gis moll'` or `'嬰ト短調'`.\n *\n * The name is a tonic followed by a mode word, in any of the supported\n * notation systems; German also accepts its hyphenated form (`'gis-Moll'`).\n * Without a `system` the name is attributed by {@link detectNoteNameSystem},\n * so a mode word is itself enough to pick one: `'B dur'` is B flat major while\n * `'B major'` is B major.\n *\n * German carries the mode twice, in the word and in the case of the tonic\n * (`C dur`, `c moll`). When the two disagree the word wins — `'C moll'` is C\n * minor — because the word is what the writer said and the case only what they\n * typed. A German name with no mode word is decided by its case alone\n * (`'gis'` is G sharp minor, `'Gis'` G sharp major); a bare tonic in any other\n * system names a major key.\n *\n * @param text The key name.\n * @param opts `system` reads the name in that notation system instead of\n * detecting it.\n * @returns The spelled tonic and the mode.\n * @throws If the text is not a key name in the given (or detected) system, if\n * it mixes two systems, or if the tonic carries an octave. Use\n * {@link tryParseKeyName} where failure is ordinary, such as a key field read\n * on every keystroke.\n * @example\n * ```ts\n * import { formatNote, parseKeyName } from '@libraz/libcantus';\n * const key = parseKeyName('gis moll');\n * formatNote(key.tonic); // 'G#'\n * key.mode; // 'minor'\n * ```\n * @category Scales\n */\nexport function parseKeyName(text: string, opts?: NoteNameOptions): KeyName {\n return unwrapParse(tryParseKeyName(text, opts));\n}\n\n/**\n * Parse a key name, reporting failure instead of throwing it.\n *\n * The same reading as {@link parseKeyName} — that function is this one with its\n * error thrown — for the callers where a name that does not parse yet is the\n * normal state of the input rather than a fault.\n *\n * @param text The key name.\n * @param opts `system` reads the name in that notation system instead of\n * detecting it.\n * @returns The key, or the error explaining why the text is not one.\n * @example\n * ```ts\n * import { tryParseKeyName } from '@libraz/libcantus';\n * const result = tryParseKeyName('gis moll');\n * result.ok ? result.value.mode : result.error.message; // 'minor'\n * ```\n * @category Scales\n */\nexport function tryParseKeyName(text: string, opts?: NoteNameOptions): ParseResult<KeyName> {\n const asked = assertOptions(opts, 'opts');\n try {\n if (typeof text !== 'string') {\n throw new InvalidInputError(`key name must be a string; received ${typeof text}`);\n }\n const key = readKeyName(text, asked);\n assertNote(key.tonic, `key ${text}`);\n return { ok: true, value: key };\n } catch (error) {\n return parseFailure(error);\n }\n}\n\n/**\n * Render a spelled tonic and a mode as a key name.\n *\n * The inverse of {@link parseKeyName}. German is written the way it is read,\n * with the mode in the case of the tonic as well as in the word.\n *\n * @param key The spelled tonic and mode; any octave on the tonic is dropped,\n * since a key has no register.\n * @param opts `system` writes the name in that notation system instead of\n * English.\n * @returns The key name.\n * @throws If the tonic or the mode is not valid.\n * @example\n * ```ts\n * import { formatKeyName, parseNote } from '@libraz/libcantus';\n * formatKeyName({ tonic: parseNote('G#'), mode: 'minor' }); // 'G# minor'\n * formatKeyName({ tonic: parseNote('G#'), mode: 'minor' }, { system: 'german' }); // 'gis moll'\n * ```\n * @category Scales\n */\nexport function formatKeyName(key: KeyName, opts?: NoteNameOptions): string {\n const named = assertRecord<KeyName>(key, 'key');\n assertNote(named.tonic, 'key.tonic');\n const mode = assertOneOf(named.mode, ['major', 'minor'], 'key.mode');\n return writeKeyName(\n { tonic: { letter: mod7(named.tonic.letter), alter: named.tonic.alter }, mode },\n opts,\n );\n}\n\n/**\n * Pitch class (0..11) of a note, ignoring octave.\n *\n * @param note The note.\n * @returns The pitch class.\n * @example\n * ```ts\n * import { noteToPitchClass, parseNote } from '@libraz/libcantus';\n * noteToPitchClass(parseNote('Db')); // 1\n * ```\n * @category Pitch & Intervals\n */\nexport function noteToPitchClass(note: Note): number {\n assertNote(note, 'note');\n const natural = LETTER_SEMITONES[mod7(note.letter)] ?? 0;\n return mod12(natural + note.alter);\n}\n\n/**\n * MIDI number of a note (middle C = C4 = 60).\n *\n * @param note The note; must carry an octave.\n * @returns The MIDI number.\n * @throws If the note has no octave.\n * @example\n * ```ts\n * import { noteToMidi, parseNote } from '@libraz/libcantus';\n * noteToMidi(parseNote('A4')); // 69\n * ```\n * @category Pitch & Intervals\n */\nexport function noteToMidi(note: Note): number {\n assertNote(note, 'note');\n if (note.octave === undefined) {\n throw new InvalidInputError('noteToMidi requires an octave');\n }\n const natural = LETTER_SEMITONES[mod7(note.letter)] ?? 0;\n return (note.octave + 1) * 12 + natural + note.alter;\n}\n\n/**\n * Letter and alteration of each pitch class, by the side a black key is named\n * from when a bare MIDI number carries no spelling of its own.\n */\nconst SPELLINGS = {\n sharp: [\n [0, 0],\n [0, 1],\n [1, 0],\n [1, 1],\n [2, 0],\n [3, 0],\n [3, 1],\n [4, 0],\n [4, 1],\n [5, 0],\n [5, 1],\n [6, 0],\n ],\n flat: [\n [0, 0],\n [1, -1],\n [1, 0],\n [2, -1],\n [2, 0],\n [3, 0],\n [4, -1],\n [4, 0],\n [5, -1],\n [5, 0],\n [6, -1],\n [6, 0],\n ],\n} as const satisfies Record<'sharp' | 'flat', readonly (readonly [number, number])[]>;\n\n/** The spellings a caller may ask for, read off the table rather than repeated. */\nconst SPELLING_NAMES = Object.keys(SPELLINGS) as (keyof typeof SPELLINGS)[];\n\n/**\n * Name a MIDI number as a {@link Note}, choosing sharp or flat spelling.\n *\n * The input is rounded to the nearest integer but is not clamped to the MIDI\n * range 0..127: out-of-range values extrapolate linearly (e.g. `-1` -> `B-2`,\n * `128` -> `G#9`) and remain an exact inverse of {@link noteToMidi}.\n *\n * @param midi The MIDI number.\n * @param spelling Whether to prefer sharps or flats for black keys.\n * @returns The spelled note, with octave.\n * @throws If `spelling` is neither `'sharp'` nor `'flat'`; a name the table does\n * not carry would otherwise be spelled as one of them without saying which.\n * @example\n * ```ts\n * import { midiToNote, formatNote } from '@libraz/libcantus';\n * formatNote(midiToNote(61)); // 'C#4'\n * formatNote(midiToNote(61, 'flat')); // 'Db4'\n * ```\n * @category Pitch & Intervals\n */\nexport function midiToNote(midi: number, spelling: 'sharp' | 'flat' = 'sharp'): Note {\n assertFiniteNumber(midi, 'midi');\n const side = assertOneOf(spelling, SPELLING_NAMES, 'midi spelling');\n const rounded = Math.round(midi);\n const pc = mod12(rounded);\n const octave = Math.floor(rounded / 12) - 1;\n const entry = SPELLINGS[side][pc] ?? [0, 0];\n return { letter: entry[0], alter: entry[1], octave };\n}\n\n/**\n * Diatonic letter distance of the conventional ascending interval for each\n * semitone step within an octave: P1, m2, M2, m3, M3, P4, A4, P5, m6, M6, m7, M7.\n */\nconst LETTER_STEPS_BY_SEMITONE = [0, 1, 1, 2, 2, 3, 3, 4, 5, 5, 6, 6] as const;\n\n/**\n * Transpose a note by a signed number of semitones, keeping its spelling.\n *\n * The letter moves by the diatonic distance of the conventional interval for\n * that many semitones and the accidental is recomputed for the new letter, so\n * enharmonic identity survives: `Ab4` up a major second is `Bb4`, not `A#4`, and\n * the operation is an exact inverse of itself. An octave-less note stays\n * octave-less.\n *\n * A bare semitone count cannot distinguish an augmented fourth from a diminished\n * fifth; pass `spelling` to override the letter distance when the enharmonic\n * choice matters.\n *\n * @param note The note to transpose.\n * @param semitones The signed semitone offset.\n * @param opts `spelling` forces the result onto the sharp or flat side instead\n * of following the source note's letter.\n * @returns The transposed note.\n * @example\n * ```ts\n * import { transposeNote, formatNote, parseNote } from '@libraz/libcantus';\n * formatNote(transposeNote(parseNote('Ab4'), 2)); // 'Bb4'\n * formatNote(transposeNote(parseNote('Ab4'), 2, { spelling: 'sharp' })); // 'A#4'\n * ```\n * @category Pitch & Intervals\n */\nexport function transposeNote(\n note: Note,\n semitones: number,\n opts?: { spelling?: 'sharp' | 'flat' },\n): Note {\n assertNote(note, 'note');\n const asked = assertOptions(opts, 'opts');\n if (!Number.isFinite(semitones)) {\n throw new InvalidInputError(`semitones must be a finite number; received ${semitones}`);\n }\n const steps = Math.round(semitones);\n if (asked.spelling !== undefined) {\n return note.octave === undefined\n ? bareOf(midiToNote(60 + mod12(noteToPitchClass(note) + steps), asked.spelling))\n : midiToNote(noteToMidi(note) + steps, asked.spelling);\n }\n const direction = steps < 0 ? -1 : 1;\n const magnitude = Math.abs(steps);\n const octaves = Math.floor(magnitude / 12);\n const withinOctave = magnitude % 12;\n // Descending motion reverses the conventional ascending letter distance.\n // Deriving it from floor(negative / 12) treated -6 as a descending fourth,\n // so transpose(+n) followed by transpose(-n) changed the letter spelling.\n const letterSteps = direction * ((LETTER_STEPS_BY_SEMITONE[withinOctave] ?? 0) + 7 * octaves);\n const absoluteLetter = mod7(note.letter) + letterSteps;\n const letter = mod7(absoluteLetter);\n const natural = LETTER_SEMITONES[letter] ?? 0;\n if (note.octave === undefined) {\n return assertNote(\n { letter, alter: alterFor(natural, mod12(noteToPitchClass(note) + steps)) },\n 'transposed note',\n );\n }\n const octave = note.octave + Math.floor(absoluteLetter / 7);\n // The same domain this module requires of a note it is given: a transposition\n // that lands outside it is refused here rather than handed on to be refused\n // by whichever caller formats or measures it next.\n return assertNote(\n { letter, alter: noteToMidi(note) + steps - ((octave + 1) * 12 + natural), octave },\n 'transposed note',\n );\n}\n\n/** Drop the octave from a spelled note. */\nfunction bareOf(note: Note): Note {\n return { letter: note.letter, alter: note.alter };\n}\n\n/** Shortest signed alteration taking a letter's natural pitch class to `pc`. */\nfunction alterFor(natural: number, pc: number): number {\n const d = mod12(pc - natural);\n return d > 6 ? d - 12 : d;\n}\n\n/** Reference semitone span of a perfect/major simple interval by diatonic number. */\nconst SIMPLE_REFERENCE = [0, 0, 2, 4, 5, 7, 9, 11] as const;\n\n/** Whether a simple diatonic number (1..7 within an octave) is a perfect kind. */\nfunction isPerfectNumber(simpleNumber: number): boolean {\n return simpleNumber === 1 || simpleNumber === 4 || simpleNumber === 5;\n}\n\n/** Quality label from a diatonic number and its actual semitone span. */\nfunction qualityFromSpan(numberValue: number, semitones: number): IntervalQualityLabel {\n const octaves = Math.floor((numberValue - 1) / 7);\n const simple = numberValue - 7 * octaves;\n const reference = (SIMPLE_REFERENCE[simple] ?? 0) + 12 * octaves;\n const delta = semitones - reference;\n const repeat = (glyph: 'A' | 'd', count: number): IntervalQualityLabel =>\n `${glyph}${glyph.repeat(Math.min(count, MAX_ALTER * 2) - 1)}`;\n if (isPerfectNumber(simple)) {\n if (delta === 0) {\n return 'P';\n }\n return delta > 0 ? repeat('A', delta) : repeat('d', -delta);\n }\n if (delta === 0) {\n return 'M';\n }\n if (delta === -1) {\n return 'm';\n }\n return delta > 0 ? repeat('A', delta) : repeat('d', -delta - 1);\n}\n\n/**\n * Widest diatonic interval number the library measures.\n *\n * It is the widest {@link spelledInterval} can produce between two notes that\n * pass their own field checks: C at the lowest octave up to B at the highest\n * climbs seven letters per octave across both halves of the octave range, plus\n * the six letters within the top octave. Rejecting anything narrower would make\n * a value one public function returns impossible to hand to another.\n */\nconst MAX_INTERVAL_NUMBER = 7 * (2 * MAX_OCTAVE) + 6 + 1;\n\n/**\n * The semitone span of the interval named by a diatonic number and a quality.\n *\n * The inverse of the quality derivation in {@link spelledInterval}: it turns a\n * name back into a distance, which is what transposing by a named interval or\n * parsing one from text needs.\n *\n * @param numberValue Diatonic size: 1 = unison, 2 = second, ... 8 = octave.\n * @param quality Quality label: `'P'`, `'M'`, `'m'`, or repeated `'A'`/`'d'`.\n * @returns The signed semitone span the name covers when its letters ascend.\n * Nearly every name spans upward, but a second narrowed far enough crosses\n * zero while its letters still rise — C# up to Dbb is a doubly diminished\n * second spanning -1 — and the sign is what keeps that name reading as the\n * same interval a measurement of those two notes reports.\n * @throws If the quality cannot apply to the number, such as a major fifth or a\n * diminished unison.\n * @example\n * ```ts\n * import { intervalSemitones } from '@libraz/libcantus';\n * intervalSemitones(5, 'P'); // 7\n * ```\n * @category Pitch & Intervals\n */\nexport function intervalSemitones(numberValue: number, quality: IntervalQualityLabel): number {\n assertInteger(numberValue, 'interval number', 1, MAX_INTERVAL_NUMBER);\n const octaves = Math.floor((numberValue - 1) / 7);\n const simple = numberValue - 7 * octaves;\n const reference = (SIMPLE_REFERENCE[simple] ?? 0) + 12 * octaves;\n const perfect = isPerfectNumber(simple);\n if (quality === 'P' || quality === 'M') {\n if (perfect !== (quality === 'P')) {\n throw new InvalidInputError(\n `an interval of ${numberValue} cannot be ${quality === 'P' ? 'perfect' : 'major'}`,\n );\n }\n return reference;\n }\n if (quality === 'm') {\n if (perfect) {\n throw new InvalidInputError(\n `a perfect-class interval cannot be minor; received ${numberValue}`,\n );\n }\n return reference - 1;\n }\n if (/^A+$/.test(quality)) {\n return reference + quality.length;\n }\n if (/^d+$/.test(quality)) {\n if (numberValue === 1) {\n // The letters do not move in a unison, so narrowing one takes it past\n // zero and back up the other side: `spelledInterval` reads C down to Cb\n // as a descending augmented unison, and no measurement in the library\n // produces a diminished one. Accepting the name would return a span\n // indistinguishable from the augmented unison's.\n throw new InvalidInputError(\n `a unison cannot be diminished; a unison narrowed by a semitone descends, so name it '-${'A'.repeat(quality.length)}1'`,\n );\n }\n // The span keeps its sign: narrowing a second past zero leaves the letters\n // ascending while the pitch falls, and taking the magnitude here would make\n // the name transpose a semitone the wrong way.\n return reference - quality.length - (perfect ? 0 : 1);\n }\n throw new InvalidInputError(`unknown interval quality ${describeRejected(quality)}`);\n}\n\n/** Interval name grammar: an optional descent marker, a quality, a number. */\nconst INTERVAL_NAME_PATTERN = /^(-?)(P|M|m|A+|d+)(\\d+)$/;\n\n/**\n * Parse an interval name such as `'P5'`, `'m3'`, `'AA4'`, or `'-m3'`.\n *\n * A leading `'-'` names the same interval taken downward: the span is negated\n * and `descending` is set. The flag is not redundant with the sign — a\n * descending unison spans zero semitones, so only the flag records that the\n * letters move down.\n *\n * @param name The interval name: an optional `'-'`, a quality label, and a\n * diatonic number. Surrounding whitespace is ignored.\n * @returns The spelled interval. `descending` is always present, `false` for an\n * ascending name, and the span is the one {@link intervalSemitones} reports —\n * negative for the rare second narrowed past a zero span.\n * @throws If the name is not a quality label followed by a number, or the two\n * cannot describe the same interval. Use {@link tryParseInterval} where\n * failure is ordinary, such as an interval field read on every keystroke.\n * @example\n * ```ts\n * import { parseInterval } from '@libraz/libcantus';\n * parseInterval('m3'); // { number: 3, quality: 'm', semitones: 3, descending: false }\n * parseInterval('-m3'); // { number: 3, quality: 'm', semitones: -3, descending: true }\n * ```\n * @category Pitch & Intervals\n */\nexport function parseInterval(name: string): SpelledInterval {\n return unwrapParse(tryParseInterval(name));\n}\n\n/**\n * Parse an interval name, reporting failure instead of throwing it.\n *\n * The same reading as {@link parseInterval} — that function is this one with\n * its error thrown — for the callers where a name that does not parse yet is\n * the normal state of the input rather than a fault.\n *\n * @param name The interval name.\n * @returns The interval, or the error explaining why the text is not one.\n * @example\n * ```ts\n * import { tryParseInterval } from '@libraz/libcantus';\n * const result = tryParseInterval('M5');\n * result.ok ? result.value.semitones : result.error.message; // a fifth cannot be major\n * ```\n * @category Pitch & Intervals\n */\nexport function tryParseInterval(name: string): ParseResult<SpelledInterval> {\n try {\n const match = typeof name === 'string' ? name.trim().match(INTERVAL_NAME_PATTERN) : null;\n const quality = match?.[2] as IntervalQualityLabel | undefined;\n const numberValue = Number(match?.[3]);\n if (quality === undefined || !Number.isFinite(numberValue)) {\n throw new InvalidInputError(\n `interval must be a quality followed by a number, such as 'P5'; received ${describeRejected(name)}`,\n );\n }\n const span = intervalSemitones(numberValue, quality);\n if (match?.[1] !== '-') {\n return {\n ok: true,\n value: { number: numberValue, quality, semitones: span, descending: false },\n };\n }\n // Negating a zero span yields -0, which compares unequal to 0 under\n // Object.is and would leak into every equality check downstream.\n return {\n ok: true,\n value: { number: numberValue, quality, semitones: span === 0 ? 0 : -span, descending: true },\n };\n } catch (error) {\n return parseFailure(error);\n }\n}\n\n/**\n * Anything that names a spelled interval: an interval name, plain interval\n * data, or a value that serializes to interval data such as the `Interval`\n * class.\n *\n * @category Pitch & Intervals\n */\nexport type IntervalLike =\n | string\n | IntervalData\n | {\n /** The interval data this value stands for. */\n toJSON(): IntervalData;\n };\n\n/**\n * Interval data as a caller may write it, with the direction optional.\n *\n * Deliberately wider than {@link SpelledInterval}: a caller hands in what they\n * have, including data written before the direction travelled with it, and\n * {@link toSpelledInterval} decides what is missing. Narrowing the input to the\n * resolved shape would refuse the very data the resolver exists to repair.\n *\n * @category Pitch & Intervals\n */\nexport type IntervalData = Omit<SpelledInterval, 'descending'> & {\n /** Whether the letters move down; read from the span and quality when absent. */\n descending?: boolean;\n};\n\n/**\n * Whether an interval's letters move down.\n *\n * Data that carries the flag decides it there. Without one the quality answers\n * it: the span is compared against the quality the same number would carry with\n * its letters ascending, so plain data such as `{ P5, -7 }` reads as the\n * descending fifth it is, while `{ dd2, -1 }` reads as the ascending doubly\n * diminished second it is — an interval can climb a letter while losing a\n * semitone, and reading that span as a descent would spell the result on the\n * wrong letter.\n *\n * A unison is the exception: its letters do not move, so both readings name the\n * same quality and only the sign of the span separates them.\n */\nfunction isDescendingInterval(interval: IntervalData): boolean {\n if (interval.descending !== undefined) {\n return interval.descending;\n }\n const span = Math.round(interval.semitones);\n if (qualityFromSpan(interval.number, span) === interval.quality) {\n return interval.number === 1 && span < 0;\n }\n return span !== 0;\n}\n\n/** Validate plain interval data and return it in the canonical shape. */\nfunction normalizedInterval(data: IntervalData): SpelledInterval {\n assertInteger(data.number, 'interval.number', 1);\n assertFiniteNumber(data.semitones, 'interval.semitones');\n // A name covers exactly two spans, the ascending one and its negation, so the\n // magnitudes are compared on both sides: the ascending span of a second\n // narrowed past zero is itself negative.\n const expected = intervalSemitones(data.number, data.quality);\n if (Math.abs(data.semitones) !== Math.abs(expected)) {\n throw new InvalidInputError(\n `${data.quality}${data.number} spans ${expected} semitones; received ${data.semitones}`,\n );\n }\n // Decided here rather than left out, so a parsed name, this function and\n // `spelledInterval` all produce the same object and none of them hands on an\n // interval whose direction the next reader has to guess.\n return {\n number: data.number,\n quality: data.quality,\n semitones: data.semitones,\n descending: isDescendingInterval(data),\n };\n}\n\n/**\n * Resolve any interval-shaped value to plain {@link SpelledInterval} data.\n *\n * This is what lets an entry point accept an interval name, the plain data the\n * pitch module returns, or an `Interval` instance without every caller\n * branching on the form. An instance is accepted through its `toJSON` method\n * rather than by its type, because the core layer cannot import the model layer\n * that defines the class.\n *\n * @param value An interval name, plain interval data, or a value whose `toJSON`\n * returns interval data.\n * @returns The validated interval data, always carrying `descending`, `false`\n * for an interval that ascends.\n * @throws If the value is not interval-shaped, or its number, quality, and span\n * do not describe the same interval.\n * @example\n * ```ts\n * import { toSpelledInterval } from '@libraz/libcantus';\n * toSpelledInterval('P5'); // { number: 5, quality: 'P', semitones: 7, descending: false }\n * toSpelledInterval({ number: 5, quality: 'P', semitones: -7 });\n * // { number: 5, quality: 'P', semitones: -7, descending: true }\n * ```\n * @category Pitch & Intervals\n */\nexport function toSpelledInterval(value: IntervalLike): SpelledInterval {\n if (typeof value === 'string') {\n return parseInterval(value);\n }\n if (typeof value === 'object' && value !== null) {\n const data = 'toJSON' in value && typeof value.toJSON === 'function' ? value.toJSON() : value;\n return normalizedInterval(data as SpelledInterval);\n }\n throw new InvalidInputError(\n `interval must be a name or spelled interval data; received ${typeof value}`,\n );\n}\n\n/**\n * Anything that names a spelled note: a note name, plain note data, a MIDI\n * number, or a value that serializes to note data such as the `Note` class.\n *\n * @category Pitch & Intervals\n */\nexport type NoteLike =\n | string\n | number\n | Note\n | {\n /** The note data this value stands for. */\n toJSON(): Note;\n };\n\n/**\n * Resolve any note-shaped value to plain {@link Note} data.\n *\n * The counterpart of {@link toSpelledInterval} for notes: an entry point takes\n * whatever form the caller has — the name a text field holds, the MIDI number a\n * device sends, the data the pitch module returns, or a `Note` instance — and\n * gets one shape back. An instance is accepted through its `toJSON` method\n * rather than by its type, because the core layer cannot import the model layer\n * that defines the class.\n *\n * A number is read as MIDI and spelled with sharps, the same reading\n * {@link midiToNote} takes by default. Where a key is known the caller spells\n * it there instead — `spellPitch` reads the key — because no single default\n * suits both a G# in E major and an Ab in Eb major.\n *\n * @param value A note name, a MIDI number, plain note data, or a value whose\n * `toJSON` returns note data.\n * @returns The validated note data, carrying `octave` only when the value has\n * one.\n * @throws If the value is not note-shaped, or its letter, alteration, or octave\n * fall outside the range a spelled note holds.\n * @example\n * ```ts\n * import { toNoteData } from '@libraz/libcantus';\n * toNoteData('Eb4'); // { letter: 2, alter: -1, octave: 4 }\n * toNoteData(60); // { letter: 0, alter: 0, octave: 4 }\n * ```\n * @category Pitch & Intervals\n */\nexport function toNoteData(value: NoteLike): Note {\n if (typeof value === 'string') {\n return parseNote(value);\n }\n if (typeof value === 'number') {\n // A MIDI note number, and only that: a value from a project file or a\n // JavaScript caller that is fractional or off the compass spells a note\n // outside the domain every other entry point requires, and the failure\n // then surfaces at whichever of them reads it next rather than here.\n return midiToNote(assertMidiPitch(value, 'note'));\n }\n if (typeof value === 'object' && value !== null) {\n const data = 'toJSON' in value && typeof value.toJSON === 'function' ? value.toJSON() : value;\n const note = assertNote(data as Note, 'note');\n // A fresh object, so a caller's own note cannot become library state and\n // the result carries `octave` only when the note has one.\n return note.octave === undefined\n ? { letter: note.letter, alter: note.alter }\n : { letter: note.letter, alter: note.alter, octave: note.octave };\n }\n throw new InvalidInputError(\n `note must be a name, a MIDI number, or spelled note data; received ${typeof value}`,\n );\n}\n\n/**\n * Transpose a note by a spelled interval, keeping the spelling the interval\n * names.\n *\n * Unlike {@link transposeNote}, which picks a letter from the semitone count,\n * the diatonic number decides the letter here: transposing C by an augmented\n * second gives D#, not Eb.\n *\n * Both arguments are taken in whatever form the caller holds them — the text a\n * field carries, the plain data the library returns, or the class that wraps\n * it — as the class mirror of this operation already did.\n *\n * @param given The note to transpose: a name, a MIDI number, plain note data,\n * or a `Note`.\n * @param named The interval to apply: a name, plain interval data, or an\n * `Interval`. A negative span transposes downward.\n * @returns The transposed note, octave-less if the source was.\n * @example\n * ```ts\n * import { formatNote, transposeByInterval } from '@libraz/libcantus';\n * formatNote(transposeByInterval('C4', 'A2')); // 'D#4'\n * ```\n * @category Pitch & Intervals\n */\nexport function transposeByInterval(given: NoteLike, named: IntervalLike): Note {\n const note = toNoteData(given);\n const interval = toSpelledInterval(named);\n // `spelledInterval` accepts the full supported octave range, so accepting\n // only 64 here made a value produced by that sibling public function\n // impossible to apply back to its source note. The bound is the one that\n // sibling uses: past it the letter arithmetic answers with a note no other\n // entry point accepts, and the failure surfaces several calls away from the\n // interval that caused it.\n assertInteger(interval.number, 'interval.number', 1, MAX_INTERVAL_NUMBER);\n assertFiniteNumber(interval.semitones, 'interval.semitones');\n const letterSteps = (interval.number - 1) * (isDescendingInterval(interval) ? -1 : 1);\n const absoluteLetter = mod7(note.letter) + letterSteps;\n const letter = mod7(absoluteLetter);\n const natural = LETTER_SEMITONES[letter] ?? 0;\n const steps = Math.round(interval.semitones);\n if (note.octave === undefined) {\n return assertNote(\n { letter, alter: alterFor(natural, mod12(noteToPitchClass(note) + steps)) },\n 'transposed note',\n );\n }\n const octave = note.octave + Math.floor(absoluteLetter / 7);\n // The same domain this module requires of a note it is given: a transposition\n // that lands outside it is refused here rather than handed on to be refused\n // by whichever caller formats or measures it next.\n return assertNote(\n { letter, alter: noteToMidi(note) + steps - ((octave + 1) * 12 + natural), octave },\n 'transposed note',\n );\n}\n\n/** Diatonic ladder index of a note (letter + 7 * octave when octave-bearing). */\nfunction diatonicIndex(note: Note): number {\n return mod7(note.letter) + 7 * (note.octave ?? 0);\n}\n\n/**\n * The spelled interval from one note to another.\n *\n * When both notes carry octaves, the interval reflects their full signed\n * distance (so `C4 -> C5` is a perfect octave). When either lacks an octave the\n * interval is measured within a single ascending octave from `a` to `b`.\n *\n * @param a The lower/first note.\n * @param b The upper/second note.\n * @returns The diatonic number, quality, and semitone span.\n * @example\n * ```ts\n * import { spelledInterval, parseNote } from '@libraz/libcantus';\n * spelledInterval(parseNote('C4'), parseNote('G4'));\n * // { number: 5, quality: 'P', semitones: 7, descending: false }\n * ```\n * @category Pitch & Intervals\n */\nexport function spelledInterval(a: Note, b: Note): SpelledInterval {\n assertNote(a, 'a');\n assertNote(b, 'b');\n // Two octave-bearing notes measure their full signed distance; two\n // octave-less ones measure a single ascending octave. One of each has no\n // defined answer, and silently picking either reading gives a number the\n // caller cannot interpret.\n if ((a.octave === undefined) !== (b.octave === undefined)) {\n throw new InvalidInputError(\n 'spelledInterval needs both notes to carry an octave or neither to; received one of each',\n );\n }\n const octaved = a.octave !== undefined && b.octave !== undefined;\n let letterSteps: number;\n let semitones: number;\n if (octaved) {\n letterSteps = diatonicIndex(b) - diatonicIndex(a);\n // Signed pitch distance from a to b, so a note below a yields a negative span.\n semitones = noteToMidi(b) - noteToMidi(a);\n } else {\n letterSteps = mod7(b.letter - a.letter);\n let rawSemis = mod12(noteToPitchClass(b) - noteToPitchClass(a));\n // Lift the chromatic span into the octave nearest the diatonic reference so\n // wraparound intervals stay consistent with the diatonic number instead of\n // collapsing modulo 12. The correction is bidirectional: an upward wrap\n // (e.g. Ab -> G# = augmented seventh) adds an octave, while a same-letter or\n // downward chromatic step (e.g. E -> Eb, F# -> F, C -> Cb = descending\n // diminished/augmented unison) subtracts one so the sign follows pitch\n // direction instead of returning a garbage stack of augmentations.\n const reference = SIMPLE_REFERENCE[letterSteps + 1] ?? 0;\n if (reference - rawSemis > 6) {\n rawSemis += 12;\n } else if (rawSemis - reference > 6) {\n rawSemis -= 12;\n }\n semitones = rawSemis;\n }\n const absSteps = Math.abs(letterSteps);\n const number = absSteps + 1;\n // The span is measured in the direction the letters move, not as a magnitude:\n // C# up to Dbb steps up one letter but down one semitone, which is a doubly\n // diminished second, not a minor one. `semitones` keeps its own sign.\n //\n // A unison is the exception: the letters do not move, so there is no\n // direction to measure against and the quality names the chromatic\n // alteration alone — C down to Cb is a descending augmented unison.\n const directedSpan =\n letterSteps === 0 ? Math.abs(semitones) : letterSteps > 0 ? semitones : -semitones;\n // Decided here, so a parsed name, `normalizedInterval` and this function all\n // produce the same object for the same interval.\n return {\n number,\n quality: qualityFromSpan(number, directedSpan),\n semitones,\n descending: letterSteps < 0 || (letterSteps === 0 && semitones < 0),\n };\n}\n","import { pitchClassOf } from '../pitch/index.js';\nimport { assertFiniteSemitones, assertFlag } from '../validation/index.js';\n\n/**\n * Counterpoint classification of a harmonic interval by consonance.\n *\n * Distinct from a spelled interval's quality label — see\n * {@link IntervalQualityLabel}, which names the `'P'` / `'M'` / `'m'` / `'A'` /\n * `'d'` spelling of an interval rather than how it sounds against another\n * voice.\n *\n * @see {@link IntervalQualityLabel}\n * @category Pitch & Intervals\n */\nexport enum ConsonanceClass {\n PerfectConsonance = 0,\n ImperfectConsonance = 1,\n Dissonance = 2,\n}\n\n// An enum is emitted as a plain object carrying both the name-to-value and the\n// value-to-name mapping, so without this it is the one public table here a\n// consumer could write to — and a second consumer in the same process would\n// read the edit.\nObject.freeze(ConsonanceClass);\n\n/**\n * Reduce an interval to a simple interval class in the range [0, 11].\n *\n * Every public predicate in this module funnels through here, so an interval\n * that is not a number is rejected once rather than silently classifying as\n * something. The check comes before the absolute value: `Math.abs` reads a\n * `null` or an empty array as zero, which would report a unison — a perfect\n * consonance, and so an answer the parallel-motion rules act on — for an\n * interval nobody ever gave.\n */\nfunction simpleInterval(semitones: number): number {\n assertFiniteSemitones(semitones);\n return pitchClassOf(Math.abs(semitones));\n}\n\n/**\n * Classify an interval for counterpoint evaluation.\n *\n * The interval is reduced modulo 12, so compound intervals classify as their\n * simple equivalents. The perfect fourth (5) is context-dependent: with\n * `twoVoice` (the default) it classifies as a dissonance, matching\n * {@link isConsonantInterval}; otherwise it is an imperfect consonance.\n *\n * @param semitones Interval size in semitones (may be negative or compound).\n * @param twoVoice When true, the perfect fourth is treated as dissonant.\n * @returns The counterpoint quality of the interval.\n * @example\n * ```ts\n * import { classifyInterval, ConsonanceClass } from '@libraz/libcantus';\n * classifyInterval(7); // ConsonanceClass.PerfectConsonance\n * classifyInterval(5); // ConsonanceClass.Dissonance (two-voice)\n * classifyInterval(5, false); // ConsonanceClass.ImperfectConsonance\n * ```\n * @category Pitch & Intervals\n */\nexport function classifyInterval(semitones: number, twoVoice = true): ConsonanceClass {\n assertFlag(twoVoice, 'twoVoice');\n const pc = simpleInterval(semitones);\n if (pc === 0 || pc === 7) {\n return ConsonanceClass.PerfectConsonance;\n }\n if (pc === 3 || pc === 4 || pc === 8 || pc === 9) {\n return ConsonanceClass.ImperfectConsonance;\n }\n if (pc === 5) {\n return twoVoice ? ConsonanceClass.Dissonance : ConsonanceClass.ImperfectConsonance;\n }\n return ConsonanceClass.Dissonance;\n}\n\n/**\n * Test whether an interval is a perfect consonance: the unison/octave or the\n * fifth.\n *\n * The perfect fourth is deliberately excluded. This is the predicate the\n * parallel-motion rules are written against, where the fourth behaves as a\n * dissonance between two voices; {@link classifyInterval} is the general\n * classifier, and it treats the fourth as context-dependent.\n *\n * @param semitones Interval size in semitones (may be negative or compound).\n * @returns True for the unison/octave (0) and the perfect fifth (7) mod 12.\n * @category Pitch & Intervals\n */\nexport function isPerfectInterval(semitones: number): boolean {\n const pc = simpleInterval(semitones);\n return pc === 0 || pc === 7;\n}\n\n/**\n * Test whether an interval is consonant.\n *\n * The consonant set is {0, 3, 4, 5, 7, 8, 9} mod 12. In two-voice counterpoint\n * the perfect fourth (5) is treated as a dissonance, so `twoVoice` set to true\n * excludes it.\n *\n * @param semitones Interval size in semitones (may be negative or compound).\n * @param twoVoice When true, the perfect fourth is treated as dissonant.\n * @returns True if the interval is consonant in the given context.\n * @category Pitch & Intervals\n */\nexport function isConsonantInterval(semitones: number, twoVoice = true): boolean {\n assertFlag(twoVoice, 'twoVoice');\n const pc = simpleInterval(semitones);\n if (pc === 5) {\n return !twoVoice;\n }\n return pc === 0 || pc === 3 || pc === 4 || pc === 7 || pc === 8 || pc === 9;\n}\n","/**\n * Meter and time signatures: bar/beat arithmetic, simple vs. compound meters,\n * metric-accent hierarchy, and tuplet subdivision.\n *\n * Positions and durations are measured in quarter-note beats, matching the rest\n * of the library's beat convention (four quarter-note beats per bar in 4/4).\n * Beat 0 is the first downbeat, so a pickup sounds at negative beats, and a\n * piece that changes meter is described by a {@link MeterMap} rather than by\n * one signature.\n */\n\nimport { InvalidInputError, type ParseResult, parseFailure, unwrapParse } from '../errors/index.js';\nimport {\n assertFiniteNumber,\n assertInteger,\n assertMeterMap,\n assertOptions,\n assertPositiveInt,\n assertRange,\n assertRecord,\n assertTimeSignature,\n describeRejected,\n} from '../validation/index.js';\nimport type { MeterData } from './internal.js';\nimport {\n BEAT_EPS,\n barBeatsOf,\n barIndexOf,\n barLengthOf,\n barStartOf,\n beatOfBarIndex,\n copyMeterData,\n copyTimeSignature,\n entryIndexOf,\n groupingSumOf,\n isAdditiveReading,\n isCompoundNumerator,\n isMeterMap,\n pulseBeatsOf,\n pulseCountOf,\n pulseGroupingOf,\n} from './internal.js';\n\n/**\n * A time signature as a numerator over a note-value denominator.\n *\n * @category Rhythm & Meter\n */\nexport type TimeSignature = {\n numerator: number;\n denominator: number;\n /**\n * Optional grouping of the bar into felt beats, as positive integers. The\n * entries are group lengths, written either in the meter's main pulses —\n * `[2, 2, 3]` for a 2+2+3 reading of 7/8, `[3, 2]` for 5/8 — or, for a\n * compound numerator, in denominator units. They must sum to\n * {@link pulsesPerBar} in the first spelling and to the numerator in the\n * second; a pulse is one unit outside compound meters, where the two\n * spellings coincide.\n *\n * A compound numerator accepts both readings, and the shape of the grouping\n * says which is meant. Groups of nothing but threes spell the compound\n * division itself, so 9/8 as `[3, 3, 3]` (equivalently `[1, 1, 1]`) is the\n * ordinary three dotted-quarter pulses; any other grouping summing to the\n * numerator reads additively, so 9/8 as `[2, 2, 2, 3]` is nine quaver pulses\n * grouped aksak-fashion. {@link pulsesPerBar}, {@link pulseBeats} and\n * {@link isCompound} follow whichever reading the grouping selects.\n *\n * The head pulse of each group other than the downbeat is a secondary strong\n * pulse to {@link metricWeight}/{@link isStrongBeat}. A grouping whose groups\n * are all the same length states no accent the meter does not already have,\n * so it weighs exactly as an ungrouped bar does.\n */\n grouping?: number[];\n};\n\n/**\n * One time signature and the beat at which it takes effect.\n *\n * @category Rhythm & Meter\n */\nexport type MeterChange = {\n /** Absolute quarter-note beat the signature takes effect at. */\n startBeat: number;\n /** The signature in force from that beat until the next change. */\n ts: TimeSignature;\n};\n\n/**\n * A piece's meter over time: the signatures in force, in beat order.\n *\n * A meter change starts a new bar, so a span that does not divide evenly into\n * its own bars ends with a short bar rather than spilling across the change.\n * The first entry also governs everything before it, which is what reads a\n * pickup written at negative beats in the signature the piece opens in.\n *\n * Beat 0 is the first downbeat here as everywhere else: the opening signature\n * lays its bar lines from beat 0 whatever beat the first entry is written at, so\n * a map opening at the pickup it covers numbers its bars exactly as the bare\n * signature does. Every later entry starts a bar at the beat it takes effect.\n *\n * Pass the whole piece with its map rather than one call per meter span: a\n * split call cannot see a voice move or a key region that crosses the change.\n *\n * @category Rhythm & Meter\n */\nexport type MeterMap = MeterChange[];\n\nexport type { MeterData } from './internal.js';\n// The one tolerance the beat axis is compared with, declared in the layer\n// below every reader of it.\nexport { BEAT_EPS } from './internal.js';\n\n/**\n * Anything that names a meter: a signature text such as `'6/8'`, a plain\n * {@link TimeSignature}, a full {@link MeterMap}, or a value that serializes to\n * one of those such as the `Meter` class.\n *\n * Every meter-aware function takes this, so a piece in one meter reads as\n * `'4/4'` and a piece that changes meter reads as the map, without the caller\n * choosing a different function for each. Only a signature has a text form — a\n * meter map is a run of changes and is given as the data it is.\n *\n * @category Rhythm & Meter\n */\nexport type MeterLike =\n | string\n | TimeSignature\n | MeterMap\n | {\n /** The meter data this value stands for. */\n toJSON(): TimeSignature | MeterMap;\n };\n\n/**\n * Resolve any meter-shaped value to the plain meter data the library reads.\n *\n * The counterpart of {@link toNoteData} for meters: an entry point takes\n * whatever form the caller has — the signature a meter field holds, the data\n * the meter module returns, the map of a piece that changes meter, or a `Meter`\n * instance — and gets one of two shapes back. An instance is accepted through\n * its `toJSON` method rather than by its type, so the core layer can read a\n * class it cannot import.\n *\n * Text is read by {@link parseTimeSignature} and nothing else, so every entry\n * point that takes a meter accepts exactly the signatures that parser accepts,\n * the additive `'2+2+3/8'` included and nothing besides. A meter map has no text\n * form — it is a run of changes, each with the beat it starts at — so text\n * always names a single signature.\n *\n * @param value A signature text, a plain time signature, a meter map, or a\n * value whose `toJSON` returns one of those.\n * @param name What the meter is called in an error message, so a caller that\n * holds several of them hears which one was malformed.\n * @returns The validated signature, or the validated map, freshly allocated\n * down to every grouping array — so a caller may keep and edit what it gets\n * back without editing the meter it passed in, and without any two calls\n * handing out the same object.\n * @throws If the value names no meter, or the meter it names is malformed.\n */\nexport function toMeterData(value: MeterLike, name = 'meter'): MeterData {\n return copyMeterData(readMeterData(value, name));\n}\n\n/**\n * {@link toMeterData} without the copy, for the library's own reads.\n *\n * The copy is what keeps a returned meter from aliasing the caller's, and the\n * functions below only read what they resolve — a positional question is asked\n * once per slot, and copying the map for each of them would cost more than\n * answering it.\n */\nfunction readMeterData(value: MeterLike, name = 'meter'): MeterData {\n if (typeof value === 'string') {\n const parsed = tryParseTimeSignature(value);\n if (parsed.ok) {\n return parsed.value;\n }\n // The reading is the parser's, but the failure is reported against the\n // argument the caller filled: a caller holding several meters has to hear\n // which one it was, and `time signature` names none of them.\n throw new InvalidInputError(`${name} must name a time signature; ${parsed.error.message}`);\n }\n if (typeof value === 'object' && value !== null) {\n const data =\n !Array.isArray(value) && 'toJSON' in value && typeof value.toJSON === 'function'\n ? value.toJSON()\n : (value as MeterData);\n if (isMeterMap(data)) {\n return assertMeterMap(data, name);\n }\n // A value that carries no numerator names no meter at all, so it is refused\n // as the argument it is rather than as a signature missing a field: an\n // options object handed to the wrong parameter is not a malformed\n // numerator, and saying so sends the caller looking for the wrong fault.\n if (typeof data === 'object' && data !== null && 'numerator' in data) {\n return assertTimeSignature(data, name);\n }\n }\n throw new InvalidInputError(\n `${name} must be a time signature, a meter map, or a signature name; received ${describeRejected(value)}`,\n );\n}\n\n/**\n * The single signature a meter-shaped value names.\n *\n * A meter map is a run of changes and so names no one bar. The functions that\n * answer about a single signature take no beat to ask about, so they all read\n * the same one — the signature the piece opens in, which is the signature in\n * force at beat 0 — rather than each falling over a different field of the\n * array.\n */\nfunction readSignature(value: MeterLike, name: string): TimeSignature {\n const resolved = readMeterData(value, name);\n return isMeterMap(resolved) ? meterAtChecked(0, resolved) : resolved;\n}\n\n/**\n * A position expressed as a bar index and a quarter-note offset within the bar.\n *\n * @category Rhythm & Meter\n */\nexport type BarPosition = {\n /**\n * 0-based bar index, counting the first full bar as 0.\n * {@link formatBarPosition} renders it 1-based. A pickup sounds before that\n * bar, so its notes report bar -1.\n */\n bar: number;\n /**\n * Quarter-note offset from the start of the bar — not the felt beat. In 6/8\n * the second felt beat is at `beat: 1.5`; {@link barPositionToPulse} converts\n * to felt-beat numbering.\n */\n beat: number;\n};\n\n/**\n * The meter assumed when a caller names none.\n *\n * Frozen, and copied on the way out of every function that hands a default\n * meter back: a shared default that a caller can write to is a default the\n * whole process then reads differently.\n */\nconst DEFAULT_TS: TimeSignature = Object.freeze({ numerator: 4, denominator: 4 });\n\n/**\n * How far {@link metricGridUnit} divides a pulse to land on a meter change.\n *\n * The finest subdivision a bar is written in, which is what separates a change\n * placed inside a bar from one placed a floating hair off a beat.\n */\nconst MAX_CHANGE_DIVISIONS = 16;\n\n/** Whether `value` is an integer multiple of `unit` (within a float tolerance). */\nfunction isMultiple(value: number, unit: number): boolean {\n if (unit === 0) {\n return false;\n }\n const ratio = value / unit;\n return Math.abs(ratio - Math.round(ratio)) < BEAT_EPS;\n}\n\n/**\n * Parse a time signature such as `\"4/4\"` or `\"6/8\"`, or the additive `\"2+2+3/8\"`.\n *\n * @param text The signature text.\n * @returns The parsed time signature.\n * @throws If the text is not `n/d` with positive integers, or names a signature\n * the library rejects. Use {@link tryParseTimeSignature} where failure is\n * ordinary, such as a meter field read on every keystroke.\n * @example\n * ```ts\n * import { parseTimeSignature } from '@libraz/libcantus';\n * parseTimeSignature('6/8'); // { numerator: 6, denominator: 8 }\n * ```\n * @category Rhythm & Meter\n */\nexport function parseTimeSignature(text: string): TimeSignature {\n return unwrapParse(tryParseTimeSignature(text));\n}\n\n/**\n * Parse a time signature, reporting failure instead of throwing it.\n *\n * The same reading as {@link parseTimeSignature} — that function is this one\n * with its error thrown — for the callers where text that does not parse yet is\n * the normal state of the input rather than a fault.\n *\n * @param text The signature text.\n * @returns The signature, or the error explaining why the text is not one.\n * @example\n * ```ts\n * import { tryParseTimeSignature } from '@libraz/libcantus';\n * const result = tryParseTimeSignature('7/8');\n * result.ok ? result.value.numerator : result.error.message;\n * ```\n * @category Rhythm & Meter\n */\nexport function tryParseTimeSignature(text: string): ParseResult<TimeSignature> {\n try {\n if (typeof text !== 'string') {\n throw new InvalidInputError(`time signature must be a string; received ${typeof text}`);\n }\n return { ok: true, value: readTimeSignature(text) };\n } catch (error) {\n return parseFailure(error);\n }\n}\n\n/** The reading both parsers share, throwing on anything it cannot read. */\nfunction readTimeSignature(text: string): TimeSignature {\n const match = /^\\s*((?:\\d+\\s*\\+\\s*)*\\d+)\\s*\\/\\s*(\\d+)\\s*$/.exec(text);\n if (!match) {\n throw new InvalidInputError(`Invalid time signature: ${text}`);\n }\n const groupTokens = (match[1] ?? '').split('+').map((token) => Number.parseInt(token.trim(), 10));\n const numerator = groupTokens.reduce((sum, value) => sum + value, 0);\n const denominator = Number.parseInt(match[2] ?? '', 10);\n if (\n !Number.isSafeInteger(numerator) ||\n !Number.isSafeInteger(denominator) ||\n numerator <= 0 ||\n denominator <= 0\n ) {\n throw new InvalidInputError(`Invalid time signature: ${text}`);\n }\n // The same signature every consumer validates, validated here too: parsing\n // a signature the rest of the library rejects only moves the failure. A\n // signature without a grouping omits the field rather than holding an\n // undefined one, so equality by own keys reads a parsed signature and one\n // written by hand as the same bar.\n const ts: TimeSignature =\n groupTokens.length > 1\n ? { numerator, denominator, grouping: groupTokens }\n : { numerator, denominator };\n return assertTimeSignature(ts, `time signature ${text}`);\n}\n\n/**\n * Render a time signature as `\"n/d\"`, or as `\"a+b+c/d\"` when it carries an\n * additive grouping and `grouping` is requested.\n *\n * The additive form is what {@link parseTimeSignature} reads back, and it adds\n * its terms to get the numerator — so only a grouping written in denominator\n * units can be rendered that way. A grouping counted in main pulses whose groups\n * are all the same length (9/8 as `[1, 1, 1]`, 12/8 as `[2, 2]`) states the\n * division the bare signature already has, so it falls back to the plain form at\n * no cost. One whose groups differ (12/8 as `[1, 1, 2]`) states an accent no\n * signature text can carry, and asking for the additive form of it is refused\n * rather than answered with a bar that weighs its pulses differently.\n *\n * The plain form drops the grouping, so a round trip through it reads 7/8 as\n * flat rather than as 2+2+3; ask for the additive form to keep it.\n *\n * @param ts The time signature, in any form that names one; a meter map is\n * rendered as the signature it opens in.\n * @param opts Set `grouping: true` to render an additive grouping.\n * @returns The formatted signature.\n * @throws If `grouping: true` is asked of a grouping that no signature text can\n * spell: one counted in main pulses, on a compound numerator, whose groups are\n * not all the same length.\n * @example\n * ```ts\n * import { formatTimeSignature } from '@libraz/libcantus';\n * const aksak = { numerator: 7, denominator: 8, grouping: [2, 2, 3] };\n * formatTimeSignature(aksak); // '7/8'\n * formatTimeSignature(aksak, { grouping: true }); // '2+2+3/8'\n * ```\n * @category Rhythm & Meter\n */\nexport function formatTimeSignature(ts: MeterLike, opts: { grouping?: boolean } = {}): string {\n const asked = assertOptions(opts, 'opts');\n const signature = readSignature(ts, 'ts');\n const grouping = signature.grouping;\n if (asked.grouping === true && grouping !== undefined) {\n if (groupingSumOf(signature) === signature.numerator) {\n return `${grouping.join('+')}/${signature.denominator}`;\n }\n // A grouping counted in pulses adds up to the numerator only where a pulse\n // is one unit, so on a compound numerator it has no additive spelling. Where\n // its groups differ it is the only thing saying which pulses are accented,\n // and the plain form would hand back a bar whose weights are not this bar's.\n const pulseGrouping = pulseGroupingOf(signature);\n if (pulseGrouping !== undefined && !isUniformGrouping(pulseGrouping)) {\n throw new InvalidInputError(\n `ts carries a grouping no signature text can spell: ${grouping.join('+')} counted in the pulses of ${signature.numerator}/${signature.denominator}. Format it without the grouping to name the bar it is written in.`,\n );\n }\n }\n return `${signature.numerator}/${signature.denominator}`;\n}\n\n/**\n * Whether a meter is compound: its main pulses each divide into three, as in\n * 6/8, 9/8, 12/8, or 6/4. Compound meters are those whose numerator is a\n * multiple of three greater than three, independent of the denominator. Meters\n * like 3/8 and 3/4 (simple triples, numerator 3) are not compound, and neither\n * is a signature whose {@link TimeSignature.grouping} selects the additive\n * reading (9/8 as 2+2+2+3).\n *\n * @param ts The time signature, in any form that names one; a meter map is read\n * as the signature it opens in.\n * @returns True for compound meters.\n * @category Rhythm & Meter\n */\nexport function isCompound(ts: MeterLike): boolean {\n const signature = readSignature(ts, 'ts');\n return isCompoundNumerator(signature.numerator) && !isAdditiveReading(signature);\n}\n\n/**\n * Length of a bar in quarter-note beats.\n *\n * @param ts The time signature, in any form that names one; a meter map has no\n * single bar length, so it is read as the signature it opens in. Ask\n * {@link beatsPerBarAt} for the bar a given beat falls in.\n * @returns The bar length in quarter notes.\n * @example\n * ```ts\n * import { beatsPerBar } from '@libraz/libcantus';\n * beatsPerBar('6/8'); // 3\n * ```\n * @category Rhythm & Meter\n */\nexport function beatsPerBar(ts: MeterLike): number {\n return barBeatsOf(readSignature(ts, 'ts'));\n}\n\n/**\n * The time signature in force at a beat.\n *\n * @param beatInQuarters Absolute position in quarter-note beats.\n * @param meter A single signature, or the piece's meter map.\n * @returns The signature governing that beat.\n * @example\n * ```ts\n * import { meterAt, parseTimeSignature } from '@libraz/libcantus';\n * const meters = [\n * { startBeat: 0, ts: parseTimeSignature('4/4') },\n * { startBeat: 8, ts: parseTimeSignature('3/4') },\n * ];\n * meterAt(9, meters); // { numerator: 3, denominator: 4 }\n * ```\n * @category Rhythm & Meter\n */\nexport function meterAt(beatInQuarters: number, meter: MeterLike): TimeSignature {\n assertFiniteNumber(beatInQuarters, 'beat');\n return copyTimeSignature(meterAtChecked(beatInQuarters, readMeterData(meter)));\n}\n\n/** {@link meterAt} without re-reading an already resolved meter. */\nfunction meterAtChecked(beatInQuarters: number, meter: MeterData): TimeSignature {\n if (!isMeterMap(meter)) {\n return meter;\n }\n const ts = meter[entryIndexOf(meter, beatInQuarters)]?.ts;\n if (ts === undefined) {\n // A validated map is a non-empty run whose first entry governs everything\n // before it, so there is always an entry in force. Reaching here means the\n // map was emptied or holed after it was read, and answering 4/4 would put\n // the whole position system on a bar the caller never named.\n throw new InvalidInputError(\n `meters names no time signature in force at beat ${beatInQuarters}; a meter map must stay a non-empty run of changes while it is being read`,\n );\n }\n return ts;\n}\n\n/**\n * Absolute beat at which the bar containing `beatInQuarters` begins.\n *\n * @param beatInQuarters Absolute position in quarter-note beats.\n * @param meter A single signature, or the piece's meter map.\n * @returns The bar's first beat, negative inside a pickup.\n * @category Rhythm & Meter\n */\nexport function barStartBeat(beatInQuarters: number, meter: MeterLike): number {\n assertFiniteNumber(beatInQuarters, 'beat');\n return barStartChecked(beatInQuarters, readMeterData(meter));\n}\n\n/** {@link barStartBeat} without re-reading an already resolved meter. */\nfunction barStartChecked(beatInQuarters: number, meter: MeterData): number {\n if (isMeterMap(meter)) {\n return barStartOf(meter, beatInQuarters);\n }\n const barLen = barBeatsOf(meter);\n return Math.floor(beatInQuarters / barLen + BEAT_EPS) * barLen;\n}\n\n/**\n * Bar index of a beat: 0 for the first full bar, negative inside a pickup.\n *\n * Bars accumulate across meter changes, so the bar after a 4/4-to-3/4 change is\n * the next bar and not the first bar of a new count.\n *\n * @param beatInQuarters Absolute position in quarter-note beats.\n * @param meter A single signature, or the piece's meter map.\n * @returns The 0-based bar index.\n * @example\n * ```ts\n * import { barIndexAt, parseTimeSignature } from '@libraz/libcantus';\n * const meters = [\n * { startBeat: 0, ts: parseTimeSignature('4/4') },\n * { startBeat: 8, ts: parseTimeSignature('3/4') },\n * ];\n * barIndexAt(11, meters); // 3\n * ```\n * @category Rhythm & Meter\n */\nexport function barIndexAt(beatInQuarters: number, meter: MeterLike): number {\n assertFiniteNumber(beatInQuarters, 'beat');\n return barIndexChecked(beatInQuarters, readMeterData(meter));\n}\n\n/** {@link barIndexAt} without re-reading an already resolved meter. */\nfunction barIndexChecked(beatInQuarters: number, meter: MeterData): number {\n if (isMeterMap(meter)) {\n return barIndexOf(meter, beatInQuarters);\n }\n return Math.floor(beatInQuarters / barBeatsOf(meter) + BEAT_EPS);\n}\n\n/**\n * Length in quarter-note beats of the bar containing a beat.\n *\n * The meter-map counterpart of {@link beatsPerBar}, which answers for one\n * signature and so cannot be asked about a piece that changes meter.\n *\n * The bar the beat is in, not the bar its signature nominally has: a change of\n * meter starts a new bar, so a bar interrupted by one is shorter than its own\n * signature says. Reading the signature's own length there would put the end of\n * the bar past where the next one begins, and every span measured in bars from\n * that point on would be counted against a bar length the music never had.\n *\n * @param beatInQuarters Absolute position in quarter-note beats.\n * @param meter A single signature, or the piece's meter map.\n * @returns The bar length in quarter notes.\n * @category Rhythm & Meter\n */\nexport function beatsPerBarAt(beatInQuarters: number, meter: MeterLike): number {\n assertFiniteNumber(beatInQuarters, 'beat');\n const data = readMeterData(meter);\n // A single signature has no interruption to be cut short by, so the two\n // readings agree there and the map walk is not paid for.\n return isMeterMap(data)\n ? barLengthOf(data, beatInQuarters)\n : barBeatsOf(meterAt(beatInQuarters, meter));\n}\n\n/**\n * Read the meter out of a pair of options that accept either form.\n *\n * Entry points take `meters` for a piece that changes meter and keep `ts` as\n * sugar for a piece that does not, so this is the one place that resolves the\n * pair — including the rule that naming both is an input error rather than one\n * of them silently winning.\n *\n * @param opts The options carrying `ts`, `meters`, or neither.\n * @param name What the options belong to, for the error message.\n * @returns The meter map to analyse against, freshly allocated down to every\n * signature and grouping array, so writing to it changes nothing another\n * caller reads; 4/4 throughout when neither `ts` nor `meters` is given.\n * @throws If both `ts` and `meters` are given, or the map is malformed.\n * @example\n * ```ts\n * import { parseTimeSignature, resolveMeters } from '@libraz/libcantus';\n * resolveMeters({ ts: parseTimeSignature('3/4') });\n * // [{ startBeat: 0, ts: { numerator: 3, denominator: 4 } }]\n * ```\n * @category Rhythm & Meter\n */\nexport function resolveMeters(\n opts: { ts?: MeterLike; meters?: MeterLike },\n name = 'meters',\n): MeterMap {\n assertRecord(opts, `${name} options`);\n if (opts.ts !== undefined && opts.meters !== undefined) {\n throw new InvalidInputError(\n `${name} and ts name the same thing; give one or the other, not both`,\n );\n }\n // A null is refused rather than defaulted: the coalescing below reads it as\n // absent, so a field a caller wrote `null` into — which is what a host with no\n // meter to give passes on — would silently be answered with the library's own\n // bar instead of with the meter the caller meant to name.\n for (const [field, value] of [\n ['meters', opts.meters],\n ['ts', opts.ts],\n ] as const) {\n if ((value as unknown) === null) {\n throw new InvalidInputError(\n `${field === 'meters' ? name : 'ts'} must name a meter, not null`,\n );\n }\n }\n const given = opts.meters ?? opts.ts;\n if (given === undefined) {\n return [{ startBeat: 0, ts: copyTimeSignature(DEFAULT_TS) }];\n }\n // Either field takes any meter-shaped value, so either may name the map: what\n // separates them is which name an error is reported under, not which shape is\n // accepted where.\n const resolved = toMeterData(given, opts.meters !== undefined ? name : 'ts');\n return isMeterMap(resolved) ? resolved : [{ startBeat: 0, ts: resolved }];\n}\n\n/**\n * Number of main pulses (felt beats) per bar: the numerator for simple meters,\n * a third of it for compound meters.\n *\n * For additive/irregular meters such as 7/8 or 5/8 this counts the raw pulses\n * (7 and 5 respectively), which are otherwise felt as flat, evenly divided and\n * equally accented pulses. To recover a 2+2+3 or 3+2 felt-beat grouping, set\n * {@link TimeSignature.grouping}; {@link metricWeight} then accents each\n * group's head pulse.\n *\n * @param ts The time signature, in any form that names one; a meter map is read\n * as the signature it opens in.\n * @returns The pulse count per bar.\n * @category Rhythm & Meter\n */\nexport function pulsesPerBar(ts: MeterLike): number {\n return pulseCountOf(readSignature(ts, 'ts'));\n}\n\n/** Whether `pulseIndex` is the head pulse of one of the groups, counted in pulses. */\nfunction isGroupHead(grouping: number[], pulseIndex: number): boolean {\n let acc = 0;\n for (const g of grouping) {\n if (acc === pulseIndex) {\n return true;\n }\n acc += g;\n }\n return false;\n}\n\n/**\n * Whether every group is the same length.\n *\n * Such a grouping divides the bar the way its own meter already divides it, so\n * it names no accent structure: 9/8 as `[1, 1, 1]` is the plain compound bar,\n * not three pulses of equal strength.\n */\nfunction isUniformGrouping(grouping: number[]): boolean {\n return grouping.every((entry) => entry === grouping[0]);\n}\n\n/**\n * Convert an absolute quarter-note position to a bar index and in-bar offset.\n *\n * @param beatInQuarters Absolute position in quarter-note beats.\n * @param meter A single signature, or the piece's meter map.\n * @returns The bar and in-bar quarter-note offset.\n * @example\n * ```ts\n * import { parseTimeSignature, beatToBarPosition } from '@libraz/libcantus';\n * const ts = parseTimeSignature('4/4');\n * beatToBarPosition(5, ts); // { bar: 1, beat: 1 }\n * ```\n * @category Rhythm & Meter\n */\nexport function beatToBarPosition(beatInQuarters: number, meter: MeterLike): BarPosition {\n assertFiniteNumber(beatInQuarters, 'beat');\n return barPositionChecked(beatInQuarters, readMeterData(meter));\n}\n\n/** {@link beatToBarPosition} without re-reading an already resolved meter. */\nfunction barPositionChecked(beatInQuarters: number, meter: MeterData): BarPosition {\n return {\n bar: barIndexChecked(beatInQuarters, meter),\n beat: beatInQuarters - barStartChecked(beatInQuarters, meter),\n };\n}\n\n/**\n * Length of one felt beat (main pulse) in quarter-note beats.\n *\n * A quarter note in simple meters, a dotted quarter in compound ones, and one\n * denominator unit in an additive metre. Position displays, click tracks, and\n * score export are all written against this length.\n *\n * @param ts The time signature, in any form that names one; a meter map is read\n * as the signature it opens in.\n * @returns The pulse length in quarter-note beats.\n * @example\n * ```ts\n * import { pulseBeats } from '@libraz/libcantus';\n * pulseBeats('6/8'); // 1.5\n * ```\n * @category Rhythm & Meter\n */\nexport function pulseBeats(ts: MeterLike): number {\n return pulseBeatsOf(readSignature(ts, 'ts'));\n}\n\n/**\n * The felt-beat number of a bar position, 1-based.\n *\n * {@link BarPosition.beat} is a quarter-note offset, so in 6/8 the second felt\n * beat reads as 1.5. This is the number a musician says and a position display\n * shows.\n *\n * @param pos The bar position.\n * @param meter A single signature, or the piece's meter map.\n * @returns The 1-based felt-beat number, fractional between pulses.\n * @example\n * ```ts\n * import { barPositionToPulse, parseTimeSignature } from '@libraz/libcantus';\n * barPositionToPulse({ bar: 0, beat: 1.5 }, parseTimeSignature('6/8')); // 2\n * ```\n * @category Rhythm & Meter\n */\nexport function barPositionToPulse(pos: BarPosition, meter: MeterLike): number {\n // The bar is checked before the meter is read, so a position no meter could\n // hold is refused the same way whichever form the meter came in: which bar a\n // signature is asked about is the caller's own answer, and a single signature\n // hiding a NaN behind arithmetic that never touches it is the reading the map\n // form already rejects.\n const position = assertRecord<BarPosition>(pos, 'position');\n assertInteger(position.bar, 'position.bar');\n assertFiniteNumber(position.beat, 'position.beat');\n return pulseChecked(position, readMeterData(meter));\n}\n\n/** {@link barPositionToPulse} without re-reading an already resolved meter. */\nfunction pulseChecked(pos: BarPosition, meter: MeterData): number {\n return pos.beat / pulseBeatsOf(meterAtBarChecked(pos.bar, meter)) + 1;\n}\n\n/** The signature governing a bar index, on an already resolved meter. */\nfunction meterAtBarChecked(bar: number, meter: MeterData): TimeSignature {\n if (!isMeterMap(meter)) {\n return meter;\n }\n assertFiniteNumber(bar, 'position.bar');\n return meterAtChecked(beatOfBarIndex(meter, bar), meter);\n}\n\n/**\n * Render an absolute position as the `bar.beat` a DAW or a score shows:\n * 1-based bar, 1-based felt beat.\n *\n * The felt beats counted are the ones the bar actually has. A meter change\n * starts a new bar, so the bar it interrupts is short, and a position that\n * rounds past the end of a short bar reads as the downbeat of the next one\n * rather than as a beat the bar never reached.\n *\n * @param beatInQuarters Absolute position in quarter-note beats.\n * @param meter A single signature, or the piece's meter map.\n * @param decimals Digits of the fractional beat to keep.\n * @returns The formatted position in one of two forms: `bar.beat` on a felt\n * beat, e.g. `'3.2'` for bar 3, felt beat 2; and `bar.beat+fraction` between\n * felt beats, e.g. `'3.2+0.5'` halfway from the second felt beat to the third.\n * A reader of these strings has to take both, since most onsets of an ordinary\n * piece fall between pulses.\n * @example\n * ```ts\n * import { formatBarPosition, parseTimeSignature } from '@libraz/libcantus';\n * formatBarPosition(7.5, parseTimeSignature('6/8')); // '3.2'\n * formatBarPosition(8.25, parseTimeSignature('6/8')); // '3.2+0.5'\n * ```\n * @category Rhythm & Meter\n */\nexport function formatBarPosition(beatInQuarters: number, meter: MeterLike, decimals = 2): string {\n assertInteger(decimals, 'decimals', 0, 100);\n assertFiniteNumber(beatInQuarters, 'beat');\n const resolved = readMeterData(meter);\n const position = barPositionChecked(beatInQuarters, resolved);\n const ts = meterAtChecked(beatInQuarters, resolved);\n const pulse = pulseChecked(position, ts);\n const rounded = Number(pulse.toFixed(decimals));\n const barLength = isMeterMap(resolved)\n ? barLengthOf(resolved, beatInQuarters)\n : barBeatsOf(resolved);\n // A short bar has a whole final pulse only in the sense that the pulse it\n // started is cut off, so the count rounds up: 2 beats of 4/4 hold felt beats\n // 1 and 2, and anything past those belongs to the next bar.\n const pulsesInBar = Math.ceil(barLength / pulseBeatsOf(ts) - BEAT_EPS);\n if (rounded >= pulsesInBar + 1) {\n return `${barIndexChecked(barStartChecked(beatInQuarters, resolved) + barLength, resolved) + 1}.1`;\n }\n const wholePulse = Math.floor(rounded);\n const fraction = Number((rounded - wholePulse).toFixed(decimals));\n return fraction === 0\n ? `${position.bar + 1}.${wholePulse}`\n : `${position.bar + 1}.${wholePulse}+${fraction}`;\n}\n\n/**\n * Convert a bar index and in-bar offset back to an absolute quarter-note\n * position.\n *\n * @param pos The bar position.\n * @param meter A single signature, or the piece's meter map.\n * @returns The absolute position in quarter-note beats.\n * @category Rhythm & Meter\n */\nexport function barPositionToBeat(pos: BarPosition, meter: MeterLike): number {\n const position = assertRecord<BarPosition>(pos, 'bar position');\n assertInteger(position.bar, 'bar position bar');\n assertFiniteNumber(position.beat, 'bar position beat');\n const resolved = readMeterData(meter);\n if (isMeterMap(resolved)) {\n return beatOfBarIndex(resolved, position.bar) + position.beat;\n }\n return position.bar * barBeatsOf(resolved) + position.beat;\n}\n\n/**\n * Metric weight of a position within its bar, on a 0–3 scale:\n * 3 the downbeat, 2 a secondary strong pulse, 1 any other main pulse, and 0 an\n * off-pulse subdivision.\n *\n * The secondary strong pulse is the bar's midpoint in even simple/compound\n * meters. For an additive/irregular meter with {@link TimeSignature.grouping}\n * set (e.g. `[2, 2, 3]` for 7/8), each group's head pulse other than the\n * downbeat is the secondary strong pulse instead; without a grouping every\n * non-downbeat main pulse of such a meter weighs 1 (flat, evenly divided\n * pulses). A grouping of equal-length groups (9/8 as `[1, 1, 1]`, 4/4 as\n * `[1, 1, 1, 1]`) states the division the meter already has, so it weighs as\n * an ungrouped bar rather than accenting every group head.\n *\n * Given a meter map, the weight follows the signature in force at that beat, so\n * beat 2 of a piece is a mid-bar accent in 4/4 and a plain main pulse in 3/4.\n * The downbeat is beat 0 however much pickup precedes it, so a note in the\n * pickup weighs as the upbeat it is rather than as a downbeat.\n *\n * @param beatInQuarters Absolute quarter-note position, or an in-bar offset\n * when the meter is a single signature.\n * @param meter A single signature, or the piece's meter map.\n * @returns The metric weight (0–3).\n * @throws If the meter is malformed, including a grouping that is not a\n * positive-integer list summing to the pulse count or the numerator.\n * @example\n * ```ts\n * import { parseTimeSignature, metricWeight } from '@libraz/libcantus';\n * const ts = parseTimeSignature('4/4');\n * metricWeight(0, ts); // 3 (the downbeat)\n * ```\n * @category Rhythm & Meter\n */\nexport function metricWeight(beatInQuarters: number, meter: MeterLike): number {\n assertFiniteNumber(beatInQuarters, 'beat');\n const resolved = readMeterData(meter);\n const ts = meterAtChecked(beatInQuarters, resolved);\n const beat = beatInQuarters - barStartChecked(beatInQuarters, resolved);\n const pulse = pulseBeatsOf(ts);\n if (!isMultiple(beat, pulse)) {\n return 0;\n }\n const pulses = pulseCountOf(ts);\n const pulseIndex = Math.round(beat / pulse) % pulses;\n if (pulseIndex === 0) {\n return 3;\n }\n const grouping = pulseGroupingOf(ts);\n // A grouping of equal-length groups states no accent only when it restates the\n // division its own meter already has. An additive reading has flattened the\n // bar into its units, so its groups are the only thing saying where the accents\n // are: 6/8 as [2, 2, 2] is felt on the head of each pair, and the midpoint the\n // compound reading would accent is not one of them.\n if (grouping !== undefined && (isAdditiveReading(ts) || !isUniformGrouping(grouping))) {\n return isGroupHead(grouping, pulseIndex) ? 2 : 1;\n }\n if (pulses % 2 === 0 && pulseIndex === pulses / 2) {\n return 2;\n }\n return 1;\n}\n\n/**\n * Length in quarter-note beats of the metric grid a meter states: the longest\n * step that lands on every main pulse the meter has.\n *\n * One signature answers with its own {@link pulseBeats} — a quarter in 4/4, a\n * dotted quarter in 6/8. A meter map answers with the longest step that is a\n * whole division of every signature it names, so a grid built on it lands on the\n * pulses of each of them rather than on the ones the piece opened in. A change\n * need not fall on a bar line of the signature before it, so the beat each of\n * them takes effect at divides the step too: a grid that steps over the onset of\n * a change lands on none of the pulses that follow it.\n *\n * This is the single derivation of the grid that everything metric is laid out\n * against: a slot grid that steps over pulses never sees what happens on them,\n * so the analysis reports a bar as one chord that no instrument ever played, and\n * a generator ranks a bar's positions by a bar length it does not have.\n * {@link metricWeight} says how strong a position is, and this says which\n * positions there are; nothing else derives either.\n *\n * @param meter A single signature, or the piece's meter map.\n * @returns The grid step in quarter-note beats — 1 in 4/4, 1.5 in 6/8.\n */\nexport function metricGridUnit(meter: MeterLike): number {\n const resolved = readMeterData(meter);\n if (!isMeterMap(resolved)) {\n return pulseBeatsOf(resolved);\n }\n let unit = 0;\n for (const change of resolved) {\n unit = commonStep(unit, pulseBeatsOf(change.ts));\n }\n if (unit <= 0) {\n return pulseBeatsOf(DEFAULT_TS);\n }\n const origin = resolved[0]?.startBeat ?? 0;\n let onChanges = unit;\n for (const change of resolved) {\n onChanges = commonStep(onChanges, Math.abs(change.startBeat - origin));\n }\n // An onset written a hair off a beat divides into a step no coarser than the\n // hair, and a grid that fine costs a slot per step of the piece while landing\n // on nothing anyone plays. Past the division limit the onset is read as\n // unmeasured and the grid keeps the step the pulses alone state.\n return onChanges * MAX_CHANGE_DIVISIONS >= unit - BEAT_EPS ? onChanges : unit;\n}\n\n/**\n * The longest step both lengths are a whole number of, or `b` when `a` is zero.\n *\n * Euclid over beat lengths, which are the small rationals a signature makes them\n * — halves, thirds and quarters of a beat — so the remainder reaches zero in a\n * few turns. A pair that does not divide within them falls back to the shorter\n * length, since a grid finer than either pulse buys nothing the pulses do not\n * already give and a runaway one costs a slot per subdivision of the piece.\n */\nfunction commonStep(a: number, b: number): number {\n let longer = Math.max(a, b);\n let shorter = Math.min(a, b);\n for (let i = 0; i < 8 && shorter > BEAT_EPS; i += 1) {\n const remainder = longer - Math.floor(longer / shorter + BEAT_EPS) * shorter;\n longer = shorter;\n shorter = remainder > BEAT_EPS ? remainder : 0;\n }\n const smallest = a > 0 && b > 0 ? Math.min(a, b) : Math.max(a, b);\n return longer > BEAT_EPS && longer <= smallest + BEAT_EPS ? longer : smallest;\n}\n\n/**\n * Whether a position is metrically accented (weight 2 or more — a downbeat or a\n * secondary strong pulse).\n *\n * @param beatInQuarters Absolute quarter-note position, or an in-bar offset\n * when the meter is a single signature.\n * @param meter A single signature, or the piece's meter map.\n * @returns True on strong beats.\n * @category Rhythm & Meter\n */\nexport function isStrongBeat(beatInQuarters: number, meter: MeterLike): boolean {\n return metricWeight(beatInQuarters, meter) >= 2;\n}\n\n/**\n * Subdivide a span into `count` equal tuplet durations (e.g. an eighth-note\n * triplet is `tuplet(1, 3)`).\n *\n * @param totalBeats Total span in quarter-note beats.\n * @param count Number of equal parts.\n * @returns `count` equal durations summing to `totalBeats`.\n * @throws If `count` is not a positive integer.\n * @category Rhythm & Meter\n */\nexport function tuplet(totalBeats: number, count: number): number[] {\n assertRange(totalBeats, 0, Number.MAX_SAFE_INTEGER, 'tuplet total beats');\n assertPositiveInt(count, 'tuplet count');\n return new Array<number>(count).fill(totalBeats / count);\n}\n"],"mappings":"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","names":["ConsonanceClass"]}