@pepperhorn/chordl-core 0.3.4 → 0.5.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.
- package/dist/audio/midi-export.js +11 -2
- package/dist/audio/midi-export.js.map +1 -1
- package/dist/chord-sheet/codec.d.ts +1 -1
- package/dist/chord-sheet/codec.js +1 -1
- package/dist/chord-sheet/codec.js.map +1 -1
- package/dist/chord-sheet/defaults.d.ts +8 -1
- package/dist/chord-sheet/defaults.js +25 -1
- package/dist/chord-sheet/defaults.js.map +1 -1
- package/dist/chord-sheet/index.d.ts +3 -3
- package/dist/chord-sheet/index.js +3 -3
- package/dist/chord-sheet/index.js.map +1 -1
- package/dist/engine/auto-fingering.js +1 -1
- package/dist/engine/auto-fingering.js.map +1 -1
- package/dist/engine/highlight-mapper.d.ts +1 -1
- package/dist/engine/highlight-mapper.js +2 -2
- package/dist/engine/highlight-mapper.js.map +1 -1
- package/dist/engine/keyboard-layout.d.ts +1 -1
- package/dist/engine/keyboard-layout.js +1 -1
- package/dist/engine/keyboard-layout.js.map +1 -1
- package/dist/engine/mei-builder.d.ts +47 -0
- package/dist/engine/mei-builder.js +155 -0
- package/dist/engine/mei-builder.js.map +1 -0
- package/dist/engine/staff-glyphs.js +5 -10
- package/dist/engine/staff-glyphs.js.map +1 -1
- package/dist/engine/staff-layout.js +2 -2
- package/dist/engine/staff-layout.js.map +1 -1
- package/dist/index.d.ts +52 -42
- package/dist/index.js +34 -28
- package/dist/index.js.map +1 -1
- package/dist/parser/natural-language.d.ts +23 -1
- package/dist/parser/natural-language.js +282 -32
- package/dist/parser/natural-language.js.map +1 -1
- package/dist/parser/progression-parser.d.ts +1 -1
- package/dist/parser/progression-parser.js +1 -1
- package/dist/parser/progression-parser.js.map +1 -1
- package/dist/pipeline.d.ts +1 -1
- package/dist/pipeline.js +46 -25
- package/dist/pipeline.js.map +1 -1
- package/dist/progression/index.d.ts +5 -5
- package/dist/progression/index.js +3 -3
- package/dist/progression/index.js.map +1 -1
- package/dist/progression/progression-resolver.js +5 -5
- package/dist/progression/progression-resolver.js.map +1 -1
- package/dist/progression/roman-numeral.js +1 -1
- package/dist/progression/roman-numeral.js.map +1 -1
- package/dist/resolver/auto-layout.d.ts +12 -1
- package/dist/resolver/auto-layout.js +27 -11
- package/dist/resolver/auto-layout.js.map +1 -1
- package/dist/resolver/chord-resolver.d.ts +11 -1
- package/dist/resolver/chord-resolver.js +28 -2
- package/dist/resolver/chord-resolver.js.map +1 -1
- package/dist/resolver/scale-resolver.d.ts +5 -2
- package/dist/resolver/scale-resolver.js +28 -8
- package/dist/resolver/scale-resolver.js.map +1 -1
- package/dist/themes/boomwhacker.d.ts +1 -1
- package/dist/themes/boomwhacker.js +1 -1
- package/dist/themes/boomwhacker.js.map +1 -1
- package/dist/themes/crf.d.ts +1 -1
- package/dist/themes/crf.js +1 -1
- package/dist/themes/crf.js.map +1 -1
- package/dist/themes/index.d.ts +1 -1
- package/dist/themes/index.js +3 -3
- package/dist/themes/index.js.map +1 -1
- package/dist/themes/simple.d.ts +1 -1
- package/dist/themes/simple.js +1 -1
- package/dist/themes/simple.js.map +1 -1
- package/dist/theory/chord-identify.d.ts +72 -0
- package/dist/theory/chord-identify.js +334 -0
- package/dist/theory/chord-identify.js.map +1 -0
- package/dist/theory/constrained-variants.d.ts +46 -0
- package/dist/theory/constrained-variants.js +117 -0
- package/dist/theory/constrained-variants.js.map +1 -0
- package/dist/theory/degree-labels.d.ts +39 -0
- package/dist/theory/degree-labels.js +102 -1
- package/dist/theory/degree-labels.js.map +1 -1
- package/dist/theory/hand-constraints.d.ts +104 -0
- package/dist/theory/hand-constraints.js +214 -0
- package/dist/theory/hand-constraints.js.map +1 -0
- package/dist/theory/starting-note.d.ts +43 -0
- package/dist/theory/starting-note.js +97 -0
- package/dist/theory/starting-note.js.map +1 -0
- package/dist/types.d.ts +19 -1
- package/package.json +9 -4
package/dist/pipeline.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import { parseChordDescription } from "./parser/natural-language";
|
|
2
|
-
import { resolveChord } from "./resolver/chord-resolver";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
1
|
+
import { parseChordDescription } from "./parser/natural-language.js";
|
|
2
|
+
import { resolveChord } from "./resolver/chord-resolver.js";
|
|
3
|
+
import { resolveScale } from "./resolver/scale-resolver.js";
|
|
4
|
+
import { calculateLayout } from "./resolver/auto-layout.js";
|
|
5
|
+
import { computeKeyboard, computeSvgDimensions } from "./engine/keyboard-layout.js";
|
|
6
|
+
import { mapHighlights, normalizeNote } from "./engine/highlight-mapper.js";
|
|
7
|
+
import { generateMidiFile } from "./audio/midi-export.js";
|
|
8
|
+
import { logChordRequest } from "./logging.js";
|
|
9
|
+
import { WHITE_KEY_RY, BLACK_KEY_RY, DEFAULT_STROKE, DEFAULT_STROKE_WIDTH, } from "./engine/svg-constants.js";
|
|
9
10
|
// ── SVG builder ───────────────────────────────────────────────────
|
|
10
11
|
function buildSvgString(keys, fills, svgWidth, svgHeight) {
|
|
11
12
|
const whiteRects = [];
|
|
@@ -29,7 +30,7 @@ function buildSvgString(keys, fills, svgWidth, svgHeight) {
|
|
|
29
30
|
`</svg>`,
|
|
30
31
|
].join("\n");
|
|
31
32
|
}
|
|
32
|
-
import { PC_SEMITONES as NOTE_SEMITONES } from "./engine/note-spelling";
|
|
33
|
+
import { PC_SEMITONES as NOTE_SEMITONES } from "./engine/note-spelling.js";
|
|
33
34
|
// ── Main pipeline ─────────────────────────────────────────────────
|
|
34
35
|
export function processChordRequest(request) {
|
|
35
36
|
const start = performance.now();
|
|
@@ -54,18 +55,37 @@ export function processChordRequest(request) {
|
|
|
54
55
|
}
|
|
55
56
|
// 1. Parse
|
|
56
57
|
const parsed = parseChordDescription(input);
|
|
57
|
-
|
|
58
|
-
|
|
58
|
+
const isScale = Boolean(parsed.isScale && parsed.scaleName);
|
|
59
|
+
// 2. Resolve — scales resolve one octave from the root by default
|
|
60
|
+
// ("N octaves" extends, "starting on X" rotates); chords via Tonal.
|
|
61
|
+
let displayName;
|
|
62
|
+
let resolvedRoot;
|
|
63
|
+
let resolvedType;
|
|
64
|
+
let pitchClasses;
|
|
65
|
+
if (isScale) {
|
|
66
|
+
const [scaleRoot, ...scaleTypeParts] = parsed.scaleName.split(" ");
|
|
67
|
+
const scaleResolved = resolveScale(scaleRoot, scaleTypeParts.join(" "), parsed.scaleDirection, parsed.scaleOctaves ?? 1, parsed.startingNote);
|
|
68
|
+
displayName = `${parsed.scaleName} scale`;
|
|
69
|
+
resolvedRoot = scaleResolved.root;
|
|
70
|
+
resolvedType = scaleResolved.type;
|
|
71
|
+
pitchClasses = scaleResolved.notes;
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
if (!parsed.chordName) {
|
|
75
|
+
return errorResult("Could not extract a chord name from the input");
|
|
76
|
+
}
|
|
77
|
+
const resolved = resolveChord(parsed.chordName, parsed.inversion);
|
|
78
|
+
displayName = parsed.chordName;
|
|
79
|
+
resolvedRoot = resolved.root;
|
|
80
|
+
resolvedType = resolved.type;
|
|
81
|
+
pitchClasses = resolved.notes; // display names (Bb, Eb, etc.)
|
|
59
82
|
}
|
|
60
|
-
// 2. Resolve
|
|
61
|
-
const resolved = resolveChord(parsed.chordName, parsed.inversion);
|
|
62
|
-
const pitchClasses = resolved.notes; // display names (Bb, Eb, etc.)
|
|
63
83
|
const keyboardPitchClasses = pitchClasses.map(normalizeNote); // sharps for keyboard internals
|
|
64
|
-
// 3. Layout
|
|
84
|
+
// 3. Layout — a scale's starting note is already applied via rotation
|
|
65
85
|
const layoutFormat = parsed.format ?? "compact";
|
|
66
86
|
const layout = calculateLayout(keyboardPitchClasses, {
|
|
67
87
|
padding: parsed.padding,
|
|
68
|
-
startingNote: parsed.startingNote,
|
|
88
|
+
startingNote: isScale ? undefined : parsed.startingNote,
|
|
69
89
|
spanFrom: parsed.spanFrom,
|
|
70
90
|
spanTo: parsed.spanTo,
|
|
71
91
|
});
|
|
@@ -94,8 +114,9 @@ export function processChordRequest(request) {
|
|
|
94
114
|
prevSemitone = semitone;
|
|
95
115
|
assigned.push({ pc, kpc, semitone, octave: currentOctave });
|
|
96
116
|
}
|
|
97
|
-
// Step 2: compact — fold notes down if span exceeds playable range
|
|
98
|
-
|
|
117
|
+
// Step 2: compact — fold notes down if span exceeds playable range.
|
|
118
|
+
// Scales are sequential runs, not stacked voicings — never fold them.
|
|
119
|
+
if (!isScale && assigned.length > 1) {
|
|
99
120
|
const baseSemi = assigned[0].semitone + assigned[0].octave * 12;
|
|
100
121
|
for (let i = 1; i < assigned.length; i++) {
|
|
101
122
|
const noteSemi = assigned[i].semitone + assigned[i].octave * 12;
|
|
@@ -114,8 +135,8 @@ export function processChordRequest(request) {
|
|
|
114
135
|
// 7. Build result
|
|
115
136
|
const result = {
|
|
116
137
|
success: true,
|
|
117
|
-
chordName:
|
|
118
|
-
root:
|
|
138
|
+
chordName: displayName,
|
|
139
|
+
root: resolvedRoot,
|
|
119
140
|
notes: midiNoteNames,
|
|
120
141
|
inversion: parsed.inversion,
|
|
121
142
|
keyboard: {
|
|
@@ -126,8 +147,8 @@ export function processChordRequest(request) {
|
|
|
126
147
|
telemetry: {
|
|
127
148
|
parser: "chord",
|
|
128
149
|
resolver: {
|
|
129
|
-
root:
|
|
130
|
-
type:
|
|
150
|
+
root: resolvedRoot,
|
|
151
|
+
type: resolvedType,
|
|
131
152
|
pitchClasses,
|
|
132
153
|
},
|
|
133
154
|
durationMs: performance.now() - start,
|
|
@@ -149,7 +170,7 @@ export function processChordRequest(request) {
|
|
|
149
170
|
pipeline: {
|
|
150
171
|
parser: "chord",
|
|
151
172
|
parsed: {
|
|
152
|
-
chordName:
|
|
173
|
+
chordName: displayName,
|
|
153
174
|
inversion: parsed.inversion,
|
|
154
175
|
allInversions: parsed.allInversions,
|
|
155
176
|
startingNote: parsed.startingNote,
|
|
@@ -169,8 +190,8 @@ export function processChordRequest(request) {
|
|
|
169
190
|
},
|
|
170
191
|
resolver: {
|
|
171
192
|
method: "tonal",
|
|
172
|
-
type:
|
|
173
|
-
root:
|
|
193
|
+
type: resolvedType,
|
|
194
|
+
root: resolvedRoot,
|
|
174
195
|
pitchClasses,
|
|
175
196
|
},
|
|
176
197
|
voicing: {
|
package/dist/pipeline.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pipeline.js","sourceRoot":"","sources":["../src/pipeline.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"pipeline.js","sourceRoot":"","sources":["../src/pipeline.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AACrE,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AACpF,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAC5E,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAG/C,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,cAAc,EACd,oBAAoB,GACrB,MAAM,2BAA2B,CAAC;AAuCnC,qEAAqE;AAErE,SAAS,cAAc,CACrB,IAAqB,EACrB,KAAe,EACf,QAAgB,EAChB,SAAiB;IAEjB,MAAM,UAAU,GAAa,EAAE,CAAC;IAChC,MAAM,UAAU,GAAa,EAAE,CAAC;IAEhC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QACtB,MAAM,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,YAAY,CAAC;QACnD,MAAM,IAAI,GAAG,YAAY,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,KAAK,aAAa,CAAC,CAAC,MAAM,SAAS,EAAE,SAAS,EAAE,WAAW,IAAI,aAAa,cAAc,mBAAmB,oBAAoB,KAAK,CAAC;QAE5L,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC;YACd,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACxB,CAAC;aAAM,CAAC;YACN,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACxB,CAAC;IACH,CAAC;IAED,OAAO;QACL,kDAAkD,QAAQ,aAAa,SAAS,kBAAkB,QAAQ,IAAI,SAAS,IAAI;QAC3H,GAAG,UAAU;QACb,GAAG,UAAU;QACb,QAAQ;KACT,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC;AAED,OAAO,EAAE,YAAY,IAAI,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAE3E,qEAAqE;AAErE,MAAM,UAAU,mBAAmB,CAAC,OAAqB;IACvD,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;IAEhC,uBAAuB;IACvB,MAAM,WAAW,GAAG,CAAC,GAAW,EAAe,EAAE,CAAC,CAAC;QACjD,OAAO,EAAE,KAAK;QACd,SAAS,EAAE,EAAE;QACb,IAAI,EAAE,EAAE;QACR,KAAK,EAAE,EAAE;QACT,QAAQ,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,EAAE,aAAa,EAAE,EAAE,EAAE;QACxD,SAAS,EAAE;YACT,MAAM,EAAE,OAAO;YACf,QAAQ,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,YAAY,EAAE,EAAE,EAAE;YAClD,UAAU,EAAE,WAAW,CAAC,GAAG,EAAE,GAAG,KAAK;SACtC;QACD,YAAY,EAAE,GAAG;KAClB,CAAC,CAAC;IAEH,IAAI,CAAC;QACH,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC;QAE3D,IAAI,CAAC,KAAK,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC;YAC5B,OAAO,WAAW,CAAC,yBAAyB,CAAC,CAAC;QAChD,CAAC;QAED,WAAW;QACX,MAAM,MAAM,GAAG,qBAAqB,CAAC,KAAK,CAAC,CAAC;QAC5C,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,OAAO,IAAI,MAAM,CAAC,SAAS,CAAC,CAAC;QAE5D,kEAAkE;QAClE,oEAAoE;QACpE,IAAI,WAAmB,CAAC;QACxB,IAAI,YAAoB,CAAC;QACzB,IAAI,YAAoB,CAAC;QACzB,IAAI,YAAsB,CAAC;QAE3B,IAAI,OAAO,EAAE,CAAC;YACZ,MAAM,CAAC,SAAS,EAAE,GAAG,cAAc,CAAC,GAAG,MAAM,CAAC,SAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YACpE,MAAM,aAAa,GAAG,YAAY,CAChC,SAAS,EACT,cAAc,CAAC,IAAI,CAAC,GAAG,CAAC,EACxB,MAAM,CAAC,cAAc,EACrB,MAAM,CAAC,YAAY,IAAI,CAAC,EACxB,MAAM,CAAC,YAAY,CACpB,CAAC;YACF,WAAW,GAAG,GAAG,MAAM,CAAC,SAAS,QAAQ,CAAC;YAC1C,YAAY,GAAG,aAAa,CAAC,IAAI,CAAC;YAClC,YAAY,GAAG,aAAa,CAAC,IAAI,CAAC;YAClC,YAAY,GAAG,aAAa,CAAC,KAAK,CAAC;QACrC,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC;gBACtB,OAAO,WAAW,CAAC,+CAA+C,CAAC,CAAC;YACtE,CAAC;YACD,MAAM,QAAQ,GAAG,YAAY,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC;YAClE,WAAW,GAAG,MAAM,CAAC,SAAS,CAAC;YAC/B,YAAY,GAAG,QAAQ,CAAC,IAAI,CAAC;YAC7B,YAAY,GAAG,QAAQ,CAAC,IAAI,CAAC;YAC7B,YAAY,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAwB,+BAA+B;QACvF,CAAC;QACD,MAAM,oBAAoB,GAAG,YAAY,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,gCAAgC;QAE9F,sEAAsE;QACtE,MAAM,YAAY,GAAW,MAAM,CAAC,MAAM,IAAI,SAAS,CAAC;QACxD,MAAM,MAAM,GAAG,eAAe,CAAC,oBAAoB,EAAE;YACnD,OAAO,EAAE,MAAM,CAAC,OAAO;YACvB,YAAY,EAAE,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,YAAY;YACvD,QAAQ,EAAE,MAAM,CAAC,QAAQ;YACzB,MAAM,EAAE,MAAM,CAAC,MAAM;SACtB,CAAC,CAAC;QAEH,2BAA2B;QAC3B,MAAM,IAAI,GAAG,eAAe,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;QAE1E,2CAA2C;QAC3C,MAAM,UAAU,GAAG,CAAC,CAAC;QACrB,MAAM,aAAa,GAAa,EAAE,CAAC;QACnC,MAAM,aAAa,GAAa,EAAE,CAAC;QAEnC,yDAAyD;QACzD,MAAM,QAAQ,GAAG,EAAE,CAAC;QAEpB,wDAAwD;QACxD,IAAI,YAAY,GAAG,CAAC,CAAC,CAAC;QACtB,IAAI,aAAa,GAAG,UAAU,GAAG,MAAM,CAAC,WAAW,CAAC;QAEpD,4CAA4C;QAC5C,MAAM,QAAQ,GAAoE,EAAE,CAAC;QACrF,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,YAAY,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAC7C,MAAM,EAAE,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC;YAC3B,MAAM,GAAG,GAAG,oBAAoB,CAAC,CAAC,CAAC,CAAC;YACpC,MAAM,QAAQ,GAAG,cAAc,CAAC,EAAE,CAAC,CAAC;YACpC,IAAI,QAAQ,KAAK,SAAS;gBAAE,SAAS;YAErC,IAAI,YAAY,KAAK,CAAC,CAAC,IAAI,QAAQ,IAAI,YAAY,EAAE,CAAC;gBACpD,aAAa,EAAE,CAAC;YAClB,CAAC;YACD,YAAY,GAAG,QAAQ,CAAC;YACxB,QAAQ,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,aAAa,EAAE,CAAC,CAAC;QAC9D,CAAC;QAED,oEAAoE;QACpE,sEAAsE;QACtE,IAAI,CAAC,OAAO,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACpC,MAAM,QAAQ,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,EAAE,CAAC;YAChE,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBACzC,MAAM,QAAQ,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,EAAE,CAAC;gBAChE,IAAI,QAAQ,GAAG,QAAQ,GAAG,QAAQ,IAAI,QAAQ,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;oBAC9E,QAAQ,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;gBACvB,CAAC;YACH,CAAC;QACH,CAAC;QAED,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;YACzB,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC;YACzC,MAAM,SAAS,GAAG,CAAC,CAAC,MAAM,GAAG,UAAU,CAAC;YACxC,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,SAAS,EAAE,CAAC,CAAC;QAC9C,CAAC;QAED,yBAAyB;QACzB,MAAM,KAAK,GAAG,aAAa,CAAC,IAAI,EAAE,aAAa,CAAC,CAAC;QAEjD,kBAAkB;QAClB,MAAM,MAAM,GAAgB;YAC1B,OAAO,EAAE,IAAI;YACb,SAAS,EAAE,WAAW;YACtB,IAAI,EAAE,YAAY;YAClB,KAAK,EAAE,aAAa;YACpB,SAAS,EAAE,MAAM,CAAC,SAAS;YAC3B,QAAQ,EAAE;gBACR,SAAS,EAAE,MAAM,CAAC,SAAS;gBAC3B,IAAI,EAAE,MAAM,CAAC,IAAI;gBACjB,aAAa;aACd;YACD,SAAS,EAAE;gBACT,MAAM,EAAE,OAAO;gBACf,QAAQ,EAAE;oBACR,IAAI,EAAE,YAAY;oBAClB,IAAI,EAAE,YAAY;oBAClB,YAAY;iBACb;gBACD,UAAU,EAAE,WAAW,CAAC,GAAG,EAAE,GAAG,KAAK;aACtC;SACF,CAAC;QAEF,gBAAgB;QAChB,IAAI,YAAY,KAAK,KAAK,EAAE,CAAC;YAC3B,MAAM,IAAI,GAAG,oBAAoB,CAAC,MAAM,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;YAC7D,MAAM,CAAC,GAAG,GAAG,cAAc,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;QACpE,CAAC;QAED,iBAAiB;QACjB,IAAI,YAAY,KAAK,MAAM,EAAE,CAAC;YAC5B,MAAM,CAAC,IAAI,GAAG,gBAAgB,CAAC,EAAE,KAAK,EAAE,YAAY,EAAE,CAAC,CAAC;QAC1D,CAAC;QAED,uBAAuB;QACvB,IAAI,SAAS,EAAE,CAAC;YACd,MAAM,QAAQ,GAAkB;gBAC9B,KAAK;gBACL,QAAQ,EAAE;oBACR,MAAM,EAAE,OAAO;oBACf,MAAM,EAAE;wBACN,SAAS,EAAE,WAAW;wBACtB,SAAS,EAAE,MAAM,CAAC,SAAS;wBAC3B,aAAa,EAAE,MAAM,CAAC,aAAa;wBACnC,YAAY,EAAE,MAAM,CAAC,YAAY;wBACjC,cAAc,EAAE,MAAM,CAAC,cAAc;wBACrC,QAAQ,EAAE,MAAM,CAAC,QAAQ;wBACzB,UAAU,EAAE,MAAM,CAAC,UAAU;wBAC7B,QAAQ,EAAE,MAAM,CAAC,QAAQ;wBACzB,MAAM,EAAE,MAAM,CAAC,MAAM;wBACrB,OAAO,EAAE,MAAM,CAAC,OAAO;wBACvB,gBAAgB,EAAE,MAAM,CAAC,gBAAgB;wBACzC,eAAe,EAAE,MAAM,CAAC,eAAe;wBACvC,SAAS,EAAE,MAAM,CAAC,SAAS;wBAC3B,MAAM,EAAE,MAAM,CAAC,MAAM;wBACrB,aAAa,EAAE,MAAM,CAAC,aAAa;wBACnC,SAAS,EAAE,MAAM,CAAC,SAAS;wBAC3B,aAAa,EAAE,MAAM,CAAC,aAAa;qBACpC;oBACD,QAAQ,EAAE;wBACR,MAAM,EAAE,OAAO;wBACf,IAAI,EAAE,YAAY;wBAClB,IAAI,EAAE,YAAY;wBAClB,YAAY;qBACb;oBACD,OAAO,EAAE;wBACP,SAAS,EAAE,KAAK;wBAChB,KAAK,EAAE,KAAK;qBACb;oBACD,MAAM,EAAE;wBACN,SAAS,EAAE,MAAM,CAAC,SAAS;wBAC3B,IAAI,EAAE,MAAM,CAAC,IAAI;wBACjB,WAAW,EAAE,MAAM,CAAC,WAAW;qBAChC;oBACD,MAAM,EAAE;wBACN,KAAK,EAAE,aAAa;wBACpB,aAAa;wBACb,MAAM,EAAE,YAAY;qBACrB;iBACF;gBACD,OAAO,EAAE,IAAI;gBACb,UAAU,EAAE,WAAW,CAAC,GAAG,EAAE,GAAG,KAAK;aACtC,CAAC;YACF,eAAe,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;QACvC,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC7D,OAAO,WAAW,CAAC,GAAG,CAAC,CAAC;IAC1B,CAAC;AACH,CAAC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export { resolveProgression, tokenizeProgression } from "./roman-numeral";
|
|
2
|
-
export { FORM_TEMPLATES, findTemplate } from "./form-templates";
|
|
3
|
-
export type { FormTemplate } from "./form-templates";
|
|
4
|
-
export { resolveProgressionRequest, } from "./progression-resolver";
|
|
5
|
-
export type { ProgressionRequest, ProgressionResult, ProgressionExample, ProgressionChord, } from "./progression-resolver";
|
|
1
|
+
export { resolveProgression, tokenizeProgression } from "./roman-numeral.js";
|
|
2
|
+
export { FORM_TEMPLATES, findTemplate } from "./form-templates.js";
|
|
3
|
+
export type { FormTemplate } from "./form-templates.js";
|
|
4
|
+
export { resolveProgressionRequest, } from "./progression-resolver.js";
|
|
5
|
+
export type { ProgressionRequest, ProgressionResult, ProgressionExample, ProgressionChord, } from "./progression-resolver.js";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { resolveProgression, tokenizeProgression } from "./roman-numeral";
|
|
2
|
-
export { FORM_TEMPLATES, findTemplate } from "./form-templates";
|
|
3
|
-
export { resolveProgressionRequest, } from "./progression-resolver";
|
|
1
|
+
export { resolveProgression, tokenizeProgression } from "./roman-numeral.js";
|
|
2
|
+
export { FORM_TEMPLATES, findTemplate } from "./form-templates.js";
|
|
3
|
+
export { resolveProgressionRequest, } from "./progression-resolver.js";
|
|
4
4
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/progression/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/progression/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAC7E,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAEnE,OAAO,EACL,yBAAyB,GAC1B,MAAM,2BAA2B,CAAC"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { MAX_EXAMPLES } from "../config";
|
|
2
|
-
import { resolveChord } from "../resolver/chord-resolver";
|
|
3
|
-
import { resolveProgression, tokenizeProgression } from "./roman-numeral";
|
|
4
|
-
import { findTemplate } from "./form-templates";
|
|
1
|
+
import { MAX_EXAMPLES } from "../config.js";
|
|
2
|
+
import { resolveChord } from "../resolver/chord-resolver.js";
|
|
3
|
+
import { resolveProgression, tokenizeProgression } from "./roman-numeral.js";
|
|
4
|
+
import { findTemplate } from "./form-templates.js";
|
|
5
5
|
import { findVoicing, voicingPitchClasses, mapToVoicingQuality, queryVoicings, inferStyle, } from "@pepperhorn/chordl-voicings";
|
|
6
6
|
/**
|
|
7
7
|
* A set of contrasting styles to auto-cycle through when no style hint is given.
|
|
@@ -63,7 +63,7 @@ function getStyleVariations(styleHint) {
|
|
|
63
63
|
*/
|
|
64
64
|
function voiceChord(symbol, style) {
|
|
65
65
|
const resolved = resolveChord(symbol);
|
|
66
|
-
const quality = mapToVoicingQuality(resolved.type, resolved.
|
|
66
|
+
const quality = mapToVoicingQuality(resolved.type, resolved.intervals);
|
|
67
67
|
let notes = resolved.notes;
|
|
68
68
|
let voicingStyle;
|
|
69
69
|
if (quality && style) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"progression-resolver.js","sourceRoot":"","sources":["../../src/progression/progression-resolver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"progression-resolver.js","sourceRoot":"","sources":["../../src/progression/progression-resolver.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"roman-numeral.js","sourceRoot":"","sources":["../../src/progression/roman-numeral.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC;AAC7B,OAAO,EAAE,mBAAmB,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"roman-numeral.js","sourceRoot":"","sources":["../../src/progression/roman-numeral.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { WhiteNote } from "../types";
|
|
1
|
+
import type { WhiteNote } from "../types.js";
|
|
2
2
|
/** Check if a white-key index (mod 7) has a sharp. */
|
|
3
3
|
export declare function whiteIdxHasSharp(idx: number): boolean;
|
|
4
4
|
export interface LayoutOptions {
|
|
@@ -6,6 +6,17 @@ export interface LayoutOptions {
|
|
|
6
6
|
startingNote?: string;
|
|
7
7
|
spanFrom?: string;
|
|
8
8
|
spanTo?: string;
|
|
9
|
+
/**
|
|
10
|
+
* Whole octaves above the first note, one per note, when the caller knows
|
|
11
|
+
* where the voicing really sits.
|
|
12
|
+
*
|
|
13
|
+
* Without it the notes are read as an ascending stack — each note that fails
|
|
14
|
+
* to rise wraps into the next octave — which is the only thing bare pitch
|
|
15
|
+
* classes can support. A library voicing declares its octaves, and a
|
|
16
|
+
* declared tenth needs a window two octaves wide where the stack rule would
|
|
17
|
+
* size one for a third and crop the top note off the keyboard.
|
|
18
|
+
*/
|
|
19
|
+
octaveOffsets?: number[];
|
|
9
20
|
}
|
|
10
21
|
export interface LayoutResult {
|
|
11
22
|
startFrom: WhiteNote;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { WHITE_NOTE_ORDER } from "../engine/svg-constants";
|
|
2
|
-
import { normalizeToSharps } from "../engine/note-spelling";
|
|
1
|
+
import { WHITE_NOTE_ORDER } from "../engine/svg-constants.js";
|
|
2
|
+
import { normalizeToSharps } from "../engine/note-spelling.js";
|
|
3
3
|
// White notes that have a sharp (black key to their right)
|
|
4
4
|
const HAS_SHARP = new Set(["C", "D", "F", "G", "A"]);
|
|
5
5
|
/** Check if a white-key index (mod 7) has a sharp. */
|
|
@@ -61,7 +61,8 @@ function ensureFullBlackKeyGroups(startIdx, endIdx) {
|
|
|
61
61
|
return { startIdx, endIdx };
|
|
62
62
|
}
|
|
63
63
|
export function calculateLayout(notes, options = {}) {
|
|
64
|
-
const { padding = 1, startingNote, spanFrom, spanTo } = options;
|
|
64
|
+
const { padding = 1, startingNote, spanFrom, spanTo, octaveOffsets } = options;
|
|
65
|
+
const hasOffsets = octaveOffsets != null && octaveOffsets.length === notes.length;
|
|
65
66
|
// Explicit starting note: anchor the keyboard there
|
|
66
67
|
if (startingNote) {
|
|
67
68
|
const anchorKey = nearestWhiteKey(startingNote);
|
|
@@ -80,9 +81,19 @@ export function calculateLayout(notes, options = {}) {
|
|
|
80
81
|
// the previous wraps into the next octave (matches voicing rotation).
|
|
81
82
|
const anchorWhiteIdx = WHITE_NOTE_ORDER.indexOf(anchorKey);
|
|
82
83
|
const indices = [];
|
|
83
|
-
for (
|
|
84
|
-
let idx = WHITE_NOTE_ORDER.indexOf(
|
|
85
|
-
if (
|
|
84
|
+
for (let i = 0; i < whiteKeys.length; i++) {
|
|
85
|
+
let idx = WHITE_NOTE_ORDER.indexOf(whiteKeys[i]);
|
|
86
|
+
if (hasOffsets) {
|
|
87
|
+
// A declared placement: seven white keys to the octave, counted from
|
|
88
|
+
// the first note, whose own octave is the frame.
|
|
89
|
+
idx += 7 * octaveOffsets[i];
|
|
90
|
+
if (i === 0)
|
|
91
|
+
while (idx < anchorWhiteIdx)
|
|
92
|
+
idx += 7;
|
|
93
|
+
else
|
|
94
|
+
idx += indices[0] - WHITE_NOTE_ORDER.indexOf(whiteKeys[0]);
|
|
95
|
+
}
|
|
96
|
+
else if (indices.length === 0) {
|
|
86
97
|
// First note: place relative to anchor (must be >= anchor)
|
|
87
98
|
while (idx < anchorWhiteIdx)
|
|
88
99
|
idx += 7;
|
|
@@ -142,17 +153,22 @@ export function calculateLayout(notes, options = {}) {
|
|
|
142
153
|
// the previous one (in white-key index) wraps into the next octave.
|
|
143
154
|
const whiteKeys = notes.map(nearestWhiteKey);
|
|
144
155
|
const ascending = [];
|
|
145
|
-
for (
|
|
146
|
-
let idx = WHITE_NOTE_ORDER.indexOf(
|
|
147
|
-
if (
|
|
156
|
+
for (let i = 0; i < whiteKeys.length; i++) {
|
|
157
|
+
let idx = WHITE_NOTE_ORDER.indexOf(whiteKeys[i]);
|
|
158
|
+
if (hasOffsets) {
|
|
159
|
+
// A declared placement, so no wrapping is inferred: the offsets already
|
|
160
|
+
// say which octave each note is in, seven white keys apart.
|
|
161
|
+
idx += 7 * octaveOffsets[i];
|
|
162
|
+
}
|
|
163
|
+
else if (ascending.length > 0) {
|
|
148
164
|
const lastIdx = ascending[ascending.length - 1];
|
|
149
165
|
while (idx <= lastIdx)
|
|
150
166
|
idx += 7;
|
|
151
167
|
}
|
|
152
168
|
ascending.push(idx);
|
|
153
169
|
}
|
|
154
|
-
const minAsc = ascending
|
|
155
|
-
const maxAsc = ascending
|
|
170
|
+
const minAsc = Math.min(...ascending);
|
|
171
|
+
const maxAsc = Math.max(...ascending);
|
|
156
172
|
let startIdx = minAsc - padding;
|
|
157
173
|
let endIdx = maxAsc + padding;
|
|
158
174
|
// Black-key context padding: if an edge white key has a sharp, extend by 1
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auto-layout.js","sourceRoot":"","sources":["../../src/resolver/auto-layout.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"auto-layout.js","sourceRoot":"","sources":["../../src/resolver/auto-layout.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,7 +2,17 @@ export interface ResolvedChord {
|
|
|
2
2
|
notes: string[];
|
|
3
3
|
root: string;
|
|
4
4
|
type: string;
|
|
5
|
-
/**
|
|
5
|
+
/**
|
|
6
|
+
* Interval names relative to the root (e.g. ["1P", "3M", "5P", "7M"]).
|
|
7
|
+
*
|
|
8
|
+
* Populated on every branch of `resolveChord` — tonal, `buildSpecialChord`
|
|
9
|
+
* and `resolveWithFallback` alike. `mapToVoicingQuality` classifies chords by
|
|
10
|
+
* these rather than by the shape of `type`, so a branch that left them
|
|
11
|
+
* undefined would silently fall back to reading the chord's name.
|
|
12
|
+
*
|
|
13
|
+
* Unlike `notes`, these are *not* rotated by `inversion` below: they describe
|
|
14
|
+
* the chord, not the order its notes are voiced in.
|
|
15
|
+
*/
|
|
6
16
|
intervals?: string[];
|
|
7
17
|
}
|
|
8
18
|
export declare function resolveChord(chordName: string, inversion?: number): ResolvedChord;
|
|
@@ -52,6 +52,12 @@ function resolveWithFallback(chordName) {
|
|
|
52
52
|
const chord = Chord.get(root + suffix);
|
|
53
53
|
if (!chord.empty) {
|
|
54
54
|
let notes = chord.notes.map(simplifyNote);
|
|
55
|
+
// Kept in step with `notes`, entry for entry: an interval is pushed
|
|
56
|
+
// exactly when its note is. `mapToVoicingQuality` classifies by interval,
|
|
57
|
+
// and the type string this branch returns ("major (extended)") names only
|
|
58
|
+
// the *base* chord — the alterations that made it a fallback are not in
|
|
59
|
+
// it, so the name alone cannot describe the chord.
|
|
60
|
+
const intervals = [...chord.intervals];
|
|
55
61
|
// Add extra notes from stripped alterations
|
|
56
62
|
for (const ivl of extraIntervals) {
|
|
57
63
|
const extra = Note.transpose(root, ivl);
|
|
@@ -60,10 +66,16 @@ function resolveWithFallback(chordName) {
|
|
|
60
66
|
// Replace if same degree already exists, otherwise add
|
|
61
67
|
if (!notes.includes(normalized)) {
|
|
62
68
|
notes.push(normalized);
|
|
69
|
+
intervals.push(ivl);
|
|
63
70
|
}
|
|
64
71
|
}
|
|
65
72
|
}
|
|
66
|
-
return {
|
|
73
|
+
return {
|
|
74
|
+
notes,
|
|
75
|
+
root: simplifyNote(root),
|
|
76
|
+
type: chord.type + " (extended)",
|
|
77
|
+
intervals,
|
|
78
|
+
};
|
|
67
79
|
}
|
|
68
80
|
}
|
|
69
81
|
return null;
|
|
@@ -101,6 +113,7 @@ function buildSpecialChord(name) {
|
|
|
101
113
|
notes: [root, Note.transpose(root, "5P"), Note.transpose(root, "7m")].map(simplifyNote),
|
|
102
114
|
root: simplifyNote(root),
|
|
103
115
|
type: "7omit3",
|
|
116
|
+
intervals: ["1P", "5P", "7m"],
|
|
104
117
|
};
|
|
105
118
|
}
|
|
106
119
|
// Xm7sus / Xm7sus4 → root, m3, P4, m7
|
|
@@ -114,6 +127,7 @@ function buildSpecialChord(name) {
|
|
|
114
127
|
].map(simplifyNote),
|
|
115
128
|
root: simplifyNote(root),
|
|
116
129
|
type: "m7sus4",
|
|
130
|
+
intervals: ["1P", "3m", "4P", "7m"],
|
|
117
131
|
};
|
|
118
132
|
}
|
|
119
133
|
// Xm6/9 → root, m3, 5, 6, 9
|
|
@@ -128,6 +142,9 @@ function buildSpecialChord(name) {
|
|
|
128
142
|
].map(simplifyNote),
|
|
129
143
|
root: simplifyNote(root),
|
|
130
144
|
type: "m6/9",
|
|
145
|
+
// The ninth is transposed as a 2M above, which is the same pitch class;
|
|
146
|
+
// named here as the ninth the chord actually spells.
|
|
147
|
+
intervals: ["1P", "3m", "5P", "6M", "9M"],
|
|
131
148
|
};
|
|
132
149
|
}
|
|
133
150
|
return null;
|
|
@@ -145,11 +162,19 @@ export function resolveChord(chordName, inversion) {
|
|
|
145
162
|
notes = special.notes;
|
|
146
163
|
root = special.root;
|
|
147
164
|
type = special.type;
|
|
165
|
+
intervals = special.intervals;
|
|
148
166
|
}
|
|
149
167
|
else if (!chord.empty) {
|
|
150
168
|
notes = chord.notes.map(simplifyNote);
|
|
151
169
|
root = simplifyNote(chord.tonic ?? notes[0]);
|
|
152
|
-
|
|
170
|
+
// tonal names most of its chord types but not all: `Cadd9`, `CM7b5` and
|
|
171
|
+
// `C6#11` resolve to real notes carrying `type: ""`. An empty type tells a
|
|
172
|
+
// consumer nothing — `mapToVoicingQuality` reads this field to pick a
|
|
173
|
+
// voicing — so fall back to the type's own first alias, which is the
|
|
174
|
+
// canonical spelling tonal lists for it. The display name comes from the
|
|
175
|
+
// parsed chord name, not from here, so this only affects consumers that
|
|
176
|
+
// reason about the chord's quality.
|
|
177
|
+
type = chord.type || chord.aliases?.[0] || "";
|
|
153
178
|
intervals = chord.intervals;
|
|
154
179
|
}
|
|
155
180
|
else {
|
|
@@ -161,6 +186,7 @@ export function resolveChord(chordName, inversion) {
|
|
|
161
186
|
notes = fallback.notes;
|
|
162
187
|
root = fallback.root;
|
|
163
188
|
type = fallback.type;
|
|
189
|
+
intervals = fallback.intervals;
|
|
164
190
|
}
|
|
165
191
|
// Apply inversion: rotate notes array
|
|
166
192
|
if (inversion && inversion > 0) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chord-resolver.js","sourceRoot":"","sources":["../../src/resolver/chord-resolver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,IAAI,EAAY,MAAM,OAAO,CAAC;AAE9C;;;GAGG;AACH,SAAS,YAAY,CAAC,IAAY;IAChC,MAAM,UAAU,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACvC,OAAO,UAAU,IAAI,IAAI,CAAC;AAC5B,CAAC;AAED,2DAA2D;AAC3D,MAAM,aAAa,GACjB,mDAAmD,CAAC;AAEtD,MAAM,sBAAsB,GAA2B;IACrD,IAAI,EAAE,IAAI;IACV,IAAI,EAAE,IAAI;IACV,IAAI,EAAE,IAAI;IACV,IAAI,EAAE,IAAI;IACV,KAAK,EAAE,IAAI;IACX,KAAK,EAAE,IAAI;IACX,KAAK,EAAE,IAAI;IACX,KAAK,EAAE,IAAI;IACX,MAAM,EAAE,IAAI;IACZ,OAAO,EAAE,IAAI;IACb,OAAO,EAAE,IAAI;IACb,OAAO,EAAE,IAAI;IACb,OAAO,EAAE,IAAI;IACb,QAAQ,EAAE,IAAI;IACd,QAAQ,EAAE,IAAI;CACf,CAAC;AAEF,kEAAkE;AAClE,kEAAkE;AAClE,SAAS,mBAAmB,CAC1B,SAAiB;IAEjB,oBAAoB;IACpB,MAAM,SAAS,GAAG,SAAS,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC;IACnD,IAAI,CAAC,SAAS;QAAE,OAAO,IAAI,CAAC;IAE5B,MAAM,IAAI,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;IAC1B,IAAI,MAAM,GAAG,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC1C,MAAM,cAAc,GAAa,EAAE,CAAC;IAEpC,iEAAiE;IACjE,IAAI,QAAQ,GAAG,CAAC,CAAC;IACjB,OAAO,MAAM,IAAI,QAAQ,GAAG,CAAC,EAAE,CAAC;QAC9B,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;QAC1C,IAAI,CAAC,KAAK;YAAE,MAAM;QAElB,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QACvB,MAAM,QAAQ,GAAG,sBAAsB,CAAC,KAAK,CAAC,CAAC;QAC/C,IAAI,CAAC,QAAQ;YAAE,MAAM;QAErB,cAAc,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QACjC,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QACxC,QAAQ,EAAE,CAAC;QAEX,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,GAAG,MAAM,CAAC,CAAC;QACvC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;YACjB,IAAI,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"chord-resolver.js","sourceRoot":"","sources":["../../src/resolver/chord-resolver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,IAAI,EAAY,MAAM,OAAO,CAAC;AAE9C;;;GAGG;AACH,SAAS,YAAY,CAAC,IAAY;IAChC,MAAM,UAAU,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACvC,OAAO,UAAU,IAAI,IAAI,CAAC;AAC5B,CAAC;AAED,2DAA2D;AAC3D,MAAM,aAAa,GACjB,mDAAmD,CAAC;AAEtD,MAAM,sBAAsB,GAA2B;IACrD,IAAI,EAAE,IAAI;IACV,IAAI,EAAE,IAAI;IACV,IAAI,EAAE,IAAI;IACV,IAAI,EAAE,IAAI;IACV,KAAK,EAAE,IAAI;IACX,KAAK,EAAE,IAAI;IACX,KAAK,EAAE,IAAI;IACX,KAAK,EAAE,IAAI;IACX,MAAM,EAAE,IAAI;IACZ,OAAO,EAAE,IAAI;IACb,OAAO,EAAE,IAAI;IACb,OAAO,EAAE,IAAI;IACb,OAAO,EAAE,IAAI;IACb,QAAQ,EAAE,IAAI;IACd,QAAQ,EAAE,IAAI;CACf,CAAC;AAEF,kEAAkE;AAClE,kEAAkE;AAClE,SAAS,mBAAmB,CAC1B,SAAiB;IAEjB,oBAAoB;IACpB,MAAM,SAAS,GAAG,SAAS,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC;IACnD,IAAI,CAAC,SAAS;QAAE,OAAO,IAAI,CAAC;IAE5B,MAAM,IAAI,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;IAC1B,IAAI,MAAM,GAAG,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC1C,MAAM,cAAc,GAAa,EAAE,CAAC;IAEpC,iEAAiE;IACjE,IAAI,QAAQ,GAAG,CAAC,CAAC;IACjB,OAAO,MAAM,IAAI,QAAQ,GAAG,CAAC,EAAE,CAAC;QAC9B,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;QAC1C,IAAI,CAAC,KAAK;YAAE,MAAM;QAElB,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QACvB,MAAM,QAAQ,GAAG,sBAAsB,CAAC,KAAK,CAAC,CAAC;QAC/C,IAAI,CAAC,QAAQ;YAAE,MAAM;QAErB,cAAc,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QACjC,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QACxC,QAAQ,EAAE,CAAC;QAEX,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,GAAG,MAAM,CAAC,CAAC;QACvC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;YACjB,IAAI,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;YAC1C,oEAAoE;YACpE,0EAA0E;YAC1E,0EAA0E;YAC1E,wEAAwE;YACxE,mDAAmD;YACnD,MAAM,SAAS,GAAG,CAAC,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC;YAEvC,4CAA4C;YAC5C,KAAK,MAAM,GAAG,IAAI,cAAc,EAAE,CAAC;gBACjC,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;gBACxC,IAAI,KAAK,EAAE,CAAC;oBACV,MAAM,UAAU,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;oBACvC,uDAAuD;oBACvD,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;wBAChC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;wBACvB,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;oBACtB,CAAC;gBACH,CAAC;YACH,CAAC;YAED,OAAO;gBACL,KAAK;gBACL,IAAI,EAAE,YAAY,CAAC,IAAI,CAAC;gBACxB,IAAI,EAAE,KAAK,CAAC,IAAI,GAAG,aAAa;gBAChC,SAAS;aACV,CAAC;QACJ,CAAC;IACH,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAoBD,wEAAwE;AACxE,SAAS,kBAAkB,CAAC,IAAY;IACtC,0BAA0B;IAC1B,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC;IAC/C,IAAI,CAAC,SAAS;QAAE,OAAO,IAAI,CAAC;IAC5B,MAAM,IAAI,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;IAC1B,IAAI,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAErC,2EAA2E;IAE3E,iCAAiC;IACjC,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;IAE1C,gEAAgE;IAChE,wDAAwD;IAExD,gEAAgE;IAChE,2CAA2C;IAC3C,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAEzC,kDAAkD;IAClD,0CAA0C;IAE1C,OAAO,IAAI,GAAG,MAAM,CAAC;AACvB,CAAC;AAED,+DAA+D;AAC/D,SAAS,iBAAiB,CACxB,IAAY;IAEZ,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC;IAC/C,IAAI,CAAC,SAAS;QAAE,OAAO,IAAI,CAAC;IAC5B,MAAM,IAAI,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;IAC1B,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAEvC,mCAAmC;IACnC,IAAI,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;QAC7B,OAAO;YACL,KAAK,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,YAAY,CAAC;YACvF,IAAI,EAAE,YAAY,CAAC,IAAI,CAAC;YACxB,IAAI,EAAE,QAAQ;YACd,SAAS,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC;SAC9B,CAAC;IACJ,CAAC;IAED,sCAAsC;IACtC,IAAI,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;QAC9B,OAAO;YACL,KAAK,EAAE;gBACL,IAAI;gBACJ,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC;gBAC1B,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC;gBAC1B,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC;aAC3B,CAAC,GAAG,CAAC,YAAY,CAAC;YACnB,IAAI,EAAE,YAAY,CAAC,IAAI,CAAC;YACxB,IAAI,EAAE,QAAQ;YACd,SAAS,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC;SACpC,CAAC;IACJ,CAAC;IAED,4BAA4B;IAC5B,IAAI,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;QAC5B,OAAO;YACL,KAAK,EAAE;gBACL,IAAI;gBACJ,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC;gBAC1B,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC;gBAC1B,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC;gBAC1B,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC;aAC3B,CAAC,GAAG,CAAC,YAAY,CAAC;YACnB,IAAI,EAAE,YAAY,CAAC,IAAI,CAAC;YACxB,IAAI,EAAE,MAAM;YACZ,wEAAwE;YACxE,qDAAqD;YACrD,SAAS,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC;SAC1C,CAAC;IACJ,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,YAAY,CAC1B,SAAiB,EACjB,SAAkB;IAElB,SAAS,GAAG,kBAAkB,CAAC,SAAS,CAAC,CAAC;IAC1C,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IAEnC,IAAI,KAAe,CAAC;IACpB,IAAI,IAAY,CAAC;IACjB,IAAI,IAAY,CAAC;IACjB,IAAI,SAA+B,CAAC;IAEpC,uDAAuD;IACvD,MAAM,OAAO,GAAG,iBAAiB,CAAC,SAAS,CAAC,CAAC;IAC7C,IAAI,OAAO,EAAE,CAAC;QACZ,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;QACtB,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;QACpB,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;QACpB,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC;IAChC,CAAC;SAAM,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QACxB,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;QACtC,IAAI,GAAG,YAAY,CAAC,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QAC7C,wEAAwE;QACxE,2EAA2E;QAC3E,sEAAsE;QACtE,qEAAqE;QACrE,yEAAyE;QACzE,wEAAwE;QACxE,oCAAoC;QACpC,IAAI,GAAG,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAC9C,SAAS,GAAG,KAAK,CAAC,SAAS,CAAC;IAC9B,CAAC;SAAM,CAAC;QACN,gEAAgE;QAChE,MAAM,QAAQ,GAAG,mBAAmB,CAAC,SAAS,CAAC,CAAC;QAChD,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,MAAM,IAAI,KAAK,CAAC,mBAAmB,SAAS,GAAG,CAAC,CAAC;QACnD,CAAC;QACD,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC;QACvB,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC;QACrB,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC;QACrB,SAAS,GAAG,QAAQ,CAAC,SAAS,CAAC;IACjC,CAAC;IAED,sCAAsC;IACtC,IAAI,SAAS,IAAI,SAAS,GAAG,CAAC,EAAE,CAAC;QAC/B,MAAM,QAAQ,GAAG,SAAS,GAAG,KAAK,CAAC,MAAM,CAAC;QAC1C,KAAK,GAAG,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC;IAClE,CAAC;IAED,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;AAC1C,CAAC"}
|
|
@@ -3,7 +3,10 @@ export interface ResolvedScale {
|
|
|
3
3
|
notes: string[];
|
|
4
4
|
root: string;
|
|
5
5
|
type: string;
|
|
6
|
-
/** Single-octave Tonal intervals (e.g. ["1P","2M","3M","4P","5P","6M","7M"])
|
|
6
|
+
/** Single-octave Tonal intervals (e.g. ["1P","2M","3M","4P","5P","6M","7M"]),
|
|
7
|
+
* rotated to match `notes` when a custom starting note is used. */
|
|
7
8
|
intervals: string[];
|
|
9
|
+
/** Index into the un-rotated scale that `notes` starts on (0 = root). */
|
|
10
|
+
startIndex: number;
|
|
8
11
|
}
|
|
9
|
-
export declare function resolveScale(root: string, scaleType: string, direction?: "ascending" | "descending", octaves?: number): ResolvedScale;
|
|
12
|
+
export declare function resolveScale(root: string, scaleType: string, direction?: "ascending" | "descending", octaves?: number, startOn?: string): ResolvedScale;
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Scale resolver — resolves scale names to notes via Tonal.
|
|
3
|
-
* Handles melodic minor direction, multi-octave expansion,
|
|
4
|
-
* generates Tonal interval arrays for degree
|
|
3
|
+
* Handles melodic minor direction, multi-octave expansion, rotation to a
|
|
4
|
+
* custom starting note, and generates Tonal interval arrays for degree
|
|
5
|
+
* label computation.
|
|
5
6
|
*/
|
|
6
|
-
import { Scale } from "tonal";
|
|
7
|
+
import { Note, Scale } from "tonal";
|
|
7
8
|
/** Normalize common scale name variants for Tonal compatibility. */
|
|
8
9
|
const SCALE_NAME_MAP = {
|
|
9
10
|
"natural minor": "minor",
|
|
@@ -14,7 +15,7 @@ const SCALE_NAME_MAP = {
|
|
|
14
15
|
"whole tone": "whole tone",
|
|
15
16
|
"bebop": "bebop major",
|
|
16
17
|
};
|
|
17
|
-
export function resolveScale(root, scaleType, direction, octaves = 1) {
|
|
18
|
+
export function resolveScale(root, scaleType, direction, octaves = 1, startOn) {
|
|
18
19
|
// Melodic minor descending = natural minor
|
|
19
20
|
let effectiveType = scaleType;
|
|
20
21
|
if (scaleType === "melodic minor" && direction === "descending") {
|
|
@@ -26,20 +27,39 @@ export function resolveScale(root, scaleType, direction, octaves = 1) {
|
|
|
26
27
|
if (scale.empty) {
|
|
27
28
|
throw new Error(`Unknown scale: "${root} ${scaleType}"`);
|
|
28
29
|
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
30
|
+
let oneOctaveNotes = scale.notes;
|
|
31
|
+
let intervals = scale.intervals;
|
|
32
|
+
let startIndex = 0;
|
|
33
|
+
// "starting on X" — rotate the scale so it runs one octave (or N octaves)
|
|
34
|
+
// from that note instead of the root. Matched by pitch (chroma) so an
|
|
35
|
+
// enharmonic spelling like G# still finds Ab.
|
|
36
|
+
if (startOn) {
|
|
37
|
+
const targetChroma = Note.chroma(startOn);
|
|
38
|
+
startIndex = oneOctaveNotes.findIndex((n) => Note.chroma(n) === targetChroma);
|
|
39
|
+
if (startIndex < 0) {
|
|
40
|
+
throw new Error(`${startOn} isn't in ${root} ${scaleType} — the notes are: ${oneOctaveNotes.join(", ")}`);
|
|
41
|
+
}
|
|
42
|
+
if (startIndex > 0) {
|
|
43
|
+
oneOctaveNotes = [
|
|
44
|
+
...oneOctaveNotes.slice(startIndex),
|
|
45
|
+
...oneOctaveNotes.slice(0, startIndex),
|
|
46
|
+
];
|
|
47
|
+
intervals = [...intervals.slice(startIndex), ...intervals.slice(0, startIndex)];
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
// Expand across octaves: repeat pitch classes + add final starting note
|
|
32
51
|
const notes = [];
|
|
33
52
|
for (let oct = 0; oct < octaves; oct++) {
|
|
34
53
|
notes.push(...oneOctaveNotes);
|
|
35
54
|
}
|
|
36
|
-
// Add the final
|
|
55
|
+
// Add the final starting note to complete the last octave
|
|
37
56
|
notes.push(oneOctaveNotes[0]);
|
|
38
57
|
return {
|
|
39
58
|
notes,
|
|
40
59
|
root,
|
|
41
60
|
type: scaleType,
|
|
42
61
|
intervals,
|
|
62
|
+
startIndex,
|
|
43
63
|
};
|
|
44
64
|
}
|
|
45
65
|
//# sourceMappingURL=scale-resolver.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scale-resolver.js","sourceRoot":"","sources":["../../src/resolver/scale-resolver.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"scale-resolver.js","sourceRoot":"","sources":["../../src/resolver/scale-resolver.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,OAAO,CAAC;AAcpC,oEAAoE;AACpE,MAAM,cAAc,GAA2B;IAC7C,eAAe,EAAE,OAAO;IACxB,gBAAgB,EAAE,gBAAgB;IAClC,eAAe,EAAE,eAAe;IAChC,kBAAkB,EAAE,kBAAkB;IACtC,kBAAkB,EAAE,kBAAkB;IACtC,YAAY,EAAE,YAAY;IAC1B,OAAO,EAAE,aAAa;CACvB,CAAC;AAEF,MAAM,UAAU,YAAY,CAC1B,IAAY,EACZ,SAAiB,EACjB,SAAsC,EACtC,UAAkB,CAAC,EACnB,OAAgB;IAEhB,2CAA2C;IAC3C,IAAI,aAAa,GAAG,SAAS,CAAC;IAC9B,IAAI,SAAS,KAAK,eAAe,IAAI,SAAS,KAAK,YAAY,EAAE,CAAC;QAChE,aAAa,GAAG,OAAO,CAAC;IAC1B,CAAC;IAED,2BAA2B;IAC3B,MAAM,SAAS,GAAG,cAAc,CAAC,aAAa,CAAC,IAAI,aAAa,CAAC;IAEjE,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,IAAI,IAAI,SAAS,EAAE,CAAC,CAAC;IAChD,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;QAChB,MAAM,IAAI,KAAK,CAAC,mBAAmB,IAAI,IAAI,SAAS,GAAG,CAAC,CAAC;IAC3D,CAAC;IAED,IAAI,cAAc,GAAG,KAAK,CAAC,KAAK,CAAC;IACjC,IAAI,SAAS,GAAG,KAAK,CAAC,SAAS,CAAC;IAChC,IAAI,UAAU,GAAG,CAAC,CAAC;IAEnB,0EAA0E;IAC1E,sEAAsE;IACtE,8CAA8C;IAC9C,IAAI,OAAO,EAAE,CAAC;QACZ,MAAM,YAAY,GAAG,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAC1C,UAAU,GAAG,cAAc,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,YAAY,CAAC,CAAC;QAC9E,IAAI,UAAU,GAAG,CAAC,EAAE,CAAC;YACnB,MAAM,IAAI,KAAK,CACb,GAAG,OAAO,aAAa,IAAI,IAAI,SAAS,qBAAqB,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CACzF,CAAC;QACJ,CAAC;QACD,IAAI,UAAU,GAAG,CAAC,EAAE,CAAC;YACnB,cAAc,GAAG;gBACf,GAAG,cAAc,CAAC,KAAK,CAAC,UAAU,CAAC;gBACnC,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC,EAAE,UAAU,CAAC;aACvC,CAAC;YACF,SAAS,GAAG,CAAC,GAAG,SAAS,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC;QAClF,CAAC;IACH,CAAC;IAED,wEAAwE;IACxE,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,OAAO,EAAE,GAAG,EAAE,EAAE,CAAC;QACvC,KAAK,CAAC,IAAI,CAAC,GAAG,cAAc,CAAC,CAAC;IAChC,CAAC;IACD,0DAA0D;IAC1D,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC;IAE9B,OAAO;QACL,KAAK;QACL,IAAI;QACJ,IAAI,EAAE,SAAS;QACf,SAAS;QACT,UAAU;KACX,CAAC;AACJ,CAAC"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import type { ColorTheme } from "../types";
|
|
1
|
+
import type { ColorTheme } from "../types.js";
|
|
2
2
|
export declare const boomwhackerTheme: ColorTheme;
|