@libraz/libcantus 1.0.1 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (142) hide show
  1. package/README.md +27 -65
  2. package/README_ja.md +28 -66
  3. package/dist/analyze/index.cjs +11 -7
  4. package/dist/analyze/index.cjs.map +1 -1
  5. package/dist/analyze/index.d.cts +79 -144
  6. package/dist/analyze/index.d.ts +79 -144
  7. package/dist/analyze/index.js +20 -16
  8. package/dist/chunk-35NBV2FT.cjs +145 -0
  9. package/dist/chunk-35NBV2FT.cjs.map +1 -0
  10. package/dist/{chunk-UADYAYAT.cjs → chunk-3R3QVKY5.cjs} +1353 -580
  11. package/dist/chunk-3R3QVKY5.cjs.map +1 -0
  12. package/dist/{chunk-WWURE4XT.cjs → chunk-76ZBTRG2.cjs} +624 -729
  13. package/dist/chunk-76ZBTRG2.cjs.map +1 -0
  14. package/dist/{chunk-FVSI36UV.js → chunk-7KG3RTYS.js} +197 -110
  15. package/dist/chunk-7KG3RTYS.js.map +1 -0
  16. package/dist/{chunk-VTI6FOLB.js → chunk-AGOVW7U6.js} +709 -133
  17. package/dist/chunk-AGOVW7U6.js.map +1 -0
  18. package/dist/{chunk-E3F4AHAH.cjs → chunk-CGBADIO5.cjs} +221 -134
  19. package/dist/chunk-CGBADIO5.cjs.map +1 -0
  20. package/dist/{chunk-6XH6QZYQ.cjs → chunk-DSMJRXCZ.cjs} +1455 -849
  21. package/dist/chunk-DSMJRXCZ.cjs.map +1 -0
  22. package/dist/{chunk-PKFNUHDY.js → chunk-FBH75DAY.js} +1218 -612
  23. package/dist/chunk-FBH75DAY.js.map +1 -0
  24. package/dist/chunk-H2KJHBW4.js +3329 -0
  25. package/dist/chunk-H2KJHBW4.js.map +1 -0
  26. package/dist/chunk-HPVSH7SF.cjs +2294 -0
  27. package/dist/chunk-HPVSH7SF.cjs.map +1 -0
  28. package/dist/{chunk-MXO72PLY.cjs → chunk-HWHGOVO6.cjs} +21 -19
  29. package/dist/chunk-HWHGOVO6.cjs.map +1 -0
  30. package/dist/chunk-HYJJ2V2I.js +2294 -0
  31. package/dist/chunk-HYJJ2V2I.js.map +1 -0
  32. package/dist/{chunk-AFM2ULJH.cjs → chunk-J7FHVZII.cjs} +1567 -1067
  33. package/dist/chunk-J7FHVZII.cjs.map +1 -0
  34. package/dist/chunk-K6OZXIR6.js +1 -0
  35. package/dist/{chunk-H3VORETI.js → chunk-M5RYMAFI.js} +487 -592
  36. package/dist/chunk-M5RYMAFI.js.map +1 -0
  37. package/dist/chunk-NB25P3EH.js +363 -0
  38. package/dist/chunk-NB25P3EH.js.map +1 -0
  39. package/dist/{chunk-TTCLJX6D.js → chunk-NFJ4P6ZZ.js} +10 -8
  40. package/dist/chunk-NFJ4P6ZZ.js.map +1 -0
  41. package/dist/chunk-NM7UAMC3.cjs +457 -0
  42. package/dist/chunk-NM7UAMC3.cjs.map +1 -0
  43. package/dist/chunk-PM4XJE2Y.cjs +363 -0
  44. package/dist/chunk-PM4XJE2Y.cjs.map +1 -0
  45. package/dist/chunk-PUKJP2Z5.js +145 -0
  46. package/dist/chunk-PUKJP2Z5.js.map +1 -0
  47. package/dist/{chunk-VOHZB45S.js → chunk-Q6LFSAKV.js} +1321 -821
  48. package/dist/chunk-Q6LFSAKV.js.map +1 -0
  49. package/dist/{chunk-INHVXP6Z.js → chunk-RFIBF2RR.js} +1203 -430
  50. package/dist/chunk-RFIBF2RR.js.map +1 -0
  51. package/dist/{chunk-Q2WGKJNN.cjs → chunk-S5BKZZGM.cjs} +699 -123
  52. package/dist/chunk-S5BKZZGM.cjs.map +1 -0
  53. package/dist/chunk-SGLEQVJH.cjs +3329 -0
  54. package/dist/chunk-SGLEQVJH.cjs.map +1 -0
  55. package/dist/chunk-UGLFDG7L.cjs +1 -0
  56. package/dist/chunk-UGLFDG7L.cjs.map +1 -0
  57. package/dist/{chunk-YH3BIKHH.js → chunk-UMWZ4ZET.js} +146 -49
  58. package/dist/chunk-UMWZ4ZET.js.map +1 -0
  59. package/dist/{index-szBv3496.d.ts → coerce-DP0vYu-x.d.ts} +286 -199
  60. package/dist/{index-C_8o--VE.d.cts → coerce-DRERzdve.d.cts} +286 -199
  61. package/dist/core/index.cjs +9 -5
  62. package/dist/core/index.cjs.map +1 -1
  63. package/dist/core/index.d.cts +122 -108
  64. package/dist/core/index.d.ts +122 -108
  65. package/dist/core/index.js +32 -28
  66. package/dist/generate/index.cjs +8 -8
  67. package/dist/generate/index.d.cts +168 -84
  68. package/dist/generate/index.d.ts +168 -84
  69. package/dist/generate/index.js +7 -7
  70. package/dist/{index-CGpRv5sl.d.cts → index-9eoQs2C1.d.ts} +34 -19
  71. package/dist/{index-CCNJRG-P.d.cts → index-B9QLziDe.d.cts} +293 -56
  72. package/dist/{index-Dzr13q3d.d.cts → index-BBWNZS0f.d.cts} +135 -58
  73. package/dist/{index-9wcMhG73.d.ts → index-BHIUyjhZ.d.ts} +293 -56
  74. package/dist/{index-BGFW-8P2.d.cts → index-BJgP97N1.d.ts} +196 -114
  75. package/dist/{index-CunYKLiu.d.ts → index-BL5N2Oyz.d.cts} +1 -1
  76. package/dist/{index-Cj49F892.d.ts → index-BMweUlm5.d.cts} +63 -23
  77. package/dist/{index-CgHqxdps.d.ts → index-BNSM-DSk.d.cts} +196 -114
  78. package/dist/{index-D57QRbVn.d.ts → index-BRMbPkHE.d.ts} +480 -254
  79. package/dist/{index-Chbst3Jx.d.ts → index-CJBBiAmU.d.ts} +135 -58
  80. package/dist/{index-BkGmlyI3.d.cts → index-CL4b4gUQ.d.ts} +63 -23
  81. package/dist/{index-B9MNZboQ.d.ts → index-Cy15oTvh.d.cts} +52 -22
  82. package/dist/{index-B9MNZboQ.d.cts → index-Cy15oTvh.d.ts} +52 -22
  83. package/dist/{index-BO6xE9YU.d.cts → index-DGCNKAUr.d.cts} +480 -254
  84. package/dist/{index-B4o55NDr.d.cts → index-Dw2DP7vm.d.ts} +1 -1
  85. package/dist/{index-G1uwGGWQ.d.ts → index-cHvbYgJI.d.cts} +34 -19
  86. package/dist/index.cjs +42 -14
  87. package/dist/index.cjs.map +1 -1
  88. package/dist/index.d.cts +14 -14
  89. package/dist/index.d.ts +14 -14
  90. package/dist/index.js +82 -54
  91. package/dist/{masks-DYbE485J.d.cts → masks-Cc7-MzzY.d.ts} +49 -2
  92. package/dist/{masks-DYbE485J.d.ts → masks-pADfTOiD.d.cts} +49 -2
  93. package/dist/model/index.cjs +19 -12
  94. package/dist/model/index.cjs.map +1 -1
  95. package/dist/model/index.d.cts +504 -182
  96. package/dist/model/index.d.ts +504 -182
  97. package/dist/model/index.js +18 -11
  98. package/dist/{positional-Cptlj-xs.d.ts → positional-DJgs6ltD.d.ts} +85 -8
  99. package/dist/{positional-DvH_sd8u.d.cts → positional-DMZer-FM.d.cts} +85 -8
  100. package/dist/theory/index.cjs +35 -6
  101. package/dist/theory/index.cjs.map +1 -1
  102. package/dist/theory/index.d.cts +257 -62
  103. package/dist/theory/index.d.ts +257 -62
  104. package/dist/theory/index.js +41 -12
  105. package/package.json +7 -5
  106. package/dist/chunk-2LCPM3EG.js +0 -3224
  107. package/dist/chunk-2LCPM3EG.js.map +0 -1
  108. package/dist/chunk-6XH6QZYQ.cjs.map +0 -1
  109. package/dist/chunk-6XPTBE7Y.cjs +0 -49
  110. package/dist/chunk-6XPTBE7Y.cjs.map +0 -1
  111. package/dist/chunk-AFM2ULJH.cjs.map +0 -1
  112. package/dist/chunk-B6XNKWZV.cjs +0 -3224
  113. package/dist/chunk-B6XNKWZV.cjs.map +0 -1
  114. package/dist/chunk-E3F4AHAH.cjs.map +0 -1
  115. package/dist/chunk-ELCTZUJJ.js +0 -379
  116. package/dist/chunk-ELCTZUJJ.js.map +0 -1
  117. package/dist/chunk-FVSI36UV.js.map +0 -1
  118. package/dist/chunk-H3VORETI.js.map +0 -1
  119. package/dist/chunk-H42UHPYW.js +0 -1577
  120. package/dist/chunk-H42UHPYW.js.map +0 -1
  121. package/dist/chunk-HFPS7JFD.js +0 -1
  122. package/dist/chunk-INHVXP6Z.js.map +0 -1
  123. package/dist/chunk-K4ZJUGF4.cjs +0 -379
  124. package/dist/chunk-K4ZJUGF4.cjs.map +0 -1
  125. package/dist/chunk-KNJEKLKV.js +0 -49
  126. package/dist/chunk-KNJEKLKV.js.map +0 -1
  127. package/dist/chunk-MXO72PLY.cjs.map +0 -1
  128. package/dist/chunk-NLEU4QSE.cjs +0 -360
  129. package/dist/chunk-NLEU4QSE.cjs.map +0 -1
  130. package/dist/chunk-OE6WK2Y2.cjs +0 -1577
  131. package/dist/chunk-OE6WK2Y2.cjs.map +0 -1
  132. package/dist/chunk-PKFNUHDY.js.map +0 -1
  133. package/dist/chunk-Q2WGKJNN.cjs.map +0 -1
  134. package/dist/chunk-RHIJ3S4I.cjs +0 -1
  135. package/dist/chunk-RHIJ3S4I.cjs.map +0 -1
  136. package/dist/chunk-TTCLJX6D.js.map +0 -1
  137. package/dist/chunk-UADYAYAT.cjs.map +0 -1
  138. package/dist/chunk-VOHZB45S.js.map +0 -1
  139. package/dist/chunk-VTI6FOLB.js.map +0 -1
  140. package/dist/chunk-WWURE4XT.cjs.map +0 -1
  141. package/dist/chunk-YH3BIKHH.js.map +0 -1
  142. /package/dist/{chunk-HFPS7JFD.js.map → chunk-K6OZXIR6.js.map} +0 -0
