@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,164 +1,99 @@
1
- import { h as NoteLike, f as Note, g as NoteEvent } from '../index-B9MNZboQ.cjs';
2
- export { a as Articulation, b as IntervalQualityLabel, d as KeyScale, S as SpelledInterval } from '../index-B9MNZboQ.cjs';
3
- export { M as MeterChange, b as MeterLike, c as MeterMap, T as TimeSignature } from '../index-BkGmlyI3.cjs';
4
- import { K as KeyLike, b as Chord, c as ChordLike } from '../index-C_8o--VE.cjs';
5
- export { d as ChordQuality, e as ChordSegment, g as ChordSpan, j as ChordToneRole, k as KeyRelation, N as NoteSafety, l as PitchSpelling, S as SafetyProfile, V as VoiceSnapshot } from '../index-C_8o--VE.cjs';
6
- export { r as ScaleName } from '../masks-DYbE485J.cjs';
7
- export { A as ArrangementAnalysis, a as ArrangementOptions, b as ArrangementSession, c as ArrangementTrack, C as ChordMatch, d as Conflict, e as ContourDirection, D as DetectChordOptions, f as DetectKeyOptions, E as ExtractMotifsOptions, F as FormSection, g as FormSectionOptions, H as Hypermeter, h as HypermeterOptions, K as KeyMatch, i as KeyVariant, M as MODAL_SCALE_NAMES, j as MelodicComparison, k as MelodicContour, l as MelodicContourShape, m as MelodicPhrase, n as ModalCandidate, o as ModalScaleName, p as MotifData, q as MotifOccurrence, r as MotifRelation, s as MotifRelationKind, P as Phrase, t as PhraseOptions, u as PhraseSignal, R as ReduceProgressionOptions, v as ReducedChord, w as ReductionBasis, x as ReductionLevel, S as StructuralCadence, T as TensionPoint, y as TrackAnalysis, z as TrackEdit, B as TrackRole, G as analyzeArrangement, I as compareMelodies, J as createArrangementSession, L as detectChord, N as detectChordBest, O as detectKey, Q as detectKeyBest, U as detectKeyFromNotes, V as extractMotifs, W as hypermeter, X as melodicContour, Y as melodicSimilarity, Z as motifFromNotes, _ as phrasesFromTimeline, $ as reduceProgression, a0 as relateMotifs, a1 as sectionsFromNotes, a2 as structuralCadences, a3 as tensionCurve, a4 as tensionCurveFrom } from '../index-BO6xE9YU.cjs';
8
- import { e as ChordTimeline } from '../index-Dzr13q3d.cjs';
9
- export { A as AnalyzeChordOptions, a as AnalyzedNote, B as BorrowedSource, C as CadenceHit, b as CadenceResult, c as ChordAnalysis, d as ChordSegmentation, f as ChordTimelineOptions, g as ChordTimelineResult, h as ChordToRomanOptions, D as DetectCadenceOptions, E as ExplainRomanOptions, H as HarmonicFunction, I as IdentifiedVoiceNote, K as KeyContext, i as KeyProfileName, j as KeyProfilePair, k as KeyRegion, l as KeyTimelineOptions, P as PivotChord, R as RejectedCandidate, m as RomanExplanation, S as SuspensionFigure, T as TheoryLabel, V as VoiceNote, n as analyzeChord, o as analyzeVoice, p as borrowedSource, q as chordTimelineFromChords, r as chordTimelineFromNotes, s as chordToRoman, t as detectCadence, u as detectCadences, v as detectModulations, w as explainRoman, x as functionOf, y as isBorrowedChord, z as isDiatonic, F as isMinorKey, G as keyTimelineFromNotes, J as pivotChords, L as prevailingKeyOf, M as romanToChord, N as secondaryDominant, O as secondaryDominantOf, Q as toVoiceNotes } from '../index-Dzr13q3d.cjs';
1
+ import { i as NoteLike, h as NoteEvent, g as Note } from '../index-Cy15oTvh.cjs';
2
+ export { a as Articulation, I as IntervalData, c as IntervalQualityLabel, e as KeyScale, S as SpelledInterval } from '../index-Cy15oTvh.cjs';
3
+ export { M as MeterChange, b as MeterLike, c as MeterMap, T as TimeSignature } from '../index-BMweUlm5.cjs';
4
+ import { r as SpelledKeyLike } from '../coerce-DRERzdve.cjs';
5
+ export { b as ChordData, c as ChordLike, d as ChordQuality, e as ChordSegment, g as ChordSpan, i as ChordToneRole, K as KeyLike, j as KeyRelation, k as KeyVariant, N as NoteSafety, l as PitchSpelling, n as ResolvedKey, o as SafetyProfile, s as SpelledKeyScale, V as VoiceSnapshot } from '../coerce-DRERzdve.cjs';
6
+ export { r as ScaleName } from '../masks-pADfTOiD.cjs';
7
+ import { e as ChordTimeline } from '../index-BBWNZS0f.cjs';
8
+ export { A as AnalyzeChordOptions, a as AnalyzedNote, B as BorrowedSource, C as CadenceHit, b as CadenceResult, c as ChordAnalysis, d as ChordSegmentation, f as ChordTimelineOptions, g as ChordTimelineResult, h as ChordToRomanOptions, D as DetectCadenceOptions, E as ExplainRomanOptions, H as HarmonicFunction, I as IdentifiedVoiceNote, K as KeyContext, i as KeyProfileName, j as KeyProfilePair, k as KeyRegion, l as KeyTimelineOptions, P as PivotChord, R as RejectedCandidate, m as RomanExplanation, S as SuspensionFigure, T as TheoryLabel, V as VoiceNote, n as analyzeChord, o as analyzeVoice, p as assertChordTimeline, q as borrowedSource, r as chordTimelineFromChords, s as chordTimelineFromNotes, t as chordToRoman, u as detectCadence, v as detectCadences, w as detectModulations, x as explainRoman, y as functionOf, z as isBorrowedChord, F as isDiatonic, G as isMinorKey, J as keyTimelineFromNotes, L as pivotChords, M as prevailingKeyOf, N as romanToChord, O as secondaryDominant, Q as secondaryDominantOf, U as toVoiceNotes } from '../index-BBWNZS0f.cjs';
9
+ import { m as MelodicPhrase } from '../index-DGCNKAUr.cjs';
10
+ export { A as ArrangementAnalysis, a as ArrangementOptions, b as ArrangementSession, c as ArrangementTrack, d as AugmentedSixthKind, C as ChordMatch, e as Conflict, f as ConflictPartner, g as ContourDirection, D as DetectChordOptions, h as DetectKeyOptions, E as ExtractMotifsOptions, F as FormSection, i as FormSectionOptions, H as Hypermeter, j as HypermeterOptions, K as KeyMatch, M as MODAL_SCALE_NAMES, k as MelodicContour, l as MelodicContourShape, n as ModalCandidate, o as ModalScaleName, p as MotifData, q as MotifOccurrence, r as MotifRelation, s as MotifRelationKind, P as Phrase, t as PhraseOptions, u as PhraseSignal, R as ReduceProgressionOptions, v as ReducedChord, w as ReductionBasis, x as ReductionLevel, S as StructuralCadence, T as TensionPoint, y as TrackAnalysis, z as TrackEdit, B as TrackRole, G as analyzeArrangement, I as analyzePolyphony, J as augmentedSixthChord, L as augmentedSixthFromPitchClasses, N as augmentedSixthKind, O as createArrangementSession, Q as detectChord, U as detectChordBest, V as detectKey, W as detectKeyBest, X as detectKeyFromNotes, Y as extractMotifs, Z as hypermeter, _ as melodicContour, $ as motifFromNotes, a0 as phrasesFromTimeline, a1 as reduceProgression, a2 as relateMotifs, a3 as sectionsFromNotes, a4 as spellAugmentedSixth, a5 as structuralCadences, a6 as tensionCurve, a7 as tensionCurveFrom } from '../index-DGCNKAUr.cjs';
10
11
 
