@libraz/libcantus 0.9.5 → 1.0.1

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 (185) hide show
  1. package/README.md +61 -270
  2. package/README_ja.md +61 -214
  3. package/dist/analyze/index.cjs +54 -7
  4. package/dist/analyze/index.cjs.map +1 -1
  5. package/dist/analyze/index.d.cts +200 -353
  6. package/dist/analyze/index.d.ts +200 -353
  7. package/dist/analyze/index.js +56 -9
  8. package/dist/chunk-2LCPM3EG.js +3224 -0
  9. package/dist/chunk-2LCPM3EG.js.map +1 -0
  10. package/dist/chunk-6XH6QZYQ.cjs +7647 -0
  11. package/dist/chunk-6XH6QZYQ.cjs.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-B6XNKWZV.cjs +3224 -0
  17. package/dist/chunk-B6XNKWZV.cjs.map +1 -0
  18. package/dist/chunk-E3F4AHAH.cjs +690 -0
  19. package/dist/chunk-E3F4AHAH.cjs.map +1 -0
  20. package/dist/{chunk-2PTFGVD7.js → chunk-ELCTZUJJ.js} +250 -132
  21. package/dist/chunk-ELCTZUJJ.js.map +1 -0
  22. package/dist/chunk-FVSI36UV.js +690 -0
  23. package/dist/chunk-FVSI36UV.js.map +1 -0
  24. package/dist/chunk-GEDTJHAC.cjs +1 -0
  25. package/dist/chunk-GEDTJHAC.cjs.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-MXO72PLY.cjs +211 -0
  38. package/dist/chunk-MXO72PLY.cjs.map +1 -0
  39. package/dist/chunk-NLEU4QSE.cjs +360 -0
  40. package/dist/chunk-NLEU4QSE.cjs.map +1 -0
  41. package/dist/chunk-OE6WK2Y2.cjs +1577 -0
  42. package/dist/chunk-OE6WK2Y2.cjs.map +1 -0
  43. package/dist/chunk-PKFNUHDY.js +7647 -0
  44. package/dist/chunk-PKFNUHDY.js.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 +93 -6
  64. package/dist/core/index.cjs.map +1 -1
  65. package/dist/core/index.d.cts +87 -346
  66. package/dist/core/index.d.ts +87 -346
  67. package/dist/core/index.js +94 -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 +436 -1094
  71. package/dist/generate/index.d.ts +436 -1094
  72. package/dist/generate/index.js +94 -15
  73. package/dist/index-9wcMhG73.d.ts +1095 -0
  74. package/dist/{index-Cfx8xgH0.d.ts → 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-x2vcsduE.d.cts → 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 +348 -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 +397 -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 +4659 -249
  103. package/dist/model/index.d.ts +4659 -249
  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 +511 -171
  110. package/dist/theory/index.d.ts +511 -171
  111. package/dist/theory/index.js +118 -24
  112. package/package.json +6 -4
  113. package/dist/chunk-2A2QMA74.cjs +0 -261
  114. package/dist/chunk-2A2QMA74.cjs.map +0 -1
  115. package/dist/chunk-2PTFGVD7.js.map +0 -1
  116. package/dist/chunk-357ZDPVU.cjs +0 -162
  117. package/dist/chunk-357ZDPVU.cjs.map +0 -1
  118. package/dist/chunk-3KX76RLG.js +0 -1548
  119. package/dist/chunk-3KX76RLG.js.map +0 -1
  120. package/dist/chunk-4VZ5MZAM.cjs +0 -889
  121. package/dist/chunk-4VZ5MZAM.cjs.map +0 -1
  122. package/dist/chunk-7EONYVI5.js +0 -1204
  123. package/dist/chunk-7EONYVI5.js.map +0 -1
  124. package/dist/chunk-7JEP3MFY.js +0 -162
  125. package/dist/chunk-7JEP3MFY.js.map +0 -1
  126. package/dist/chunk-AID75RN3.js +0 -3176
  127. package/dist/chunk-AID75RN3.js.map +0 -1
  128. package/dist/chunk-BSLTLGM3.cjs +0 -497
  129. package/dist/chunk-BSLTLGM3.cjs.map +0 -1
  130. package/dist/chunk-CU6VG2YM.cjs +0 -109
  131. package/dist/chunk-CU6VG2YM.cjs.map +0 -1
  132. package/dist/chunk-DZMHIGI4.js +0 -337
  133. package/dist/chunk-DZMHIGI4.js.map +0 -1
  134. package/dist/chunk-EDOTEABK.js +0 -109
  135. package/dist/chunk-EDOTEABK.js.map +0 -1
  136. package/dist/chunk-HN2OEUN2.js +0 -33
  137. package/dist/chunk-HN2OEUN2.js.map +0 -1
  138. package/dist/chunk-KBTTEX7Q.js +0 -497
  139. package/dist/chunk-KBTTEX7Q.js.map +0 -1
  140. package/dist/chunk-KQN2ZYND.cjs +0 -724
  141. package/dist/chunk-KQN2ZYND.cjs.map +0 -1
  142. package/dist/chunk-MPTVJIVG.cjs +0 -3176
  143. package/dist/chunk-MPTVJIVG.cjs.map +0 -1
  144. package/dist/chunk-MTMZTMWM.cjs +0 -53
  145. package/dist/chunk-MTMZTMWM.cjs.map +0 -1
  146. package/dist/chunk-N6IHQUOX.js +0 -1
  147. package/dist/chunk-NNB67XA2.js +0 -724
  148. package/dist/chunk-NNB67XA2.js.map +0 -1
  149. package/dist/chunk-OL3IHHSJ.cjs +0 -1204
  150. package/dist/chunk-OL3IHHSJ.cjs.map +0 -1
  151. package/dist/chunk-PI3UXRWK.cjs +0 -528
  152. package/dist/chunk-PI3UXRWK.cjs.map +0 -1
  153. package/dist/chunk-R2VVFAIN.js +0 -528
  154. package/dist/chunk-R2VVFAIN.js.map +0 -1
  155. package/dist/chunk-T64C7ZD7.cjs +0 -1
  156. package/dist/chunk-T64C7ZD7.cjs.map +0 -1
  157. package/dist/chunk-WFDXOLUB.cjs +0 -337
  158. package/dist/chunk-WFDXOLUB.cjs.map +0 -1
  159. package/dist/chunk-WTAN4ACG.cjs +0 -1548
  160. package/dist/chunk-WTAN4ACG.cjs.map +0 -1
  161. package/dist/chunk-YFJXS3AU.cjs +0 -33
  162. package/dist/chunk-YFJXS3AU.cjs.map +0 -1
  163. package/dist/chunk-YUE6TJ4M.js +0 -889
  164. package/dist/chunk-YUE6TJ4M.js.map +0 -1
  165. package/dist/chunk-ZGLJM4A4.js +0 -53
  166. package/dist/chunk-ZGLJM4A4.js.map +0 -1
  167. package/dist/function-CxixTB02.d.cts +0 -299
  168. package/dist/function-DTCt675z.d.ts +0 -299
  169. package/dist/index-B2Ulxxpo.d.cts +0 -144
  170. package/dist/index-BkYJ0xMq.d.cts +0 -152
  171. package/dist/index-BuaB-ypt.d.ts +0 -144
  172. package/dist/index-CAN7v-kw.d.ts +0 -199
  173. package/dist/index-COw1Ky9g.d.ts +0 -242
  174. package/dist/index-DRtIhlJj.d.ts +0 -152
  175. package/dist/index-DXd9JikN.d.cts +0 -246
  176. package/dist/index-DXd9JikN.d.ts +0 -246
  177. package/dist/index-alrRninU.d.cts +0 -199
  178. package/dist/index-oTQbYYIs.d.cts +0 -242
  179. package/dist/index-tR9jTn26.d.cts +0 -275
  180. package/dist/index-tR9jTn26.d.ts +0 -275
  181. package/dist/styled-Bl0ZK28h.d.ts +0 -543
  182. package/dist/styled-Crv6SA4S.d.cts +0 -543
  183. package/dist/types-BN6_Q9Kl.d.cts +0 -39
  184. package/dist/types-BN6_Q9Kl.d.ts +0 -39
  185. /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-3KX76RLG.js";
8
- import "../chunk-7JEP3MFY.js";
9
- import "../chunk-NNB67XA2.js";
10
- import "../chunk-7EONYVI5.js";
11
- import "../chunk-KBTTEX7Q.js";
12
- import "../chunk-R2VVFAIN.js";
12
+ Progression,
13
+ Rhythm,
14
+ Score,
15
+ Tempo,
16
+ Timeline,
17
+ Tuning,
18
+ Voicing
19
+ } from "../chunk-PKFNUHDY.js";
20
+ import "../chunk-2LCPM3EG.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 };