@libraz/libcantus 0.9.4 → 1.0.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 (186) hide show
  1. package/README.md +61 -261
  2. package/README_ja.md +115 -0
  3. package/dist/analyze/index.cjs +54 -7
  4. package/dist/analyze/index.cjs.map +1 -1
  5. package/dist/analyze/index.d.cts +213 -456
  6. package/dist/analyze/index.d.ts +213 -456
  7. package/dist/analyze/index.js +56 -9
  8. package/dist/chunk-3JXCW6DX.cjs +3220 -0
  9. package/dist/chunk-3JXCW6DX.cjs.map +1 -0
  10. package/dist/chunk-4A2RMUCC.js +7647 -0
  11. package/dist/chunk-4A2RMUCC.js.map +1 -0
  12. package/dist/chunk-6XPTBE7Y.cjs +49 -0
  13. package/dist/chunk-6XPTBE7Y.cjs.map +1 -0
  14. package/dist/chunk-AFM2ULJH.cjs +5121 -0
  15. package/dist/chunk-AFM2ULJH.cjs.map +1 -0
  16. package/dist/chunk-E3F4AHAH.cjs +690 -0
  17. package/dist/chunk-E3F4AHAH.cjs.map +1 -0
  18. package/dist/chunk-ELCTZUJJ.js +379 -0
  19. package/dist/chunk-ELCTZUJJ.js.map +1 -0
  20. package/dist/chunk-FVSI36UV.js +690 -0
  21. package/dist/chunk-FVSI36UV.js.map +1 -0
  22. package/dist/chunk-GEDTJHAC.cjs +1 -0
  23. package/dist/chunk-GEDTJHAC.cjs.map +1 -0
  24. package/dist/chunk-GOZG57ER.js +3220 -0
  25. package/dist/chunk-GOZG57ER.js.map +1 -0
  26. package/dist/chunk-H3VORETI.js +2243 -0
  27. package/dist/chunk-H3VORETI.js.map +1 -0
  28. package/dist/chunk-H42UHPYW.js +1577 -0
  29. package/dist/chunk-H42UHPYW.js.map +1 -0
  30. package/dist/chunk-HFPS7JFD.js +1 -0
  31. package/dist/chunk-INHVXP6Z.js +3053 -0
  32. package/dist/chunk-INHVXP6Z.js.map +1 -0
  33. package/dist/chunk-K4ZJUGF4.cjs +379 -0
  34. package/dist/chunk-K4ZJUGF4.cjs.map +1 -0
  35. package/dist/chunk-KNJEKLKV.js +49 -0
  36. package/dist/chunk-KNJEKLKV.js.map +1 -0
  37. package/dist/chunk-M4CWTJWJ.cjs +7647 -0
  38. package/dist/chunk-M4CWTJWJ.cjs.map +1 -0
  39. package/dist/chunk-MXO72PLY.cjs +211 -0
  40. package/dist/chunk-MXO72PLY.cjs.map +1 -0
  41. package/dist/chunk-NLEU4QSE.cjs +360 -0
  42. package/dist/chunk-NLEU4QSE.cjs.map +1 -0
  43. package/dist/chunk-OE6WK2Y2.cjs +1577 -0
  44. package/dist/chunk-OE6WK2Y2.cjs.map +1 -0
  45. package/dist/chunk-Q2WGKJNN.cjs +1064 -0
  46. package/dist/chunk-Q2WGKJNN.cjs.map +1 -0
  47. package/dist/chunk-QYQQ5J6E.js +1 -0
  48. package/dist/chunk-QYQQ5J6E.js.map +1 -0
  49. package/dist/chunk-RHIJ3S4I.cjs +1 -0
  50. package/dist/chunk-RHIJ3S4I.cjs.map +1 -0
  51. package/dist/chunk-TTCLJX6D.js +211 -0
  52. package/dist/chunk-TTCLJX6D.js.map +1 -0
  53. package/dist/chunk-UADYAYAT.cjs +3053 -0
  54. package/dist/chunk-UADYAYAT.cjs.map +1 -0
  55. package/dist/chunk-VOHZB45S.js +5121 -0
  56. package/dist/chunk-VOHZB45S.js.map +1 -0
  57. package/dist/chunk-VTI6FOLB.js +1064 -0
  58. package/dist/chunk-VTI6FOLB.js.map +1 -0
  59. package/dist/chunk-WWURE4XT.cjs +2243 -0
  60. package/dist/chunk-WWURE4XT.cjs.map +1 -0
  61. package/dist/chunk-YH3BIKHH.js +360 -0
  62. package/dist/chunk-YH3BIKHH.js.map +1 -0
  63. package/dist/core/index.cjs +103 -6
  64. package/dist/core/index.cjs.map +1 -1
  65. package/dist/core/index.d.cts +96 -345
  66. package/dist/core/index.d.ts +96 -345
  67. package/dist/core/index.js +104 -7
  68. package/dist/generate/index.cjs +89 -10
  69. package/dist/generate/index.cjs.map +1 -1
  70. package/dist/generate/index.d.cts +437 -1095
  71. package/dist/generate/index.d.ts +437 -1095
  72. package/dist/generate/index.js +94 -15
  73. package/dist/index-9wcMhG73.d.ts +1095 -0
  74. package/dist/{index-D6b6na69.d.cts → index-B4o55NDr.d.cts} +13 -9
  75. package/dist/index-B9MNZboQ.d.cts +770 -0
  76. package/dist/index-B9MNZboQ.d.ts +770 -0
  77. package/dist/index-BGFW-8P2.d.cts +2307 -0
  78. package/dist/index-BO6xE9YU.d.cts +1804 -0
  79. package/dist/index-BkGmlyI3.d.cts +470 -0
  80. package/dist/index-CCNJRG-P.d.cts +1095 -0
  81. package/dist/index-CGpRv5sl.d.cts +643 -0
  82. package/dist/index-C_8o--VE.d.cts +1242 -0
  83. package/dist/index-CgHqxdps.d.ts +2307 -0
  84. package/dist/index-Chbst3Jx.d.ts +1343 -0
  85. package/dist/index-Cj49F892.d.ts +470 -0
  86. package/dist/{index-tSQh-xwY.d.ts → index-CunYKLiu.d.ts} +13 -9
  87. package/dist/index-D57QRbVn.d.ts +1804 -0
  88. package/dist/index-DInQqT8Q.d.cts +66 -0
  89. package/dist/index-DInQqT8Q.d.ts +66 -0
  90. package/dist/index-Dzr13q3d.d.cts +1343 -0
  91. package/dist/index-G1uwGGWQ.d.ts +643 -0
  92. package/dist/index-szBv3496.d.ts +1242 -0
  93. package/dist/index.cjs +358 -15
  94. package/dist/index.cjs.map +1 -1
  95. package/dist/index.d.cts +17 -15
  96. package/dist/index.d.ts +17 -15
  97. package/dist/index.js +407 -64
  98. package/dist/masks-DYbE485J.d.cts +445 -0
  99. package/dist/masks-DYbE485J.d.ts +445 -0
  100. package/dist/model/index.cjs +39 -7
  101. package/dist/model/index.cjs.map +1 -1
  102. package/dist/model/index.d.cts +4685 -243
  103. package/dist/model/index.d.ts +4685 -243
  104. package/dist/model/index.js +40 -8
  105. package/dist/positional-Cptlj-xs.d.ts +287 -0
  106. package/dist/positional-DvH_sd8u.d.cts +287 -0
  107. package/dist/theory/index.cjs +101 -7
  108. package/dist/theory/index.cjs.map +1 -1
  109. package/dist/theory/index.d.cts +513 -173
  110. package/dist/theory/index.d.ts +513 -173
  111. package/dist/theory/index.js +118 -24
  112. package/package.json +16 -11
  113. package/dist/chunk-36N73KZ3.cjs +0 -246
  114. package/dist/chunk-36N73KZ3.cjs.map +0 -1
  115. package/dist/chunk-4HLLZPXT.cjs +0 -3077
  116. package/dist/chunk-4HLLZPXT.cjs.map +0 -1
  117. package/dist/chunk-7MGZ7D62.cjs +0 -498
  118. package/dist/chunk-7MGZ7D62.cjs.map +0 -1
  119. package/dist/chunk-7NKDPF74.js +0 -3077
  120. package/dist/chunk-7NKDPF74.js.map +0 -1
  121. package/dist/chunk-CAN76NCU.cjs +0 -679
  122. package/dist/chunk-CAN76NCU.cjs.map +0 -1
  123. package/dist/chunk-D2FAJBYL.js +0 -479
  124. package/dist/chunk-D2FAJBYL.js.map +0 -1
  125. package/dist/chunk-EHVEBWM5.js +0 -1449
  126. package/dist/chunk-EHVEBWM5.js.map +0 -1
  127. package/dist/chunk-FCANXBAT.cjs +0 -30
  128. package/dist/chunk-FCANXBAT.cjs.map +0 -1
  129. package/dist/chunk-FNDWXRRI.cjs +0 -479
  130. package/dist/chunk-FNDWXRRI.cjs.map +0 -1
  131. package/dist/chunk-GQSGS2N4.js +0 -173
  132. package/dist/chunk-GQSGS2N4.js.map +0 -1
  133. package/dist/chunk-HKGYCQ34.js +0 -53
  134. package/dist/chunk-HKGYCQ34.js.map +0 -1
  135. package/dist/chunk-I24MV65U.js +0 -106
  136. package/dist/chunk-I24MV65U.js.map +0 -1
  137. package/dist/chunk-KMHOICIY.js +0 -679
  138. package/dist/chunk-KMHOICIY.js.map +0 -1
  139. package/dist/chunk-LW53AHQU.cjs +0 -1117
  140. package/dist/chunk-LW53AHQU.cjs.map +0 -1
  141. package/dist/chunk-N6IHQUOX.js +0 -1
  142. package/dist/chunk-NKIBQ6PT.js +0 -30
  143. package/dist/chunk-NKIBQ6PT.js.map +0 -1
  144. package/dist/chunk-NP4NA2FB.cjs +0 -106
  145. package/dist/chunk-NP4NA2FB.cjs.map +0 -1
  146. package/dist/chunk-NVE34YGZ.cjs +0 -1449
  147. package/dist/chunk-NVE34YGZ.cjs.map +0 -1
  148. package/dist/chunk-NYYWMV2C.js +0 -327
  149. package/dist/chunk-NYYWMV2C.js.map +0 -1
  150. package/dist/chunk-Q2XUP227.js +0 -845
  151. package/dist/chunk-Q2XUP227.js.map +0 -1
  152. package/dist/chunk-Q6OP4U43.cjs +0 -327
  153. package/dist/chunk-Q6OP4U43.cjs.map +0 -1
  154. package/dist/chunk-RC6GBMCD.cjs +0 -845
  155. package/dist/chunk-RC6GBMCD.cjs.map +0 -1
  156. package/dist/chunk-RK35RIN7.js +0 -1117
  157. package/dist/chunk-RK35RIN7.js.map +0 -1
  158. package/dist/chunk-RUMU3UA6.cjs +0 -53
  159. package/dist/chunk-RUMU3UA6.cjs.map +0 -1
  160. package/dist/chunk-T64C7ZD7.cjs +0 -1
  161. package/dist/chunk-T64C7ZD7.cjs.map +0 -1
  162. package/dist/chunk-XEBG3G53.js +0 -498
  163. package/dist/chunk-XEBG3G53.js.map +0 -1
  164. package/dist/chunk-YLEMGEFH.js +0 -246
  165. package/dist/chunk-YLEMGEFH.js.map +0 -1
  166. package/dist/chunk-ZEJR4TKL.cjs +0 -173
  167. package/dist/chunk-ZEJR4TKL.cjs.map +0 -1
  168. package/dist/function-BtiZb9i9.d.ts +0 -208
  169. package/dist/function-DNugAOrt.d.cts +0 -208
  170. package/dist/index-6VR8-kit.d.ts +0 -143
  171. package/dist/index-70p168VM.d.ts +0 -192
  172. package/dist/index-Be74mcon.d.cts +0 -152
  173. package/dist/index-BtXT6UQ0.d.cts +0 -192
  174. package/dist/index-C5UBbQ4G.d.ts +0 -152
  175. package/dist/index-C83mZI1P.d.ts +0 -242
  176. package/dist/index-DXd9JikN.d.cts +0 -246
  177. package/dist/index-DXd9JikN.d.ts +0 -246
  178. package/dist/index-OG65ocOr.d.cts +0 -272
  179. package/dist/index-OG65ocOr.d.ts +0 -272
  180. package/dist/index-tJhkmQgE.d.cts +0 -143
  181. package/dist/index-y_ak9_Hi.d.cts +0 -242
  182. package/dist/styled-DIRkk9Uz.d.ts +0 -506
  183. package/dist/styled-DJbkJQfj.d.cts +0 -506
  184. package/dist/types-BN6_Q9Kl.d.cts +0 -39
  185. package/dist/types-BN6_Q9Kl.d.ts +0 -39
  186. /package/dist/{chunk-N6IHQUOX.js.map → chunk-HFPS7JFD.js.map} +0 -0