11
12
  /**
12
- * Augmented-sixth chords: the Italian, French, and German sixths.
13
+ * How alike two phrases are, when they stand in no named relation.
13
14
  *
14
- * All three stand on the lowered submediant (b6) in the bass and carry an
15
- * augmented sixth above it, and all three are predominants whose two outer
16
- * voices resolve outward onto the dominant. The family is defined by that bass
17
- * and that interval rather than by a stack of thirds, so a chord is recognized
18
- * here from the tones sounding over that bass rather than through the
19
- * Roman-numeral degree tables.
20
- *
21
- * The interval is spelled, so recognition reads letters and not only pitch
22
- * classes: over an Ab bass the augmented sixth is F# and the minor seventh of
23
- * the bVI7 it otherwise sounds exactly like is Gb. A caller holding pitch
24
- * classes alone — an analysis of a MIDI track, which names no accidentals —
25
- * makes that reading with {@link augmentedSixthFromPitchClasses}, and the chord
26
- * it hands back carries the spelling that decided it.
15
+ * A device the repertoire names is an account of how one phrase was made from
16
+ * another; a similarity score is what is left to say when there is no such
17
+ * account — that the two are near, and how near. The reading is an edit
18
+ * distance over the intervals and over the onset gaps, so a phrase answered by
19
+ * a slightly ornamented version of itself still reads as close.
27
20
  */
28
21
 
