@libraz/libcantus 0.9.1 → 0.9.3

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