@@ -1,6 +1,6 @@
1
- import { f as Note, d as KeyScale, h as NoteLike, I as IntervalLike, S as SpelledInterval } from './index-B9MNZboQ.cjs';
2
- import { r as ScaleName, u as WorldScaleName, s as ScaleNameInput } from './masks-DYbE485J.cjs';
3
- import { c as ChordLike, b as Chord, K as KeyLike } from './index-C_8o--VE.cjs';
1
+ import { e as KeyScale, i as NoteLike, j as NoteNameOptions, P as ParseResult, g as Note, b as IntervalLike, S as SpelledInterval } from './index-Cy15oTvh.cjs';
2
+ import { n as ResolvedKey, K as KeyLike, c as ChordLike, b as Chord, r as SpelledKeyLike } from './coerce-DRERzdve.cjs';
3
+ import { r as ScaleName, u as WorldScaleName, s as ScaleNameInput } from './masks-pADfTOiD.cjs';
4
4
 
5
5
  /**
6
6
  * Which of the two modes a key signature is read in.
@@ -17,6 +17,21 @@ import { c as ChordLike, b as Chord, K as KeyLike } from './index-C_8o--VE.cjs';
17
17
  * @category Scales
18
18
  */
19
19
  type KeyMode = 'major' | 'minor';
