@libraz/libcantus 0.9.0 → 0.9.2

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 (155) hide show
  1. package/README.md +25 -2
  2. package/dist/analyze/index.cjs +1697 -0
  3. package/dist/analyze/index.cjs.map +1 -0
  4. package/dist/analyze/index.d.cts +429 -0
  5. package/dist/analyze/index.d.ts +429 -0
  6. package/dist/analyze/index.js +51 -0
  7. package/dist/analyze/index.js.map +1 -0
  8. package/dist/chunk-5HTNMQW4.js +653 -0
  9. package/dist/chunk-5HTNMQW4.js.map +1 -0
  10. package/dist/chunk-7Y7WF64D.js +410 -0
  11. package/dist/chunk-7Y7WF64D.js.map +1 -0
  12. package/dist/chunk-A4532ZFR.js +259 -0
  13. package/dist/chunk-A4532ZFR.js.map +1 -0
  14. package/dist/chunk-BHUT2S5G.js +22 -0
  15. package/dist/chunk-BHUT2S5G.js.map +1 -0
  16. package/dist/chunk-CCBLVAPK.js +42 -0
  17. package/dist/chunk-CCBLVAPK.js.map +1 -0
  18. package/dist/chunk-COKTX2G5.js +907 -0
  19. package/dist/chunk-COKTX2G5.js.map +1 -0
  20. package/dist/chunk-DYWFNC4A.js +152 -0
  21. package/dist/chunk-DYWFNC4A.js.map +1 -0
  22. package/dist/chunk-GQKN5KDT.js +159 -0
  23. package/dist/chunk-GQKN5KDT.js.map +1 -0
  24. package/dist/chunk-LN7ZZMD2.js +530 -0
  25. package/dist/chunk-LN7ZZMD2.js.map +1 -0
  26. package/dist/chunk-MSWFZF7J.js +118 -0
  27. package/dist/chunk-MSWFZF7J.js.map +1 -0
  28. package/dist/chunk-R3S2LUBH.js +2722 -0
  29. package/dist/chunk-R3S2LUBH.js.map +1 -0
  30. package/dist/chunk-SDM3VJJ5.js +41 -0
  31. package/dist/chunk-SDM3VJJ5.js.map +1 -0
  32. package/dist/chunk-XTC3X6MS.js +816 -0
  33. package/dist/chunk-XTC3X6MS.js.map +1 -0
  34. package/dist/chunk-ZXW5YIWK.js +55 -0
  35. package/dist/chunk-ZXW5YIWK.js.map +1 -0
  36. package/dist/core/index.cjs +432 -0
  37. package/dist/core/index.cjs.map +1 -0
  38. package/dist/core/index.d.cts +210 -0
  39. package/dist/core/index.d.ts +210 -0
  40. package/dist/core/index.js +73 -0
  41. package/dist/core/index.js.map +1 -0
  42. package/dist/function-2bJW1Zp_.d.ts +187 -0
  43. package/dist/function-r2sh-jOO.d.cts +187 -0
  44. package/dist/generate/index.cjs +3787 -0
  45. package/dist/generate/index.cjs.map +1 -0
  46. package/dist/generate/index.d.cts +980 -0
  47. package/dist/generate/index.d.ts +980 -0
  48. package/dist/generate/index.js +52 -0
  49. package/dist/generate/index.js.map +1 -0
  50. package/dist/index-BMPxwjwV.d.ts +151 -0
  51. package/dist/index-BOBXBNwP.d.cts +157 -0
  52. package/dist/index-BdeQ1r_p.d.cts +56 -0
  53. package/dist/index-BreoJRw0.d.ts +127 -0
  54. package/dist/index-CGMZNCx6.d.cts +140 -0
  55. package/dist/index-CGMZNCx6.d.ts +140 -0
  56. package/dist/index-CM5W4rcm.d.ts +157 -0
  57. package/dist/index-CP3wAfEH.d.ts +56 -0
  58. package/dist/index-Cl7mhOFM.d.cts +164 -0
  59. package/dist/index-Cl7mhOFM.d.ts +164 -0
  60. package/dist/index-DZ1M21do.d.cts +127 -0
  61. package/dist/index-D_ZTUNKp.d.cts +151 -0
  62. package/dist/index.cjs +5277 -4893
  63. package/dist/index.cjs.map +1 -1
  64. package/dist/index.d.cts +14 -2621
  65. package/dist/index.d.ts +14 -2621
  66. package/dist/index.js +170 -6152
  67. package/dist/index.js.map +1 -1
  68. package/dist/model/index.cjs +2435 -0
  69. package/dist/model/index.cjs.map +1 -0
  70. package/dist/model/index.d.cts +630 -0
  71. package/dist/model/index.d.ts +630 -0
  72. package/dist/model/index.js +21 -0
  73. package/dist/model/index.js.map +1 -0
  74. package/dist/styled-BjXtOFNk.d.cts +282 -0
  75. package/dist/styled-D7BAx3S3.d.ts +282 -0
  76. package/dist/theory/index.cjs +1677 -0
  77. package/dist/theory/index.cjs.map +1 -0
  78. package/dist/theory/index.d.cts +535 -0
  79. package/dist/theory/index.d.ts +535 -0
  80. package/dist/theory/index.js +149 -0
  81. package/dist/theory/index.js.map +1 -0
  82. package/dist/types-MGP29r3t.d.cts +30 -0
  83. package/dist/types-MGP29r3t.d.ts +30 -0
  84. package/package.json +31 -1
  85. package/src/analyze/arrange/index.ts +21 -0
  86. package/src/analyze/arrange/internal.ts +125 -0
  87. package/src/analyze/arrange/tension.ts +187 -0
  88. package/src/analyze/arrange/tracks.ts +279 -0
  89. package/src/{detect → analyze/detect}/index.ts +82 -23
  90. package/src/analyze/functional/borrowed.ts +84 -0
  91. package/src/analyze/functional/cadence.ts +66 -0
  92. package/src/analyze/functional/function.ts +184 -0
  93. package/src/analyze/functional/index.ts +23 -0
  94. package/src/analyze/functional/internal.ts +29 -0
  95. package/src/analyze/functional/roman.ts +393 -0
  96. package/src/analyze/index.ts +49 -0
  97. package/src/{timeline → analyze/timeline}/index.ts +87 -24
  98. package/src/{analysis → analyze/voice}/index.ts +81 -12
  99. package/src/core/index.ts +47 -0
  100. package/src/{interval → core/interval}/index.ts +15 -1
  101. package/src/{meter → core/meter}/index.ts +108 -5
  102. package/src/{pitch → core/pitch}/index.ts +58 -3
  103. package/src/{random → core/random}/index.ts +13 -1
  104. package/src/{tuning → core/tuning}/index.ts +28 -1
  105. package/src/{bass → generate/bass}/index.ts +66 -17
  106. package/src/{countermelody → generate/countermelody}/index.ts +54 -24
  107. package/src/{drums → generate/drums}/fills.ts +31 -20
  108. package/src/{drums → generate/drums}/index.ts +127 -9
  109. package/src/{drums → generate/drums}/internal.ts +7 -1
  110. package/src/{drums → generate/drums}/rng.ts +2 -2
  111. package/src/{drums → generate/drums}/swing.ts +7 -2
  112. package/src/{groove → generate/groove}/index.ts +118 -22
  113. package/src/{harmonize → generate/harmonize}/index.ts +96 -23
  114. package/src/generate/index.ts +59 -0
  115. package/src/{motif → generate/motif}/index.ts +94 -17
  116. package/src/{progression → generate/progression}/index.ts +61 -27
  117. package/src/{reharmony → generate/reharmony}/index.ts +46 -15
  118. package/src/{rhythm → generate/rhythm}/index.ts +47 -13
  119. package/src/index.ts +130 -116
  120. package/src/model/chord.ts +423 -0
  121. package/src/model/index.ts +5 -947
  122. package/src/model/interval.ts +82 -0
  123. package/src/model/key.ts +266 -0
  124. package/src/model/note.ts +176 -0
  125. package/src/model/progression.ts +161 -0
  126. package/src/model/shared.ts +12 -0
  127. package/src/{chord → theory/chord}/index.ts +85 -4
  128. package/src/{chordscale → theory/chordscale}/index.ts +67 -9
  129. package/src/{counterpoint → theory/counterpoint}/index.ts +23 -2
  130. package/src/{harmony → theory/harmony}/index.ts +19 -2
  131. package/src/theory/index.ts +107 -0
  132. package/src/{safety → theory/safety}/index.ts +59 -12
  133. package/src/theory/scale/degrees.ts +123 -0
  134. package/src/theory/scale/index.ts +28 -0
  135. package/src/theory/scale/key.ts +56 -0
  136. package/src/theory/scale/masks.ts +153 -0
  137. package/src/{spelling → theory/spelling}/index.ts +21 -3
  138. package/src/{symbol → theory/symbol}/index.ts +91 -36
  139. package/src/theory/voicing/index.ts +5 -0
  140. package/src/theory/voicing/internal.ts +168 -0
  141. package/src/theory/voicing/leading.ts +112 -0
  142. package/src/theory/voicing/satb.ts +195 -0
  143. package/src/theory/voicing/styled.ts +176 -0
  144. package/src/arrange/index.ts +0 -409
  145. package/src/functional/index.ts +0 -602
  146. package/src/scale/index.ts +0 -215
  147. package/src/voicing/index.ts +0 -523
  148. /package/src/{types.ts → core/types.ts} +0 -0
  149. /package/src/{drums → generate/drums}/beat.ts +0 -0
  150. /package/src/{drums → generate/drums}/euclid.ts +0 -0
  151. /package/src/{drums → generate/drums}/ghost.ts +0 -0
  152. /package/src/{drums → generate/drums}/hihat.ts +0 -0
  153. /package/src/{drums → generate/drums}/hit.ts +0 -0
  154. /package/src/{drums → generate/drums}/kick.ts +0 -0
  155. /package/src/{drums → generate/drums}/percussion.ts +0 -0