@@ -1,20 +1,52 @@
1
1
  import {
2
+ Arrangement,
2
3
  Chord,
4
+ Composer,
5
+ Duration,
6
+ Instrument,
3
7
  Interval,
4
8
  Key,
9
+ Meter,
10
+ Motif,
5
11
  Note,
6
- Progression
7
- } from "../chunk-EHVEBWM5.js";
8
- import "../chunk-GQSGS2N4.js";
9
- import "../chunk-KMHOICIY.js";
10
- import "../chunk-RK35RIN7.js";
11
- import "../chunk-D2FAJBYL.js";
12
- import "../chunk-XEBG3G53.js";
12
+ Progression,
13
+ Rhythm,
14
+ Score,
15
+ Tempo,
16
+ Timeline,
17
+ Tuning,
18
+ Voicing
19
+ } from "../chunk-4A2RMUCC.js";
20
+ import "../chunk-GOZG57ER.js";
21
+ import "../chunk-YH3BIKHH.js";
22
+ import "../chunk-VOHZB45S.js";
23
+ import "../chunk-H42UHPYW.js";
24
+ import "../chunk-FVSI36UV.js";
25
+ import "../chunk-ELCTZUJJ.js";
26
+ import "../chunk-H3VORETI.js";
27
+ import "../chunk-KNJEKLKV.js";
28
+ import {
29
+ NoteSafety
30
+ } from "../chunk-INHVXP6Z.js";
31
+ import "../chunk-VTI6FOLB.js";
13
32
  export {
33
+ Arrangement,
14
34
  Chord,
35
+ Composer,
36
+ Duration,
37
+ Instrument,
15
38
  Interval,
16
39
  Key,
40
+ Meter,
41
+ Motif,
17
42
  Note,
18
- Progression
43
+ NoteSafety,
44
+ Progression,
45
+ Rhythm,
46
+ Score,
47
+ Tempo,
48
+ Timeline,
49
+ Tuning,
50
+ Voicing
19
51
  };