20
+ /**
21
+ * Whether a key is one that is actually written with a key signature.
22
+ *
23
+ * Each of the seven diatonic modes has a signature of its own, and the harmonic
24
+ * and melodic minor are the minor key with a degree or two raised: G# harmonic
25
+ * minor is written with G# minor's five sharps and an F## in front of the note,
26
+ * which is why it is spelled G# and not Ab. Every other scale only borrows the
27
+ * signature of its parallel major or minor as an approximation, so nothing
28
+ * about how it is written follows from that signature — and how such a scale is
29
+ * spelled has to be decided from the scale itself.
30
+ *
31
+ * @param key The key/scale.
32
+ * @returns True when the signature is the key's own rather than a stand-in.
33
+ */
34
+ declare function isSignatureKey(key: KeyScale): boolean;
20
35
  /**
21
36
  * The key signature of a key, as a signed count of sharps (positive) or flats
22
37
  * (negative) — the `fifths` value a notation format such as MusicXML writes.
@@ -47,14 +62,14 @@ type KeyMode = 'major' | 'minor';
47
62
  * ```
48
63
  * @category Scales
49
64
  */
50
- declare function keySignatureFifths(tonic: NoteLike, key: KeyScale): number;
65
+ declare function keySignatureFifths(tonic: NoteLike, key: KeyLike): number;
51
66
  /**
52
67
  * The key a signature denotes: the inverse of {@link keySignatureFifths} for
53
68
  * the two modes a signature is conventionally read in.
54
69
  *
55
70
  * A signature names two keys — three sharps is both A major and F# minor — so
56
71
  * the mode decides which one is built. The tonic is spelled the way that key is
57
- * written, including the theoretical keys past ±7 (nine sharps is B# major).
72
+ * written, including the theoretical keys past ±7 (nine sharps is D# major).
58
73
  *
59
74
  * @param fifths The signed number of sharps (positive) or flats (negative).
60
75
  * @param mode Which of the signature's two keys to build; defaults to major.
@@ -69,10 +84,7 @@ declare function keySignatureFifths(tonic: NoteLike, key: KeyScale): number;
69
84
  * ```
70
85
  * @category Scales
71
86
  */
72
- declare function keyFromFifths(fifths: number, mode?: KeyMode): {
73
- tonic: Note;
74
- key: KeyScale;
75
- };
87
+ declare function keyFromFifths(fifths: number, mode?: KeyMode): ResolvedKey;
76
88
 
77
89
  /**
78
90
  * Scale systems: which pitch organisations functional harmony was built for,
@@ -168,6 +180,175 @@ declare function scaleSystemOf(scale: KeyScale | ScaleNameInput): ScaleSystem |
168
180
  */
169
181
  declare function supportsFunctionalHarmony(scale: KeyScale | ScaleNameInput): boolean;
170
182
 