29
22
  /**
30
- * The three augmented-sixth chords, under the nationalities convention gives
31
- * them.
32
- *
33
- * Over an Ab bass in C: the Italian sixth is Ab C F#, the French sixth adds the
34
- * supertonic (Ab C D F#), and the German sixth adds the lowered mediant
35
- * (Ab C Eb F#).
36
- *
37
- * @category Functional Harmony
38
- */
39
- type AugmentedSixthKind = 'italian' | 'french' | 'german';
40
- /**
41
- * Build an augmented-sixth chord in a key.
42
- *
43
- * The chord always carries an explicit `bassPc` on the lowered submediant,
44
- * which is what makes it an augmented sixth rather than the dominant seventh or
45
- * the altered supertonic seventh it shares pitch classes with, and an explicit
46
- * interval template naming exactly the tones that sound.
47
- *
48
- * It also carries its spelling: the tones as `toneSpellings`, and the root and
49
- * bass as the usual hints. Those are what let the ordinary chord speller and
50
- * the symbol formatter name the chord — `Ab C Eb F#` and `Ab7` for the German
51
- * sixth of C major — since a stack of thirds over that root would put a Gb
52
- * where the augmented sixth belongs. The spelling is the one the key is written
53
- * on, so a flat-side key takes the double flats it genuinely needs.
54
- *
55
- * The lowered submediant is taken as eight semitones above the tonic in every
56
- * mode, since the chord is a chromatic alteration rather than a degree of the
57
- * prevailing scale.
58
- *
59
- * @param kind Which of the three augmented sixths to build.
60
- * @param key The prevailing key, as a key name, a key/scale, or a `Key`.
61
- * @returns The chord, with its bass on the lowered submediant.
62
- * @throws If `kind` is not one of the three, or the key's root is not finite.
63
- * @see {@link spellAugmentedSixth} to spell the family from a tonic without
64
- * building a chord at all.
65
- * @example
66
- * ```ts
67
- * import { augmentedSixthChord, majorKey } from '@libraz/libcantus';
68
- * augmentedSixthChord('german', majorKey(0));
69
- * // Ab C Eb F# in C: { rootPc: 8, quality: 'dom7', intervals: [0, 4, 7, 10], bassPc: 8, ... }
70
- * ```
71
- * @category Functional Harmony
72
- */
73
- declare function augmentedSixthChord(kind: AugmentedSixthKind, key: KeyLike): Chord;
74
- /**
75
- * Identify a chord as one of the augmented sixths, or null when it is none.
23
+ * How alike two lines are, and how the answer was reached.
76
24
  *
77
- * A chord qualifies when it sounds the lowered submediant of `key` in the bass,
78
- * its pitch classes are exactly one of the three sets built over that bass, and
79
- * its own letters spell the augmented sixth above it. All three are needed: the
80
- * same pitch classes over the same bass are an ordinary bVI7 when the tone ten
81
- * semitones above the bass is written as a minor seventh, and the letters are
82
- * the only place that distinction lives.
83
- *
84
- * A chord naming no `bassPc` sounds its root lowest, which is how the two
85
- * conventions for that field — the sounding bass always, or only a bass that
86
- * differs from the root — are read alike here.
87
- *
88
- * The root the chord is measured from is not consulted, so a chord voiced or
89
- * rebuilt around any of its own tones still identifies as long as it keeps its
90
- * spelling.
91
- *
92
- * @param chord The chord to test, as a chord symbol, chord data, or a `Chord`.
93
- * @param key The prevailing key, as a key name, a key/scale, or a `Key`.
94
- * @returns The kind of augmented sixth, or null.
95
- * @see {@link augmentedSixthFromPitchClasses} to make the reading from pitch
96
- * classes that carry no spelling at all.
97
- * @example
98
- * ```ts
99
- * import { augmentedSixthKind, majorKey, romanToChord } from '@libraz/libcantus';
100
- * augmentedSixthKind(romanToChord('Fr6', majorKey(0)), majorKey(0)); // 'french'
101
- * ```
102
- * @category Functional Harmony
25
+ * @category Arrangement & Analysis
103
26
  */
104
- declare function augmentedSixthKind(chord: ChordLike, key: KeyLike): AugmentedSixthKind | null;
27
+ type MelodicComparison = {
28
+ /** Overall likeness in [0, 1]; 1 for the same line, transposition included. */
29
+ similarity: number;
30
+ /** Likeness of the interval sequences alone, in [0, 1]. */
31
+ pitchSimilarity: number;
32
+ /** Likeness of the rhythmic profiles alone, in [0, 1]. */
33
+ rhythmSimilarity: number;
34
+ /** Why the lines scored what they did. */
35
+ rationale: string;
36
+ };
105
37
  /**
106
- * Read a set of sounding pitch classes over a sounding bass as an augmented
107
- * sixth, or null when they are none.
108
- *
109
- * The reading a caller holding no spelling has to make for itself: pitch
110
- * classes name no accidentals, so nothing downstream can tell the German sixth
111
- * from the bVI7 it sounds like once the letters are gone. The chord returned is
112
- * the one {@link augmentedSixthChord} builds, spelling and all, so it keeps
113
- * identifying as an augmented sixth everywhere it travels.
114
- *
115
- * Not every b6-1-b3-#4 over a b6 bass is an augmented sixth, and this cannot
116
- * know which one is: it answers what the tones would spell, and the caller
117
- * decides whether that reading is the one the music supports.
118
- *
119
- * @param pcs The sounding pitch classes; duplicates and unreduced values are
120
- * fine.
121
- * @param bassPc The pitch class sounding in the bass.
122
- * @param key The prevailing key, as a key name, a key/scale, or a `Key`.
123
- * @returns The augmented-sixth chord, or null.
124
- * @see {@link augmentedSixthKind} to read a chord that already carries its
125
- * spelling.
38
+ * Compare two lines and say why they scored what they did.
39
+ *
40
+ * The metric is a normalised edit distance over the interval sequence, weighted
41
+ * against the same over the rhythmic profile. Intervals rather than pitches,
42
+ * because the same tune in another key is the same tune; edit distance rather
43
+ * than a step-by-step correlation, because a variant that adds a passing note or
44
+ * drops one still has to line up with its model, and only an alignment-based
45
+ * measure can do that. Substituting one interval for another costs by how far
46
+ * apart they are rather than a flat step, so an answer that widens a third to a
47
+ * fourth stays close to its model while one that replaces it with a leap does
48
+ * not. The rhythm carries the smaller share: a melody is recognised mostly by
49
+ * its pitch shape, but a figure in a wholly different rhythm is a different
50
+ * figure.
51
+ *
52
+ * Both lines are expected to be monophonic, as {@link analyzeVoice} expects a
53
+ * voice to be. Notes struck together are read as one event, the highest of them
54
+ * standing for it, so a chord is reduced to its top voice rather than read as a
55
+ * line of its own.
56
+ *
57
+ * @param a The first line: a motif, or plain note events.
58
+ * @param b The second line.
59
+ * @returns The overall likeness, the two terms behind it, and a rationale.
126
60
  * @example
127
61
  * ```ts
128
- * import { augmentedSixthFromPitchClasses, majorKey } from '@libraz/libcantus';
129
- * // Ab C Eb Gb sounding over Ab in C: the German sixth, spelled with its F#.
130
- * augmentedSixthFromPitchClasses([8, 0, 3, 6], 8, majorKey(0))?.quality; // 'dom7'
62
+ * import { compareMelodies } from '@libraz/libcantus';
63
+ * const line = [
64
+ * { pitch: 60, startBeat: 0, durationBeat: 1 },
65
+ * { pitch: 62, startBeat: 1, durationBeat: 1 },
66
+ * { pitch: 64, startBeat: 2, durationBeat: 1 },
67
+ * ];
68
+ * compareMelodies(line, line).similarity; // 1
131
69
  * ```
132
- * @category Functional Harmony
70
+ * @category Arrangement & Analysis
133
71
  */
