@libraz/libcantus 0.9.3 → 0.9.5

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 (201) hide show
  1. package/README.md +29 -20
  2. package/README_ja.md +268 -0
  3. package/dist/analyze/index.cjs +39 -1947
  4. package/dist/analyze/index.cjs.map +1 -1
  5. package/dist/analyze/index.d.cts +161 -91
  6. package/dist/analyze/index.d.ts +161 -91
  7. package/dist/analyze/index.js +19 -8
  8. package/dist/chunk-2A2QMA74.cjs +261 -0
  9. package/dist/chunk-2A2QMA74.cjs.map +1 -0
  10. package/dist/chunk-2PTFGVD7.js +261 -0
  11. package/dist/chunk-2PTFGVD7.js.map +1 -0
  12. package/dist/chunk-357ZDPVU.cjs +162 -0
  13. package/dist/chunk-357ZDPVU.cjs.map +1 -0
  14. package/dist/chunk-3KX76RLG.js +1548 -0
  15. package/dist/chunk-3KX76RLG.js.map +1 -0
  16. package/dist/chunk-4VZ5MZAM.cjs +889 -0
  17. package/dist/chunk-4VZ5MZAM.cjs.map +1 -0
  18. package/dist/{chunk-C5XYKUVG.js → chunk-7EONYVI5.js} +471 -171
  19. package/dist/chunk-7EONYVI5.js.map +1 -0
  20. package/dist/{chunk-IT2O4XFE.js → chunk-7JEP3MFY.js} +42 -34
  21. package/dist/chunk-7JEP3MFY.js.map +1 -0
  22. package/dist/{chunk-4MHA432G.js → chunk-AID75RN3.js} +572 -250
  23. package/dist/chunk-AID75RN3.js.map +1 -0
  24. package/dist/chunk-BSLTLGM3.cjs +497 -0
  25. package/dist/chunk-BSLTLGM3.cjs.map +1 -0
  26. package/dist/chunk-CU6VG2YM.cjs +109 -0
  27. package/dist/chunk-CU6VG2YM.cjs.map +1 -0
  28. package/dist/{chunk-EH6EM37U.js → chunk-DZMHIGI4.js} +81 -59
  29. package/dist/chunk-DZMHIGI4.js.map +1 -0
  30. package/dist/{chunk-AKLYPWIN.js → chunk-EDOTEABK.js} +45 -19
  31. package/dist/chunk-EDOTEABK.js.map +1 -0
  32. package/dist/{chunk-2ZWMSJH6.js → chunk-HN2OEUN2.js} +7 -4
  33. package/dist/chunk-HN2OEUN2.js.map +1 -0
  34. package/dist/{chunk-MIWO425M.js → chunk-KBTTEX7Q.js} +128 -43
  35. package/dist/chunk-KBTTEX7Q.js.map +1 -0
  36. package/dist/chunk-KQN2ZYND.cjs +724 -0
  37. package/dist/chunk-KQN2ZYND.cjs.map +1 -0
  38. package/dist/chunk-MPTVJIVG.cjs +3176 -0
  39. package/dist/chunk-MPTVJIVG.cjs.map +1 -0
  40. package/dist/chunk-MTMZTMWM.cjs +53 -0
  41. package/dist/chunk-MTMZTMWM.cjs.map +1 -0
  42. package/dist/{chunk-CHMXELDS.js → chunk-NNB67XA2.js} +372 -197
  43. package/dist/chunk-NNB67XA2.js.map +1 -0
  44. package/dist/chunk-OL3IHHSJ.cjs +1204 -0
  45. package/dist/chunk-OL3IHHSJ.cjs.map +1 -0
  46. package/dist/chunk-PI3UXRWK.cjs +528 -0
  47. package/dist/chunk-PI3UXRWK.cjs.map +1 -0
  48. package/dist/chunk-R2VVFAIN.js +528 -0
  49. package/dist/chunk-R2VVFAIN.js.map +1 -0
  50. package/dist/chunk-T64C7ZD7.cjs +1 -0
  51. package/dist/chunk-T64C7ZD7.cjs.map +1 -0
  52. package/dist/chunk-WFDXOLUB.cjs +337 -0
  53. package/dist/chunk-WFDXOLUB.cjs.map +1 -0
  54. package/dist/chunk-WTAN4ACG.cjs +1548 -0
  55. package/dist/chunk-WTAN4ACG.cjs.map +1 -0
  56. package/dist/chunk-YFJXS3AU.cjs +33 -0
  57. package/dist/chunk-YFJXS3AU.cjs.map +1 -0
  58. package/dist/{chunk-GOAW4VYL.js → chunk-YUE6TJ4M.js} +315 -145
  59. package/dist/chunk-YUE6TJ4M.js.map +1 -0
  60. package/dist/{chunk-62QZKCJQ.js → chunk-ZGLJM4A4.js} +10 -6
  61. package/dist/chunk-ZGLJM4A4.js.map +1 -0
  62. package/dist/core/index.cjs +140 -647
  63. package/dist/core/index.cjs.map +1 -1
  64. package/dist/core/index.d.cts +313 -41
  65. package/dist/core/index.d.ts +313 -41
  66. package/dist/core/index.js +64 -16
  67. package/dist/{function-DVH4Eusr.d.ts → function-CxixTB02.d.cts} +122 -10
  68. package/dist/{function-DYt4iKsn.d.cts → function-DTCt675z.d.ts} +122 -10
  69. package/dist/generate/index.cjs +28 -4085
  70. package/dist/generate/index.cjs.map +1 -1
  71. package/dist/generate/index.d.cts +374 -66
  72. package/dist/generate/index.d.ts +374 -66
  73. package/dist/generate/index.js +23 -9
  74. package/dist/{index-Jc0Ryi79.d.ts → index-B2Ulxxpo.d.cts} +21 -5
  75. package/dist/{index-CpOsP1y9.d.cts → index-BkYJ0xMq.d.cts} +18 -17
  76. package/dist/{index-CxqBQtH1.d.cts → index-BuaB-ypt.d.ts} +21 -5
  77. package/dist/index-CAN7v-kw.d.ts +199 -0
  78. package/dist/{index-Bt4tOUD9.d.ts → index-COw1Ky9g.d.ts} +93 -8
  79. package/dist/{index-Dikst44v.d.cts → index-Cfx8xgH0.d.ts} +14 -11
  80. package/dist/{index-DxvARIP2.d.ts → index-DRtIhlJj.d.ts} +18 -17
  81. package/dist/{index-Cl7mhOFM.d.cts → index-DXd9JikN.d.cts} +92 -10
  82. package/dist/{index-Cl7mhOFM.d.ts → index-DXd9JikN.d.ts} +92 -10
  83. package/dist/index-alrRninU.d.cts +199 -0
  84. package/dist/{index-BNlGP86A.d.cts → index-oTQbYYIs.d.cts} +93 -8
  85. package/dist/index-tR9jTn26.d.cts +275 -0
  86. package/dist/index-tR9jTn26.d.ts +275 -0
  87. package/dist/{index-Bg5dYMmZ.d.ts → index-x2vcsduE.d.cts} +14 -11
  88. package/dist/index.cjs +429 -7383
  89. package/dist/index.cjs.map +1 -1
  90. package/dist/index.d.cts +15 -15
  91. package/dist/index.d.ts +15 -15
  92. package/dist/index.js +121 -27
  93. package/dist/model/index.cjs +8 -2562
  94. package/dist/model/index.cjs.map +1 -1
  95. package/dist/model/index.d.cts +471 -81
  96. package/dist/model/index.d.ts +471 -81
  97. package/dist/model/index.js +6 -7
  98. package/dist/styled-Bl0ZK28h.d.ts +543 -0
  99. package/dist/styled-Crv6SA4S.d.cts +543 -0
  100. package/dist/theory/index.cjs +172 -1822
  101. package/dist/theory/index.cjs.map +1 -1
  102. package/dist/theory/index.d.cts +151 -233
  103. package/dist/theory/index.d.ts +151 -233
  104. package/dist/theory/index.js +30 -7
  105. package/dist/{types-MGP29r3t.d.cts → types-BN6_Q9Kl.d.cts} +11 -2
  106. package/dist/{types-MGP29r3t.d.ts → types-BN6_Q9Kl.d.ts} +11 -2
  107. package/package.json +34 -13
  108. package/dist/chunk-2ZWMSJH6.js.map +0 -1
  109. package/dist/chunk-4MHA432G.js.map +0 -1
  110. package/dist/chunk-62QZKCJQ.js.map +0 -1
  111. package/dist/chunk-AKLYPWIN.js.map +0 -1
  112. package/dist/chunk-C5XYKUVG.js.map +0 -1
  113. package/dist/chunk-CHMXELDS.js.map +0 -1
  114. package/dist/chunk-DYWFNC4A.js +0 -152
  115. package/dist/chunk-DYWFNC4A.js.map +0 -1
  116. package/dist/chunk-EH6EM37U.js.map +0 -1
  117. package/dist/chunk-FBQK3ZQN.js +0 -131
  118. package/dist/chunk-FBQK3ZQN.js.map +0 -1
  119. package/dist/chunk-GOAW4VYL.js.map +0 -1
  120. package/dist/chunk-I5R7ZBJS.js +0 -202
  121. package/dist/chunk-I5R7ZBJS.js.map +0 -1
  122. package/dist/chunk-IT2O4XFE.js.map +0 -1
  123. package/dist/chunk-MIWO425M.js.map +0 -1
  124. package/dist/chunk-SGU7SPLK.js +0 -924
  125. package/dist/chunk-SGU7SPLK.js.map +0 -1
  126. package/dist/index-CGMZNCx6.d.cts +0 -140
  127. package/dist/index-CGMZNCx6.d.ts +0 -140
  128. package/dist/index-CnZCo29u.d.cts +0 -108
  129. package/dist/index-JnF4v9bx.d.ts +0 -108
  130. package/dist/styled-DZ7GjShb.d.ts +0 -282
  131. package/dist/styled-ZTbdaVFM.d.cts +0 -282
  132. package/src/analyze/arrange/index.ts +0 -21
  133. package/src/analyze/arrange/internal.ts +0 -127
  134. package/src/analyze/arrange/tension.ts +0 -199
  135. package/src/analyze/arrange/tracks.ts +0 -312
  136. package/src/analyze/detect/index.ts +0 -272
  137. package/src/analyze/functional/borrowed.ts +0 -84
  138. package/src/analyze/functional/cadence.ts +0 -66
  139. package/src/analyze/functional/function.ts +0 -184
  140. package/src/analyze/functional/index.ts +0 -23
  141. package/src/analyze/functional/internal.ts +0 -29
  142. package/src/analyze/functional/roman.ts +0 -402
  143. package/src/analyze/index.ts +0 -49
  144. package/src/analyze/timeline/index.ts +0 -451
  145. package/src/analyze/voice/index.ts +0 -339
  146. package/src/core/event-index/index.ts +0 -104
  147. package/src/core/index.ts +0 -61
  148. package/src/core/interval/index.ts +0 -81
  149. package/src/core/meter/index.ts +0 -302
  150. package/src/core/pitch/index.ts +0 -311
  151. package/src/core/random/index.ts +0 -76
  152. package/src/core/tuning/index.ts +0 -186
  153. package/src/core/types.ts +0 -29
  154. package/src/core/validation/index.ts +0 -119
  155. package/src/generate/bass/index.ts +0 -373
  156. package/src/generate/countermelody/index.ts +0 -470
  157. package/src/generate/drums/beat.ts +0 -266
  158. package/src/generate/drums/euclid.ts +0 -65
  159. package/src/generate/drums/fills.ts +0 -356
  160. package/src/generate/drums/ghost.ts +0 -119
  161. package/src/generate/drums/hihat.ts +0 -285
  162. package/src/generate/drums/hit.ts +0 -31
  163. package/src/generate/drums/index.ts +0 -361
  164. package/src/generate/drums/internal.ts +0 -257
  165. package/src/generate/drums/kick.ts +0 -160
  166. package/src/generate/drums/percussion.ts +0 -121
  167. package/src/generate/drums/rng.ts +0 -7
  168. package/src/generate/drums/swing.ts +0 -71
  169. package/src/generate/groove/index.ts +0 -351
  170. package/src/generate/harmonize/index.ts +0 -451
  171. package/src/generate/index.ts +0 -58
  172. package/src/generate/motif/index.ts +0 -422
  173. package/src/generate/progression/index.ts +0 -362
  174. package/src/generate/reharmony/index.ts +0 -323
  175. package/src/generate/rhythm/index.ts +0 -175
  176. package/src/index.ts +0 -13
  177. package/src/model/chord.ts +0 -442
  178. package/src/model/index.ts +0 -15
  179. package/src/model/interval.ts +0 -82
  180. package/src/model/key.ts +0 -266
  181. package/src/model/note.ts +0 -176
  182. package/src/model/progression.ts +0 -161
  183. package/src/model/shared.ts +0 -12
  184. package/src/theory/chord/index.ts +0 -375
  185. package/src/theory/chordscale/index.ts +0 -374
  186. package/src/theory/counterpoint/index.ts +0 -230
  187. package/src/theory/harmony/index.ts +0 -77
  188. package/src/theory/index.ts +0 -112
  189. package/src/theory/safety/index.ts +0 -488
  190. package/src/theory/scale/degrees.ts +0 -123
  191. package/src/theory/scale/index.ts +0 -28
  192. package/src/theory/scale/key.ts +0 -56
  193. package/src/theory/scale/masks.ts +0 -153
  194. package/src/theory/spelling/index.ts +0 -249
  195. package/src/theory/symbol/index.ts +0 -268
  196. package/src/theory/voicing/index.ts +0 -5
  197. package/src/theory/voicing/internal.ts +0 -168
  198. package/src/theory/voicing/leading.ts +0 -112
  199. package/src/theory/voicing/satb.ts +0 -216
  200. package/src/theory/voicing/styled.ts +0 -199
  201. package/tsconfig.json +0 -23