183
+ /**
184
+ * Lead-sheet chord symbol parsing and formatting.
185
+ *
186
+ * Bridges the informal `<root><quality>[/<bass>]` notation musicians write
187
+ * (`Cmaj7`, `F#m7b5`, `Bb7`, `C/G`) and the library's structured {@link Chord}
188
+ * type, so callers can accept/emit plain text at the edges of the API.
189
+ *
190
+ * The root and the slash bass are note names, so they are read and written in
191
+ * whichever notation system the caller names — a German chart's `H7`, `As7` and
192
+ * `Ges/B` included. Unlike a note name, a chord symbol is never attributed to a
193
+ * system on its own: German `B` is a B flat and English `B` a B natural, and a
194
+ * symbol carries no `dur`/`moll` word to break the tie, so the most common
195
+ * symbol in the vocabulary would otherwise change chord with the source it came
196
+ * from. With no system given a symbol is English.
197
+ */
198
+
199
+ /**
200
+ * Parse a lead-sheet chord symbol into a {@link Chord}.
201
+ *
202
+ * Accepts `<root><quality>[/<bass>]`, e.g. `Cmaj7`, `F#m7b5`, `Bb7`, `C/G`,
203
+ * `C6/9`, `C6/9/E`. Root and bass letters are case-insensitive, matching
204
+ * {@link parseNote}. A `/` is ambiguous between a slash bass and the `6/9`
205
+ * quality; the text splits at the last `/` whose right-hand side is a valid
206
+ * bare note preceded by a recognized quality, so `6/9` (with or without a
207
+ * further slash bass) parses as a quality.
208
+ *
209
+ * The root and bass are read in `system`, so a German chart's `H7`, `As7` and
210
+ * `Ges/B` are read by asking for `'german'`. The system is never inferred: with
211
+ * none given the symbol is English, where `B` is the B natural and `H` no note
212
+ * at all. Case carries nothing in a chord symbol — unlike a German key name,
213
+ * where the case of the tonic is the mode — so the quality suffix alone says
214
+ * major or minor. Where a German root's flat suffix could equally open the
215
+ * quality, the longest root that leaves a known quality behind wins: `Asus4` is
216
+ * an A suspended chord and `Assus4` the A flat one.
217
+ *
218
+ * The quality suffix is read structurally when no name covers it, so a chart's
219
+ * bracketed tensions parse as readily as the names do: `Cmaj7(#11)`,
220
+ * `C7(b9,#11)`, `C7(13)`, `Csus4(add9)`, `C-Δ9`, `C6/9(#11)`. A `/` between two
221
+ * figures separates them as it does inside brackets, which is what the sixth
222
+ * and ninth of a `6/9` are. Such a chord carries the tones it names and reports
223
+ * the nearest quality name (see {@link chordSpecQuality}); read
224
+ * {@link chordSpecOf} for its structure.
225
+ *
226
+ * The parsed chord carries the root/bass spellings as enharmonic hints
227
+ * (`rootSpelling`/`bassSpelling`) so {@link formatChordSymbol} can reproduce
228
+ * flat spellings such as `Bbmaj7` instead of respelling them with sharps.
229
+ *
230
+ * @param text The chord symbol text.
231
+ * @param opts `system` reads the root and bass in that notation system instead
232
+ * of English.
233
+ * @returns The parsed chord.
234
+ * @throws If the root or quality is not recognized in that system. Use
235
+ * {@link tryParseChordSymbol} where failure is ordinary, such as a chord
236
+ * field read on every keystroke.
237
+ * @example
238
+ * ```ts
239
+ * import { parseChordSymbol, formatChordSymbol } from '@libraz/libcantus';
240
+ * const c = parseChordSymbol('Bbmaj7');
241
+ * formatChordSymbol(c); // 'Bbmaj7' — flat spelling is preserved on round-trip
242
+ * parseChordSymbol('H7', { system: 'german' }).rootPc; // 11 — the B natural
243
+ * parseChordSymbol('B', { system: 'german' }).rootPc; // 10 — the German B flat
244
+ * ```
245
+ * @category Chords
246
+ */
247
+ declare function parseChordSymbol(text: string, opts?: NoteNameOptions): Chord;
248
+ /**
249
+ * Parse a lead-sheet chord symbol, reporting failure instead of throwing it.
250
+ *
251
+ * The same reading as {@link parseChordSymbol} — that function is this one with
252
+ * its error thrown — for the callers where a symbol that does not parse yet is
253
+ * the normal state of the input rather than a fault: a chord field says what is
254
+ * wrong with what has been typed so far, and does not need a `try` around every
255
+ * keystroke to do it.
256
+ *
257
+ * @param text The chord symbol text.
258
+ * @param opts `system` reads the root and bass in that notation system instead
259
+ * of English.
260
+ * @returns The chord, or the error explaining why the text is not one.
261
+ * @example
262
+ * ```ts
263
+ * import { tryParseChordSymbol } from '@libraz/libcantus';
264
+ * const result = tryParseChordSymbol('Cmaj7(#11)');
265
+ * result.ok ? result.value.intervals : result.error.message;
266
+ * ```
267
+ * @category Chords
268
+ */
269
+ declare function tryParseChordSymbol(text: string, opts?: NoteNameOptions): ParseResult<Chord>;
270
+ /**
271
+ * How a chord symbol is written: in which notation system, and on which side of
272
+ * the enharmonic fence.
273
+ *
274
+ * @category Chords
275
+ */
276
+ type ChordSymbolOptions = NoteNameOptions & {
277
+ /**
278
+ * Which side of the staff the whole symbol is written on: `true` writes it in
279
+ * flats, `false` in sharps. The root, the slash bass and the chord's tones are
280
+ * spelled together, so a symbol never pairs a flat root with a sharp bass, and
281
+ * a spelling hint already on the requested side is kept rather than renamed.
282
+ * Where that side cannot spell the chord at all, the spelling a chart writes
283
+ * wins over an unwritable one.
284
+ */
285
+ flats?: boolean;
286
+ };
287
+ /**
288
+ * Format a {@link Chord} as a lead-sheet chord symbol.
289
+ *
290
+ * The inverse of {@link parseChordSymbol} in every notation system: each
291
+ * quality maps to one canonical suffix spelling, the root and bass are written
292
+ * in `system`, and a slash bass is appended only when it differs from the root.
293
+ * Every symbol written here reads back through {@link parseChordSymbol} as the
294
+ * same root, sounding bass and tones apart from the degrees the chord omits —
295
+ * whatever combination of tensions it carries, and whether or not a quality
296
+ * name covers it. Those omissions are the one difference the round trip has: a
297
+ * chord that leaves a degree out is written without saying so, so reading the
298
+ * symbol back puts the degree in.
299
+ * When the chord carries `rootSpelling`/`bassSpelling` hints (as chords from
300
+ * {@link parseChordSymbol} do) and no explicit `flats` preference is given, the
301
+ * hints are reused so flat symbols round-trip unchanged.
302
+ *
303
+ * The suffix is written from the chord's own tones (see {@link chordSpecOf}),
304
+ * not from its quality name, so a chord carrying alterations no name covers is
305
+ * written out in full — `C7(b9,#11)` — rather than under the nearest name. A
306
+ * tone the chord leaves out is not written: the symbol names the harmony, so a
307
+ * fifth-less dominant is still `C7`.
308
+ *
309
+ * @param chord The chord to format, as a chord symbol, chord data, or a
310
+ * `Chord`.
311
+ * @param opts `system` writes the root and bass in that notation system instead
312
+ * of English; `flats` chooses the side of the staff the whole symbol is
313
+ * written on, as {@link ChordSymbolOptions} describes.
314
+ * @returns The chord symbol text.
315
+ * @example
316
+ * ```ts
317
+ * import { makeChord, formatChordSymbol, parseChordSymbol } from '@libraz/libcantus';
318
+ * formatChordSymbol(makeChord(0, 'min7')); // 'Cm7'
319
+ * formatChordSymbol(parseChordSymbol('Bb7'), { system: 'german' }); // 'B7'
320
+ * formatChordSymbol(parseChordSymbol('B7'), { system: 'german' }); // 'H7'
321
+ * ```
322
+ * @category Chords
323
+ */
324
+ declare function formatChordSymbol(chord: ChordLike, opts?: ChordSymbolOptions): string;
325
+ /**
326
+ * Transpose a chord symbol by a number of semitones.
327
+ *
328
+ * The symbol is read in the same system it is written back in, so a German
329
+ * chart stays German across the transposition.
330
+ *
331
+ * The root and the bass are respelled where moving them by letter would leave
332
+ * a name no chart writes, so raising a flat chart a semitone gives `Bmaj7`
333
+ * rather than `Cbmaj7`. Pass `flats` to write the whole symbol on one side of
334
+ * the staff, root and bass together.
335
+ *
336
+ * @param text The chord symbol text.
337
+ * @param semitones Signed semitone offset to apply to the root and bass.
338
+ * @param opts Options for reading and writing the symbol; see
339
+ * {@link ChordSymbolOptions}.
340
+ * @returns The transposed chord symbol text.
341
+ * @throws If `text` does not parse as a chord symbol.
342
+ * @example
343
+ * ```ts
344
+ * import { transposeChordSymbol } from '@libraz/libcantus';
345
+ * transposeChordSymbol('C/G', 2); // 'D/A'
346
+ * transposeChordSymbol('H7', 1, { system: 'german' }); // 'C7'
347
+ * ```
348
+ * @category Chords
349
+ */
350
+ declare function transposeChordSymbol(text: string, semitones: number, opts?: ChordSymbolOptions): string;
351
+
171
352
  /**
172
353
  * Test whether every chord pitch class is contained in a scale.
173
354
  *
@@ -195,18 +376,28 @@ type ChordScaleMatch = {
195
376
  * conventional chord-scale relationship. Every entry of {@link NAMED_SCALES}
196
377
  * whose pitch-class set is a superset of the chord's is returned once per
197
378
  * distinct pitch-class set (aliased masks such as major/ionian report only the
198
- * modal name), ranked by fewest extra scale tones beyond the chord and then by
199
- * conventional
200
- * preference. For bare triads and smaller chords, heptatonic scales rank before
201
- * pentatonics and other sizes: a pentatonic adds no modal color over a triad,
202
- * so the seven-note modes are the more useful answer. The chromatic scale is
203
- * only returned as a fallback when no other scale contains the chord.
204
- *
205
- * The ranking is by fit, so the first entry is the tightest-fitting scale
206
- * rather than the idiomatic choice: a four-note chord that a pentatonic covers
207
- * exactly puts that pentatonic ahead of the mode a player would name. Read the
208
- * whole list, or pick by name, when the idiomatic scale is what is wanted;
209
- * {@link scalesForChanges} makes that choice for a progression.
379
+ * modal name). The chromatic scale is only returned as a fallback when no other
380
+ * scale contains the chord.
381
+ *
382
+ * The ranking applies these keys in order:
383
+ *
384
+ * 1. The idiomatic scales for the chord quality, in the order they are named
385
+ * there, ahead of every scale that is not one of them.
386
+ * 2. For bare triads and smaller chords, heptatonic scales ahead of pentatonics
387
+ * and other sizes: a pentatonic adds no modal color over a triad, so the
388
+ * seven-note modes are the more useful answer.
389
+ * 3. Fewest extra scale tones beyond the chord.
390
+ * 4. Conventional modal preference.
391
+ * 5. Fewest avoid notes, which separates the symmetric and melodic-minor
392
+ * scales the modal preference does not name.
393
+ * 6. Alphabetical order, so the list is stable.
394
+ *
395
+ * The idiomatic key comes first, so the head of the list is the scale a player
396
+ * would name rather than the tightest fit: over `Cm7b5` the locrian mode leads
397
+ * even though the blues scale adds fewer tones, because locrian is what a
398
+ * half-diminished chord is read as. Read further down the list, or pick by name,
399
+ * when the closest fit is what is wanted; {@link scalesForChanges} makes the
400
+ * choice for a whole progression.
210
401
  *
211
402
  * @param chord The chord to fit scales over, as a chord symbol, chord data, or
212
403
  * a `Chord`.
@@ -256,7 +447,9 @@ type AvoidNotesOptions = {
256
447
  *
257
448
  * @param chord The chord providing the chord tones, as a chord symbol, chord
258
449
  * data, or a `Chord`.
259
- * @param scaleName A key of {@link NAMED_SCALES}.
450
+ * @param scaleName A key of {@link NAMED_SCALES}, or an alias of one. A world
451
+ * scale is not one: chord-scale theory is a Western practice, so a raga named
452
+ * here is rejected rather than answered with a number.
260
453
  * @param opts Set `use: 'melodic'` to judge a line rather than a voicing.
261
454
  * @returns The avoid-note pitch classes, sorted ascending in [0, 11].
262
455
  * @throws If `scaleName` is not a built-in scale. An empty result already
@@ -301,7 +494,8 @@ type AvailableTensionsOptions = {
301
494
  *
302
495
  * @param chord The chord providing the chord tones, as a chord symbol, chord
303
496
  * data, or a `Chord`.
304
- * @param scaleName A key of {@link NAMED_SCALES}.
497
+ * @param scaleName A key of {@link NAMED_SCALES}, or an alias of one; a world
498
+ * scale is outside chord-scale theory, as in {@link avoidNotes}.
305
499
  * @param opts Set `resolvesTo` to the chord this one resolves to.
306
500
  * @returns The available-tension pitch classes, sorted ascending in [0, 11].
307
501
  * @throws If `scaleName` is not a built-in scale, as {@link avoidNotes} does.
@@ -551,14 +745,22 @@ type VoicingOptions = {
551
745
  /**
552
746
  * The prevailing key, as a key name, a key/scale, or a `Key`. Supplying it
553
747
  * enables the rules that only make sense relative to a tonic: the leading
554
- * tone is neither doubled nor left unresolved. Without it, voicings are
555
- * chosen from chord structure and voice-leading distance alone.
748
+ * tone is not doubled, and — where the chord being left is known as well —
749
+ * it is not left unresolved. Without it, voicings are chosen from chord
750
+ * structure and voice-leading distance alone.
556
751
  */