134
- declare function augmentedSixthFromPitchClasses(pcs: readonly number[], bassPc: number, key: KeyLike): Chord | null;
72
+ declare function compareMelodies(a: MelodicPhrase, b: MelodicPhrase): MelodicComparison;
135
73
  /**
136
- * Spell an augmented-sixth chord from a spelled tonic, lowest note first.
137
- *
138
- * This is the spelled counterpart of {@link augmentedSixthChord}, and the table
139
- * the chord's own spelling is built from: every tone is placed by a named
140
- * interval above the bass, so the outer interval is an augmented sixth in every
141
- * key rather than the minor seventh its ten semitones would otherwise imply.
142
- * Reach for it when a spelled tonic is all there is; spelling the chord itself
143
- * with {@link spellChord} names the same notes, in the chord's own order.
74
+ * How alike two lines are, in [0, 1].
144
75
  *
145
- * A tonic carrying an octave yields notes carrying octaves, ascending from the
146
- * bass; an octave-less tonic yields octave-less notes.
76
+ * The number {@link compareMelodies} reaches, for callers that only want to rank
77
+ * phrases: 1 for the same line — a transposition of it included, since the
78
+ * measure is built on intervals — and lower the further two lines are from being
79
+ * each other's variant. Symmetric in its arguments, and deterministic.
147
80
  *
148
- * @param kind Which of the three augmented sixths to spell.
149
- * @param tonic The spelled tonic of the key, as a note name, a MIDI number,
150
- * note data, or a `Note`.
151
- * @returns The spelled tones, bass first and ascending.
152
- * @throws If `kind` is not one of the three, or `tonic` is not a note.
81
+ * @param a The first line: a motif, or plain note events.
82
+ * @param b The second line.
83
+ * @returns The likeness in [0, 1].
153
84
  * @example
154
85
  * ```ts
155
- * import { noteNames, parseNote, spellAugmentedSixth } from '@libraz/libcantus';
156
- * noteNames(spellAugmentedSixth('german', parseNote('C'))); // ['Ab', 'C', 'Eb', 'F#']
157
- * noteNames(spellAugmentedSixth('italian', 'E')); // ['C', 'E', 'A#']
86
+ * import { melodicSimilarity } from '@libraz/libcantus';
87
+ * const line = [
88
+ * { pitch: 60, startBeat: 0, durationBeat: 1 },
89
+ * { pitch: 62, startBeat: 1, durationBeat: 1 },
90
+ * { pitch: 64, startBeat: 2, durationBeat: 1 },
91
+ * ];
92
+ * melodicSimilarity(line, line); // 1
158
93
  * ```
159
- * @category Functional Harmony
94
+ * @category Arrangement & Analysis
160
95
  */
161
- declare function spellAugmentedSixth(kind: AugmentedSixthKind, tonic: NoteLike): Note[];
96
+ declare function melodicSimilarity(a: MelodicPhrase, b: MelodicPhrase): number;
162
97
 
163
98
  /**
164
99
  * Line spelling: name every note of a melodic line in one pass.
@@ -187,7 +122,7 @@ type SpellLineOptions = {
187
122
  * Tonic spelling to anchor the key, for a caller that already knows how the
188
123
  * piece is written. It must sound the key's own root pitch class; anything
189
124
  * else is rejected rather than spelled. Defaults to the conventional
190
- * spelling `spelledKeyOf` gives the key. Accepted as a note name, a MIDI
125
+ * spelling the key itself is written with. Accepted as a note name, a MIDI
191
126
  * number, note data, or a `Note`.
192
127
  */
193
128
  tonic?: NoteLike;
