@libraz/libcantus 1.2.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (131) hide show
  1. package/NOTICE +63 -0
  2. package/README.md +7 -1
  3. package/README_ja.md +17 -11
  4. package/dist/analyze/index.cjs +31 -7
  5. package/dist/analyze/index.cjs.map +1 -1
  6. package/dist/analyze/index.d.cts +161 -13
  7. package/dist/analyze/index.d.ts +161 -13
  8. package/dist/analyze/index.js +37 -13
  9. package/dist/{chunk-NB25P3EH.js → chunk-2G5MCGYU.js} +33 -11
  10. package/dist/chunk-2G5MCGYU.js.map +1 -0
  11. package/dist/{chunk-NM7UAMC3.cjs → chunk-3FDBMIPR.cjs} +64 -64
  12. package/dist/chunk-3FDBMIPR.cjs.map +1 -0
  13. package/dist/{chunk-HPVSH7SF.cjs → chunk-3MDOEFIQ.cjs} +618 -954
  14. package/dist/chunk-3MDOEFIQ.cjs.map +1 -0
  15. package/dist/{chunk-FBH75DAY.js → chunk-5MWRBYAT.js} +560 -159
  16. package/dist/chunk-5MWRBYAT.js.map +1 -0
  17. package/dist/{chunk-J7FHVZII.cjs → chunk-6TTBEON3.cjs} +3074 -740
  18. package/dist/chunk-6TTBEON3.cjs.map +1 -0
  19. package/dist/{chunk-UMWZ4ZET.js → chunk-7NQ6AL3H.js} +4 -4
  20. package/dist/chunk-7NQ6AL3H.js.map +1 -0
  21. package/dist/{chunk-HWHGOVO6.cjs → chunk-E3QO3UET.cjs} +31 -23
  22. package/dist/chunk-E3QO3UET.cjs.map +1 -0
  23. package/dist/{chunk-H2KJHBW4.js → chunk-FJFULJZE.js} +2375 -191
  24. package/dist/chunk-FJFULJZE.js.map +1 -0
  25. package/dist/{chunk-Q6LFSAKV.js → chunk-FK3DGAIZ.js} +2657 -323
  26. package/dist/chunk-FK3DGAIZ.js.map +1 -0
  27. package/dist/chunk-GEDTJHAC.cjs.map +1 -1
  28. package/dist/{chunk-RFIBF2RR.js → chunk-H7FVMBUC.js} +138 -65
  29. package/dist/chunk-H7FVMBUC.js.map +1 -0
  30. package/dist/{chunk-DSMJRXCZ.cjs → chunk-HYSVSFNI.cjs} +931 -530
  31. package/dist/chunk-HYSVSFNI.cjs.map +1 -0
  32. package/dist/{chunk-35NBV2FT.cjs → chunk-KMYGRFZ6.cjs} +47 -24
  33. package/dist/chunk-KMYGRFZ6.cjs.map +1 -0
  34. package/dist/chunk-LQZQDBCD.cjs +5513 -0
  35. package/dist/chunk-LQZQDBCD.cjs.map +1 -0
  36. package/dist/{chunk-PM4XJE2Y.cjs → chunk-P3CPXAJ5.cjs} +76 -54
  37. package/dist/chunk-P3CPXAJ5.cjs.map +1 -0
  38. package/dist/{chunk-S5BKZZGM.cjs → chunk-S3QELJUE.cjs} +72 -56
  39. package/dist/chunk-S3QELJUE.cjs.map +1 -0
  40. package/dist/{chunk-PUKJP2Z5.js → chunk-TXFWSU5D.js} +31 -8
  41. package/dist/chunk-TXFWSU5D.js.map +1 -0
  42. package/dist/{chunk-76ZBTRG2.cjs → chunk-U4EQTDGN.cjs} +258 -218
  43. package/dist/chunk-U4EQTDGN.cjs.map +1 -0
  44. package/dist/chunk-UGLFDG7L.cjs.map +1 -1
  45. package/dist/{chunk-HYJJ2V2I.js → chunk-UTE5A36R.js} +483 -819
  46. package/dist/chunk-UTE5A36R.js.map +1 -0
  47. package/dist/{chunk-NFJ4P6ZZ.js → chunk-UZKQISRF.js} +17 -9
  48. package/dist/chunk-UZKQISRF.js.map +1 -0
  49. package/dist/{chunk-7KG3RTYS.js → chunk-VL5NXVCN.js} +281 -155
  50. package/dist/chunk-VL5NXVCN.js.map +1 -0
  51. package/dist/{chunk-CGBADIO5.cjs → chunk-WOMCXN2W.cjs} +328 -202
  52. package/dist/chunk-WOMCXN2W.cjs.map +1 -0
  53. package/dist/{chunk-3R3QVKY5.cjs → chunk-YDGMWH43.cjs} +397 -324
  54. package/dist/chunk-YDGMWH43.cjs.map +1 -0
  55. package/dist/{chunk-AGOVW7U6.js → chunk-YYVXRV3V.js} +72 -56
  56. package/dist/chunk-YYVXRV3V.js.map +1 -0
  57. package/dist/{chunk-M5RYMAFI.js → chunk-ZLNSH4UL.js} +71 -31
  58. package/dist/chunk-ZLNSH4UL.js.map +1 -0
  59. package/dist/{coerce-DRERzdve.d.cts → coerce-CUhHc3Tu.d.ts} +16 -8
  60. package/dist/{coerce-DP0vYu-x.d.ts → coerce-Ytt2Eiq9.d.cts} +16 -8
  61. package/dist/core/index.cjs +5 -5
  62. package/dist/core/index.cjs.map +1 -1
  63. package/dist/core/index.d.cts +9 -8
  64. package/dist/core/index.d.ts +9 -8
  65. package/dist/core/index.js +4 -4
  66. package/dist/generate/index.cjs +20 -8
  67. package/dist/generate/index.cjs.map +1 -1
  68. package/dist/generate/index.d.cts +105 -17
  69. package/dist/generate/index.d.ts +105 -17
  70. package/dist/generate/index.js +19 -7
  71. package/dist/{index-CL4b4gUQ.d.ts → index-5VJgKz_Q.d.cts} +6 -2
  72. package/dist/{index-B9QLziDe.d.cts → index-BLuDesVG.d.ts} +20 -13
  73. package/dist/{index-BHIUyjhZ.d.ts → index-BV6APVa6.d.cts} +20 -13
  74. package/dist/{index-BMweUlm5.d.cts → index-Bf0Sv8a9.d.ts} +6 -2
  75. package/dist/{index-Dw2DP7vm.d.ts → index-BkT21EMv.d.cts} +3 -2
  76. package/dist/{index-BL5N2Oyz.d.cts → index-C7KCaTRz.d.ts} +3 -2
  77. package/dist/{index-Cy15oTvh.d.ts → index-C9MYbuKS.d.cts} +7 -3
  78. package/dist/{index-Cy15oTvh.d.cts → index-C9MYbuKS.d.ts} +7 -3
  79. package/dist/{index-BNSM-DSk.d.cts → index-DVInzCDS.d.cts} +533 -28
  80. package/dist/{index-9eoQs2C1.d.ts → index-Dg-SAfhz.d.ts} +6 -4
  81. package/dist/{index-BJgP97N1.d.ts → index-jgeug9EA.d.ts} +533 -28
  82. package/dist/{index-cHvbYgJI.d.cts → index-pQihL4z7.d.cts} +6 -4
  83. package/dist/index.cjs +49 -13
  84. package/dist/index.cjs.map +1 -1
  85. package/dist/index.d.cts +13 -13
  86. package/dist/index.d.ts +13 -13
  87. package/dist/index.js +55 -19
  88. package/dist/{masks-Cc7-MzzY.d.ts → masks-BnzXnBj0.d.cts} +3 -2
  89. package/dist/{masks-pADfTOiD.d.cts → masks-tycmkrgs.d.ts} +3 -2
  90. package/dist/model/index.cjs +12 -12
  91. package/dist/model/index.cjs.map +1 -1
  92. package/dist/model/index.d.cts +259 -48
  93. package/dist/model/index.d.ts +259 -48
  94. package/dist/model/index.js +11 -11
  95. package/dist/{positional-DJgs6ltD.d.ts → positional-CscpxtlE.d.cts} +3 -2
  96. package/dist/{positional-DMZer-FM.d.cts → positional-DLnfUgqG.d.ts} +3 -2
  97. package/dist/{index-BRMbPkHE.d.ts → profile-B4WqcM4H.d.ts} +85 -610
  98. package/dist/{index-DGCNKAUr.d.cts → profile-BJd1XkPB.d.cts} +85 -610
  99. package/dist/theory/index.cjs +5 -5
  100. package/dist/theory/index.cjs.map +1 -1
  101. package/dist/theory/index.d.cts +18 -14
  102. package/dist/theory/index.d.ts +18 -14
  103. package/dist/theory/index.js +4 -4
  104. package/dist/{index-CJBBiAmU.d.ts → types-7mGFwvMm.d.ts} +1210 -31
  105. package/dist/{index-BBWNZS0f.d.cts → types-_ofpb2be.d.cts} +1210 -31
  106. package/package.json +13 -13
  107. package/dist/chunk-35NBV2FT.cjs.map +0 -1
  108. package/dist/chunk-3R3QVKY5.cjs.map +0 -1
  109. package/dist/chunk-76ZBTRG2.cjs.map +0 -1
  110. package/dist/chunk-7KG3RTYS.js.map +0 -1
  111. package/dist/chunk-AGOVW7U6.js.map +0 -1
  112. package/dist/chunk-CGBADIO5.cjs.map +0 -1
  113. package/dist/chunk-DSMJRXCZ.cjs.map +0 -1
  114. package/dist/chunk-FBH75DAY.js.map +0 -1
  115. package/dist/chunk-H2KJHBW4.js.map +0 -1
  116. package/dist/chunk-HPVSH7SF.cjs.map +0 -1
  117. package/dist/chunk-HWHGOVO6.cjs.map +0 -1
  118. package/dist/chunk-HYJJ2V2I.js.map +0 -1
  119. package/dist/chunk-J7FHVZII.cjs.map +0 -1
  120. package/dist/chunk-M5RYMAFI.js.map +0 -1
  121. package/dist/chunk-NB25P3EH.js.map +0 -1
  122. package/dist/chunk-NFJ4P6ZZ.js.map +0 -1
  123. package/dist/chunk-NM7UAMC3.cjs.map +0 -1
  124. package/dist/chunk-PM4XJE2Y.cjs.map +0 -1
  125. package/dist/chunk-PUKJP2Z5.js.map +0 -1
  126. package/dist/chunk-Q6LFSAKV.js.map +0 -1
  127. package/dist/chunk-RFIBF2RR.js.map +0 -1
  128. package/dist/chunk-S5BKZZGM.cjs.map +0 -1
  129. package/dist/chunk-SGLEQVJH.cjs +0 -3329
  130. package/dist/chunk-SGLEQVJH.cjs.map +0 -1
  131. package/dist/chunk-UMWZ4ZET.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/instrument/profile.ts","../src/core/instrument/playability.ts","../src/core/instrument/profiles.ts","../src/core/random/internal.ts","../src/core/random/positional.ts","../src/core/random/seed.ts","../src/core/random/version.ts","../src/core/random/index.ts"],"sourcesContent":["import { InvalidInputError } from '../errors/index.js';\nimport {\n assertArray,\n assertInteger,\n assertMidiPitch,\n assertOneOf,\n assertPositiveInt,\n describeRejected,\n} from '../validation/index.js';\nimport type { Articulation } from './articulation.js';\nimport { ARTICULATIONS } from './articulation.js';\n\n/**\n * Every limb a percussionist strikes with, in declaration order.\n *\n * @category Core\n */\nexport const LIMBS = Object.freeze(['rightHand', 'leftHand', 'rightFoot', 'leftFoot'] as const);\n\n/**\n * One limb of a percussionist.\n *\n * @category Core\n */\nexport type Limb = (typeof LIMBS)[number];\n\n/**\n * Fields every instrument profile carries, whatever its family.\n *\n * @category Core\n */\nexport type InstrumentProfileCommon = {\n /** Instrument name, for issue messages and for the caller's own display. */\n name: string;\n /** Techniques this instrument can produce; anything else it cannot play. */\n articulations: readonly Articulation[];\n /** Greatest number of notes that can sound at once. */\n polyphony: number;\n};\n\n/**\n * A fretted or fretless string instrument, described by what it is rather than\n * by the range it happens to have.\n *\n * The sounding range follows from `tuning` and `frets`: string `s` sounds\n * `tuning[s] .. tuning[s] + frets`. Storing `[min, max]` instead would make a\n * five-string bass, a drop tuning, a seven-string guitar and an extended-range\n * neck four unrelated special cases, and would leave \"the neck is not long\n * enough\" indistinguishable from \"the note is below the instrument\".\n *\n * @category Core\n */\nexport type StringedProfile = InstrumentProfileCommon & {\n kind: 'stringed';\n /** Open-string MIDI pitch per string, lowest-sounding string first. */\n tuning: readonly number[];\n /** Highest fret number; fret 0 is the open string. */\n frets: number;\n /** Greatest fret span one hand can hold down at once. */\n maxStretch: number;\n /**\n * The neck has no frets. Positions are continuous, so intonation is the\n * player's and a slide is unbroken; in twelve-tone equal temperament the\n * positions coincide with fret numbers, so range and stretch are read the\n * same way.\n */\n fretless?: boolean;\n};\n\n/**\n * A percussion setup, described by the voices within reach of each limb.\n *\n * A kit's constraint is not range but limbs: a voice no limb can reach is not\n * on the instrument, and two voices needing the same limb at the same instant\n * cannot both sound.\n *\n * @category Core\n */\nexport type PercussionProfile = InstrumentProfileCommon & {\n kind: 'percussion';\n /** The limbs the player has available. */\n limbs: readonly Limb[];\n /** Limbs that can strike each voice, in preference order, keyed by MIDI note. */\n reach: Readonly<Record<number, readonly Limb[]>>;\n /**\n * Voices dubbed over the kit on a pass of their own, by MIDI note number.\n *\n * A tambourine or a shaker riding a groove whose backbeat already commits\n * both hands is a second pass, not a third hand: it is played over the kit,\n * so it takes no limb from the kit and none from another overdub. Such a\n * voice is still held in a hand on its own pass, so it keeps its `reach`\n * entry and remains a voice of the instrument; this names which of them are\n * played that way.\n */\n overdub?: readonly number[];\n};\n\n/**\n * An instrument the library can check a passage against.\n *\n * @category Core\n */\nexport type InstrumentProfile = StringedProfile | PercussionProfile;\n\ndeclare const checked: unique symbol;\n\n/**\n * A neck whose every field has been checked against the domain it declares.\n *\n * @category Core\n */\nexport type ValidatedStringedProfile = StringedProfile & { readonly [checked]: true };\n\n/**\n * A kit whose every field has been checked against the domain it declares.\n *\n * @category Core\n */\nexport type ValidatedPercussionProfile = PercussionProfile & { readonly [checked]: true };\n\n/**\n * A profile whose every field has been checked against the domain it declares.\n *\n * The mark is carried by the type alone — nothing is added to the object, so a\n * validated profile serializes exactly as the plain one it was made from. Its\n * only source is {@link toInstrumentProfile}, which is what makes the mark worth\n * anything: the routines that read a profile note by note take this rather than\n * a plain {@link InstrumentProfile}, so a path that skipped the checks does not\n * compile instead of failing on the one passage that happens to expose it.\n *\n * @category Core\n */\nexport type ValidatedProfile = ValidatedStringedProfile | ValidatedPercussionProfile;\n\n/**\n * Anything that names an instrument: a plain {@link InstrumentProfile}, or a\n * value that serializes to one such as the `Instrument` class.\n *\n * Every entry point that takes an instrument takes this, so a caller holding\n * the class hands it over as it is instead of unwrapping it for one call and\n * wrapping it again for the next.\n *\n * @category Core\n */\nexport type InstrumentProfileLike =\n | InstrumentProfile\n | {\n /** The profile data this value stands for. */\n toJSON(): InstrumentProfile;\n };\n\n/**\n * Resolve any instrument-shaped value to a plain {@link InstrumentProfile}.\n *\n * The counterpart of {@link toNoteData} for instruments: an entry point takes\n * whatever form the caller has — the profile a project file holds, one of the\n * built-in profiles, or an `Instrument` instance — and gets one shape back. An\n * instance is accepted through its `toJSON` method rather than by its type,\n * because the core layer cannot import the model layer that defines the class.\n *\n * @param value A plain profile, or a value whose `toJSON` returns one.\n * @param name What the instrument is called in an error message, so a caller\n * holding several of them hears which one was malformed.\n * @returns The validated profile.\n * @throws If the value names no instrument, or the instrument it names is\n * contradictory — a neck with no strings, a fret count that is no count, or a\n * kit no limb reaches.\n * @category Core\n */\nexport function toInstrumentProfile(\n value: InstrumentProfileLike,\n name = 'instrument',\n): ValidatedProfile {\n if (typeof value !== 'object' || value === null) {\n throw new InvalidInputError(`${name} must be an instrument profile; received ${typeof value}`);\n }\n const data =\n 'toJSON' in value && typeof value.toJSON === 'function'\n ? value.toJSON()\n : (value as InstrumentProfile);\n const kind: unknown = data?.kind;\n if (kind !== 'stringed' && kind !== 'percussion') {\n throw new InvalidInputError(\n `${name} must be a stringed or percussion profile; received kind ${String(kind)}`,\n );\n }\n assertProfile(data);\n // The only place the mark is applied, and it is applied to a profile every\n // check has just passed: see {@link ValidatedProfile}.\n return data as ValidatedProfile;\n}\n\n/**\n * Resolve any instrument-shaped value to a plain {@link StringedProfile}.\n *\n * What {@link toInstrumentProfile} is for an entry point that reads any\n * instrument, this is for one that only has a neck to work with: a bass line\n * placed on strings and frets cannot be written for a kit, and saying so by\n * name is more use than a missing `tuning` surfacing later as a note the\n * generator could not place.\n *\n * @param value A plain profile, or a value whose `toJSON` returns one.\n * @param name What the instrument is called in an error message.\n * @returns The validated profile, narrowed to the stringed family.\n * @throws If the value names no instrument, or names one with no strings.\n * @category Core\n */\nexport function toStringedProfile(\n value: InstrumentProfileLike,\n name = 'instrument',\n): ValidatedStringedProfile {\n const profile = toInstrumentProfile(value, name);\n if (profile.kind !== 'stringed') {\n throw new InvalidInputError(\n `${name} must be a stringed instrument; ${profile.name} has no strings`,\n );\n }\n return profile;\n}\n\n/**\n * A fretting-hand position: which string, and how far up the neck.\n *\n * @category Core\n */\nexport type StringFingering = {\n /** Index into the `tuning` of a {@link StringedProfile}. */\n string: number;\n /** Fret number; 0 is the open string. */\n fret: number;\n};\n\n/**\n * Greatest fret number a neck can carry.\n *\n * A fret sounds an open string a semitone higher per fret, so a neck longer\n * than the MIDI compass names positions that sound no pitch. Bounding it here\n * is what keeps every routine that walks the instrument by octaves — the range,\n * the fingerings, the folding — finite for every profile the library accepts.\n */\nexport const MAX_FRETS = 127;\n\n/**\n * Greatest number of notes one instrument may sound at once.\n *\n * The MIDI compass is 128 pitches, so an instrument sounding more than that at\n * one instant is sounding one of them twice — which is a voicing question\n * rather than a property of the instrument.\n */\nexport const MAX_POLYPHONY = 128;\n\n/**\n * Reject a profile whose own description is contradictory.\n *\n * Every field the library goes on to read is checked, not only the ones that\n * describe the family: a profile read out of a project file or written by a\n * JavaScript caller may be missing any of them, and a missing one does not\n * fail where it is missing. A `maxStretch` of `undefined` makes every span\n * comparison false, so a chord no hand can hold reads as playable; a missing\n * `polyphony` turns every group into one that exceeds it, and says so in a\n * message with `undefined` in it. Neither is a diagnosis a caller can act on.\n */\nfunction assertProfile(profile: InstrumentProfile): void {\n if (typeof profile.name !== 'string' || profile.name === '') {\n throw new InvalidInputError(\n `instrument name must be a non-empty string; received ${describeRejected(profile.name)}`,\n );\n }\n if (!Array.isArray(profile.articulations)) {\n throw new InvalidInputError(\n `${profile.name} articulations must be an array; received ${describeRejected(profile.articulations)}`,\n );\n }\n for (const [index, articulation] of profile.articulations.entries()) {\n assertOneOf(articulation, ARTICULATIONS, `${profile.name} articulations[${index}]`);\n }\n assertPositiveInt(profile.polyphony, `${profile.name} polyphony`, MAX_POLYPHONY);\n if (profile.kind === 'stringed') {\n if (!Array.isArray(profile.tuning) || profile.tuning.length === 0) {\n throw new InvalidInputError(`${profile.name} must have at least one string`);\n }\n for (const [index, open] of profile.tuning.entries()) {\n assertMidiPitch(open, `${profile.name} tuning[${index}]`);\n }\n assertInteger(profile.frets, `${profile.name} frets`, 0, MAX_FRETS);\n // A hand holds down frets, so the span it can hold is a fret count: zero is\n // a player who only sounds open strings, and anything wider than the neck\n // is a stretch the neck has nowhere to put.\n assertInteger(profile.maxStretch, `${profile.name} maxStretch`, 0, MAX_FRETS);\n return;\n }\n if (!Array.isArray(profile.limbs) || profile.limbs.length === 0) {\n throw new InvalidInputError(`${profile.name} must have at least one limb`);\n }\n for (const [index, limb] of profile.limbs.entries()) {\n assertOneOf(limb, LIMBS, `${profile.name} limbs[${index}]`);\n }\n if (typeof profile.reach !== 'object' || profile.reach === null) {\n throw new InvalidInputError(\n `${profile.name} reach must be a table of limbs by voice; received ${describeRejected(profile.reach)}`,\n );\n }\n const voices = Object.keys(profile.reach);\n for (const key of voices) {\n assertMidiPitch(Number(key), `${profile.name} reach pitch`);\n }\n // The table is held to the limbs the library names, so a voice reaching for\n // something else is refused here rather than carried to the plain data.\n for (const key of voices) {\n const label = `${profile.name} reach[${key}]`;\n for (const [index, limb] of assertArray<Limb>(\n (profile.reach as Record<string, unknown>)[key],\n label,\n ).entries()) {\n assertOneOf(limb, LIMBS, `${label}[${index}]`);\n }\n }\n // A voice is on the kit only when a limb the player has can strike it, so a\n // reach table naming limbs the player has not got describes a kit with\n // nothing on it — and a range read off one has no low or high to report.\n if (voices.every((key) => reachOf(profile, Number(key)).length === 0)) {\n throw new InvalidInputError(`${profile.name} must have at least one voice within reach`);\n }\n // An overdub is still held in a hand, on a pass of its own, so it is read\n // through the reach and the limbs like every other voice: naming one the\n // player cannot hold leaves it off the instrument rather than in dispute.\n if (profile.overdub !== undefined) {\n for (const pitch of assertArray<number>(profile.overdub, `${profile.name} overdub`)) {\n assertMidiPitch(pitch, `${profile.name} overdub pitch`);\n }\n }\n}\n\n/**\n * Whether a voice is dubbed over the kit rather than played by the limbs\n * holding it together.\n *\n * An overdubbed voice is recorded on a pass of its own, so it shares limbs\n * neither with the kit nor with another overdub — which is what lets a shaker\n * sound through a bar whose every stroke is already spoken for.\n *\n * @param profile The kit.\n * @param pitch MIDI pitch, or `undefined` for a note that is not there.\n * @returns True when the kit names this voice as an overdub.\n * @category Core\n */\nexport function isOverdub(profile: PercussionProfile, pitch: number | undefined): boolean {\n if (pitch === undefined) {\n return false;\n }\n return (profile.overdub ?? []).includes(pitch);\n}\n\n/**\n * The limbs a kit can actually strike a voice with.\n *\n * A `reach` entry names the limbs that are placed to hit a voice; `limbs` names\n * the limbs the player has. A voice reachable only by a limb the player has not\n * got is not on the instrument, so the two are read together everywhere rather\n * than the reach alone.\n *\n * @param profile The kit.\n * @param pitch MIDI pitch, or `undefined` for a note that is not there.\n * @returns The available limbs in preference order; empty when none can strike.\n * @category Core\n */\nexport function reachOf(profile: PercussionProfile, pitch: number | undefined): readonly Limb[] {\n if (pitch === undefined) {\n return [];\n }\n return (profile.reach[pitch] ?? []).filter((limb) => profile.limbs.includes(limb));\n}\n\n/**\n * The lowest and highest pitch an instrument sounds.\n *\n * For a string instrument this is derived from the tuning and the fret count,\n * never stored; for a kit it is the extent of the voices the player's limbs\n * reach. The range is not necessarily gapless — use {@link canSound} to ask\n * about one pitch.\n *\n * @param profile The instrument.\n * @returns The extreme sounding pitches, inclusive.\n *\n * @example\n * ```ts\n * import { BASS_5_STRING, instrumentRange } from '@libraz/libcantus';\n * instrumentRange(BASS_5_STRING).low; // 23, low B\n * ```\n * @category Core\n */\nexport function instrumentRange(profile: InstrumentProfileLike): { low: number; high: number } {\n return rangeIn(toInstrumentProfile(profile));\n}\n\n/** {@link instrumentRange} on a profile that has already been checked. */\nexport function rangeIn(profile: ValidatedProfile): { low: number; high: number } {\n if (profile.kind === 'stringed') {\n let low = Number.POSITIVE_INFINITY;\n let high = Number.NEGATIVE_INFINITY;\n for (const open of profile.tuning) {\n low = Math.min(low, open);\n high = Math.max(high, open + profile.frets);\n }\n return { low, high };\n }\n let low = Number.POSITIVE_INFINITY;\n let high = Number.NEGATIVE_INFINITY;\n for (const key of Object.keys(profile.reach)) {\n const pitch = Number(key);\n // A voice only an absent limb reaches is not on this kit, so it does not\n // stretch the range either — otherwise the range would promise a pitch\n // {@link canSound} denies.\n if (reachOf(profile, pitch).length === 0) {\n continue;\n }\n low = Math.min(low, pitch);\n high = Math.max(high, pitch);\n }\n return { low, high };\n}\n\n/**\n * Whether the instrument has this pitch at all.\n *\n * This is the first of the three playability layers: no amount of skill or\n * rehearsal puts a note on an instrument that has no position for it.\n *\n * @param profile The instrument.\n * @param pitch MIDI pitch.\n * @returns True when some string and fret, or some limb the player has,\n * produces it.\n * @category Core\n */\nexport function canSound(profile: InstrumentProfileLike, pitch: number): boolean {\n const resolved = toInstrumentProfile(profile, 'instrument');\n assertMidiPitch(pitch, 'pitch');\n return soundsIn(resolved, pitch);\n}\n\n/** {@link canSound} on a profile that has already been checked. */\nexport function soundsIn(profile: ValidatedProfile, pitch: number): boolean {\n if (profile.kind === 'stringed') {\n return profile.tuning.some((open) => pitch >= open && pitch - open <= profile.frets);\n }\n return reachOf(profile, pitch).length > 0;\n}\n\n/**\n * Every position on the neck that sounds a pitch, lowest string first.\n *\n * @param profile The instrument.\n * @param pitch MIDI pitch.\n * @returns One entry per string that reaches the pitch; empty when none does.\n * @category Core\n */\nexport function fingeringsFor(profile: InstrumentProfileLike, pitch: number): StringFingering[] {\n const stringed = toStringedProfile(profile, 'instrument');\n assertMidiPitch(pitch, 'pitch');\n return fingeringsIn(stringed, pitch);\n}\n\n/** {@link fingeringsFor} on a profile that has already been checked. */\nexport function fingeringsIn(stringed: ValidatedStringedProfile, pitch: number): StringFingering[] {\n const out: StringFingering[] = [];\n for (let string = 0; string < stringed.tuning.length; string += 1) {\n const open = stringed.tuning[string];\n if (open === undefined) {\n continue;\n }\n const fret = pitch - open;\n if (fret >= 0 && fret <= stringed.frets) {\n out.push({ string, fret });\n }\n }\n return out;\n}\n\n/**\n * Move a pitch by whole octaves until the instrument can sound it.\n *\n * This is what a player does with a line written below the instrument: the note\n * comes back an octave up, keeping its pitch class and its place in the phrase.\n * Substituting a different scale degree, or refusing the passage outright, is\n * the wrong answer for a bass line.\n *\n * @param pitch MIDI pitch to place.\n * @param profile The instrument.\n * @returns The nearest octave transposition the instrument sounds, taking the\n * upper one when two are equally near; the pitch unchanged when no\n * transposition of it is available.\n *\n * @example\n * ```ts\n * import { BASS_4_STRING, foldIntoRange } from '@libraz/libcantus';\n * foldIntoRange(27, BASS_4_STRING); // 39 — Eb1 is under the low E\n * ```\n * @category Core\n */\nexport function foldIntoRange(pitch: number, profile: InstrumentProfileLike): number {\n const resolved = toInstrumentProfile(profile, 'instrument');\n assertMidiPitch(pitch, 'pitch');\n return foldIn(pitch, resolved);\n}\n\n/** {@link foldIntoRange} on a profile that has already been checked. */\nexport function foldIn(pitch: number, resolved: ValidatedProfile): number {\n if (soundsIn(resolved, pitch)) {\n return pitch;\n }\n const { low, high } = rangeIn(resolved);\n // Every octave of the pitch that lies inside the instrument is weighed, and\n // the least distant of the ones it sounds wins: on a gapped range the octave\n // below can be nearer than the octave above, and answering with the first one\n // found upward would change the voice rather than the register. The walk\n // starts at the first octave inside the instrument rather than stepping up to\n // it one octave at a time, so a pitch far outside the range costs no loop.\n const first = pitch + 12 * Math.ceil((low - pitch) / 12);\n let best: number | undefined;\n for (let candidate = first; candidate <= high; candidate += 12) {\n if (!soundsIn(resolved, candidate)) {\n continue;\n }\n // Not strictly nearer: the candidates rise, so an equal distance means the\n // upper octave, which is the one a player reaches for.\n if (best === undefined || Math.abs(candidate - pitch) <= Math.abs(best - pitch)) {\n best = candidate;\n }\n }\n return best ?? pitch;\n}\n","import { canonicalNoteOrder, soundingIndices } from '../event-index/order.js';\nimport { BEAT_EPS } from '../meter/internal.js';\nimport type { NoteEvent } from '../types.js';\nimport { assertNoteEvents, assertRange } from '../validation/index.js';\nimport {\n fingeringsIn,\n type InstrumentProfileLike,\n type Limb,\n reachOf,\n type StringFingering,\n soundsIn,\n toInstrumentProfile,\n type ValidatedPercussionProfile,\n type ValidatedProfile,\n type ValidatedStringedProfile,\n} from './profile.js';\n\n/**\n * What makes a passage hard or impossible on an instrument.\n *\n * `noteOutOfRange` and `articulationUnavailable` belong to the first layer: the\n * instrument has no position for what was written. `stringConflict`,\n * `stretchTooWide`, `limbConflict` and `polyphonyExceeded` belong to the second:\n * the notes exist but the arrangement cannot be held or struck. `tooFast`\n * belongs to the third, the only one that depends on tempo.\n *\n * @category Core\n */\nexport type PlayabilityIssueType =\n | 'noteOutOfRange'\n | 'articulationUnavailable'\n | 'stringConflict'\n | 'stretchTooWide'\n | 'limbConflict'\n | 'polyphonyExceeded'\n | 'tooFast';\n\n/**\n * Which playability layer an issue belongs to: 1 the note does not exist, 2 the\n * arrangement does not hold together, 3 there is not enough time.\n *\n * @category Core\n */\nexport type PlayabilityLayer = 1 | 2 | 3;\n\n/**\n * One thing standing between a passage and a performance of it.\n *\n * @category Core\n */\nexport type PlayabilityIssue = {\n type: PlayabilityIssueType;\n layer: PlayabilityLayer;\n /** Indices into the analysed note array, ascending. */\n notes: readonly number[];\n /** Where the problem occurs, in quarter-note beats. */\n startBeat: number;\n /**\n * True when practice cannot fix it. Layers 1 and 2 depend on the instrument\n * alone, so they are impossible however skilled the player; only a layer-3\n * issue is a matter of degree.\n */\n impossible: boolean;\n message: string;\n};\n\n/**\n * How one note is actually produced: the string and fret it is stopped at, or\n * the limb that strikes it.\n *\n * This is reported for every note that has a position at all, whether or not\n * the passage raises issues, so a caller can apply its own standard rather than\n * take this module's.\n *\n * @category Core\n */\nexport type NotePlacement = {\n /** Index into the analysed note array. */\n note: number;\n /** String instruments: where the note is stopped. */\n fingering?: StringFingering;\n /** Percussion: which limb plays the stroke. */\n limb?: Limb;\n};\n\n/**\n * The verdict on a passage: how hard it is, what stands in the way, and how\n * each note would be produced.\n *\n * @category Core\n */\nexport type PlayabilityReport = {\n /**\n * Movement per unit time, mapped onto 1 (trivial) to 5 (at the limit).\n * Without a tempo the passage is measured at 120 BPM, so the number stays\n * comparable between passages; with one it rises as the tempo does.\n */\n difficulty: number;\n issues: PlayabilityIssue[];\n placements: NotePlacement[];\n};\n\n/** Tempo the difficulty is measured at when the caller gives none. */\nexport const REFERENCE_BPM = 120;\n/** Fastest the fretting hand shifts along the neck, in frets per second. */\nexport const MAX_FRET_SHIFT_PER_SECOND = 100;\n/** Shortest gap between two strokes of one limb, in seconds. */\nexport const MIN_LIMB_STROKE_SECONDS = 0.06;\n/** Movement rate, in units per second, that reads as a demanding passage. */\nexport const DIFFICULTY_SCALE = 12;\nexport const MIN_DIFFICULTY = 1;\nexport const MAX_DIFFICULTY = 5;\n/** Cost of crossing one string, relative to moving one fret. */\nexport const STRING_CROSSING_COST = 2;\n/** Onsets no further apart than this many beats count as simultaneous. */\nexport const SIMULTANEITY_BEATS = 1 / 128;\n/**\n * Longest overlap, in beats, of a note past a later onset that still releases\n * it: a sixty-fourth note, which covers a legato or humanized line overlapping\n * its successor without reading it as a note held under the next one.\n */\nexport const LEGATO_OVERLAP_BEATS = 1 / 16;\n\n/** Working state shared by both instrument families. */\ntype Analysis = {\n notes: readonly NoteEvent[];\n /** Note indices in onset order, ties broken by pitch. */\n order: number[];\n placements: NotePlacement[];\n issues: PlayabilityIssue[];\n /** Accumulated movement, in frets or strokes. */\n movement: number;\n /** Seconds per quarter-note beat, or undefined when no tempo was given. */\n secondsPerBeat: number | undefined;\n};\n\n/**\n * Judge whether a passage can be played on an instrument, and how hard it is.\n *\n * Inspection is deliberately separate from generation: this answers \"can this\n * be played\" for a chart handed to a player or a practice tool, and never\n * rewrites or rejects anything. The three layers are reported together but stay\n * distinct — an out-of-range note or an impossible stretch is not the bottom of\n * the difficulty scale but a different axis, since no amount of skill puts a\n * note on an instrument that does not have it. Only the third layer consults\n * `bpm`, so omitting the tempo reports what the instrument alone decides.\n *\n * @param notes The passage, in any order. Drum hits qualify as note events.\n * @param profile The instrument to play it on.\n * @param bpm Tempo in quarter-note beats per minute; enables the third layer.\n * @returns Difficulty, the issues found, and each note's string/fret or limb.\n * @throws If the notes are not note events, the tempo is not a finite positive\n * number of beats per minute, or the profile describes no instrument — a neck\n * with no strings or a kit no limb reaches, whatever the passage holds.\n *\n * @example\n * ```ts\n * import { BASS_4_STRING, playability } from '@libraz/libcantus';\n * const report = playability([{ pitch: 27, startBeat: 0, durationBeat: 1 }], BASS_4_STRING);\n * report.issues[0]?.type; // 'noteOutOfRange'\n * ```\n * @category Core\n */\nexport function playability(\n notes: readonly NoteEvent[],\n profile: InstrumentProfileLike,\n bpm?: number,\n): PlayabilityReport {\n assertNoteEvents(notes, 'playability notes', { allowNonPositiveDuration: true });\n if (bpm !== undefined) {\n assertRange(bpm, Number.MIN_VALUE, 1000, 'playability bpm');\n }\n // The profile is read once here, as every sibling in the module reads it\n // before answering: a contradictory instrument is refused whether or not the\n // passage happens to hold a note that would have exposed it.\n const instrument = toInstrumentProfile(profile, 'playability profile');\n\n const state: Analysis = {\n notes,\n order: canonicalNoteOrder(notes),\n placements: notes.map((_, index) => ({ note: index })),\n issues: [],\n movement: 0,\n secondsPerBeat: bpm === undefined ? undefined : 60 / bpm,\n };\n\n const attacks = timelineOf(state);\n if (instrument.kind === 'stringed') {\n checkExistence(state, instrument, (pitch) => soundsIn(instrument, pitch));\n placeOnNeck(state, instrument, attacks);\n } else {\n // The kit is read here rather than inside the note-by-note stages, which is\n // what makes the reading below a lookup: asking the profile per note walked\n // the reach table for every stroke of the track.\n const kit = readKit(instrument);\n checkExistence(state, instrument, (pitch) => limbsFor(kit, pitch).length > 0);\n placeOnKit(state, kit, attacks);\n }\n\n return {\n difficulty: difficultyOf(state, attacks, bpm),\n issues: state.issues,\n placements: state.placements,\n };\n}\n\n/**\n * Layer 1: the instrument has no position for the note, or no such technique.\n *\n * Whether the instrument has a pitch is asked through `sounds`, which the\n * caller has already read the instrument for: a kit answers out of the table it\n * built once, and reading the profile again per note is the cost this stage\n * used to carry.\n */\nfunction checkExistence(\n state: Analysis,\n profile: ValidatedProfile,\n sounds: (pitch: number) => boolean,\n): void {\n for (const index of state.order) {\n const note = state.notes[index];\n if (!note) {\n continue;\n }\n if (!sounds(note.pitch)) {\n state.issues.push({\n type: 'noteOutOfRange',\n layer: 1,\n notes: [index],\n startBeat: note.startBeat,\n impossible: true,\n message: `${profile.name} cannot sound MIDI ${note.pitch}`,\n });\n }\n // The note has been validated, so this names a technique the library knows:\n // the issue below says this instrument does not offer it, which is a fact\n // about the instrument rather than about the string that was written.\n const articulation = note.articulation;\n if (articulation !== undefined && !profile.articulations.includes(articulation)) {\n state.issues.push({\n type: 'articulationUnavailable',\n layer: 1,\n notes: [index],\n startBeat: note.startBeat,\n impossible: true,\n message: `${profile.name} cannot play ${articulation}`,\n });\n }\n }\n}\n\n/** One sounding note as every layer-2 and layer-3 check reads it. */\ntype TimedNote = {\n index: number;\n startBeat: number;\n endBeat: number;\n /** Onset of the attack the note is struck in. */\n attackBeat: number;\n};\n\n/** The sounding notes struck together, and the earlier ones still held under them. */\ntype Attack = {\n startBeat: number;\n /** The notes struck, by pitch and then by index. */\n members: TimedNote[];\n /** Notes of earlier attacks not yet released when this one lands. */\n held: TimedNote[];\n};\n\n/**\n * Whether a note ending at `endBeat` has let go by `beat`.\n *\n * A line played legato or humanized overlaps its successor by a few hundredths\n * of a beat; that overlap frees the string and the hand rather than holding the\n * note under the next one.\n */\nfunction isReleased(endBeat: number, beat: number): boolean {\n return endBeat <= beat + LEGATO_OVERLAP_BEATS + BEAT_EPS;\n}\n\n/**\n * The passage as a timeline of attacks, built once for every check.\n *\n * Silent notes are left out, since they strike nothing. Simultaneity is the\n * distance between two onsets, never the cell each of them rounds into: two\n * strokes a ten-thousandth of a beat apart are one attack wherever a fixed grid\n * would happen to cut between them, and a part played by hand lands on no grid.\n */\nfunction timelineOf(state: Analysis): Attack[] {\n const sounding = new Set(soundingIndices(state.notes));\n const attacks: Attack[] = [];\n let active: TimedNote[] = [];\n let current: Attack | undefined;\n for (const index of state.order) {\n const note = state.notes[index];\n if (!note || !sounding.has(index)) {\n continue;\n }\n if (!current || note.startBeat - current.startBeat > SIMULTANEITY_BEATS + BEAT_EPS) {\n const at = note.startBeat;\n active = active.filter((held) => !isReleased(held.endBeat, at));\n current = { startBeat: at, members: [], held: [...active] };\n attacks.push(current);\n }\n const timed: TimedNote = {\n index,\n startBeat: note.startBeat,\n endBeat: note.startBeat + note.durationBeat,\n attackBeat: current.startBeat,\n };\n current.members.push(timed);\n active.push(timed);\n }\n for (const attack of attacks) {\n attack.members.sort(\n (a, b) =>\n (state.notes[a.index]?.pitch ?? 0) - (state.notes[b.index]?.pitch ?? 0) ||\n a.index - b.index,\n );\n }\n return attacks;\n}\n\n/** Most notes of one attack that are placed jointly; a larger group keeps its greedy picks. */\nconst MAX_JOINT_PLACEMENT_NOTES = 12;\n/** Most search nodes spent on one attack before the best placement found so far stands. */\nconst MAX_PLACEMENT_SEARCH_NODES = 20000;\n\n/** One note of an attack waiting for a string. */\ntype NeckMember = TimedNote & { candidates: StringFingering[] };\n\n/** Whether the fretted notes of a hand fit one maxStretch. */\nfunction fitsHand(frets: readonly number[], maxStretch: number): boolean {\n let low = Number.POSITIVE_INFINITY;\n let high = Number.NEGATIVE_INFINITY;\n let count = 0;\n for (const fret of frets) {\n if (fret > 0) {\n low = Math.min(low, fret);\n high = Math.max(high, fret);\n count += 1;\n }\n }\n return count < 2 || high - low <= maxStretch;\n}\n\n/**\n * Each member takes the cheapest free string in turn; strings with no free one\n * are reported. `freeAt` is the beat each string is released at; a string taken\n * inside the attack stays taken until it ends.\n */\nfunction placeGreedily(\n members: readonly NeckMember[],\n previous: Origin,\n freeAt: readonly number[],\n heldBy: readonly (number | undefined)[],\n): { picks: StringFingering[]; conflicts: { member: NeckMember; blocked: number[] }[] } {\n const free = [...freeAt];\n const held = [...heldBy];\n const picks: StringFingering[] = [];\n const conflicts: { member: NeckMember; blocked: number[] }[] = [];\n let from = previous;\n for (const member of members) {\n const open = member.candidates.filter((candidate) =>\n isReleased(free[candidate.string] ?? Number.NEGATIVE_INFINITY, member.attackBeat),\n );\n if (open.length === 0) {\n conflicts.push({\n member,\n blocked: member.candidates\n .map((candidate) => held[candidate.string])\n .filter((value): value is number => value !== undefined),\n });\n }\n const pool = open.length > 0 ? open : member.candidates;\n const origin = from;\n const chosen = pool.reduce((best, candidate) =>\n fingeringCost(candidate, origin) < fingeringCost(best, origin) ? candidate : best,\n );\n picks.push(chosen);\n free[chosen.string] = Number.POSITIVE_INFINITY;\n held[chosen.string] = member.index;\n from = movedTo(from, chosen);\n }\n return { picks, conflicts };\n}\n\n/**\n * Cheapest assignment of the members to distinct free strings, found by a\n * bounded depth-first search; `undefined` when none exists within the budget.\n * With `heldFrets` the fretted span, held notes included, must fit `maxStretch`.\n */\nfunction searchPlacement(\n members: readonly NeckMember[],\n previous: Origin,\n freeAt: readonly number[],\n heldFrets: readonly number[] | undefined,\n maxStretch: number,\n): StringFingering[] | undefined {\n const free = [...freeAt];\n const frets = heldFrets === undefined ? undefined : [...heldFrets];\n const picks: StringFingering[] = [];\n let best: StringFingering[] | undefined;\n let bestCost = Number.POSITIVE_INFINITY;\n let nodes = 0;\n const visit = (depth: number, from: Origin, cost: number): void => {\n if (cost >= bestCost || nodes >= MAX_PLACEMENT_SEARCH_NODES) {\n return;\n }\n const member = members[depth];\n if (member === undefined) {\n best = [...picks];\n bestCost = cost;\n return;\n }\n for (const candidate of member.candidates) {\n const previousFree = free[candidate.string] ?? Number.NEGATIVE_INFINITY;\n if (!isReleased(previousFree, member.attackBeat)) {\n continue;\n }\n nodes += 1;\n if (frets !== undefined) {\n frets.push(candidate.fret);\n if (!fitsHand(frets, maxStretch)) {\n frets.pop();\n continue;\n }\n }\n free[candidate.string] = Number.POSITIVE_INFINITY;\n picks.push(candidate);\n visit(depth + 1, movedTo(from, candidate), cost + fingeringCost(candidate, from));\n picks.pop();\n free[candidate.string] = previousFree;\n if (frets !== undefined) {\n frets.pop();\n }\n }\n };\n visit(0, previous, 0);\n return best;\n}\n\n/**\n * Pick a string for each note of one attack.\n *\n * The greedy picks stand when they are free and fit the hand. Otherwise the\n * notes are placed jointly, so that a chord tone is not pushed up the neck by\n * the note below it taking an open string; the greedy picks, and the issues they\n * raise, remain only when no assignment exists.\n */\nfunction placeAttack(\n members: readonly NeckMember[],\n previous: Origin,\n freeAt: readonly number[],\n heldBy: readonly (number | undefined)[],\n heldFrets: readonly number[],\n maxStretch: number,\n): { picks: StringFingering[]; conflicts: { member: NeckMember; blocked: number[] }[] } {\n const greedy = placeGreedily(members, previous, freeAt, heldBy);\n const soundingFrets = [...heldFrets, ...greedy.picks.map((pick) => pick.fret)];\n if (greedy.conflicts.length === 0 && fitsHand(soundingFrets, maxStretch)) {\n return greedy;\n }\n if (members.length > MAX_JOINT_PLACEMENT_NOTES) {\n return greedy;\n }\n const fitted = searchPlacement(members, previous, freeAt, heldFrets, maxStretch);\n if (fitted !== undefined) {\n return { picks: fitted, conflicts: [] };\n }\n if (greedy.conflicts.length > 0) {\n const loose = searchPlacement(members, previous, freeAt, undefined, maxStretch);\n if (loose !== undefined) {\n return { picks: loose, conflicts: [] };\n }\n }\n return greedy;\n}\n\n/** Where the fretting hand stands: the last note stopped at a fret. */\ntype HandPosition = { note: TimedNote; fingering: StringFingering };\n\n/**\n * Layers 2 and 3 for a string instrument, and the fingering that goes with them.\n *\n * The fretting hand moves once per attack, between stopped notes: an open\n * string leaves it where it was, and the notes of one attack are one hand shape.\n */\nfunction placeOnNeck(\n state: Analysis,\n profile: ValidatedStringedProfile,\n attacks: readonly Attack[],\n): void {\n /** Beat each string is released at. */\n const stringFreeAt = profile.tuning.map(() => Number.NEGATIVE_INFINITY);\n /** Note currently holding each string. */\n const stringHeldBy = profile.tuning.map<number | undefined>(() => undefined);\n let origin: Origin = {};\n let hand: HandPosition | undefined;\n\n for (const attack of attacks) {\n const members: NeckMember[] = [];\n for (const timed of attack.members) {\n const note = state.notes[timed.index];\n const candidates = note === undefined ? [] : fingeringsIn(profile, note.pitch);\n if (candidates.length > 0) {\n members.push({ ...timed, candidates });\n }\n }\n const heldFrets = attack.held\n .map((held) => state.placements[held.index]?.fingering?.fret)\n .filter((fret): fret is number => fret !== undefined);\n const { picks, conflicts } = placeAttack(\n members,\n origin,\n stringFreeAt,\n stringHeldBy,\n heldFrets,\n profile.maxStretch,\n );\n let shifted = hand;\n members.forEach((member, k) => {\n const chosen = picks[k];\n const placement = state.placements[member.index];\n if (!chosen || !placement) {\n return;\n }\n const conflict = conflicts.find((entry) => entry.member === member);\n const note = state.notes[member.index];\n if (conflict && note) {\n state.issues.push({\n type: 'stringConflict',\n layer: 2,\n notes: [...new Set([...conflict.blocked, member.index])].sort((a, b) => a - b),\n startBeat: member.startBeat,\n impossible: true,\n message: `MIDI ${note.pitch} needs a string already sounding on ${profile.name}`,\n });\n }\n placement.fingering = chosen;\n stringFreeAt[chosen.string] = member.endBeat;\n stringHeldBy[chosen.string] = member.index;\n\n state.movement += 1;\n if (origin.string !== undefined) {\n state.movement += Math.abs(chosen.string - origin.string);\n }\n origin = movedTo(origin, chosen);\n if (chosen.fret > 0) {\n shifted = { note: member, fingering: chosen };\n }\n });\n if (hand && shifted && shifted !== hand) {\n state.movement += Math.abs(shifted.fingering.fret - hand.fingering.fret);\n checkShiftSpeed(state, profile, hand, shifted);\n }\n hand = shifted;\n }\n\n for (const attack of attacks) {\n checkStretch(state, profile, attack);\n checkPolyphony(state, profile, { startBeat: attack.startBeat, members: soundingAt(attack) });\n }\n}\n\n/**\n * Where the hands are before a note: the string last played, and the fret the\n * fretting hand last stopped. An open string moves the picking hand only.\n */\ntype Origin = { string?: number; fret?: number };\n\n/** The origin after playing `chosen`. */\nfunction movedTo(origin: Origin, chosen: StringFingering): Origin {\n return { string: chosen.string, fret: chosen.fret > 0 ? chosen.fret : origin.fret };\n}\n\n/** Cost of taking a position, counting a string crossing as several frets. */\nfunction fingeringCost(candidate: StringFingering, origin: Origin): number {\n // With no fret stopped yet, the low frets are the resting position; an open\n // string asks nothing of the fretting hand.\n const stopped =\n candidate.fret === 0\n ? 0\n : origin.fret === undefined\n ? candidate.fret\n : Math.abs(candidate.fret - origin.fret);\n const crossing =\n origin.string === undefined\n ? 0\n : STRING_CROSSING_COST * Math.abs(candidate.string - origin.string);\n return stopped + crossing + candidate.string / 100;\n}\n\n/** Layer 3: the fretting hand cannot travel that far between two attacks. */\nfunction checkShiftSpeed(\n state: Analysis,\n profile: ValidatedProfile,\n from: HandPosition,\n to: HandPosition,\n): void {\n const secondsPerBeat = state.secondsPerBeat;\n if (secondsPerBeat === undefined) {\n return;\n }\n const seconds = (to.note.attackBeat - from.note.attackBeat) * secondsPerBeat;\n const shift = Math.abs(to.fingering.fret - from.fingering.fret);\n if (seconds <= BEAT_EPS || shift === 0) {\n return;\n }\n if (shift / seconds > MAX_FRET_SHIFT_PER_SECOND) {\n state.issues.push({\n type: 'tooFast',\n layer: 3,\n notes: [from.note.index, to.note.index].sort((a, b) => a - b),\n startBeat: to.note.startBeat,\n impossible: false,\n message: `a ${shift}-fret shift in ${seconds.toFixed(3)}s is beyond ${profile.name}`,\n });\n }\n}\n\n/** Every note sounding once an attack has landed: the held ones and the struck ones. */\nfunction soundingAt(attack: Attack): number[] {\n return [...attack.held, ...attack.members].map((timed) => timed.index);\n}\n\n/** Layer 2: one hand cannot span that many frets at once. */\nfunction checkStretch(state: Analysis, profile: ValidatedStringedProfile, attack: Attack): void {\n const sounding = soundingAt(attack);\n const frets = sounding\n .map((member) => state.placements[member]?.fingering)\n .filter(\n (fingering): fingering is StringFingering => fingering !== undefined && fingering.fret > 0,\n )\n .map((fingering) => fingering.fret);\n if (frets.length < 2) {\n return;\n }\n const span = Math.max(...frets) - Math.min(...frets);\n if (span > profile.maxStretch) {\n state.issues.push({\n type: 'stretchTooWide',\n layer: 2,\n notes: sounding.sort((a, b) => a - b),\n startBeat: attack.startBeat,\n impossible: true,\n message: `a ${span}-fret stretch exceeds the ${profile.maxStretch} frets one hand spans on ${profile.name}`,\n });\n }\n}\n\n/** Layer 2: more notes sounding at once than the instrument has voices. */\nfunction checkPolyphony(\n state: Analysis,\n profile: ValidatedProfile,\n group: { startBeat: number; members: readonly number[] },\n): void {\n if (group.members.length <= profile.polyphony) {\n return;\n }\n state.issues.push({\n type: 'polyphonyExceeded',\n layer: 2,\n notes: [...group.members].sort((a, b) => a - b),\n startBeat: group.startBeat,\n impossible: true,\n message: `${group.members.length} notes sound at once; ${profile.name} has ${profile.polyphony}`,\n });\n}\n\n/** One take a percussion part is recorded on: the kit, or a voice dubbed over it. */\ntype KitPass = {\n /** Identity of the pass, so no two of them share a limb's history. */\n id: string;\n /** The notes struck on this pass at one attack. */\n members: TimedNote[];\n};\n\n/**\n * The kit a percussion part is read against.\n *\n * Which limbs can strike a voice, and whether a voice is dubbed over the kit,\n * are properties of the instrument rather than of the passage, so both are read\n * out of the profile once per call: asking the profile per stroke — inside a\n * sort comparator, at that — rebuilt the same answer for every note of the\n * track and allocated an array each time it did.\n */\ntype Kit = {\n profile: ValidatedPercussionProfile;\n /** Limbs the player has that reach each voice, in preference order. */\n limbs: ReadonlyMap<number, readonly Limb[]>;\n /** Voices played on a pass of their own. */\n overdub: ReadonlySet<number>;\n};\n\n/** No limb reaches a voice the kit does not name. */\nconst NO_LIMBS: readonly Limb[] = Object.freeze([]);\n\n/** Read a kit's limbs and overdubs out of the profile, once. */\nfunction readKit(profile: ValidatedPercussionProfile): Kit {\n const limbs = new Map<number, readonly Limb[]>();\n for (const key of Object.keys(profile.reach)) {\n const pitch = Number(key);\n limbs.set(pitch, reachOf(profile, pitch));\n }\n return { profile, limbs, overdub: new Set(profile.overdub ?? []) };\n}\n\n/** The limbs that can strike a voice, or none for a note that is not there. */\nfunction limbsFor(kit: Kit, pitch: number | undefined): readonly Limb[] {\n if (pitch === undefined) {\n return NO_LIMBS;\n }\n return kit.limbs.get(pitch) ?? NO_LIMBS;\n}\n\n/** What the limbs were last doing, carried from one onset to the next. */\ntype KitMemory = {\n /** Limb that last struck each voice, so a voice keeps its stick. */\n limbForVoice: Map<number, Limb>;\n /** Last stroke of each limb on each pass. */\n lastStroke: Map<string, TimedNote>;\n};\n\n/**\n * The passes one onset is played on.\n *\n * A percussion part is a kit performance with voices dubbed over it, and each\n * overdubbed voice is its own take: it takes no limb from the kit and none from\n * another overdub. That is what lets a tambourine sound on a backbeat where a\n * snare is already in one hand and a hi-hat in the other — a player does not\n * grow a third arm for it, the part is recorded twice.\n */\nfunction passesAt(state: Analysis, kit: Kit, members: readonly TimedNote[]): KitPass[] {\n const played: KitPass = { id: 'kit', members: [] };\n const overdubs = new Map<number, KitPass>();\n for (const member of members) {\n const pitch = state.notes[member.index]?.pitch;\n if (pitch === undefined || !kit.overdub.has(pitch)) {\n played.members.push(member);\n continue;\n }\n let pass = overdubs.get(pitch);\n if (!pass) {\n pass = { id: `overdub ${pitch}`, members: [] };\n overdubs.set(pitch, pass);\n }\n pass.members.push(member);\n }\n return [played, ...overdubs.values()];\n}\n\n/**\n * Hand every stroke of one pass to a limb, at one onset.\n *\n * @returns True when the pass wants more limbs at once than it has.\n */\nfunction placePass(state: Analysis, kit: Kit, pass: KitPass, memory: KitMemory): boolean {\n const taken = new Set<Limb>();\n let conflicted = false;\n // The most constrained voice picks first: a kick only the right foot\n // reaches must not lose it to a snare that either hand could have taken.\n const members = [...pass.members].sort((a, b) => {\n const left = limbsFor(kit, state.notes[a.index]?.pitch);\n const right = limbsFor(kit, state.notes[b.index]?.pitch);\n return left.length - right.length || a.index - b.index;\n });\n for (const member of members) {\n const note = state.notes[member.index];\n const placement = state.placements[member.index];\n if (!note || !placement) {\n continue;\n }\n const candidates = limbsFor(kit, note.pitch);\n if (candidates.length === 0) {\n continue;\n }\n const preferred = memory.limbForVoice.get(note.pitch);\n const free = candidates.filter((limb) => !taken.has(limb));\n const chosen =\n free.length === 0\n ? candidates[0]\n : preferred !== undefined && free.includes(preferred)\n ? preferred\n : free[0];\n if (free.length === 0) {\n conflicted = true;\n }\n if (chosen === undefined) {\n continue;\n }\n taken.add(chosen);\n placement.limb = chosen;\n memory.limbForVoice.set(note.pitch, chosen);\n\n state.movement += 1;\n const strokeKey = `${pass.id} ${chosen}`;\n const previousStroke = memory.lastStroke.get(strokeKey);\n if (previousStroke !== undefined) {\n const previousNote = state.notes[previousStroke.index];\n if (previousNote && previousNote.pitch !== note.pitch) {\n // The limb had to travel across the kit rather than repeat a voice.\n state.movement += 1;\n }\n checkStrokeSpeed(state, kit.profile, previousStroke, member, chosen);\n }\n memory.lastStroke.set(strokeKey, member);\n }\n return conflicted;\n}\n\n/** Layers 2 and 3 for a kit, and the limb assignment that goes with them. */\nfunction placeOnKit(state: Analysis, kit: Kit, attacks: readonly Attack[]): void {\n const memory: KitMemory = { limbForVoice: new Map(), lastStroke: new Map() };\n\n for (const attack of attacks) {\n const strokes = attack.members.map((member) => member.index);\n let conflicted = false;\n for (const pass of passesAt(state, kit, attack.members)) {\n if (!placePass(state, kit, pass, memory)) {\n continue;\n }\n conflicted = true;\n state.issues.push({\n type: 'limbConflict',\n layer: 2,\n notes: pass.members.map((member) => member.index).sort((a, b) => a - b),\n startBeat: attack.startBeat,\n impossible: true,\n message: `${pass.members.length} simultaneous strokes cannot be shared among the limbs of ${kit.profile.name}`,\n });\n }\n if (!conflicted) {\n checkPolyphony(state, kit.profile, { startBeat: attack.startBeat, members: strokes });\n }\n }\n}\n\n/** Layer 3: one limb cannot strike twice that close together. */\nfunction checkStrokeSpeed(\n state: Analysis,\n profile: ValidatedProfile,\n from: TimedNote,\n to: TimedNote,\n limb: Limb,\n): void {\n const secondsPerBeat = state.secondsPerBeat;\n if (secondsPerBeat === undefined) {\n return;\n }\n const seconds = (to.attackBeat - from.attackBeat) * secondsPerBeat;\n if (seconds <= BEAT_EPS || seconds >= MIN_LIMB_STROKE_SECONDS) {\n return;\n }\n state.issues.push({\n type: 'tooFast',\n layer: 3,\n notes: [from.index, to.index].sort((a, b) => a - b),\n startBeat: to.startBeat,\n impossible: false,\n message: `${limb} strikes twice ${seconds.toFixed(3)}s apart on ${profile.name}`,\n });\n}\n\n/**\n * Movement per unit time, on a 1..5 scale.\n *\n * The rate is what a passage demands of the player: strokes and shifts divided\n * by the seconds available for them. It is mapped through a saturating curve so\n * the scale has a fixed top a ceiling can be compared against — a faster tempo\n * over the same notes never reads easier, and 5 is reached only where the\n * passage has already left what the instrument allows.\n */\nfunction difficultyOf(\n state: Analysis,\n attacks: readonly Attack[],\n bpm: number | undefined,\n): number {\n let first = Number.POSITIVE_INFINITY;\n let last = Number.NEGATIVE_INFINITY;\n for (const attack of attacks) {\n for (const member of attack.members) {\n first = Math.min(first, member.startBeat);\n last = Math.max(last, member.endBeat);\n }\n }\n const spanBeats = last - first;\n if (!Number.isFinite(spanBeats) || spanBeats <= BEAT_EPS) {\n return MIN_DIFFICULTY;\n }\n const seconds = (spanBeats * 60) / (bpm ?? REFERENCE_BPM);\n const rate = state.movement / seconds;\n const scaled =\n MIN_DIFFICULTY + (MAX_DIFFICULTY - MIN_DIFFICULTY) * (1 - Math.exp(-rate / DIFFICULTY_SCALE));\n return Math.round(scaled * 1e4) / 1e4;\n}\n","import type { Articulation } from './articulation.js';\nimport type { StringedProfile } from './profile.js';\n\n/** Techniques common to every fretted string instrument here. */\nconst STRINGED_ARTICULATIONS: readonly Articulation[] = Object.freeze([\n 'accent',\n 'ghost',\n 'staccato',\n 'legato',\n 'slide',\n 'hammer',\n 'mute',\n 'open',\n] as const);\n\n/**\n * Electric bass in standard tuning: E1 A1 D2 G2 over a 24-fret neck.\n *\n * @category Core\n */\nexport const BASS_4_STRING: StringedProfile = Object.freeze({\n kind: 'stringed',\n name: '4-string bass',\n tuning: Object.freeze([28, 33, 38, 43]),\n frets: 24,\n maxStretch: 4,\n articulations: STRINGED_ARTICULATIONS,\n polyphony: 4,\n});\n\n/**\n * Five-string bass with the low B: B0 E1 A1 D2 G2.\n *\n * @category Core\n */\nexport const BASS_5_STRING: StringedProfile = Object.freeze({\n kind: 'stringed',\n name: '5-string bass',\n tuning: Object.freeze([23, 28, 33, 38, 43]),\n frets: 24,\n maxStretch: 4,\n articulations: STRINGED_ARTICULATIONS,\n polyphony: 5,\n});\n\n/**\n * Six-string guitar in standard tuning: E2 A2 D3 G3 B3 E4.\n *\n * @category Core\n */\nexport const GUITAR_STANDARD: StringedProfile = Object.freeze({\n kind: 'stringed',\n name: 'guitar',\n tuning: Object.freeze([40, 45, 50, 55, 59, 64]),\n frets: 24,\n maxStretch: 5,\n articulations: STRINGED_ARTICULATIONS,\n polyphony: 6,\n});\n\n/**\n * Six-string guitar in drop D: the lowest string down a tone to D2, the rest\n * standard. Only the tuning differs, which is the whole point of deriving the\n * range from it.\n *\n * @category Core\n */\nexport const GUITAR_DROP_D: StringedProfile = Object.freeze({\n kind: 'stringed',\n name: 'guitar (drop D)',\n tuning: Object.freeze([38, 45, 50, 55, 59, 64]),\n frets: 24,\n maxStretch: 5,\n articulations: STRINGED_ARTICULATIONS,\n polyphony: 6,\n});\n","/**\n * The hash behind hierarchical seeds and position-addressed draws.\n *\n * Both public entry points reduce a root seed plus a path to one 32-bit word,\n * so the mixing lives here once. The construction is FNV-1a (32-bit) over a\n * type-tagged byte encoding of the path, finished with the MurmurHash3 fmix32\n * avalanche step: FNV-1a alone leaves neighbouring inputs — `'drums'` against\n * `'drum'`, bar 1 against bar 2 — differing in only a few bits, and fmix32\n * spreads a one-bit input difference across the whole word so sibling paths\n * behave as unrelated seeds.\n *\n * Nothing here reads the platform: only code units, IEEE 754 bytes and 32-bit\n * integer arithmetic, so the same path yields the same word in every runtime\n * and every locale.\n */\n\nimport { InvalidInputError } from '../errors/index.js';\nimport { assertFiniteNumber } from '../validation/index.js';\n\n/** Number of distinct values a 32-bit word takes; the divisor for a unit float. */\nexport const UINT32_RANGE = 4294967296;\n\n/** FNV-1a 32-bit offset basis. */\nexport const FNV_OFFSET_BASIS = 0x811c9dc5;\n\n/** FNV-1a 32-bit prime. */\nexport const FNV_PRIME = 0x01000193;\n\n/**\n * Keyspace a hash belongs to.\n *\n * Derived seeds and positional draws are asked for at the same paths, so they\n * are hashed under different tags; without that, `at(...path)` would be the\n * unit-scaled `deriveSeed(seed, ...path)` and a generator using both at one\n * position would draw the same number twice.\n */\nexport const DOMAIN_SEED = 0x01;\nexport const DOMAIN_POSITION = 0x02;\n\n/** Segment tags, so `'3'` and `3` never encode to the same bytes. */\nexport const TAG_STRING = 0x01;\nexport const TAG_NUMBER = 0x02;\n\n/**\n * Scratch view for the IEEE 754 encoding of a numeric segment.\n *\n * Written and read within a single synchronous call, so the reuse is not\n * observable; it keeps the hot path — one draw per bar, beat and voice — free\n * of per-call allocation.\n */\nconst numberBytes = new DataView(new ArrayBuffer(8));\n\n/** Absorb one byte into a running FNV-1a hash. */\nfunction absorb(hash: number, byte: number): number {\n return Math.imul(hash ^ (byte & 0xff), FNV_PRIME) >>> 0;\n}\n\n/** Absorb a 32-bit word, least significant byte first. */\nfunction absorbUint32(hash: number, value: number): number {\n let next = hash;\n for (let shift = 0; shift < 32; shift += 8) {\n next = absorb(next, (value >>> shift) & 0xff);\n }\n return next;\n}\n\n/**\n * MurmurHash3 32-bit finalizer.\n *\n * @param value The accumulated hash.\n * @returns The avalanched word.\n */\nfunction fmix32(value: number): number {\n let mixed = value >>> 0;\n mixed ^= mixed >>> 16;\n mixed = Math.imul(mixed, 0x85ebca6b);\n mixed ^= mixed >>> 13;\n mixed = Math.imul(mixed, 0xc2b2ae35);\n mixed ^= mixed >>> 16;\n return mixed >>> 0;\n}\n\n/**\n * Absorb one path segment, tagged and length-prefixed.\n *\n * The length prefix is what keeps `['ab', 'c']` apart from `['a', 'bc']`: a\n * plain separator byte could itself appear inside a segment.\n */\nfunction absorbSegment(hash: number, segment: string | number, index: number): number {\n if (typeof segment === 'string') {\n let next = absorb(hash, TAG_STRING);\n next = absorbUint32(next, segment.length);\n for (let i = 0; i < segment.length; i += 1) {\n // UTF-16 code units, low byte first: a fixed encoding of the string,\n // with no case folding or normalisation that a locale could steer.\n const unit = segment.charCodeAt(i);\n next = absorb(next, unit & 0xff);\n next = absorb(next, (unit >>> 8) & 0xff);\n }\n return next;\n }\n if (typeof segment === 'number') {\n // A path segment that is not a number at all would otherwise hash as one\n // fixed word (NaN) or two (the infinities), aliasing unrelated positions.\n assertFiniteNumber(segment, `seed path segment ${index}`);\n // Negative zero carries different bytes from zero while comparing equal,\n // which would make two paths a caller reads as identical derive apart.\n numberBytes.setFloat64(0, segment === 0 ? 0 : segment, true);\n let next = absorb(hash, TAG_NUMBER);\n for (let i = 0; i < 8; i += 1) {\n next = absorb(next, numberBytes.getUint8(i));\n }\n return next;\n }\n throw new InvalidInputError(\n `seed path segment ${index} must be a string or a number; received ${typeof segment}`,\n );\n}\n\n/**\n * Hash a root seed and a path to a 32-bit word within one keyspace.\n *\n * @param domain The keyspace tag.\n * @param root The validated root seed.\n * @param path The path segments.\n * @returns The mixed word in `[0, 0xffffffff]`.\n */\nexport function hashPath(domain: number, root: number, path: readonly (string | number)[]): number {\n let hash = absorb(FNV_OFFSET_BASIS, domain);\n hash = absorbUint32(hash, root);\n for (let index = 0; index < path.length; index += 1) {\n const segment = path[index];\n if (segment === undefined) {\n throw new InvalidInputError(\n `seed path segment ${index} must be a string or a number; received undefined`,\n );\n }\n hash = absorbSegment(hash, segment, index);\n }\n return fmix32(hash);\n}\n\n/** Scratch view for stepping a double to its neighbour below. */\nconst stepBytes = new DataView(new ArrayBuffer(8));\n\n/**\n * A unit draw scaled into [lo, hi).\n *\n * `lo + unit * (hi - lo)` rounds up to `hi` when the span is narrow against the\n * magnitude of its ends, so a result at `hi` is pulled back to the largest\n * double below it. An empty range, `lo === hi`, answers `lo`.\n */\nexport function scaleUnitDraw(unit: number, lo: number, hi: number): number {\n const value = lo + unit * (hi - lo);\n if (value < hi || lo === hi) {\n return value;\n }\n if (hi === 0) {\n return -Number.MIN_VALUE;\n }\n stepBytes.setFloat64(0, hi);\n const bits = stepBytes.getBigUint64(0);\n stepBytes.setBigUint64(0, hi > 0 ? bits - 1n : bits + 1n);\n return stepBytes.getFloat64(0);\n}\n","/**\n * Position-addressed randomness and threshold sampling.\n *\n * Drawing in call order makes a generator's output depend on how many draws\n * preceded it, so editing a parameter in the middle of a piece redraws\n * everything after it. Addressing each draw by where it happens — bar, beat,\n * voice — removes that coupling: the value at a position depends on the\n * position alone, so a change anywhere leaves every other position as it was.\n *\n * Deciding inclusion by comparing a fixed positional draw against a complexity\n * dial gives the property a slider needs: raising the dial only adds events,\n * and everything already sounding stays where it was.\n */\n\nimport { InvalidInputError } from '../errors/index.js';\nimport { assertInteger, assertRange } from '../validation/index.js';\nimport { DOMAIN_POSITION, hashPath, UINT32_RANGE } from './internal.js';\nimport type { SeedPath } from './seed.js';\n\n/**\n * A random source addressed by position rather than by call order.\n *\n * @category Utilities\n */\nexport type PositionalRng = {\n /**\n * The draw belonging to a position: a float in [0, 1) that depends only on\n * the seed and the path, so it is the same however often and in whatever\n * order it is asked for.\n */\n at: (...path: SeedPath) => number;\n};\n\n/**\n * Create a position-addressed random source.\n *\n * `at` holds no cursor: it is a pure function of the seed and the path, safe to\n * call in any order, any number of times, from anywhere in a generator. Its\n * draws are independent of {@link deriveSeed} at the same path, so a generator\n * may seed a sub-part and take a positional draw at one position without\n * getting the same number twice.\n *\n * @param seed The seed; an integer in 0..0xffffffff, typically from\n * {@link deriveSeed}.\n * @returns The positional source.\n * @throws If the seed is not a 32-bit integer.\n * @example\n * ```ts\n * import { createPositionalRng, deriveSeed } from '@libraz/libcantus';\n * const rng = createPositionalRng(deriveSeed(42, 'drums'));\n * rng.at('ghost', 4, 2.5); // the same value however often it is asked for\n * ```\n * @category Utilities\n */\nexport function createPositionalRng(seed: number): PositionalRng {\n assertInteger(seed, 'seed', 0, 0xffffffff);\n return {\n at: (...path: SeedPath) => hashPath(DOMAIN_POSITION, seed, path) / UINT32_RANGE,\n };\n}\n\n/**\n * Whether the event at a position belongs in the output at a given complexity.\n *\n * The test is `at(...path) < complexity`, and because the draw is fixed by the\n * position, the selected set grows monotonically with complexity: for any\n * `c1 < c2` the events at `c1` are a subset of the events at `c2` over the same\n * seed and the same path space. Complexity 0 selects nothing and complexity 1\n * selects everything.\n *\n * @param rng The positional source; may be a caller-supplied one.\n * @param complexity The dial, in [0, 1].\n * @param path The position to test.\n * @returns True when the position is included.\n * @throws If the complexity is outside [0, 1], or the source returns a value\n * outside [0, 1).\n * @example\n * ```ts\n * import { createPositionalRng, includeAt } from '@libraz/libcantus';\n * const rng = createPositionalRng(7);\n * includeAt(rng, 0.3, 'ghost', 4, 2.5); // raising 0.3 only adds hits\n * ```\n * @category Utilities\n */\nexport function includeAt(rng: PositionalRng, complexity: number, ...path: SeedPath): boolean {\n assertRange(complexity, 0, 1, 'complexity');\n const draw = rng.at(...path);\n // A substituted source is part of the contract, and one that returns 1, a\n // negative value or NaN would quietly break monotonicity rather than fail.\n if (!(draw >= 0 && draw < 1)) {\n throw new InvalidInputError(`positional draw must be in [0, 1); received ${draw}`);\n }\n return draw < complexity;\n}\n","/**\n * Hierarchical seeds: one project number that addresses every part.\n *\n * A flat seed per generator makes the caller keep a table of numbers and,\n * worse, makes \"reroll the drums\" mean \"pick a number nobody else is using\".\n * Deriving instead — `deriveSeed(project, 'drums', 'chorus', 2)` — turns a\n * reroll into an extra path segment, and every other part keeps the seed it\n * had because its path did not change.\n */\n\nimport { assertInteger } from '../validation/index.js';\nimport { DOMAIN_SEED, hashPath } from './internal.js';\n\n/**\n * The address of one derivation: a namespace, and whatever names or indices\n * locate the thing being seeded.\n *\n * Strings and numbers are kept apart by the hash, so `'3'` and `3` address\n * different things, as do `['ab', 'c']` and `['a', 'bc']`.\n *\n * @category Utilities\n */\nexport type SeedPath = readonly (string | number)[];\n\n/**\n * Derive a child seed from a root seed and a path.\n *\n * The result is a 32-bit integer, so it can be passed straight to\n * {@link createRng}. Derivation is a pure function of its arguments — the same\n * root and path give the same seed in every runtime — and near-identical paths\n * (`'drums'` against `'drum'`, bar 1 against bar 2) give unrelated seeds: the\n * path is hashed with FNV-1a and finished with the MurmurHash3 fmix32\n * avalanche step.\n *\n * @param root The project seed; an integer in 0..0xffffffff.\n * @param path The address to derive at; string or finite number segments.\n * @returns The derived seed, an integer in 0..0xffffffff.\n * @throws If the root is not a 32-bit integer, or a segment is neither a\n * string nor a finite number.\n * @example\n * ```ts\n * import { createRng, deriveSeed } from '@libraz/libcantus';\n * const drums = deriveSeed(42, 'drums', 'chorus', 3);\n * const rng = createRng(drums); // rerolling only the drums: bump the 3\n * ```\n * @category Utilities\n */\nexport function deriveSeed(root: number, ...path: SeedPath): number {\n // The root is held to the seed range createRng accepts, so a derived seed is\n // always a legal root for a further derivation.\n assertInteger(root, 'root seed', 0, 0xffffffff);\n return hashPath(DOMAIN_SEED, root, path);\n}\n","/**\n * How generated output is pinned across builds.\n *\n * A saved project is a seed plus parameters, and it reopens as the same piece\n * only while the library turns them into the same notes. The algorithm version\n * is the number that says which reading of those parameters a project was\n * written against. It is drawn into every seed, so two versions never draw the\n * same stream, and a caller records it beside the seed.\n */\n\nimport { InvalidInputError } from '../errors/index.js';\nimport { assertInteger } from '../validation/index.js';\n\n/**\n * The generator algorithm version this build produces by default.\n *\n * What it carries: for a fixed algorithm version, the same inputs — seed,\n * version and every documented parameter — produce the same generated output\n * from a given build. It covers what the generators return, and nothing else:\n * analysis results, error messages and output taken under a different version\n * are outside it.\n *\n * What it does not carry is a reading frozen against correction. The\n * generators hold one implementation rather than one per version, so pinning\n * an older number selects a different draw of the current implementation and\n * does not restore what that number produced before: a fix to output that was\n * musically wrong moves the notes of a version already in use, ships as a\n * patch, and is stated in the changelog. Reproducing a piece exactly therefore\n * means recording the package version alongside the seed and this number.\n *\n * Raising this constant marks a deliberate change of approach rather than a\n * correction. A project pinned to a version this build does not know is\n * rejected rather than reinterpreted.\n *\n * @category Utilities\n */\nexport const ALGORITHM_VERSION = 1;\n\n/**\n * The oldest algorithm version this build still accepts.\n *\n * @category Utilities\n */\nexport const MIN_ALGORITHM_VERSION = 1;\n\n/**\n * Resolve the algorithm version a request runs under.\n *\n * An unpinned request runs at {@link ALGORITHM_VERSION}, which is what a\n * caller who wants the current behaviour means; a caller who wants the piece\n * back records the resolved number and passes it next time. A version this\n * build does not produce is rejected — a project saved by a newer build cannot\n * be reproduced by an older one, and quietly rendering it at another version\n * would return a different piece under the same name.\n *\n * @param requested The pinned version, or undefined for the current one.\n * @returns The version to generate under.\n * @throws If the version is not an integer this build produces.\n * @example\n * ```ts\n * import { ALGORITHM_VERSION, resolveAlgorithmVersion } from '@libraz/libcantus';\n * resolveAlgorithmVersion(undefined); // ALGORITHM_VERSION\n * resolveAlgorithmVersion(ALGORITHM_VERSION); // the pinned value, unchanged\n * ```\n * @category Utilities\n */\nexport function resolveAlgorithmVersion(requested?: number): number {\n if (requested === undefined) {\n return ALGORITHM_VERSION;\n }\n assertInteger(requested, 'algorithm version');\n if (requested < MIN_ALGORITHM_VERSION || requested > ALGORITHM_VERSION) {\n throw new InvalidInputError(\n `algorithm version ${requested} is not produced by this build; supported versions are ` +\n `${MIN_ALGORITHM_VERSION}..${ALGORITHM_VERSION}`,\n );\n }\n return requested;\n}\n","/**\n * Deterministic seeded pseudo-random number generation shared across the\n * generative modules (rhythm, drums, bass, groove, counter-melody). A single\n * mulberry32 core exposes the small set of samplers those modules need; given a\n * seed the stream is fully reproducible.\n *\n * Around that core sit the pieces that make a whole project reproducible: seeds\n * derived hierarchically from one project number, draws addressed by position\n * rather than by call order, and the algorithm version the output is pinned to.\n */\n\nimport { InvalidInputError } from '../errors/index.js';\nimport { assertFiniteNumber, assertInteger, assertRange } from '../validation/index.js';\nimport { scaleUnitDraw } from './internal.js';\n\nexport type { PositionalRng } from './positional.js';\nexport { createPositionalRng, includeAt } from './positional.js';\nexport type { SeedPath } from './seed.js';\nexport { deriveSeed } from './seed.js';\nexport { ALGORITHM_VERSION, MIN_ALGORITHM_VERSION, resolveAlgorithmVersion } from './version.js';\n\n/**\n * A deterministic PRNG with the sampling helpers the generators need.\n *\n * @category Utilities\n */\nexport type Rng = {\n /** Next float in [0, 1). */\n next: () => number;\n /** True with probability `p`. */\n prob: (p: number) => boolean;\n /** Integer in the inclusive range [lo, hi]. */\n range: (lo: number, hi: number) => number;\n /** Float in [lo, hi). */\n float: (lo: number, hi: number) => number;\n};\n\n/**\n * Create a seeded PRNG (mulberry32) exposing the shared samplers.\n *\n * @param seed The 32-bit seed; the same seed always yields the same stream.\n * @returns The seeded generator.\n * @example\n * ```ts\n * import { createRng } from '@libraz/libcantus';\n * const rng = createRng(42);\n * rng.next(); // deterministic float in [0, 1)\n * rng.range(1, 6); // deterministic integer in [1, 6]\n * ```\n * @category Utilities\n */\nexport function createRng(seed: number): Rng {\n // The state is 32 bits, so a wider or fractional seed would be truncated —\n // silently mapping distinct seeds onto one sequence.\n assertInteger(seed, 'seed', 0, 0xffffffff);\n let state = seed >>> 0;\n const next = () => {\n state = (state + 0x6d2b79f5) >>> 0;\n let t = state;\n t = Math.imul(t ^ (t >>> 15), t | 1);\n t ^= t + Math.imul(t ^ (t >>> 7), t | 61);\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296;\n };\n return {\n next,\n prob: (p) => {\n // Validate first: a draw consumed by a rejected call shifts the stream,\n // so a caller who catches the error gets a different sequence than one\n // who never made the call.\n assertRange(p, 0, 1, 'probability');\n return next() < p;\n },\n range: (lo, hi) => {\n assertInteger(lo, 'range lower bound');\n assertInteger(hi, 'range upper bound');\n if (lo > hi) {\n throw new InvalidInputError(\n `range lower bound must not exceed upper bound; received ${lo} > ${hi}`,\n );\n }\n assertInteger(hi - lo, 'range span', 0);\n return lo + Math.floor(next() * (hi - lo + 1));\n },\n float: (lo, hi) => {\n assertFiniteNumber(lo, 'float lower bound');\n assertFiniteNumber(hi, 'float upper bound');\n if (lo > hi) {\n throw new InvalidInputError(\n `float lower bound must not exceed upper bound; received ${lo} > ${hi}`,\n );\n }\n assertFiniteNumber(hi - lo, 'float span');\n return scaleUnitDraw(next(), lo, hi);\n },\n };\n}\n"],"mappings":"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","names":["low","high"]}