@@ -1,40 +1,154 @@
1
- import { N as NoteEvent } from '../types-MGP29r3t.js';
2
- export { K as KeyScale } from '../types-MGP29r3t.js';
3
- import { T as TimeSignature } from '../index-Cl7mhOFM.js';
4
- export { B as BarPosition, b as barPositionToBeat, a as beatToBarPosition, c as beatsPerBar, f as formatTimeSignature, i as isCompound, d as isStrongBeat, m as metricWeight, p as parseTimeSignature, e as pulsesPerBar, t as tuplet } from '../index-Cl7mhOFM.js';
5
- export { N as NoteData, S as SpelledInterval, f as formatNote, m as midiToNote, n as noteToMidi, a as noteToPitchClass, p as parseNote, s as spelledInterval } from '../index-CGMZNCx6.js';
1
+ import { N as NoteEvent } from '../types-BN6_Q9Kl.js';
2
+ export { K as KeyScale } from '../types-BN6_Q9Kl.js';
3
+ import { T as TimeSignature } from '../index-DXd9JikN.js';
4
+ export { B as BarPosition, b as barPositionToBeat, a as barPositionToPulse, c as beatToBarPosition, d as beatsPerBar, f as formatBarPosition, e as formatTimeSignature, i as isCompound, g as isStrongBeat, m as metricWeight, p as parseTimeSignature, h as pulseBeats, j as pulsesPerBar, t as tuplet } from '../index-DXd9JikN.js';
5
+ export { I as IntervalQualityLabel, N as NoteData, S as SpelledInterval, d as diatonicLetterOf, f as formatNote, i as intervalSemitones, m as midiToNote, n as naturalPitchClassOf, a as noteToMidi, b as noteToPitchClass, p as parseInterval, c as parseNote, e as pitchClassOf, s as spelledInterval, t as transposeByInterval, g as transposeNote } from '../index-tR9jTn26.js';
6
6
 
