@libraz/libcantus 0.9.3 → 0.9.5

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 (201) hide show
  1. package/README.md +29 -20
  2. package/README_ja.md +268 -0
  3. package/dist/analyze/index.cjs +39 -1947
  4. package/dist/analyze/index.cjs.map +1 -1
  5. package/dist/analyze/index.d.cts +161 -91
  6. package/dist/analyze/index.d.ts +161 -91
  7. package/dist/analyze/index.js +19 -8
  8. package/dist/chunk-2A2QMA74.cjs +261 -0
  9. package/dist/chunk-2A2QMA74.cjs.map +1 -0
  10. package/dist/chunk-2PTFGVD7.js +261 -0
  11. package/dist/chunk-2PTFGVD7.js.map +1 -0
  12. package/dist/chunk-357ZDPVU.cjs +162 -0
  13. package/dist/chunk-357ZDPVU.cjs.map +1 -0
  14. package/dist/chunk-3KX76RLG.js +1548 -0
  15. package/dist/chunk-3KX76RLG.js.map +1 -0
  16. package/dist/chunk-4VZ5MZAM.cjs +889 -0
  17. package/dist/chunk-4VZ5MZAM.cjs.map +1 -0
  18. package/dist/{chunk-C5XYKUVG.js → chunk-7EONYVI5.js} +471 -171
  19. package/dist/chunk-7EONYVI5.js.map +1 -0
  20. package/dist/{chunk-IT2O4XFE.js → chunk-7JEP3MFY.js} +42 -34
  21. package/dist/chunk-7JEP3MFY.js.map +1 -0
  22. package/dist/{chunk-4MHA432G.js → chunk-AID75RN3.js} +572 -250
  23. package/dist/chunk-AID75RN3.js.map +1 -0
  24. package/dist/chunk-BSLTLGM3.cjs +497 -0
  25. package/dist/chunk-BSLTLGM3.cjs.map +1 -0
  26. package/dist/chunk-CU6VG2YM.cjs +109 -0
  27. package/dist/chunk-CU6VG2YM.cjs.map +1 -0
  28. package/dist/{chunk-EH6EM37U.js → chunk-DZMHIGI4.js} +81 -59
  29. package/dist/chunk-DZMHIGI4.js.map +1 -0
  30. package/dist/{chunk-AKLYPWIN.js → chunk-EDOTEABK.js} +45 -19
  31. package/dist/chunk-EDOTEABK.js.map +1 -0
  32. package/dist/{chunk-2ZWMSJH6.js → chunk-HN2OEUN2.js} +7 -4
  33. package/dist/chunk-HN2OEUN2.js.map +1 -0
  34. package/dist/{chunk-MIWO425M.js → chunk-KBTTEX7Q.js} +128 -43
  35. package/dist/chunk-KBTTEX7Q.js.map +1 -0
  36. package/dist/chunk-KQN2ZYND.cjs +724 -0
  37. package/dist/chunk-KQN2ZYND.cjs.map +1 -0
  38. package/dist/chunk-MPTVJIVG.cjs +3176 -0
  39. package/dist/chunk-MPTVJIVG.cjs.map +1 -0
  40. package/dist/chunk-MTMZTMWM.cjs +53 -0
  41. package/dist/chunk-MTMZTMWM.cjs.map +1 -0
  42. package/dist/{chunk-CHMXELDS.js → chunk-NNB67XA2.js} +372 -197
  43. package/dist/chunk-NNB67XA2.js.map +1 -0
  44. package/dist/chunk-OL3IHHSJ.cjs +1204 -0
  45. package/dist/chunk-OL3IHHSJ.cjs.map +1 -0
  46. package/dist/chunk-PI3UXRWK.cjs +528 -0
  47. package/dist/chunk-PI3UXRWK.cjs.map +1 -0
  48. package/dist/chunk-R2VVFAIN.js +528 -0
  49. package/dist/chunk-R2VVFAIN.js.map +1 -0
  50. package/dist/chunk-T64C7ZD7.cjs +1 -0
  51. package/dist/chunk-T64C7ZD7.cjs.map +1 -0
  52. package/dist/chunk-WFDXOLUB.cjs +337 -0
  53. package/dist/chunk-WFDXOLUB.cjs.map +1 -0
  54. package/dist/chunk-WTAN4ACG.cjs +1548 -0
  55. package/dist/chunk-WTAN4ACG.cjs.map +1 -0
  56. package/dist/chunk-YFJXS3AU.cjs +33 -0
  57. package/dist/chunk-YFJXS3AU.cjs.map +1 -0
  58. package/dist/{chunk-GOAW4VYL.js → chunk-YUE6TJ4M.js} +315 -145
  59. package/dist/chunk-YUE6TJ4M.js.map +1 -0
  60. package/dist/{chunk-62QZKCJQ.js → chunk-ZGLJM4A4.js} +10 -6
  61. package/dist/chunk-ZGLJM4A4.js.map +1 -0
  62. package/dist/core/index.cjs +140 -647
  63. package/dist/core/index.cjs.map +1 -1
  64. package/dist/core/index.d.cts +313 -41
  65. package/dist/core/index.d.ts +313 -41
  66. package/dist/core/index.js +64 -16
  67. package/dist/{function-DVH4Eusr.d.ts → function-CxixTB02.d.cts} +122 -10
  68. package/dist/{function-DYt4iKsn.d.cts → function-DTCt675z.d.ts} +122 -10
  69. package/dist/generate/index.cjs +28 -4085
  70. package/dist/generate/index.cjs.map +1 -1
  71. package/dist/generate/index.d.cts +374 -66
  72. package/dist/generate/index.d.ts +374 -66
  73. package/dist/generate/index.js +23 -9
  74. package/dist/{index-Jc0Ryi79.d.ts → index-B2Ulxxpo.d.cts} +21 -5
  75. package/dist/{index-CpOsP1y9.d.cts → index-BkYJ0xMq.d.cts} +18 -17
  76. package/dist/{index-CxqBQtH1.d.cts → index-BuaB-ypt.d.ts} +21 -5
  77. package/dist/index-CAN7v-kw.d.ts +199 -0
  78. package/dist/{index-Bt4tOUD9.d.ts → index-COw1Ky9g.d.ts} +93 -8
  79. package/dist/{index-Dikst44v.d.cts → index-Cfx8xgH0.d.ts} +14 -11
  80. package/dist/{index-DxvARIP2.d.ts → index-DRtIhlJj.d.ts} +18 -17
  81. package/dist/{index-Cl7mhOFM.d.cts → index-DXd9JikN.d.cts} +92 -10
  82. package/dist/{index-Cl7mhOFM.d.ts → index-DXd9JikN.d.ts} +92 -10
  83. package/dist/index-alrRninU.d.cts +199 -0
  84. package/dist/{index-BNlGP86A.d.cts → index-oTQbYYIs.d.cts} +93 -8
  85. package/dist/index-tR9jTn26.d.cts +275 -0
  86. package/dist/index-tR9jTn26.d.ts +275 -0
  87. package/dist/{index-Bg5dYMmZ.d.ts → index-x2vcsduE.d.cts} +14 -11
  88. package/dist/index.cjs +429 -7383
  89. package/dist/index.cjs.map +1 -1
  90. package/dist/index.d.cts +15 -15
  91. package/dist/index.d.ts +15 -15
  92. package/dist/index.js +121 -27
  93. package/dist/model/index.cjs +8 -2562
  94. package/dist/model/index.cjs.map +1 -1
  95. package/dist/model/index.d.cts +471 -81
  96. package/dist/model/index.d.ts +471 -81
  97. package/dist/model/index.js +6 -7
  98. package/dist/styled-Bl0ZK28h.d.ts +543 -0
  99. package/dist/styled-Crv6SA4S.d.cts +543 -0
  100. package/dist/theory/index.cjs +172 -1822
  101. package/dist/theory/index.cjs.map +1 -1
  102. package/dist/theory/index.d.cts +151 -233
  103. package/dist/theory/index.d.ts +151 -233
  104. package/dist/theory/index.js +30 -7
  105. package/dist/{types-MGP29r3t.d.cts → types-BN6_Q9Kl.d.cts} +11 -2
  106. package/dist/{types-MGP29r3t.d.ts → types-BN6_Q9Kl.d.ts} +11 -2
  107. package/package.json +34 -13
  108. package/dist/chunk-2ZWMSJH6.js.map +0 -1
  109. package/dist/chunk-4MHA432G.js.map +0 -1
  110. package/dist/chunk-62QZKCJQ.js.map +0 -1
  111. package/dist/chunk-AKLYPWIN.js.map +0 -1
  112. package/dist/chunk-C5XYKUVG.js.map +0 -1
  113. package/dist/chunk-CHMXELDS.js.map +0 -1
  114. package/dist/chunk-DYWFNC4A.js +0 -152
  115. package/dist/chunk-DYWFNC4A.js.map +0 -1
  116. package/dist/chunk-EH6EM37U.js.map +0 -1
  117. package/dist/chunk-FBQK3ZQN.js +0 -131
  118. package/dist/chunk-FBQK3ZQN.js.map +0 -1
  119. package/dist/chunk-GOAW4VYL.js.map +0 -1
  120. package/dist/chunk-I5R7ZBJS.js +0 -202
  121. package/dist/chunk-I5R7ZBJS.js.map +0 -1
  122. package/dist/chunk-IT2O4XFE.js.map +0 -1
  123. package/dist/chunk-MIWO425M.js.map +0 -1
  124. package/dist/chunk-SGU7SPLK.js +0 -924
  125. package/dist/chunk-SGU7SPLK.js.map +0 -1
  126. package/dist/index-CGMZNCx6.d.cts +0 -140
  127. package/dist/index-CGMZNCx6.d.ts +0 -140
  128. package/dist/index-CnZCo29u.d.cts +0 -108
  129. package/dist/index-JnF4v9bx.d.ts +0 -108
  130. package/dist/styled-DZ7GjShb.d.ts +0 -282
  131. package/dist/styled-ZTbdaVFM.d.cts +0 -282
  132. package/src/analyze/arrange/index.ts +0 -21
  133. package/src/analyze/arrange/internal.ts +0 -127
  134. package/src/analyze/arrange/tension.ts +0 -199
  135. package/src/analyze/arrange/tracks.ts +0 -312
  136. package/src/analyze/detect/index.ts +0 -272
  137. package/src/analyze/functional/borrowed.ts +0 -84
  138. package/src/analyze/functional/cadence.ts +0 -66
  139. package/src/analyze/functional/function.ts +0 -184
  140. package/src/analyze/functional/index.ts +0 -23
  141. package/src/analyze/functional/internal.ts +0 -29
  142. package/src/analyze/functional/roman.ts +0 -402
  143. package/src/analyze/index.ts +0 -49
  144. package/src/analyze/timeline/index.ts +0 -451
  145. package/src/analyze/voice/index.ts +0 -339
  146. package/src/core/event-index/index.ts +0 -104
  147. package/src/core/index.ts +0 -61
  148. package/src/core/interval/index.ts +0 -81
  149. package/src/core/meter/index.ts +0 -302
  150. package/src/core/pitch/index.ts +0 -311
  151. package/src/core/random/index.ts +0 -76
  152. package/src/core/tuning/index.ts +0 -186
  153. package/src/core/types.ts +0 -29
  154. package/src/core/validation/index.ts +0 -119
  155. package/src/generate/bass/index.ts +0 -373
  156. package/src/generate/countermelody/index.ts +0 -470
  157. package/src/generate/drums/beat.ts +0 -266
  158. package/src/generate/drums/euclid.ts +0 -65
  159. package/src/generate/drums/fills.ts +0 -356
  160. package/src/generate/drums/ghost.ts +0 -119
  161. package/src/generate/drums/hihat.ts +0 -285
  162. package/src/generate/drums/hit.ts +0 -31
  163. package/src/generate/drums/index.ts +0 -361
  164. package/src/generate/drums/internal.ts +0 -257
  165. package/src/generate/drums/kick.ts +0 -160
  166. package/src/generate/drums/percussion.ts +0 -121
  167. package/src/generate/drums/rng.ts +0 -7
  168. package/src/generate/drums/swing.ts +0 -71
  169. package/src/generate/groove/index.ts +0 -351
  170. package/src/generate/harmonize/index.ts +0 -451
  171. package/src/generate/index.ts +0 -58
  172. package/src/generate/motif/index.ts +0 -422
  173. package/src/generate/progression/index.ts +0 -362
  174. package/src/generate/reharmony/index.ts +0 -323
  175. package/src/generate/rhythm/index.ts +0 -175
  176. package/src/index.ts +0 -13
  177. package/src/model/chord.ts +0 -442
  178. package/src/model/index.ts +0 -15
  179. package/src/model/interval.ts +0 -82
  180. package/src/model/key.ts +0 -266
  181. package/src/model/note.ts +0 -176
  182. package/src/model/progression.ts +0 -161
  183. package/src/model/shared.ts +0 -12
  184. package/src/theory/chord/index.ts +0 -375
  185. package/src/theory/chordscale/index.ts +0 -374
  186. package/src/theory/counterpoint/index.ts +0 -230
  187. package/src/theory/harmony/index.ts +0 -77
  188. package/src/theory/index.ts +0 -112
  189. package/src/theory/safety/index.ts +0 -488
  190. package/src/theory/scale/degrees.ts +0 -123
  191. package/src/theory/scale/index.ts +0 -28
  192. package/src/theory/scale/key.ts +0 -56
  193. package/src/theory/scale/masks.ts +0 -153
  194. package/src/theory/spelling/index.ts +0 -249
  195. package/src/theory/symbol/index.ts +0 -268
  196. package/src/theory/voicing/index.ts +0 -5
  197. package/src/theory/voicing/internal.ts +0 -168
  198. package/src/theory/voicing/leading.ts +0 -112
  199. package/src/theory/voicing/satb.ts +0 -216
  200. package/src/theory/voicing/styled.ts +0 -199
  201. package/tsconfig.json +0 -23