557
752
  key?: KeyLike;
558
753
  /**
559
- * The chord that produced the current voicing passed to {@link nextVoicing},
560
- * as a chord symbol, chord data, or a `Chord`. When supplied, chordal-seventh
561
- * resolution is scored exactly as it is by {@link voiceProgression}.
754
+ * The chord the current voicing was written on, as a chord symbol, chord
755
+ * data, or a `Chord`.
756
+ *
757
+ * It enables every rule that is read from the chord being left: the
758
+ * resolution of a chordal seventh, the resolution of a leading tone, and the
759
+ * cross relation between the two chords. All three are scored exactly as
760
+ * {@link voiceProgression} scores them, and none of them is scored without
761
+ * it — a leading tone cannot be told from the third of a chord that merely
762
+ * contains it until the chord it belongs to is known. Supply it whenever the
763
+ * caller has the chord, not only where that chord carried a seventh.
562
764
  */
563
765
  previousChord?: ChordLike;
564
766
  };
@@ -587,8 +789,9 @@ declare function voiceChord(chord: ChordLike, opts?: VoicingOptions): number[];
587
789
  * Voice a chord progression with smooth, bounded SATB-style leading.
588
790
  *
589
791
  * Each chord is chosen from a deterministic candidate set, minimizing motion
590
- * while penalizing counterpoint violations. A supplied key additionally
591
- * resolves leading tones and chordal sevenths.
792
+ * while penalizing counterpoint violations, and weighing the violations the
793
+ * move onto the following chord would then be forced into. A supplied key
794
+ * additionally resolves leading tones and chordal sevenths.
592
795
  *