20
52
  //# sourceMappingURL=index.js.map
@@ -0,0 +1,287 @@
1
+ import { a as Articulation } from './index-B9MNZboQ.js';
2
+
3
+ /**
4
+ * Every limb a percussionist strikes with, in declaration order.
5
+ *
6
+ * @category Core
7
+ */
8
+ declare const LIMBS: readonly ["rightHand", "leftHand", "rightFoot", "leftFoot"];
9
+ /**
10
+ * One limb of a percussionist.
11
+ *
12
+ * @category Core
13
+ */
14
+ type Limb = (typeof LIMBS)[number];
15
+ /**
16
+ * Fields every instrument profile carries, whatever its family.
17
+ *
18
+ * @category Core
19
+ */
20
+ type InstrumentProfileCommon = {
21
+ /** Instrument name, for issue messages and for the caller's own display. */
22
+ name: string;
23
+ /** Techniques this instrument can produce; anything else it cannot play. */
24
+ articulations: readonly Articulation[];
25
+ /** Greatest number of notes that can sound at once. */
26
+ polyphony: number;
27
+ };
28
+ /**
29
+ * A fretted or fretless string instrument, described by what it is rather than
30
+ * by the range it happens to have.
31
+ *
32
+ * The sounding range follows from `tuning` and `frets`: string `s` sounds
33
+ * `tuning[s] .. tuning[s] + frets`. Storing `[min, max]` instead would make a
34
+ * five-string bass, a drop tuning, a seven-string guitar and an extended-range
35
+ * neck four unrelated special cases, and would leave "the neck is not long
36
+ * enough" indistinguishable from "the note is below the instrument".
37
+ *
38
+ * @category Core
39
+ */
40
+ type StringedProfile = InstrumentProfileCommon & {
41
+ kind: 'stringed';
42
+ /** Open-string MIDI pitch per string, lowest-sounding string first. */
43
+ tuning: readonly number[];
44
+ /** Highest fret number; fret 0 is the open string. */
45
+ frets: number;
46
+ /** Greatest fret span one hand can hold down at once. */
47
+ maxStretch: number;
48
+ /**
49
+ * The neck has no frets. Positions are continuous, so intonation is the
50
+ * player's and a slide is unbroken; in twelve-tone equal temperament the
51
+ * positions coincide with fret numbers, so range and stretch are read the
52
+ * same way.
53
+ */
54
+ fretless?: boolean;
55
+ };
56
+ /**
57
+ * A percussion setup, described by the voices within reach of each limb.
58
+ *
59
+ * A kit's constraint is not range but limbs: a voice no limb can reach is not
60
+ * on the instrument, and two voices needing the same limb at the same instant
61
+ * cannot both sound.
62
+ *
63
+ * @category Core
64
+ */
65
+ type PercussionProfile = InstrumentProfileCommon & {
66
+ kind: 'percussion';
67
+ /** The limbs the player has available. */
68
+ limbs: readonly Limb[];
69
+ /** Limbs that can strike each voice, in preference order, keyed by MIDI note. */
70
+ reach: Readonly<Record<number, readonly Limb[]>>;
71
+ };
72
+ /**
73
+ * An instrument the library can check a passage against.
74
+ *
75
+ * @category Core
76
+ */
77
+ type InstrumentProfile = StringedProfile | PercussionProfile;
78
+ /**
79
+ * Anything that names an instrument: a plain {@link InstrumentProfile}, or a
80
+ * value that serializes to one such as the `Instrument` class.
81
+ *
82
+ * Every entry point that takes an instrument takes this, so a caller holding
83
+ * the class hands it over as it is instead of unwrapping it for one call and
84
+ * wrapping it again for the next.
85
+ *
86
+ * @category Core
87
+ */
88
+ type InstrumentProfileLike = InstrumentProfile | {
89
+ /** The profile data this value stands for. */
90
+ toJSON(): InstrumentProfile;
91
+ };
92
+ /**
93
+ * A fretting-hand position: which string, and how far up the neck.
94
+ *
95
+ * @category Core
96
+ */
97
+ type StringFingering = {
98
+ /** Index into the `tuning` of a {@link StringedProfile}. */
99
+ string: number;
100
+ /** Fret number; 0 is the open string. */
101
+ fret: number;
102
+ };
103
+ /**
104
+ * The lowest and highest pitch an instrument sounds.
105
+ *
106
+ * For a string instrument this is derived from the tuning and the fret count,
107
+ * never stored; for a kit it is the extent of the voices the player's limbs
108
+ * reach. The range is not necessarily gapless — use {@link canSound} to ask
109
+ * about one pitch.
110
+ *
111
+ * @param profile The instrument.
112
+ * @returns The extreme sounding pitches, inclusive.
113
+ *
114
+ * @example
115
+ * ```ts
116
+ * import { BASS_5_STRING, instrumentRange } from '@libraz/libcantus';
117
+ * instrumentRange(BASS_5_STRING).low; // 23, low B
118
+ * ```
119
+ * @category Core
120
+ */
121
+ declare function instrumentRange(profile: InstrumentProfile): {
122
+ low: number;
123
+ high: number;
124
+ };
125
+ /**
126
+ * Whether the instrument has this pitch at all.
127
+ *
128
+ * This is the first of the three playability layers: no amount of skill or
129
+ * rehearsal puts a note on an instrument that has no position for it.
130
+ *
131
+ * @param profile The instrument.
132
+ * @param pitch MIDI pitch.
133
+ * @returns True when some string and fret, or some limb the player has,
134
+ * produces it.
135
+ * @category Core
136
+ */
137
+ declare function canSound(profile: InstrumentProfile, pitch: number): boolean;
138
+ /**
139
+ * Every position on the neck that sounds a pitch, lowest string first.
140
+ *
141
+ * @param profile The instrument.
142
+ * @param pitch MIDI pitch.
143
+ * @returns One entry per string that reaches the pitch; empty when none does.
144
+ * @category Core
145
+ */
146
+ declare function fingeringsFor(profile: StringedProfile, pitch: number): StringFingering[];
147
+ /**
148
+ * Move a pitch by whole octaves until the instrument can sound it.
149
+ *
150
+ * This is what a player does with a line written below the instrument: the note
151
+ * comes back an octave up, keeping its pitch class and its place in the phrase.
152
+ * Substituting a different scale degree, or refusing the passage outright, is
153
+ * the wrong answer for a bass line.
154
+ *
155
+ * @param pitch MIDI pitch to place.
156
+ * @param profile The instrument.
157
+ * @returns The nearest octave transposition the instrument sounds, searching
158
+ * upward first; the pitch unchanged when no transposition of it is available.
159
+ *
160
+ * @example
161
+ * ```ts
162
+ * import { BASS_4_STRING, foldIntoRange } from '@libraz/libcantus';
163
+ * foldIntoRange(27, BASS_4_STRING); // 39 — Eb1 is under the low E
164
+ * ```
165
+ * @category Core
166
+ */
167
+ declare function foldIntoRange(pitch: number, profile: InstrumentProfile): number;
168
+
169
+ /**
170
+ * Hierarchical seeds: one project number that addresses every part.
171
+ *
172
+ * A flat seed per generator makes the caller keep a table of numbers and,
173
+ * worse, makes "reroll the drums" mean "pick a number nobody else is using".
174
+ * Deriving instead — `deriveSeed(project, 'drums', 'chorus', 2)` — turns a
175
+ * reroll into an extra path segment, and every other part keeps the seed it
176
+ * had because its path did not change.
177
+ */
178
+ /**
179
+ * The address of one derivation: a namespace, and whatever names or indices
180
+ * locate the thing being seeded.
181
+ *
182
+ * Strings and numbers are kept apart by the hash, so `'3'` and `3` address
183
+ * different things, as do `['ab', 'c']` and `['a', 'bc']`.
184
+ *
185
+ * @category Utilities
186
+ */
187
+ type SeedPath = readonly (string | number)[];
188
+ /**
189
+ * Derive a child seed from a root seed and a path.
190
+ *
191
+ * The result is a 32-bit integer, so it can be passed straight to
192
+ * {@link createRng}. Derivation is a pure function of its arguments — the same
193
+ * root and path give the same seed in every runtime — and near-identical paths
194
+ * (`'drums'` against `'drum'`, bar 1 against bar 2) give unrelated seeds: the
195
+ * path is hashed with FNV-1a and finished with the MurmurHash3 fmix32
196
+ * avalanche step.
197
+ *
198
+ * @param root The project seed; an integer in 0..0xffffffff.
199
+ * @param path The address to derive at; string or finite number segments.
200
+ * @returns The derived seed, an integer in 0..0xffffffff.
201
+ * @throws If the root is not a 32-bit integer, or a segment is neither a
202
+ * string nor a finite number.
203
+ * @example
204
+ * ```ts
205
+ * import { createRng, deriveSeed } from '@libraz/libcantus';
206
+ * const drums = deriveSeed(42, 'drums', 'chorus', 3);
207
+ * const rng = createRng(drums); // rerolling only the drums: bump the 3
208
+ * ```
209
+ * @category Utilities
210
+ */
211
+ declare function deriveSeed(root: number, ...path: SeedPath): number;
212
+
213
+ /**
214
+ * Position-addressed randomness and threshold sampling.
215
+ *
216
+ * Drawing in call order makes a generator's output depend on how many draws
217
+ * preceded it, so editing a parameter in the middle of a piece redraws
218
+ * everything after it. Addressing each draw by where it happens — bar, beat,
219
+ * voice — removes that coupling: the value at a position depends on the
220
+ * position alone, so a change anywhere leaves every other position as it was.
221
+ *
222
+ * Deciding inclusion by comparing a fixed positional draw against a complexity
223
+ * dial gives the property a slider needs: raising the dial only adds events,
224
+ * and everything already sounding stays where it was.
225
+ */
226
+
227
+ /**
228
+ * A random source addressed by position rather than by call order.
229
+ *
230
+ * @category Utilities
231
+ */
232
+ type PositionalRng = {
233
+ /**
234
+ * The draw belonging to a position: a float in [0, 1) that depends only on
235
+ * the seed and the path, so it is the same however often and in whatever
236
+ * order it is asked for.
237
+ */
238
+ at: (...path: SeedPath) => number;
239
+ };
240
+ /**
241
+ * Create a position-addressed random source.
242
+ *
243
+ * `at` holds no cursor: it is a pure function of the seed and the path, safe to
244
+ * call in any order, any number of times, from anywhere in a generator. Its
245
+ * draws are independent of {@link deriveSeed} at the same path, so a generator
246
+ * may seed a sub-part and take a positional draw at one position without
247
+ * getting the same number twice.
248
+ *
249
+ * @param seed The seed; an integer in 0..0xffffffff, typically from
250
+ * {@link deriveSeed}.
251
+ * @returns The positional source.
252
+ * @throws If the seed is not a 32-bit integer.
253
+ * @example
254
+ * ```ts
255
+ * import { createPositionalRng, deriveSeed } from '@libraz/libcantus';
256
+ * const rng = createPositionalRng(deriveSeed(42, 'drums'));
257
+ * rng.at('ghost', 4, 2.5); // the same value however often it is asked for
258
+ * ```
259
+ * @category Utilities
260
+ */
261
+ declare function createPositionalRng(seed: number): PositionalRng;
262
+ /**
263
+ * Whether the event at a position belongs in the output at a given complexity.
264
+ *
265
+ * The test is `at(...path) < complexity`, and because the draw is fixed by the
266
+ * position, the selected set grows monotonically with complexity: for any
267
+ * `c1 < c2` the events at `c1` are a subset of the events at `c2` over the same
268
+ * seed and the same path space. Complexity 0 selects nothing and complexity 1
269
+ * selects everything.
270
+ *
271
+ * @param rng The positional source; may be a caller-supplied one.
272
+ * @param complexity The dial, in [0, 1].
273
+ * @param path The position to test.
274
+ * @returns True when the position is included.
275
+ * @throws If the complexity is outside [0, 1], or the source returns a value
276
+ * outside [0, 1).
277
+ * @example
278
+ * ```ts
279
+ * import { createPositionalRng, includeAt } from '@libraz/libcantus';
280
+ * const rng = createPositionalRng(7);
281
+ * includeAt(rng, 0.3, 'ghost', 4, 2.5); // raising 0.3 only adds hits
282
+ * ```
283
+ * @category Utilities
284
+ */
285
+ declare function includeAt(rng: PositionalRng, complexity: number, ...path: SeedPath): boolean;
286
+
287
+ export { type InstrumentProfile as I, LIMBS as L, type PercussionProfile as P, type SeedPath as S, type InstrumentProfileCommon as a, type InstrumentProfileLike as b, type Limb as c, type PositionalRng as d, type StringFingering as e, type StringedProfile as f, canSound as g, createPositionalRng as h, deriveSeed as i, fingeringsFor as j, foldIntoRange as k, includeAt as l, instrumentRange as m };
@@ -0,0 +1,287 @@
1
+ import { a as Articulation } from './index-B9MNZboQ.cjs';
2
+
3
+ /**
4
+ * Every limb a percussionist strikes with, in declaration order.
5
+ *
6
+ * @category Core
7
+ */
8
+ declare const LIMBS: readonly ["rightHand", "leftHand", "rightFoot", "leftFoot"];
9
+ /**
10
+ * One limb of a percussionist.
11
+ *
12
+ * @category Core
13
+ */
14
+ type Limb = (typeof LIMBS)[number];
15
+ /**
16
+ * Fields every instrument profile carries, whatever its family.
17
+ *
18
+ * @category Core
19
+ */
20
+ type InstrumentProfileCommon = {
21
+ /** Instrument name, for issue messages and for the caller's own display. */
22
+ name: string;
23
+ /** Techniques this instrument can produce; anything else it cannot play. */
24
+ articulations: readonly Articulation[];
25
+ /** Greatest number of notes that can sound at once. */
26
+ polyphony: number;
27
+ };
28
+ /**
29
+ * A fretted or fretless string instrument, described by what it is rather than
30
+ * by the range it happens to have.
31
+ *
32
+ * The sounding range follows from `tuning` and `frets`: string `s` sounds
33
+ * `tuning[s] .. tuning[s] + frets`. Storing `[min, max]` instead would make a
34
+ * five-string bass, a drop tuning, a seven-string guitar and an extended-range
35
+ * neck four unrelated special cases, and would leave "the neck is not long
36
+ * enough" indistinguishable from "the note is below the instrument".
37
+ *
38
+ * @category Core
39
+ */
40
+ type StringedProfile = InstrumentProfileCommon & {
41
+ kind: 'stringed';
42
+ /** Open-string MIDI pitch per string, lowest-sounding string first. */
43
+ tuning: readonly number[];
44
+ /** Highest fret number; fret 0 is the open string. */
45
+ frets: number;
46
+ /** Greatest fret span one hand can hold down at once. */
47
+ maxStretch: number;
48
+ /**
49
+ * The neck has no frets. Positions are continuous, so intonation is the
50
+ * player's and a slide is unbroken; in twelve-tone equal temperament the
51
+ * positions coincide with fret numbers, so range and stretch are read the
52
+ * same way.
53
+ */
54
+ fretless?: boolean;
55
+ };
56
+ /**
57
+ * A percussion setup, described by the voices within reach of each limb.
58
+ *
59
+ * A kit's constraint is not range but limbs: a voice no limb can reach is not
60
+ * on the instrument, and two voices needing the same limb at the same instant
61
+ * cannot both sound.
62
+ *
63
+ * @category Core
64
+ */
65
+ type PercussionProfile = InstrumentProfileCommon & {
66
+ kind: 'percussion';
67
+ /** The limbs the player has available. */
68
+ limbs: readonly Limb[];
69
+ /** Limbs that can strike each voice, in preference order, keyed by MIDI note. */
70
+ reach: Readonly<Record<number, readonly Limb[]>>;
71
+ };
72
+ /**
73
+ * An instrument the library can check a passage against.
74
+ *
75
+ * @category Core
76
+ */
77
+ type InstrumentProfile = StringedProfile | PercussionProfile;
78
+ /**
79
+ * Anything that names an instrument: a plain {@link InstrumentProfile}, or a
80
+ * value that serializes to one such as the `Instrument` class.
81
+ *
82
+ * Every entry point that takes an instrument takes this, so a caller holding
83
+ * the class hands it over as it is instead of unwrapping it for one call and
84
+ * wrapping it again for the next.
85
+ *
86
+ * @category Core
87
+ */
88
+ type InstrumentProfileLike = InstrumentProfile | {
89
+ /** The profile data this value stands for. */
90
+ toJSON(): InstrumentProfile;
91
+ };
92
+ /**
93
+ * A fretting-hand position: which string, and how far up the neck.
94
+ *
95
+ * @category Core
96
+ */
97
+ type StringFingering = {
98
+ /** Index into the `tuning` of a {@link StringedProfile}. */
99
+ string: number;
100
+ /** Fret number; 0 is the open string. */
101
+ fret: number;
102
+ };
103
+ /**
104
+ * The lowest and highest pitch an instrument sounds.
105
+ *
106
+ * For a string instrument this is derived from the tuning and the fret count,
107
+ * never stored; for a kit it is the extent of the voices the player's limbs
108
+ * reach. The range is not necessarily gapless — use {@link canSound} to ask
109
+ * about one pitch.
110
+ *
111
+ * @param profile The instrument.
112
+ * @returns The extreme sounding pitches, inclusive.
113
+ *
114
+ * @example
115
+ * ```ts
116
+ * import { BASS_5_STRING, instrumentRange } from '@libraz/libcantus';
117
+ * instrumentRange(BASS_5_STRING).low; // 23, low B
118
+ * ```
119
+ * @category Core
120
+ */
121
+ declare function instrumentRange(profile: InstrumentProfile): {
122
+ low: number;
123
+ high: number;
124
+ };
125
+ /**
126
+ * Whether the instrument has this pitch at all.
127
+ *
128
+ * This is the first of the three playability layers: no amount of skill or
129
+ * rehearsal puts a note on an instrument that has no position for it.
130
+ *
131
+ * @param profile The instrument.
132
+ * @param pitch MIDI pitch.
133
+ * @returns True when some string and fret, or some limb the player has,
134
+ * produces it.
135
+ * @category Core
136
+ */
137
+ declare function canSound(profile: InstrumentProfile, pitch: number): boolean;
138
+ /**
139
+ * Every position on the neck that sounds a pitch, lowest string first.
140
+ *
141
+ * @param profile The instrument.
142
+ * @param pitch MIDI pitch.
143
+ * @returns One entry per string that reaches the pitch; empty when none does.
144
+ * @category Core
145
+ */
146
+ declare function fingeringsFor(profile: StringedProfile, pitch: number): StringFingering[];
147
+ /**
148
+ * Move a pitch by whole octaves until the instrument can sound it.
149
+ *
150
+ * This is what a player does with a line written below the instrument: the note
151
+ * comes back an octave up, keeping its pitch class and its place in the phrase.
152
+ * Substituting a different scale degree, or refusing the passage outright, is
153
+ * the wrong answer for a bass line.
154
+ *
155
+ * @param pitch MIDI pitch to place.
156
+ * @param profile The instrument.
157
+ * @returns The nearest octave transposition the instrument sounds, searching
158
+ * upward first; the pitch unchanged when no transposition of it is available.
159
+ *
160
+ * @example
161
+ * ```ts
162
+ * import { BASS_4_STRING, foldIntoRange } from '@libraz/libcantus';
163
+ * foldIntoRange(27, BASS_4_STRING); // 39 — Eb1 is under the low E
164
+ * ```
165
+ * @category Core
166
+ */
167
+ declare function foldIntoRange(pitch: number, profile: InstrumentProfile): number;
168
+
169
+ /**
170
+ * Hierarchical seeds: one project number that addresses every part.
171
+ *
172
+ * A flat seed per generator makes the caller keep a table of numbers and,
173
+ * worse, makes "reroll the drums" mean "pick a number nobody else is using".
174
+ * Deriving instead — `deriveSeed(project, 'drums', 'chorus', 2)` — turns a
175
+ * reroll into an extra path segment, and every other part keeps the seed it
176
+ * had because its path did not change.
177
+ */
178
+ /**
179
+ * The address of one derivation: a namespace, and whatever names or indices
180
+ * locate the thing being seeded.
181
+ *
182
+ * Strings and numbers are kept apart by the hash, so `'3'` and `3` address
183
+ * different things, as do `['ab', 'c']` and `['a', 'bc']`.
184
+ *
185
+ * @category Utilities
186
+ */
187
+ type SeedPath = readonly (string | number)[];
188
+ /**
189
+ * Derive a child seed from a root seed and a path.
190
+ *
191
+ * The result is a 32-bit integer, so it can be passed straight to
192
+ * {@link createRng}. Derivation is a pure function of its arguments — the same
193
+ * root and path give the same seed in every runtime — and near-identical paths
194
+ * (`'drums'` against `'drum'`, bar 1 against bar 2) give unrelated seeds: the
195
+ * path is hashed with FNV-1a and finished with the MurmurHash3 fmix32
196
+ * avalanche step.
197
+ *
198
+ * @param root The project seed; an integer in 0..0xffffffff.
199
+ * @param path The address to derive at; string or finite number segments.
200
+ * @returns The derived seed, an integer in 0..0xffffffff.
201
+ * @throws If the root is not a 32-bit integer, or a segment is neither a
202
+ * string nor a finite number.
203
+ * @example
204
+ * ```ts
205
+ * import { createRng, deriveSeed } from '@libraz/libcantus';
206
+ * const drums = deriveSeed(42, 'drums', 'chorus', 3);
207
+ * const rng = createRng(drums); // rerolling only the drums: bump the 3
208
+ * ```
209
+ * @category Utilities
210
+ */
211
+ declare function deriveSeed(root: number, ...path: SeedPath): number;
212
+
213
+ /**
214
+ * Position-addressed randomness and threshold sampling.
215
+ *
216
+ * Drawing in call order makes a generator's output depend on how many draws
217
+ * preceded it, so editing a parameter in the middle of a piece redraws
218
+ * everything after it. Addressing each draw by where it happens — bar, beat,
219
+ * voice — removes that coupling: the value at a position depends on the
220
+ * position alone, so a change anywhere leaves every other position as it was.
221
+ *
222
+ * Deciding inclusion by comparing a fixed positional draw against a complexity
223
+ * dial gives the property a slider needs: raising the dial only adds events,
224
+ * and everything already sounding stays where it was.
225
+ */
226
+
227
+ /**
228
+ * A random source addressed by position rather than by call order.
229
+ *
230
+ * @category Utilities
231
+ */
232
+ type PositionalRng = {
233
+ /**
234
+ * The draw belonging to a position: a float in [0, 1) that depends only on
235
+ * the seed and the path, so it is the same however often and in whatever
236
+ * order it is asked for.
237
+ */
238
+ at: (...path: SeedPath) => number;
239
+ };
240
+ /**
241
+ * Create a position-addressed random source.
242
+ *
243
+ * `at` holds no cursor: it is a pure function of the seed and the path, safe to
244
+ * call in any order, any number of times, from anywhere in a generator. Its
245
+ * draws are independent of {@link deriveSeed} at the same path, so a generator
246
+ * may seed a sub-part and take a positional draw at one position without
247
+ * getting the same number twice.
248
+ *
249
+ * @param seed The seed; an integer in 0..0xffffffff, typically from
250
+ * {@link deriveSeed}.
251
+ * @returns The positional source.
252
+ * @throws If the seed is not a 32-bit integer.
253
+ * @example
254
+ * ```ts
255
+ * import { createPositionalRng, deriveSeed } from '@libraz/libcantus';
256
+ * const rng = createPositionalRng(deriveSeed(42, 'drums'));
257
+ * rng.at('ghost', 4, 2.5); // the same value however often it is asked for
258
+ * ```
259
+ * @category Utilities
260
+ */
261
+ declare function createPositionalRng(seed: number): PositionalRng;
262
+ /**
263
+ * Whether the event at a position belongs in the output at a given complexity.
264
+ *
265
+ * The test is `at(...path) < complexity`, and because the draw is fixed by the
266
+ * position, the selected set grows monotonically with complexity: for any
267
+ * `c1 < c2` the events at `c1` are a subset of the events at `c2` over the same
268
+ * seed and the same path space. Complexity 0 selects nothing and complexity 1
269
+ * selects everything.
270
+ *
271
+ * @param rng The positional source; may be a caller-supplied one.
272
+ * @param complexity The dial, in [0, 1].
273
+ * @param path The position to test.
274
+ * @returns True when the position is included.
275
+ * @throws If the complexity is outside [0, 1], or the source returns a value
276
+ * outside [0, 1).
277
+ * @example
278
+ * ```ts
279
+ * import { createPositionalRng, includeAt } from '@libraz/libcantus';
280
+ * const rng = createPositionalRng(7);
281
+ * includeAt(rng, 0.3, 'ghost', 4, 2.5); // raising 0.3 only adds hits
282
+ * ```
283
+ * @category Utilities
284
+ */
285
+ declare function includeAt(rng: PositionalRng, complexity: number, ...path: SeedPath): boolean;
286
+
287
+ export { type InstrumentProfile as I, LIMBS as L, type PercussionProfile as P, type SeedPath as S, type InstrumentProfileCommon as a, type InstrumentProfileLike as b, type Limb as c, type PositionalRng as d, type StringFingering as e, type StringedProfile as f, canSound as g, createPositionalRng as h, deriveSeed as i, fingeringsFor as j, foldIntoRange as k, includeAt as l, instrumentRange as m };