7
- /** A validated note retaining its position in the caller's original array. */
7
+ /**
8
+ * The library's error taxonomy.
9
+ *
10
+ * Every failure this library raises falls into one of three kinds, and the kind
11
+ * decides what a caller can do about it. Batch-voicing a lead sheet, for
12
+ * instance, has to tell "fix the input" apart from "loosen the constraints",
13
+ * and a message string is not a contract.
14
+ *
15
+ * The classes extend the built-in error types a caller would otherwise catch —
16
+ * a rejected argument is still a `RangeError` — so the `code` narrows an
17
+ * existing category rather than replacing it.
18
+ */
19
+ /**
20
+ * What kind of failure an error reports.
21
+ *
22
+ * - `INVALID_INPUT`: an argument is malformed or out of range. The caller's
23
+ * input must change.
24
+ * - `NO_SOLUTION`: the input is valid but nothing satisfies the constraints.
25
+ * The constraints must change, or the failure must be accepted.
26
+ * - `BUDGET_EXCEEDED`: the requested work is larger than the synchronous
27
+ * generation budget. The request must be smaller, or the budget larger.
28
+ *
29
+ * @category Core
30
+ */
31
+ type LibcantusErrorCode = 'INVALID_INPUT' | 'NO_SOLUTION' | 'BUDGET_EXCEEDED';
32
+ /**
33
+ * A rejected argument: malformed, out of range, or naming something unknown.
34
+ *
35
+ * @category Core
36
+ */
37
+ declare class InvalidInputError extends RangeError {
38
+ readonly code: "INVALID_INPUT";
39
+ readonly name = "InvalidInputError";
40
+ }
41
+ /**
42
+ * A valid request with no answer: no voicing fits the given ranges, no chord
43
+ * matches the pitches, no preset claims the style.
44
+ *
45
+ * @category Core
46
+ */
47
+ declare class NoSolutionError extends Error {
48
+ readonly code: "NO_SOLUTION";
49
+ readonly name = "NoSolutionError";
50
+ /**
51
+ * Where in a sequence the failure occurred, when the operation was working
52
+ * through one — the chord index of a progression, say.
53
+ */
54
+ readonly at: number | undefined;
55
+ constructor(message: string, options?: {
56
+ at?: number;
57
+ });
58
+ }
59
+ /**
60
+ * Work that would exceed the synchronous generation budget.
61
+ *
62
+ * @category Core
63
+ */
64
+ declare class BudgetExceededError extends RangeError {
65
+ readonly code: "BUDGET_EXCEEDED";
66
+ readonly name = "BudgetExceededError";
67
+ }
68
+ /**
69
+ * Whether a caught value is one of this library's coded errors.
70
+ *
71
+ * @param value The caught value.
72
+ * @returns True when it carries a {@link LibcantusErrorCode}.
73
+ * @example
74
+ * ```ts
75
+ * import { isLibcantusError, voiceChord, parseChordSymbol } from '@libraz/libcantus';
76
+ * try {
77
+ * voiceChord(parseChordSymbol('C'), { ranges: [] });
78
+ * } catch (error) {
79
+ * if (isLibcantusError(error) && error.code === 'NO_SOLUTION') {
80
+ * // loosen the constraints rather than blaming the input
81
+ * }
82
+ * }
83
+ * ```
84
+ * @category Core
85
+ */
86
+ declare function isLibcantusError(value: unknown): value is InvalidInputError | NoSolutionError | BudgetExceededError;
87
+
88
+ /**
89
+ * A validated note retaining its position in the caller's original array.
90
+ *
91
+ * @category Core
92
+ */
8
93
  type IndexedNoteEvent = {
9
- note: NoteEvent;
94
+ note: Readonly<NoteEvent>;
10
95
  originalIndex: number;
11
96
  endBeat: number;
12
97
  };
