@libraz/libcantus 0.9.0 → 0.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -27,16 +27,47 @@ type NoteEvent = {
27
27
  velocity?: number;
28
28
  };
29
29
 
30
- /** Chord quality identifiers understood by the chord builder. */
30
+ /**
31
+ * Chord quality identifiers understood by the chord builder.
32
+ *
33
+ * @category Chords
34
+ */
31
35
  type ChordQuality = 'maj' | 'min' | 'dim' | 'aug' | 'maj7' | 'min7' | 'dom7' | 'dim7' | 'm7b5' | 'minMaj7' | 'aug7' | 'augMaj7' | 'majb5' | '6' | 'min6' | '6/9' | 'sus2' | 'sus4' | 'add9' | 'add11' | 'maj9' | 'min9' | 'dom9' | '7b9' | '7#9' | '7#11' | '7b13' | '11' | '13' | '5';
32
- /** A chord expressed as a root pitch class plus semitone offsets. */
36
+ /**
37
+ * A bare spelled pitch used as an enharmonic hint: a diatonic letter
38
+ * (0..6 = C..B) plus a chromatic alteration (-2 double-flat .. +2 double-sharp).
39
+ * Mirrors the letter/alter half of the pitch module's `Note` without an octave.
40
+ *
41
+ * @category Chords
42
+ */
43
+ type PitchSpelling = {
44
+ letter: number;
45
+ alter: number;
46
+ };
47
+ /**
48
+ * A chord expressed as a root pitch class plus semitone offsets.
49
+ *
50
+ * `rootSpelling`/`bassSpelling` are optional enharmonic hints recorded by
51
+ * parsers (e.g. `parseChordSymbol('Bb7')`) so formatters can reproduce the
52
+ * original spelling instead of defaulting to sharps. Consumers may ignore
53
+ * them; a hint is only trusted when its pitch class still matches the
54
+ * corresponding `rootPc`/`bassPc`.
55
+ *
56
+ * @category Chords
57
+ */
33
58
  type Chord$1 = {
34
59
  rootPc: number;
35
60
  quality: ChordQuality;
36
61
  intervals: number[];
37
62
  bassPc?: number;
63
+ rootSpelling?: PitchSpelling;
64
+ bassSpelling?: PitchSpelling;
38
65
  };
39
- /** All chord qualities the builder understands, longest templates last. */
66
+ /**
67
+ * All chord qualities the builder understands, longest templates last.
68
+ *
69
+ * @category Chords
70
+ */
40
71
  declare function chordQualities(): ChordQuality[];
41
72
  /**
42
73
  * Build a chord rooted on a diatonic scale degree.
@@ -49,6 +80,8 @@ declare function chordQualities(): ChordQuality[];
49
80
  * @param ext Chord quality to apply.
50
81
  * @param key Key context supplying the diatonic root.
51
82
  * @returns The constructed chord.
83
+ *
84
+ * @category Chords
52
85
  */
53
86
  declare function chordFromDegree(degree: number, ext: ChordQuality, key: KeyScale): Chord$1;
54
87
  /**
@@ -58,6 +91,15 @@ declare function chordFromDegree(degree: number, ext: ChordQuality, key: KeyScal
58
91
  * @param quality Chord quality supplying the interval template.
59
92
  * @param bassPc Optional slash-chord bass pitch class.
60
93
  * @returns The constructed chord.
94
+ *
95
+ * @example
96
+ * ```ts
97
+ * import { makeChord } from '@libraz/libcantus';
98
+ * const cmaj7 = makeChord(0, 'maj7');
99
+ * // { rootPc: 0, quality: 'maj7', intervals: [0, 4, 7, 11] }
100
+ * ```
101
+ *
102
+ * @category Chords
61
103
  */
62
104
  declare function makeChord(rootPc: number, quality: ChordQuality, bassPc?: number): Chord$1;
63
105
  /**
@@ -65,6 +107,14 @@ declare function makeChord(rootPc: number, quality: ChordQuality, bassPc?: numbe
65
107
  *
66
108
  * @param chord The chord to enumerate.
67
109
  * @returns The chord's pitch classes, sorted ascending in [0, 11].
110
+ *
111
+ * @example
112
+ * ```ts
113
+ * import { makeChord, chordPitchClasses } from '@libraz/libcantus';
114
+ * chordPitchClasses(makeChord(0, 'maj7')); // [0, 4, 7, 11]
115
+ * ```
116
+ *
117
+ * @category Chords
68
118
  */
69
119
  declare function chordPitchClasses(chord: Chord$1): number[];
70
120
  /**
@@ -78,6 +128,8 @@ declare function chordPitchClasses(chord: Chord$1): number[];
78
128
  * @param pitch MIDI pitch or bare pitch class.
79
129
  * @param chord The chord providing the root reference.
80
130
  * @returns The chord-tone role, or null if the pitch has no basic role.
131
+ *
132
+ * @category Chords
81
133
  */
82
134
  declare function chordToneRole(pitch: number, chord: Chord$1): 'root' | 'third' | 'fifth' | 'sixth' | 'seventh' | null;
83
135
  /**
@@ -91,6 +143,14 @@ declare function chordToneRole(pitch: number, chord: Chord$1): 'root' | 'third'
91
143
  * @param degree 0-based scale degree of the chord root.
92
144
  * @param key Key/scale context.
93
145
  * @returns The diatonic triad.
146
+ *
147
+ * @example
148
+ * ```ts
149
+ * import { majorKey, diatonicTriad } from '@libraz/libcantus';
150
+ * const tonic = diatonicTriad(0, majorKey(0)); // C major triad (degree 0 of C major)
151
+ * ```
152
+ *
153
+ * @category Chords
94
154
  */
95
155
  declare function diatonicTriad(degree: number, key: KeyScale): Chord$1;
96
156
  /**
@@ -99,18 +159,32 @@ declare function diatonicTriad(degree: number, key: KeyScale): Chord$1;
99
159
  * @param degree 0-based scale degree of the chord root.
100
160
  * @param key Key/scale context.
101
161
  * @returns The diatonic seventh chord.
162
+ *
163
+ * @category Chords
102
164
  */
103
165
  declare function diatonicSeventh(degree: number, key: KeyScale): Chord$1;
104
166
 
105
- /** Severity policy: `strict` counterpoint vs. lenient `pop` voice-leading. */
167
+ /**
168
+ * Severity policy: `strict` counterpoint vs. lenient `pop` voice-leading.
169
+ *
170
+ * @category Arrangement & Analysis
171
+ */
106
172
  type SafetyProfile = 'strict' | 'pop';
107
- /** Overall placeability verdict for a candidate pitch. */
173
+ /**
174
+ * Overall placeability verdict for a candidate pitch.
175
+ *
176
+ * @category Arrangement & Analysis
177
+ */
108
178
  declare enum NoteSafety {
109
179
  Safe = 0,
110
180
  Warning = 1,
111
181
  Dissonant = 2
112
182
  }