@@ -0,0 +1,724 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
2
+
3
+
4
+
5
+
6
+
7
+
8
+
9
+
10
+
11
+
12
+ var _chunkBSLTLGM3cjs = require('./chunk-BSLTLGM3.cjs');
13
+
14
+
15
+
16
+
17
+
18
+
19
+
20
+
21
+ var _chunkPI3UXRWKcjs = require('./chunk-PI3UXRWK.cjs');
22
+
23
+ // src/analyze/detect/index.ts
24
+ function uniquePitchClasses(pitches) {
25
+ return [...new Set(pitches.map(_chunkPI3UXRWKcjs.pitchClassOf))].sort((a, b) => a - b);
26
+ }
27
+ function assertPitches(pitches, name, budget = void 0) {
28
+ _chunkPI3UXRWKcjs.assertGenerationBudget.call(void 0, pitches.length, name, budget);
29
+ for (let index = 0; index < pitches.length; index += 1) {
30
+ _chunkPI3UXRWKcjs.assertMidiPitch.call(void 0, _nullishCoalesce(pitches[index], () => ( Number.NaN)), `pitches[${index}]`);
31
+ }
32
+ }
33
+ function detectChord(pitches, opts = {}) {
34
+ assertPitches(pitches, "chord detection pitches");
35
+ if (opts.bassPc !== void 0) _chunkPI3UXRWKcjs.assertFiniteNumber.call(void 0, opts.bassPc, "bassPc");
36
+ const input = uniquePitchClasses(pitches);
37
+ if (input.length === 0) {
38
+ return [];
39
+ }
40
+ const inputKind = opts.input === void 0 || opts.input === "auto" ? pitches.every((pitch) => Number.isInteger(pitch) && pitch >= 0 && pitch <= 11) ? "pitchClass" : "midi" : opts.input;
41
+ const bassPc = opts.bassPc !== void 0 ? _chunkPI3UXRWKcjs.pitchClassOf.call(void 0, opts.bassPc) : inputKind === "midi" ? _chunkPI3UXRWKcjs.pitchClassOf.call(void 0, pitches.reduce((lowest, pitch) => Math.min(lowest, pitch), Infinity)) : void 0;
42
+ const inputSet = new Set(input);
43
+ const matches = [];
44
+ const qualities = _chunkBSLTLGM3cjs.chordQualities.call(void 0, );
45
+ const toneCounts = new Map(
46
+ qualities.map((quality) => [quality, _chunkBSLTLGM3cjs.chordPitchClasses.call(void 0, _chunkBSLTLGM3cjs.makeChord.call(void 0, 0, quality)).length])
47
+ );
48
+ for (const rootPc of input) {
49
+ for (const quality of qualities) {
50
+ const chord = _chunkBSLTLGM3cjs.makeChord.call(void 0, rootPc, quality);
51
+ const tones = _chunkBSLTLGM3cjs.chordPitchClasses.call(void 0, chord);
52
+ const toneSet = new Set(tones);
53
+ const missingPcs = tones.filter((pc) => !inputSet.has(pc));
54
+ const fifthPc = _chunkPI3UXRWKcjs.pitchClassOf.call(void 0, rootPc + 7);
55
+ if (missingPcs.length > 1 || missingPcs.length === 1 && missingPcs[0] !== fifthPc) {
56
+ continue;
57
+ }
58
+ const extraPcs = input.filter((pc) => !toneSet.has(pc));
59
+ const bassIndex = bassPc === void 0 ? -1 : chord.intervals.findIndex((iv) => _chunkPI3UXRWKcjs.pitchClassOf.call(void 0, rootPc + iv) === bassPc);
60
+ const inversion = bassPc === void 0 || bassIndex < 0 ? null : bassIndex;
61
+ const match = {
62
+ rootPc,
63
+ quality,
64
+ missingPcs,
65
+ extraPcs,
66
+ exact: extraPcs.length === 0 && missingPcs.length === 0,
67
+ inversion
68
+ };
69
+ if (bassPc !== void 0 && bassPc !== rootPc) {
70
+ match.bassPc = bassPc;
71
+ }
72
+ matches.push(match);
73
+ }
74
+ }
75
+ matches.sort((a, b) => {
76
+ if (a.extraPcs.length !== b.extraPcs.length) {
77
+ return a.extraPcs.length - b.extraPcs.length;
78
+ }
79
+ if (a.missingPcs.length !== b.missingPcs.length) {
80
+ return a.missingPcs.length - b.missingPcs.length;
81
+ }
82
+ if (a.inversion === 0 !== (b.inversion === 0)) {
83
+ return a.inversion === 0 ? -1 : 1;
84
+ }
85
+ const aSize = _nullishCoalesce(toneCounts.get(a.quality), () => ( 0));
86
+ const bSize = _nullishCoalesce(toneCounts.get(b.quality), () => ( 0));
87
+ return bSize - aSize;
88
+ });
89
+ return matches;
90
+ }
91
+ function detectChordBest(pitches, opts = {}) {
92
+ const best = detectChord(pitches, opts)[0];
93
+ if (!best) {
94
+ return null;
95
+ }
96
+ return _chunkBSLTLGM3cjs.makeChord.call(void 0, best.rootPc, best.quality, best.bassPc);
97
+ }
98
+ var MINOR_VARIANTS = [
99
+ { variant: "natural", mask: _chunkBSLTLGM3cjs.NATURAL_MINOR_MASK },
100
+ { variant: "harmonic", mask: _chunkBSLTLGM3cjs.HARMONIC_MINOR_MASK },
101
+ { variant: "melodic", mask: _chunkBSLTLGM3cjs.MELODIC_MINOR_MASK }
102
+ ];
103
+ var MAJOR_VARIANTS = [{ variant: "major", mask: _chunkBSLTLGM3cjs.MAJOR_MASK }];
104
+ function detectKey(pitches, opts = {}) {
105
+ assertPitches(pitches, "key detection pitches", opts.budget);
106
+ const weights = opts.weights;
107
+ if (weights !== void 0 && weights.length !== pitches.length) {
108
+ throw new (0, _chunkPI3UXRWKcjs.InvalidInputError)("weights must have one entry per pitch");
109
+ }
110
+ const counts = /* @__PURE__ */ new Map();
111
+ let total = 0;
112
+ for (let index = 0; index < pitches.length; index += 1) {
113
+ const weight = weights === void 0 ? 1 : _nullishCoalesce(weights[index], () => ( 0));
114
+ _chunkPI3UXRWKcjs.assertFiniteNumber.call(void 0, weight, `weights[${index}]`);
115
+ if (weight <= 0) {
116
+ continue;
117
+ }
118
+ const pc = _chunkPI3UXRWKcjs.pitchClassOf.call(void 0, _nullishCoalesce(pitches[index], () => ( 0)));
119
+ counts.set(pc, (_nullishCoalesce(counts.get(pc), () => ( 0))) + weight);
120
+ total += weight;
121
+ }
122
+ if (total === 0) {
123
+ return [];
124
+ }
125
+ const input = [...counts.keys()];
126
+ const results = [];
127
+ for (let tonic = 0; tonic < 12; tonic += 1) {
128
+ for (const mode of ["major", "minor"]) {
129
+ const variants = mode === "major" ? MAJOR_VARIANTS : MINOR_VARIANTS;
130
+ let inScale = 0;
131
+ let weighted = Number.NEGATIVE_INFINITY;
132
+ let best = variants[0];
133
+ for (const candidate of variants) {
134
+ let variantInScale = 0;
135
+ let variantWeighted = 0;
136
+ for (const pc of input) {
137
+ const offset = (pc - tonic + 12) % 12;
138
+ if (candidate.mask >> offset & 1) {
139
+ variantInScale += 1;
140
+ }
141
+ }
142
+ for (const [pc, count] of counts) {
143
+ const offset = (pc - tonic + 12) % 12;
144
+ if (candidate.mask >> offset & 1) {
145
+ variantWeighted += count;
146
+ }
147
+ }
148
+ if (variantWeighted > weighted) {
149
+ weighted = variantWeighted;
150
+ inScale = variantInScale;
151
+ best = candidate;
152
+ }
153
+ }
154
+ weighted += (_nullishCoalesce(counts.get(tonic), () => ( 0))) * 0.5;
155
+ results.push({
156
+ key: { rootPc: tonic, modeMask12: best.mask },
157
+ mode,
158
+ variant: best.variant,
159
+ fit: inScale / input.length,
160
+ score: weighted / total
161
+ });
162
+ }
163
+ }
164
+ results.sort((a, b) => b.score - a.score);
165
+ return results;
166
+ }
167
+ var DEFAULT_VELOCITY = 100;
168
+ function detectKeyFromNotes(notes, opts = {}) {
169
+ _chunkPI3UXRWKcjs.assertNoteEvents.call(void 0, notes, "key detection notes", {
170
+ allowNonPositiveDuration: true,
171
+ budget: opts.budget
172
+ });
173
+ const sounding = notes.filter((note) => note.durationBeat > 0);
174
+ return detectKey(
175
+ sounding.map((note) => note.pitch),
176
+ {
177
+ weights: sounding.map((note) => note.durationBeat * (_nullishCoalesce(note.velocity, () => ( DEFAULT_VELOCITY)))),
178
+ budget: opts.budget
179
+ }
180
+ );
181
+ }
182
+ function detectKeyBest(pitches, opts = {}) {
183
+ return _nullishCoalesce(detectKey(pitches, opts)[0], () => ( null));
184
+ }
185
+
186
+ // src/analyze/functional/internal.ts
187
+ function degreeRootPc(degreeNumber, key) {
188
+ const tones = _chunkBSLTLGM3cjs.scaleTonesInDegreeOrder.call(void 0, key);
189
+ if (tones.length === 0) {
190
+ return _chunkPI3UXRWKcjs.pitchClassOf.call(void 0, key.rootPc);
191
+ }
192
+ const index = ((degreeNumber - 1) % tones.length + tones.length) % tones.length;
193
+ return _nullishCoalesce(tones[index], () => ( _chunkPI3UXRWKcjs.pitchClassOf.call(void 0, key.rootPc)));
194
+ }
195
+ function loweredDegrees(key) {
196
+ const tones = _chunkBSLTLGM3cjs.scaleTonesInDegreeOrder.call(void 0, key);
197
+ const out = /* @__PURE__ */ new Set();
198
+ if (tones.length !== 7) {
199
+ return out;
200
+ }
201
+ const major = _chunkBSLTLGM3cjs.scaleTonesInDegreeOrder.call(void 0, { rootPc: _chunkPI3UXRWKcjs.pitchClassOf.call(void 0, key.rootPc), modeMask12: _chunkBSLTLGM3cjs.MAJOR_MASK });
202
+ for (let index = 0; index < 7; index += 1) {
203
+ const tone = tones[index];
204
+ const majorTone = major[index];
205
+ if (tone !== void 0 && majorTone !== void 0 && _chunkPI3UXRWKcjs.pitchClassOf.call(void 0, majorTone - tone) === 1) {
206
+ out.add(index + 1);
207
+ }
208
+ }
209
+ return out;
210
+ }
211
+ function romanReference(key) {
212
+ return _chunkBSLTLGM3cjs.scaleTonesInDegreeOrder.call(void 0, key).length === 7 ? key : _chunkBSLTLGM3cjs.majorKey.call(void 0, _chunkPI3UXRWKcjs.pitchClassOf.call(void 0, key.rootPc));
213
+ }
214
+ function isNeapolitan(chord, key) {
215
+ return _chunkPI3UXRWKcjs.pitchClassOf.call(void 0, chord.rootPc - key.rootPc) === 1 && chord.quality === "maj";
216
+ }
217
+ function isAppliedDominantSonority(chord) {
218
+ const has = (semitones) => chord.intervals.some((i) => _chunkPI3UXRWKcjs.pitchClassOf.call(void 0, i) === semitones);
219
+ return chord.quality === "maj" || has(4) && has(10);
220
+ }
221
+
222
+ // src/analyze/functional/roman.ts
223
+ var ROMAN = ["I", "II", "III", "IV", "V", "VI", "VII"];
224
+ var ROMAN_TO_DEGREE = {
225
+ I: 1,
226
+ II: 2,
227
+ III: 3,
228
+ IV: 4,
229
+ V: 5,
230
+ VI: 6,
231
+ VII: 7
232
+ };
233
+ var OFFSET_SPELLING = [
234
+ [1, ""],
235
+ [2, "b"],
236
+ [2, ""],
237
+ [3, "b"],
238
+ [3, ""],
239
+ [4, ""],
240
+ [4, "#"],
241
+ [5, ""],
242
+ [6, "b"],
243
+ [6, ""],
244
+ [7, "b"],
245
+ [7, ""]
246
+ ];
247
+ function seventhQuality(base, halfDim) {
248
+ if (halfDim) {
249
+ return "m7b5";
250
+ }
251
+ if (base === "dim") {
252
+ return "dim7";
253
+ }
254
+ if (base === "aug") {
255
+ return "aug7";
256
+ }
257
+ return base === "maj" ? "dom7" : "min7";
258
+ }
259
+ var INVERSION_FIGURES = /* @__PURE__ */ new Set(["6", "64", "65", "43", "42", "2", "7"]);
260
+ var ROMAN_STYLE = {
261
+ maj: { lower: false, suffix: "" },
262
+ min: { lower: true, suffix: "" },
263
+ dim: { lower: true, suffix: "o" },
264
+ aug: { lower: false, suffix: "+" },
265
+ maj7: { lower: false, suffix: "maj7" },
266
+ min7: { lower: true, suffix: "7" },
267
+ dom7: { lower: false, suffix: "7" },
268
+ dim7: { lower: true, suffix: "o7" },
269
+ m7b5: { lower: true, suffix: "\xF87" },
270
+ minMaj7: { lower: true, suffix: "maj7" },
271
+ minMaj9: { lower: true, suffix: "maj9" },
272
+ minMaj11: { lower: true, suffix: "maj11" },
273
+ minMaj13: { lower: true, suffix: "maj13" },
274
+ aug7: { lower: false, suffix: "+7" },
275
+ augMaj7: { lower: false, suffix: "+maj7" },
276
+ majb5: { lower: false, suffix: "b5" },
277
+ "6": { lower: false, suffix: "add6" },
278
+ min6: { lower: true, suffix: "add6" },
279
+ "6/9": { lower: false, suffix: "69" },
280
+ sus2: { lower: false, suffix: "sus2" },
281
+ sus4: { lower: false, suffix: "sus4" },
282
+ add9: { lower: false, suffix: "add9" },
283
+ add11: { lower: false, suffix: "add11" },
284
+ maj9: { lower: false, suffix: "maj9" },
285
+ min9: { lower: true, suffix: "9" },
286
+ dom9: { lower: false, suffix: "9" },
287
+ "7b9": { lower: false, suffix: "7b9" },
288
+ "7#9": { lower: false, suffix: "7#9" },
289
+ "7#11": { lower: false, suffix: "7#11" },
290
+ "7b13": { lower: false, suffix: "7b13" },
291
+ "11": { lower: false, suffix: "11" },
292
+ "13": { lower: false, suffix: "13" },
293
+ "5": { lower: false, suffix: "5" },
294
+ "7sus4": { lower: false, suffix: "7sus4" },
295
+ "7b5": { lower: false, suffix: "7b5" },
296
+ "7alt": { lower: false, suffix: "7alt" },
297
+ "13b9": { lower: false, suffix: "13b9" },
298
+ maj13: { lower: false, suffix: "maj13" },
299
+ "maj7#11": { lower: false, suffix: "maj7#11" },
300
+ min11: { lower: true, suffix: "11" },
301
+ min13: { lower: true, suffix: "13" },
302
+ minAdd9: { lower: true, suffix: "add9" },
303
+ "min6/9": { lower: true, suffix: "69" }
304
+ };
305
+ var SUFFIX_QUALITY = new Map(
306
+ Object.entries(ROMAN_STYLE).map(
307
+ ([quality, style]) => [`${style.lower ? "l" : "u"}:${style.suffix}`, quality]
308
+ )
309
+ );
310
+ function parseInversion(figures) {
311
+ if (figures === "65") {
312
+ return { inversion: 1, seventh: true };
313
+ }
314
+ if (figures === "43") {
315
+ return { inversion: 2, seventh: true };
316
+ }
317
+ if (figures === "42" || figures === "2") {
318
+ return { inversion: 3, seventh: true };
319
+ }
320
+ if (figures === "7") {
321
+ return { inversion: 0, seventh: true };
322
+ }
323
+ if (figures === "64") {
324
+ return { inversion: 2, seventh: false };
325
+ }
326
+ if (figures === "6") {
327
+ return { inversion: 1, seventh: false };
328
+ }
329
+ return { inversion: 0, seventh: false };
330
+ }
331
+ function parseSimpleRoman(text, key) {
332
+ const match = /^([b#]?)([iIvV]+)(.*)$/.exec(text.trim());
333
+ if (!match) {
334
+ throw new (0, _chunkPI3UXRWKcjs.InvalidInputError)(`Invalid Roman numeral: ${text}`);
335
+ }
336
+ const glyphText = _nullishCoalesce(match[2], () => ( ""));
337
+ if (glyphText !== glyphText.toUpperCase() && glyphText !== glyphText.toLowerCase()) {
338
+ throw new (0, _chunkPI3UXRWKcjs.InvalidInputError)(`Roman numeral must use one case: ${text}`);
339
+ }
340
+ const accidental = match[1] === "b" ? -1 : match[1] === "#" ? 1 : 0;
341
+ const glyph = glyphText.toUpperCase();
342
+ const degreeNumber = ROMAN_TO_DEGREE[glyph];
343
+ if (degreeNumber === void 0) {
344
+ throw new (0, _chunkPI3UXRWKcjs.InvalidInputError)(`Invalid Roman numeral: ${text}`);
345
+ }
346
+ const isUpper = glyphText[0] === _optionalChain([glyphText, 'access', _ => _[0], 'optionalAccess', _2 => _2.toUpperCase, 'call', _3 => _3()]);
347
+ const suffix = _nullishCoalesce(match[3], () => ( ""));
348
+ const frame = romanReference(key);
349
+ const redundantFlat = accidental === -1 && loweredDegrees(frame).has(degreeNumber);
350
+ const diatonicRootPc = _chunkPI3UXRWKcjs.pitchClassOf.call(void 0,
351
+ degreeRootPc(degreeNumber, frame) + (redundantFlat ? 0 : accidental)
352
+ );
353
+ const rootForQuality = (quality2) => accidental === 0 && degreeNumber === 7 && loweredDegrees(frame).has(7) && (quality2 === "dim" || quality2 === "dim7") ? _chunkPI3UXRWKcjs.pitchClassOf.call(void 0, diatonicRootPc + 1) : diatonicRootPc;
354
+ const canonical = SUFFIX_QUALITY.get(`${isUpper ? "u" : "l"}:${suffix}`);
355
+ if (canonical !== void 0) {
356
+ return { rootPc: rootForQuality(canonical), quality: canonical, inversion: 0 };
357
+ }
358
+ const parsedSuffix = /^(o|°|dim|ø|\+|aug)?(maj7|M7)?(65|64|43|42|7|6|2)?$/.exec(suffix);
359
+ if (!parsedSuffix) {
360
+ throw new (0, _chunkPI3UXRWKcjs.InvalidInputError)(`Unsupported suffix "${suffix}" in Roman numeral: ${text}`);
361
+ }
362
+ const qualityMarker = _nullishCoalesce(parsedSuffix[1], () => ( ""));
363
+ const isDim = qualityMarker === "o" || qualityMarker === "\xB0" || qualityMarker === "dim";
364
+ const isAug = qualityMarker === "+" || qualityMarker === "aug";
365
+ const isHalfDim = qualityMarker === "\xF8";
366
+ const explicitMaj7 = parsedSuffix[2] !== void 0;
367
+ const figures = _nullishCoalesce(parsedSuffix[3], () => ( ""));
368
+ if (figures !== "" && !INVERSION_FIGURES.has(figures)) {
369
+ throw new (0, _chunkPI3UXRWKcjs.InvalidInputError)(
370
+ `Unsupported figured-bass or extension "${figures}" in Roman numeral: ${text}`
371
+ );
372
+ }
373
+ const { inversion, seventh } = parseInversion(figures);
374
+ const hasSeventh = explicitMaj7 || seventh || isHalfDim;
375
+ let base;
376
+ if (isDim || isHalfDim) {
377
+ base = "dim";
378
+ } else if (isAug) {
379
+ base = "aug";
380
+ } else {
381
+ base = isUpper ? "maj" : "min";
382
+ }
383
+ let quality;
384
+ if (explicitMaj7) {
385
+ quality = base === "min" ? "minMaj7" : base === "aug" ? "augMaj7" : "maj7";
386
+ } else if (hasSeventh) {
387
+ quality = seventhQuality(base, isHalfDim);
388
+ } else if (base === "dim") {
389
+ quality = "dim";
390
+ } else if (base === "aug") {
391
+ quality = "aug";
392
+ } else {
393
+ quality = base;
394
+ }
395
+ return { rootPc: rootForQuality(quality), quality, inversion };
396
+ }
397
+ function chordFromParsed(parsed) {
398
+ const chord = _chunkBSLTLGM3cjs.makeChord.call(void 0, parsed.rootPc, parsed.quality);
399
+ if (parsed.inversion > 0 && parsed.inversion < chord.intervals.length) {
400
+ chord.bassPc = _chunkPI3UXRWKcjs.pitchClassOf.call(void 0, parsed.rootPc + (_nullishCoalesce(chord.intervals[parsed.inversion], () => ( 0))));
401
+ }
402
+ return chord;
403
+ }
404
+ function romanToChord(text, key) {
405
+ const trimmed = text.trim().replace(/(\d)\/(?=\d)/g, "$1");
406
+ const slash = trimmed.indexOf("/");
407
+ if (slash >= 0) {
408
+ const applied = trimmed.slice(0, slash);
409
+ const target = trimmed.slice(slash + 1);
410
+ const targetRoot = parseSimpleRoman(target, key).rootPc;
411
+ const localKey = _chunkBSLTLGM3cjs.majorKey.call(void 0, targetRoot);
412
+ return chordFromParsed(parseSimpleRoman(applied, localKey));
413
+ }
414
+ return chordFromParsed(parseSimpleRoman(trimmed, key));
415
+ }
416
+ function romanStyle(quality) {
417
+ return ROMAN_STYLE[quality];
418
+ }
419
+ function romanSpelling(rootPc, key) {
420
+ const tones = _chunkBSLTLGM3cjs.scaleTonesInDegreeOrder.call(void 0, romanReference(key));
421
+ const diatonic = tones.indexOf(_chunkPI3UXRWKcjs.pitchClassOf.call(void 0, rootPc));
422
+ if (diatonic >= 0) {
423
+ return { degreeNumber: diatonic + 1, accidental: "" };
424
+ }
425
+ const lowered = loweredDegrees(romanReference(key));
426
+ for (let i = 0; i < tones.length; i += 1) {
427
+ if (lowered.has(i + 1) && _chunkPI3UXRWKcjs.pitchClassOf.call(void 0, (_nullishCoalesce(tones[i], () => ( 0))) + 1) === _chunkPI3UXRWKcjs.pitchClassOf.call(void 0, rootPc)) {
428
+ return { degreeNumber: i + 1, accidental: "#" };
429
+ }
430
+ }
431
+ for (let i = 0; i < tones.length; i += 1) {
432
+ const degreeNumber2 = i + 1;
433
+ if (degreeNumber2 === 1 || degreeNumber2 === 5) {
434
+ continue;
435
+ }
436
+ if (_chunkPI3UXRWKcjs.pitchClassOf.call(void 0, (_nullishCoalesce(tones[i], () => ( 0))) - 1) === _chunkPI3UXRWKcjs.pitchClassOf.call(void 0, rootPc)) {
437
+ return { degreeNumber: degreeNumber2, accidental: "b" };
438
+ }
439
+ }
440
+ for (let i = 0; i < tones.length; i += 1) {
441
+ if (_chunkPI3UXRWKcjs.pitchClassOf.call(void 0, (_nullishCoalesce(tones[i], () => ( 0))) + 1) === _chunkPI3UXRWKcjs.pitchClassOf.call(void 0, rootPc)) {
442
+ return { degreeNumber: i + 1, accidental: "#" };
443
+ }
444
+ }
445
+ const [degreeNumber, accidental] = _nullishCoalesce(OFFSET_SPELLING[_chunkPI3UXRWKcjs.pitchClassOf.call(void 0, rootPc - key.rootPc)], () => ( [1, ""]));
446
+ return { degreeNumber, accidental };
447
+ }
448
+ function baseMarker(quality) {
449
+ if (quality === "dim" || quality === "dim7") {
450
+ return "o";
451
+ }
452
+ if (quality === "m7b5") {
453
+ return "\xF8";
454
+ }
455
+ if (quality === "aug" || quality === "aug7") {
456
+ return "+";
457
+ }
458
+ if (quality === "augMaj7") {
459
+ return "+maj7";
460
+ }
461
+ if (quality === "maj7" || quality === "minMaj7") {
462
+ return "maj7";
463
+ }
464
+ return "";
465
+ }
466
+ var TRIAD_FIGURES = { 1: "6", 2: "64" };
467
+ var SEVENTH_FIGURES = { 1: "65", 2: "43", 3: "42" };
468
+ var TRIAD_FIGURE_QUALITIES = /* @__PURE__ */ new Set(["maj", "min", "dim", "aug"]);
469
+ var SEVENTH_FIGURE_QUALITIES = /* @__PURE__ */ new Set([
470
+ "maj7",
471
+ "min7",
472
+ "dom7",
473
+ "dim7",
474
+ "m7b5",
475
+ "minMaj7",
476
+ "aug7",
477
+ "augMaj7"
478
+ ]);
479
+ function numeralFor(degreeNumber, lower) {
480
+ const glyph = ROMAN[degreeNumber - 1];
481
+ if (glyph === void 0) {
482
+ throw new (0, _chunkPI3UXRWKcjs.InvalidInputError)(`no Roman numeral for scale degree ${degreeNumber}`);
483
+ }
484
+ return lower ? glyph.toLowerCase() : glyph;
485
+ }
486
+ function isDiatonicChord(chord, key) {
487
+ return _chunkBSLTLGM3cjs.chordPitchClasses.call(void 0, chord).every((pc) => _chunkBSLTLGM3cjs.isScaleTone.call(void 0, pc, key));
488
+ }
489
+ var LEADING_TONE_QUALITIES = /* @__PURE__ */ new Set(["dim", "dim7", "m7b5"]);
490
+ function degreeTriad(tones, index) {
491
+ const root = _nullishCoalesce(tones[index], () => ( 0));
492
+ return {
493
+ third: _chunkPI3UXRWKcjs.pitchClassOf.call(void 0, (_nullishCoalesce(tones[(index + 2) % tones.length], () => ( 0))) - root),
494
+ fifth: _chunkPI3UXRWKcjs.pitchClassOf.call(void 0, (_nullishCoalesce(tones[(index + 4) % tones.length], () => ( 0))) - root)
495
+ };
496
+ }
497
+ function appliedTarget(chord, key) {
498
+ const dominant = isAppliedDominantSonority(chord);
499
+ const leadingTone = LEADING_TONE_QUALITIES.has(chord.quality);
500
+ if (!dominant && !leadingTone) {
501
+ return null;
502
+ }
503
+ const tones = _chunkBSLTLGM3cjs.scaleTonesInDegreeOrder.call(void 0, romanReference(key));
504
+ for (let index = 1; index < tones.length; index += 1) {
505
+ const targetRoot = tones[index];
506
+ if (targetRoot === void 0) {
507
+ continue;
508
+ }
509
+ const triad = degreeTriad(tones, index);
510
+ const expectedRoot = _chunkPI3UXRWKcjs.pitchClassOf.call(void 0, targetRoot + (dominant ? 7 : -1));
511
+ if (expectedRoot === _chunkPI3UXRWKcjs.pitchClassOf.call(void 0, chord.rootPc)) {
512
+ return { degreeNumber: index + 1, rootPc: targetRoot, lower: triad.third === 3 };
513
+ }
514
+ }
515
+ return null;
516
+ }
517
+ function chordToRoman(chord, key, opts = {}) {
518
+ if (opts.applied === true && !isDiatonicChord(chord, key)) {
519
+ const target = appliedTarget(chord, key);
520
+ if (target !== null) {
521
+ const local = chordToRoman(chord, _chunkBSLTLGM3cjs.majorKey.call(void 0, target.rootPc));
522
+ return `${local}/${numeralFor(target.degreeNumber, target.lower)}`;
523
+ }
524
+ }
525
+ const { degreeNumber, accidental: spelledAccidental } = romanSpelling(chord.rootPc, key);
526
+ const { lower, suffix } = romanStyle(chord.quality);
527
+ const cased = numeralFor(degreeNumber, lower);
528
+ const accidental = spelledAccidental === "#" && degreeNumber === 7 && loweredDegrees(romanReference(key)).has(7) && (chord.quality === "dim" || chord.quality === "dim7") ? "" : spelledAccidental;
529
+ let inversion = 0;
530
+ if (chord.bassPc !== void 0) {
531
+ const idx = chord.intervals.findIndex((iv) => _chunkPI3UXRWKcjs.pitchClassOf.call(void 0, chord.rootPc + iv) === chord.bassPc);
532
+ if (idx > 0) {
533
+ inversion = idx;
534
+ }
535
+ }
536
+ if (inversion > 0) {
537
+ const figure = SEVENTH_FIGURE_QUALITIES.has(chord.quality) ? SEVENTH_FIGURES[inversion] : TRIAD_FIGURE_QUALITIES.has(chord.quality) ? TRIAD_FIGURES[inversion] : void 0;
538
+ if (figure !== void 0) {
539
+ return `${accidental}${cased}${baseMarker(chord.quality)}${figure}`;
540
+ }
541
+ }
542
+ return `${accidental}${cased}${suffix}`;
543
+ }
544
+
545
+ // src/analyze/functional/borrowed.ts
546
+ function isMinorScaleAlteration(chord, key) {
547
+ if (!isMinorKey(key)) return false;
548
+ const alteredKey = { rootPc: _chunkPI3UXRWKcjs.pitchClassOf.call(void 0, key.rootPc), modeMask12: _chunkBSLTLGM3cjs.HARMONIC_MINOR_MASK };
549
+ if (isDiatonic(chord, alteredKey)) return true;
550
+ return _chunkPI3UXRWKcjs.pitchClassOf.call(void 0, chord.rootPc - key.rootPc) === 11 && isDiatonic(chord, { rootPc: _chunkPI3UXRWKcjs.pitchClassOf.call(void 0, key.rootPc), modeMask12: _chunkBSLTLGM3cjs.MELODIC_MINOR_MASK });
551
+ }
552
+ function isBorrowedChord(chord, key) {
553
+ if (isDiatonic(chord, key)) {
554
+ return false;
555
+ }
556
+ if (isNeapolitan(chord, key)) {
557
+ return true;
558
+ }
559
+ if (isMinorScaleAlteration(chord, key)) {
560
+ return false;
561
+ }
562
+ return isDiatonic(chord, parallelKey(key));
563
+ }
564
+ function borrowedSource(chord, key) {
565
+ if (isDiatonic(chord, key)) {
566
+ return null;
567
+ }
568
+ if (isNeapolitan(chord, key)) return "neapolitan";
569
+ if (isBorrowedChord(chord, key)) {
570
+ return isMinorKey(key) ? "parallelMajor" : "parallelMinor";
571
+ }
572
+ return null;
573
+ }
574
+
575
+ // src/analyze/functional/function.ts
576
+ var FUNCTION_BY_OFFSET = [
577
+ "tonic",
578
+ // 0 I
579
+ "subdominant",
580
+ // 1 bII (Neapolitan)
581
+ "subdominant",
582
+ // 2 ii
583
+ "tonic",
584
+ // 3 bIII
585
+ "tonic",
586
+ // 4 iii
587
+ "subdominant",
588
+ // 5 IV
589
+ "dominant",
590
+ // 6 #IV / bV
591
+ "dominant",
592
+ // 7 V
593
+ "subdominant",
594
+ // 8 bVI
595
+ "tonic",
596
+ // 9 vi
597
+ "subdominant",
598
+ // 10 bVII
599
+ "dominant"
600
+ // 11 vii
601
+ ];
602
+ var MINOR_FUNCTION_BY_OFFSET = [
603
+ "tonic",
604
+ "subdominant",
605
+ "subdominant",
606
+ "tonic",
607
+ "dominant",
608
+ "subdominant",
609
+ "dominant",
610
+ "dominant",
611
+ "tonic",
612
+ "tonic",
613
+ "subdominant",
614
+ "dominant"
615
+ ];
616
+ function isMinorKey(key) {
617
+ const hasMinorThird = key.modeMask12 >> 3 & 1;
618
+ const hasMajorThird2 = key.modeMask12 >> 4 & 1;
619
+ return Boolean(hasMinorThird) && !hasMajorThird2;
620
+ }
621
+ function functionOf(chord, key) {
622
+ const offset = _chunkPI3UXRWKcjs.pitchClassOf.call(void 0, chord.rootPc - key.rootPc);
623
+ if (isNeapolitan(chord, key)) {
624
+ return "subdominant";
625
+ }
626
+ if (isAppliedDominant(chord, key)) {
627
+ return "dominant";
628
+ }
629
+ if (!isMinorKey(key) && hasMajorThird(chord) && (offset === 8 || offset === 10)) {
630
+ return "subdominant";
631
+ }
632
+ const functions = isMinorKey(key) ? MINOR_FUNCTION_BY_OFFSET : FUNCTION_BY_OFFSET;
633
+ return _nullishCoalesce(functions[offset], () => ( "tonic"));
634
+ }
635
+ function isAppliedDominant(chord, key) {
636
+ if (isDiatonic(chord, key)) {
637
+ return false;
638
+ }
639
+ const root = _chunkPI3UXRWKcjs.pitchClassOf.call(void 0, chord.rootPc);
640
+ const resolvesTo = (step) => _chunkBSLTLGM3cjs.isScaleTone.call(void 0, _chunkPI3UXRWKcjs.pitchClassOf.call(void 0, root + step), key);
641
+ if (isAppliedDominantSonority(chord)) {
642
+ return chord.quality === "maj" ? resolvesTo(5) : resolvesTo(5) || resolvesTo(11);
643
+ }
644
+ return isDiminishedQuality(chord.quality) && resolvesTo(1);
645
+ }
646
+ function isDiatonic(chord, key) {
647
+ return _chunkBSLTLGM3cjs.chordPitchClasses.call(void 0, chord).every((pc) => _chunkBSLTLGM3cjs.isScaleTone.call(void 0, pc, key));
648
+ }
649
+ function parallelKey(key) {
650
+ return {
651
+ rootPc: _chunkPI3UXRWKcjs.pitchClassOf.call(void 0, key.rootPc),
652
+ modeMask12: isMinorKey(key) ? _chunkBSLTLGM3cjs.MAJOR_MASK : _chunkBSLTLGM3cjs.NATURAL_MINOR_MASK
653
+ };
654
+ }
655
+ function isDiminishedQuality(quality) {
656
+ return quality === "dim" || quality === "dim7" || quality === "m7b5";
657
+ }
658
+ function hasMajorThird(chord) {
659
+ return chord.intervals.some((interval) => _chunkPI3UXRWKcjs.pitchClassOf.call(void 0, interval) === 4);
660
+ }
661
+ function analyzeChord(chord, key, opts = {}) {
662
+ const source = borrowedSource(chord, key);
663
+ return {
664
+ function: functionOf(chord, key),
665
+ borrowed: source !== null,
666
+ source,
667
+ roman: chordToRoman(chord, key, opts)
668
+ };
669
+ }
670
+ function secondaryDominant(targetDegree, key) {
671
+ const degreeCount = _chunkBSLTLGM3cjs.scaleTonesInDegreeOrder.call(void 0, key).length;
672
+ _chunkPI3UXRWKcjs.assertInteger.call(void 0, targetDegree, "targetDegree", 0, degreeCount - 1);
673
+ const targetRoot = degreeRootPc(targetDegree + 1, key);
674
+ return _chunkBSLTLGM3cjs.makeChord.call(void 0, _chunkPI3UXRWKcjs.pitchClassOf.call(void 0, targetRoot + 7), "dom7");
675
+ }
676
+
677
+ // src/analyze/functional/cadence.ts
678
+ function hasDominantThird(chord) {
679
+ return chord.intervals.some((interval) => _chunkPI3UXRWKcjs.pitchClassOf.call(void 0, interval) === 4);
680
+ }
681
+ function isLeadingToneDiminished(chord) {
682
+ return chord.quality === "dim" || chord.quality === "dim7" || chord.quality === "m7b5";
683
+ }
684
+ function detectCadence(from, to, key) {
685
+ const tonic = _chunkPI3UXRWKcjs.pitchClassOf.call(void 0, key.rootPc);
686
+ const fromOffset = _chunkPI3UXRWKcjs.pitchClassOf.call(void 0, from.rootPc - tonic);
687
+ const toOffset = _chunkPI3UXRWKcjs.pitchClassOf.call(void 0, to.rootPc - tonic);
688
+ const deceptiveTargets = isMinorKey(key) ? [8] : [8, 9];
689
+ const dominant = fromOffset === 7 && hasDominantThird(from);
690
+ const leadingTone = fromOffset === 11 && isLeadingToneDiminished(from);
691
+ if ((dominant || leadingTone) && toOffset === 0) {
692
+ return "authentic";
693
+ }
694
+ if (fromOffset === 5 && toOffset === 0) {
695
+ return "plagal";
696
+ }
697
+ if (dominant && deceptiveTargets.includes(toOffset)) {
698
+ return "deceptive";
699
+ }
700
+ if (toOffset === 7 && hasDominantThird(to) && fromOffset !== 7) {
701
+ return "half";
702
+ }
703
+ return null;
704
+ }
705
+
706
+
707
+
708
+
709
+
710
+
711
+
712
+
713
+
714
+
715
+
716
+
717
+
718
+
719
+
720
+
721
+
722
+
723
+ exports.detectChord = detectChord; exports.detectChordBest = detectChordBest; exports.detectKey = detectKey; exports.detectKeyFromNotes = detectKeyFromNotes; exports.detectKeyBest = detectKeyBest; exports.romanToChord = romanToChord; exports.chordToRoman = chordToRoman; exports.isMinorKey = isMinorKey; exports.functionOf = functionOf; exports.isDiatonic = isDiatonic; exports.parallelKey = parallelKey; exports.analyzeChord = analyzeChord; exports.secondaryDominant = secondaryDominant; exports.isBorrowedChord = isBorrowedChord; exports.borrowedSource = borrowedSource; exports.detectCadence = detectCadence;
724
+ //# sourceMappingURL=chunk-KQN2ZYND.cjs.map