13
- /** Binary-searchable, stable-sorted index over note onsets and active spans. */
98
+ /**
99
+ * Which note wins when several sound from the same onset.
100
+ *
101
+ * `'highest'` and `'lowest'` name a voice, so the answer does not depend on the
102
+ * order the caller happened to store the chord in; `'last'` takes the one
103
+ * latest in the input array.
104
+ *
105
+ * @category Core
106
+ */
107
+ type OnsetTieBreak = 'highest' | 'lowest' | 'last';
108
+ /**
109
+ * Binary-searchable, stable-sorted index over note onsets and active spans.
110
+ *
111
+ * @category Core
112
+ */
14
113
  type NoteEventIndex = {
15
- notes: IndexedNoteEvent[];
16
- /** Latest-onset note sounding at `beat`, with later input order winning ties. */
114
+ notes: readonly IndexedNoteEvent[];
115
+ /**
116
+ * Latest-onset note sounding at `beat`. Simultaneous onsets are resolved by
117
+ * the index's {@link OnsetTieBreak}.
118
+ */
17
119
  at: (beat: number) => IndexedNoteEvent | undefined;
18
- /** Whether one or more notes attack at `beat`. */
120
+ /** Whether one or more sounding notes attack at `beat`. */
19
121
  attacksAt: (beat: number) => boolean;
20
- /** Unique attack beats strictly inside `(startBeat, endBeat)`. */
122
+ /** Unique sounding-note attack beats strictly inside `(startBeat, endBeat)`. */
21
123
  onsetsBetween: (startBeat: number, endBeat: number) => number[];
22
124
  };