113
- /** Bit flags describing why a pitch received its verdict. */
183
+ /**
184
+ * Bit flags describing why a pitch received its verdict.
185
+ *
186
+ * @category Arrangement & Analysis
187
+ */
114
188
  declare enum ReasonFlag {
115
189
  ChordTone = 1,
116
190
  Tension = 2,
@@ -129,12 +203,20 @@ declare enum ReasonFlag {
129
203
  Suspension = 16384,
130
204
  NeedsResolution = 32768
131
205
  }
132
- /** A neighbouring voice's current and previous pitch. */
206
+ /**
207
+ * A neighbouring voice's current and previous pitch.
208
+ *
209
+ * @category Arrangement & Analysis
210
+ */
133
211
  type VoiceSnapshot = {
134
212
  pitch: number;
135
213
  prevPitch?: number;
136
214
  };
137
- /** Everything needed to evaluate one candidate pitch. */
215
+ /**
216
+ * Everything needed to evaluate one candidate pitch.
217
+ *
218
+ * @category Arrangement & Analysis
219
+ */
138
220
  type SafetyQuery = {
139
221
  profile: SafetyProfile;
140
222
  candidatePitch: number;
@@ -146,7 +228,11 @@ type SafetyQuery = {
146
228
  vocalLow?: number;
147
229
  vocalHigh?: number;
148
230
  };
149
- /** The verdict, reason flags, and optional resolution guidance. */
231
+ /**
232
+ * The verdict, reason flags, and optional resolution guidance.
233
+ *
234
+ * @category Arrangement & Analysis
235
+ */
150
236
  type SafetyResult = {
151
237
  safety: NoteSafety;
152
238
  reasons: number;
@@ -164,6 +250,20 @@ type SafetyResult = {
164
250
  *
165
251
  * @param q The candidate and its harmonic/voice-leading context.
166
252
  * @returns The verdict, reason bitmask, and optional resolution guidance.
253
+ * @example
254
+ * ```ts
255
+ * import { evaluateSafety, makeChord, majorKey, NoteSafety } from '@libraz/libcantus';
256
+ * const result = evaluateSafety({
257
+ * profile: 'pop',
258
+ * candidatePitch: 60, // C over a C major chord
259
+ * chord: makeChord(0, 'maj'),
260
+ * key: majorKey(0),
261
+ * otherVoices: [],
262
+ * strongBeat: true,
263
+ * });
264
+ * result.safety === NoteSafety.Safe; // true — C is a chord tone
265
+ * ```
266
+ * @category Arrangement & Analysis
167
267
  */
168
268
  declare function evaluateSafety(q: SafetyQuery): SafetyResult;
169
269
  /**
@@ -173,10 +273,25 @@ declare function evaluateSafety(q: SafetyQuery): SafetyResult;
173
273
  * @param pitchLow Lowest MIDI pitch to consider (inclusive).
174
274
  * @param pitchHigh Highest MIDI pitch to consider (inclusive).
175
275
  * @returns Placeable pitches (non-dissonant), chord tones before others, each group descending.
276
+ * @example
277
+ * ```ts
278
+ * import { enumerateSafePitches, makeChord, majorKey } from '@libraz/libcantus';
279
+ * const pitches = enumerateSafePitches(
280
+ * { profile: 'pop', chord: makeChord(0, 'maj'), key: majorKey(0), otherVoices: [], strongBeat: true },
281
+ * 60,
282
+ * 72,
283
+ * );
284
+ * pitches; // placeable pitches in [60, 72], chord tones first, each group descending
285
+ * ```
286
+ * @category Arrangement & Analysis
176
287
  */
177
288
  declare function enumerateSafePitches(q: Omit<SafetyQuery, 'candidatePitch'>, pitchLow: number, pitchHigh: number): number[];
178
289
 
179
- /** A theory annotation attached to a note. */
290
+ /**
291
+ * A theory annotation attached to a note.
292
+ *
293
+ * @category Arrangement & Analysis
294
+ */
180
295
  type TheoryLabel = {
181
296
  kind: 'chordTone';
182
297
  role: 'root' | 'third' | 'fifth' | 'sixth' | 'seventh';
@@ -204,13 +319,21 @@ type TheoryLabel = {
204
319
  kind: 'leadingTone';
205
320
  resolveTo: number;
206
321
  };
207
- /** A note with its theory labels and a short rationale. */
322
+ /**
323
+ * A note with its theory labels and a short rationale.
324
+ *
325
+ * @category Arrangement & Analysis
326
+ */
208
327
  type AnalyzedNote = {
209
328
  noteId: number;
210
329
  labels: TheoryLabel[];
211
330
  rationale?: string;
212
331
  };
213
- /** A single note in a monophonic voice: a {@link NoteEvent} with a stable id. */
332
+ /**
333
+ * A single note in a monophonic voice: a {@link NoteEvent} with a stable id.
334
+ *
335
+ * @category Arrangement & Analysis
336
+ */
214
337
  type VoiceNote = NoteEvent & {
215
338
  id: number;
216
339
  };
@@ -224,11 +347,30 @@ type VoiceNote = NoteEvent & {
224
347
  * avoid, or an unresolved-dissonance label. Leading-tone resolutions are noted
225
348
  * additionally.
226
349
  *
350
+ * The voice is expected to be monophonic (one note at a time). Notes sharing an
351
+ * onset are treated as simultaneous cluster members, not melodic neighbors, so
352
+ * they receive no melodic labels (suspension, passing, neighbor, anticipation,
353
+ * escape) — only harmonic ones. Callers with truly polyphonic material should
354
+ * split it into monophonic sub-voices first, as `analyzeArrangement` does.
355
+ *
227
356
  * @param voice The monophonic voice, in time order.
228
357
  * @param chordAtBeat Chord sounding at a given beat, or null.
229
358
  * @param key Key context for leading-tone detection.
230
359
  * @param otherVoicesAtBeat Other sounding voices at a given beat.
231
360
  * @returns One annotation per input note.
361
+ * @example
362
+ * ```ts
363
+ * import { analyzeVoice, makeChord, majorKey } from '@libraz/libcantus';
364
+ * const voice = [
365
+ * { id: 0, pitch: 60, startBeat: 0, durationBeat: 1 },
366
+ * { id: 1, pitch: 62, startBeat: 1, durationBeat: 1 },
367
+ * { id: 2, pitch: 64, startBeat: 2, durationBeat: 1 },
368
+ * ];
369
+ * const cMajor = makeChord(0, 'maj');
370
+ * const labels = analyzeVoice(voice, () => cMajor, majorKey(0), () => []);
371
+ * labels; // one AnalyzedNote per input note, in the same order
372
+ * ```
373
+ * @category Arrangement & Analysis
232
374
  */
233
375
  declare function analyzeVoice(voice: VoiceNote[], chordAtBeat: (beat: number) => Chord$1 | null, key: KeyScale, otherVoicesAtBeat: (beat: number) => VoiceSnapshot[]): AnalyzedNote[];
234
376
 
@@ -239,12 +381,30 @@ declare function analyzeVoice(voice: VoiceNote[], chordAtBeat: (beat: number) =>
239
381
  * Positions and durations are measured in quarter-note beats, matching the rest
240
382
  * of the library's beat convention (four quarter-note beats per bar in 4/4).
241
383
  */
242
- /** A time signature as a numerator over a note-value denominator. */
384
+ /**
385
+ * A time signature as a numerator over a note-value denominator.
386
+ *
387
+ * @category Rhythm & Meter
388
+ */
243
389
  type TimeSignature = {
244
390
  numerator: number;
245
391
  denominator: number;
392
+ /**
393
+ * Optional additive grouping of the bar's main pulses, as the felt-beat
394
+ * lengths in pulses — e.g. `[2, 2, 3]` for a 2+2+3 reading of 7/8, or
395
+ * `[3, 2]` for 5/8. The entries must be positive integers summing to
396
+ * {@link pulsesPerBar}. When present, the head pulse of each group (other
397
+ * than the downbeat) is treated as a secondary strong pulse by
398
+ * {@link metricWeight}/{@link isStrongBeat}; when absent, all main pulses
399
+ * are weighted equally as flat, evenly divided pulses.
400
+ */
401
+ grouping?: number[];
246
402
  };
247
- /** A position expressed as a bar index and a quarter-note offset within the bar. */
403
+ /**
404
+ * A position expressed as a bar index and a quarter-note offset within the bar.
405
+ *
406
+ * @category Rhythm & Meter
407
+ */
248
408
  type BarPosition = {
249
409
  bar: number;
250
410
  /** Quarter-note offset from the start of the bar. */
@@ -256,9 +416,19 @@ type BarPosition = {
256
416
  * @param text The signature text.
257
417
  * @returns The parsed time signature.
258
418
  * @throws If the text is not `n/d` with positive integers.
419
+ * @example
420
+ * ```ts
421
+ * import { parseTimeSignature } from '@libraz/libcantus';
422
+ * parseTimeSignature('6/8'); // { numerator: 6, denominator: 8 }
423
+ * ```
424
+ * @category Rhythm & Meter
259
425
  */
260
426
  declare function parseTimeSignature(text: string): TimeSignature;
261
- /** Render a time signature as `"n/d"`. */
427
+ /**
428
+ * Render a time signature as `"n/d"`.
429
+ *
430
+ * @category Rhythm & Meter
431
+ */
262
432
  declare function formatTimeSignature(ts: TimeSignature): string;
263
433
  /**
264
434
  * Whether a meter is compound: its main pulses each divide into three, as in
@@ -268,6 +438,7 @@ declare function formatTimeSignature(ts: TimeSignature): string;
268
438
  *
269
439
  * @param ts The time signature.
270
440
  * @returns True for compound meters.
441
+ * @category Rhythm & Meter
271
442
  */
272
443
  declare function isCompound(ts: TimeSignature): boolean;
273
444
  /**
@@ -275,14 +446,22 @@ declare function isCompound(ts: TimeSignature): boolean;
275
446
  *
276
447
  * @param ts The time signature.
277
448
  * @returns The bar length in quarter notes.
449
+ * @category Rhythm & Meter
278
450
  */
279
451
  declare function beatsPerBar(ts: TimeSignature): number;
280
452
  /**
281
453
  * Number of main pulses (felt beats) per bar: the numerator for simple meters,
282
454
  * a third of it for compound meters.
283
455
  *
456
+ * For additive/irregular meters such as 7/8 or 5/8 this counts the raw pulses
457
+ * (7 and 5 respectively), which are otherwise felt as flat, evenly divided and
458
+ * equally accented pulses. To recover a 2+2+3 or 3+2 felt-beat grouping, set
459
+ * {@link TimeSignature.grouping}; {@link metricWeight} then accents each
460
+ * group's head pulse.
461
+ *
284
462
  * @param ts The time signature.
285
463
  * @returns The pulse count per bar.
464
+ * @category Rhythm & Meter
286
465
  */
287
466
  declare function pulsesPerBar(ts: TimeSignature): number;
288
467
  /**
@@ -291,6 +470,13 @@ declare function pulsesPerBar(ts: TimeSignature): number;
291
470
  * @param beatInQuarters Absolute position in quarter-note beats.
292
471
  * @param ts The time signature.
293
472
  * @returns The bar and in-bar quarter-note offset.
473
+ * @example
474
+ * ```ts
475
+ * import { parseTimeSignature, beatToBarPosition } from '@libraz/libcantus';
476
+ * const ts = parseTimeSignature('4/4');
477
+ * beatToBarPosition(5, ts); // { bar: 1, beat: 1 }
478
+ * ```
479
+ * @category Rhythm & Meter
294
480
  */
295
481
  declare function beatToBarPosition(beatInQuarters: number, ts: TimeSignature): BarPosition;
296
482
  /**
@@ -300,16 +486,33 @@ declare function beatToBarPosition(beatInQuarters: number, ts: TimeSignature): B
300
486
  * @param pos The bar position.
301
487
  * @param ts The time signature.
302
488
  * @returns The absolute position in quarter-note beats.
489
+ * @category Rhythm & Meter
303
490
  */
304
491
  declare function barPositionToBeat(pos: BarPosition, ts: TimeSignature): number;
305
492
  /**
306
493
  * Metric weight of a position within its bar, on a 0–3 scale:
307
- * 3 the downbeat, 2 a secondary strong pulse (the bar's midpoint in even
308
- * meters), 1 any other main pulse, and 0 an off-pulse subdivision.
494
+ * 3 the downbeat, 2 a secondary strong pulse, 1 any other main pulse, and 0 an
495
+ * off-pulse subdivision.
496
+ *
497
+ * The secondary strong pulse is the bar's midpoint in even simple/compound
498
+ * meters. For an additive/irregular meter with {@link TimeSignature.grouping}
499
+ * set (e.g. `[2, 2, 3]` for 7/8), each group's head pulse other than the
500
+ * downbeat is the secondary strong pulse instead; without a grouping every
501
+ * non-downbeat main pulse of such a meter weighs 1 (flat, evenly divided
502
+ * pulses).
309
503
  *
310
504
  * @param beatInQuarters Absolute or in-bar quarter-note position.
311
505
  * @param ts The time signature.
312
506
  * @returns The metric weight (0–3).
507
+ * @throws If `ts.grouping` is present but is not a positive-integer list
508
+ * summing to {@link pulsesPerBar}.
509
+ * @example
510
+ * ```ts
511
+ * import { parseTimeSignature, metricWeight } from '@libraz/libcantus';
512
+ * const ts = parseTimeSignature('4/4');
513
+ * metricWeight(0, ts); // 3 (the downbeat)
514
+ * ```
515
+ * @category Rhythm & Meter
313
516
  */
314
517
  declare function metricWeight(beatInQuarters: number, ts: TimeSignature): number;
315
518
  /**
@@ -319,6 +522,7 @@ declare function metricWeight(beatInQuarters: number, ts: TimeSignature): number
319
522
  * @param beatInQuarters Absolute or in-bar quarter-note position.
320
523
  * @param ts The time signature.
321
524
  * @returns True on strong beats.
525
+ * @category Rhythm & Meter
322
526
  */
323
527
  declare function isStrongBeat(beatInQuarters: number, ts: TimeSignature): boolean;
324
528
  /**
@@ -329,6 +533,7 @@ declare function isStrongBeat(beatInQuarters: number, ts: TimeSignature): boolea
329
533
  * @param count Number of equal parts.
330
534
  * @returns `count` equal durations summing to `totalBeats`.
331
535
  * @throws If `count` is not a positive integer.
536
+ * @category Rhythm & Meter
332
537
  */
333
538
  declare function tuplet(totalBeats: number, count: number): number[];
334
539
 
@@ -341,11 +546,23 @@ declare function tuplet(totalBeats: number, count: number): number[];
341
546
  * spelled key signature.
342
547
  */
343
548
 
344
- /** The three broad harmonic functions of tonal music. */
549
+ /**
550
+ * The three broad harmonic functions of tonal music.
551
+ *
552
+ * @category Functional Harmony
553
+ */
345
554
  type HarmonicFunction = 'tonic' | 'subdominant' | 'dominant';
346
- /** A recognized cadence type, or null when a chord pair forms none. */
555
+ /**
556
+ * A recognized cadence type, or null when a chord pair forms none.
557
+ *
558
+ * @category Functional Harmony
559
+ */
347
560
  type Cadence = 'authentic' | 'plagal' | 'half' | 'deceptive' | null;
348
- /** Whether a key's scale has a minor third and no major third (a minor key). */
561
+ /**
562
+ * Whether a key's scale has a minor third and no major third (a minor key).
563
+ *
564
+ * @category Functional Harmony
565
+ */
349
566
  declare function isMinorKey(key: KeyScale): boolean;
350
567
  /**
351
568
  * Build the chord denoted by a Roman numeral in a key.
@@ -358,14 +575,24 @@ declare function isMinorKey(key: KeyScale): boolean;
358
575
  * carry a `bassPc`.
359
576
  *
360
577
  * The `ø` glyph always denotes the half-diminished seventh (`iiø` == `iiø7` ==
361
- * `m7b5`), since no half-diminished triad exists. Root-position extension
362
- * figures map to fixed qualities (`V9` -> `dom9`, `V11` -> `11`, `V13` -> `13`).
578
+ * `m7b5`), since no half-diminished triad exists. Extension and added-tone
579
+ * suffixes are the canonical case-sensitive forms emitted by
580
+ * {@link chordToRoman} and honor the numeral case: `V9` -> `dom9`, `ii9` ->
581
+ * `min9`, `Imaj9` -> `maj9`, `V11` -> `11`, `V13` -> `13`, `Iadd6`/`iadd6` ->
582
+ * `6`/`min6`, `I69` -> `6/9`, `Isus2`/`Isus4`, `Iadd9`/`Iadd11`, `Ib5` ->
583
+ * `majb5`, `I5` -> `5`, and the altered dominants `V7b9`/`V7#9`/`V7#11`/`V7b13`.
363
584
  * A figure string that is neither a recognized inversion nor a supported
364
- * extension throws rather than silently degrading to a triad.
585
+ * quality suffix throws rather than silently degrading to a triad.
365
586
  *
366
587
  * @param text The Roman numeral.
367
588
  * @param key The prevailing key.
368
589
  * @returns The chord.
590
+ * @example
591
+ * ```ts
592
+ * import { romanToChord, majorKey } from '@libraz/libcantus';
593
+ * romanToChord('V7', majorKey(0)); // G7 in C major: { rootPc: 7, quality: 'dom7', ... }
594
+ * ```
595
+ * @category Functional Harmony
369
596
  */
370
597
  declare function romanToChord(text: string, key: KeyScale): Chord$1;
371
598
  /**
@@ -375,11 +602,20 @@ declare function romanToChord(text: string, key: KeyScale): Chord$1;
375
602
  * correct in both major and minor keys (and any custom scale). The quality
376
603
  * selects the case and suffix; chromatic roots receive a flat/sharp spelling by
377
604
  * convention. When the chord carries a `bassPc` on a chord tone, a figured-bass
378
- * inversion (`6`, `64`, `65`, `43`, `42`) is emitted.
605
+ * inversion (`6`, `64`, `65`, `43`, `42`) is emitted for plain triads and true
606
+ * seventh chords; added-tone and extended qualities have no lossless figure and
607
+ * render in root position instead (the bass is dropped, pitch classes are
608
+ * preserved).
379
609
  *
380
610
  * @param chord The chord to name.
381
611
  * @param key The prevailing key.
382
612
  * @returns The Roman numeral string.
613
+ * @example
614
+ * ```ts
615
+ * import { chordToRoman, makeChord, majorKey } from '@libraz/libcantus';
616
+ * chordToRoman(makeChord(7, 'dom7'), majorKey(0)); // => 'V7' (G7 in C major)
617
+ * ```
618
+ * @category Functional Harmony
383
619
  */
384
620
  declare function chordToRoman(chord: Chord$1, key: KeyScale): string;
385
621
  /**
@@ -390,11 +626,20 @@ declare function chordToRoman(chord: Chord$1, key: KeyScale): string;
390
626
  * @param chord The chord.
391
627
  * @param key The prevailing key.
392
628
  * @returns The harmonic function.
629
+ * @category Functional Harmony
393
630
  */
394
631
  declare function functionOf(chord: Chord$1, key: KeyScale): HarmonicFunction;
395
- /** The origin of a recognized non-diatonic chord, or null when none applies. */
632
+ /**
633
+ * The origin of a recognized non-diatonic chord, or null when none applies.
634
+ *
635
+ * @category Functional Harmony
636
+ */
396
637
  type BorrowedSource = 'parallel-minor' | 'parallel-major' | 'neapolitan' | null;
397
- /** The result of {@link analyzeChord}: function, borrowing, and Roman numeral. */
638
+ /**
639
+ * The result of {@link analyzeChord}: function, borrowing, and Roman numeral.
640
+ *
641
+ * @category Functional Harmony
642
+ */
398
643
  type ChordAnalysis = {
399
644
  function: HarmonicFunction;
400
645
  borrowed: boolean;
@@ -412,6 +657,7 @@ type ChordAnalysis = {
412
657
  * @param chord The chord to test.
413
658
  * @param key The prevailing key.
414
659
  * @returns True if all chord pitch classes are scale tones.
660
+ * @category Functional Harmony
415
661
  */
416
662
  declare function isDiatonic(chord: Chord$1, key: KeyScale): boolean;
417
663
  /**
@@ -422,6 +668,7 @@ declare function isDiatonic(chord: Chord$1, key: KeyScale): boolean;
422
668
  *
423
669
  * @param key The key to mirror.
424
670
  * @returns The parallel major or natural-minor key on the same tonic.
671
+ * @category Functional Harmony
425
672
  */
426
673
  declare function parallelKey(key: KeyScale): KeyScale;
427
674
  /**
@@ -438,6 +685,7 @@ declare function parallelKey(key: KeyScale): KeyScale;
438
685
  * @param chord The chord to test.
439
686
  * @param key The prevailing key.
440
687
  * @returns True if the chord is borrowed from the parallel mode.
688
+ * @category Functional Harmony
441
689
  */
442
690
  declare function isBorrowedChord(chord: Chord$1, key: KeyScale): boolean;
443
691
  /**
@@ -451,6 +699,7 @@ declare function isBorrowedChord(chord: Chord$1, key: KeyScale): boolean;
451
699
  * @param chord The chord to classify.
452
700
  * @param key The prevailing key.
453
701
  * @returns The borrowing source, or null.
702
+ * @category Functional Harmony
454
703
  */
455
704
  declare function borrowedSource(chord: Chord$1, key: KeyScale): BorrowedSource;
456
705
  /**
@@ -465,6 +714,13 @@ declare function borrowedSource(chord: Chord$1, key: KeyScale): BorrowedSource;
465
714
  * @param chord The chord to analyze.
466
715
  * @param key The prevailing key.
467
716
  * @returns The chord analysis.
717
+ * @example
718
+ * ```ts
719
+ * import { analyzeChord, makeChord, majorKey } from '@libraz/libcantus';
720
+ * analyzeChord(makeChord(7, 'dom7'), majorKey(0));
721
+ * // { function: 'dominant', borrowed: false, source: null, roman: 'V7' }
722
+ * ```
723
+ * @category Functional Harmony
468
724
  */
469
725
  declare function analyzeChord(chord: Chord$1, key: KeyScale): ChordAnalysis;
470
726
  /**
@@ -482,6 +738,12 @@ declare function analyzeChord(chord: Chord$1, key: KeyScale): ChordAnalysis;
482
738
  * @param to The final chord.
483
739
  * @param key The prevailing key.
484
740
  * @returns The cadence type, or null.
741
+ * @example
742
+ * ```ts
743
+ * import { detectCadence, makeChord, majorKey } from '@libraz/libcantus';
744
+ * detectCadence(makeChord(7, 'maj'), makeChord(0, 'maj'), majorKey(0)); // => 'authentic'
745
+ * ```
746
+ * @category Functional Harmony
485
747
  */
486
748
  declare function detectCadence(from: Chord$1, to: Chord$1, key: KeyScale): Cadence;
487
749
  /**
@@ -490,14 +752,27 @@ declare function detectCadence(from: Chord$1, to: Chord$1, key: KeyScale): Caden
490
752
  * @param targetDegree 0-based scale degree to tonicize.
491
753
  * @param key The prevailing key.
492
754
  * @returns A dominant-seventh chord a fifth above the target's root.
755
+ * @category Functional Harmony
493
756
  */
494
757
  declare function secondaryDominant(targetDegree: number, key: KeyScale): Chord$1;
495
758
 
496
- /** Broad production style a progression preset suits. */
759
+ /**
760
+ * Broad production style a progression preset suits.
761
+ *
762
+ * @category Composition
763
+ */
497
764
  type ProgStyle = 'minimal' | 'dance' | 'idol' | 'rock';
498
- /** Harmonic-function role of a progression as a whole. */
765
+ /**
766
+ * Harmonic-function role of a progression as a whole.
767
+ *
768
+ * @category Composition
769
+ */
499
770
  type ProgFunction = 'loop' | 'tensionBuild' | 'cadenceStrong' | 'stable';
500
- /** A named chord-progression preset expressed in scale degrees. */
771
+ /**
772
+ * A named chord-progression preset expressed in scale degrees.
773
+ *
774
+ * @category Composition
775
+ */
501
776
  type ProgressionPreset = {
502
777
  id: string;
503
778
  name: string;
@@ -505,7 +780,11 @@ type ProgressionPreset = {
505
780
  functional: ProgFunction;
506
781
  styles: ProgStyle[];
507
782
  };
508
- /** A chord placed on the timeline by {@link generateProgression}. */
783
+ /**
784
+ * A chord placed on the timeline by {@link generateProgression}.
785
+ *
786
+ * @category Composition
787
+ */
509
788
  type GeneratedChord = {
510
789
  rootPc: number;
511
790
  quality: ChordQuality;
@@ -516,7 +795,11 @@ type GeneratedChord = {
516
795
  /** True when the chord is a secondary dominant tonicizing another degree. */
517
796
  secondaryDominant?: boolean;
518
797
  };
519
- /** Options controlling {@link generateProgression}. */
798
+ /**
799
+ * Options controlling {@link generateProgression}.
800
+ *
801
+ * @category Composition
802
+ */
520
803
  type GenerateProgressionOptions = {
521
804
  key: KeyScale;
522
805
  style: ProgStyle;
@@ -524,17 +807,32 @@ type GenerateProgressionOptions = {
524
807
  presetId?: string;
525
808
  ext?: ChordQuality | 'auto';
526
809
  reharmonize?: boolean;
810
+ /**
811
+ * Seed for the deterministic preset choice and reharmonization.
812
+ *
813
+ * @defaultValue 0
814
+ */
527
815
  seed?: number;
528
816
  };
529
- /** All built-in progression presets. */
817
+ /**
818
+ * All built-in progression presets.
819
+ *
820
+ * @category Composition
821
+ */
530
822
  declare function progressions(): ProgressionPreset[];
531
- /** Presets whose style list includes the given style. */
823
+ /**
824
+ * Presets whose style list includes the given style.
825
+ *
826
+ * @category Composition
827
+ */
532
828
  declare function progressionsByStyle(style: ProgStyle): ProgressionPreset[];
533
829
  /**
534
830
  * Generate a chord progression laid out one chord per bar.
535
831
  *
536
832
  * A preset is chosen by `presetId` when given, otherwise deterministically from
537
- * the presets matching `style`, seeded by `seed`. The preset's degrees cycle to
833
+ * the presets matching `style`, seeded by `seed`. An unknown `presetId` is a
834
+ * caller error and throws rather than silently falling back to a random preset.
835
+ * The preset's degrees cycle to
538
836
  * fill `bars`; each bar is four beats, so `startBeat` is `barIndex * 4`. Chord
539
837
  * roots come from the key's diatonic scale-degree mapping. When `ext` is
540
838
  * omitted or `'auto'`, each chord takes its diatonic triad quality; otherwise
@@ -544,16 +842,34 @@ declare function progressionsByStyle(style: ProgStyle): ProgressionPreset[];
544
842
  *
545
843
  * @param opts Generation options.
546
844
  * @returns One chord per bar in timeline order.
845
+ * @throws If `presetId` is given but does not match any built-in preset.
846
+ *
847
+ * @example
848
+ * ```ts
849
+ * import { generateProgression, majorKey } from '@libraz/libcantus';
850
+ * const chords = generateProgression({ key: majorKey(0), style: 'dance', bars: 4 });
851
+ * // Deterministic for a given seed (defaults to 0); one GeneratedChord per bar.
852
+ * ```
853
+ *
854
+ * @category Composition
547
855
  */
548
856
  declare function generateProgression(opts: GenerateProgressionOptions): GeneratedChord[];
549
857
 
550
- /** A chord occupying a half-open beat span. */
858
+ /**
859
+ * A chord occupying a half-open beat span.
860
+ *
861
+ * @category Arrangement & Analysis
862
+ */
551
863
  type ChordSegment = {
552
864
  startBeat: number;
553
865
  endBeat: number;
554
866
  chord: Chord$1;
555
867
  };
556
- /** A beat-indexed sequence of chord segments. */
868
+ /**
869
+ * A beat-indexed sequence of chord segments.
870
+ *
871
+ * @category Arrangement & Analysis
872
+ */
557
873
  type ChordTimeline = {
558
874
  /** The chord sounding at a beat, or null when no segment covers it. */
559
875
  at: (beat: number) => Chord$1 | null;
@@ -570,20 +886,41 @@ type ChordTimeline = {
570
886
  * @param chords Placed chords in time order.
571
887
  * @param totalBeats End of the timeline in beats.
572
888
  * @returns A queryable chord timeline.
889
+ * @category Arrangement & Analysis
573
890
  */
574
891
  declare function chordTimelineFromChords(chords: GeneratedChord[], totalBeats: number): ChordTimeline;
575
- /** Options controlling {@link chordTimelineFromNotes}. */
892
+ /**
893
+ * Options controlling {@link chordTimelineFromNotes}.
894
+ *
895
+ * @category Arrangement & Analysis
896
+ */
576
897
  type ChordTimelineOptions = {
577
898
  /** Key context; inferred from the notes with {@link detectKey} when omitted. */
578
899
  key?: KeyScale;
579
- /** Time signature used for metric accents; defaults to 4/4. */
900
+ /**
901
+ * Time signature used for metric accents; defaults to 4/4.
902
+ *
903
+ * @defaultValue `4/4`
904
+ */
580
905
  ts?: TimeSignature;
581
- /** Window length in beats per chord slot; defaults to one bar of `ts`. */
906
+ /**
907
+ * Window length in beats per chord slot; defaults to one bar of `ts`.
908
+ *
909
+ * @defaultValue one bar of `ts`
910
+ */
582
911
  harmonicRhythm?: number;
583
- /** End of the analyzed span in beats; defaults to the end of the last note. */
912
+ /**
913
+ * End of the analyzed span in beats; defaults to the end of the last note.
914
+ *
915
+ * @defaultValue the end of the last note
916
+ */
584
917
  totalBeats?: number;
585
918
  };
586
- /** The result of {@link chordTimelineFromNotes}. */
919
+ /**
920
+ * The result of {@link chordTimelineFromNotes}.
921
+ *
922
+ * @category Arrangement & Analysis
923
+ */
587
924
  type ChordTimelineResult = {
588
925
  /** The inferred timeline, with adjacent identical chords merged. */
589
926
  timeline: ChordTimeline;
@@ -604,13 +941,33 @@ type ChordTimelineResult = {
604
941
  * the fraction of the window weight explained by chord tones, reduced when the
605
942
  * match is inexact, and duration-weighted across merged windows.
606
943
  *
944
+ * Notes with a zero or negative duration never sound, so they are dropped at
945
+ * ingest: they contribute to neither the key inference, the span, nor any
946
+ * window's histogram.
947
+ *
607
948
  * @param notes The notes to analyze (any number of tracks, flattened).
608
949
  * @param opts Analysis options; see {@link ChordTimelineOptions}.
609
950
  * @returns The inferred timeline, the key used, and per-segment confidences.
610
951
  * @throws If `harmonicRhythm` is not positive.
952
+ * @example
953
+ * ```ts
954
+ * import { chordTimelineFromNotes } from '@libraz/libcantus';
955
+ * const notes = [
956
+ * { pitch: 60, startBeat: 0, durationBeat: 2 }, // C
957
+ * { pitch: 64, startBeat: 0, durationBeat: 2 }, // E
958
+ * { pitch: 67, startBeat: 0, durationBeat: 2 }, // G
959
+ * ];
960
+ * const { timeline, key } = chordTimelineFromNotes(notes);
961
+ * timeline.at(0); // the chord inferred over beat 0, or null
962
+ * ```
963
+ * @category Arrangement & Analysis
611
964
  */
612
965
  declare function chordTimelineFromNotes(notes: NoteEvent[], opts?: ChordTimelineOptions): ChordTimelineResult;
613
- /** A cadence found between two consecutive timeline segments. */
966
+ /**
967
+ * A cadence found between two consecutive timeline segments.
968
+ *
969
+ * @category Arrangement & Analysis
970
+ */
614
971
  type CadenceHit = {
615
972
  /** The beat where the cadence arrives (the second chord's onset). */
616
973
  atBeat: number;
@@ -621,12 +978,25 @@ type CadenceHit = {
621
978
  /**
622
979
  * Find cadences between consecutive segments of a chord timeline.
623
980
  *
624
- * Each adjacent segment pair is classified with {@link detectCadence}; pairs
625
- * forming no cadence are skipped.
981
+ * Each temporally adjacent segment pair is classified with
982
+ * {@link detectCadence}; pairs forming no cadence are skipped. Segments
983
+ * separated by a gap (a rest in the timeline) are not a chord-to-chord
984
+ * progression, so they are never paired.
626
985
  *
627
986
  * @param timeline The chord timeline to scan.
628
987
  * @param key The prevailing key.
629
988
  * @returns The cadences found, in time order.
989
+ * @example
990
+ * ```ts
991
+ * import { chordTimelineFromNotes, detectCadences } from '@libraz/libcantus';
992
+ * const notes = [
993
+ * { pitch: 67, startBeat: 0, durationBeat: 4 }, // G, a dominant
994
+ * { pitch: 60, startBeat: 4, durationBeat: 4 }, // C, the tonic
995
+ * ];
996
+ * const { timeline, key } = chordTimelineFromNotes(notes);
997
+ * const cadences = detectCadences(timeline, key);
998
+ * ```
999
+ * @category Arrangement & Analysis
630
1000
  */
631
1001
  declare function detectCadences(timeline: ChordTimeline, key: KeyScale): CadenceHit[];
632
1002
 
@@ -640,22 +1010,38 @@ declare function detectCadences(timeline: ChordTimeline, key: KeyScale): Cadence
640
1010
  * curve is sampled across the piece.
641
1011
  */
642
1012
 
643
- /** The musical role a track plays in the arrangement. */
1013
+ /**
1014
+ * The musical role a track plays in the arrangement.
1015
+ *
1016
+ * @category Arrangement & Analysis
1017
+ */
644
1018
  type TrackRole = 'melody' | 'harmony' | 'bass' | 'other';
645
- /** One input track: its notes plus optional name and role. */
1019
+ /**
1020
+ * One input track: its notes plus optional name and role.
1021
+ *
1022
+ * @category Arrangement & Analysis
1023
+ */
646
1024
  type ArrangementTrack = {
647
1025
  name?: string;
648
1026
  role?: TrackRole;
649
1027
  notes: NoteEvent[];
650
1028
  };
651
- /** A track after analysis: its resolved name, role, and per-note annotations. */
1029
+ /**
1030
+ * A track after analysis: its resolved name, role, and per-note annotations.
1031
+ *
1032
+ * @category Arrangement & Analysis
1033
+ */
652
1034
  type TrackAnalysis = {
653
1035
  name: string;
654
1036
  role: TrackRole;
655
1037
  /** One {@link AnalyzedNote} per note, labelled against the inferred chords. */
656
1038
  notes: AnalyzedNote[];
657
1039
  };
658
- /** A note that clashes with the harmony sounding beneath it. */
1040
+ /**
1041
+ * A note that clashes with the harmony sounding beneath it.
1042
+ *
1043
+ * @category Arrangement & Analysis
1044
+ */
659
1045
  type Conflict = {
660
1046
  beat: number;
661
1047
  trackName: string;
@@ -666,7 +1052,11 @@ type Conflict = {
666
1052
  reasons: number;
667
1053
  rationale?: string;
668
1054
  };
669
- /** The full result of {@link analyzeArrangement}. */
1055
+ /**
1056
+ * The full result of {@link analyzeArrangement}.
1057
+ *
1058
+ * @category Arrangement & Analysis
1059
+ */
670
1060
  type ArrangementAnalysis = {
671
1061
  key: KeyScale;
672
1062
  timeline: ChordTimeline;
@@ -676,15 +1066,31 @@ type ArrangementAnalysis = {
676
1066
  /** Notes clashing with the sounding harmony, worst severity first. */
677
1067
  conflicts: Conflict[];
678
1068
  };
679
- /** Options controlling {@link analyzeArrangement} and {@link tensionCurve}. */
1069
+ /**
1070
+ * Options controlling {@link analyzeArrangement} and {@link tensionCurve}.
1071
+ *
1072
+ * @category Arrangement & Analysis
1073
+ */
680
1074
  type ArrangementOptions = {
681
1075
  /** Key context; inferred from the pooled notes when omitted. */
682
1076
  key?: KeyScale;
683
- /** Time signature; defaults to 4/4. */
1077
+ /**
1078
+ * Time signature; defaults to 4/4.
1079
+ *
1080
+ * @defaultValue `4/4`
1081
+ */
684
1082
  ts?: TimeSignature;
685
- /** Chord-slot length in beats; defaults to one bar of `ts`. */
1083
+ /**
1084
+ * Chord-slot length in beats; defaults to one bar of `ts`.
1085
+ *
1086
+ * @defaultValue one bar of `ts`
1087
+ */
686
1088
  harmonicRhythm?: number;
687
- /** Safety profile used for conflict detection; defaults to `pop`. */
1089
+ /**
1090
+ * Safety profile used for conflict detection; defaults to `pop`.
1091
+ *
1092
+ * @defaultValue `'pop'`
1093
+ */
688
1094
  profile?: SafetyProfile;
689
1095
  };
690
1096
  /**
@@ -693,18 +1099,42 @@ type ArrangementOptions = {
693
1099
  * The chord timeline and key are inferred from the pooled notes of every track
694
1100
  * (see {@link chordTimelineFromNotes}); pooling all voices is robust even when
695
1101
  * roles are absent or a track doubles the harmony, so it is preferred over
696
- * deriving the harmony from a subset. Each track is then labelled note-by-note
697
- * against that harmony with {@link analyzeVoice}, seeing the other tracks as its
698
- * accompaniment, and every note is re-checked with {@link evaluateSafety}: those
699
- * that are not {@link NoteSafety.Safe} against the sounding chord become
700
- * conflicts, sorted worst severity first and then by beat.
1102
+ * deriving the harmony from a subset. Zero- and negative-length notes never
1103
+ * sound, so they are dropped at ingest and appear in neither the annotations
1104
+ * nor the conflicts.
1105
+ *
1106
+ * Voice analysis assumes one monophonic voice at a time, so each track is
1107
+ * first partitioned into monophonic sub-voices (a polyphonic block-chord track
1108
+ * fans out into one sub-voice per simultaneous note; a monophonic track is
1109
+ * unaffected). Each sub-voice is labelled note-by-note against the harmony
1110
+ * with {@link analyzeVoice}, seeing every other sub-voice — including siblings
1111
+ * within the same track — as its accompaniment. Every note is then re-checked
1112
+ * with {@link evaluateSafety} at its onset and again at each chord change it
1113
+ * sustains across, so a held note that clashes with a later chord is caught:
1114
+ * evaluations that are not {@link NoteSafety.Safe} become conflicts, one per
1115
+ * clashing beat, sorted worst severity first and then by beat.
701
1116
  *
702
1117
  * @param tracks The tracks to analyse.
703
1118
  * @param opts Analysis options; see {@link ArrangementOptions}.
704
1119
  * @returns The inferred harmony, per-track annotations, cadences, and conflicts.
1120
+ * @example
1121
+ * ```ts
1122
+ * import { analyzeArrangement } from '@libraz/libcantus';
1123
+ * const melody = [
1124
+ * { pitch: 60, startBeat: 0, durationBeat: 2 },
1125
+ * { pitch: 67, startBeat: 2, durationBeat: 2 },
1126
+ * ];
1127
+ * const { key, conflicts } = analyzeArrangement([{ role: 'melody', notes: melody }]);
1128
+ * conflicts; // notes clashing with the inferred harmony, worst severity first
1129
+ * ```
1130
+ * @category Arrangement & Analysis
705
1131
  */
706
1132
  declare function analyzeArrangement(tracks: ArrangementTrack[], opts?: ArrangementOptions): ArrangementAnalysis;
707
- /** A tension reading sampled at a beat. */
1133
+ /**
1134
+ * A tension reading sampled at a beat.
1135
+ *
1136
+ * @category Arrangement & Analysis
1137
+ */
708
1138
  type TensionPoint = {
709
1139
  beat: number;
710
1140
  /** Combined tension in [0, 1]. */
@@ -729,6 +1159,14 @@ type TensionPoint = {
729
1159
  * @param opts Analysis options plus an optional `step` (default one beat).
730
1160
  * @returns One {@link TensionPoint} per sampled beat, in beat order.
731
1161
  * @throws If `step` is not positive.
1162
+ * @example
1163
+ * ```ts
1164
+ * import { tensionCurve } from '@libraz/libcantus';
1165
+ * const notes = [{ pitch: 60, startBeat: 0, durationBeat: 4 }];
1166
+ * const curve = tensionCurve([{ notes }], { step: 1 });
1167
+ * curve; // one { beat, tension } sample per beat, in beat order
1168
+ * ```
1169
+ * @category Arrangement & Analysis
732
1170
  */
733
1171
  declare function tensionCurve(tracks: ArrangementTrack[], opts?: ArrangementOptions & {
734
1172
  step?: number;
@@ -748,27 +1186,55 @@ declare function tensionCurve(tracks: ArrangementTrack[], opts?: ArrangementOpti
748
1186
  * library-wide convention.
749
1187
  */
750
1188
 
751
- /** A chord sounding over a half-open beat span `[startBeat, endBeat)`. */
1189
+ /**
1190
+ * A chord sounding over a half-open beat span `[startBeat, endBeat)`.
1191
+ *
1192
+ * @category Composition
1193
+ */
752
1194
  type BassSegment = {
753
1195
  startBeat: number;
754
1196
  endBeat: number;
755
1197
  chord: Chord$1;
756
1198
  };
757
- /** The bass-line idiom to generate. */
1199
+ /**
1200
+ * The bass-line idiom to generate.
1201
+ *
1202
+ * @category Composition
1203
+ */
758
1204
  type BassStyle = 'root' | 'rootFifth' | 'pop' | 'walking' | 'arpeggio';
759
- /** Options controlling {@link generateBassLine}. */
1205
+ /**
1206
+ * Options controlling {@link generateBassLine}.
1207
+ *
1208
+ * @category Composition
1209
+ */
760
1210
  type BassLineOptions = {
761
1211
  /** Chord placement to follow; need not be pre-sorted. */
762
1212
  segments: BassSegment[];
763
1213
  /** Key/scale context, used for diatonic approach tones in `walking`. */
764
1214
  key: KeyScale;
765
- /** Time signature; used for metric accents. Default 4/4. */
1215
+ /**
1216
+ * Time signature; used for metric accents.
1217
+ *
1218
+ * @defaultValue `{ numerator: 4, denominator: 4 }`
1219
+ */
766
1220
  ts?: TimeSignature;
767
- /** Bass-line idiom. Default `'root'`. */
1221
+ /**
1222
+ * Bass-line idiom.
1223
+ *
1224
+ * @defaultValue `'root'`
1225
+ */
768
1226
  style?: BassStyle;
769
- /** Target register as a base MIDI octave; roots land around `octave*12+12`. Default 2. */
1227
+ /**
1228
+ * Target register as a base MIDI octave; roots land around `octave*12+12`.
1229
+ *
1230
+ * @defaultValue 2
1231
+ */
770
1232
  octave?: number;
771
- /** Seed for the deterministic PRNG. Default 0. */
1233
+ /**
1234
+ * Seed for the deterministic PRNG.
1235
+ *
1236
+ * @defaultValue 0
1237
+ */
772
1238
  seed?: number;
773
1239
  };
774
1240
  /**
@@ -781,6 +1247,18 @@ type BassLineOptions = {
781
1247
  *
782
1248
  * @param opts Segments, key, and generation options.
783
1249
  * @returns Bass notes sorted by onset, non-overlapping.
1250
+ *
1251
+ * @example
1252
+ * ```ts
1253
+ * import { generateBassLine, makeChord, majorKey } from '@libraz/libcantus';
1254
+ * const segments = [
1255
+ * { startBeat: 0, endBeat: 4, chord: makeChord(0, 'maj') },
1256
+ * { startBeat: 4, endBeat: 8, chord: makeChord(7, 'maj') },
1257
+ * ];
1258
+ * const notes = generateBassLine({ segments, key: majorKey(0), style: 'walking' });
1259
+ * ```
1260
+ *
1261
+ * @category Composition
784
1262
  */
785
1263
  declare function generateBassLine(opts: BassLineOptions): NoteEvent[];
786
1264
 
@@ -791,9 +1269,15 @@ declare function generateBassLine(opts: BassLineOptions): NoteEvent[];
791
1269
  * @param scaleMask The scale's 12-bit mode mask.
792
1270
  * @param scaleRootPc The pitch class the mask is rooted on.
793
1271
  * @returns True if the scale is a superset of the chord.
1272
+ *
1273
+ * @category Scales
794
1274
  */
795
1275
  declare function scaleMatchesChord(chordPcs: number[], scaleMask: number, scaleRootPc: number): boolean;
796
- /** A named scale rooted on a pitch class that fits over a chord. */
1276
+ /**
1277
+ * A named scale rooted on a pitch class that fits over a chord.
1278
+ *
1279
+ * @category Scales
1280
+ */
797
1281
  type ChordScaleMatch = {
798
1282
  name: string;
799
1283
  rootPc: number;
@@ -803,13 +1287,26 @@ type ChordScaleMatch = {
803
1287
  *
804
1288
  * Only the chord root is considered as the scale root, matching the
805
1289
  * conventional chord-scale relationship. Every entry of {@link NAMED_SCALES}
806
- * whose pitch-class set is a superset of the chord's is returned, ranked by
807
- * fewest extra scale tones beyond the chord, then by scale size (heptatonic
808
- * before larger scales), then by scale name. The chromatic scale is only
809
- * returned as a fallback when no other scale contains the chord.
1290
+ * whose pitch-class set is a superset of the chord's is returned once per
1291
+ * distinct pitch-class set (aliased masks such as major/ionian report only the
1292
+ * modal name), ranked by fewest extra scale tones beyond the chord, then by
1293
+ * scale size (heptatonic before larger scales), then by scale name. For bare
1294
+ * triads and smaller chords, heptatonic scales rank before pentatonics and
1295
+ * other sizes: a pentatonic adds no modal color over a triad, so the seven-note
1296
+ * modes are the more useful answer. The chromatic scale is only returned as a
1297
+ * fallback when no other scale contains the chord.
810
1298
  *
811
1299
  * @param chord The chord to fit scales over.
812
1300
  * @returns The matching scales rooted on the chord root, best fit first.
1301
+ *
1302
+ * @example
1303
+ * ```ts
1304
+ * import { makeChord, chordScales } from '@libraz/libcantus';
1305
+ * const scales = chordScales(makeChord(0, 'maj7'));
1306
+ * // scales for Cmaj7, best fit first; each is { name, rootPc: 0 }
1307
+ * ```
1308
+ *
1309
+ * @category Scales
813
1310
  */
814
1311
  declare function chordScales(chord: Chord$1): ChordScaleMatch[];
815
1312
  /**
@@ -822,6 +1319,8 @@ declare function chordScales(chord: Chord$1): ChordScaleMatch[];
822
1319
  * @param chord The chord providing the chord tones.
823
1320
  * @param scaleName A key of {@link NAMED_SCALES}.
824
1321
  * @returns The avoid-note pitch classes, sorted ascending in [0, 11].
1322
+ *
1323
+ * @category Scales
825
1324
  */
826
1325
  declare function avoidNotes(chord: Chord$1, scaleName: string): number[];
827
1326
  /**
@@ -835,9 +1334,21 @@ declare function avoidNotes(chord: Chord$1, scaleName: string): number[];
835
1334
  * @param chord The chord providing the chord tones.
836
1335
  * @param scaleName A key of {@link NAMED_SCALES}.
837
1336
  * @returns The available-tension pitch classes, sorted ascending in [0, 11].
1337
+ *
1338
+ * @example
1339
+ * ```ts
1340
+ * import { makeChord, availableTensions } from '@libraz/libcantus';
1341
+ * availableTensions(makeChord(0, 'maj7'), 'ionian'); // [2, 9] — color tones over Cmaj7
1342
+ * ```
1343
+ *
1344
+ * @category Scales
838
1345
  */
839
1346
  declare function availableTensions(chord: Chord$1, scaleName: string): number[];
840
- /** A scale fit over a chord together with its avoid notes and tensions. */
1347
+ /**
1348
+ * A scale fit over a chord together with its avoid notes and tensions.
1349
+ *
1350
+ * @category Scales
1351
+ */
841
1352
  type ChordScaleReportEntry = {
842
1353
  name: string;
843
1354
  rootPc: number;
@@ -853,9 +1364,15 @@ type ChordScaleReportEntry = {
853
1364
  * @param chord The chord to analyze.
854
1365
  * @param limit Optional maximum number of scales to report; all by default.
855
1366
  * @returns One entry per reported scale, best fit first.
1367
+ *
1368
+ * @category Scales
856
1369
  */
857
1370
  declare function chordScaleReport(chord: Chord$1, limit?: number): ChordScaleReportEntry[];
858
- /** A chord paired with the scale chosen for it by {@link scalesForChanges}. */
1371
+ /**
1372
+ * A chord paired with the scale chosen for it by {@link scalesForChanges}.
1373
+ *
1374
+ * @category Scales
1375
+ */
859
1376
  type ScaleChoice = {
860
1377
  chord: Chord$1;
861
1378
  scale: ChordScaleMatch;
@@ -872,10 +1389,16 @@ type ScaleChoice = {
872
1389
  *
873
1390
  * @param chords The chord sequence to choose scales for.
874
1391
  * @returns One scale choice per chord, in input order.
1392
+ *
1393
+ * @category Scales
875
1394
  */
876
1395
  declare function scalesForChanges(chords: Chord$1[]): ScaleChoice[];
877
1396
 
878
- /** Options controlling {@link generateCounterMelody}. */
1397
+ /**
1398
+ * Options controlling {@link generateCounterMelody}.
1399
+ *
1400
+ * @category Voicing & Counterpoint
1401
+ */
879
1402
  type CounterMelodyOptions = {
880
1403
  /** The lead line to write against, in ascending onset order. */
881
1404
  melody: NoteEvent[];
@@ -883,22 +1406,40 @@ type CounterMelodyOptions = {
883
1406
  chordAt: (beat: number) => Chord$1 | null;
884
1407
  /** Key/scale context for scale-tone decisions. */
885
1408
  key: KeyScale;
886
- /** Meter used for strong-beat decisions (default 4/4). */
1409
+ /**
1410
+ * Meter used for strong-beat decisions.
1411
+ *
1412
+ * @defaultValue 4/4
1413
+ */
887
1414
  ts?: TimeSignature;
888
- /** Which side of the melody the counter line occupies (default `'below'`). */
1415
+ /**
1416
+ * Which side of the melody the counter line occupies.
1417
+ *
1418
+ * @defaultValue 'below'
1419
+ */
889
1420
  register?: 'above' | 'below';
890
1421
  /**
891
- * Onset strategy: `'complement'` (default) moves where the melody holds or
892
- * rests and reinforces some strong beats; `'follow'` mirrors melody onsets.
1422
+ * Onset strategy: `'complement'` moves where the melody holds or rests and
1423
+ * reinforces some strong beats; `'follow'` mirrors melody onsets.
1424
+ *
1425
+ * @defaultValue 'complement'
893
1426
  */
894
1427
  rhythm?: 'complement' | 'follow';
895
- /** Safety profile applied to candidate pitches (default `'pop'`). */
1428
+ /**
1429
+ * Safety profile applied to candidate pitches.
1430
+ *
1431
+ * @defaultValue 'pop'
1432
+ */
896
1433
  profile?: 'strict' | 'pop';
897
1434
  /** Lowest MIDI pitch the counter line may use (default derived from `register`). */
898
1435
  pitchLow?: number;
899
1436
  /** Highest MIDI pitch the counter line may use (default derived from `register`). */
900
1437
  pitchHigh?: number;
901
- /** PRNG seed; the same seed always yields the same line (default 0). */
1438
+ /**
1439
+ * PRNG seed; the same seed always yields the same line.
1440
+ *
1441
+ * @defaultValue 0
1442
+ */
902
1443
  seed?: number;
903
1444
  };
904
1445
  /**
@@ -917,6 +1458,17 @@ type CounterMelodyOptions = {
917
1458
  *
918
1459
  * @param opts The lead line, chord context callback, key, and generation knobs.
919
1460
  * @returns The counter line as note events sorted by onset; `[]` for an empty melody.
1461
+ * @example
1462
+ * ```ts
1463
+ * import { generateCounterMelody, majorKey, parseChordSymbol } from '@libraz/libcantus';
1464
+ * const melody = [{ pitch: 72, startBeat: 0, durationBeat: 2 }];
1465
+ * const counter = generateCounterMelody({
1466
+ * melody,
1467
+ * chordAt: () => parseChordSymbol('C'),
1468
+ * key: majorKey(0),
1469
+ * }); // note events below the melody, in onset order
1470
+ * ```
1471
+ * @category Voicing & Counterpoint
920
1472
  */
921
1473
  declare function generateCounterMelody(opts: CounterMelodyOptions): NoteEvent[];
922
1474
 
@@ -926,6 +1478,7 @@ declare function generateCounterMelody(opts: CounterMelodyOptions): NoteEvent[];
926
1478
  * @param upperPitch Pitch of the nominally higher voice.
927
1479
  * @param lowerPitch Pitch of the nominally lower voice.
928
1480
  * @returns True when the upper voice sits below the lower voice.
1481
+ * @category Voicing & Counterpoint
929
1482
  */
930
1483
  declare function createsVoiceCrossing(upperPitch: number, lowerPitch: number): boolean;
931
1484
  /**
@@ -935,6 +1488,7 @@ declare function createsVoiceCrossing(upperPitch: number, lowerPitch: number): b
935
1488
  * @param b Second pitch.
936
1489
  * @param twoVoice When true, the perfect fourth counts as dissonant.
937
1490
  * @returns True when the vertical interval is dissonant.
1491
+ * @category Voicing & Counterpoint
938
1492
  */
939
1493
  declare function createsVerticalDissonance(a: number, b: number, twoVoice: boolean): boolean;
940
1494
  /**
@@ -947,6 +1501,7 @@ declare function createsVerticalDissonance(a: number, b: number, twoVoice: boole
947
1501
  * @param prev Starting pitch.
948
1502
  * @param cur Ending pitch.
949
1503
  * @returns True when the leap is forbidden in strict counterpoint.
1504
+ * @category Voicing & Counterpoint
950
1505
  */
951
1506
  declare function isForbiddenMelodicLeap(prev: number, cur: number): boolean;
952
1507
  /**
@@ -962,16 +1517,29 @@ declare function isForbiddenMelodicLeap(prev: number, cur: number): boolean;
962
1517
  * A fifth expanding to a twelfth counts (same perfect class); a fifth moving to
963
1518
  * an octave does not (different perfect kinds — the direct/hidden case owned by
964
1519
  * {@link createsHiddenParallelPerfect}).
1520
+ *
1521
+ * @category Voicing & Counterpoint
965
1522
  */
966
1523
  declare function createsParallelPerfect(aPrev: number, aCur: number, bPrev: number, bCur: number): boolean;
967
1524
  /**
968
1525
  * Whether two voices move in consecutive parallel octaves (or unisons) by
969
1526
  * similar motion.
1527
+ *
1528
+ * This is a strict subset of {@link createsParallelPerfect}: a similar-motion
1529
+ * octave-to-octave is the perfect-class-zero case that predicate already flags
1530
+ * (and it additionally catches the contrary-motion anti-parallel). Callers that
1531
+ * tally parallel violations should therefore use {@link createsParallelPerfect}
1532
+ * alone to avoid double counting; this predicate remains for callers wanting a
1533
+ * dedicated similar-motion octave test.
1534
+ *
1535
+ * @category Voicing & Counterpoint
970
1536
  */
971
1537
  declare function createsParallelOctave(aPrev: number, aCur: number, bPrev: number, bCur: number): boolean;
972
1538
  /**
973
1539
  * Whether two voices move in consecutive parallel unisons — both landing on the
974
1540
  * same pitch, having shared a pitch on the previous move.
1541
+ *
1542
+ * @category Voicing & Counterpoint
975
1543
  */
976
1544
  declare function createsParallelUnison(aPrev: number, aCur: number, bPrev: number, bCur: number): boolean;
977
1545
  /**
@@ -981,6 +1549,8 @@ declare function createsParallelUnison(aPrev: number, aCur: number, bPrev: numbe
981
1549
  * The traditional step exception is applied: the approach is allowed when the
982
1550
  * upper of the two voices moves by step, so only leaps into the perfect
983
1551
  * interval are flagged.
1552
+ *
1553
+ * @category Voicing & Counterpoint
984
1554
  */
985
1555
  declare function createsHiddenParallelPerfect(aPrev: number, aCur: number, bPrev: number, bCur: number): boolean;
986
1556
  /**
@@ -992,6 +1562,7 @@ declare function createsHiddenParallelPerfect(aPrev: number, aCur: number, bPrev
992
1562
  * @param upperCur Current pitch of the upper voice.
993
1563
  * @param lowerPrev Previous pitch of the lower voice.
994
1564
  * @param lowerCur Current pitch of the lower voice.
1565
+ * @category Voicing & Counterpoint
995
1566
  */
996
1567
  declare function createsVoiceOverlap(upperPrev: number, upperCur: number, lowerPrev: number, lowerCur: number): boolean;
997
1568
  /**
@@ -1002,6 +1573,7 @@ declare function createsVoiceOverlap(upperPrev: number, upperCur: number, lowerP
1002
1573
  * @param upperPitch Pitch of the higher voice.
1003
1574
  * @param lowerPitch Pitch of the lower voice.
1004
1575
  * @param maxSemitones Maximum allowed spacing in semitones (default an octave).
1576
+ * @category Voicing & Counterpoint
1005
1577
  */
1006
1578
  declare function exceedsSpacing(upperPitch: number, lowerPitch: number, maxSemitones?: number): boolean;
1007
1579
  /**
@@ -1011,6 +1583,7 @@ declare function exceedsSpacing(upperPitch: number, lowerPitch: number, maxSemit
1011
1583
  * @param cur The following pitch.
1012
1584
  * @param key Key context supplying the tonic.
1013
1585
  * @returns True when `prev` is the leading tone and `cur` is the tonic a step above.
1586
+ * @category Voicing & Counterpoint
1014
1587
  */
1015
1588
  declare function isLeadingToneResolution(prev: number, cur: number, key: KeyScale): boolean;
1016
1589
 
@@ -1020,7 +1593,11 @@ declare function isLeadingToneResolution(prev: number, cur: number, key: KeyScal
1020
1593
  * which only go name -> notes.
1021
1594
  */
1022
1595
 
1023
- /** A candidate chord interpretation of a pitch set. */
1596
+ /**
1597
+ * A candidate chord interpretation of a pitch set.
1598
+ *
1599
+ * @category Recognition
1600
+ */
1024
1601
  type ChordMatch = {
1025
1602
  rootPc: number;
1026
1603
  quality: ChordQuality;
@@ -1035,7 +1612,11 @@ type ChordMatch = {
1035
1612
  /** Bass pitch class when inverted (the lowest note is not the root). */
1036
1613
  bassPc?: number;
1037
1614
  };
1038
- /** A candidate key interpretation of a pitch-class set. */
1615
+ /**
1616
+ * A candidate key interpretation of a pitch-class set.
1617
+ *
1618
+ * @category Recognition
1619
+ */
1039
1620
  type KeyMatch = {
1040
1621
  key: KeyScale;
1041
1622
  mode: 'major' | 'minor';
@@ -1054,6 +1635,13 @@ type KeyMatch = {
1054
1635
  *
1055
1636
  * @param pitches MIDI pitches or bare pitch classes (octave-agnostic).
1056
1637
  * @returns Ranked chord interpretations (may be empty).
1638
+ * @example
1639
+ * ```ts
1640
+ * import { detectChord } from '@libraz/libcantus';
1641
+ * const matches = detectChord([60, 64, 67]); // C E G
1642
+ * matches[0]; // { rootPc: 0, quality: 'maj', exact: true, ... }
1643
+ * ```
1644
+ * @category Recognition
1057
1645
  */
1058
1646
  declare function detectChord(pitches: number[]): ChordMatch[];
1059
1647
  /**
@@ -1061,16 +1649,34 @@ declare function detectChord(pitches: number[]): ChordMatch[];
1061
1649
  *
1062
1650
  * @param pitches MIDI pitches or bare pitch classes.
1063
1651
  * @returns The top-ranked chord, or null when nothing matches.
1652
+ * @example
1653
+ * ```ts
1654
+ * import { detectChordBest } from '@libraz/libcantus';
1655
+ * detectChordBest([60, 64, 67]); // C major triad: { rootPc: 0, quality: 'maj', ... }
1656
+ * ```
1657
+ * @category Recognition
1064
1658
  */
1065
1659
  declare function detectChordBest(pitches: number[]): Chord$1 | null;
1066
1660
  /**
1067
1661
  * Rank major and minor keys by how well they contain a set of pitch classes.
1068
1662
  *
1069
1663
  * The tonic is weighted so that, among equally-fitting keys, the one whose root
1070
- * appears in the input is preferred. Returns all 24 keys ranked best-first.
1664
+ * appears in the input is preferred. Minor candidates are scored against the
1665
+ * natural, harmonic, and melodic minor variants and keep the best of the three,
1666
+ * so a minor cadence containing the leading tone still resolves to its own
1667
+ * tonic; the returned key is always the natural-minor scale. Returns all 24
1668
+ * keys ranked best-first, or an empty array for an empty input (mirroring
1669
+ * {@link detectChord}).
1071
1670
  *
1072
1671
  * @param pitches MIDI pitches or bare pitch classes.
1073
- * @returns Ranked key interpretations.
1672
+ * @returns Ranked key interpretations (empty for an empty input).
1673
+ * @example
1674
+ * ```ts
1675
+ * import { detectKey } from '@libraz/libcantus';
1676
+ * const keys = detectKey([60, 62, 64, 65, 67, 69, 71]); // C major scale
1677
+ * keys[0].mode; // 'major', with keys[0].key.rootPc === 0
1678
+ * ```
1679
+ * @category Recognition
1074
1680
  */
1075
1681
  declare function detectKey(pitches: number[]): KeyMatch[];
1076
1682
 
@@ -1085,27 +1691,87 @@ type DrumHit = {
1085
1691
  /** Groove feel controlling off-beat swing. */
1086
1692
  type Feel = 'straight' | 'swing' | 'shuffle';
1087
1693
  /** Public groove style identifiers. */
1088
- type GrooveStyle = 'standard' | 'funk' | 'shuffle' | 'bossa' | 'trap' | 'halftime' | 'breakbeat';
1694
+ type GrooveStyle = 'standard' | 'funk' | 'shuffle' | 'bossa' | 'trap' | 'halftime' | 'breakbeat' | 'house' | 'synthpop';
1089
1695
  /** Public role identifiers gating which voices are present. */
1090
1696
  type DrumRole = 'full' | 'ambient' | 'minimal' | 'fxOnly';
1091
1697
  /** Public section identifiers. */
1092
1698
  type PublicSection = 'intro' | 'verse' | 'prechorus' | 'chorus' | 'bridge' | 'outro';
1093
1699
 
1700
+ /**
1701
+ * Groove feel (the swing/straight rhythmic character) for {@link generateDrums}.
1702
+ *
1703
+ * @category Composition
1704
+ */
1094
1705
  type GrooveFeel = Feel;
1095
1706
 
1096
- /** Public section identifiers for {@link generateDrums}. */
1707
+ /**
1708
+ * Public section identifiers for {@link generateDrums}.
1709
+ *
1710
+ * @category Composition
1711
+ */
1097
1712
  type Section = PublicSection;
1098
- /** Options controlling {@link generateDrums}. */
1713
+ /**
1714
+ * A Euclidean (Bjorklund) kick pattern for {@link generateDrums}.
1715
+ *
1716
+ * @category Composition
1717
+ */
1718
+ type EuclideanKick = {
1719
+ /** Number of kick onsets, clamped to `[0, steps]`. */
1720
+ pulses: number;
1721
+ /**
1722
+ * Total steps in the bar (1..16).
1723
+ *
1724
+ * @defaultValue 16
1725
+ */
1726
+ steps?: number;
1727
+ /**
1728
+ * Steps to rotate the onsets toward later positions.
1729
+ *
1730
+ * @defaultValue 0
1731
+ */
1732
+ rotation?: number;
1733
+ };
1734
+ /**
1735
+ * Options controlling {@link generateDrums}.
1736
+ *
1737
+ * @category Composition
1738
+ */
1099
1739
  type DrumGenOptions = {
1100
1740
  bars: number;
1101
1741
  bpm: number;
1102
1742
  style: GrooveStyle;
1103
1743
  section: Section;
1104
1744
  density: number;
1745
+ /**
1746
+ * Replace the final bar with a fill.
1747
+ *
1748
+ * @defaultValue false
1749
+ */
1105
1750
  fills?: boolean;
1106
1751
  feel?: GrooveFeel;
1752
+ /**
1753
+ * Voicing role; `'fxOnly'` suppresses the main kick/snare/ghost/fill voices.
1754
+ *
1755
+ * @defaultValue `'full'`
1756
+ */
1107
1757
  role?: DrumRole;
1758
+ /**
1759
+ * Seed for the deterministic PRNG.
1760
+ *
1761
+ * @defaultValue 0
1762
+ */
1108
1763
  seed?: number;
1764
+ /**
1765
+ * Section the final-bar fill leads into. Shapes which fill archetype is
1766
+ * chosen (into-chorus and out-of-intro fills differ from generic ones).
1767
+ * Defaults to `section`, i.e. a within-section fill.
1768
+ */
1769
+ nextSection?: Section;
1770
+ /**
1771
+ * When set, the kick follows this Euclidean rhythm instead of the
1772
+ * style/section pattern, giving direct access to evenly spread onsets.
1773
+ */
1774
+ euclideanKick?: EuclideanKick;
1109
1775
  };
1110
1776
  /**
1111
1777
  * Generate a drum performance as a flat list of onsets.
@@ -1115,11 +1781,23 @@ type DrumGenOptions = {
1115
1781
  * by its General MIDI pitch. Groove style selects an internal style and feel;
1116
1782
  * `density` sets the backing-density level; `section` shapes kick, hi-hat, ghost,
1117
1783
  * and percussion density. 16th-note hi-hats drop to 8ths at or above 150 BPM.
1118
- * When `fills` is true the final bar is replaced with a fill. Output is fully
1784
+ * When `fills` is true the final bar is replaced with a fill whose archetype is
1785
+ * shaped by `nextSection`; a fill that would emit nothing on its beat falls back
1786
+ * to the normal groove so the phrase end is never silent. `euclideanKick`
1787
+ * overrides the kick with an evenly-spread Euclidean pattern. Output is fully
1119
1788
  * determined by the options plus `seed`.
1120
1789
  *
1121
1790
  * @param opts Generation options.
1122
1791
  * @returns Percussion onsets in bar order.
1792
+ *
1793
+ * @example
1794
+ * ```ts
1795
+ * import { generateDrums } from '@libraz/libcantus';
1796
+ * const hits = generateDrums({ bars: 4, bpm: 120, style: 'standard', section: 'chorus', density: 0.6, fills: true });
1797
+ * // Fully determined by the options plus seed (defaults to 0).
1798
+ * ```
1799
+ *
1800
+ * @category Composition
1123
1801
  */
1124
1802
  declare function generateDrums(opts: DrumGenOptions): DrumHit[];
1125
1803
 
@@ -1133,19 +1811,47 @@ declare function generateDrums(opts: DrumGenOptions): DrumHit[];
1133
1811
  * seeded PRNG from the `random` module so results are fully reproducible.
1134
1812
  */
1135
1813
 
1136
- /** Options controlling {@link humanize}. */
1814
+ /**
1815
+ * Options controlling {@link humanize}.
1816
+ *
1817
+ * @category Rhythm & Meter
1818
+ */
1137
1819
  type HumanizeOptions = {
1138
- /** Time signature used to derive metric accents. Default 4/4. */
1820
+ /**
1821
+ * Time signature used to derive metric accents.
1822
+ *
1823
+ * @defaultValue 4/4
1824
+ */
1139
1825
  ts?: TimeSignature;
1140
- /** Maximum timing jitter in quarter-note beats, applied as ±this value. Default 0.02. */
1826
+ /**
1827
+ * Maximum timing jitter in quarter-note beats, applied as ±this value.
1828
+ *
1829
+ * @defaultValue 0.02
1830
+ */
1141
1831
  timing?: number;
1142
- /** Maximum velocity jitter (MIDI units), applied as ±this value. Default 8. */
1832
+ /**
1833
+ * Maximum velocity jitter (MIDI units), applied as ±this value.
1834
+ *
1835
+ * @defaultValue 8
1836
+ */
1143
1837
  velocity?: number;
1144
- /** How much louder strong beats get relative to weak ones, in MIDI velocity units. Default 12. */
1838
+ /**
1839
+ * How much louder strong beats get relative to weak ones, in MIDI velocity units.
1840
+ *
1841
+ * @defaultValue 12
1842
+ */
1145
1843
  accent?: number;
1146
- /** Velocity assumed for events with no `velocity` of their own. Default 80. */
1844
+ /**
1845
+ * Velocity assumed for events with no `velocity` of their own.
1846
+ *
1847
+ * @defaultValue 80
1848
+ */
1147
1849
  baseVelocity?: number;
1148
- /** Seed for the deterministic PRNG. Default 0. */
1850
+ /**
1851
+ * Seed for the deterministic PRNG.
1852
+ *
1853
+ * @defaultValue 0
1854
+ */
1149
1855
  seed?: number;
1150
1856
  };
1151
1857
  /**
@@ -1166,16 +1872,35 @@ type HumanizeOptions = {
1166
1872
  * @param events The events to humanize.
1167
1873
  * @param opts Humanization options.
1168
1874
  * @returns Humanized copies of `events`, in input order.
1875
+ * @example
1876
+ * ```ts
1877
+ * import { humanize } from '@libraz/libcantus';
1878
+ * const events = [{ pitch: 60, startBeat: 0, durationBeat: 1, velocity: 80 }];
1879
+ * humanize(events, { seed: 1, timing: 0.03 }); // copies with jittered timing and accented velocity
1880
+ * ```
1881
+ * @category Rhythm & Meter
1169
1882
  */
1170
1883
  declare function humanize(events: NoteEvent[], opts?: HumanizeOptions): NoteEvent[];
1171
- /** The recorded feel at a single grid slot: an average timing deviation and velocity. */
1884
+ /**
1885
+ * The recorded feel at a single grid slot: an average timing deviation and velocity.
1886
+ *
1887
+ * @category Rhythm & Meter
1888
+ */
1172
1889
  type GrooveSlot = {
1173
1890
  /** Average `actualStartBeat - quantizedBeat` (in quarter-note beats) for events landing on this slot. */
1174
1891
  timingOffset: number;
1175
- /** Average velocity of events landing on this slot; 0 if none did. */
1176
- velocity: number;
1892
+ /**
1893
+ * Average velocity of events landing on this slot, or `null` if no event
1894
+ * with a velocity did. `null` (not 0) is the "unrecorded" sentinel so that a
1895
+ * genuine velocity of 0 is preserved and applied like any other value.
1896
+ */
1897
+ velocity: number | null;
1177
1898
  };
1178
- /** A per-bar grid of timing and velocity deviations captured from a performance. */
1899
+ /**
1900
+ * A per-bar grid of timing and velocity deviations captured from a performance.
1901
+ *
1902
+ * @category Rhythm & Meter
1903
+ */
1179
1904
  type GrooveTemplate = {
1180
1905
  /** Grid resolution: equal grid steps per quarter-note beat. */
1181
1906
  subdivision: number;
@@ -1183,34 +1908,70 @@ type GrooveTemplate = {
1183
1908
  slotsPerBar: number;
1184
1909
  /** One entry per grid slot, in slot-index order (slot 0 is the downbeat). */
1185
1910
  slots: GrooveSlot[];
1911
+ /**
1912
+ * The time signature the template was extracted under. {@link applyGrooveTemplate}
1913
+ * requires the apply-time meter to match this so the per-bar grid lines up
1914
+ * instead of silently drifting. Optional for backward compatibility with
1915
+ * templates constructed without it (in which case no check is performed).
1916
+ */
1917
+ ts?: TimeSignature;
1186
1918
  };
1187
1919
  /**
1188
1920
  * Extract a groove template from a set of note events: for each grid slot,
1189
1921
  * the average timing deviation from the quantized grid and the average
1190
- * velocity of events landing on it. Slots with no events default to
1191
- * `{ timingOffset: 0, velocity: 0 }`.
1922
+ * velocity of events landing on it. Slots with no velocity-carrying event
1923
+ * record `velocity: null` (the "unrecorded" sentinel); empty slots default to
1924
+ * `{ timingOffset: 0, velocity: null }`. The time signature is stored on the
1925
+ * template so {@link applyGrooveTemplate} can verify the meter matches.
1192
1926
  *
1193
1927
  * @param events The (typically "groovy", human-played) events to analyze.
1194
1928
  * @param ts The time signature, used to compute the bar length.
1195
1929
  * @param subdivision Grid resolution: equal grid steps per quarter-note beat.
1196
1930
  * @returns The extracted groove template.
1931
+ * @category Rhythm & Meter
1197
1932
  */
1198
1933
  declare function extractGrooveTemplate(events: NoteEvent[], ts: TimeSignature, subdivision: number): GrooveTemplate;
1199
1934
  /**
1200
1935
  * Apply a groove template to a set of (typically quantized) note events: each
1201
1936
  * event is snapped to its grid slot and then offset by that slot's recorded
1202
1937
  * timing deviation, pushing stiff timing toward the template's feel.
1203
- * Velocity is set to the slot's recorded average when it recorded any
1204
- * (`velocity > 0`); otherwise the event's own velocity is left untouched.
1938
+ * Velocity is set to the slot's recorded average when it recorded one (a
1939
+ * non-`null` velocity, including a genuine 0); otherwise the event's own
1940
+ * velocity is left untouched.
1941
+ *
1942
+ * If the template carries a time signature (see {@link GrooveTemplate.ts}) it
1943
+ * must match `ts`, since a differing bar length would misalign the per-bar
1944
+ * grid and drift the feel; a mismatch throws rather than corrupting timing
1945
+ * silently.
1205
1946
  *
1206
1947
  * @param events The events to reshape.
1207
1948
  * @param template The groove template, from {@link extractGrooveTemplate}.
1208
1949
  * @param ts The time signature, used to compute the bar length.
1209
1950
  * @returns Reshaped copies of `events`, in input order.
1951
+ * @throws If `template.ts` is set and does not match `ts`.
1952
+ * @example
1953
+ * ```ts
1954
+ * import { extractGrooveTemplate, applyGrooveTemplate, parseTimeSignature } from '@libraz/libcantus';
1955
+ * const ts = parseTimeSignature('4/4');
1956
+ * // Learn the feel from a loosely played performance...
1957
+ * const groovy = [
1958
+ * { pitch: 36, startBeat: 0.02, durationBeat: 1, velocity: 100 },
1959
+ * { pitch: 38, startBeat: 1.06, durationBeat: 1, velocity: 70 },
1960
+ * ];
1961
+ * const template = extractGrooveTemplate(groovy, ts, 4);
1962
+ * // ...then impose it on stiff, quantized events.
1963
+ * const quantized = [{ pitch: 36, startBeat: 0, durationBeat: 1, velocity: 80 }];
1964
+ * applyGrooveTemplate(quantized, template, ts); // events nudged toward the captured feel
1965
+ * ```
1966
+ * @category Rhythm & Meter
1210
1967
  */
1211
1968
  declare function applyGrooveTemplate(events: NoteEvent[], template: GrooveTemplate, ts: TimeSignature): NoteEvent[];
1212
1969
 
1213
- /** Harmonic role a pitch plays within a chord. */
1970
+ /**
1971
+ * Harmonic role a pitch plays within a chord.
1972
+ *
1973
+ * @category Functional Harmony
1974
+ */
1214
1975
  type HarmonyRole = 'root' | 'third' | 'fifth' | 'sixth' | 'seventh' | 'tension' | 'doubling';
1215
1976
  /**
1216
1977
  * How firmly a pitch is locked to the chord's identity.
@@ -1218,9 +1979,15 @@ type HarmonyRole = 'root' | 'third' | 'fifth' | 'sixth' | 'seventh' | 'tension'
1218
1979
  * - `identity`: moving it produces a different chord (the root).
1219
1980
  * - `quality`: moving it flips the chord quality (the third).
1220
1981
  * - `voicing`: it can move freely without changing chord identity or quality.
1982
+ *
1983
+ * @category Functional Harmony
1221
1984
  */
1222
1985
  type LockLevel = 'identity' | 'quality' | 'voicing';
1223
- /** A pitch's role, lock level, and owning chord. */
1986
+ /**
1987
+ * A pitch's role, lock level, and owning chord.
1988
+ *
1989
+ * @category Functional Harmony
1990
+ */
1224
1991
  type VoicedRole = {
1225
1992
  role: HarmonyRole;
1226
1993
  lock: LockLevel;
@@ -1243,12 +2010,27 @@ type VoicedRole = {
1243
2010
  * @param chord The chord providing the root reference.
1244
2011
  * @param chordId Identifier stored on the result (defaults to 0).
1245
2012
  * @returns The pitch's role, lock level, and owning chord id.
2013
+ * @example
2014
+ * ```ts
2015
+ * import { roleOf, makeChord } from '@libraz/libcantus';
2016
+ * roleOf(64, makeChord(0, 'maj')); // E over C major
2017
+ * // { role: 'third', lock: 'quality', belongsToChordId: 0 }
2018
+ * ```
2019
+ * @category Functional Harmony
1246
2020
  */
1247
2021
  declare function roleOf(pitch: number, chord: Chord$1, chordId?: number): VoicedRole;
1248
2022
 
1249
- /** A melody note supplied to the harmonizer: a {@link NoteEvent}. */
2023
+ /**
2024
+ * A melody note supplied to the harmonizer: a {@link NoteEvent}.
2025
+ *
2026
+ * @category Reharmonization
2027
+ */
1250
2028
  type MelodyNote = NoteEvent;
1251
- /** Options controlling {@link harmonizeMelody}. */
2029
+ /**
2030
+ * Options controlling {@link harmonizeMelody}.
2031
+ *
2032
+ * @category Reharmonization
2033
+ */
1252
2034
  type HarmonizeOptions = {
1253
2035
  melody: MelodyNote[];
1254
2036
  key: KeyScale | 'infer';
@@ -1258,9 +2040,18 @@ type HarmonizeOptions = {
1258
2040
  transposeSearch: boolean;
1259
2041
  octaveSearch: boolean;
1260
2042
  };
2043
+ /**
2044
+ * Seed for the deterministic tie-break perturbation.
2045
+ *
2046
+ * @defaultValue 0
2047
+ */
1261
2048
  seed?: number;
1262
2049
  };
1263
- /** The chosen transpose, key, chord path, and per-note roles. */
2050
+ /**
2051
+ * The chosen transpose, key, chord path, and per-note roles.
2052
+ *
2053
+ * @category Reharmonization
2054
+ */
1264
2055
  type HarmonizeResult = {
1265
2056
  transposeSemitones: number;
1266
2057
  key: KeyScale;
@@ -1281,13 +2072,39 @@ type HarmonizeResult = {
1281
2072
  * `(transpose, progression)` pair is returned; a small tessitura cost breaks
1282
2073
  * ties toward placements that keep the melody in a comfortable register.
1283
2074
  *
2075
+ * The `seed` drives a deterministic tie-break only: it perturbs candidates by a
2076
+ * magnitude far below any real cost difference (see {@link TIE_BREAK_JITTER}),
2077
+ * so it can decide between chords or paths of otherwise-equal cost but never
2078
+ * overrides melody fit or functional flow. For a well-determined melody the
2079
+ * result is identical across seeds; the same seed always yields the same result.
2080
+ *
1284
2081
  * @param opts Melody, key (or `'infer'`), harmonic rhythm, reharmonization
1285
2082
  * strength, height-search flags, and seed.
1286
2083
  * @returns The chosen transpose, key, chord path, and per-note roles.
2084
+ * @example
2085
+ * ```ts
2086
+ * import { harmonizeMelody, majorKey } from '@libraz/libcantus';
2087
+ * const result = harmonizeMelody({
2088
+ * melody: [
2089
+ * { pitch: 60, startBeat: 0, durationBeat: 1 },
2090
+ * { pitch: 64, startBeat: 1, durationBeat: 1 },
2091
+ * ],
2092
+ * key: majorKey(0),
2093
+ * harmonicRhythm: 1,
2094
+ * reharmonize: 'diatonic',
2095
+ * placement: { transposeSearch: false, octaveSearch: false },
2096
+ * });
2097
+ * result.chords; // one GeneratedChord per harmonic-rhythm segment
2098
+ * ```
2099
+ * @category Reharmonization
1287
2100
  */
1288
2101
  declare function harmonizeMelody(opts: HarmonizeOptions): HarmonizeResult;
1289
2102
 
1290
- /** Counterpoint classification of a harmonic interval. */
2103
+ /**
2104
+ * Counterpoint classification of a harmonic interval.
2105
+ *
2106
+ * @category Pitch & Intervals
2107
+ */
1291
2108
  declare enum IntervalQuality {
1292
2109
  PerfectConsonance = 0,
1293
2110
  ImperfectConsonance = 1,
@@ -1304,6 +2121,14 @@ declare enum IntervalQuality {
1304
2121
  * @param semitones Interval size in semitones (may be negative or compound).
1305
2122
  * @param twoVoice When true, the perfect fourth is treated as dissonant.
1306
2123
  * @returns The counterpoint quality of the interval.
2124
+ * @example
2125
+ * ```ts
2126
+ * import { classifyInterval, IntervalQuality } from '@libraz/libcantus';
2127
+ * classifyInterval(7); // IntervalQuality.PerfectConsonance
2128
+ * classifyInterval(5); // IntervalQuality.Dissonance (two-voice)
2129
+ * classifyInterval(5, false); // IntervalQuality.ImperfectConsonance
2130
+ * ```
2131
+ * @category Pitch & Intervals
1307
2132
  */
1308
2133
  declare function classifyInterval(semitones: number, twoVoice?: boolean): IntervalQuality;
1309
2134
  /**
@@ -1311,6 +2136,7 @@ declare function classifyInterval(semitones: number, twoVoice?: boolean): Interv
1311
2136
  *
1312
2137
  * @param semitones Interval size in semitones (may be negative or compound).
1313
2138
  * @returns True for the unison/octave (0) and the perfect fifth (7) mod 12.
2139
+ * @category Pitch & Intervals
1314
2140
  */
1315
2141
  declare function isPerfectInterval(semitones: number): boolean;
1316
2142
  /**
@@ -1323,6 +2149,7 @@ declare function isPerfectInterval(semitones: number): boolean;
1323
2149
  * @param semitones Interval size in semitones (may be negative or compound).
1324
2150
  * @param twoVoice When true, the perfect fourth is treated as dissonant.
1325
2151
  * @returns True if the interval is consonant in the given context.
2152
+ * @category Pitch & Intervals
1326
2153
  */
1327
2154
  declare function isConsonantInterval(semitones: number, twoVoice?: boolean): boolean;
1328
2155
 
@@ -1345,13 +2172,19 @@ declare function isConsonantInterval(semitones: number, twoVoice?: boolean): boo
1345
2172
  * 0 natural, +1 sharp, +2 double-sharp.
1346
2173
  * - `octave` follows scientific pitch notation (middle C = C4 = MIDI 60). When
1347
2174
  * absent, the note denotes a bare pitch class.
2175
+ *
2176
+ * @category Pitch & Intervals
1348
2177
  */
1349
2178
  type Note$1 = {
1350
2179
  letter: number;
1351
2180
  alter: number;
1352
2181
  octave?: number;
1353
2182
  };
1354
- /** A spelled interval: a diatonic number, a quality label, and its semitone span. */
2183
+ /**
2184
+ * A spelled interval: a diatonic number, a quality label, and its semitone span.
2185
+ *
2186
+ * @category Pitch & Intervals
2187
+ */
1355
2188
  type SpelledInterval = {
1356
2189
  /** Diatonic size: 1 = unison, 2 = second, ... 8 = octave, and beyond. */
1357
2190
  number: number;
@@ -1371,6 +2204,13 @@ type SpelledInterval = {
1371
2204
  * @param text The note text.
1372
2205
  * @returns The parsed note.
1373
2206
  * @throws If the text is not a valid note.
2207
+ * @example
2208
+ * ```ts
2209
+ * import { parseNote, noteToMidi } from '@libraz/libcantus';
2210
+ * const n = parseNote('C#4');
2211
+ * noteToMidi(n); // 61
2212
+ * ```
2213
+ * @category Pitch & Intervals
1374
2214
  */
1375
2215
  declare function parseNote(text: string): Note$1;
1376
2216
  /**
@@ -1378,6 +2218,12 @@ declare function parseNote(text: string): Note$1;
1378
2218
  *
1379
2219
  * @param note The note to format.
1380
2220
  * @returns The note text, including the octave when present.
2221
+ * @example
2222
+ * ```ts
2223
+ * import { formatNote, parseNote } from '@libraz/libcantus';
2224
+ * formatNote(parseNote('C#4')); // 'C#4'
2225
+ * ```
2226
+ * @category Pitch & Intervals
1381
2227
  */
1382
2228
  declare function formatNote(note: Note$1): string;
1383
2229
  /**
@@ -1385,6 +2231,12 @@ declare function formatNote(note: Note$1): string;
1385
2231
  *
1386
2232
  * @param note The note.
1387
2233
  * @returns The pitch class.
2234
+ * @example
2235
+ * ```ts
2236
+ * import { noteToPitchClass, parseNote } from '@libraz/libcantus';
2237
+ * noteToPitchClass(parseNote('Db')); // 1
2238
+ * ```
2239
+ * @category Pitch & Intervals
1388
2240
  */
1389
2241
  declare function noteToPitchClass(note: Note$1): number;
1390
2242
  /**
@@ -1393,14 +2245,31 @@ declare function noteToPitchClass(note: Note$1): number;
1393
2245
  * @param note The note; must carry an octave.
1394
2246
  * @returns The MIDI number.
1395
2247
  * @throws If the note has no octave.
2248
+ * @example
2249
+ * ```ts
2250
+ * import { noteToMidi, parseNote } from '@libraz/libcantus';
2251
+ * noteToMidi(parseNote('A4')); // 69
2252
+ * ```
2253
+ * @category Pitch & Intervals
1396
2254
  */
1397
2255
  declare function noteToMidi(note: Note$1): number;
1398
2256
  /**
1399
2257
  * Name a MIDI number as a {@link Note}, choosing sharp or flat spelling.
1400
2258
  *
2259
+ * The input is rounded to the nearest integer but is not clamped to the MIDI
2260
+ * range 0..127: out-of-range values extrapolate linearly (e.g. `-1` -> `B-2`,
2261
+ * `128` -> `G#9`) and remain an exact inverse of {@link noteToMidi}.
2262
+ *
1401
2263
  * @param midi The MIDI number.
1402
2264
  * @param spelling Whether to prefer sharps or flats for black keys.
1403
2265
  * @returns The spelled note, with octave.
2266
+ * @example
2267
+ * ```ts
2268
+ * import { midiToNote, formatNote } from '@libraz/libcantus';
2269
+ * formatNote(midiToNote(61)); // 'C#4'
2270
+ * formatNote(midiToNote(61, 'flat')); // 'Db4'
2271
+ * ```
2272
+ * @category Pitch & Intervals
1404
2273
  */
1405
2274
  declare function midiToNote(midi: number, spelling?: 'sharp' | 'flat'): Note$1;
1406
2275
  /**
@@ -1413,10 +2282,21 @@ declare function midiToNote(midi: number, spelling?: 'sharp' | 'flat'): Note$1;
1413
2282
  * @param a The lower/first note.
1414
2283
  * @param b The upper/second note.
1415
2284
  * @returns The diatonic number, quality, and semitone span.
2285
+ * @example
2286
+ * ```ts
2287
+ * import { spelledInterval, parseNote } from '@libraz/libcantus';
2288
+ * spelledInterval(parseNote('C4'), parseNote('G4'));
2289
+ * // { number: 5, quality: 'P', semitones: 7 }
2290
+ * ```
2291
+ * @category Pitch & Intervals
1416
2292
  */
1417
2293
  declare function spelledInterval(a: Note$1, b: Note$1): SpelledInterval;
1418
2294
 
1419
- /** An inclusive MIDI pitch range for a single voice. */
2295
+ /**
2296
+ * An inclusive MIDI pitch range for a single voice.
2297
+ *
2298
+ * @category Voicing & Counterpoint
2299
+ */
1420
2300
  type VoiceRange = {
1421
2301
  min: number;
1422
2302
  max: number;
@@ -1425,25 +2305,43 @@ type VoiceRange = {
1425
2305
  * Default four-voice SATB ranges, ascending (index 0 = lowest):
1426
2306
  * bass E2–C4 (40–60), tenor C3–G4 (48–67), alto G3–D5 (55–74),
1427
2307
  * soprano C4–G5 (60–79).
2308
+ *
2309
+ * @category Voicing & Counterpoint
1428
2310
  */
1429
2311
  declare const SATB_RANGES: readonly VoiceRange[];
1430
- /** Options controlling {@link voiceChord} and {@link voiceProgression}. */
2312
+ /**
2313
+ * Options controlling {@link voiceChord} and {@link voiceProgression}.
2314
+ *
2315
+ * @category Voicing & Counterpoint
2316
+ */
1431
2317
  type VoicingOptions = {
1432
- /** Number of voices to realize (default 4). Ignored when `ranges` is given. */
2318
+ /**
2319
+ * Number of voices to realize. Ignored when `ranges` is given.
2320
+ *
2321
+ * @defaultValue 4
2322
+ */
1433
2323
  voices?: number;
1434
2324
  /** Explicit per-voice ranges, ascending (index 0 = lowest). Takes precedence over `voices`. */
1435
2325
  ranges?: VoiceRange[];
1436
- /** Maximum spacing in semitones between adjacent upper voices (default 12). */
2326
+ /**
2327
+ * Maximum spacing in semitones between adjacent upper voices.
2328
+ *
2329
+ * @defaultValue 12
2330
+ */
1437
2331
  maxSpacing?: number;
1438
2332
  };
1439
2333
  /**
1440
2334
  * Total voice-leading cost between two voicings: the sum of absolute semitone
1441
- * motion across voices. The arrays must be the same length; when they differ
1442
- * the voicings are not comparable and the cost is `Infinity`.
2335
+ * motion across voices, plus a moderate {@link HIDDEN_PERFECT_PENALTY} when the
2336
+ * outer-voice (bass–soprano) pair reaches a hidden/direct perfect fifth or
2337
+ * octave by similar motion. The arrays must be the same length; when they
2338
+ * differ the voicings are not comparable and the cost is `Infinity`.
1443
2339
  *
1444
2340
  * @param from The previous voicing, one MIDI pitch per voice.
1445
2341
  * @param to The next voicing, one MIDI pitch per voice.
1446
- * @returns The summed absolute motion, or `Infinity` when lengths differ.
2342
+ * @returns The summed absolute motion (plus any hidden-perfect penalty), or
2343
+ * `Infinity` when lengths differ.
2344
+ * @category Voicing & Counterpoint
1447
2345
  */
1448
2346
  declare function voiceLeadingCost(from: number[], to: number[]): number;
1449
2347
  /**
@@ -1458,6 +2356,13 @@ declare function voiceLeadingCost(from: number[], to: number[]): number;
1458
2356
  * @param opts Voicing options; defaults to four voices in {@link SATB_RANGES}.
1459
2357
  * @returns MIDI pitches, ascending, one per voice.
1460
2358
  * @throws If no voicing fits the given ranges.
2359
+ * @example
2360
+ * ```ts
2361
+ * import { parseChordSymbol, voiceChord } from '@libraz/libcantus';
2362
+ * const chord = parseChordSymbol('Cmaj7');
2363
+ * voiceChord(chord); // four ascending MIDI pitches within the SATB ranges
2364
+ * ```
2365
+ * @category Voicing & Counterpoint
1461
2366
  */
1462
2367
  declare function voiceChord(chord: Chord$1, opts?: VoicingOptions): number[];
1463
2368
  /**
@@ -1472,6 +2377,13 @@ declare function voiceChord(chord: Chord$1, opts?: VoicingOptions): number[];
1472
2377
  * @param opts Voicing options; defaults to four voices in {@link SATB_RANGES}.
1473
2378
  * @returns One voicing per chord, each ascending with one MIDI pitch per voice.
1474
2379
  * @throws If any chord admits no voicing within the given ranges.
2380
+ * @example
2381
+ * ```ts
2382
+ * import { parseChordSymbol, voiceProgression } from '@libraz/libcantus';
2383
+ * const chords = ['C', 'Am', 'F', 'G'].map((s) => parseChordSymbol(s));
2384
+ * voiceProgression(chords); // one four-voice voicing per chord, smoothly led
2385
+ * ```
2386
+ * @category Voicing & Counterpoint
1475
2387
  */
1476
2388
  declare function voiceProgression(chords: Chord$1[], opts?: VoicingOptions): number[][];
1477
2389
  /**
@@ -1484,17 +2396,35 @@ declare function voiceProgression(chords: Chord$1[], opts?: VoicingOptions): num
1484
2396
  * root/third/fifth for triads; the fifth and tensions are omitted.
1485
2397
  * - `rootless`: the root omitted, keeping third/fifth/seventh and tensions
1486
2398
  * (a typical left-hand jazz voicing).
2399
+ *
2400
+ * @category Voicing & Counterpoint
1487
2401
  */
1488
2402
  type VoicingStyle = 'close' | 'drop2' | 'drop3' | 'shell' | 'rootless';
1489
- /** Options controlling {@link voiceChordStyled}. */
2403
+ /**
2404
+ * Options controlling {@link voiceChordStyled}.
2405
+ *
2406
+ * @category Voicing & Counterpoint
2407
+ */
1490
2408
  type StyledVoicingOptions = {
1491
- /** Voicing style to build (default `close`). */
2409
+ /**
2410
+ * Voicing style to build.
2411
+ *
2412
+ * @defaultValue 'close'
2413
+ */
1492
2414
  style?: VoicingStyle;
1493
2415
  /** Constrain the highest voice to this pitch class (0..11) when given. */
1494
2416
  topNote?: number;
1495
- /** Base octave for the close stack; the stack begins near `12 * octave` (default 4). */
2417
+ /**
2418
+ * Base octave for the close stack; the stack begins near `12 * octave`.
2419
+ *
2420
+ * @defaultValue 4
2421
+ */
1496
2422
  octave?: number;
1497
- /** Omit the root regardless of style (relevant for jazz voicings). */
2423
+ /**
2424
+ * Omit the root regardless of style (relevant for jazz voicings).
2425
+ *
2426
+ * @defaultValue false
2427
+ */
1498
2428
  rootless?: boolean;
1499
2429
  };
1500
2430
  /**
@@ -1512,6 +2442,13 @@ type StyledVoicingOptions = {
1512
2442
  * @param chord The chord to voice.
1513
2443
  * @param opts Styled voicing options; defaults to a close voicing at octave 4.
1514
2444
  * @returns MIDI pitches, ascending, one per retained voice.
2445
+ * @example
2446
+ * ```ts
2447
+ * import { parseChordSymbol, voiceChordStyled } from '@libraz/libcantus';
2448
+ * const chord = parseChordSymbol('Dm7');
2449
+ * voiceChordStyled(chord, { style: 'drop2' }); // ascending MIDI pitches, drop-2 voicing
2450
+ * ```
2451
+ * @category Voicing & Counterpoint
1515
2452
  */
1516
2453
  declare function voiceChordStyled(chord: Chord$1, opts?: StyledVoicingOptions): number[];
1517
2454
  /**
@@ -1529,6 +2466,7 @@ declare function voiceChordStyled(chord: Chord$1, opts?: StyledVoicingOptions):
1529
2466
  * @param opts Voicing options; when omitted, ranges follow `current`'s span.
1530
2467
  * @returns The chosen voicing, ascending with one MIDI pitch per voice.
1531
2468
  * @throws If no voicing fits the derived ranges.
2469
+ * @category Voicing & Counterpoint
1532
2470
  */
1533
2471
  declare function nextVoicing(current: number[], chord: Chord$1, opts?: VoicingOptions): number[];
1534
2472
 
@@ -1546,6 +2484,13 @@ declare function nextVoicing(current: number[], chord: Chord$1, opts?: VoicingOp
1546
2484
  * An immutable spelled note: a diatonic letter plus a chromatic alteration and
1547
2485
  * an optional octave. Wraps the plain note object and delegates to the pitch
1548
2486
  * module; every transformation returns a new instance.
2487
+ *
2488
+ * @category Class API
2489
+ * @example
2490
+ * ```ts
2491
+ * import { Note } from '@libraz/libcantus';
2492
+ * Note.of('C4').transpose(7).name; // 'G4'
2493
+ * ```
1549
2494
  */
1550
2495
  declare class Note {
1551
2496
  #private;
@@ -1601,7 +2546,8 @@ declare class Note {
1601
2546
  *
1602
2547
  * When the note carries an octave the transposition happens in MIDI space and
1603
2548
  * the result is spelled with a sharp preference. An octave-less note stays
1604
- * octave-less: only its pitch class is moved.
2549
+ * octave-less: only its pitch class is moved. Transposing by zero is the
2550
+ * identity: the original spelling is preserved (no enharmonic respelling).
1605
2551
  *
1606
2552
  * @param semitones The signed semitone offset.
1607
2553
  * @returns The transposed note.
@@ -1621,11 +2567,27 @@ declare class Note {
1621
2567
  * @returns True if the spellings are identical.
1622
2568
  */
1623
2569
  equals(other: Note): boolean;
2570
+ /**
2571
+ * The plain note data, for JSON serialization.
2572
+ *
2573
+ * Private class fields do not serialize, so an explicit `toJSON` keeps
2574
+ * `JSON.stringify(note)` from collapsing to `{}`.
2575
+ *
2576
+ * @returns A copy of the underlying plain note object.
2577
+ */
2578
+ toJSON(): Note$1;
1624
2579
  }
1625
2580
  /**
1626
2581
  * An immutable spelled interval value: a diatonic number, a quality label, and
1627
2582
  * a signed semitone span. A thin convenience wrapper over the pitch module's
1628
2583
  * plain interval result.
2584
+ *
2585
+ * @category Class API
2586
+ * @example
2587
+ * ```ts
2588
+ * import { Interval, Note } from '@libraz/libcantus';
2589
+ * Interval.between(Note.of('C4'), Note.of('G4')).name; // 'P5'
2590
+ * ```
1629
2591
  */
1630
2592
  declare class Interval {
1631
2593
  #private;
@@ -1655,11 +2617,27 @@ declare class Interval {
1655
2617
  get semitones(): number;
1656
2618
  /** A readable label composed of quality and number, e.g. `'P5'` or `'M3'`. */
1657
2619
  get name(): string;
2620
+ /**
2621
+ * The plain interval data, for JSON serialization.
2622
+ *
2623
+ * Private class fields do not serialize, so an explicit `toJSON` keeps
2624
+ * `JSON.stringify(interval)` from collapsing to `{}`.
2625
+ *
2626
+ * @returns The diatonic number, quality, and semitone span.
2627
+ */
2628
+ toJSON(): SpelledInterval;
1658
2629
  }
1659
2630
  /**
1660
2631
  * An immutable key/scale: a `KeyScale` (root pitch class plus mode mask) paired
1661
2632
  * with a spelled tonic that anchors letter-name spelling. Acts as the factory
1662
2633
  * for key-aware chords.
2634
+ *
2635
+ * @category Class API
2636
+ * @example
2637
+ * ```ts
2638
+ * import { Key } from '@libraz/libcantus';
2639
+ * Key.major('C').chord(4).symbol(); // 'G' (the diatonic triad on scale degree 4)
2640
+ * ```
1663
2641
  */
1664
2642
  declare class Key {
1665
2643
  #private;
@@ -1673,16 +2651,18 @@ declare class Key {
1673
2651
  /**
1674
2652
  * A major key.
1675
2653
  *
1676
- * @param root Tonic as a note name (e.g. `'Eb'`) or a pitch class; numeric
1677
- * roots are spelled with a sharp preference.
2654
+ * @param root Tonic as a note name (e.g. `'Eb'`) or a pitch class; a numeric
2655
+ * root is spelled with whichever accidental side yields the fewest
2656
+ * accidentals across the scale.
1678
2657
  * @returns The major key.
1679
2658
  */
1680
2659
  static major(root: string | number): Key;
1681
2660
  /**
1682
2661
  * A natural-minor key.
1683
2662
  *
1684
- * @param root Tonic as a note name or a pitch class; numeric roots are
1685
- * spelled with a flat preference.
2663
+ * @param root Tonic as a note name or a pitch class; a numeric root is
2664
+ * spelled with whichever accidental side yields the fewest accidentals
2665
+ * across the scale.
1686
2666
  * @returns The minor key.
1687
2667
  */
1688
2668
  static minor(root: string | number): Key;
@@ -1778,12 +2758,33 @@ declare class Key {
1778
2758
  * @returns True if the pitch class is a scale tone.
1779
2759
  */
1780
2760
  contains(x: number | Note): boolean;
2761
+ /**
2762
+ * The plain key data, for JSON serialization.
2763
+ *
2764
+ * Private class fields do not serialize, so an explicit `toJSON` keeps
2765
+ * `JSON.stringify(key)` from collapsing to `{}`. The result pairs the
2766
+ * `KeyScale` with the spelled tonic, enough to reconstruct the key via
2767
+ * {@link Key.of}.
2768
+ *
2769
+ * @returns The key/scale and its spelled tonic.
2770
+ */
2771
+ toJSON(): {
2772
+ scale: KeyScale;
2773
+ tonic: Note$1;
2774
+ };
1781
2775
  }
1782
2776
  /**
1783
2777
  * An immutable chord: a root pitch class, quality, interval template, and
1784
2778
  * optional slash bass, optionally carrying a {@link Key} context. Analysis
1785
2779
  * methods (`roman`, `function`, `analyze`, ...) use an explicitly passed key
1786
2780
  * first and fall back to the carried context.
2781
+ *
2782
+ * @category Class API
2783
+ * @example
2784
+ * ```ts
2785
+ * import { Chord } from '@libraz/libcantus';
2786
+ * Chord.parse('Cmaj7').invert(1).symbol(); // 'Cmaj7/E' (third in the bass)
2787
+ * ```
1787
2788
  */
1788
2789
  declare class Chord {
1789
2790
  #private;
@@ -1937,6 +2938,9 @@ declare class Chord {
1937
2938
  * root in the interval template (`invert(1)` puts the third in the bass).
1938
2939
  * `n` wraps around the template length; negative values count backwards.
1939
2940
  *
2941
+ * `invert(0)` (and any `n` that wraps to it) is root position, so it carries
2942
+ * no slash bass and equals the original chord.
2943
+ *
1940
2944
  * @param n The inversion number.
1941
2945
  * @returns The inverted chord, keeping any key context.
1942
2946
  * @throws If the chord has no intervals.
@@ -2000,6 +3004,15 @@ declare class Chord {
2000
3004
  /**
2001
3005
  * An immutable ordered sequence of chords, optionally carrying a {@link Key}
2002
3006
  * context shared by its analysis methods.
3007
+ *
3008
+ * @category Class API
3009
+ * @example
3010
+ * ```ts
3011
+ * import { Key } from '@libraz/libcantus';
3012
+ * const key = Key.major('C');
3013
+ * key.chord(1).progressionTo(key.chord(4), key.chord(0)).roman();
3014
+ * // ['ii', 'V', 'I']
3015
+ * ```
2003
3016
  */
2004
3017
  declare class Progression {
2005
3018
  #private;
@@ -2068,28 +3081,83 @@ declare class Progression {
2068
3081
  chords: ChordAnalysis[];
2069
3082
  cadence: Cadence;
2070
3083
  };
3084
+ /**
3085
+ * The plain progression data, for JSON serialization.
3086
+ *
3087
+ * Private class fields do not serialize, so an explicit `toJSON` keeps
3088
+ * `JSON.stringify(progression)` from collapsing to `{}`. The chords are
3089
+ * emitted as plain data and the carried key, when present, as its own data.
3090
+ *
3091
+ * @returns The chord data sequence and the carried key, if any.
3092
+ */
3093
+ toJSON(): {
3094
+ chords: Chord$1[];
3095
+ key: {
3096
+ scale: KeyScale;
3097
+ tonic: Note$1;
3098
+ } | undefined;
3099
+ };
2071
3100
  }
2072
3101
 
2073
- /** A transformation applicable to a motif cell. */
3102
+ /**
3103
+ * A transformation applicable to a motif cell.
3104
+ *
3105
+ * @category Composition
3106
+ */
2074
3107
  type MotifTransform = 'transposeDiatonic' | 'transposeChromatic' | 'invert' | 'retrograde' | 'augment' | 'diminish' | 'sequence';
2075
- /** A single note within a motif cell. */
3108
+ /**
3109
+ * A single note within a motif cell.
3110
+ *
3111
+ * @category Composition
3112
+ */
2076
3113
  type MotifNote = {
2077
3114
  pitch: number;
2078
3115
  startBeat: number;
2079
3116
  durationBeat: number;
2080
3117
  };
2081
- /** A short melodic cell. */
3118
+ /**
3119
+ * A short melodic cell.
3120
+ *
3121
+ * @category Composition
3122
+ */
2082
3123
  type MotifCell = {
2083
3124
  notes: MotifNote[];
2084
3125
  };
2085
- /** Melodic contour shape for {@link generateMotif}. */
3126
+ /**
3127
+ * Melodic contour shape for {@link generateMotif}.
3128
+ *
3129
+ * @category Composition
3130
+ */
2086
3131
  type MotifContour = 'arch' | 'ascending' | 'descending' | 'wave';
2087
- /** Options controlling {@link generateMotif}. */
3132
+ /**
3133
+ * Options controlling {@link generateMotif}.
3134
+ *
3135
+ * @category Composition
3136
+ */
2088
3137
  type GenerateMotifOptions = {
2089
3138
  key: KeyScale;
2090
3139
  chord?: Chord$1 | null;
2091
3140
  bars: number;
3141
+ /**
3142
+ * Melodic contour shape the line follows.
3143
+ *
3144
+ * @defaultValue `'arch'`
3145
+ */
2092
3146
  contour?: MotifContour;
3147
+ /**
3148
+ * Probability in [0, 1] that a note is nudged by a single diatonic step. The
3149
+ * nudge direction is balanced (up or down with equal odds), so it adds
3150
+ * variety without biasing the line off its contour. Default 0, which
3151
+ * reproduces the requested contour exactly (no drift, tails return to tonic).
3152
+ *
3153
+ * @defaultValue 0
3154
+ */
3155
+ jitter?: number;
3156
+ /**
3157
+ * Seed for the deterministic PRNG.
3158
+ *
3159
+ * @defaultValue 0
3160
+ */
2093
3161
  seed?: number;
2094
3162
  };
2095
3163
  /**
@@ -2097,10 +3165,21 @@ type GenerateMotifOptions = {
2097
3165
  *
2098
3166
  * The melody follows the requested contour in diatonic steps from the tonic,
2099
3167
  * snapped to the key. When a chord is supplied, notes landing on bar downbeats
2100
- * are pulled to the nearest chord tone. Output is deterministic for a given seed.
3168
+ * are pulled to the nearest chord tone. An optional `jitter` adds balanced
3169
+ * per-note variation without biasing the contour; it is off by default, so the
3170
+ * contour is reproduced exactly. Output is deterministic for a given seed.
2101
3171
  *
2102
- * @param opts Key, optional chord, length, contour, and seed.
3172
+ * @param opts Key, optional chord, length, contour, jitter, and seed.
2103
3173
  * @returns The generated motif cell.
3174
+ *
3175
+ * @example
3176
+ * ```ts
3177
+ * import { generateMotif, majorKey } from '@libraz/libcantus';
3178
+ * const cell = generateMotif({ key: majorKey(0), bars: 2, contour: 'arch' });
3179
+ * // cell.notes is a deterministic MotifCell (seed defaults to 0)
3180
+ * ```
3181
+ *
3182
+ * @category Composition
2104
3183
  */
2105
3184
  declare function generateMotif(opts: GenerateMotifOptions): MotifCell;
2106
3185
  /**
@@ -2121,6 +3200,15 @@ declare function generateMotif(opts: GenerateMotifOptions): MotifCell;
2121
3200
  * @param key Key context for the diatonic transforms; without it,
2122
3201
  * `transposeDiatonic` and `sequence` shift chromatically by semitones.
2123
3202
  * @returns The transformed cell.
3203
+ *
3204
+ * @example
3205
+ * ```ts
3206
+ * import { generateMotif, transformMotif, majorKey } from '@libraz/libcantus';
3207
+ * const cell = generateMotif({ key: majorKey(0), bars: 1 });
3208
+ * const inverted = transformMotif(cell, 'invert');
3209
+ * ```
3210
+ *
3211
+ * @category Composition
2124
3212
  */
2125
3213
  declare function transformMotif(cell: MotifCell, t: MotifTransform, amount?: number, key?: KeyScale): MotifCell;
2126
3214
  /**
@@ -2135,6 +3223,16 @@ declare function transformMotif(cell: MotifCell, t: MotifTransform, amount?: num
2135
3223
  * @param key Key context (used to keep snapped pitches sensible).
2136
3224
  * @param bars Number of four-beat bars to fill.
2137
3225
  * @returns The developed, harmony-aware cell.
3226
+ *
3227
+ * @example
3228
+ * ```ts
3229
+ * import { chordTimelineFromChords, developMotif, generateMotif, majorKey } from '@libraz/libcantus';
3230
+ * const key = majorKey(0);
3231
+ * const timeline = chordTimelineFromChords([{ rootPc: 0, quality: 'maj', startBeat: 0 }], 8);
3232
+ * const developed = developMotif(generateMotif({ key, bars: 1 }), timeline, key, 2);
3233
+ * ```
3234
+ *
3235
+ * @category Composition
2138
3236
  */
2139
3237
  declare function developMotif(cell: MotifCell, timeline: ChordTimeline, key: KeyScale, bars: number): MotifCell;
2140
3238
 
@@ -2144,7 +3242,11 @@ declare function developMotif(cell: MotifCell, timeline: ChordTimeline, key: Key
2144
3242
  * mulberry32 core exposes the small set of samplers those modules need; given a
2145
3243
  * seed the stream is fully reproducible.
2146
3244
  */
2147
- /** A deterministic PRNG with the sampling helpers the generators need. */
3245
+ /**
3246
+ * A deterministic PRNG with the sampling helpers the generators need.
3247
+ *
3248
+ * @category Utilities
3249
+ */
2148
3250
  type Rng = {
2149
3251
  /** Next float in [0, 1). */
2150
3252
  next: () => number;
@@ -2160,6 +3262,14 @@ type Rng = {
2160
3262
  *
2161
3263
  * @param seed The 32-bit seed; the same seed always yields the same stream.
2162
3264
  * @returns The seeded generator.
3265
+ * @example
3266
+ * ```ts
3267
+ * import { createRng } from '@libraz/libcantus';
3268
+ * const rng = createRng(42);
3269
+ * rng.next(); // deterministic float in [0, 1)
3270
+ * rng.range(1, 6); // deterministic integer in [1, 6]
3271
+ * ```
3272
+ * @category Utilities
2163
3273
  */
2164
3274
  declare function createRng(seed: number): Rng;
2165
3275
 
@@ -2172,16 +3282,28 @@ declare function createRng(seed: number): Rng;
2172
3282
  * Roots are pitch classes (0..11); no spelled key signature is required.
2173
3283
  */
2174
3284
 
2175
- /** The kind of substitution relationship a candidate realizes. */
3285
+ /**
3286
+ * The kind of substitution relationship a candidate realizes.
3287
+ *
3288
+ * @category Reharmonization
3289
+ */
2176
3290
  type SubstitutionType = 'tritone' | 'relative' | 'borrowed' | 'chromatic-mediant' | 'secondary-dominant';
2177
- /** A proposed chord substitution with its relationship, numeral, and function. */
3291
+ /**
3292
+ * A proposed chord substitution with its relationship, numeral, and function.
3293
+ *
3294
+ * @category Reharmonization
3295
+ */
2178
3296
  type Substitution = {
2179
3297
  chord: Chord$1;
2180
3298
  type: SubstitutionType;
2181
3299
  roman: string;
2182
3300
  function: HarmonicFunction;
2183
3301
  };
2184
- /** Options controlling which substitutions {@link substituteChord} returns. */
3302
+ /**
3303
+ * Options controlling which substitutions {@link substituteChord} returns.
3304
+ *
3305
+ * @category Reharmonization
3306
+ */
2185
3307
  type SubstituteOptions = {
2186
3308
  /**
2187
3309
  * Melody pitch classes that must remain chord tones. When given, only
@@ -2212,9 +3334,20 @@ type SubstituteOptions = {
2212
3334
  * @param key The prevailing key.
2213
3335
  * @param opts Optional melody-preservation constraint.
2214
3336
  * @returns The deduplicated substitution candidates.
3337
+ * @example
3338
+ * ```ts
3339
+ * import { substituteChord, makeChord, majorKey } from '@libraz/libcantus';
3340
+ * const subs = substituteChord(makeChord(7, 'dom7'), majorKey(0));
3341
+ * // includes the tritone sub Db7 (rootPc 1, quality 'dom7')
3342
+ * ```
3343
+ * @category Reharmonization
2215
3344
  */
2216
3345
  declare function substituteChord(chord: Chord$1, key: KeyScale, opts?: SubstituteOptions): Substitution[];
2217
- /** A borrowed chord in the modal-interchange palette of a key. */
3346
+ /**
3347
+ * A borrowed chord in the modal-interchange palette of a key.
3348
+ *
3349
+ * @category Reharmonization
3350
+ */
2218
3351
  type BorrowedChord = {
2219
3352
  chord: Chord$1;
2220
3353
  roman: string;
@@ -2230,6 +3363,7 @@ type BorrowedChord = {
2230
3363
  *
2231
3364
  * @param key The prevailing key.
2232
3365
  * @returns The borrowed-chord palette.
3366
+ * @category Reharmonization
2233
3367
  */
2234
3368
  declare function modalInterchangePalette(key: KeyScale): BorrowedChord[];
2235
3369
  /**
@@ -2244,6 +3378,13 @@ declare function modalInterchangePalette(key: KeyScale): BorrowedChord[];
2244
3378
  * @param chord The chord to reflect.
2245
3379
  * @param key The prevailing key.
2246
3380
  * @returns The negative-harmony counterpart of the chord.
3381
+ * @example
3382
+ * ```ts
3383
+ * import { negativeHarmonyMirror, makeChord, majorKey } from '@libraz/libcantus';
3384
+ * negativeHarmonyMirror(makeChord(7, 'maj'), majorKey(0));
3385
+ * // G major reflected across C's axis => F minor (rootPc 5, quality 'min')
3386
+ * ```
3387
+ * @category Reharmonization
2247
3388
  */
2248
3389
  declare function negativeHarmonyMirror(chord: Chord$1, key: KeyScale): Chord$1;
2249
3390
 
@@ -2260,28 +3401,49 @@ declare function negativeHarmonyMirror(chord: Chord$1, key: KeyScale): Chord$1;
2260
3401
  * library-wide convention.
2261
3402
  */
2262
3403
 
2263
- /** A single rhythmic note: an onset position and how long it sounds. */
3404
+ /**
3405
+ * A single rhythmic note: an onset position and how long it sounds.
3406
+ *
3407
+ * @category Rhythm & Meter
3408
+ */
2264
3409
  type RhythmEvent = {
2265
3410
  /** Onset position in quarter-note beats, absolute from the start of the span. */
2266
3411
  position: number;
2267
3412
  /** Duration in quarter-note beats, extending to the next onset. */
2268
3413
  duration: number;
2269
3414
  };
2270
- /** Options controlling {@link generateRhythm}. */
3415
+ /**
3416
+ * Options controlling {@link generateRhythm}.
3417
+ *
3418
+ * @category Rhythm & Meter
3419
+ */
2271
3420
  type RhythmOptions = {
2272
- /** Seed for the deterministic PRNG. Default 0. */
3421
+ /**
3422
+ * Seed for the deterministic PRNG.
3423
+ *
3424
+ * @defaultValue 0
3425
+ */
2273
3426
  seed?: number;
2274
- /** Number of bars to generate. Default 1. */
3427
+ /**
3428
+ * Number of bars to generate.
3429
+ *
3430
+ * @defaultValue 1
3431
+ */
2275
3432
  bars?: number;
2276
3433
  /**
2277
3434
  * Grid resolution as the number of equal grid steps per quarter-note beat.
2278
3435
  * The default of 2 yields an eighth-note grid; 4 yields a sixteenth-note
2279
3436
  * grid, 3 an eighth-note triplet grid, and so on.
3437
+ *
3438
+ * @defaultValue 2
2280
3439
  */
2281
3440
  subdivision?: number;
2282
3441
  /**
2283
3442
  * Overall onset density in [0, 1]. Scales the per-slot onset probability, so
2284
- * higher values fill more grid slots. Default 0.5.
3443
+ * higher values fill more grid slots. Values outside [0, 1] are clamped into
3444
+ * range.
3445
+ *
3446
+ * @defaultValue 0.5
2285
3447
  */
2286
3448
  density?: number;
2287
3449
  };
@@ -2293,19 +3455,28 @@ type RhythmOptions = {
2293
3455
  *
2294
3456
  * @param weight The metric weight, 0 (off-pulse) to 3 (downbeat).
2295
3457
  * @returns A base onset probability in [0, 1].
3458
+ * @category Rhythm & Meter
2296
3459
  */
2297
3460
  declare function onsetWeightCurve(weight: number): number;
2298
3461
  /**
2299
3462
  * Generate a deterministic rhythmic pattern over `bars` bars of a time
2300
3463
  * signature. A grid is built at the chosen subdivision; each slot becomes an
2301
3464
  * onset with a probability derived from its metric weight scaled by `density`
2302
- * and sampled from the seeded PRNG. The first slot (the downbeat) is always an
2303
- * onset. Each event's duration extends to the next onset, and the last event
2304
- * extends to the end of the span.
3465
+ * and sampled from the seeded PRNG. Every bar's downbeat is always an onset, so
3466
+ * a pattern of any length has a reliable pulse independent of the seed. Each
3467
+ * event's duration extends to the next onset, and the last event extends to the
3468
+ * end of the span. `density` is clamped to [0, 1].
2305
3469
  *
2306
3470
  * @param ts The time signature.
2307
3471
  * @param opts Generation options.
2308
3472
  * @returns Onset events sorted by position, non-overlapping, covering the span.
3473
+ * @example
3474
+ * ```ts
3475
+ * import { parseTimeSignature, generateRhythm } from '@libraz/libcantus';
3476
+ * const ts = parseTimeSignature('4/4');
3477
+ * generateRhythm(ts, { seed: 42, density: 0.6 }); // onset events over one bar
3478
+ * ```
3479
+ * @category Rhythm & Meter
2309
3480
  */
2310
3481
  declare function generateRhythm(ts: TimeSignature, opts?: RhythmOptions): RhythmEvent[];
2311
3482
  /**
@@ -2314,6 +3485,7 @@ declare function generateRhythm(ts: TimeSignature, opts?: RhythmOptions): Rhythm
2314
3485
  * @param events Events from {@link generateRhythm}.
2315
3486
  * @param ts The time signature.
2316
3487
  * @returns The onset count divided by the number of bars the events span.
3488
+ * @category Rhythm & Meter
2317
3489
  */
2318
3490
  declare function rhythmDensity(events: RhythmEvent[], ts: TimeSignature): number;
2319
3491
 
@@ -2322,45 +3494,135 @@ declare function rhythmDensity(events: RhythmEvent[], ts: TimeSignature): number
2322
3494
  *
2323
3495
  * Bit 0 (the root) is always set, enforcing the `KeyScale` invariant that the
2324
3496
  * root is a scale tone even when the offset list omits 0.
3497
+ *
3498
+ * @category Scales
2325
3499
  */
2326
3500
  declare function maskFromOffsets(offsets: readonly number[]): number;
2327
- /** Mode mask for the major (Ionian) scale: offsets {0, 2, 4, 5, 7, 9, 11}. */
3501
+ /**
3502
+ * Mode mask for the major (Ionian) scale: offsets {0, 2, 4, 5, 7, 9, 11}.
3503
+ *
3504
+ * @category Scales
3505
+ */
2328
3506
  declare const MAJOR_MASK = 2741;
2329
- /** Mode mask for the natural minor (Aeolian) scale: offsets {0, 2, 3, 5, 7, 8, 10}. */
3507
+ /**
3508
+ * Mode mask for the natural minor (Aeolian) scale: offsets {0, 2, 3, 5, 7, 8, 10}.
3509
+ *
3510
+ * @category Scales
3511
+ */
2330
3512
  declare const NATURAL_MINOR_MASK = 1453;
2331
- /** Harmonic minor: natural minor with a raised seventh — offsets {0,2,3,5,7,8,11}. */
3513
+ /**
3514
+ * Harmonic minor: natural minor with a raised seventh — offsets {0,2,3,5,7,8,11}.
3515
+ *
3516
+ * @category Scales
3517
+ */
2332
3518
  declare const HARMONIC_MINOR_MASK: number;
2333
- /** Ascending melodic minor: offsets {0,2,3,5,7,9,11}. */
3519
+ /**
3520
+ * Ascending melodic minor: offsets {0,2,3,5,7,9,11}.
3521
+ *
3522
+ * @category Scales
3523
+ */
2334
3524
  declare const MELODIC_MINOR_MASK: number;
2335
- /** Dorian mode: offsets {0,2,3,5,7,9,10}. */
3525
+ /**
3526
+ * Dorian mode: offsets {0,2,3,5,7,9,10}.
3527
+ *
3528
+ * @category Scales
3529
+ */
2336
3530
  declare const DORIAN_MASK: number;
2337
- /** Phrygian mode: offsets {0,1,3,5,7,8,10}. */
3531
+ /**
3532
+ * Phrygian mode: offsets {0,1,3,5,7,8,10}.
3533
+ *
3534
+ * @category Scales
3535
+ */
2338
3536
  declare const PHRYGIAN_MASK: number;
2339
- /** Lydian mode: offsets {0,2,4,6,7,9,11}. */
3537
+ /**
3538
+ * Lydian mode: offsets {0,2,4,6,7,9,11}.
3539
+ *
3540
+ * @category Scales
3541
+ */
2340
3542
  declare const LYDIAN_MASK: number;
2341
- /** Mixolydian mode: offsets {0,2,4,5,7,9,10}. */
3543
+ /**
3544
+ * Mixolydian mode: offsets {0,2,4,5,7,9,10}.
3545
+ *
3546
+ * @category Scales
3547
+ */
2342
3548
  declare const MIXOLYDIAN_MASK: number;
2343
- /** Locrian mode: offsets {0,1,3,5,6,8,10}. */
3549
+ /**
3550
+ * Locrian mode: offsets {0,1,3,5,6,8,10}.
3551
+ *
3552
+ * @category Scales
3553
+ */
2344
3554
  declare const LOCRIAN_MASK: number;
2345
- /** Major pentatonic: offsets {0,2,4,7,9}. */
3555
+ /**
3556
+ * Major pentatonic: offsets {0,2,4,7,9}.
3557
+ *
3558
+ * @category Scales
3559
+ */
2346
3560
  declare const MAJOR_PENTATONIC_MASK: number;
2347
- /** Minor pentatonic: offsets {0,3,5,7,10}. */
3561
+ /**
3562
+ * Minor pentatonic: offsets {0,3,5,7,10}.
3563
+ *
3564
+ * @category Scales
3565
+ */
2348
3566
  declare const MINOR_PENTATONIC_MASK: number;
2349
- /** Hexatonic blues scale: minor pentatonic plus the flat-fifth — {0,3,5,6,7,10}. */
3567
+ /**
3568
+ * Hexatonic blues scale: minor pentatonic plus the flat-fifth — {0,3,5,6,7,10}.
3569
+ *
3570
+ * @category Scales
3571
+ */
2350
3572
  declare const BLUES_MASK: number;
2351
- /** Whole-tone scale: offsets {0,2,4,6,8,10}. */
3573
+ /**
3574
+ * Whole-tone scale: offsets {0,2,4,6,8,10}.
3575
+ *
3576
+ * @category Scales
3577
+ */
2352
3578
  declare const WHOLE_TONE_MASK: number;
2353
- /** Octatonic (half-step first): offsets {0,1,3,4,6,7,9,10}. */
3579
+ /**
3580
+ * Octatonic (half-step first): offsets {0,1,3,4,6,7,9,10}.
3581
+ *
3582
+ * @category Scales
3583
+ */
2354
3584
  declare const OCTATONIC_HALF_WHOLE_MASK: number;
2355
- /** Octatonic (whole-step first): offsets {0,2,3,5,6,8,9,11}. */
3585
+ /**
3586
+ * Octatonic (whole-step first): offsets {0,2,3,5,6,8,9,11}.
3587
+ *
3588
+ * @category Scales
3589
+ */
2356
3590
  declare const OCTATONIC_WHOLE_HALF_MASK: number;
2357
- /** Chromatic scale: all twelve pitch classes. */
3591
+ /**
3592
+ * Chromatic scale: all twelve pitch classes.
3593
+ *
3594
+ * @category Scales
3595
+ */
2358
3596
  declare const CHROMATIC_MASK = 4095;
2359
- /** Named scale masks addressable by {@link scaleByName}. */
3597
+ /**
3598
+ * Named scale masks addressable by {@link scaleByName}.
3599
+ *
3600
+ * @category Scales
3601
+ */
2360
3602
  declare const NAMED_SCALES: Record<string, number>;
2361
- /** Build a `KeyScale` for a major key on the given root pitch class. */
3603
+ /**
3604
+ * Build a `KeyScale` for a major key on the given root pitch class.
3605
+ *
3606
+ * @example
3607
+ * ```ts
3608
+ * import { majorKey } from '@libraz/libcantus';
3609
+ * const cMajor = majorKey(0); // C major: { rootPc: 0, modeMask12: MAJOR_MASK }
3610
+ * ```
3611
+ *
3612
+ * @category Scales
3613
+ */
2362
3614
  declare function majorKey(rootPc: number): KeyScale;
2363
- /** Build a `KeyScale` for a natural-minor key on the given root pitch class. */
3615
+ /**
3616
+ * Build a `KeyScale` for a natural-minor key on the given root pitch class.
3617
+ *
3618
+ * @example
3619
+ * ```ts
3620
+ * import { minorKey } from '@libraz/libcantus';
3621
+ * const aMinor = minorKey(9); // A natural minor: { rootPc: 9, modeMask12: NATURAL_MINOR_MASK }
3622
+ * ```
3623
+ *
3624
+ * @category Scales
3625
+ */
2364
3626
  declare function minorKey(rootPc: number): KeyScale;
2365
3627
  /**
2366
3628
  * Build a `KeyScale` from a named scale (see {@link NAMED_SCALES}).
@@ -2369,6 +3631,14 @@ declare function minorKey(rootPc: number): KeyScale;
2369
3631
  * @param rootPc The root pitch class.
2370
3632
  * @returns The key/scale.
2371
3633
  * @throws If the name is not a known scale.
3634
+ *
3635
+ * @example
3636
+ * ```ts
3637
+ * import { scaleByName } from '@libraz/libcantus';
3638
+ * const dDorian = scaleByName('dorian', 2); // D Dorian, rootPc 2
3639
+ * ```
3640
+ *
3641
+ * @category Scales
2372
3642
  */
2373
3643
  declare function scaleByName(name: string, rootPc: number): KeyScale;
2374
3644
  /**
@@ -2377,6 +3647,16 @@ declare function scaleByName(name: string, rootPc: number): KeyScale;
2377
3647
  * @param pitch MIDI pitch or bare pitch class.
2378
3648
  * @param key The key/scale to test against.
2379
3649
  * @returns True if the pitch class is a member of the scale.
3650
+ *
3651
+ * @example
3652
+ * ```ts
3653
+ * import { majorKey, isScaleTone } from '@libraz/libcantus';
3654
+ * const key = majorKey(0); // C major
3655
+ * isScaleTone(64, key); // true — E is in C major
3656
+ * isScaleTone(61, key); // false — C# is not
3657
+ * ```
3658
+ *
3659
+ * @category Scales
2380
3660
  */
2381
3661
  declare function isScaleTone(pitch: number, key: KeyScale): boolean;
2382
3662
  /**
@@ -2388,6 +3668,8 @@ declare function isScaleTone(pitch: number, key: KeyScale): boolean;
2388
3668
  * @param pitch MIDI pitch to snap.
2389
3669
  * @param key The key/scale to snap to.
2390
3670
  * @returns The nearest in-scale MIDI pitch.
3671
+ *
3672
+ * @category Scales
2391
3673
  */
2392
3674
  declare function nearestScaleTone(pitch: number, key: KeyScale): number;
2393
3675
  /**
@@ -2396,6 +3678,8 @@ declare function nearestScaleTone(pitch: number, key: KeyScale): number;
2396
3678
  * @param pitch MIDI pitch or bare pitch class.
2397
3679
  * @param key The key/scale to measure against.
2398
3680
  * @returns The 0-based degree, or -1 if the pitch is not in the scale.
3681
+ *
3682
+ * @category Scales
2399
3683
  */
2400
3684
  declare function pitchToScaleDegree(pitch: number, key: KeyScale): number;
2401
3685
  /**
@@ -2403,6 +3687,8 @@ declare function pitchToScaleDegree(pitch: number, key: KeyScale): number;
2403
3687
  *
2404
3688
  * @param key The key/scale to enumerate.
2405
3689
  * @returns The member pitch classes, sorted ascending in [0, 11].
3690
+ *
3691
+ * @category Scales
2406
3692
  */
2407
3693
  declare function diatonicPitchClasses(key: KeyScale): number[];
2408
3694
  /**
@@ -2413,6 +3699,8 @@ declare function diatonicPitchClasses(key: KeyScale): number[];
2413
3699
  *
2414
3700
  * @param key The key/scale to enumerate.
2415
3701
  * @returns The member pitch classes ordered by scale degree.
3702
+ *
3703
+ * @category Scales
2416
3704
  */
2417
3705
  declare function scaleTonesInDegreeOrder(key: KeyScale): number[];
2418
3706
 
@@ -2437,6 +3725,7 @@ declare function scaleTonesInDegreeOrder(key: KeyScale): number[];
2437
3725
  * @param tonic The spelled tonic (its letter anchors the spelling).
2438
3726
  * @param key The key/scale.
2439
3727
  * @returns The spelled note (without octave).
3728
+ * @category Pitch & Intervals
2440
3729
  */
2441
3730
  declare function spellPitchClass(pc: number, tonic: Note$1, key: KeyScale): Note$1;
2442
3731
  /**
@@ -2448,6 +3737,13 @@ declare function spellPitchClass(pc: number, tonic: Note$1, key: KeyScale): Note
2448
3737
  * @param tonic The spelled tonic.
2449
3738
  * @param key The key/scale.
2450
3739
  * @returns Spelled notes, one per scale degree.
3740
+ * @example
3741
+ * ```ts
3742
+ * import { spellScale, noteNames, parseNote, majorKey } from '@libraz/libcantus';
3743
+ * noteNames(spellScale(parseNote('C'), majorKey(0)));
3744
+ * // ['C', 'D', 'E', 'F', 'G', 'A', 'B']
3745
+ * ```
3746
+ * @category Pitch & Intervals
2451
3747
  */
2452
3748
  declare function spellScale(tonic: Note$1, key: KeyScale): Note$1[];
2453
3749
  /**
@@ -2457,6 +3753,7 @@ declare function spellScale(tonic: Note$1, key: KeyScale): Note$1[];
2457
3753
  * @param tonic The spelled tonic.
2458
3754
  * @param key The key/scale.
2459
3755
  * @returns Spelled notes, in input order.
3756
+ * @category Pitch & Intervals
2460
3757
  */
2461
3758
  declare function spellPitchClasses(pcs: number[], tonic: Note$1, key: KeyScale): Note$1[];
2462
3759
  /**
@@ -2471,6 +3768,14 @@ declare function spellPitchClasses(pcs: number[], tonic: Note$1, key: KeyScale):
2471
3768
  * @param tonic The spelled tonic of the key.
2472
3769
  * @param key The key/scale.
2473
3770
  * @returns Spelled chord tones, root first.
3771
+ * @example
3772
+ * ```ts
3773
+ * import { spellChord, noteNames, parseNote, majorKey, makeChord } from '@libraz/libcantus';
3774
+ * // G7 in C major
3775
+ * noteNames(spellChord(makeChord(7, 'dom7'), parseNote('C'), majorKey(0)));
3776
+ * // ['G', 'B', 'D', 'F']
3777
+ * ```
3778
+ * @category Pitch & Intervals
2474
3779
  */
2475
3780
  declare function spellChord(chord: Chord$1, tonic: Note$1, key: KeyScale): Note$1[];
2476
3781
  /**
@@ -2478,6 +3783,7 @@ declare function spellChord(chord: Chord$1, tonic: Note$1, key: KeyScale): Note$
2478
3783
  *
2479
3784
  * @param notes The notes.
2480
3785
  * @returns Their formatted names.
3786
+ * @category Pitch & Intervals
2481
3787
  */
2482
3788
  declare function noteNames(notes: Note$1[]): string[];
2483
3789
 
@@ -2493,13 +3799,26 @@ declare function noteNames(notes: Note$1[]): string[];
2493
3799
  * Parse a lead-sheet chord symbol into a {@link Chord}.
2494
3800
  *
2495
3801
  * Accepts `<root><quality>[/<bass>]`, e.g. `Cmaj7`, `F#m7b5`, `Bb7`, `C/G`,
2496
- * `C6/9`. The `/` after a quality is ambiguous between a slash bass and the
2497
- * `6/9` quality; it resolves to a bass only when the token following it is
2498
- * itself a valid note.
3802
+ * `C6/9`, `C6/9/E`. Root and bass letters are case-insensitive, matching
3803
+ * {@link parseNote}. A `/` is ambiguous between a slash bass and the `6/9`
3804
+ * quality; the text splits at the last `/` whose right-hand side is a valid
3805
+ * bare note preceded by a recognized quality, so `6/9` (with or without a
3806
+ * further slash bass) parses as a quality.
3807
+ *
3808
+ * The parsed chord carries the root/bass spellings as enharmonic hints
3809
+ * (`rootSpelling`/`bassSpelling`) so {@link formatChordSymbol} can reproduce
3810
+ * flat spellings such as `Bbmaj7` instead of respelling them with sharps.
2499
3811
  *
2500
3812
  * @param text The chord symbol text.
2501
3813
  * @returns The parsed chord.
2502
3814
  * @throws If the root or quality is not recognized.
3815
+ * @example
3816
+ * ```ts
3817
+ * import { parseChordSymbol, formatChordSymbol } from '@libraz/libcantus';
3818
+ * const c = parseChordSymbol('Bbmaj7');
3819
+ * formatChordSymbol(c); // 'Bbmaj7' — flat spelling is preserved on round-trip
3820
+ * ```
3821
+ * @category Chords
2503
3822
  */
2504
3823
  declare function parseChordSymbol(text: string): Chord$1;
2505
3824
  /**
@@ -2507,12 +3826,21 @@ declare function parseChordSymbol(text: string): Chord$1;
2507
3826
  *
2508
3827
  * The inverse of {@link parseChordSymbol}: each quality maps to one canonical
2509
3828
  * suffix spelling, and a slash bass is appended only when it differs from the
2510
- * root.
3829
+ * root. When the chord carries `rootSpelling`/`bassSpelling` hints (as chords
3830
+ * from {@link parseChordSymbol} do) and no explicit `flats` preference is
3831
+ * given, the hints are reused so flat symbols round-trip unchanged.
2511
3832
  *
2512
3833
  * @param chord The chord to format.
2513
3834
  * @param opts Formatting options.
2514
- * @param opts.flats Prefer flat spellings over sharps for altered roots/basses.
3835
+ * @param opts.flats Prefer flat spellings over sharps for altered roots/basses;
3836
+ * passing either `true` or `false` overrides any spelling hints.
2515
3837
  * @returns The chord symbol text.
3838
+ * @example
3839
+ * ```ts
3840
+ * import { makeChord, formatChordSymbol } from '@libraz/libcantus';
3841
+ * formatChordSymbol(makeChord(0, 'min7')); // 'Cm7'
3842
+ * ```
3843
+ * @category Chords
2516
3844
  */
2517
3845
  declare function formatChordSymbol(chord: Chord$1, opts?: {
2518
3846
  flats?: boolean;
@@ -2525,6 +3853,12 @@ declare function formatChordSymbol(chord: Chord$1, opts?: {
2525
3853
  * @param opts Formatting options for the result; see {@link formatChordSymbol}.
2526
3854
  * @returns The transposed chord symbol text.
2527
3855
  * @throws If `text` does not parse as a chord symbol.
3856
+ * @example
3857
+ * ```ts
3858
+ * import { transposeChordSymbol } from '@libraz/libcantus';
3859
+ * transposeChordSymbol('C/G', 2); // 'D/A'
3860
+ * ```
3861
+ * @category Chords
2528
3862
  */
2529
3863
  declare function transposeChordSymbol(text: string, semitones: number, opts?: {
2530
3864
  flats?: boolean;
@@ -2542,6 +3876,8 @@ declare function transposeChordSymbol(text: string, semitones: number, opts?: {
2542
3876
  /**
2543
3877
  * An equal-tempered tuning: a reference pitch and a number of equal divisions of
2544
3878
  * the octave. With `divisions === 12` a step index is an ordinary MIDI number.
3879
+ *
3880
+ * @category Pitch & Intervals
2545
3881
  */
2546
3882
  type Tuning = {
2547
3883
  /** Step index (MIDI number when `divisions` is 12) whose frequency is `refFreq`. */
@@ -2551,7 +3887,11 @@ type Tuning = {
2551
3887
  /** Equal divisions of the octave (12 standard; e.g. 19 or 31 for microtonal). */
2552
3888
  divisions: number;
2553
3889
  };
2554
- /** Standard twelve-tone equal temperament, A4 (MIDI 69) = 440 Hz. */
3890
+ /**
3891
+ * Standard twelve-tone equal temperament, A4 (MIDI 69) = 440 Hz.
3892
+ *
3893
+ * @category Pitch & Intervals
3894
+ */
2555
3895
  declare const TWELVE_TET: Tuning;
2556
3896
  /**
2557
3897
  * Build an equal temperament with `n` divisions of the octave.
@@ -2560,6 +3900,13 @@ declare const TWELVE_TET: Tuning;
2560
3900
  * @param refFreq Reference frequency in Hz (default 440).
2561
3901
  * @param refStep Step index of the reference (default 69).
2562
3902
  * @returns The tuning.
3903
+ * @example
3904
+ * ```ts
3905
+ * import { edo, frequencyOf } from '@libraz/libcantus';
3906
+ * const et19 = edo(19); // { refStep: 69, refFreq: 440, divisions: 19 }
3907
+ * frequencyOf(70, et19); // one 19-EDO step above A4
3908
+ * ```
3909
+ * @category Pitch & Intervals
2563
3910
  */
2564
3911
  declare function edo(n: number, refFreq?: number, refStep?: number): Tuning;
2565
3912
  /**
@@ -2568,6 +3915,13 @@ declare function edo(n: number, refFreq?: number, refStep?: number): Tuning;
2568
3915
  * @param step Step index (a MIDI number under 12-EDO).
2569
3916
  * @param tuning The tuning (default 12-TET).
2570
3917
  * @returns The frequency in Hz.
3918
+ * @example
3919
+ * ```ts
3920
+ * import { frequencyOf } from '@libraz/libcantus';
3921
+ * frequencyOf(69); // 440 (A4 in 12-TET)
3922
+ * frequencyOf(60); // middle C in Hz
3923
+ * ```
3924
+ * @category Pitch & Intervals
2571
3925
  */
2572
3926
  declare function frequencyOf(step: number, tuning?: Tuning): number;
2573
3927
  /**
@@ -2577,6 +3931,7 @@ declare function frequencyOf(step: number, tuning?: Tuning): number;
2577
3931
  * @param freq Frequency in Hz.
2578
3932
  * @param tuning The tuning (default 12-TET).
2579
3933
  * @returns The nearest step index.
3934
+ * @category Pitch & Intervals
2580
3935
  */
2581
3936
  declare function nearestStep(freq: number, tuning?: Tuning): number;
2582
3937
  /**
@@ -2585,6 +3940,7 @@ declare function nearestStep(freq: number, tuning?: Tuning): number;
2585
3940
  * @param a Lower/first frequency in Hz.
2586
3941
  * @param b Upper/second frequency in Hz.
2587
3942
  * @returns Cents from `a` to `b` (negative if `b` is lower).
3943
+ * @category Pitch & Intervals
2588
3944
  */
2589
3945
  declare function centsBetweenFreq(a: number, b: number): number;
2590
3946
  /**
@@ -2593,6 +3949,7 @@ declare function centsBetweenFreq(a: number, b: number): number;
2593
3949
  * @param steps Number of steps.
2594
3950
  * @param tuning The tuning (default 12-TET).
2595
3951
  * @returns The cents.
3952
+ * @category Pitch & Intervals
2596
3953
  */
2597
3954
  declare function centsOfSteps(steps: number, tuning?: Tuning): number;
2598
3955
  /**
@@ -2602,11 +3959,14 @@ declare function centsOfSteps(steps: number, tuning?: Tuning): number;
2602
3959
  * @param numerator Ratio numerator.
2603
3960
  * @param denominator Ratio denominator.
2604
3961
  * @returns The interval in cents.
3962
+ * @category Pitch & Intervals
2605
3963
  */
2606
3964
  declare function ratioToCents(numerator: number, denominator: number): number;
2607
3965
  /**
2608
3966
  * Five-limit just-intonation ratios for the twelve interval classes above a
2609
3967
  * unison, indexed by semitone class (0..12).
3968
+ *
3969
+ * @category Pitch & Intervals
2610
3970
  */
2611
3971
  declare const JUST_RATIOS: Record<number, [number, number]>;
2612
3972
  /**
@@ -2615,7 +3975,8 @@ declare const JUST_RATIOS: Record<number, [number, number]>;
2615
3975
  *
2616
3976
  * @param semitoneClass Semitone class in [0, 12].
2617
3977
  * @returns The deviation in cents, or NaN if the class has no listed ratio.
3978
+ * @category Pitch & Intervals
2618
3979
  */
2619
3980
  declare function justDeviationCents(semitoneClass: number): number;
2620
3981
 
2621
- export { type AnalyzedNote, type ArrangementAnalysis, type ArrangementOptions, type ArrangementTrack, BLUES_MASK, type BarPosition, type BassLineOptions, type BassSegment, type BassStyle, type BorrowedChord, type BorrowedSource, CHROMATIC_MASK, type Cadence, type CadenceHit, Chord, type ChordAnalysis, type Chord$1 as ChordData, type ChordMatch, type ChordQuality, type ChordScaleMatch, type ChordScaleReportEntry, type ChordSegment, type ChordTimeline, type ChordTimelineOptions, type ChordTimelineResult, type Conflict, type CounterMelodyOptions, DORIAN_MASK, type DrumGenOptions, type DrumHit, type DrumRole, type GenerateMotifOptions, type GenerateProgressionOptions, type GeneratedChord, type GrooveFeel, type GrooveSlot, type GrooveStyle, type GrooveTemplate, HARMONIC_MINOR_MASK, type HarmonicFunction, type HarmonizeOptions, type HarmonizeResult, type HarmonyRole, type HumanizeOptions, Interval, IntervalQuality, JUST_RATIOS, Key, type KeyMatch, type KeyScale, LOCRIAN_MASK, LYDIAN_MASK, type LockLevel, MAJOR_MASK, MAJOR_PENTATONIC_MASK, MELODIC_MINOR_MASK, MINOR_PENTATONIC_MASK, MIXOLYDIAN_MASK, type MelodyNote, type MotifCell, type MotifContour, type MotifNote, type MotifTransform, NAMED_SCALES, NATURAL_MINOR_MASK, Note, type Note$1 as NoteData, type NoteEvent, NoteSafety, OCTATONIC_HALF_WHOLE_MASK, OCTATONIC_WHOLE_HALF_MASK, PHRYGIAN_MASK, type ProgFunction, type ProgStyle, Progression, type ProgressionPreset, ReasonFlag, type RhythmEvent, type RhythmOptions, type Rng, SATB_RANGES, type SafetyProfile, type SafetyQuery, type SafetyResult, type ScaleChoice, type Section, type SpelledInterval, type StyledVoicingOptions, type SubstituteOptions, type Substitution, type SubstitutionType, TWELVE_TET, type TensionPoint, type TheoryLabel, type TimeSignature, type TrackAnalysis, type TrackRole, type Tuning, type VoiceNote, type VoiceRange, type VoiceSnapshot, type VoicedRole, type VoicingOptions, type VoicingStyle, WHOLE_TONE_MASK, analyzeArrangement, analyzeChord, analyzeVoice, applyGrooveTemplate, availableTensions, avoidNotes, barPositionToBeat, beatToBarPosition, beatsPerBar, borrowedSource, centsBetweenFreq, centsOfSteps, chordFromDegree, chordPitchClasses, chordQualities, chordScaleReport, chordScales, chordTimelineFromChords, chordTimelineFromNotes, chordToRoman, chordToneRole, classifyInterval, createRng, createsHiddenParallelPerfect, createsParallelOctave, createsParallelPerfect, createsParallelUnison, createsVerticalDissonance, createsVoiceCrossing, createsVoiceOverlap, detectCadence, detectCadences, detectChord, detectChordBest, detectKey, developMotif, diatonicPitchClasses, diatonicSeventh, diatonicTriad, edo, enumerateSafePitches, evaluateSafety, exceedsSpacing, extractGrooveTemplate, formatChordSymbol, formatNote, formatTimeSignature, frequencyOf, functionOf, generateBassLine, generateCounterMelody, generateDrums, generateMotif, generateProgression, generateRhythm, harmonizeMelody, humanize, isBorrowedChord, isCompound, isConsonantInterval, isDiatonic, isForbiddenMelodicLeap, isLeadingToneResolution, isMinorKey, isPerfectInterval, isScaleTone, isStrongBeat, justDeviationCents, majorKey, makeChord, maskFromOffsets, metricWeight, midiToNote, minorKey, modalInterchangePalette, nearestScaleTone, nearestStep, negativeHarmonyMirror, nextVoicing, noteNames, noteToMidi, noteToPitchClass, onsetWeightCurve, parallelKey, parseChordSymbol, parseNote, parseTimeSignature, pitchToScaleDegree, progressions, progressionsByStyle, pulsesPerBar, ratioToCents, rhythmDensity, roleOf, romanToChord, scaleByName, scaleMatchesChord, scaleTonesInDegreeOrder, scalesForChanges, secondaryDominant, spellChord, spellPitchClass, spellPitchClasses, spellScale, spelledInterval, substituteChord, tensionCurve, transformMotif, transposeChordSymbol, tuplet, voiceChord, voiceChordStyled, voiceLeadingCost, voiceProgression };
3982
+ export { type AnalyzedNote, type ArrangementAnalysis, type ArrangementOptions, type ArrangementTrack, BLUES_MASK, type BarPosition, type BassLineOptions, type BassSegment, type BassStyle, type BorrowedChord, type BorrowedSource, CHROMATIC_MASK, type Cadence, type CadenceHit, Chord, type ChordAnalysis, type Chord$1 as ChordData, type ChordMatch, type ChordQuality, type ChordScaleMatch, type ChordScaleReportEntry, type ChordSegment, type ChordTimeline, type ChordTimelineOptions, type ChordTimelineResult, type Conflict, type CounterMelodyOptions, DORIAN_MASK, type DrumGenOptions, type DrumHit, type DrumRole, type EuclideanKick, type GenerateMotifOptions, type GenerateProgressionOptions, type GeneratedChord, type GrooveFeel, type GrooveSlot, type GrooveStyle, type GrooveTemplate, HARMONIC_MINOR_MASK, type HarmonicFunction, type HarmonizeOptions, type HarmonizeResult, type HarmonyRole, type HumanizeOptions, Interval, IntervalQuality, JUST_RATIOS, Key, type KeyMatch, type KeyScale, LOCRIAN_MASK, LYDIAN_MASK, type LockLevel, MAJOR_MASK, MAJOR_PENTATONIC_MASK, MELODIC_MINOR_MASK, MINOR_PENTATONIC_MASK, MIXOLYDIAN_MASK, type MelodyNote, type MotifCell, type MotifContour, type MotifNote, type MotifTransform, NAMED_SCALES, NATURAL_MINOR_MASK, Note, type Note$1 as NoteData, type NoteEvent, NoteSafety, OCTATONIC_HALF_WHOLE_MASK, OCTATONIC_WHOLE_HALF_MASK, PHRYGIAN_MASK, type ProgFunction, type ProgStyle, Progression, type ProgressionPreset, ReasonFlag, type RhythmEvent, type RhythmOptions, type Rng, SATB_RANGES, type SafetyProfile, type SafetyQuery, type SafetyResult, type ScaleChoice, type Section, type SpelledInterval, type StyledVoicingOptions, type SubstituteOptions, type Substitution, type SubstitutionType, TWELVE_TET, type TensionPoint, type TheoryLabel, type TimeSignature, type TrackAnalysis, type TrackRole, type Tuning, type VoiceNote, type VoiceRange, type VoiceSnapshot, type VoicedRole, type VoicingOptions, type VoicingStyle, WHOLE_TONE_MASK, analyzeArrangement, analyzeChord, analyzeVoice, applyGrooveTemplate, availableTensions, avoidNotes, barPositionToBeat, beatToBarPosition, beatsPerBar, borrowedSource, centsBetweenFreq, centsOfSteps, chordFromDegree, chordPitchClasses, chordQualities, chordScaleReport, chordScales, chordTimelineFromChords, chordTimelineFromNotes, chordToRoman, chordToneRole, classifyInterval, createRng, createsHiddenParallelPerfect, createsParallelOctave, createsParallelPerfect, createsParallelUnison, createsVerticalDissonance, createsVoiceCrossing, createsVoiceOverlap, detectCadence, detectCadences, detectChord, detectChordBest, detectKey, developMotif, diatonicPitchClasses, diatonicSeventh, diatonicTriad, edo, enumerateSafePitches, evaluateSafety, exceedsSpacing, extractGrooveTemplate, formatChordSymbol, formatNote, formatTimeSignature, frequencyOf, functionOf, generateBassLine, generateCounterMelody, generateDrums, generateMotif, generateProgression, generateRhythm, harmonizeMelody, humanize, isBorrowedChord, isCompound, isConsonantInterval, isDiatonic, isForbiddenMelodicLeap, isLeadingToneResolution, isMinorKey, isPerfectInterval, isScaleTone, isStrongBeat, justDeviationCents, majorKey, makeChord, maskFromOffsets, metricWeight, midiToNote, minorKey, modalInterchangePalette, nearestScaleTone, nearestStep, negativeHarmonyMirror, nextVoicing, noteNames, noteToMidi, noteToPitchClass, onsetWeightCurve, parallelKey, parseChordSymbol, parseNote, parseTimeSignature, pitchToScaleDegree, progressions, progressionsByStyle, pulsesPerBar, ratioToCents, rhythmDensity, roleOf, romanToChord, scaleByName, scaleMatchesChord, scaleTonesInDegreeOrder, scalesForChanges, secondaryDominant, spellChord, spellPitchClass, spellPitchClasses, spellScale, spelledInterval, substituteChord, tensionCurve, transformMotif, transposeChordSymbol, tuplet, voiceChord, voiceChordStyled, voiceLeadingCost, voiceProgression };