@libraz/libcantus 0.9.4 → 1.0.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 (186) hide show
  1. package/README.md +61 -261
  2. package/README_ja.md +115 -0
  3. package/dist/analyze/index.cjs +54 -7
  4. package/dist/analyze/index.cjs.map +1 -1
  5. package/dist/analyze/index.d.cts +213 -456
  6. package/dist/analyze/index.d.ts +213 -456
  7. package/dist/analyze/index.js +56 -9
  8. package/dist/chunk-3JXCW6DX.cjs +3220 -0
  9. package/dist/chunk-3JXCW6DX.cjs.map +1 -0
  10. package/dist/chunk-4A2RMUCC.js +7647 -0
  11. package/dist/chunk-4A2RMUCC.js.map +1 -0
  12. package/dist/chunk-6XPTBE7Y.cjs +49 -0
  13. package/dist/chunk-6XPTBE7Y.cjs.map +1 -0
  14. package/dist/chunk-AFM2ULJH.cjs +5121 -0
  15. package/dist/chunk-AFM2ULJH.cjs.map +1 -0
  16. package/dist/chunk-E3F4AHAH.cjs +690 -0
  17. package/dist/chunk-E3F4AHAH.cjs.map +1 -0
  18. package/dist/chunk-ELCTZUJJ.js +379 -0
  19. package/dist/chunk-ELCTZUJJ.js.map +1 -0
  20. package/dist/chunk-FVSI36UV.js +690 -0
  21. package/dist/chunk-FVSI36UV.js.map +1 -0
  22. package/dist/chunk-GEDTJHAC.cjs +1 -0
  23. package/dist/chunk-GEDTJHAC.cjs.map +1 -0
  24. package/dist/chunk-GOZG57ER.js +3220 -0
  25. package/dist/chunk-GOZG57ER.js.map +1 -0
  26. package/dist/chunk-H3VORETI.js +2243 -0
  27. package/dist/chunk-H3VORETI.js.map +1 -0
  28. package/dist/chunk-H42UHPYW.js +1577 -0
  29. package/dist/chunk-H42UHPYW.js.map +1 -0
  30. package/dist/chunk-HFPS7JFD.js +1 -0
  31. package/dist/chunk-INHVXP6Z.js +3053 -0
  32. package/dist/chunk-INHVXP6Z.js.map +1 -0
  33. package/dist/chunk-K4ZJUGF4.cjs +379 -0
  34. package/dist/chunk-K4ZJUGF4.cjs.map +1 -0
  35. package/dist/chunk-KNJEKLKV.js +49 -0
  36. package/dist/chunk-KNJEKLKV.js.map +1 -0
  37. package/dist/chunk-M4CWTJWJ.cjs +7647 -0
  38. package/dist/chunk-M4CWTJWJ.cjs.map +1 -0
  39. package/dist/chunk-MXO72PLY.cjs +211 -0
  40. package/dist/chunk-MXO72PLY.cjs.map +1 -0
  41. package/dist/chunk-NLEU4QSE.cjs +360 -0
  42. package/dist/chunk-NLEU4QSE.cjs.map +1 -0
  43. package/dist/chunk-OE6WK2Y2.cjs +1577 -0
  44. package/dist/chunk-OE6WK2Y2.cjs.map +1 -0
  45. package/dist/chunk-Q2WGKJNN.cjs +1064 -0
  46. package/dist/chunk-Q2WGKJNN.cjs.map +1 -0
  47. package/dist/chunk-QYQQ5J6E.js +1 -0
  48. package/dist/chunk-QYQQ5J6E.js.map +1 -0
  49. package/dist/chunk-RHIJ3S4I.cjs +1 -0
  50. package/dist/chunk-RHIJ3S4I.cjs.map +1 -0
  51. package/dist/chunk-TTCLJX6D.js +211 -0
  52. package/dist/chunk-TTCLJX6D.js.map +1 -0
  53. package/dist/chunk-UADYAYAT.cjs +3053 -0
  54. package/dist/chunk-UADYAYAT.cjs.map +1 -0
  55. package/dist/chunk-VOHZB45S.js +5121 -0
  56. package/dist/chunk-VOHZB45S.js.map +1 -0
  57. package/dist/chunk-VTI6FOLB.js +1064 -0
  58. package/dist/chunk-VTI6FOLB.js.map +1 -0
  59. package/dist/chunk-WWURE4XT.cjs +2243 -0
  60. package/dist/chunk-WWURE4XT.cjs.map +1 -0
  61. package/dist/chunk-YH3BIKHH.js +360 -0
  62. package/dist/chunk-YH3BIKHH.js.map +1 -0
  63. package/dist/core/index.cjs +103 -6
  64. package/dist/core/index.cjs.map +1 -1
  65. package/dist/core/index.d.cts +96 -345
  66. package/dist/core/index.d.ts +96 -345
  67. package/dist/core/index.js +104 -7
  68. package/dist/generate/index.cjs +89 -10
  69. package/dist/generate/index.cjs.map +1 -1
  70. package/dist/generate/index.d.cts +437 -1095
  71. package/dist/generate/index.d.ts +437 -1095
  72. package/dist/generate/index.js +94 -15
  73. package/dist/index-9wcMhG73.d.ts +1095 -0
  74. package/dist/{index-D6b6na69.d.cts → index-B4o55NDr.d.cts} +13 -9
  75. package/dist/index-B9MNZboQ.d.cts +770 -0
  76. package/dist/index-B9MNZboQ.d.ts +770 -0
  77. package/dist/index-BGFW-8P2.d.cts +2307 -0
  78. package/dist/index-BO6xE9YU.d.cts +1804 -0
  79. package/dist/index-BkGmlyI3.d.cts +470 -0
  80. package/dist/index-CCNJRG-P.d.cts +1095 -0
  81. package/dist/index-CGpRv5sl.d.cts +643 -0
  82. package/dist/index-C_8o--VE.d.cts +1242 -0
  83. package/dist/index-CgHqxdps.d.ts +2307 -0
  84. package/dist/index-Chbst3Jx.d.ts +1343 -0
  85. package/dist/index-Cj49F892.d.ts +470 -0
  86. package/dist/{index-tSQh-xwY.d.ts → index-CunYKLiu.d.ts} +13 -9
  87. package/dist/index-D57QRbVn.d.ts +1804 -0
  88. package/dist/index-DInQqT8Q.d.cts +66 -0
  89. package/dist/index-DInQqT8Q.d.ts +66 -0
  90. package/dist/index-Dzr13q3d.d.cts +1343 -0
  91. package/dist/index-G1uwGGWQ.d.ts +643 -0
  92. package/dist/index-szBv3496.d.ts +1242 -0
  93. package/dist/index.cjs +358 -15
  94. package/dist/index.cjs.map +1 -1
  95. package/dist/index.d.cts +17 -15
  96. package/dist/index.d.ts +17 -15
  97. package/dist/index.js +407 -64
  98. package/dist/masks-DYbE485J.d.cts +445 -0
  99. package/dist/masks-DYbE485J.d.ts +445 -0
  100. package/dist/model/index.cjs +39 -7
  101. package/dist/model/index.cjs.map +1 -1
  102. package/dist/model/index.d.cts +4685 -243
  103. package/dist/model/index.d.ts +4685 -243
  104. package/dist/model/index.js +40 -8
  105. package/dist/positional-Cptlj-xs.d.ts +287 -0
  106. package/dist/positional-DvH_sd8u.d.cts +287 -0
  107. package/dist/theory/index.cjs +101 -7
  108. package/dist/theory/index.cjs.map +1 -1
  109. package/dist/theory/index.d.cts +513 -173
  110. package/dist/theory/index.d.ts +513 -173
  111. package/dist/theory/index.js +118 -24
  112. package/package.json +16 -11
  113. package/dist/chunk-36N73KZ3.cjs +0 -246
  114. package/dist/chunk-36N73KZ3.cjs.map +0 -1
  115. package/dist/chunk-4HLLZPXT.cjs +0 -3077
  116. package/dist/chunk-4HLLZPXT.cjs.map +0 -1
  117. package/dist/chunk-7MGZ7D62.cjs +0 -498
  118. package/dist/chunk-7MGZ7D62.cjs.map +0 -1
  119. package/dist/chunk-7NKDPF74.js +0 -3077
  120. package/dist/chunk-7NKDPF74.js.map +0 -1
  121. package/dist/chunk-CAN76NCU.cjs +0 -679
  122. package/dist/chunk-CAN76NCU.cjs.map +0 -1
  123. package/dist/chunk-D2FAJBYL.js +0 -479
  124. package/dist/chunk-D2FAJBYL.js.map +0 -1
  125. package/dist/chunk-EHVEBWM5.js +0 -1449
  126. package/dist/chunk-EHVEBWM5.js.map +0 -1
  127. package/dist/chunk-FCANXBAT.cjs +0 -30
  128. package/dist/chunk-FCANXBAT.cjs.map +0 -1
  129. package/dist/chunk-FNDWXRRI.cjs +0 -479
  130. package/dist/chunk-FNDWXRRI.cjs.map +0 -1
  131. package/dist/chunk-GQSGS2N4.js +0 -173
  132. package/dist/chunk-GQSGS2N4.js.map +0 -1
  133. package/dist/chunk-HKGYCQ34.js +0 -53
  134. package/dist/chunk-HKGYCQ34.js.map +0 -1
  135. package/dist/chunk-I24MV65U.js +0 -106
  136. package/dist/chunk-I24MV65U.js.map +0 -1
  137. package/dist/chunk-KMHOICIY.js +0 -679
  138. package/dist/chunk-KMHOICIY.js.map +0 -1
  139. package/dist/chunk-LW53AHQU.cjs +0 -1117
  140. package/dist/chunk-LW53AHQU.cjs.map +0 -1
  141. package/dist/chunk-N6IHQUOX.js +0 -1
  142. package/dist/chunk-NKIBQ6PT.js +0 -30
  143. package/dist/chunk-NKIBQ6PT.js.map +0 -1
  144. package/dist/chunk-NP4NA2FB.cjs +0 -106
  145. package/dist/chunk-NP4NA2FB.cjs.map +0 -1
  146. package/dist/chunk-NVE34YGZ.cjs +0 -1449
  147. package/dist/chunk-NVE34YGZ.cjs.map +0 -1
  148. package/dist/chunk-NYYWMV2C.js +0 -327
  149. package/dist/chunk-NYYWMV2C.js.map +0 -1
  150. package/dist/chunk-Q2XUP227.js +0 -845
  151. package/dist/chunk-Q2XUP227.js.map +0 -1
  152. package/dist/chunk-Q6OP4U43.cjs +0 -327
  153. package/dist/chunk-Q6OP4U43.cjs.map +0 -1
  154. package/dist/chunk-RC6GBMCD.cjs +0 -845
  155. package/dist/chunk-RC6GBMCD.cjs.map +0 -1
  156. package/dist/chunk-RK35RIN7.js +0 -1117
  157. package/dist/chunk-RK35RIN7.js.map +0 -1
  158. package/dist/chunk-RUMU3UA6.cjs +0 -53
  159. package/dist/chunk-RUMU3UA6.cjs.map +0 -1
  160. package/dist/chunk-T64C7ZD7.cjs +0 -1
  161. package/dist/chunk-T64C7ZD7.cjs.map +0 -1
  162. package/dist/chunk-XEBG3G53.js +0 -498
  163. package/dist/chunk-XEBG3G53.js.map +0 -1
  164. package/dist/chunk-YLEMGEFH.js +0 -246
  165. package/dist/chunk-YLEMGEFH.js.map +0 -1
  166. package/dist/chunk-ZEJR4TKL.cjs +0 -173
  167. package/dist/chunk-ZEJR4TKL.cjs.map +0 -1
  168. package/dist/function-BtiZb9i9.d.ts +0 -208
  169. package/dist/function-DNugAOrt.d.cts +0 -208
  170. package/dist/index-6VR8-kit.d.ts +0 -143
  171. package/dist/index-70p168VM.d.ts +0 -192
  172. package/dist/index-Be74mcon.d.cts +0 -152
  173. package/dist/index-BtXT6UQ0.d.cts +0 -192
  174. package/dist/index-C5UBbQ4G.d.ts +0 -152
  175. package/dist/index-C83mZI1P.d.ts +0 -242
  176. package/dist/index-DXd9JikN.d.cts +0 -246
  177. package/dist/index-DXd9JikN.d.ts +0 -246
  178. package/dist/index-OG65ocOr.d.cts +0 -272
  179. package/dist/index-OG65ocOr.d.ts +0 -272
  180. package/dist/index-tJhkmQgE.d.cts +0 -143
  181. package/dist/index-y_ak9_Hi.d.cts +0 -242
  182. package/dist/styled-DIRkk9Uz.d.ts +0 -506
  183. package/dist/styled-DJbkJQfj.d.cts +0 -506
  184. package/dist/types-BN6_Q9Kl.d.cts +0 -39
  185. package/dist/types-BN6_Q9Kl.d.ts +0 -39
  186. /package/dist/{chunk-N6IHQUOX.js.map → chunk-HFPS7JFD.js.map} +0 -0