23
125
  /**
24
126
  * Validate and stable-sort note events once, then expose logarithmic onset and
25
127
  * active-note lookups. Non-positive-duration notes may be retained for callers
26
128
  * that intentionally filter them later, but never count as sounding.
129
+ *
130
+ * @category Core
27
131
  */
28
- declare function createNoteEventIndex(events: NoteEvent[], options?: {
132
+ declare function createNoteEventIndex(events: readonly NoteEvent[], options?: {
29
133
  allowNonPositiveDuration?: boolean;
134
+ tieBreak?: OnsetTieBreak;
135
+ budget?: number;
136
+ /** What the events are, for the validation error message. */
137
+ name?: string;
30
138
  }): NoteEventIndex;
31
139
 
32
140
  /**
33
- * Counterpoint classification of a harmonic interval.
141
+ * Counterpoint classification of a harmonic interval by consonance.
142
+ *
143
+ * Distinct from a spelled interval's quality label — see
144
+ * {@link IntervalQualityLabel}, which names the `'P'` / `'M'` / `'m'` / `'A'` /
145
+ * `'d'` spelling of an interval rather than how it sounds against another
146
+ * voice.
34
147
  *
148
+ * @see {@link IntervalQualityLabel}
35
149
  * @category Pitch & Intervals
36
150
  */
37
- declare enum IntervalQuality {
151
+ declare enum ConsonanceClass {
38
152
  PerfectConsonance = 0,
39
153
  ImperfectConsonance = 1,
40
154
  Dissonance = 2
@@ -52,16 +166,22 @@ declare enum IntervalQuality {
52
166
  * @returns The counterpoint quality of the interval.
53
167
  * @example
54
168
  * ```ts
55
- * import { classifyInterval, IntervalQuality } from '@libraz/libcantus';
56
- * classifyInterval(7); // IntervalQuality.PerfectConsonance
57
- * classifyInterval(5); // IntervalQuality.Dissonance (two-voice)
58
- * classifyInterval(5, false); // IntervalQuality.ImperfectConsonance
169
+ * import { classifyInterval, ConsonanceClass } from '@libraz/libcantus';
170
+ * classifyInterval(7); // ConsonanceClass.PerfectConsonance
171
+ * classifyInterval(5); // ConsonanceClass.Dissonance (two-voice)
172
+ * classifyInterval(5, false); // ConsonanceClass.ImperfectConsonance
59
173
  * ```
60
174
  * @category Pitch & Intervals
61
175
  */
62
- declare function classifyInterval(semitones: number, twoVoice?: boolean): IntervalQuality;
176
+ declare function classifyInterval(semitones: number, twoVoice?: boolean): ConsonanceClass;
63
177
  /**
64
- * Test whether an interval is a perfect interval (unison/octave or fifth).
178
+ * Test whether an interval is a perfect consonance: the unison/octave or the
179
+ * fifth.
180
+ *
181
+ * The perfect fourth is deliberately excluded. This is the predicate the
182
+ * parallel-motion rules are written against, where the fourth behaves as a
183
+ * dissonance between two voices; {@link classifyInterval} is the general
184
+ * classifier, and it treats the fourth as context-dependent.
65
185
  *
66
186
  * @param semitones Interval size in semitones (may be negative or compound).
67
187
  * @returns True for the unison/octave (0) and the perfect fifth (7) mod 12.
@@ -136,11 +256,11 @@ declare function createRng(seed: number): Rng;
136
256
  */
137
257
  type Tuning = {
138
258
  /** Step index (MIDI number when `divisions` is 12) whose frequency is `refFreq`. */
139
- refStep: number;
259
+ readonly refStep: number;
140
260
  /** Frequency in Hz of `refStep`. */
141
- refFreq: number;
261
+ readonly refFreq: number;
142
262
  /** Equal divisions of the octave (12 standard; e.g. 19 or 31 for microtonal). */
143
- divisions: number;
263
+ readonly divisions: number;
144
264
  };
145
265
  /**
146
266
  * Standard twelve-tone equal temperament, A4 (MIDI 69) = 440 Hz.
@@ -189,6 +309,67 @@ declare function frequencyOf(step: number, tuning?: Tuning): number;
189
309
  * @category Pitch & Intervals
190
310
  */
191
311
  declare function nearestStep(freq: number, tuning?: Tuning): number;
312
+ /**
313
+ * Step index of a frequency under a tuning, unrounded.
314
+ *
315
+ * The exact inverse of {@link frequencyOf}. {@link nearestStep} rounds it,
316
+ * which discards how far off the pitch actually is — the figure a tuner
317
+ * display, a pitch-bend amount, or an intonation check is built on.
318
+ *
319
+ * @param freq Frequency in Hz.
320
+ * @param tuning The tuning (default 12-TET).
321
+ * @returns The fractional step index.
322
+ * @example
323
+ * ```ts
324
+ * import { stepOf } from '@libraz/libcantus';
325
+ * stepOf(442); // slightly above 69, the step for A440
326
+ * ```
327
+ * @category Pitch & Intervals
328
+ */
329
+ declare function stepOf(freq: number, tuning?: Tuning): number;
330
+ /**
331
+ * How far a frequency sits from its nearest step, in cents.
332
+ *
333
+ * Positive means sharp of the step, negative flat.
334
+ *
335
+ * @param freq Frequency in Hz.
336
+ * @param tuning The tuning (default 12-TET).
337
+ * @returns The signed deviation in cents.
338
+ * @example
339
+ * ```ts
340
+ * import { centsFromNearestStep } from '@libraz/libcantus';
341
+ * Math.round(centsFromNearestStep(442)); // 8
342
+ * ```
343
+ * @category Pitch & Intervals
344
+ */
345
+ declare function centsFromNearestStep(freq: number, tuning?: Tuning): number;
346
+ /**
347
+ * Steps spanned by an interval in cents, unrounded — the inverse of
348
+ * {@link centsOfSteps}.
349
+ *
350
+ * @param cents The interval in cents.
351
+ * @param tuning The tuning (default 12-TET).
352
+ * @returns The fractional step count.
353
+ * @category Pitch & Intervals
354
+ */
355
+ declare function stepsOfCents(cents: number, tuning?: Tuning): number;
356
+ /**
357
+ * The frequency ratio an interval in cents spans — the inverse of
358
+ * {@link ratioToCents}.
359
+ *
360
+ * Multiply a frequency by this to move it by that many cents, which is how a
361
+ * cents offset (a pitch-bend spec, a tuning table entry) is applied.
362
+ *
363
+ * @param cents The interval in cents.
364
+ * @returns The frequency ratio.
365
+ * @example
366
+ * ```ts
367
+ * import { centsToRatio } from '@libraz/libcantus';
368
+ * 440 * centsToRatio(14); // A440 raised by 14 cents
369
+ * ```
370
+ * @category Pitch & Intervals
371
+ */
372
+ declare function centsToRatio(cents: number): number;
192
373
  /**
193
374
  * Interval in cents between two frequencies.
194
375
  *
@@ -223,7 +404,7 @@ declare function ratioToCents(numerator: number, denominator: number): number;
223
404
  *
224
405
  * @category Pitch & Intervals
225
406
  */
226
- declare const JUST_RATIOS: Record<number, [number, number]>;
407
+ declare const JUST_RATIOS: Readonly<Record<number, readonly [number, number]>>;
227
408
  /**
228
409
  * Cents by which a five-limit just interval departs from its 12-TET tempering
229
410
  * (positive means the just interval is wider).
@@ -235,28 +416,119 @@ declare const JUST_RATIOS: Record<number, [number, number]>;
235
416
  */
236
417
  declare function justDeviationCents(semitoneClass: number): number;
237
418
 
238
- /** Default upper bound for synchronous event/window/candidate generation. */
419
+ /**
420
+ * Default upper bound for synchronous event/window/candidate generation.
421
+ *
422
+ * @category Core
423
+ */
239
424
  declare const DEFAULT_GENERATION_BUDGET = 1000000;
240
- /** Require a finite JavaScript number and return it unchanged. */
425
+ /**
426
+ * Require a finite JavaScript number and return it unchanged.
427
+ *
428
+ * @category Core
429
+ */
241
430
  declare function assertFiniteNumber(value: number, name: string): number;
242
- /** Require an integer in the inclusive range `[min, max]`. */
431
+ /**
432
+ * Require an integer in the inclusive range `[min, max]`.
433
+ *
434
+ * @category Core
435
+ */
243
436
  declare function assertInteger(value: number, name: string, min?: number, max?: number): number;
244
- /** Require a positive safe integer, optionally capped by `max`. */
437
+ /** Require an integer MIDI pitch in the inclusive range 0..127. */
438
+ declare function assertMidiPitch(value: number, name?: string): number;
439
+ /** Clamp an integer MIDI pitch to the inclusive range 0..127. */
440
+ declare function clampToMidi(value: number, name?: string): number;
441
+ /** Require a bounded integer scale/chord degree. */
442
+ declare function assertDegree(value: number, name?: string): number;
443
+ /** Require a finite semitone offset before pitch-class reduction. */
444
+ declare function assertFiniteSemitones(value: number, name?: string): number;
445
+ /**
446
+ * Drop the notes that never sound.
447
+ *
448
+ * A MIDI or DAW import routinely carries zero-length artefacts. Every entry
449
+ * point in this library ignores them, but a caller holding such an array still
450
+ * has to decide what to do with it before comparing note counts or indices;
451
+ * this is the one filter to apply.
452
+ *
453
+ * @param events The note events to filter.
454
+ * @returns A new array containing only the notes with a positive duration.
455
+ * @example
456
+ * ```ts
457
+ * import { dropSilentNotes } from '@libraz/libcantus';
458
+ * dropSilentNotes([{ pitch: 60, startBeat: 0, durationBeat: 0 }]); // []
459
+ * ```
460
+ * @category Core
461
+ */
462
+ declare function dropSilentNotes(events: readonly NoteEvent[]): NoteEvent[];
463
+ /** Alias that makes the shared positive-duration policy explicit at API entrances. */
464
+ declare const soundingNotesOnly: typeof dropSilentNotes;
465
+ /**
466
+ * Require a value to be one of a fixed set of names.
467
+ *
468
+ * TypeScript checks string-union options at compile time only, so a value that
469
+ * arrives from JSON, a config file, or a JavaScript caller reaches the engine
470
+ * unchecked and is then read against a table that has no entry for it —
471
+ * producing a silent `undefined`, a NaN velocity, or a crash far from the call.
472
+ *
473
+ * @param value The value to check.
474
+ * @param allowed Every accepted name.
475
+ * @param name What the value is, for the error message.
476
+ * @returns The value, narrowed to the allowed union.
477
+ * @throws If the value is not one of `allowed`.
478
+ *
479
+ * @category Core
480
+ */
481
+ declare function assertOneOf<const T extends string>(value: unknown, allowed: readonly T[], name: string): T;
482
+ /**
483
+ * Require a positive safe integer, optionally capped by `max`.
484
+ *
485
+ * @category Core
486
+ */
245
487
  declare function assertPositiveInt(value: number, name: string, max?: number): number;
246
- /** Require a finite number in the inclusive range `[min, max]`. */
488
+ /**
489
+ * Require a finite number in the inclusive range `[min, max]`.
490
+ *
491
+ * @category Core
492
+ */
247
493
  declare function assertRange(value: number, min: number, max: number, name: string): number;
248
- /** Reject work estimates that would exceed a synchronous generation budget. */
249
- declare function assertGenerationBudget(estimated: number, name: string, limit?: number): number;
250
- /** Validate a time signature, including additive grouping, before any early return. */
494
+ /**
495
+ * Reject work estimates that would exceed a synchronous generation budget.
496
+ *
497
+ * @category Core
498
+ */
499
+ declare function assertGenerationBudget(estimated: number, name: string, limit?: number | undefined): number;
500
+ /**
501
+ * Validate a time signature, including additive grouping, before any early return.
502
+ *
503
+ * @category Core
504
+ */
251
505
  declare function assertTimeSignature(ts: TimeSignature, name?: string): TimeSignature;
252
- /** Validate the finite fields of one timeline note event. */
253
- declare function assertNoteEvent(event: NoteEvent, name?: string, options?: {
254
- allowNonPositiveDuration?: boolean;
255
- }): NoteEvent;
256
- /** Validate an event array and its allocation budget without copying it. */
257
- declare function assertNoteEvents(events: NoteEvent[], name?: string, options?: {
506
+ /**
507
+ * How strictly {@link assertNoteEvent} and {@link assertNoteEvents} read an
508
+ * event array.
509
+ *
510
+ * @category Core
511
+ */
512
+ type NoteEventAssertOptions = {
513
+ /**
514
+ * Accept notes that never sound. The analysis side does, so an array from a
515
+ * MIDI import can be validated before the zero-length artefacts are dropped.
516
+ */
258
517
  allowNonPositiveDuration?: boolean;
518
+ /** Upper bound on the event count; defaults to the generation budget. */
259
519
  budget?: number;
260
- }): NoteEvent[];
520
+ };
521
+ /**
522
+ * Validate the finite fields of one timeline note event.
523
+ *
524
+ * @category Core
525
+ */
526
+ declare function assertNoteEvent(event: NoteEvent, name?: string, options?: NoteEventAssertOptions): NoteEvent;
527
+ /**
528
+ * Validate an event array and its allocation budget without copying it.
529
+ *
530
+ * @category Core
531
+ */
532
+ declare function assertNoteEvents(events: readonly NoteEvent[], name?: string, options?: NoteEventAssertOptions): NoteEvent[];
261
533
 
262
- export { DEFAULT_GENERATION_BUDGET, type IndexedNoteEvent, IntervalQuality, JUST_RATIOS, NoteEvent, type NoteEventIndex, type Rng, TWELVE_TET, TimeSignature, type Tuning, assertFiniteNumber, assertGenerationBudget, assertInteger, assertNoteEvent, assertNoteEvents, assertPositiveInt, assertRange, assertTimeSignature, centsBetweenFreq, centsOfSteps, classifyInterval, createNoteEventIndex, createRng, edo, frequencyOf, isConsonantInterval, isPerfectInterval, justDeviationCents, nearestStep, ratioToCents };
534
+ export { BudgetExceededError, ConsonanceClass, DEFAULT_GENERATION_BUDGET, type IndexedNoteEvent, InvalidInputError, JUST_RATIOS, type LibcantusErrorCode, NoSolutionError, NoteEvent, type NoteEventAssertOptions, type NoteEventIndex, type OnsetTieBreak, type Rng, TWELVE_TET, TimeSignature, type Tuning, assertDegree, assertFiniteNumber, assertFiniteSemitones, assertGenerationBudget, assertInteger, assertMidiPitch, assertNoteEvent, assertNoteEvents, assertOneOf, assertPositiveInt, assertRange, assertTimeSignature, centsBetweenFreq, centsFromNearestStep, centsOfSteps, centsToRatio, clampToMidi, classifyInterval, createNoteEventIndex, createRng, dropSilentNotes, edo, frequencyOf, isConsonantInterval, isLibcantusError, isPerfectInterval, justDeviationCents, nearestStep, ratioToCents, soundingNotesOnly, stepOf, stepsOfCents };
@@ -2,92 +2,140 @@ import {
2
2
  JUST_RATIOS,
3
3
  TWELVE_TET,
4
4
  centsBetweenFreq,
5
+ centsFromNearestStep,
5
6
  centsOfSteps,
7
+ centsToRatio,
6
8
  edo,
7
9
  frequencyOf,
8
10
  justDeviationCents,
9
11
  nearestStep,
10
- ratioToCents
11
- } from "../chunk-AKLYPWIN.js";
12
+ ratioToCents,
13
+ stepOf,
14
+ stepsOfCents
15
+ } from "../chunk-EDOTEABK.js";
12
16
  import {
13
17
  createRng
14
- } from "../chunk-62QZKCJQ.js";
18
+ } from "../chunk-ZGLJM4A4.js";
15
19
  import {
16
20
  barPositionToBeat,
21
+ barPositionToPulse,
17
22
  beatToBarPosition,
18
23
  beatsPerBar,
19
24
  createNoteEventIndex,
25
+ formatBarPosition,
20
26
  formatTimeSignature,
21
27
  isCompound,
22
28
  isStrongBeat,
23
29
  metricWeight,
24
30
  parseTimeSignature,
31
+ pulseBeats,
25
32
  pulsesPerBar,
26
33
  tuplet
27
- } from "../chunk-I5R7ZBJS.js";
28
- import {
29
- formatNote,
30
- midiToNote,
31
- noteToMidi,
32
- noteToPitchClass,
33
- parseNote,
34
- spelledInterval
35
- } from "../chunk-DYWFNC4A.js";
34
+ } from "../chunk-2PTFGVD7.js";
36
35
  import {
36
+ BudgetExceededError,
37
+ ConsonanceClass,
37
38
  DEFAULT_GENERATION_BUDGET,
38
- IntervalQuality,
39
+ InvalidInputError,
40
+ NoSolutionError,
41
+ assertDegree,
39
42
  assertFiniteNumber,
43
+ assertFiniteSemitones,
40
44
  assertGenerationBudget,
41
45
  assertInteger,
46
+ assertMidiPitch,
42
47
  assertNoteEvent,
43
48
  assertNoteEvents,
49
+ assertOneOf,
44
50
  assertPositiveInt,
45
51
  assertRange,
46
52
  assertTimeSignature,
53
+ clampToMidi,
47
54
  classifyInterval,
55
+ diatonicLetterOf,
56
+ dropSilentNotes,
57
+ formatNote,
58
+ intervalSemitones,
48
59
  isConsonantInterval,
49
- isPerfectInterval
50
- } from "../chunk-FBQK3ZQN.js";
60
+ isLibcantusError,
61
+ isPerfectInterval,
62
+ midiToNote,
63
+ naturalPitchClassOf,
64
+ noteToMidi,
65
+ noteToPitchClass,
66
+ parseInterval,
67
+ parseNote,
68
+ pitchClassOf,
69
+ soundingNotesOnly,
70
+ spelledInterval,
71
+ transposeByInterval,
72
+ transposeNote
73
+ } from "../chunk-R2VVFAIN.js";
51
74
  export {
75
+ BudgetExceededError,
76
+ ConsonanceClass,
52
77
  DEFAULT_GENERATION_BUDGET,
53
- IntervalQuality,
78
+ InvalidInputError,
54
79
  JUST_RATIOS,
80
+ NoSolutionError,
55
81
  TWELVE_TET,
82
+ assertDegree,
56
83
  assertFiniteNumber,
84
+ assertFiniteSemitones,
57
85
  assertGenerationBudget,
58
86
  assertInteger,
87
+ assertMidiPitch,
59
88
  assertNoteEvent,
60
89
  assertNoteEvents,
90
+ assertOneOf,
61
91
  assertPositiveInt,
62
92
  assertRange,
63
93
  assertTimeSignature,
64
94
  barPositionToBeat,
95
+ barPositionToPulse,
65
96
  beatToBarPosition,
66
97
  beatsPerBar,
67
98
  centsBetweenFreq,
99
+ centsFromNearestStep,
68
100
  centsOfSteps,
101
+ centsToRatio,
102
+ clampToMidi,
69
103
  classifyInterval,
70
104
  createNoteEventIndex,
71
105
  createRng,
106
+ diatonicLetterOf,
107
+ dropSilentNotes,
72
108
  edo,
109
+ formatBarPosition,
73
110
  formatNote,
74
111
  formatTimeSignature,
75
112
  frequencyOf,
113
+ intervalSemitones,
76
114
  isCompound,
77
115
  isConsonantInterval,
116
+ isLibcantusError,
78
117
  isPerfectInterval,
79
118
  isStrongBeat,
80
119
  justDeviationCents,
81
120
  metricWeight,
82
121
  midiToNote,
122
+ naturalPitchClassOf,
83
123
  nearestStep,
84
124
  noteToMidi,
85
125
  noteToPitchClass,
126
+ parseInterval,
86
127
  parseNote,
87
128
  parseTimeSignature,
129
+ pitchClassOf,
130
+ pulseBeats,
88
131
  pulsesPerBar,
89
132
  ratioToCents,
133
+ soundingNotesOnly,
90
134
  spelledInterval,
135
+ stepOf,
136
+ stepsOfCents,
137
+ transposeByInterval,
138
+ transposeNote,
91
139
  tuplet
92
140
  };
93
141
  //# sourceMappingURL=index.js.map