@libraz/libcantus 0.9.5 → 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 (185) hide show
  1. package/README.md +61 -270
  2. package/README_ja.md +61 -214
  3. package/dist/analyze/index.cjs +54 -7
  4. package/dist/analyze/index.cjs.map +1 -1
  5. package/dist/analyze/index.d.cts +200 -353
  6. package/dist/analyze/index.d.ts +200 -353
  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-2PTFGVD7.js → chunk-ELCTZUJJ.js} +250 -132
  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 +93 -6
  64. package/dist/core/index.cjs.map +1 -1
  65. package/dist/core/index.d.cts +87 -346
  66. package/dist/core/index.d.ts +87 -346
  67. package/dist/core/index.js +94 -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 +436 -1094
  71. package/dist/generate/index.d.ts +436 -1094
  72. package/dist/generate/index.js +94 -15
  73. package/dist/index-9wcMhG73.d.ts +1095 -0
  74. package/dist/{index-Cfx8xgH0.d.ts → 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-x2vcsduE.d.cts → 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 +348 -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 +397 -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 +4659 -249
  103. package/dist/model/index.d.ts +4659 -249
  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 +511 -171
  110. package/dist/theory/index.d.ts +511 -171
  111. package/dist/theory/index.js +118 -24
  112. package/package.json +6 -4
  113. package/dist/chunk-2A2QMA74.cjs +0 -261
  114. package/dist/chunk-2A2QMA74.cjs.map +0 -1
  115. package/dist/chunk-2PTFGVD7.js.map +0 -1
  116. package/dist/chunk-357ZDPVU.cjs +0 -162
  117. package/dist/chunk-357ZDPVU.cjs.map +0 -1
  118. package/dist/chunk-3KX76RLG.js +0 -1548
  119. package/dist/chunk-3KX76RLG.js.map +0 -1
  120. package/dist/chunk-4VZ5MZAM.cjs +0 -889
  121. package/dist/chunk-4VZ5MZAM.cjs.map +0 -1
  122. package/dist/chunk-7EONYVI5.js +0 -1204
  123. package/dist/chunk-7EONYVI5.js.map +0 -1
  124. package/dist/chunk-7JEP3MFY.js +0 -162
  125. package/dist/chunk-7JEP3MFY.js.map +0 -1
  126. package/dist/chunk-AID75RN3.js +0 -3176
  127. package/dist/chunk-AID75RN3.js.map +0 -1
  128. package/dist/chunk-BSLTLGM3.cjs +0 -497
  129. package/dist/chunk-BSLTLGM3.cjs.map +0 -1
  130. package/dist/chunk-CU6VG2YM.cjs +0 -109
  131. package/dist/chunk-CU6VG2YM.cjs.map +0 -1
  132. package/dist/chunk-DZMHIGI4.js +0 -337
  133. package/dist/chunk-DZMHIGI4.js.map +0 -1
  134. package/dist/chunk-EDOTEABK.js +0 -109
  135. package/dist/chunk-EDOTEABK.js.map +0 -1
  136. package/dist/chunk-HN2OEUN2.js +0 -33
  137. package/dist/chunk-HN2OEUN2.js.map +0 -1
  138. package/dist/chunk-KBTTEX7Q.js +0 -497
  139. package/dist/chunk-KBTTEX7Q.js.map +0 -1
  140. package/dist/chunk-KQN2ZYND.cjs +0 -724
  141. package/dist/chunk-KQN2ZYND.cjs.map +0 -1
  142. package/dist/chunk-MPTVJIVG.cjs +0 -3176
  143. package/dist/chunk-MPTVJIVG.cjs.map +0 -1
  144. package/dist/chunk-MTMZTMWM.cjs +0 -53
  145. package/dist/chunk-MTMZTMWM.cjs.map +0 -1
  146. package/dist/chunk-N6IHQUOX.js +0 -1
  147. package/dist/chunk-NNB67XA2.js +0 -724
  148. package/dist/chunk-NNB67XA2.js.map +0 -1
  149. package/dist/chunk-OL3IHHSJ.cjs +0 -1204
  150. package/dist/chunk-OL3IHHSJ.cjs.map +0 -1
  151. package/dist/chunk-PI3UXRWK.cjs +0 -528
  152. package/dist/chunk-PI3UXRWK.cjs.map +0 -1
  153. package/dist/chunk-R2VVFAIN.js +0 -528
  154. package/dist/chunk-R2VVFAIN.js.map +0 -1
  155. package/dist/chunk-T64C7ZD7.cjs +0 -1
  156. package/dist/chunk-T64C7ZD7.cjs.map +0 -1
  157. package/dist/chunk-WFDXOLUB.cjs +0 -337
  158. package/dist/chunk-WFDXOLUB.cjs.map +0 -1
  159. package/dist/chunk-WTAN4ACG.cjs +0 -1548
  160. package/dist/chunk-WTAN4ACG.cjs.map +0 -1
  161. package/dist/chunk-YFJXS3AU.cjs +0 -33
  162. package/dist/chunk-YFJXS3AU.cjs.map +0 -1
  163. package/dist/chunk-YUE6TJ4M.js +0 -889
  164. package/dist/chunk-YUE6TJ4M.js.map +0 -1
  165. package/dist/chunk-ZGLJM4A4.js +0 -53
  166. package/dist/chunk-ZGLJM4A4.js.map +0 -1
  167. package/dist/function-CxixTB02.d.cts +0 -299
  168. package/dist/function-DTCt675z.d.ts +0 -299
  169. package/dist/index-B2Ulxxpo.d.cts +0 -144
  170. package/dist/index-BkYJ0xMq.d.cts +0 -152
  171. package/dist/index-BuaB-ypt.d.ts +0 -144
  172. package/dist/index-CAN7v-kw.d.ts +0 -199
  173. package/dist/index-COw1Ky9g.d.ts +0 -242
  174. package/dist/index-DRtIhlJj.d.ts +0 -152
  175. package/dist/index-DXd9JikN.d.cts +0 -246
  176. package/dist/index-DXd9JikN.d.ts +0 -246
  177. package/dist/index-alrRninU.d.cts +0 -199
  178. package/dist/index-oTQbYYIs.d.cts +0 -242
  179. package/dist/index-tR9jTn26.d.cts +0 -275
  180. package/dist/index-tR9jTn26.d.ts +0 -275
  181. package/dist/styled-Bl0ZK28h.d.ts +0 -543
  182. package/dist/styled-Crv6SA4S.d.cts +0 -543
  183. package/dist/types-BN6_Q9Kl.d.cts +0 -39
  184. package/dist/types-BN6_Q9Kl.d.ts +0 -39
  185. /package/dist/{chunk-N6IHQUOX.js.map → chunk-HFPS7JFD.js.map} +0 -0
@@ -1,144 +0,0 @@
1
- import { K as KeyScale } from './types-BN6_Q9Kl.js';
2
- import { C as Chord } from './index-COw1Ky9g.js';
3
-
4
- /**
5
- * Severity policy: `strict` counterpoint vs. lenient `pop` voice-leading.
6
- *
7
- * @category Arrangement & Analysis
8
- */
9
- type SafetyProfile = 'strict' | 'pop';
10
- /**
11
- * Overall placeability verdict for a candidate pitch.
12
- *
13
- * @category Arrangement & Analysis
14
- */
15
- declare enum NoteSafety {
16
- Safe = 0,
17
- Warning = 1,
18
- Dissonant = 2
19
- }
20
- /**
21
- * Bit flags describing why a pitch received its verdict.
22
- *
23
- * @category Arrangement & Analysis
24
- */
25
- declare enum ReasonFlag {
26
- ChordTone = 1,
27
- Tension = 2,
28
- AvoidNote = 4,
29
- ScaleTone = 8,
30
- NonScale = 16,
31
- OutOfRange = 32,
32
- Tritone = 64,
33
- LargeLeap = 128,
34
- MinorSecond = 256,
35
- MajorSeventh = 512,
36
- VerticalDissonance = 1024,
37
- ParallelPerfect = 2048,
38
- HiddenParallel = 4096,
39
- VoiceCrossing = 8192,
40
- Suspension = 16384,
41
- NeedsResolution = 32768,
42
- MelodicTritone = 65536
43
- }
44
- /**
45
- * A neighbouring voice's current and previous pitch.
46
- *
47
- * @category Arrangement & Analysis
48
- */
49
- type VoiceSnapshot = {
50
- pitch: number;
51
- prevPitch?: number;
52
- };
53
- /**
54
- * Everything needed to evaluate one candidate pitch.
55
- *
56
- * @category Arrangement & Analysis
57
- */
58
- type SafetyQuery = {
59
- profile: SafetyProfile;
60
- candidatePitch: number;
61
- prevPitch?: number;
62
- chord: Chord | null;
63
- key: KeyScale;
64
- otherVoices: VoiceSnapshot[];
65
- strongBeat: boolean;
66
- vocalLow?: number;
67
- vocalHigh?: number;
68
- };
69
- /**
70
- * The verdict, reason flags, and optional resolution guidance.
71
- *
72
- * @category Arrangement & Analysis
73
- */
74
- type SafetyResult = {
75
- safety: NoteSafety;
76
- reasons: number;
77
- resolveTo?: number;
78
- suggestions?: number[];
79
- rationale?: string;
80
- };
81
- /**
82
- * Evaluate the safety of placing a candidate pitch in a voice.
83
- *
84
- * Reasons are merged from harmonic context (chord tone / tension / avoid / scale)
85
- * and counterpoint (vertical dissonance, parallels, voice crossing). The `strict`
86
- * profile treats avoid notes and parallels as dissonant; `pop` treats them as
87
- * warnings. The final verdict is the worst severity among the reasons.
88
- *
89
- * @param q The candidate and its harmonic/voice-leading context.
90
- * @returns The verdict, reason bitmask, and optional resolution guidance.
91
- * @example
92
- * ```ts
93
- * import { evaluateSafety, makeChord, majorKey, NoteSafety } from '@libraz/libcantus';
94
- * const result = evaluateSafety({
95
- * profile: 'pop',
96
- * candidatePitch: 60, // C over a C major chord
97
- * chord: makeChord(0, 'maj'),
98
- * key: majorKey(0),
99
- * otherVoices: [],
100
- * strongBeat: true,
101
- * });
102
- * result.safety === NoteSafety.Safe; // true — C is a chord tone
103
- * ```
104
- * @category Arrangement & Analysis
105
- */
106
- declare function evaluateSafety(q: SafetyQuery, opts?: EvaluateSafetyOptions): SafetyResult;
107
- /**
108
- * Options for {@link evaluateSafety}.
109
- *
110
- * @category Arrangement & Analysis
111
- */
112
- type EvaluateSafetyOptions = {
113
- /**
114
- * Whether to search for safe replacement pitches when the verdict is not
115
- * safe. Turning it off skips up to two dozen extra evaluations per rejected
116
- * pitch, which is worth doing when only the verdict is wanted.
117
- *
118
- * @defaultValue true
119
- */
120
- suggestions?: boolean;
121
- };
122
- /**
123
- * Enumerate placeable pitches in a range, chord tones first, descending.
124
- *
125
- * @param q The safety context minus the candidate pitch.
126
- * @param pitchLow Lowest MIDI pitch to consider (inclusive).
127
- * @param pitchHigh Highest MIDI pitch to consider (inclusive).
128
- * @returns Placeable pitches (non-dissonant), chord tones before others, each group descending.
129
- * @throws If either bound is non-finite/non-integral, reversed, or exceeds the generation budget.
130
- * @example
131
- * ```ts
132
- * import { enumerateSafePitches, makeChord, majorKey } from '@libraz/libcantus';
133
- * const pitches = enumerateSafePitches(
134
- * { profile: 'pop', chord: makeChord(0, 'maj'), key: majorKey(0), otherVoices: [], strongBeat: true },
135
- * 60,
136
- * 72,
137
- * );
138
- * pitches; // placeable pitches in [60, 72], chord tones first, each group descending
139
- * ```
140
- * @category Arrangement & Analysis
141
- */
142
- declare function enumerateSafePitches(q: Omit<SafetyQuery, 'candidatePitch'>, pitchLow: number, pitchHigh: number): number[];
143
-
144
- export { type EvaluateSafetyOptions as E, NoteSafety as N, ReasonFlag as R, type SafetyProfile as S, type VoiceSnapshot as V, type SafetyQuery as a, type SafetyResult as b, evaluateSafety as c, enumerateSafePitches as e };
@@ -1,199 +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-COw1Ky9g.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
- * Upper bound on the input pitches processed by this detection call.
97
- *
98
- * @defaultValue {@link DEFAULT_GENERATION_BUDGET}
99
- */
100
- budget?: number;
101
- };
102
- /**
103
- * Identify chords matching a set of pitches.
104
- *
105
- * Every input pitch class is tried as a root against every known chord quality.
106
- * A match is reported when all of the chord's tones are present in the input, or
107
- * when the only absent tone is the perfect fifth (a common omission in shell
108
- * voicings); matches are ranked best-first by fewest extra notes, then fewest
109
- * missing notes, then most specific (largest) chord. An exact match (no extras,
110
- * no missing) is flagged and ranked first.
111
- *
112
- * @param pitches MIDI pitches or bare pitch classes (octave-agnostic).
113
- * @returns Ranked chord interpretations (may be empty).
114
- * @example
115
- * ```ts
116
- * import { detectChord } from '@libraz/libcantus';
117
- * const matches = detectChord([60, 64, 67]); // C E G
118
- * matches[0]; // { rootPc: 0, quality: 'maj', exact: true, ... }
119
- * ```
120
- * @category Recognition
121
- */
122
- declare function detectChord(pitches: readonly number[], opts?: DetectChordOptions): ChordMatch[];
123
- /**
124
- * The single best chord interpretation of a pitch set, or null if none.
125
- *
126
- * @param pitches MIDI pitches or bare pitch classes.
127
- * @returns The top-ranked chord, or null when nothing matches.
128
- * @example
129
- * ```ts
130
- * import { detectChordBest } from '@libraz/libcantus';
131
- * detectChordBest([60, 64, 67]); // C major triad: { rootPc: 0, quality: 'maj', ... }
132
- * ```
133
- * @category Recognition
134
- */
135
- declare function detectChordBest(pitches: readonly number[], opts?: DetectChordOptions): Chord | null;
136
- /**
137
- * Rank major and minor keys by how well they contain a set of pitch classes.
138
- *
139
- * Ranking is by `score`, which counts repetitions and adds a tonic weight so
140
- * that, among equally-fitting keys, the one whose root is actually sounded is
141
- * preferred. Minor candidates are scored against the natural, harmonic, and
142
- * melodic minor variants and keep the best of the three, so a minor cadence
143
- * containing the leading tone still resolves to its own tonic; the winning
144
- * variant is what `key` and `variant` report, so `fit` describes the scale the
145
- * caller receives. Returns all 24 keys ranked best-first, or an empty array for
146
- * an empty input (mirroring {@link detectChord}).
147
- *
148
- * @param pitches MIDI pitches or bare pitch classes.
149
- * @returns Ranked key interpretations (empty for an empty input).
150
- * @example
151
- * ```ts
152
- * import { detectKey } from '@libraz/libcantus';
153
- * const keys = detectKey([60, 62, 64, 65, 67, 69, 71]); // C major scale
154
- * keys[0].mode; // 'major', with keys[0].key.rootPc === 0
155
- * ```
156
- * @category Recognition
157
- */
158
- declare function detectKey(pitches: readonly number[], opts?: DetectKeyOptions): KeyMatch[];
159
- /**
160
- * Rank keys by how well they contain a set of note events, weighting each note
161
- * by how much of the music it actually occupies.
162
- *
163
- * {@link detectKey} counts every pitch once, which lets a run of fast ornamental
164
- * notes outvote the sustained harmony that establishes the key. This weighs
165
- * each note by duration times velocity, the same measure chord inference uses,
166
- * so the two agree on what the music emphasises. Notes that never sound (zero
167
- * or negative duration) are ignored.
168
- *
169
- * @param notes The note events to weigh.
170
- * @param opts Budget for processing imported note events.
171
- * @returns Ranked key interpretations (empty when nothing sounds).
172
- * @example
173
- * ```ts
174
- * import { detectKeyFromNotes } from '@libraz/libcantus';
175
- * detectKeyFromNotes([{ pitch: 60, startBeat: 0, durationBeat: 4 }])[0]?.key.rootPc; // 0
176
- * ```
177
- * @category Recognition
178
- */
179
- declare function detectKeyFromNotes(notes: readonly NoteEvent[], opts?: Omit<DetectKeyOptions, 'weights'>): KeyMatch[];
180
- /**
181
- * The single best key interpretation of a pitch set.
182
- *
183
- * The counterpart of {@link detectChordBest}: the ranked list is the general
184
- * answer, but a caller that just wants "what key is this" should not have to
185
- * index into it and assert the result is there.
186
- *
187
- * @param pitches MIDI pitches or bare pitch classes.
188
- * @param opts How to weigh the input; see {@link DetectKeyOptions}.
189
- * @returns The top-ranked key, or null when nothing sounds.
190
- * @example
191
- * ```ts
192
- * import { detectKeyBest } from '@libraz/libcantus';
193
- * detectKeyBest([0, 2, 4, 5, 7, 9, 11])?.mode; // 'major'
194
- * ```
195
- * @category Recognition
196
- */
197
- declare function detectKeyBest(pitches: readonly number[], opts?: DetectKeyOptions): KeyMatch | null;
198
-
199
- 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,242 +0,0 @@
1
- import { K as KeyScale } from './types-BN6_Q9Kl.js';
2
-
3
- /**
4
- * Chord quality identifiers understood by the chord builder.
5
- *
6
- * @category Chords
7
- */
8
- type ChordQuality = 'maj' | 'min' | 'dim' | 'aug' | 'maj7' | 'min7' | 'dom7' | 'dim7' | 'm7b5' | 'minMaj7' | 'minMaj9' | 'minMaj11' | 'minMaj13' | 'aug7' | 'augMaj7' | 'majb5' | '6' | 'min6' | '6/9' | 'sus2' | 'sus4' | 'add9' | 'add11' | 'maj9' | 'min9' | 'dom9' | '7b9' | '7#9' | '7#11' | '7b13' | '11' | '13' | '5' | '7sus4' | '7b5' | '7alt' | '13b9' | 'maj13' | 'maj7#11' | 'min11' | 'min13' | 'minAdd9' | 'min6/9';
9
- /**
10
- * The basic role a chord tone plays: the degrees a chord's own template names.
11
- *
12
- * The shared vocabulary behind {@link chordToneRole}, the harmony layer's
13
- * `HarmonyRole`, and the voice analyser's labels, so the three cannot drift.
14
- *
15
- * @category Chords
16
- */
17
- type ChordToneRole = 'root' | 'third' | 'fifth' | 'sixth' | 'seventh';
18
- /**
19
- * A bare spelled pitch used as an enharmonic hint: a diatonic letter
20
- * (0..6 = C..B) plus a chromatic alteration (-2 double-flat .. +2 double-sharp).
21
- * Mirrors the letter/alter half of the pitch module's `Note` without an octave.
22
- *
23
- * @category Chords
24
- */
25
- type PitchSpelling = {
26
- letter: number;
27
- alter: number;
28
- };
29
- /**
30
- * A chord expressed as a root pitch class plus semitone offsets.
31
- *
32
- * `rootSpelling`/`bassSpelling` are optional enharmonic hints recorded by
33
- * parsers (e.g. `parseChordSymbol('Bb7')`) so formatters can reproduce the
34
- * original spelling instead of defaulting to sharps. Consumers may ignore
35
- * them; a hint is only trusted when its pitch class still matches the
36
- * corresponding `rootPc`/`bassPc`.
37
- *
38
- * @category Chords
39
- */
40
- type Chord = {
41
- rootPc: number;
42
- quality: ChordQuality;
43
- intervals: number[];
44
- bassPc?: number;
45
- rootSpelling?: PitchSpelling;
46
- bassSpelling?: PitchSpelling;
47
- };
48
- /**
49
- * A chord positioned in time: a root pitch class and quality placed at a beat,
50
- * with optional harmonic-analysis hints. Serves as the neutral exchange record
51
- * between progression generators and timeline analysers.
52
- *
53
- * @category Composition
54
- */
55
- type ChordSpan = {
56
- rootPc: number;
57
- quality: ChordQuality;
58
- startBeat: number;
59
- bassPc?: number;
60
- /** 0-based scale degree of the chord root, when known. */
61
- degree?: number;
62
- /** True when the chord is a secondary dominant tonicizing another degree. */
63
- secondaryDominant?: boolean;
64
- };
65
- /**
66
- * A chord occupying a half-open beat span `[startBeat, endBeat)`.
67
- *
68
- * The exchange record between anything that lays chords out in time — a
69
- * timeline analysis, a bass-line plan, an accompaniment generator — so those
70
- * surfaces share one definition instead of agreeing by coincidence.
71
- *
72
- * @category Composition
73
- */
74
- type ChordSegment = {
75
- startBeat: number;
76
- endBeat: number;
77
- chord: Chord;
78
- };
79
- /**
80
- * All chord qualities the builder understands, in declaration order.
81
- *
82
- * The order is stable but carries no meaning: it is neither alphabetical nor
83
- * sorted by template size. {@link detectChord} uses it as its final tie-break,
84
- * so it is part of the observable behaviour and does not get reshuffled
85
- * casually — but do not read it as a ranking.
86
- *
87
- * @category Chords
88
- */
89
- declare function chordQualities(): ChordQuality[];
90
- /**
91
- * Build a chord rooted on a diatonic scale degree.
92
- *
93
- * The root pitch class is the degree's diatonic pitch class in `key`; the
94
- * quality's interval template is attached unchanged. Degrees beyond the scale
95
- * length wrap around.
96
- *
97
- * @param degree 0-based scale degree of the chord root.
98
- * @param ext Chord quality to apply.
99
- * @param key Key context supplying the diatonic root.
100
- * @returns The constructed chord.
101
- *
102
- * @category Chords
103
- */
104
- declare function chordFromDegree(degree: number, ext: ChordQuality, key: KeyScale): Chord;
105
- /**
106
- * Build a chord from an explicit root pitch class and quality.
107
- *
108
- * @param rootPc Root pitch class (0..11).
109
- * @param quality Chord quality supplying the interval template.
110
- * @param bassPc Optional slash-chord bass pitch class.
111
- * @returns The constructed chord.
112
- *
113
- * @example
114
- * ```ts
115
- * import { makeChord } from '@libraz/libcantus';
116
- * const cmaj7 = makeChord(0, 'maj7');
117
- * // { rootPc: 0, quality: 'maj7', intervals: [0, 4, 7, 11] }
118
- * ```
119
- *
120
- * @category Chords
121
- */
122
- declare function makeChord(rootPc: number, quality: ChordQuality, bassPc?: number): Chord;
123
- /**
124
- * Transpose a chord by a number of semitones.
125
- *
126
- * The interval template is carried over untouched, so a chord whose intervals
127
- * were customised keeps them, and a slash bass moves with the root. Enharmonic
128
- * spelling hints are dropped rather than shifted: the letter a transposed root
129
- * should take depends on the destination key, which a semitone count does not
130
- * carry. Pass the result through {@link spellChord} to respell it.
131
- *
132
- * @param chord The chord to transpose.
133
- * @param semitones The signed semitone offset.
134
- * @returns The transposed chord.
135
- * @throws If `semitones` is not finite.
136
- *
137
- * @example
138
- * ```ts
139
- * import { formatChordSymbol, parseChordSymbol, transposeChord } from '@libraz/libcantus';
140
- * formatChordSymbol(transposeChord(parseChordSymbol('C/G'), 2)); // 'D/A'
141
- * ```
142
- *
143
- * @category Chords
144
- */
145
- declare function transposeChord(chord: Chord, semitones: number): Chord;
146
- /**
147
- * Get the sorted, deduplicated pitch classes of a chord.
148
- *
149
- * A slash bass is one of them: `F/G` sounds a G, the voicers put it in the
150
- * bass, and a set that omitted it would not re-detect as the chord it came
151
- * from. Pass `includeBass: false` to enumerate the interval template alone.
152
- *
153
- * @param chord The chord to enumerate.
154
- * @param opts Set `includeBass: false` to omit a slash bass.
155
- * @returns The chord's pitch classes, sorted ascending in [0, 11].
156
- *
157
- * @example
158
- * ```ts
159
- * import { makeChord, chordPitchClasses } from '@libraz/libcantus';
160
- * chordPitchClasses(makeChord(0, 'maj7')); // [0, 4, 7, 11]
161
- * chordPitchClasses(makeChord(5, 'maj', 7)); // [0, 5, 7, 9] — F/G, G included
162
- * ```
163
- *
164
- * @category Chords
165
- */
166
- declare function chordPitchClasses(chord: Chord, opts?: {
167
- includeBass?: boolean;
168
- }): number[];
169
- /**
170
- * A pitch's interval class above the chord root, in [0, 11].
171
- *
172
- * The shared reading of "where does this pitch sit in the chord", used by the
173
- * safety evaluator and the voice analyser alike so they cannot disagree.
174
- *
175
- * @param pitch MIDI pitch or bare pitch class.
176
- * @param chord The chord providing the root reference.
177
- * @returns The interval class above the root.
178
- * @category Chords
179
- */
180
- declare function intervalAboveRoot(pitch: number, chord: Chord): number;
181
- /**
182
- * Whether a pitch is one of a chord's tones, ignoring octave.
183
- *
184
- * @param pitch MIDI pitch or bare pitch class.
185
- * @param chord The chord, or null for no sounding harmony.
186
- * @returns True when the pitch class belongs to the chord.
187
- * @category Chords
188
- */
189
- declare function isChordMember(pitch: number, chord: Chord | null): boolean;
190
- /**
191
- * Determine a pitch's harmonic role within a chord.
192
- *
193
- * The role is derived from the pitch's interval above the chord root, reduced
194
- * modulo 12. A major sixth (9) reads as a `sixth` for sixth chords but as a
195
- * `seventh` for a diminished-seventh chord; ninths and other tensions have no
196
- * basic role and return null.
197
- *
198
- * @param pitch MIDI pitch or bare pitch class.
199
- * @param chord The chord providing the root reference.
200
- * @returns The chord-tone role, or null if the pitch has no basic role.
201
- *
202
- * @category Chords
203
- */
204
- declare function chordToneRole(pitch: number, chord: Chord): ChordToneRole | null;
205
- /**
206
- * Build the diatonic triad rooted on a scale degree by stacking scale thirds.
207
- *
208
- * Unlike {@link chordFromDegree}, the chord quality is derived from the scale
209
- * rather than supplied, so degrees yield their scale-correct triads (e.g. a
210
- * diminished triad on the leading tone of a major key).
211
- *
212
- * @param degree 0-based scale degree of the chord root.
213
- * @param key Key/scale context.
214
- * @returns The diatonic triad.
215
- * @throws If the scale is not heptatonic. Stacking thirds means skipping every
216
- * other degree, which only lands on a triad when there are seven of them, so
217
- * the pentatonic, blues, whole-tone, octatonic and chromatic scales have no
218
- * diatonic triad; use {@link chordFromDegree} with an explicit quality there.
219
- *
220
- * @example
221
- * ```ts
222
- * import { majorKey, diatonicTriad } from '@libraz/libcantus';
223
- * const tonic = diatonicTriad(0, majorKey(0)); // C major triad (degree 0 of C major)
224
- * ```
225
- *
226
- * @category Chords
227
- */
228
- declare function diatonicTriad(degree: number, key: KeyScale): Chord;
229
- /**
230
- * Build the diatonic seventh chord rooted on a scale degree.
231
- *
232
- * @param degree 0-based scale degree of the chord root.
233
- * @param key Key/scale context.
234
- * @returns The diatonic seventh chord.
235
- * @throws If the scale is not heptatonic, for the reason given on
236
- * {@link diatonicTriad}.
237
- *
238
- * @category Chords
239
- */
240
- declare function diatonicSeventh(degree: number, key: KeyScale): Chord;
241
-
242
- export { type Chord as C, type PitchSpelling as P, type ChordQuality as a, type ChordSegment as b, type ChordSpan as c, type ChordToneRole as d, chordFromDegree as e, chordPitchClasses as f, chordQualities as g, chordToneRole as h, diatonicSeventh as i, diatonicTriad as j, intervalAboveRoot as k, isChordMember as l, makeChord as m, transposeChord as t };