@@ -1,192 +0,0 @@
1
- import { K as KeyScale, N as NoteEvent } from './types-BN6_Q9Kl.js';
2
- import { a as ChordQuality, C as Chord } from './index-C83mZI1P.js';
3
-
4
- /**
5
- * Recognition: infer a chord name from a set of pitches, or a key from a set of
6
- * pitch classes. This is the inverse direction of the chord/scale builders,
7
- * which only go name -> notes.
8
- */
9
-
10
- /**
11
- * A candidate chord interpretation of a pitch set.
12
- *
13
- * @category Recognition
14
- */
15
- type ChordMatch = {
16
- rootPc: number;
17
- quality: ChordQuality;
18
- /** Chord tones absent from the input (an incomplete voicing). */
19
- missingPcs: number[];
20
- /** Input pitch classes not belonging to the chord. */
21
- extraPcs: number[];
22
- /** True when the input pitch-class set equals the chord exactly. */
23
- exact: boolean;
24
- /**
25
- * Inversion implied by a known bass: 0 for root position, 1..n for an
26
- * inversion. Null when no inversion can be named — either the input is an
27
- * unordered pitch-class set with no bass, or the bass is not a chord tone (a
28
- * pedal or passing bass), in which case `bassPc` still reports it.
29
- */
30
- inversion: number | null;
31
- /** Bass pitch class when the lowest note is not the root. */
32
- bassPc?: number;
33
- };
34
- /**
35
- * Input interpretation for {@link detectChord} and {@link detectChordBest}.
36
- *
37
- * @category Recognition
38
- */
39
- type DetectChordOptions = {
40
- /**
41
- * `midi` uses the numerically lowest pitch as bass; `pitchClass` treats the
42
- * input as unordered. `auto` (default) selects pitch-class mode only when all
43
- * values lie in 0..11.
44
- */
45
- input?: 'auto' | 'midi' | 'pitchClass';
46
- /** Explicit bass pitch class, including for an unordered pitch-class set. */
47
- bassPc?: number;
48
- };
49
- /**
50
- * A candidate key interpretation of a pitch-class set.
51
- *
52
- * @category Recognition
53
- */
54
- type KeyMatch = {
55
- /** The scale that scored best for this tonic and mode, `variant` included. */
56
- key: KeyScale;
57
- mode: 'major' | 'minor';
58
- /** Which scale form `key` uses; minor keys pick the best-scoring of the three. */
59
- variant: KeyVariant;
60
- /**
61
- * Fraction of the distinct input pitch classes that belong to `key`, in
62
- * [0, 1]. Measured against the returned scale, so it always agrees with
63
- * `isScaleTone(pc, match.key)`. This is a coverage figure, not the ranking:
64
- * see `score`.
65
- */
66
- fit: number;
67
- /**
68
- * The value the results are ranked by, in [0, 1.5]. Unlike `fit` it counts
69
- * every occurrence rather than every distinct pitch class, so a repeated tone
70
- * weighs more, and it adds half a count per sounding of the tonic itself to
71
- * break ties between keys that contain the same notes.
72
- */
73
- score: number;
74
- };
75
- /**
76
- * Which form of a scale a {@link KeyMatch} settled on.
77
- *
78
- * @category Recognition
79
- */
80
- type KeyVariant = 'major' | 'natural' | 'harmonic' | 'melodic';
81
- /**
82
- * Input weighting for {@link detectKey}.
83
- *
84
- * @category Recognition
85
- */
86
- type DetectKeyOptions = {
87
- /**
88
- * How much each pitch counts toward the histogram, one entry per pitch.
89
- * Defaults to one per pitch, which weighs a thirty-second-note ornament as
90
- * heavily as the whole note under it. {@link detectKeyFromNotes} supplies
91
- * duration times velocity, matching how chord inference weighs its own
92
- * histogram.
93
- */
94
- weights?: readonly number[];
95
- };
96
- /**
97
- * Identify chords matching a set of pitches.
98
- *
99
- * Every input pitch class is tried as a root against every known chord quality.
100
- * A match is reported when all of the chord's tones are present in the input, or
101
- * when the only absent tone is the perfect fifth (a common omission in shell
102
- * voicings); matches are ranked best-first by fewest extra notes, then fewest
103
- * missing notes, then most specific (largest) chord. An exact match (no extras,
104
- * no missing) is flagged and ranked first.
105
- *
106
- * @param pitches MIDI pitches or bare pitch classes (octave-agnostic).
107
- * @returns Ranked chord interpretations (may be empty).
108
- * @example
109
- * ```ts
110
- * import { detectChord } from '@libraz/libcantus';
111
- * const matches = detectChord([60, 64, 67]); // C E G
112
- * matches[0]; // { rootPc: 0, quality: 'maj', exact: true, ... }
113
- * ```
114
- * @category Recognition
115
- */
116
- declare function detectChord(pitches: readonly number[], opts?: DetectChordOptions): ChordMatch[];
117
- /**
118
- * The single best chord interpretation of a pitch set, or null if none.
119
- *
120
- * @param pitches MIDI pitches or bare pitch classes.
121
- * @returns The top-ranked chord, or null when nothing matches.
122
- * @example
123
- * ```ts
124
- * import { detectChordBest } from '@libraz/libcantus';
125
- * detectChordBest([60, 64, 67]); // C major triad: { rootPc: 0, quality: 'maj', ... }
126
- * ```
127
- * @category Recognition
128
- */
129
- declare function detectChordBest(pitches: readonly number[], opts?: DetectChordOptions): Chord | null;
130
- /**
131
- * Rank major and minor keys by how well they contain a set of pitch classes.
132
- *
133
- * Ranking is by `score`, which counts repetitions and adds a tonic weight so
134
- * that, among equally-fitting keys, the one whose root is actually sounded is
135
- * preferred. Minor candidates are scored against the natural, harmonic, and
136
- * melodic minor variants and keep the best of the three, so a minor cadence
137
- * containing the leading tone still resolves to its own tonic; the winning
138
- * variant is what `key` and `variant` report, so `fit` describes the scale the
139
- * caller receives. Returns all 24 keys ranked best-first, or an empty array for
140
- * an empty input (mirroring {@link detectChord}).
141
- *
142
- * @param pitches MIDI pitches or bare pitch classes.
143
- * @returns Ranked key interpretations (empty for an empty input).
144
- * @example
145
- * ```ts
146
- * import { detectKey } from '@libraz/libcantus';
147
- * const keys = detectKey([60, 62, 64, 65, 67, 69, 71]); // C major scale
148
- * keys[0].mode; // 'major', with keys[0].key.rootPc === 0
149
- * ```
150
- * @category Recognition
151
- */
152
- declare function detectKey(pitches: readonly number[], opts?: DetectKeyOptions): KeyMatch[];
153
- /**
154
- * Rank keys by how well they contain a set of note events, weighting each note
155
- * by how much of the music it actually occupies.
156
- *
157
- * {@link detectKey} counts every pitch once, which lets a run of fast ornamental
158
- * notes outvote the sustained harmony that establishes the key. This weighs
159
- * each note by duration times velocity, the same measure chord inference uses,
160
- * so the two agree on what the music emphasises. Notes that never sound (zero
161
- * or negative duration) are ignored.
162
- *
163
- * @param notes The note events to weigh.
164
- * @returns Ranked key interpretations (empty when nothing sounds).
165
- * @example
166
- * ```ts
167
- * import { detectKeyFromNotes } from '@libraz/libcantus';
168
- * detectKeyFromNotes([{ pitch: 60, startBeat: 0, durationBeat: 4 }])[0]?.key.rootPc; // 0
169
- * ```
170
- * @category Recognition
171
- */
172
- declare function detectKeyFromNotes(notes: readonly NoteEvent[]): KeyMatch[];
173
- /**
174
- * The single best key interpretation of a pitch set.
175
- *
176
- * The counterpart of {@link detectChordBest}: the ranked list is the general
177
- * answer, but a caller that just wants "what key is this" should not have to
178
- * index into it and assert the result is there.
179
- *
180
- * @param pitches MIDI pitches or bare pitch classes.
181
- * @param opts How to weigh the input; see {@link DetectKeyOptions}.
182
- * @returns The top-ranked key, or null when nothing sounds.
183
- * @example
184
- * ```ts
185
- * import { detectKeyBest } from '@libraz/libcantus';
186
- * detectKeyBest([0, 2, 4, 5, 7, 9, 11])?.mode; // 'major'
187
- * ```
188
- * @category Recognition
189
- */
190
- declare function detectKeyBest(pitches: readonly number[], opts?: DetectKeyOptions): KeyMatch | null;
191
-
192
- export { type ChordMatch as C, type DetectChordOptions as D, type KeyMatch as K, type DetectKeyOptions as a, type KeyVariant as b, detectChordBest as c, detectChord as d, detectKey as e, detectKeyBest as f, detectKeyFromNotes as g };
@@ -1,152 +0,0 @@
1
- import { T as TimeSignature } from './index-DXd9JikN.cjs';
2
- import { K as KeyScale, N as NoteEvent } from './types-BN6_Q9Kl.cjs';
3
- import { C as Chord, b as ChordSegment, c as ChordSpan } from './index-y_ak9_Hi.cjs';
4
- import { C as Cadence } from './function-DNugAOrt.cjs';
5
-
6
- /**
7
- * A beat-indexed sequence of chord segments.
8
- *
9
- * @category Arrangement & Analysis
10
- */
11
- type ChordTimeline = {
12
- /** The chord sounding at a beat, or null when no segment covers it. */
13
- at: (beat: number) => Chord | null;
14
- segments: ChordSegment[];
15
- };
16
- /**
17
- * Build a chord timeline from placed chords.
18
- *
19
- * Each chord spans from its `startBeat` to the next chord's `startBeat`; the last
20
- * chord runs to `totalBeats`. Segments with no positive length (from duplicate
21
- * onsets or a last chord at or past `totalBeats`) are dropped. `at(beat)` returns
22
- * the covering segment's chord, or null when the beat lies outside every segment.
23
- *
24
- * @param chords Placed chords in time order.
25
- * @param totalBeats End of the timeline in beats.
26
- * @returns A queryable chord timeline.
27
- * @category Arrangement & Analysis
28
- */
29
- declare function chordTimelineFromChords(chords: readonly ChordSpan[], totalBeats: number): ChordTimeline;
30
- /**
31
- * Options controlling {@link chordTimelineFromNotes}.
32
- *
33
- * @category Arrangement & Analysis
34
- */
35
- type ChordTimelineOptions = {
36
- /** Key context; inferred from the notes with {@link detectKeyFromNotes} when omitted. */
37
- key?: KeyScale;
38
- /**
39
- * Time signature used for metric accents; defaults to 4/4.
40
- *
41
- * @defaultValue `4/4`
42
- */
43
- ts?: TimeSignature;
44
- /**
45
- * Window length in beats per chord slot; defaults to one bar of `ts`.
46
- *
47
- * @defaultValue one bar of `ts`
48
- */
49
- harmonicRhythm?: number;
50
- /**
51
- * End of the analyzed span in beats; defaults to the end of the last note.
52
- *
53
- * @defaultValue the end of the last note
54
- */
55
- totalBeats?: number;
56
- /**
57
- * Upper bound on the work this call may do — note counts, windows, and
58
- * candidate counts are each checked against it before anything is allocated.
59
- *
60
- * Raise it to analyse a piece larger than the default allows; the default is
61
- * {@link DEFAULT_GENERATION_BUDGET}, chosen so a runaway input fails fast
62
- * rather than blocking the thread.
63
- *
64
- * @defaultValue {@link DEFAULT_GENERATION_BUDGET}
65
- */
66
- budget?: number;
67
- };
68
- /**
69
- * The result of {@link chordTimelineFromNotes}.
70
- *
71
- * @category Arrangement & Analysis
72
- */
73
- type ChordTimelineResult = {
74
- /** The inferred timeline, with adjacent identical chords merged. */
75
- timeline: ChordTimeline;
76
- /** The key used for the analysis (given or inferred). */
77
- key: KeyScale;
78
- /** One confidence value in [0, 1] per segment, in segment order. */
79
- segmentConfidence: number[];
80
- };
81
- /**
82
- * Infer a chord timeline from raw multi-track notes.
83
- *
84
- * The span `[0, totalBeats)` is sliced into `harmonicRhythm`-beat windows; each
85
- * window's chord is inferred from a pitch-class weight histogram of the notes
86
- * overlapping it (weight = overlap duration x velocity x metric-accent bonus
87
- * for onsets in the window). Adjacent windows carrying the identical chord are
88
- * merged into one segment; windows with no notes produce no segment, so
89
- * `at(beat)` returns null there. Each segment carries a confidence in [0, 1]:
90
- * the fraction of the window weight explained by chord tones, reduced when the
91
- * match is inexact, and duration-weighted across merged windows.
92
- *
93
- * Notes with a zero or negative duration never sound, so they are dropped at
94
- * ingest: they contribute to neither the key inference, the span, nor any
95
- * window's histogram.
96
- *
97
- * @param notes The notes to analyze (any number of tracks, flattened).
98
- * @param opts Analysis options; see {@link ChordTimelineOptions}.
99
- * @returns The inferred timeline, the key used, and per-segment confidences.
100
- * @throws If `harmonicRhythm` is not positive.
101
- * @example
102
- * ```ts
103
- * import { chordTimelineFromNotes } from '@libraz/libcantus';
104
- * const notes = [
105
- * { pitch: 60, startBeat: 0, durationBeat: 2 }, // C
106
- * { pitch: 64, startBeat: 0, durationBeat: 2 }, // E
107
- * { pitch: 67, startBeat: 0, durationBeat: 2 }, // G
108
- * ];
109
- * const { timeline, key } = chordTimelineFromNotes(notes);
110
- * timeline.at(0); // the chord inferred over beat 0, or null
111
- * ```
112
- * @category Arrangement & Analysis
113
- */
114
- declare function chordTimelineFromNotes(notes: NoteEvent[], opts?: ChordTimelineOptions): ChordTimelineResult;
115
- /**
116
- * A cadence found between two consecutive timeline segments.
117
- *
118
- * @category Arrangement & Analysis
119
- */
120
- type CadenceHit = {
121
- /** The beat where the cadence arrives (the second chord's onset). */
122
- atBeat: number;
123
- type: Exclude<Cadence, null>;
124
- from: Chord;
125
- to: Chord;
126
- };
127
- /**
128
- * Find cadences between consecutive segments of a chord timeline.
129
- *
130
- * Each temporally adjacent segment pair is classified with
131
- * {@link detectCadence}; pairs forming no cadence are skipped. Segments
132
- * separated by a gap (a rest in the timeline) are not a chord-to-chord
133
- * progression, so they are never paired.
134
- *
135
- * @param timeline The chord timeline to scan.
136
- * @param key The prevailing key.
137
- * @returns The cadences found, in time order.
138
- * @example
139
- * ```ts
140
- * import { chordTimelineFromNotes, detectCadences } from '@libraz/libcantus';
141
- * const notes = [
142
- * { pitch: 67, startBeat: 0, durationBeat: 4 }, // G, a dominant
143
- * { pitch: 60, startBeat: 4, durationBeat: 4 }, // C, the tonic
144
- * ];
145
- * const { timeline, key } = chordTimelineFromNotes(notes);
146
- * const cadences = detectCadences(timeline, key);
147
- * ```
148
- * @category Arrangement & Analysis
149
- */
150
- declare function detectCadences(timeline: ChordTimeline, key: KeyScale): CadenceHit[];
151
-
152
- export { type CadenceHit as C, type ChordTimeline as a, type ChordTimelineOptions as b, type ChordTimelineResult as c, chordTimelineFromChords as d, chordTimelineFromNotes as e, detectCadences as f };
@@ -1,192 +0,0 @@
1
- import { K as KeyScale, N as NoteEvent } from './types-BN6_Q9Kl.cjs';
2
- import { a as ChordQuality, C as Chord } from './index-y_ak9_Hi.cjs';
3
-
4
- /**
5
- * Recognition: infer a chord name from a set of pitches, or a key from a set of
6
- * pitch classes. This is the inverse direction of the chord/scale builders,
7
- * which only go name -> notes.
8
- */
9
-
10
- /**
11
- * A candidate chord interpretation of a pitch set.
12
- *
13
- * @category Recognition
14
- */
15
- type ChordMatch = {
16
- rootPc: number;
17
- quality: ChordQuality;
18
- /** Chord tones absent from the input (an incomplete voicing). */
19
- missingPcs: number[];
20
- /** Input pitch classes not belonging to the chord. */
21
- extraPcs: number[];
22
- /** True when the input pitch-class set equals the chord exactly. */
23
- exact: boolean;
24
- /**
25
- * Inversion implied by a known bass: 0 for root position, 1..n for an
26
- * inversion. Null when no inversion can be named — either the input is an
27
- * unordered pitch-class set with no bass, or the bass is not a chord tone (a
28
- * pedal or passing bass), in which case `bassPc` still reports it.
29
- */
30
- inversion: number | null;
31
- /** Bass pitch class when the lowest note is not the root. */
32
- bassPc?: number;
33
- };
34
- /**
35
- * Input interpretation for {@link detectChord} and {@link detectChordBest}.
36
- *
37
- * @category Recognition
38
- */
39
- type DetectChordOptions = {
40
- /**
41
- * `midi` uses the numerically lowest pitch as bass; `pitchClass` treats the
42
- * input as unordered. `auto` (default) selects pitch-class mode only when all
43
- * values lie in 0..11.
44
- */
45
- input?: 'auto' | 'midi' | 'pitchClass';
46
- /** Explicit bass pitch class, including for an unordered pitch-class set. */
47
- bassPc?: number;
48
- };
49
- /**
50
- * A candidate key interpretation of a pitch-class set.
51
- *
52
- * @category Recognition
53
- */
54
- type KeyMatch = {
55
- /** The scale that scored best for this tonic and mode, `variant` included. */
56
- key: KeyScale;
57
- mode: 'major' | 'minor';
58
- /** Which scale form `key` uses; minor keys pick the best-scoring of the three. */
59
- variant: KeyVariant;
60
- /**
61
- * Fraction of the distinct input pitch classes that belong to `key`, in
62
- * [0, 1]. Measured against the returned scale, so it always agrees with
63
- * `isScaleTone(pc, match.key)`. This is a coverage figure, not the ranking:
64
- * see `score`.
65
- */
66
- fit: number;
67
- /**
68
- * The value the results are ranked by, in [0, 1.5]. Unlike `fit` it counts
69
- * every occurrence rather than every distinct pitch class, so a repeated tone
70
- * weighs more, and it adds half a count per sounding of the tonic itself to
71
- * break ties between keys that contain the same notes.
72
- */
73
- score: number;
74
- };
75
- /**
76
- * Which form of a scale a {@link KeyMatch} settled on.
77
- *
78
- * @category Recognition
79
- */
80
- type KeyVariant = 'major' | 'natural' | 'harmonic' | 'melodic';
81
- /**
82
- * Input weighting for {@link detectKey}.
83
- *
84
- * @category Recognition
85
- */
86
- type DetectKeyOptions = {
87
- /**
88
- * How much each pitch counts toward the histogram, one entry per pitch.
89
- * Defaults to one per pitch, which weighs a thirty-second-note ornament as
90
- * heavily as the whole note under it. {@link detectKeyFromNotes} supplies
91
- * duration times velocity, matching how chord inference weighs its own
92
- * histogram.
93
- */
94
- weights?: readonly number[];
95
- };
96
- /**
97
- * Identify chords matching a set of pitches.
98
- *
99
- * Every input pitch class is tried as a root against every known chord quality.
100
- * A match is reported when all of the chord's tones are present in the input, or
101
- * when the only absent tone is the perfect fifth (a common omission in shell
102
- * voicings); matches are ranked best-first by fewest extra notes, then fewest
103
- * missing notes, then most specific (largest) chord. An exact match (no extras,
104
- * no missing) is flagged and ranked first.
105
- *
106
- * @param pitches MIDI pitches or bare pitch classes (octave-agnostic).
107
- * @returns Ranked chord interpretations (may be empty).
108
- * @example
109
- * ```ts
110
- * import { detectChord } from '@libraz/libcantus';
111
- * const matches = detectChord([60, 64, 67]); // C E G
112
- * matches[0]; // { rootPc: 0, quality: 'maj', exact: true, ... }
113
- * ```
114
- * @category Recognition
115
- */
116
- declare function detectChord(pitches: readonly number[], opts?: DetectChordOptions): ChordMatch[];
117
- /**
118
- * The single best chord interpretation of a pitch set, or null if none.
119
- *
120
- * @param pitches MIDI pitches or bare pitch classes.
121
- * @returns The top-ranked chord, or null when nothing matches.
122
- * @example
123
- * ```ts
124
- * import { detectChordBest } from '@libraz/libcantus';
125
- * detectChordBest([60, 64, 67]); // C major triad: { rootPc: 0, quality: 'maj', ... }
126
- * ```
127
- * @category Recognition
128
- */
129
- declare function detectChordBest(pitches: readonly number[], opts?: DetectChordOptions): Chord | null;
130
- /**
131
- * Rank major and minor keys by how well they contain a set of pitch classes.
132
- *
133
- * Ranking is by `score`, which counts repetitions and adds a tonic weight so
134
- * that, among equally-fitting keys, the one whose root is actually sounded is
135
- * preferred. Minor candidates are scored against the natural, harmonic, and
136
- * melodic minor variants and keep the best of the three, so a minor cadence
137
- * containing the leading tone still resolves to its own tonic; the winning
138
- * variant is what `key` and `variant` report, so `fit` describes the scale the
139
- * caller receives. Returns all 24 keys ranked best-first, or an empty array for
140
- * an empty input (mirroring {@link detectChord}).
141
- *
142
- * @param pitches MIDI pitches or bare pitch classes.
143
- * @returns Ranked key interpretations (empty for an empty input).
144
- * @example
145
- * ```ts
146
- * import { detectKey } from '@libraz/libcantus';
147
- * const keys = detectKey([60, 62, 64, 65, 67, 69, 71]); // C major scale
148
- * keys[0].mode; // 'major', with keys[0].key.rootPc === 0
149
- * ```
150
- * @category Recognition
151
- */
152
- declare function detectKey(pitches: readonly number[], opts?: DetectKeyOptions): KeyMatch[];
153
- /**
154
- * Rank keys by how well they contain a set of note events, weighting each note
155
- * by how much of the music it actually occupies.
156
- *
157
- * {@link detectKey} counts every pitch once, which lets a run of fast ornamental
158
- * notes outvote the sustained harmony that establishes the key. This weighs
159
- * each note by duration times velocity, the same measure chord inference uses,
160
- * so the two agree on what the music emphasises. Notes that never sound (zero
161
- * or negative duration) are ignored.
162
- *
163
- * @param notes The note events to weigh.
164
- * @returns Ranked key interpretations (empty when nothing sounds).
165
- * @example
166
- * ```ts
167
- * import { detectKeyFromNotes } from '@libraz/libcantus';
168
- * detectKeyFromNotes([{ pitch: 60, startBeat: 0, durationBeat: 4 }])[0]?.key.rootPc; // 0
169
- * ```
170
- * @category Recognition
171
- */
172
- declare function detectKeyFromNotes(notes: readonly NoteEvent[]): KeyMatch[];
173
- /**
174
- * The single best key interpretation of a pitch set.
175
- *
176
- * The counterpart of {@link detectChordBest}: the ranked list is the general
177
- * answer, but a caller that just wants "what key is this" should not have to
178
- * index into it and assert the result is there.
179
- *
180
- * @param pitches MIDI pitches or bare pitch classes.
181
- * @param opts How to weigh the input; see {@link DetectKeyOptions}.
182
- * @returns The top-ranked key, or null when nothing sounds.
183
- * @example
184
- * ```ts
185
- * import { detectKeyBest } from '@libraz/libcantus';
186
- * detectKeyBest([0, 2, 4, 5, 7, 9, 11])?.mode; // 'major'
187
- * ```
188
- * @category Recognition
189
- */
190
- declare function detectKeyBest(pitches: readonly number[], opts?: DetectKeyOptions): KeyMatch | null;
191
-
192
- export { type ChordMatch as C, type DetectChordOptions as D, type KeyMatch as K, type DetectKeyOptions as a, type KeyVariant as b, detectChordBest as c, detectChord as d, detectKey as e, detectKeyBest as f, detectKeyFromNotes as g };
@@ -1,152 +0,0 @@
1
- import { T as TimeSignature } from './index-DXd9JikN.js';
2
- import { K as KeyScale, N as NoteEvent } from './types-BN6_Q9Kl.js';
3
- import { C as Chord, b as ChordSegment, c as ChordSpan } from './index-C83mZI1P.js';
4
- import { C as Cadence } from './function-BtiZb9i9.js';
5
-
6
- /**
7
- * A beat-indexed sequence of chord segments.
8
- *
9
- * @category Arrangement & Analysis
10
- */
11
- type ChordTimeline = {
12
- /** The chord sounding at a beat, or null when no segment covers it. */
13
- at: (beat: number) => Chord | null;
14
- segments: ChordSegment[];
15
- };
16
- /**
17
- * Build a chord timeline from placed chords.
18
- *
19
- * Each chord spans from its `startBeat` to the next chord's `startBeat`; the last
20
- * chord runs to `totalBeats`. Segments with no positive length (from duplicate
21
- * onsets or a last chord at or past `totalBeats`) are dropped. `at(beat)` returns
22
- * the covering segment's chord, or null when the beat lies outside every segment.
23
- *
24
- * @param chords Placed chords in time order.
25
- * @param totalBeats End of the timeline in beats.
26
- * @returns A queryable chord timeline.
27
- * @category Arrangement & Analysis
28
- */
29
- declare function chordTimelineFromChords(chords: readonly ChordSpan[], totalBeats: number): ChordTimeline;
30
- /**
31
- * Options controlling {@link chordTimelineFromNotes}.
32
- *
33
- * @category Arrangement & Analysis
34
- */
35
- type ChordTimelineOptions = {
36
- /** Key context; inferred from the notes with {@link detectKeyFromNotes} when omitted. */
37
- key?: KeyScale;
38
- /**
39
- * Time signature used for metric accents; defaults to 4/4.
40
- *
41
- * @defaultValue `4/4`
42
- */
43
- ts?: TimeSignature;
44
- /**
45
- * Window length in beats per chord slot; defaults to one bar of `ts`.
46
- *
47
- * @defaultValue one bar of `ts`
48
- */
49
- harmonicRhythm?: number;
50
- /**
51
- * End of the analyzed span in beats; defaults to the end of the last note.
52
- *
53
- * @defaultValue the end of the last note
54
- */
55
- totalBeats?: number;
56
- /**
57
- * Upper bound on the work this call may do — note counts, windows, and
58
- * candidate counts are each checked against it before anything is allocated.
59
- *
60
- * Raise it to analyse a piece larger than the default allows; the default is
61
- * {@link DEFAULT_GENERATION_BUDGET}, chosen so a runaway input fails fast
62
- * rather than blocking the thread.
63
- *
64
- * @defaultValue {@link DEFAULT_GENERATION_BUDGET}
65
- */
66
- budget?: number;
67
- };
68
- /**
69
- * The result of {@link chordTimelineFromNotes}.
70
- *
71
- * @category Arrangement & Analysis
72
- */
73
- type ChordTimelineResult = {
74
- /** The inferred timeline, with adjacent identical chords merged. */
75
- timeline: ChordTimeline;
76
- /** The key used for the analysis (given or inferred). */
77
- key: KeyScale;
78
- /** One confidence value in [0, 1] per segment, in segment order. */
79
- segmentConfidence: number[];
80
- };
81
- /**
82
- * Infer a chord timeline from raw multi-track notes.
83
- *
84
- * The span `[0, totalBeats)` is sliced into `harmonicRhythm`-beat windows; each
85
- * window's chord is inferred from a pitch-class weight histogram of the notes
86
- * overlapping it (weight = overlap duration x velocity x metric-accent bonus
87
- * for onsets in the window). Adjacent windows carrying the identical chord are
88
- * merged into one segment; windows with no notes produce no segment, so
89
- * `at(beat)` returns null there. Each segment carries a confidence in [0, 1]:
90
- * the fraction of the window weight explained by chord tones, reduced when the
91
- * match is inexact, and duration-weighted across merged windows.
92
- *
93
- * Notes with a zero or negative duration never sound, so they are dropped at
94
- * ingest: they contribute to neither the key inference, the span, nor any
95
- * window's histogram.
96
- *
97
- * @param notes The notes to analyze (any number of tracks, flattened).
98
- * @param opts Analysis options; see {@link ChordTimelineOptions}.
99
- * @returns The inferred timeline, the key used, and per-segment confidences.
100
- * @throws If `harmonicRhythm` is not positive.
101
- * @example
102
- * ```ts
103
- * import { chordTimelineFromNotes } from '@libraz/libcantus';
104
- * const notes = [
105
- * { pitch: 60, startBeat: 0, durationBeat: 2 }, // C
106
- * { pitch: 64, startBeat: 0, durationBeat: 2 }, // E
107
- * { pitch: 67, startBeat: 0, durationBeat: 2 }, // G
108
- * ];
109
- * const { timeline, key } = chordTimelineFromNotes(notes);
110
- * timeline.at(0); // the chord inferred over beat 0, or null
111
- * ```
112
- * @category Arrangement & Analysis
113
- */
114
- declare function chordTimelineFromNotes(notes: NoteEvent[], opts?: ChordTimelineOptions): ChordTimelineResult;
115
- /**
116
- * A cadence found between two consecutive timeline segments.
117
- *
118
- * @category Arrangement & Analysis
119
- */
120
- type CadenceHit = {
121
- /** The beat where the cadence arrives (the second chord's onset). */
122
- atBeat: number;
123
- type: Exclude<Cadence, null>;
124
- from: Chord;
125
- to: Chord;
126
- };
127
- /**
128
- * Find cadences between consecutive segments of a chord timeline.
129
- *
130
- * Each temporally adjacent segment pair is classified with
131
- * {@link detectCadence}; pairs forming no cadence are skipped. Segments
132
- * separated by a gap (a rest in the timeline) are not a chord-to-chord
133
- * progression, so they are never paired.
134
- *
135
- * @param timeline The chord timeline to scan.
136
- * @param key The prevailing key.
137
- * @returns The cadences found, in time order.
138
- * @example
139
- * ```ts
140
- * import { chordTimelineFromNotes, detectCadences } from '@libraz/libcantus';
141
- * const notes = [
142
- * { pitch: 67, startBeat: 0, durationBeat: 4 }, // G, a dominant
143
- * { pitch: 60, startBeat: 4, durationBeat: 4 }, // C, the tonic
144
- * ];
145
- * const { timeline, key } = chordTimelineFromNotes(notes);
146
- * const cadences = detectCadences(timeline, key);
147
- * ```
148
- * @category Arrangement & Analysis
149
- */
150
- declare function detectCadences(timeline: ChordTimeline, key: KeyScale): CadenceHit[];
151
-
152
- export { type CadenceHit as C, type ChordTimeline as a, type ChordTimelineOptions as b, type ChordTimelineResult as c, chordTimelineFromChords as d, chordTimelineFromNotes as e, detectCadences as f };