@@ -0,0 +1,980 @@
1
+ import { T as TimeSignature } from '../index-Cl7mhOFM.js';
2
+ import { K as KeyScale, N as NoteEvent } from '../types-MGP29r3t.js';
3
+ import { C as Chord, a as ChordQuality, b as ChordSpan } from '../index-CM5W4rcm.js';
4
+ import { H as HarmonyRole } from '../index-CP3wAfEH.js';
5
+ import { b as ChordTimeline } from '../index-BMPxwjwV.js';
6
+ import { B as BorrowedSource, H as HarmonicFunction } from '../function-2bJW1Zp_.js';
7
+
8
+ /**
9
+ * Deterministic bass-line generation over a chord placement.
10
+ *
11
+ * Given a sequence of chord segments and a key, this builds a monophonic bass
12
+ * line in a chosen low register. Several idiomatic styles are supported, from a
13
+ * single held root per segment to a quarter-note walking line that leads by
14
+ * step into each chord change. All pitches are kept in a narrow bass band and
15
+ * consecutive notes move by small intervals; given a seed the output is fully
16
+ * reproducible.
17
+ *
18
+ * Positions and durations are measured in quarter-note beats, matching the
19
+ * library-wide convention.
20
+ */
21
+
22
+ /**
23
+ * A chord sounding over a half-open beat span `[startBeat, endBeat)`.
24
+ *
25
+ * @category Composition
26
+ */
27
+ type BassSegment = {
28
+ startBeat: number;
29
+ endBeat: number;
30
+ chord: Chord;
31
+ };
32
+ /**
33
+ * The bass-line idiom to generate.
34
+ *
35
+ * @category Composition
36
+ */
37
+ type BassStyle = 'root' | 'rootFifth' | 'pop' | 'walking' | 'arpeggio';
38
+ /**
39
+ * Options controlling {@link generateBassLine}.
40
+ *
41
+ * @category Composition
42
+ */
43
+ type BassLineOptions = {
44
+ /** Chord placement to follow; need not be pre-sorted. */
45
+ segments: BassSegment[];
46
+ /** Key/scale context, used for diatonic approach tones in `walking`. */
47
+ key: KeyScale;
48
+ /**
49
+ * Time signature; used for metric accents.
50
+ *
51
+ * @defaultValue `{ numerator: 4, denominator: 4 }`
52
+ */
53
+ ts?: TimeSignature;
54
+ /**
55
+ * Bass-line idiom.
56
+ *
57
+ * @defaultValue `'root'`
58
+ */
59
+ style?: BassStyle;
60
+ /**
61
+ * Target register as a base MIDI octave; roots land around `octave*12+12`.
62
+ *
63
+ * @defaultValue 2
64
+ */
65
+ octave?: number;
66
+ /**
67
+ * Seed for the deterministic PRNG.
68
+ *
69
+ * @defaultValue 0
70
+ */
71
+ seed?: number;
72
+ };
73
+ /**
74
+ * Generate a bass line following a chord placement.
75
+ *
76
+ * Each segment contributes notes in the chosen bass register per the selected
77
+ * style; consecutive notes are kept within roughly a fifth. Every note's
78
+ * duration extends to the next onset (the final note extends to the last
79
+ * segment's end). Given a seed the output is fully reproducible.
80
+ *
81
+ * @param opts Segments, key, and generation options.
82
+ * @returns Bass notes sorted by onset, non-overlapping.
83
+ *
84
+ * @example
85
+ * ```ts
86
+ * import { generateBassLine, makeChord, majorKey } from '@libraz/libcantus';
87
+ * const segments = [
88
+ * { startBeat: 0, endBeat: 4, chord: makeChord(0, 'maj') },
89
+ * { startBeat: 4, endBeat: 8, chord: makeChord(7, 'maj') },
90
+ * ];
91
+ * const notes = generateBassLine({ segments, key: majorKey(0), style: 'walking' });
92
+ * ```
93
+ *
94
+ * @category Composition
95
+ */
96
+ declare function generateBassLine(opts: BassLineOptions): NoteEvent[];
97
+
98
+ /**
99
+ * Options controlling {@link generateCounterMelody}.
100
+ *
101
+ * @category Voicing & Counterpoint
102
+ */
103
+ type CounterMelodyOptions = {
104
+ /** The lead line to write against, in ascending onset order. */
105
+ melody: NoteEvent[];
106
+ /** Chord sounding at an absolute beat position, or null when none applies. */
107
+ chordAt: (beat: number) => Chord | null;
108
+ /** Key/scale context for scale-tone decisions. */
109
+ key: KeyScale;
110
+ /**
111
+ * Meter used for strong-beat decisions.
112
+ *
113
+ * @defaultValue 4/4
114
+ */
115
+ ts?: TimeSignature;
116
+ /**
117
+ * Which side of the melody the counter line occupies.
118
+ *
119
+ * @defaultValue 'below'
120
+ */
121
+ register?: 'above' | 'below';
122
+ /**
123
+ * Onset strategy: `'complement'` moves where the melody holds or rests and
124
+ * reinforces some strong beats; `'follow'` mirrors melody onsets.
125
+ *
126
+ * @defaultValue 'complement'
127
+ */
128
+ rhythm?: 'complement' | 'follow';
129
+ /**
130
+ * Safety profile applied to candidate pitches.
131
+ *
132
+ * @defaultValue 'pop'
133
+ */
134
+ profile?: 'strict' | 'pop';
135
+ /** Lowest MIDI pitch the counter line may use (default derived from `register`). */
136
+ pitchLow?: number;
137
+ /** Highest MIDI pitch the counter line may use (default derived from `register`). */
138
+ pitchHigh?: number;
139
+ /**
140
+ * PRNG seed; the same seed always yields the same line.
141
+ *
142
+ * @defaultValue 0
143
+ */
144
+ seed?: number;
145
+ };
146
+ /**
147
+ * Generate a counter melody against a lead line.
148
+ *
149
+ * Onsets are chosen per `rhythm`: `'follow'` places one counter note on each
150
+ * melody onset; `'complement'` fills melody rests and sustains and reinforces
151
+ * an occasional strong beat, spaced at least a beat apart. Each onset's pitch
152
+ * is picked from the safe pitches in the counter register (chord tones and
153
+ * consonant tensions against the sounding melody note), rejecting candidates
154
+ * that would form a parallel perfect interval with the melody or sit on the
155
+ * wrong side of it, then scored to favour contrary or oblique motion, imperfect
156
+ * consonance, and stepwise movement. Ties break toward the lower pitch, so a
157
+ * given seed always yields the same line. Notes extend to the next counter
158
+ * onset (the last to the melody's end) at a velocity slightly under the melody.
159
+ *
160
+ * @param opts The lead line, chord context callback, key, and generation knobs.
161
+ * @returns The counter line as note events sorted by onset; `[]` for an empty melody.
162
+ * @example
163
+ * ```ts
164
+ * import { generateCounterMelody, majorKey, parseChordSymbol } from '@libraz/libcantus';
165
+ * const melody = [{ pitch: 72, startBeat: 0, durationBeat: 2 }];
166
+ * const counter = generateCounterMelody({
167
+ * melody,
168
+ * chordAt: () => parseChordSymbol('C'),
169
+ * key: majorKey(0),
170
+ * }); // note events below the melody, in onset order
171
+ * ```
172
+ * @category Voicing & Counterpoint
173
+ */
174
+ declare function generateCounterMelody(opts: CounterMelodyOptions): NoteEvent[];
175
+
176
+ /** A single percussion onset. */
177
+ type DrumHit = {
178
+ pitch: number;
179
+ startBeat: number;
180
+ durationBeat: number;
181
+ velocity: number;
182
+ };
183
+
184
+ /** Groove feel controlling off-beat swing. */
185
+ type Feel = 'straight' | 'swing' | 'shuffle';
186
+ /** Public groove style identifiers. */
187
+ type GrooveStyle = 'standard' | 'funk' | 'shuffle' | 'bossa' | 'trap' | 'halftime' | 'breakbeat' | 'house' | 'synthpop';
188
+ /** Public role identifiers gating which voices are present. */
189
+ type DrumRole = 'full' | 'ambient' | 'minimal' | 'fxOnly';
190
+ /** Public section identifiers. */
191
+ type PublicSection = 'intro' | 'verse' | 'prechorus' | 'chorus' | 'bridge' | 'outro';
192
+
193
+ /**
194
+ * Groove feel (the swing/straight rhythmic character) for {@link generateDrums}.
195
+ *
196
+ * @category Composition
197
+ */
198
+ type GrooveFeel = Feel;
199
+
200
+ /**
201
+ * Public section identifiers for {@link generateDrums}.
202
+ *
203
+ * @category Composition
204
+ */
205
+ type Section = PublicSection;
206
+ /**
207
+ * A Euclidean (Bjorklund) kick pattern for {@link generateDrums}.
208
+ *
209
+ * @category Composition
210
+ */
211
+ type EuclideanKick = {
212
+ /** Number of kick onsets, clamped to `[0, steps]`. */
213
+ pulses: number;
214
+ /**
215
+ * Total steps in the bar (1..16).
216
+ *
217
+ * @defaultValue 16
218
+ */
219
+ steps?: number;
220
+ /**
221
+ * Steps to rotate the onsets toward later positions.
222
+ *
223
+ * @defaultValue 0
224
+ */
225
+ rotation?: number;
226
+ };
227
+ /**
228
+ * Options controlling {@link generateDrums}.
229
+ *
230
+ * @category Composition
231
+ */
232
+ type DrumsOptions = {
233
+ bars: number;
234
+ bpm: number;
235
+ style: GrooveStyle;
236
+ section: Section;
237
+ density: number;
238
+ /**
239
+ * Replace the final bar with a fill.
240
+ *
241
+ * @defaultValue false
242
+ */
243
+ fills?: boolean;
244
+ feel?: GrooveFeel;
245
+ /**
246
+ * Voicing role; `'fxOnly'` suppresses the main kick/snare/ghost/fill voices.
247
+ *
248
+ * @defaultValue `'full'`
249
+ */
250
+ role?: DrumRole;
251
+ /**
252
+ * Seed for the deterministic PRNG.
253
+ *
254
+ * @defaultValue 0
255
+ */
256
+ seed?: number;
257
+ /**
258
+ * Section the final-bar fill leads into. Shapes which fill archetype is
259
+ * chosen (into-chorus and out-of-intro fills differ from generic ones).
260
+ * Defaults to `section`, i.e. a within-section fill.
261
+ */
262
+ nextSection?: Section;
263
+ /**
264
+ * When set, the kick follows this Euclidean rhythm instead of the
265
+ * style/section pattern, giving direct access to evenly spread onsets.
266
+ */
267
+ euclideanKick?: EuclideanKick;
268
+ };
269
+ /**
270
+ * Generate a drum performance as a flat list of onsets.
271
+ *
272
+ * Every voice (kick, snare, ghost snares, closed/open/foot hi-hats, ride, toms,
273
+ * crash, and auxiliary percussion) is emitted as a {@link DrumHit} distinguished
274
+ * by its General MIDI pitch. Groove style selects an internal style and feel;
275
+ * `density` sets the backing-density level; `section` shapes kick, hi-hat, ghost,
276
+ * and percussion density. 16th-note hi-hats drop to 8ths at or above 150 BPM.
277
+ * When `fills` is true the final bar is replaced with a fill whose archetype is
278
+ * shaped by `nextSection`; a fill that would emit nothing on its beat falls back
279
+ * to the normal groove so the phrase end is never silent. `euclideanKick`
280
+ * overrides the kick with an evenly-spread Euclidean pattern. Output is fully
281
+ * determined by the options plus `seed`.
282
+ *
283
+ * @param opts Generation options.
284
+ * @returns Percussion onsets in bar order.
285
+ *
286
+ * @example
287
+ * ```ts
288
+ * import { generateDrums } from '@libraz/libcantus';
289
+ * const hits = generateDrums({ bars: 4, bpm: 120, style: 'standard', section: 'chorus', density: 0.6, fills: true });
290
+ * // Fully determined by the options plus seed (defaults to 0).
291
+ * ```
292
+ *
293
+ * @category Composition
294
+ */
295
+ declare function generateDrums(opts: DrumsOptions): DrumHit[];
296
+
297
+ /**
298
+ * Groove and humanization: nudging quantized note events toward a more human
299
+ * feel, and capturing/replaying the timing-and-velocity "feel" of a
300
+ * performance as a reusable groove template.
301
+ *
302
+ * Positions and durations are measured in quarter-note beats, matching the
303
+ * library-wide convention. Randomness, where used, always goes through the
304
+ * seeded PRNG from the `random` module so results are fully reproducible.
305
+ */
306
+
307
+ /**
308
+ * Options controlling {@link humanize}.
309
+ *
310
+ * @category Rhythm & Meter
311
+ */
312
+ type HumanizeOptions = {
313
+ /**
314
+ * Time signature used to derive metric accents.
315
+ *
316
+ * @defaultValue 4/4
317
+ */
318
+ ts?: TimeSignature;
319
+ /**
320
+ * Maximum timing jitter in quarter-note beats, applied as ±this value.
321
+ *
322
+ * @defaultValue 0.02
323
+ */
324
+ timing?: number;
325
+ /**
326
+ * Maximum velocity jitter (MIDI units), applied as ±this value.
327
+ *
328
+ * @defaultValue 8
329
+ */
330
+ velocity?: number;
331
+ /**
332
+ * How much louder strong beats get relative to weak ones, in MIDI velocity units.
333
+ *
334
+ * @defaultValue 12
335
+ */
336
+ accent?: number;
337
+ /**
338
+ * Velocity assumed for events with no `velocity` of their own.
339
+ *
340
+ * @defaultValue 80
341
+ */
342
+ baseVelocity?: number;
343
+ /**
344
+ * Seed for the deterministic PRNG.
345
+ *
346
+ * @defaultValue 0
347
+ */
348
+ seed?: number;
349
+ };
350
+ /**
351
+ * Humanize a sequence of note events by nudging their timing and velocity
352
+ * with small, deterministic (seeded) randomness plus a metric-accent shape:
353
+ * events on strong beats (see {@link metricWeight}) come out louder on
354
+ * average than events on weak ones.
355
+ *
356
+ * Each returned event is a copy; `startBeat` is jittered within
357
+ * `[-timing, +timing]` beats and clamped to be non-negative, and `velocity`
358
+ * is the event's own velocity (or `baseVelocity` if it has none) plus an
359
+ * accent term scaled by the event's metric weight plus a jitter within
360
+ * `[-velocity, +velocity]`, clamped to `[1, 127]` and rounded. The metric
361
+ * weight is computed from each event's original (pre-jitter) `startBeat`.
362
+ * `pitch` and `durationBeat` pass through unchanged, and the output keeps the
363
+ * input order.
364
+ *
365
+ * @param events The events to humanize.
366
+ * @param opts Humanization options.
367
+ * @returns Humanized copies of `events`, in input order.
368
+ * @example
369
+ * ```ts
370
+ * import { humanize } from '@libraz/libcantus';
371
+ * const events = [{ pitch: 60, startBeat: 0, durationBeat: 1, velocity: 80 }];
372
+ * humanize(events, { seed: 1, timing: 0.03 }); // copies with jittered timing and accented velocity
373
+ * ```
374
+ * @category Rhythm & Meter
375
+ */
376
+ declare function humanize(events: NoteEvent[], opts?: HumanizeOptions): NoteEvent[];
377
+ /**
378
+ * The recorded feel at a single grid slot: an average timing deviation and velocity.
379
+ *
380
+ * @category Rhythm & Meter
381
+ */
382
+ type GrooveSlot = {
383
+ /** Average `actualStartBeat - quantizedBeat` (in quarter-note beats) for events landing on this slot. */
384
+ timingOffset: number;
385
+ /**
386
+ * Average velocity of events landing on this slot, or `null` if no event
387
+ * with a velocity did. `null` (not 0) is the "unrecorded" sentinel so that a
388
+ * genuine velocity of 0 is preserved and applied like any other value.
389
+ */
390
+ velocity: number | null;
391
+ };
392
+ /**
393
+ * A per-bar grid of timing and velocity deviations captured from a performance.
394
+ *
395
+ * @category Rhythm & Meter
396
+ */
397
+ type GrooveTemplate = {
398
+ /** Grid resolution: equal grid steps per quarter-note beat. */
399
+ subdivision: number;
400
+ /** Number of grid slots per bar (`beatsPerBar(ts) * subdivision`). */
401
+ slotsPerBar: number;
402
+ /** One entry per grid slot, in slot-index order (slot 0 is the downbeat). */
403
+ slots: GrooveSlot[];
404
+ /**
405
+ * The time signature the template was extracted under. {@link applyGrooveTemplate}
406
+ * requires the apply-time meter to match this so the per-bar grid lines up
407
+ * instead of silently drifting. Optional for backward compatibility with
408
+ * templates constructed without it (in which case no check is performed).
409
+ */
410
+ ts?: TimeSignature;
411
+ };
412
+ /**
413
+ * Extract a groove template from a set of note events: for each grid slot,
414
+ * the average timing deviation from the quantized grid and the average
415
+ * velocity of events landing on it. Slots with no velocity-carrying event
416
+ * record `velocity: null` (the "unrecorded" sentinel); empty slots default to
417
+ * `{ timingOffset: 0, velocity: null }`. The time signature is stored on the
418
+ * template so {@link applyGrooveTemplate} can verify the meter matches.
419
+ *
420
+ * @param events The (typically "groovy", human-played) events to analyze.
421
+ * @param ts The time signature, used to compute the bar length.
422
+ * @param subdivision Grid resolution: equal grid steps per quarter-note beat.
423
+ * @returns The extracted groove template.
424
+ * @category Rhythm & Meter
425
+ */
426
+ declare function extractGrooveTemplate(events: NoteEvent[], ts: TimeSignature, subdivision: number): GrooveTemplate;
427
+ /**
428
+ * Apply a groove template to a set of (typically quantized) note events: each
429
+ * event is snapped to its grid slot and then offset by that slot's recorded
430
+ * timing deviation, pushing stiff timing toward the template's feel.
431
+ * Velocity is set to the slot's recorded average when it recorded one (a
432
+ * non-`null` velocity, including a genuine 0); otherwise the event's own
433
+ * velocity is left untouched.
434
+ *
435
+ * If the template carries a time signature (see {@link GrooveTemplate.ts}) it
436
+ * must match `ts`, since a differing bar length would misalign the per-bar
437
+ * grid and drift the feel; a mismatch throws rather than corrupting timing
438
+ * silently.
439
+ *
440
+ * @param events The events to reshape.
441
+ * @param template The groove template, from {@link extractGrooveTemplate}.
442
+ * @param ts The time signature, used to compute the bar length.
443
+ * @returns Reshaped copies of `events`, in input order.
444
+ * @throws If `template.ts` is set and does not match `ts`.
445
+ * @example
446
+ * ```ts
447
+ * import { extractGrooveTemplate, applyGrooveTemplate, parseTimeSignature } from '@libraz/libcantus';
448
+ * const ts = parseTimeSignature('4/4');
449
+ * // Learn the feel from a loosely played performance...
450
+ * const groovy = [
451
+ * { pitch: 36, startBeat: 0.02, durationBeat: 1, velocity: 100 },
452
+ * { pitch: 38, startBeat: 1.06, durationBeat: 1, velocity: 70 },
453
+ * ];
454
+ * const template = extractGrooveTemplate(groovy, ts, 4);
455
+ * // ...then impose it on stiff, quantized events.
456
+ * const quantized = [{ pitch: 36, startBeat: 0, durationBeat: 1, velocity: 80 }];
457
+ * applyGrooveTemplate(quantized, template, ts); // events nudged toward the captured feel
458
+ * ```
459
+ * @category Rhythm & Meter
460
+ */
461
+ declare function applyGrooveTemplate(events: NoteEvent[], template: GrooveTemplate, ts: TimeSignature): NoteEvent[];
462
+
463
+ /**
464
+ * Broad production style a progression preset suits.
465
+ *
466
+ * @category Composition
467
+ */
468
+ type ProgStyle = 'minimal' | 'dance' | 'idol' | 'rock';
469
+ /**
470
+ * Harmonic-function role of a progression as a whole.
471
+ *
472
+ * @category Composition
473
+ */
474
+ type ProgFunction = 'loop' | 'tensionBuild' | 'cadenceStrong' | 'stable';
475
+ /**
476
+ * A named chord-progression preset expressed in scale degrees.
477
+ *
478
+ * @category Composition
479
+ */
480
+ type ProgressionPreset = {
481
+ id: string;
482
+ name: string;
483
+ degrees: number[];
484
+ functional: ProgFunction;
485
+ styles: ProgStyle[];
486
+ };
487
+ /**
488
+ * Options controlling {@link generateProgression}.
489
+ *
490
+ * @category Composition
491
+ */
492
+ type ProgressionOptions = {
493
+ key: KeyScale;
494
+ style: ProgStyle;
495
+ bars: number;
496
+ presetId?: string;
497
+ ext?: ChordQuality | 'auto';
498
+ reharmonize?: boolean;
499
+ /**
500
+ * Seed for the deterministic preset choice and reharmonization.
501
+ *
502
+ * @defaultValue 0
503
+ */
504
+ seed?: number;
505
+ };
506
+ /**
507
+ * All built-in progression presets.
508
+ *
509
+ * @category Composition
510
+ */
511
+ declare function progressions(): ProgressionPreset[];
512
+ /**
513
+ * Presets whose style list includes the given style.
514
+ *
515
+ * @category Composition
516
+ */
517
+ declare function progressionsByStyle(style: ProgStyle): ProgressionPreset[];
518
+ /**
519
+ * Generate a chord progression laid out one chord per bar.
520
+ *
521
+ * A preset is chosen by `presetId` when given, otherwise deterministically from
522
+ * the presets matching `style`, seeded by `seed`. An unknown `presetId` is a
523
+ * caller error and throws rather than silently falling back to a random preset.
524
+ * The preset's degrees cycle to
525
+ * fill `bars`; each bar is four beats, so `startBeat` is `barIndex * 4`. Chord
526
+ * roots come from the key's diatonic scale-degree mapping. When `ext` is
527
+ * omitted or `'auto'`, each chord takes its diatonic triad quality; otherwise
528
+ * `ext` is forced on every chord. When `reharmonize` is set, some chords are
529
+ * deterministically replaced with the secondary dominant (V7) of the following
530
+ * chord, flagged with `secondaryDominant`.
531
+ *
532
+ * @param opts Generation options.
533
+ * @returns One chord per bar in timeline order.
534
+ * @throws If `presetId` is given but does not match any built-in preset.
535
+ *
536
+ * @example
537
+ * ```ts
538
+ * import { generateProgression, majorKey } from '@libraz/libcantus';
539
+ * const chords = generateProgression({ key: majorKey(0), style: 'dance', bars: 4 });
540
+ * // Deterministic for a given seed (defaults to 0); one ChordSpan per bar.
541
+ * ```
542
+ *
543
+ * @category Composition
544
+ */
545
+ declare function generateProgression(opts: ProgressionOptions): ChordSpan[];
546
+
547
+ /**
548
+ * A melody note supplied to the harmonizer: a {@link NoteEvent}.
549
+ *
550
+ * @category Reharmonization
551
+ */
552
+ type MelodyNote = NoteEvent;
553
+ /**
554
+ * Options controlling {@link harmonizeMelody}.
555
+ *
556
+ * @category Reharmonization
557
+ */
558
+ type HarmonizeOptions = {
559
+ melody: MelodyNote[];
560
+ key: KeyScale | 'infer';
561
+ harmonicRhythm: number;
562
+ reharmonize: 'diatonic' | 'secondaryDominant' | 'borrowed';
563
+ placement: {
564
+ transposeSearch: boolean;
565
+ octaveSearch: boolean;
566
+ };
567
+ /**
568
+ * Seed for the deterministic tie-break perturbation.
569
+ *
570
+ * @defaultValue 0
571
+ */
572
+ seed?: number;
573
+ };
574
+ /**
575
+ * The chosen transpose, key, chord path, and per-note roles.
576
+ *
577
+ * @category Reharmonization
578
+ */
579
+ type HarmonizeResult = {
580
+ transposeSemitones: number;
581
+ key: KeyScale;
582
+ chords: ChordSpan[];
583
+ melodyRoles: {
584
+ noteIndex: number;
585
+ role: HarmonyRole;
586
+ }[];
587
+ };
588
+ /**
589
+ * Harmonize a melody with a min-cost chord progression.
590
+ *
591
+ * The melody is segmented by `harmonicRhythm`; each segment is scored against
592
+ * diatonic (and, per `reharmonize`, secondary-dominant and borrowed) candidate
593
+ * chords by melody fit, and a Viterbi search picks the lowest-cost path using a
594
+ * functional-flow transition cost. When `placement.transposeSearch`/`octaveSearch`
595
+ * is set, the whole melody is transposed across a range and the best
596
+ * `(transpose, progression)` pair is returned; a small tessitura cost breaks
597
+ * ties toward placements that keep the melody in a comfortable register.
598
+ *
599
+ * The `seed` drives a deterministic tie-break only: it perturbs candidates by a
600
+ * magnitude far below any real cost difference (see {@link TIE_BREAK_JITTER}),
601
+ * so it can decide between chords or paths of otherwise-equal cost but never
602
+ * overrides melody fit or functional flow. For a well-determined melody the
603
+ * result is identical across seeds; the same seed always yields the same result.
604
+ *
605
+ * @param opts Melody, key (or `'infer'`), harmonic rhythm, reharmonization
606
+ * strength, height-search flags, and seed.
607
+ * @returns The chosen transpose, key, chord path, and per-note roles.
608
+ * @example
609
+ * ```ts
610
+ * import { harmonizeMelody, majorKey } from '@libraz/libcantus';
611
+ * const result = harmonizeMelody({
612
+ * melody: [
613
+ * { pitch: 60, startBeat: 0, durationBeat: 1 },
614
+ * { pitch: 64, startBeat: 1, durationBeat: 1 },
615
+ * ],
616
+ * key: majorKey(0),
617
+ * harmonicRhythm: 1,
618
+ * reharmonize: 'diatonic',
619
+ * placement: { transposeSearch: false, octaveSearch: false },
620
+ * });
621
+ * result.chords; // one ChordSpan per harmonic-rhythm segment
622
+ * ```
623
+ * @category Reharmonization
624
+ */
625
+ declare function harmonizeMelody(opts: HarmonizeOptions): HarmonizeResult;
626
+
627
+ /**
628
+ * A transformation applicable to a motif cell.
629
+ *
630
+ * @category Composition
631
+ */
632
+ type MotifTransform = 'transposeDiatonic' | 'transposeChromatic' | 'invert' | 'retrograde' | 'augment' | 'diminish' | 'sequence';
633
+ /**
634
+ * A single note within a motif cell.
635
+ *
636
+ * @category Composition
637
+ */
638
+ type MotifNote = {
639
+ pitch: number;
640
+ startBeat: number;
641
+ durationBeat: number;
642
+ };
643
+ /**
644
+ * A short melodic cell.
645
+ *
646
+ * @category Composition
647
+ */
648
+ type MotifCell = {
649
+ notes: MotifNote[];
650
+ };
651
+ /**
652
+ * Melodic contour shape for {@link generateMotif}.
653
+ *
654
+ * @category Composition
655
+ */
656
+ type MotifContour = 'arch' | 'ascending' | 'descending' | 'wave';
657
+ /**
658
+ * Options controlling {@link generateMotif}.
659
+ *
660
+ * @category Composition
661
+ */
662
+ type MotifOptions = {
663
+ key: KeyScale;
664
+ chord?: Chord | null;
665
+ bars: number;
666
+ /**
667
+ * Melodic contour shape the line follows.
668
+ *
669
+ * @defaultValue `'arch'`
670
+ */
671
+ contour?: MotifContour;
672
+ /**
673
+ * Probability in [0, 1] that a note is nudged by a single diatonic step. The
674
+ * nudge direction is balanced (up or down with equal odds), so it adds
675
+ * variety without biasing the line off its contour. Default 0, which
676
+ * reproduces the requested contour exactly (no drift, tails return to tonic).
677
+ *
678
+ * @defaultValue 0
679
+ */
680
+ jitter?: number;
681
+ /**
682
+ * Seed for the deterministic PRNG.
683
+ *
684
+ * @defaultValue 0
685
+ */
686
+ seed?: number;
687
+ };
688
+ /**
689
+ * Generate a short seed motif over `bars`.
690
+ *
691
+ * The melody follows the requested contour in diatonic steps from the tonic,
692
+ * snapped to the key. When a chord is supplied, notes landing on bar downbeats
693
+ * are pulled to the nearest chord tone. An optional `jitter` adds balanced
694
+ * per-note variation without biasing the contour; it is off by default, so the
695
+ * contour is reproduced exactly. Output is deterministic for a given seed.
696
+ *
697
+ * @param opts Key, optional chord, length, contour, jitter, and seed.
698
+ * @returns The generated motif cell.
699
+ *
700
+ * @example
701
+ * ```ts
702
+ * import { generateMotif, majorKey } from '@libraz/libcantus';
703
+ * const cell = generateMotif({ key: majorKey(0), bars: 2, contour: 'arch' });
704
+ * // cell.notes is a deterministic MotifCell (seed defaults to 0)
705
+ * ```
706
+ *
707
+ * @category Composition
708
+ */
709
+ declare function generateMotif(opts: MotifOptions): MotifCell;
710
+ /**
711
+ * Apply a transformation to a motif cell.
712
+ *
713
+ * `invert` reflects pitches about the first note (chromatic, self-inverse);
714
+ * `retrograde` mirrors onsets about the cell span, preserving rests (self-inverse);
715
+ * `augment`/`diminish` scale time by `amount ?? 2` and its reciprocal;
716
+ * `transposeChromatic` adds `amount` semitones; `transposeDiatonic` shifts by
717
+ * `amount` scale degrees when a `key` is given, or — with no `key` — falls back
718
+ * to a chromatic shift of `amount` semitones; `sequence` appends a shifted copy
719
+ * (by `amount` diatonic degrees with a `key`, or by `amount` semitones without
720
+ * one, since it delegates to `transposeDiatonic`).
721
+ *
722
+ * @param cell The cell to transform.
723
+ * @param t The transformation.
724
+ * @param amount Optional parameter (semitones, degrees, or time factor).
725
+ * @param key Key context for the diatonic transforms; without it,
726
+ * `transposeDiatonic` and `sequence` shift chromatically by semitones.
727
+ * @returns The transformed cell.
728
+ *
729
+ * @example
730
+ * ```ts
731
+ * import { generateMotif, transformMotif, majorKey } from '@libraz/libcantus';
732
+ * const cell = generateMotif({ key: majorKey(0), bars: 1 });
733
+ * const inverted = transformMotif(cell, 'invert');
734
+ * ```
735
+ *
736
+ * @category Composition
737
+ */
738
+ declare function transformMotif(cell: MotifCell, t: MotifTransform, amount?: number, key?: KeyScale): MotifCell;
739
+ /**
740
+ * Lay a motif across `bars` and snap it to a chord timeline.
741
+ *
742
+ * The cell is tiled back-to-back to fill the requested span; each note is then
743
+ * pulled to the nearest chord tone of the segment sounding at its onset, so the
744
+ * developed line spells the underlying harmony.
745
+ *
746
+ * @param cell The source motif.
747
+ * @param timeline Chord segments to snap against.
748
+ * @param key Key context (used to keep snapped pitches sensible).
749
+ * @param bars Number of four-beat bars to fill.
750
+ * @returns The developed, harmony-aware cell.
751
+ *
752
+ * @example
753
+ * ```ts
754
+ * import { chordTimelineFromChords, developMotif, generateMotif, majorKey } from '@libraz/libcantus';
755
+ * const key = majorKey(0);
756
+ * const timeline = chordTimelineFromChords([{ rootPc: 0, quality: 'maj', startBeat: 0 }], 8);
757
+ * const developed = developMotif(generateMotif({ key, bars: 1 }), timeline, key, 2);
758
+ * ```
759
+ *
760
+ * @category Composition
761
+ */
762
+ declare function developMotif(cell: MotifCell, timeline: ChordTimeline, key: KeyScale, bars: number): MotifCell;
763
+
764
+ /**
765
+ * Reharmonization: chord substitution, modal-interchange palettes, and negative
766
+ * harmony. These transforms take an existing chord (or a key) and propose
767
+ * alternative harmonies that preserve a chosen relationship — a shared function,
768
+ * a common tone, a tonicizing dominant, or a reflection across the key axis.
769
+ *
770
+ * Roots are pitch classes (0..11); no spelled key signature is required.
771
+ */
772
+
773
+ /**
774
+ * The kind of substitution relationship a candidate realizes.
775
+ *
776
+ * @category Reharmonization
777
+ */
778
+ type SubstitutionType = 'tritone' | 'relative' | 'borrowed' | 'chromatic-mediant' | 'secondary-dominant';
779
+ /**
780
+ * A proposed chord substitution with its relationship, numeral, and function.
781
+ *
782
+ * @category Reharmonization
783
+ */
784
+ type Substitution = {
785
+ chord: Chord;
786
+ type: SubstitutionType;
787
+ roman: string;
788
+ function: HarmonicFunction;
789
+ };
790
+ /**
791
+ * Options controlling which substitutions {@link substituteChord} returns.
792
+ *
793
+ * @category Reharmonization
794
+ */
795
+ type SubstituteOptions = {
796
+ /**
797
+ * Melody pitch classes that must remain chord tones. When given, only
798
+ * substitutions whose pitch classes contain every listed pitch class are
799
+ * kept, so the melody stays consonant against the new harmony.
800
+ */
801
+ melodyPcs?: number[];
802
+ };
803
+ /**
804
+ * Propose substitutions for a chord within a key.
805
+ *
806
+ * Candidates are generated by several relationships and deduplicated against the
807
+ * original chord and each other:
808
+ *
809
+ * - `tritone`: for a dominant-type chord, the dominant seventh a tritone away.
810
+ * - `secondary-dominant`: for a stable target, the dominant seventh a fifth
811
+ * above its root (tonicizing it).
812
+ * - `relative`: a diatonic triad a third away that shares two common tones.
813
+ * - `borrowed`: a triad from the parallel mode with the same harmonic function.
814
+ * - `chromatic-mediant`: a major/minor triad a third away sharing one common
815
+ * tone.
816
+ *
817
+ * Each result carries its Roman numeral and harmonic function in `key`. When
818
+ * `opts.melodyPcs` is given, only substitutions whose pitch classes contain all
819
+ * of those pitch classes are returned.
820
+ *
821
+ * @param chord The chord to reharmonize.
822
+ * @param key The prevailing key.
823
+ * @param opts Optional melody-preservation constraint.
824
+ * @returns The deduplicated substitution candidates.
825
+ * @example
826
+ * ```ts
827
+ * import { substituteChord, makeChord, majorKey } from '@libraz/libcantus';
828
+ * const subs = substituteChord(makeChord(7, 'dom7'), majorKey(0));
829
+ * // includes the tritone sub Db7 (rootPc 1, quality 'dom7')
830
+ * ```
831
+ * @category Reharmonization
832
+ */
833
+ declare function substituteChord(chord: Chord, key: KeyScale, opts?: SubstituteOptions): Substitution[];
834
+ /**
835
+ * A borrowed chord in the modal-interchange palette of a key.
836
+ *
837
+ * @category Reharmonization
838
+ */
839
+ type BorrowedChord = {
840
+ chord: Chord;
841
+ roman: string;
842
+ source: BorrowedSource;
843
+ };
844
+ /**
845
+ * The modal-interchange palette of a key.
846
+ *
847
+ * Lists the diatonic triads of the {@link parallelKey} that are not diatonic to
848
+ * `key` (the classic borrowed chords such as `iv`, `bVI`, and `bVII` in a major
849
+ * key), plus the Neapolitan (a major triad on the flat second degree). Each
850
+ * carries its Roman numeral and {@link borrowedSource} relative to `key`.
851
+ *
852
+ * @param key The prevailing key.
853
+ * @returns The borrowed-chord palette.
854
+ * @category Reharmonization
855
+ */
856
+ declare function modalInterchangePalette(key: KeyScale): BorrowedChord[];
857
+ /**
858
+ * Reflect a chord across the tonic–dominant axis of a key (negative harmony).
859
+ *
860
+ * Every pitch class `p` maps to `(2*T + 7 - p) mod 12`, where `T` is the key
861
+ * tonic — the reflection that swaps the tonic with the dominant. The mirrored
862
+ * pitch classes (including the bass, if set) are reassembled into a chord by
863
+ * {@link detectChordBest}; when no chord is recognized, the mirrored root and
864
+ * the original quality are used as a fallback.
865
+ *
866
+ * @param chord The chord to reflect.
867
+ * @param key The prevailing key.
868
+ * @returns The negative-harmony counterpart of the chord.
869
+ * @example
870
+ * ```ts
871
+ * import { negativeHarmonyMirror, makeChord, majorKey } from '@libraz/libcantus';
872
+ * negativeHarmonyMirror(makeChord(7, 'maj'), majorKey(0));
873
+ * // G major reflected across C's axis => F minor (rootPc 5, quality 'min')
874
+ * ```
875
+ * @category Reharmonization
876
+ */
877
+ declare function negativeHarmonyMirror(chord: Chord, key: KeyScale): Chord;
878
+
879
+ /**
880
+ * Deterministic rhythm generation over a metric grid.
881
+ *
882
+ * Builds a fixed-resolution grid across one or more bars of a time signature
883
+ * and decides, per grid slot, whether it becomes a note onset. Onset
884
+ * probability follows the metric-accent hierarchy from the `meter` module, so
885
+ * strong positions (downbeats, secondary pulses) are favored over weak
886
+ * off-pulse subdivisions. Given a seed the output is fully reproducible.
887
+ *
888
+ * Positions and durations are measured in quarter-note beats, matching the
889
+ * library-wide convention.
890
+ */
891
+
892
+ /**
893
+ * A single rhythmic note: an onset position and how long it sounds.
894
+ *
895
+ * @category Rhythm & Meter
896
+ */
897
+ type RhythmEvent = {
898
+ /** Onset position in quarter-note beats, absolute from the start of the span. */
899
+ position: number;
900
+ /** Duration in quarter-note beats, extending to the next onset. */
901
+ duration: number;
902
+ };
903
+ /**
904
+ * Options controlling {@link generateRhythm}.
905
+ *
906
+ * @category Rhythm & Meter
907
+ */
908
+ type RhythmOptions = {
909
+ /**
910
+ * Seed for the deterministic PRNG.
911
+ *
912
+ * @defaultValue 0
913
+ */
914
+ seed?: number;
915
+ /**
916
+ * Number of bars to generate.
917
+ *
918
+ * @defaultValue 1
919
+ */
920
+ bars?: number;
921
+ /**
922
+ * Grid resolution as the number of equal grid steps per quarter-note beat.
923
+ * The default of 2 yields an eighth-note grid; 4 yields a sixteenth-note
924
+ * grid, 3 an eighth-note triplet grid, and so on.
925
+ *
926
+ * @defaultValue 2
927
+ */
928
+ subdivision?: number;
929
+ /**
930
+ * Overall onset density in [0, 1]. Scales the per-slot onset probability, so
931
+ * higher values fill more grid slots. Values outside [0, 1] are clamped into
932
+ * range.
933
+ *
934
+ * @defaultValue 0.5
935
+ */
936
+ density?: number;
937
+ };
938
+ /**
939
+ * Map a metric weight (0–3 from {@link metricWeight}) to a base onset
940
+ * probability before density scaling. Strong positions are much more likely to
941
+ * carry an onset than weak ones; the curve is intentionally small and explicit
942
+ * so its behavior is easy to inspect and test.
943
+ *
944
+ * @param weight The metric weight, 0 (off-pulse) to 3 (downbeat).
945
+ * @returns A base onset probability in [0, 1].
946
+ * @category Rhythm & Meter
947
+ */
948
+ declare function onsetWeightCurve(weight: number): number;
949
+ /**
950
+ * Generate a deterministic rhythmic pattern over `bars` bars of a time
951
+ * signature. A grid is built at the chosen subdivision; each slot becomes an
952
+ * onset with a probability derived from its metric weight scaled by `density`
953
+ * and sampled from the seeded PRNG. Every bar's downbeat is always an onset, so
954
+ * a pattern of any length has a reliable pulse independent of the seed. Each
955
+ * event's duration extends to the next onset, and the last event extends to the
956
+ * end of the span. `density` is clamped to [0, 1].
957
+ *
958
+ * @param ts The time signature.
959
+ * @param opts Generation options.
960
+ * @returns Onset events sorted by position, non-overlapping, covering the span.
961
+ * @example
962
+ * ```ts
963
+ * import { parseTimeSignature, generateRhythm } from '@libraz/libcantus';
964
+ * const ts = parseTimeSignature('4/4');
965
+ * generateRhythm(ts, { seed: 42, density: 0.6 }); // onset events over one bar
966
+ * ```
967
+ * @category Rhythm & Meter
968
+ */
969
+ declare function generateRhythm(ts: TimeSignature, opts?: RhythmOptions): RhythmEvent[];
970
+ /**
971
+ * Onset density of a generated pattern: the mean number of onsets per bar.
972
+ *
973
+ * @param events Events from {@link generateRhythm}.
974
+ * @param ts The time signature.
975
+ * @returns The onset count divided by the number of bars the events span.
976
+ * @category Rhythm & Meter
977
+ */
978
+ declare function rhythmDensity(events: RhythmEvent[], ts: TimeSignature): number;
979
+
980
+ export { type BassLineOptions, type BassSegment, type BassStyle, type BorrowedChord, ChordSpan, type CounterMelodyOptions, type DrumHit, type DrumRole, type DrumsOptions, type EuclideanKick, type GrooveFeel, type GrooveSlot, type GrooveStyle, type GrooveTemplate, type HarmonizeOptions, type HarmonizeResult, type HumanizeOptions, type MelodyNote, type MotifCell, type MotifContour, type MotifNote, type MotifOptions, type MotifTransform, type ProgFunction, type ProgStyle, type ProgressionOptions, type ProgressionPreset, type RhythmEvent, type RhythmOptions, type Section, type SubstituteOptions, type Substitution, type SubstitutionType, applyGrooveTemplate, developMotif, extractGrooveTemplate, generateBassLine, generateCounterMelody, generateDrums, generateMotif, generateProgression, generateRhythm, harmonizeMelody, humanize, modalInterchangePalette, negativeHarmonyMirror, onsetWeightCurve, progressions, progressionsByStyle, rhythmDensity, substituteChord, transformMotif };