@@ -253,6 +188,6 @@ type SpellLineOptions = {
253
188
  * ```
254
189
  * @category Arrangement & Analysis
255
190
  */
256
- declare function spellLine(notes: readonly NoteEvent[], timeline: ChordTimeline | null, key: KeyLike, opts?: SpellLineOptions): Note[];
191
+ declare function spellLine(notes: readonly NoteEvent[], timeline: ChordTimeline | null, key: SpelledKeyLike, opts?: SpellLineOptions): Note[];
257
192
 
258
- export { type AugmentedSixthKind, Chord as ChordData, ChordLike, ChordTimeline, KeyLike, Note as NoteData, NoteEvent, NoteLike, type SpellLineOptions, augmentedSixthChord, augmentedSixthFromPitchClasses, augmentedSixthKind, spellAugmentedSixth, spellLine };
193
+ export { ChordTimeline, type MelodicComparison, MelodicPhrase, Note as NoteData, NoteEvent, NoteLike, type SpellLineOptions, SpelledKeyLike, compareMelodies, melodicSimilarity, spellLine };
@@ -1,164 +1,99 @@
1
- import { h as NoteLike, f as Note, g as NoteEvent } from '../index-B9MNZboQ.js';
2
- export { a as Articulation, b as IntervalQualityLabel, d as KeyScale, S as SpelledInterval } from '../index-B9MNZboQ.js';
3
- export { M as MeterChange, b as MeterLike, c as MeterMap, T as TimeSignature } from '../index-Cj49F892.js';
4
- import { K as KeyLike, b as Chord, c as ChordLike } from '../index-szBv3496.js';
5
- export { d as ChordQuality, e as ChordSegment, g as ChordSpan, j as ChordToneRole, k as KeyRelation, N as NoteSafety, l as PitchSpelling, S as SafetyProfile, V as VoiceSnapshot } from '../index-szBv3496.js';
6
- export { r as ScaleName } from '../masks-DYbE485J.js';
7
- export { A as ArrangementAnalysis, a as ArrangementOptions, b as ArrangementSession, c as ArrangementTrack, C as ChordMatch, d as Conflict, e as ContourDirection, D as DetectChordOptions, f as DetectKeyOptions, E as ExtractMotifsOptions, F as FormSection, g as FormSectionOptions, H as Hypermeter, h as HypermeterOptions, K as KeyMatch, i as KeyVariant, M as MODAL_SCALE_NAMES, j as MelodicComparison, k as MelodicContour, l as MelodicContourShape, m as MelodicPhrase, n as ModalCandidate, o as ModalScaleName, p as MotifData, q as MotifOccurrence, r as MotifRelation, s as MotifRelationKind, P as Phrase, t as PhraseOptions, u as PhraseSignal, R as ReduceProgressionOptions, v as ReducedChord, w as ReductionBasis, x as ReductionLevel, S as StructuralCadence, T as TensionPoint, y as TrackAnalysis, z as TrackEdit, B as TrackRole, G as analyzeArrangement, I as compareMelodies, J as createArrangementSession, L as detectChord, N as detectChordBest, O as detectKey, Q as detectKeyBest, U as detectKeyFromNotes, V as extractMotifs, W as hypermeter, X as melodicContour, Y as melodicSimilarity, Z as motifFromNotes, _ as phrasesFromTimeline, $ as reduceProgression, a0 as relateMotifs, a1 as sectionsFromNotes, a2 as structuralCadences, a3 as tensionCurve, a4 as tensionCurveFrom } from '../index-D57QRbVn.js';
8
- import { e as ChordTimeline } from '../index-Chbst3Jx.js';
9
- export { A as AnalyzeChordOptions, a as AnalyzedNote, B as BorrowedSource, C as CadenceHit, b as CadenceResult, c as ChordAnalysis, d as ChordSegmentation, f as ChordTimelineOptions, g as ChordTimelineResult, h as ChordToRomanOptions, D as DetectCadenceOptions, E as ExplainRomanOptions, H as HarmonicFunction, I as IdentifiedVoiceNote, K as KeyContext, i as KeyProfileName, j as KeyProfilePair, k as KeyRegion, l as KeyTimelineOptions, P as PivotChord, R as RejectedCandidate, m as RomanExplanation, S as SuspensionFigure, T as TheoryLabel, V as VoiceNote, n as analyzeChord, o as analyzeVoice, p as borrowedSource, q as chordTimelineFromChords, r as chordTimelineFromNotes, s as chordToRoman, t as detectCadence, u as detectCadences, v as detectModulations, w as explainRoman, x as functionOf, y as isBorrowedChord, z as isDiatonic, F as isMinorKey, G as keyTimelineFromNotes, J as pivotChords, L as prevailingKeyOf, M as romanToChord, N as secondaryDominant, O as secondaryDominantOf, Q as toVoiceNotes } from '../index-Chbst3Jx.js';
1
+ import { i as NoteLike, h as NoteEvent, g as Note } from '../index-Cy15oTvh.js';
2
+ export { a as Articulation, I as IntervalData, c as IntervalQualityLabel, e as KeyScale, S as SpelledInterval } from '../index-Cy15oTvh.js';
3
+ export { M as MeterChange, b as MeterLike, c as MeterMap, T as TimeSignature } from '../index-CL4b4gUQ.js';
4
+ import { r as SpelledKeyLike } from '../coerce-DP0vYu-x.js';
5
+ export { b as ChordData, c as ChordLike, d as ChordQuality, e as ChordSegment, g as ChordSpan, i as ChordToneRole, K as KeyLike, j as KeyRelation, k as KeyVariant, N as NoteSafety, l as PitchSpelling, n as ResolvedKey, o as SafetyProfile, s as SpelledKeyScale, V as VoiceSnapshot } from '../coerce-DP0vYu-x.js';
6
+ export { r as ScaleName } from '../masks-Cc7-MzzY.js';
7
+ import { e as ChordTimeline } from '../index-CJBBiAmU.js';
8
+ export { A as AnalyzeChordOptions, a as AnalyzedNote, B as BorrowedSource, C as CadenceHit, b as CadenceResult, c as ChordAnalysis, d as ChordSegmentation, f as ChordTimelineOptions, g as ChordTimelineResult, h as ChordToRomanOptions, D as DetectCadenceOptions, E as ExplainRomanOptions, H as HarmonicFunction, I as IdentifiedVoiceNote, K as KeyContext, i as KeyProfileName, j as KeyProfilePair, k as KeyRegion, l as KeyTimelineOptions, P as PivotChord, R as RejectedCandidate, m as RomanExplanation, S as SuspensionFigure, T as TheoryLabel, V as VoiceNote, n as analyzeChord, o as analyzeVoice, p as assertChordTimeline, q as borrowedSource, r as chordTimelineFromChords, s as chordTimelineFromNotes, t as chordToRoman, u as detectCadence, v as detectCadences, w as detectModulations, x as explainRoman, y as functionOf, z as isBorrowedChord, F as isDiatonic, G as isMinorKey, J as keyTimelineFromNotes, L as pivotChords, M as prevailingKeyOf, N as romanToChord, O as secondaryDominant, Q as secondaryDominantOf, U as toVoiceNotes } from '../index-CJBBiAmU.js';
9
+ import { m as MelodicPhrase } from '../index-BRMbPkHE.js';
10
+ export { A as ArrangementAnalysis, a as ArrangementOptions, b as ArrangementSession, c as ArrangementTrack, d as AugmentedSixthKind, C as ChordMatch, e as Conflict, f as ConflictPartner, g as ContourDirection, D as DetectChordOptions, h as DetectKeyOptions, E as ExtractMotifsOptions, F as FormSection, i as FormSectionOptions, H as Hypermeter, j as HypermeterOptions, K as KeyMatch, M as MODAL_SCALE_NAMES, k as MelodicContour, l as MelodicContourShape, n as ModalCandidate, o as ModalScaleName, p as MotifData, q as MotifOccurrence, r as MotifRelation, s as MotifRelationKind, P as Phrase, t as PhraseOptions, u as PhraseSignal, R as ReduceProgressionOptions, v as ReducedChord, w as ReductionBasis, x as ReductionLevel, S as StructuralCadence, T as TensionPoint, y as TrackAnalysis, z as TrackEdit, B as TrackRole, G as analyzeArrangement, I as analyzePolyphony, J as augmentedSixthChord, L as augmentedSixthFromPitchClasses, N as augmentedSixthKind, O as createArrangementSession, Q as detectChord, U as detectChordBest, V as detectKey, W as detectKeyBest, X as detectKeyFromNotes, Y as extractMotifs, Z as hypermeter, _ as melodicContour, $ as motifFromNotes, a0 as phrasesFromTimeline, a1 as reduceProgression, a2 as relateMotifs, a3 as sectionsFromNotes, a4 as spellAugmentedSixth, a5 as structuralCadences, a6 as tensionCurve, a7 as tensionCurveFrom } from '../index-BRMbPkHE.js';
10
11
 
11
12
  /**
12
- * Augmented-sixth chords: the Italian, French, and German sixths.
13
+ * How alike two phrases are, when they stand in no named relation.
13
14
  *
14
- * All three stand on the lowered submediant (b6) in the bass and carry an
15
- * augmented sixth above it, and all three are predominants whose two outer
16
- * voices resolve outward onto the dominant. The family is defined by that bass
17
- * and that interval rather than by a stack of thirds, so a chord is recognized
18
- * here from the tones sounding over that bass rather than through the
19
- * Roman-numeral degree tables.
20
- *
21
- * The interval is spelled, so recognition reads letters and not only pitch
22
- * classes: over an Ab bass the augmented sixth is F# and the minor seventh of
23
- * the bVI7 it otherwise sounds exactly like is Gb. A caller holding pitch
24
- * classes alone — an analysis of a MIDI track, which names no accidentals —
25
- * makes that reading with {@link augmentedSixthFromPitchClasses}, and the chord
26
- * it hands back carries the spelling that decided it.
15
+ * A device the repertoire names is an account of how one phrase was made from
16
+ * another; a similarity score is what is left to say when there is no such
17
+ * account — that the two are near, and how near. The reading is an edit
18
+ * distance over the intervals and over the onset gaps, so a phrase answered by
19
+ * a slightly ornamented version of itself still reads as close.
27
20
  */
28
21
 
29
22
  /**
30
- * The three augmented-sixth chords, under the nationalities convention gives
31
- * them.
32
- *
33
- * Over an Ab bass in C: the Italian sixth is Ab C F#, the French sixth adds the
34
- * supertonic (Ab C D F#), and the German sixth adds the lowered mediant
35
- * (Ab C Eb F#).
36
- *
37
- * @category Functional Harmony
38
- */
39
- type AugmentedSixthKind = 'italian' | 'french' | 'german';
40
- /**
41
- * Build an augmented-sixth chord in a key.
42
- *
43
- * The chord always carries an explicit `bassPc` on the lowered submediant,
44
- * which is what makes it an augmented sixth rather than the dominant seventh or
45
- * the altered supertonic seventh it shares pitch classes with, and an explicit
46
- * interval template naming exactly the tones that sound.
47
- *
48
- * It also carries its spelling: the tones as `toneSpellings`, and the root and
49
- * bass as the usual hints. Those are what let the ordinary chord speller and
50
- * the symbol formatter name the chord — `Ab C Eb F#` and `Ab7` for the German
51
- * sixth of C major — since a stack of thirds over that root would put a Gb
52
- * where the augmented sixth belongs. The spelling is the one the key is written
53
- * on, so a flat-side key takes the double flats it genuinely needs.
54
- *
55
- * The lowered submediant is taken as eight semitones above the tonic in every
56
- * mode, since the chord is a chromatic alteration rather than a degree of the
57
- * prevailing scale.
58
- *
59
- * @param kind Which of the three augmented sixths to build.
60
- * @param key The prevailing key, as a key name, a key/scale, or a `Key`.
61
- * @returns The chord, with its bass on the lowered submediant.
62
- * @throws If `kind` is not one of the three, or the key's root is not finite.
63
- * @see {@link spellAugmentedSixth} to spell the family from a tonic without
64
- * building a chord at all.
65
- * @example
66
- * ```ts
67
- * import { augmentedSixthChord, majorKey } from '@libraz/libcantus';
68
- * augmentedSixthChord('german', majorKey(0));
69
- * // Ab C Eb F# in C: { rootPc: 8, quality: 'dom7', intervals: [0, 4, 7, 10], bassPc: 8, ... }
70
- * ```
71
- * @category Functional Harmony
72
- */
73
- declare function augmentedSixthChord(kind: AugmentedSixthKind, key: KeyLike): Chord;
74
- /**
75
- * Identify a chord as one of the augmented sixths, or null when it is none.
23
+ * How alike two lines are, and how the answer was reached.
76
24
  *
77
- * A chord qualifies when it sounds the lowered submediant of `key` in the bass,
78
- * its pitch classes are exactly one of the three sets built over that bass, and
79
- * its own letters spell the augmented sixth above it. All three are needed: the
80
- * same pitch classes over the same bass are an ordinary bVI7 when the tone ten
81
- * semitones above the bass is written as a minor seventh, and the letters are
82
- * the only place that distinction lives.
83
- *
84
- * A chord naming no `bassPc` sounds its root lowest, which is how the two
85
- * conventions for that field — the sounding bass always, or only a bass that
86
- * differs from the root — are read alike here.
87
- *
88
- * The root the chord is measured from is not consulted, so a chord voiced or
89
- * rebuilt around any of its own tones still identifies as long as it keeps its
90
- * spelling.
91
- *
92
- * @param chord The chord to test, as a chord symbol, chord data, or a `Chord`.
93
- * @param key The prevailing key, as a key name, a key/scale, or a `Key`.
94
- * @returns The kind of augmented sixth, or null.
95
- * @see {@link augmentedSixthFromPitchClasses} to make the reading from pitch
96
- * classes that carry no spelling at all.
97
- * @example
98
- * ```ts
99
- * import { augmentedSixthKind, majorKey, romanToChord } from '@libraz/libcantus';
100
- * augmentedSixthKind(romanToChord('Fr6', majorKey(0)), majorKey(0)); // 'french'
101
- * ```
102
- * @category Functional Harmony
25
+ * @category Arrangement & Analysis
103
26
  */
104
- declare function augmentedSixthKind(chord: ChordLike, key: KeyLike): AugmentedSixthKind | null;
27
+ type MelodicComparison = {
28
+ /** Overall likeness in [0, 1]; 1 for the same line, transposition included. */
29
+ similarity: number;
30
+ /** Likeness of the interval sequences alone, in [0, 1]. */
31
+ pitchSimilarity: number;
32
+ /** Likeness of the rhythmic profiles alone, in [0, 1]. */
33
+ rhythmSimilarity: number;
34
+ /** Why the lines scored what they did. */
35
+ rationale: string;
36
+ };
105
37
  /**
106
- * Read a set of sounding pitch classes over a sounding bass as an augmented
107
- * sixth, or null when they are none.
108
- *
109
- * The reading a caller holding no spelling has to make for itself: pitch
110
- * classes name no accidentals, so nothing downstream can tell the German sixth
111
- * from the bVI7 it sounds like once the letters are gone. The chord returned is
112
- * the one {@link augmentedSixthChord} builds, spelling and all, so it keeps
113
- * identifying as an augmented sixth everywhere it travels.
114
- *
115
- * Not every b6-1-b3-#4 over a b6 bass is an augmented sixth, and this cannot
116
- * know which one is: it answers what the tones would spell, and the caller
117
- * decides whether that reading is the one the music supports.
118
- *
119
- * @param pcs The sounding pitch classes; duplicates and unreduced values are
120
- * fine.
121
- * @param bassPc The pitch class sounding in the bass.
122
- * @param key The prevailing key, as a key name, a key/scale, or a `Key`.
123
- * @returns The augmented-sixth chord, or null.
124
- * @see {@link augmentedSixthKind} to read a chord that already carries its
125
- * spelling.
38
+ * Compare two lines and say why they scored what they did.
39
+ *
40
+ * The metric is a normalised edit distance over the interval sequence, weighted
41
+ * against the same over the rhythmic profile. Intervals rather than pitches,
42
+ * because the same tune in another key is the same tune; edit distance rather
43
+ * than a step-by-step correlation, because a variant that adds a passing note or
44
+ * drops one still has to line up with its model, and only an alignment-based
45
+ * measure can do that. Substituting one interval for another costs by how far
46
+ * apart they are rather than a flat step, so an answer that widens a third to a
47
+ * fourth stays close to its model while one that replaces it with a leap does
48
+ * not. The rhythm carries the smaller share: a melody is recognised mostly by
49
+ * its pitch shape, but a figure in a wholly different rhythm is a different
50
+ * figure.
51
+ *
52
+ * Both lines are expected to be monophonic, as {@link analyzeVoice} expects a
53
+ * voice to be. Notes struck together are read as one event, the highest of them
54
+ * standing for it, so a chord is reduced to its top voice rather than read as a
55
+ * line of its own.
56
+ *
57
+ * @param a The first line: a motif, or plain note events.
58
+ * @param b The second line.
59
+ * @returns The overall likeness, the two terms behind it, and a rationale.
126
60
  * @example
127
61
  * ```ts
128
- * import { augmentedSixthFromPitchClasses, majorKey } from '@libraz/libcantus';
129
- * // Ab C Eb Gb sounding over Ab in C: the German sixth, spelled with its F#.
130
- * augmentedSixthFromPitchClasses([8, 0, 3, 6], 8, majorKey(0))?.quality; // 'dom7'
62
+ * import { compareMelodies } from '@libraz/libcantus';
63
+ * const line = [
64
+ * { pitch: 60, startBeat: 0, durationBeat: 1 },
65
+ * { pitch: 62, startBeat: 1, durationBeat: 1 },
66
+ * { pitch: 64, startBeat: 2, durationBeat: 1 },
67
+ * ];
68
+ * compareMelodies(line, line).similarity; // 1
131
69
  * ```
132
- * @category Functional Harmony
70
+ * @category Arrangement & Analysis
133
71
  */
134
- declare function augmentedSixthFromPitchClasses(pcs: readonly number[], bassPc: number, key: KeyLike): Chord | null;
72
+ declare function compareMelodies(a: MelodicPhrase, b: MelodicPhrase): MelodicComparison;
135
73
  /**
136
- * Spell an augmented-sixth chord from a spelled tonic, lowest note first.
137
- *
138
- * This is the spelled counterpart of {@link augmentedSixthChord}, and the table
139
- * the chord's own spelling is built from: every tone is placed by a named
140
- * interval above the bass, so the outer interval is an augmented sixth in every
141
- * key rather than the minor seventh its ten semitones would otherwise imply.
142
- * Reach for it when a spelled tonic is all there is; spelling the chord itself
143
- * with {@link spellChord} names the same notes, in the chord's own order.
74
+ * How alike two lines are, in [0, 1].
144
75
  *
145
- * A tonic carrying an octave yields notes carrying octaves, ascending from the
146
- * bass; an octave-less tonic yields octave-less notes.
76
+ * The number {@link compareMelodies} reaches, for callers that only want to rank
77
+ * phrases: 1 for the same line — a transposition of it included, since the
78
+ * measure is built on intervals — and lower the further two lines are from being
79
+ * each other's variant. Symmetric in its arguments, and deterministic.
147
80
  *
148
- * @param kind Which of the three augmented sixths to spell.
149
- * @param tonic The spelled tonic of the key, as a note name, a MIDI number,
150
- * note data, or a `Note`.
151
- * @returns The spelled tones, bass first and ascending.
152
- * @throws If `kind` is not one of the three, or `tonic` is not a note.
81
+ * @param a The first line: a motif, or plain note events.
82
+ * @param b The second line.
83
+ * @returns The likeness in [0, 1].
153
84
  * @example
154
85
  * ```ts
155
- * import { noteNames, parseNote, spellAugmentedSixth } from '@libraz/libcantus';
156
- * noteNames(spellAugmentedSixth('german', parseNote('C'))); // ['Ab', 'C', 'Eb', 'F#']
157
- * noteNames(spellAugmentedSixth('italian', 'E')); // ['C', 'E', 'A#']
86
+ * import { melodicSimilarity } from '@libraz/libcantus';
87
+ * const line = [
88
+ * { pitch: 60, startBeat: 0, durationBeat: 1 },
89
+ * { pitch: 62, startBeat: 1, durationBeat: 1 },
90
+ * { pitch: 64, startBeat: 2, durationBeat: 1 },
91
+ * ];
92
+ * melodicSimilarity(line, line); // 1
158
93
  * ```
159
- * @category Functional Harmony
94
+ * @category Arrangement & Analysis
160
95
  */
161
- declare function spellAugmentedSixth(kind: AugmentedSixthKind, tonic: NoteLike): Note[];
96
+ declare function melodicSimilarity(a: MelodicPhrase, b: MelodicPhrase): number;
162
97
 
163
98
  /**
164
99
  * Line spelling: name every note of a melodic line in one pass.
@@ -187,7 +122,7 @@ type SpellLineOptions = {
187
122
  * Tonic spelling to anchor the key, for a caller that already knows how the
188
123
  * piece is written. It must sound the key's own root pitch class; anything
189
124
  * else is rejected rather than spelled. Defaults to the conventional
190
- * spelling `spelledKeyOf` gives the key. Accepted as a note name, a MIDI
125
+ * spelling the key itself is written with. Accepted as a note name, a MIDI
191
126
  * number, note data, or a `Note`.
192
127
  */
193
128
  tonic?: NoteLike;
@@ -253,6 +188,6 @@ type SpellLineOptions = {
253
188
  * ```
254
189
  * @category Arrangement & Analysis
255
190
  */
256
- declare function spellLine(notes: readonly NoteEvent[], timeline: ChordTimeline | null, key: KeyLike, opts?: SpellLineOptions): Note[];
191
+ declare function spellLine(notes: readonly NoteEvent[], timeline: ChordTimeline | null, key: SpelledKeyLike, opts?: SpellLineOptions): Note[];
257
192
 
258
- export { type AugmentedSixthKind, Chord as ChordData, ChordLike, ChordTimeline, KeyLike, Note as NoteData, NoteEvent, NoteLike, type SpellLineOptions, augmentedSixthChord, augmentedSixthFromPitchClasses, augmentedSixthKind, spellAugmentedSixth, spellLine };
193
+ export { ChordTimeline, type MelodicComparison, MelodicPhrase, Note as NoteData, NoteEvent, NoteLike, type SpellLineOptions, SpelledKeyLike, compareMelodies, melodicSimilarity, spellLine };