593
796
  * @param chords The chords to voice in order.
594
797
  * @param opts Voicing options; defaults to four voices in {@link SATB_RANGES}.
@@ -604,12 +807,21 @@ declare function voiceProgression(chords: readonly ChordLike[], opts?: VoicingOp
604
807
  *
605
808
  * - `close`: the plain close-position tertian stack.
606
809
  * - `drop2`: the second voice from the top dropped an octave (drop-2 voicing).
810
+ * It takes at least three voices, since the voice it names has to have
811
+ * another below it for the drop to open the stack at all.
607
812
  * - `drop3`: the third voice from the top dropped an octave (drop-3 voicing).
813
+ * It takes at least four voices, for the same reason.
608
814
  * - `shell`: root plus guide tones (third and seventh) for seventh chords, or
609
815
  * root/third/fifth for triads; the fifth and tensions are omitted.
610
816
  * - `rootless`: the root omitted, keeping third/fifth/seventh and tensions
611
817
  * (a typical left-hand jazz voicing).
612
818
  *
819
+ * A chord with too few voices for the drop it asks for is voiced in close
820
+ * position instead: a three-note `drop3` is the close stack, not a stack with
821
+ * its bottom voice pushed an octave down. A slash bass the chord does not
822
+ * contain sounds under the stack rather than in it, and is not one of the
823
+ * voices counted here.
824
+ *
613
825
  * @category Voicing & Counterpoint
614
826
  */
615
827
  type VoicingStyle = 'close' | 'drop2' | 'drop3' | 'shell' | 'rootless';
@@ -653,23 +865,32 @@ type StyledVoicingOptions = {
653
865
  * {@link VoicingStyle} then transforms the stack, and the result is returned as
654
866
  * ascending MIDI pitches (index 0 = lowest).
655
867
  *
868
+ * A drop voicing lowers one voice below the rest, so that voice is its bass —
869
+ * which is what tells the drop-2 voicings of one chord apart. When the chord
870
+ * names a bass tone of its own, the close stack is therefore rotated so the
871
+ * style drops that tone, and the result is the drop voicing whose bass is the
872
+ * tone asked for; the named bass is not lowered under an already dropped voice
873
+ * afterwards, which would leave a hole wider than an octave in the middle. A
874
+ * bass the chord does not contain is no voice of the stack and cannot be the
875
+ * dropped one, so it keeps the bottom and the drop happens above it.
876
+ *
656
877
  * Every returned pitch is a valid MIDI number: an octave whose stack would run
657
878
  * off either end of the 0..127 range is rejected rather than voiced out of
658
879
  * range, matching {@link nextVoicing}, which clamps its derived ranges.
659
880
  *
660
- * @param chord The chord to voice.
881
+ * @param given The chord to voice, in whatever form it is held: a chord symbol,
882
+ * plain chord data, or a `Chord`.
661
883
  * @param opts Styled voicing options; defaults to a close voicing at octave 4.
662
884
  * @returns MIDI pitches, ascending, one per retained voice.
663
885
  * @throws If the voicing would not fit inside MIDI 0..127 at the given octave.
664
886
  * @example
665
887
  * ```ts
666
- * import { parseChordSymbol, voiceChordStyled } from '@libraz/libcantus';
667
- * const chord = parseChordSymbol('Dm7');
668
- * voiceChordStyled(chord, { style: 'drop2' }); // ascending MIDI pitches, drop-2 voicing
888
+ * import { voiceChordStyled } from '@libraz/libcantus';
889
+ * voiceChordStyled('Dm7', { style: 'drop2' }); // ascending MIDI pitches, drop-2 voicing
669
890
  * ```
670
891
  * @category Voicing & Counterpoint
671
892
  */
672
- declare function voiceChordStyled(chord: Chord, opts?: StyledVoicingOptions): number[];
893
+ declare function voiceChordStyled(given: ChordLike, opts?: StyledVoicingOptions): number[];
673
894
 
674
895
  /**
675
896
  * Species counterpoint: mark a two-voice exercise against the sixteenth-century
@@ -727,8 +948,12 @@ type SpeciesOptions = {
727
948
  * Judged are the vertical intervals under each species' dissonance licence
728
949
  * (none in the first, a passing dissonance on the weak half in the second and
729
950
  * third, a prepared suspension on the downbeat in the fourth, both in the
730
- * fifth; the third and fifth species also write the *nota cambiata* and the
731
- * double neighbour, which quit a dissonance by leap), parallel and hidden
951
+ * fifth; the neighbour that turns back on its own note belongs to the
952
+ * quarter-note line of the third and fifth species, which also write the *nota
953
+ * cambiata* and the double neighbour, quitting a dissonance by leap). A note
954
+ * still sounding when the next cantus-firmus note is struck is judged against
955
+ * that note too, so a ligature carried across the bar line is read where it
956
+ * lands as well as where it began. Judged besides are parallel and hidden
732
957
  * perfects and the *battuta* between the voices, augmented and otherwise
733
958
  * forbidden leaps along the counterpoint, the shape of the counterpoint as a
734
959
  * line, and the opening and closing formulas. Violations name the cantus firmus
@@ -737,7 +962,7 @@ type SpeciesOptions = {
737
962
  * @param cantusFirmus The given voice, one spelled note per measure.
738
963
  * @param counterpoint The written voice, in spelled notes.
739
964
  * @param species Which species the exercise is written in.
740
- * @param mode The mode the exercise is in.
965
+ * @param modeLike The mode the exercise is in.
741
966
  * @param opts Note lengths, and which side the counterpoint is written on.
742
967
  * @returns Every violation found, in the order the exercise commits them; an
743
968
  * empty array for a clean exercise.
@@ -752,7 +977,7 @@ type SpeciesOptions = {
752
977
  * ```
753
978
  * @category Voicing & Counterpoint
754
979
  */
755
- declare function checkSpecies(cantusFirmus: readonly Note[], counterpoint: readonly Note[], species: Species, mode: KeyScale, opts?: SpeciesOptions): PartWritingViolation[];
980
+ declare function checkSpecies(cantusFirmus: readonly Note[], counterpoint: readonly Note[], species: Species, modeLike: KeyLike, opts?: SpeciesOptions): PartWritingViolation[];
756
981
 
757
982
  /**
758
983
  * Part writing: grade a finished exercise against the classical four-part rules.
@@ -774,7 +999,10 @@ declare function checkSpecies(cantusFirmus: readonly Note[], counterpoint: reado
774
999
  * kind between one pair of voices. A parallel unison is reported as a
775
1000
  * `parallelOctave`, since it is the same perfect class.
776
1001
  * - `hiddenPerfect`: the outer voices reach a perfect fifth or octave by similar
777
- * motion with a leap in the upper voice.
1002
+ * motion with a leap in the upper voice. The leap is what exposes it in a
1003
+ * four-part texture; in a two-voice species exercise nothing covers the
1004
+ * arrival, so similar motion into a perfect interval is reported however the
1005
+ * upper voice got there.
778
1006
  * - `crossRelation`: one letter carries two different accidentals in two
779
1007
  * different voices across a chord change, exposed — neither note led into by
780
1008
  * step, at least one of them in an outer voice, and neither chord one of the
@@ -787,8 +1015,11 @@ declare function checkSpecies(cantusFirmus: readonly Note[], counterpoint: reado
787
1015
  * The rest are raised by {@link checkSpecies} alone, since they describe faults
788
1016
  * only a species exercise can commit:
789
1017
  *
790
- * - `wrongRhythmicRatio`: the counterpoint does not present the number of notes
791
- * per cantus-firmus note its species requires.
1018
+ * - `wrongRhythmicRatio`: the counterpoint's rhythm does not read against the
1019
+ * cantus firmus as its species requires — the wrong number of notes per
1020
+ * cantus-firmus note, and, in the fifth species, note values the style does
1021
+ * not write or a `durations` array that does not describe the counterpoint it
1022
+ * was given.
792
1023
  * - `unpreparedDissonance`: a dissonance falls where the species allows none, or
793
1024
  * is reached or left by leap where it must be passed through by step.
794
1025
  * - `unresolvedSuspension`: a fourth-species suspension that does not fall by
@@ -835,8 +1066,9 @@ type PartWritingViolation = {
835
1066
  rationale: string;
836
1067
  };
837
1068
  /**
838
- * A chord realized as one spelled note per voice, ascending (index 0 = lowest),
839
- * matching the voice order {@link voiceChord} and {@link SATB_RANGES} use.
1069
+ * A chord realized as one spelled note per voice, in voice order (index 0 =
1070
+ * bass), matching the order {@link voiceChord} and {@link SATB_RANGES} use.
1071
+ * Pitches need not ascend; a crossing is a reportable violation.
840
1072
  *
841
1073
  * Every note must carry an octave: the rules measure real distances between
842
1074
  * sounding pitches, which a bare pitch class does not have.
@@ -872,11 +1104,14 @@ type PartWritingOptions = {
872
1104
  * {@link checkPartWriting}.
873
1105
  *
874
1106
  * Each pitch is named against the chord sounding under it and then the key, so a
875
- * chord tone takes the letter its interval above the root implies: the third of
876
- * a D major chord in C major spells F#, not Gb. The octave is kept, since the
1107
+ * chord tone takes the letter the degree it plays in that chord implies: the
1108
+ * third of a D major chord in C major spells F#, not Gb. The chord is passed
1109
+ * whole rather than by its root, so a chord carrying its own spelling names its
1110
+ * tones here exactly as {@link spellChord} names them — the German sixth keeps
1111
+ * the F# that resolves outward to the dominant. The octave is kept, since the
877
1112
  * rules measure real distances.
878
1113
  *
879
- * @param voicing MIDI pitches, ascending (index 0 = lowest).
1114
+ * @param voicing MIDI pitches in voice order (index 0 = bass).
880
1115
  * @param chord The chord sounding, supplying the enharmonic evidence.
881
1116
  * @param key The key the exercise is written in.
882
1117
  * @returns One spelled note per pitch, in the same order.
@@ -888,13 +1123,14 @@ type PartWritingOptions = {
888
1123
  * ```
889
1124
  * @category Voicing & Counterpoint
890
1125
  */
891
- declare function spellVoicing(voicing: readonly number[], chord: Chord, key: KeyScale): SpelledVoicing;
1126
+ declare function spellVoicing(voicing: readonly number[], chord: Chord, key: SpelledKeyLike): SpelledVoicing;
892
1127
  /**
893
1128
  * Check a finished part-writing exercise and report every rule it breaks.
894
1129
  *
895
- * The voicings are given one per chord, each ascending with one spelled note per
896
- * voice (index 0 = lowest, the bass), the voice order {@link voiceChord} and
897
- * {@link SATB_RANGES} already use. Notes must carry octaves.
1130
+ * The voicings are given one per chord, each with one spelled note per voice in
1131
+ * voice order (index 0 = bass), the order {@link voiceChord} and
1132
+ * {@link SATB_RANGES} already use. Notes must carry octaves. A crossing is
1133
+ * reported rather than rejected.
898
1134
  *
899
1135
  * Each chord is checked for voice crossing, over-wide spacing between adjacent
900
1136
  * upper voices, and voices outside their range; each pair of consecutive chords
@@ -902,9 +1138,9 @@ declare function spellVoicing(voicing: readonly number[], chord: Chord, key: Key
902
1138
  * melodic intervals, and unresolved tendency tones. Violations come back in
903
1139
  * musical order: the rules inside a chord, then the rules taking it to the next.
904
1140
  *
905
- * @param voicings One voicing per chord, ascending, in spelled notes.
1141
+ * @param voicings One voicing per chord, in voice order, in spelled notes.
906
1142
  * @param chords The chords those voicings realize, in the same order.
907
- * @param key The key the exercise is written in; it names the leading tone.
1143
+ * @param keyLike The key the exercise is written in; it names the leading tone.
908
1144
  * @param opts Ranges and the upper-voice spacing limit. Both are validated
909
1145
  * before any rule runs: an empty result has to mean that nothing was broken,
910
1146
  * never that a rule could not be evaluated.
@@ -927,7 +1163,7 @@ declare function spellVoicing(voicing: readonly number[], chord: Chord, key: Key
927
1163
  * ```
928
1164
  * @category Voicing & Counterpoint
929
1165
  */
930
- declare function checkPartWriting(voicings: readonly SpelledVoicing[], chords: readonly Chord[], key: KeyScale, opts?: PartWritingOptions): PartWritingViolation[];
1166
+ declare function checkPartWriting(voicings: readonly SpelledVoicing[], chords: readonly Chord[], keyLike: KeyLike, opts?: PartWritingOptions): PartWritingViolation[];
931
1167
 
932
1168
  /**
933
1169
  * Transposing instruments: the fixed interval between the pitch a player reads
@@ -1032,7 +1268,8 @@ type TransposingInstrument = TransposingInstrumentName | (string & {}) | Exclude
1032
1268
  * import { instrumentTransposition } from '@libraz/libcantus';
1033
1269
  * instrumentTransposition('clarinetA');
1034
1270
  * // { number: 3, quality: 'm', semitones: -3, descending: true }
1035
- * instrumentTransposition('piccolo'); // { number: 8, quality: 'P', semitones: 12 }
1271
+ * instrumentTransposition('piccolo');
1272
+ * // { number: 8, quality: 'P', semitones: 12, descending: false }
1036
1273
  * ```
1037
1274
  * @category Pitch & Intervals
1038
1275
  */
@@ -1092,4 +1329,4 @@ declare function toSoundingPitch(note: NoteLike, instrument: TransposingInstrume
1092
1329
  */
1093
1330
  declare function toWrittenPitch(note: NoteLike, instrument: TransposingInstrument): Note;
1094
1331
 
1095
- export { type AvailableTensionsOptions as A, keySignatureFifths as B, type ChordScaleMatch as C, scaleMatchesChord as D, scaleSystemOf as E, scalesForChanges as F, spellVoicing as G, supportsFunctionalHarmony as H, toSoundingPitch as I, toWrittenPitch as J, type KeyMode as K, voiceChord as L, voiceChordStyled as M, voiceIndependence as N, voiceProgression as O, type PartWritingOptions as P, SATB_RANGES as S, TRANSPOSING_INSTRUMENTS as T, type VoiceIndependenceOptions as V, type AvoidNoteUse as a, type AvoidNotesOptions as b, type ChordScaleReportEntry as c, type PartWritingViolation as d, type PartWritingViolationKind as e, SCALE_SYSTEMS as f, type ScaleChoice as g, type ScaleSystem as h, type Species as i, type SpeciesOptions as j, type SpelledVoicing as k, type StyledVoicingOptions as l, type TransposingInstrument as m, type TransposingInstrumentName as n, type VoiceIndependenceReport as o, type VoiceRange as p, type VoicingOptions as q, type VoicingStyle as r, availableTensions as s, avoidNotes as t, checkPartWriting as u, checkSpecies as v, chordScaleReport as w, chordScales as x, instrumentTransposition as y, keyFromFifths as z };
1332
+ export { type AvailableTensionsOptions as A, instrumentTransposition as B, type ChordScaleMatch as C, isSignatureKey as D, keyFromFifths as E, keySignatureFifths as F, parseChordSymbol as G, scaleMatchesChord as H, scaleSystemOf as I, scalesForChanges as J, type KeyMode as K, spellVoicing as L, supportsFunctionalHarmony as M, toSoundingPitch as N, toWrittenPitch as O, type PartWritingOptions as P, transposeChordSymbol as Q, tryParseChordSymbol as R, SATB_RANGES as S, TRANSPOSING_INSTRUMENTS as T, voiceChord as U, type VoiceIndependenceOptions as V, voiceChordStyled as W, voiceIndependence as X, voiceProgression as Y, type AvoidNoteUse as a, type AvoidNotesOptions as b, type ChordScaleReportEntry as c, type ChordSymbolOptions as d, type PartWritingViolation as e, type PartWritingViolationKind as f, SCALE_SYSTEMS as g, type ScaleChoice as h, type ScaleSystem as i, type Species as j, type SpeciesOptions as k, type SpelledVoicing as l, type StyledVoicingOptions as m, type TransposingInstrument as n, type TransposingInstrumentName as o, type VoiceIndependenceReport as p, type VoiceRange as q, type VoicingOptions as r, type VoicingStyle as s, availableTensions as t, avoidNotes as u, checkPartWriting as v, checkSpecies as w, chordScaleReport as x, chordScales as y, formatChordSymbol as z };