@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
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"boomwhacker.js","sourceRoot":"","sources":["../../src/themes/boomwhacker.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"boomwhacker.js","sourceRoot":"","sources":["../../src/themes/boomwhacker.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAEpF,2CAA2C;AAC3C,MAAM,YAAY,GAA2B;IAC3C,CAAC,EAAE,SAAS;IACZ,IAAI,EAAE,SAAS;IACf,CAAC,EAAE,SAAS;IACZ,IAAI,EAAE,SAAS;IACf,CAAC,EAAE,SAAS;IACZ,CAAC,EAAE,SAAS;IACZ,IAAI,EAAE,SAAS;IACf,CAAC,EAAE,SAAS;IACZ,IAAI,EAAE,SAAS;IACf,CAAC,EAAE,SAAS;IACZ,IAAI,EAAE,SAAS;IACf,CAAC,EAAE,SAAS;CACb,CAAC;AAEF,0CAA0C;AAC1C,MAAM,WAAW,GAAG,IAAI,CAAC,CAAC,sBAAsB;AAEhD,SAAS,IAAI,CAAC,GAAW;IACvB,OAAO,GAAG,GAAG,WAAW,CAAC;AAC3B,CAAC;AAED,MAAM,CAAC,MAAM,gBAAgB,GAAe;IAC1C,IAAI,EAAE,aAAa;IACnB,QAAQ,EAAE,CAAC,IAAI,EAAE,WAAW,EAAE,EAAE;QAC9B,IAAI,CAAC,WAAW;YAAE,OAAO,kBAAkB,CAAC;QAC5C,OAAO,YAAY,CAAC,IAAI,CAAC,IAAI,kBAAkB,CAAC;IAClD,CAAC;IACD,QAAQ,EAAE,CAAC,IAAI,EAAE,WAAW,EAAE,EAAE;QAC9B,IAAI,CAAC,WAAW;YAAE,OAAO,kBAAkB,CAAC;QAC5C,OAAO,YAAY,CAAC,IAAI,CAAC,IAAI,kBAAkB,CAAC;IAClD,CAAC;CACF,CAAC"}
|
package/dist/themes/crf.d.ts
CHANGED
package/dist/themes/crf.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DEFAULT_WHITE_FILL, DEFAULT_BLACK_FILL } from "../engine/svg-constants";
|
|
1
|
+
import { DEFAULT_WHITE_FILL, DEFAULT_BLACK_FILL } from "../engine/svg-constants.js";
|
|
2
2
|
export const CRF_PITCH_PALETTE = {
|
|
3
3
|
C: { hex: "#f86e6e", cmyk: [0, 56, 56, 3] },
|
|
4
4
|
"C#": { hex: "#f58841", cmyk: [0, 44, 73, 4] },
|
package/dist/themes/crf.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"crf.js","sourceRoot":"","sources":["../../src/themes/crf.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"crf.js","sourceRoot":"","sources":["../../src/themes/crf.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAiBpF,MAAM,CAAC,MAAM,iBAAiB,GAAkC;IAC9D,CAAC,EAAK,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE;IAC9C,IAAI,EAAE,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE;IAC9C,CAAC,EAAK,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE;IAC9C,IAAI,EAAE,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE;IAC/C,CAAC,EAAK,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE;IAC7C,CAAC,EAAK,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE;IAC9C,IAAI,EAAE,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE;IAC/C,CAAC,EAAK,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE;IAC/C,IAAI,EAAE,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE;IAC7C,CAAC,EAAK,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE;IAC9C,IAAI,EAAE,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE;IAC9C,CAAC,EAAK,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE;CAChD,CAAC;AAEF,2FAA2F;AAC3F,MAAM,UAAU,UAAU,CAAC,IAAsC;IAC/D,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC;IAC1B,OAAO,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC;AAC5C,CAAC;AAED,MAAM,CAAC,MAAM,QAAQ,GAAe;IAClC,IAAI,EAAE,KAAK;IACX,QAAQ,EAAE,CAAC,IAAI,EAAE,WAAW,EAAE,EAAE;QAC9B,IAAI,CAAC,WAAW;YAAE,OAAO,kBAAkB,CAAC;QAC5C,OAAO,iBAAiB,CAAC,IAAI,CAAC,EAAE,GAAG,IAAI,kBAAkB,CAAC;IAC5D,CAAC;IACD,QAAQ,EAAE,CAAC,IAAI,EAAE,WAAW,EAAE,EAAE;QAC9B,IAAI,CAAC,WAAW;YAAE,OAAO,kBAAkB,CAAC;QAC5C,OAAO,iBAAiB,CAAC,IAAI,CAAC,EAAE,GAAG,IAAI,kBAAkB,CAAC;IAC5D,CAAC;CACF,CAAC"}
|
package/dist/themes/index.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import type { ColorTheme } from "../types";
|
|
1
|
+
import type { ColorTheme } from "../types.js";
|
|
2
2
|
export declare function getTheme(name: string): ColorTheme | undefined;
|
|
3
3
|
export declare function resolveTheme(theme: ColorTheme | string | undefined, highlightColor?: string): ColorTheme | undefined;
|
package/dist/themes/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { boomwhackerTheme } from "./boomwhacker";
|
|
2
|
-
import { crfTheme } from "./crf";
|
|
3
|
-
import { createSimpleTheme } from "./simple";
|
|
1
|
+
import { boomwhackerTheme } from "./boomwhacker.js";
|
|
2
|
+
import { crfTheme } from "./crf.js";
|
|
3
|
+
import { createSimpleTheme } from "./simple.js";
|
|
4
4
|
const themeRegistry = {
|
|
5
5
|
boomwhacker: boomwhackerTheme,
|
|
6
6
|
crf: crfTheme,
|
package/dist/themes/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/themes/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/themes/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AACpC,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAEhD,MAAM,aAAa,GAA+B;IAChD,WAAW,EAAE,gBAAgB;IAC7B,GAAG,EAAE,QAAQ;IACb,MAAM,EAAE,iBAAiB,EAAE;CAC5B,CAAC;AAEF,MAAM,UAAU,QAAQ,CAAC,IAAY;IACnC,OAAO,aAAa,CAAC,IAAI,CAAC,CAAC;AAC7B,CAAC;AAED,MAAM,UAAU,YAAY,CAC1B,KAAsC,EACtC,cAAuB;IAEvB,IAAI,CAAC,KAAK,IAAI,CAAC,cAAc;QAAE,OAAO,SAAS,CAAC;IAChD,IAAI,CAAC,KAAK,IAAI,cAAc;QAAE,OAAO,iBAAiB,CAAC,cAAc,CAAC,CAAC;IACvE,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,IAAI,KAAK,KAAK,QAAQ,IAAI,cAAc,EAAE,CAAC;YACzC,OAAO,iBAAiB,CAAC,cAAc,CAAC,CAAC;QAC3C,CAAC;QACD,OAAO,aAAa,CAAC,KAAK,CAAC,CAAC;IAC9B,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
|
package/dist/themes/simple.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import type { ColorTheme } from "../types";
|
|
1
|
+
import type { ColorTheme } from "../types.js";
|
|
2
2
|
export declare function createSimpleTheme(highlightColor?: string): ColorTheme;
|
package/dist/themes/simple.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DEFAULT_WHITE_FILL, DEFAULT_BLACK_FILL } from "../engine/svg-constants";
|
|
1
|
+
import { DEFAULT_WHITE_FILL, DEFAULT_BLACK_FILL } from "../engine/svg-constants.js";
|
|
2
2
|
const DEFAULT_HIGHLIGHT = "#a0c6e8";
|
|
3
3
|
const DEFAULT_BLACK_HIGHLIGHT = "#5a8ab5";
|
|
4
4
|
export function createSimpleTheme(highlightColor) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"simple.js","sourceRoot":"","sources":["../../src/themes/simple.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"simple.js","sourceRoot":"","sources":["../../src/themes/simple.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAEpF,MAAM,iBAAiB,GAAG,SAAS,CAAC;AACpC,MAAM,uBAAuB,GAAG,SAAS,CAAC;AAE1C,MAAM,UAAU,iBAAiB,CAAC,cAAuB;IACvD,MAAM,cAAc,GAAG,cAAc,IAAI,iBAAiB,CAAC;IAC3D,MAAM,cAAc,GAAG,cAAc,IAAI,uBAAuB,CAAC;IAEjE,OAAO;QACL,IAAI,EAAE,QAAQ;QACd,QAAQ,EAAE,CAAC,KAAK,EAAE,WAAW,EAAE,EAAE,CAC/B,WAAW,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,kBAAkB;QACnD,QAAQ,EAAE,CAAC,KAAK,EAAE,WAAW,EAAE,EAAE,CAC/B,WAAW,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,kBAAkB;KACpD,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Notes → chord-name recognition, and validation of a typed chord name
|
|
3
|
+
* against a set of notes.
|
|
4
|
+
*
|
|
5
|
+
* The opposite direction to `resolveChord`: everything here compares
|
|
6
|
+
* pitch-class sets, so it is enharmonic-agnostic (A–Db–E is an A major triad)
|
|
7
|
+
* and ignores octaves and doubled notes. Chord shapes come from tonal's
|
|
8
|
+
* `ChordType` dictionary, the same one `resolveChord` reads, so a name this
|
|
9
|
+
* module accepts is a name the rest of chordl can draw.
|
|
10
|
+
*/
|
|
11
|
+
export interface IdentifyOptions {
|
|
12
|
+
/**
|
|
13
|
+
* Allowed chord-type symbols, tonal style ("M", "m", "dim", "maj7", "m7b5",
|
|
14
|
+
* "add9", ...). Synonyms are accepted ("major", "Δ", "°7"). `undefined`
|
|
15
|
+
* allows every type tonal knows.
|
|
16
|
+
*/
|
|
17
|
+
chordTypes?: string[];
|
|
18
|
+
/** Accept slash names — inversions ("C/E") and pedal basses ("C/Ab"). Default true. */
|
|
19
|
+
allowSlash?: boolean;
|
|
20
|
+
/** Accept a chord whose perfect 5th is missing (C–D–E → "Cadd9"). Default true. */
|
|
21
|
+
allowOmittedFifth?: boolean;
|
|
22
|
+
/**
|
|
23
|
+
* Name an inversion by its root ("C" for E–G–C). Default true. When false,
|
|
24
|
+
* the first note passed is taken as the bass: a chord whose root is not the
|
|
25
|
+
* bass must be written as a slash chord ("C/E").
|
|
26
|
+
*/
|
|
27
|
+
inversionAgnostic?: boolean;
|
|
28
|
+
}
|
|
29
|
+
export interface ChordCandidate {
|
|
30
|
+
/** Canonical display symbol, e.g. "Cmaj7", "C/Ab", "Abmaj7#5". */
|
|
31
|
+
symbol: string;
|
|
32
|
+
/** Spelled root, e.g. "C#" or "Db". */
|
|
33
|
+
root: string;
|
|
34
|
+
/** Canonical tonal chord-type symbol ("M" for a major triad). */
|
|
35
|
+
type: string;
|
|
36
|
+
/** Bass note of a slash name, spelled as given. */
|
|
37
|
+
bass?: string;
|
|
38
|
+
/** Chord tones left out of the notes, e.g. ["5"]. */
|
|
39
|
+
omitted?: string[];
|
|
40
|
+
}
|
|
41
|
+
export interface ChordNameMatch {
|
|
42
|
+
ok: boolean;
|
|
43
|
+
/** Canonical spelling of the typed name, whenever it parsed. */
|
|
44
|
+
normalized?: string;
|
|
45
|
+
/** The parsed name as a candidate, when `ok`. */
|
|
46
|
+
matched?: ChordCandidate;
|
|
47
|
+
/** Everything `identifyChords` finds for the notes under the same options. */
|
|
48
|
+
candidates: ChordCandidate[];
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Every chord name the given notes spell.
|
|
52
|
+
*
|
|
53
|
+
* Root-position names come first (the name whose root is the first note given
|
|
54
|
+
* leads), then omitted-5th readings, then slash names. Within each of those
|
|
55
|
+
* groups, common chord types come before rare ones (see `TYPE_PRIORITY`). A black-key root is
|
|
56
|
+
* offered in both spellings ("C#" and "Db") as separate candidates. Slash
|
|
57
|
+
* names returned here are pedal basses — a non-chord-tone under a chord
|
|
58
|
+
* ("C/Ab") — plus, when `inversionAgnostic` is false, inversions ("C/E").
|
|
59
|
+
* Returns `[]` when any note is unparseable or nothing matches.
|
|
60
|
+
*/
|
|
61
|
+
export declare function identifyChords(notes: string[], opts?: IdentifyOptions): ChordCandidate[];
|
|
62
|
+
/**
|
|
63
|
+
* Check a typed chord name against a set of notes.
|
|
64
|
+
*
|
|
65
|
+
* The name is parsed tolerantly (see `normalizeQuality`) and is correct when
|
|
66
|
+
* its pitch-class set equals the notes' set — or equals it with the perfect
|
|
67
|
+
* 5th omitted, when `allowOmittedFifth`. A slash bass must be one of the
|
|
68
|
+
* notes; the chord above it may contain it (an inversion, "C/E") or not (a
|
|
69
|
+
* pedal, "C/Ab"). `normalized` is the canonical spelling of whatever parsed,
|
|
70
|
+
* right or wrong, so a UI can echo it back.
|
|
71
|
+
*/
|
|
72
|
+
export declare function matchesChordName(input: string, notes: string[], opts?: IdentifyOptions): ChordNameMatch;
|
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
import { ChordType, Interval } from "tonal";
|
|
2
|
+
import { PC_SEMITONES, SHARP_TO_FLAT } from "../engine/note-spelling.js";
|
|
3
|
+
import { resolveChord } from "../resolver/chord-resolver.js";
|
|
4
|
+
// ── Pitch-class sets as 12-bit masks ──
|
|
5
|
+
const SHARP_NAMES = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"];
|
|
6
|
+
const FIFTH = 7;
|
|
7
|
+
/** An omitted-5th reading must still leave a triad's worth of notes. */
|
|
8
|
+
const MIN_NOTES_AFTER_OMISSION = 3;
|
|
9
|
+
/** A slash chord's upper structure must be at least a triad. */
|
|
10
|
+
const MIN_PEDAL_UPPER_NOTES = 3;
|
|
11
|
+
const bit = (pc) => 1 << pc;
|
|
12
|
+
function popcount(mask) {
|
|
13
|
+
let n = 0;
|
|
14
|
+
for (let m = mask; m; m &= m - 1)
|
|
15
|
+
n++;
|
|
16
|
+
return n;
|
|
17
|
+
}
|
|
18
|
+
function pcsOf(mask) {
|
|
19
|
+
const out = [];
|
|
20
|
+
for (let pc = 0; pc < 12; pc++)
|
|
21
|
+
if (mask & bit(pc))
|
|
22
|
+
out.push(pc);
|
|
23
|
+
return out;
|
|
24
|
+
}
|
|
25
|
+
function transpose(relMask, root) {
|
|
26
|
+
let out = 0;
|
|
27
|
+
for (const pc of pcsOf(relMask))
|
|
28
|
+
out |= bit((pc + root) % 12);
|
|
29
|
+
return out;
|
|
30
|
+
}
|
|
31
|
+
/** Both spellings of a black-key root, one for a white key. */
|
|
32
|
+
function rootSpellings(pc) {
|
|
33
|
+
const sharp = SHARP_NAMES[pc];
|
|
34
|
+
const flat = SHARP_TO_FLAT[sharp];
|
|
35
|
+
return flat ? [sharp, flat] : [sharp];
|
|
36
|
+
}
|
|
37
|
+
// ── Note and chord-type parsing ──
|
|
38
|
+
/** "c#4", " Bb ", "D♭" → "C#", "Bb", "Db". Null when it is not a note name. */
|
|
39
|
+
function spellNote(raw) {
|
|
40
|
+
const m = raw
|
|
41
|
+
.trim()
|
|
42
|
+
.replace(/♯/g, "#")
|
|
43
|
+
.replace(/♭/g, "b")
|
|
44
|
+
.match(/^([A-Ga-g])\s*([#b]?)\s*-?\d*$/);
|
|
45
|
+
if (!m)
|
|
46
|
+
return null;
|
|
47
|
+
const name = m[1].toUpperCase() + m[2];
|
|
48
|
+
return name in PC_SEMITONES ? name : null;
|
|
49
|
+
}
|
|
50
|
+
function parseNotes(notes) {
|
|
51
|
+
if (notes.length === 0)
|
|
52
|
+
return null;
|
|
53
|
+
const spelling = new Map();
|
|
54
|
+
let mask = 0;
|
|
55
|
+
let bass = -1;
|
|
56
|
+
for (const raw of notes) {
|
|
57
|
+
const name = spellNote(raw);
|
|
58
|
+
if (!name)
|
|
59
|
+
return null;
|
|
60
|
+
const pc = PC_SEMITONES[name];
|
|
61
|
+
if (bass < 0)
|
|
62
|
+
bass = pc;
|
|
63
|
+
if (!spelling.has(pc))
|
|
64
|
+
spelling.set(pc, name);
|
|
65
|
+
mask |= bit(pc);
|
|
66
|
+
}
|
|
67
|
+
return { mask, bass, spelling };
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Display-type overrides where tonal's first alias is not the symbol people
|
|
71
|
+
* write: tonal lists "Madd9" before "add9", "m/ma7" before "mMaj7".
|
|
72
|
+
*/
|
|
73
|
+
const CANONICAL_TYPE = {
|
|
74
|
+
Madd9: "add9",
|
|
75
|
+
"m/ma7": "mMaj7",
|
|
76
|
+
mM9: "mMaj9",
|
|
77
|
+
"maj#4": "maj7#11",
|
|
78
|
+
"M6#11": "6#11",
|
|
79
|
+
};
|
|
80
|
+
function shapeFromIntervals(type, intervals) {
|
|
81
|
+
let mask = 0;
|
|
82
|
+
for (const ivl of intervals) {
|
|
83
|
+
const semis = Interval.semitones(ivl);
|
|
84
|
+
if (Number.isInteger(semis))
|
|
85
|
+
mask |= bit(((semis % 12) + 12) % 12);
|
|
86
|
+
}
|
|
87
|
+
return { type, mask };
|
|
88
|
+
}
|
|
89
|
+
const TONAL_SHAPES = ChordType.all().map((t) => shapeFromIntervals(CANONICAL_TYPE[t.aliases[0]] ?? t.aliases[0], t.intervals));
|
|
90
|
+
/**
|
|
91
|
+
* Rewrite a typed chord quality into a symbol tonal recognises. Tolerates
|
|
92
|
+
* spaces, parentheses, unicode accidentals and the common written synonyms:
|
|
93
|
+
* maj/major → M, Δ → maj7 (Δ9 → maj9), min/minor/- → m, ø → m7b5, ° → dim,
|
|
94
|
+
* + → aug, sus → sus4,
|
|
95
|
+
* add2 → add9. The single letters M and m keep their case-sensitive meaning.
|
|
96
|
+
*/
|
|
97
|
+
function normalizeQuality(raw) {
|
|
98
|
+
let s = raw
|
|
99
|
+
.replace(/[\s()]/g, "")
|
|
100
|
+
.replace(/♯/g, "#")
|
|
101
|
+
.replace(/♭/g, "b")
|
|
102
|
+
// A bare Δ is maj7, as in tonal and jazz usage; Δ before a number is
|
|
103
|
+
// "maj" (Δ7, Δ9, Δ13).
|
|
104
|
+
.replace(/Δ(?=\d)/g, "maj")
|
|
105
|
+
.replace(/Δ/g, "maj7");
|
|
106
|
+
s = s.replace(/^major/i, "maj").replace(/^minor/i, "min");
|
|
107
|
+
s = s.replace(/^min/i, "m").replace(/^-/, "m");
|
|
108
|
+
s = s.replace(/^ø7?/, "m7b5").replace(/^°/, "dim");
|
|
109
|
+
s = s.replace(/maj|dim|aug|sus|add|alt|omit|dom/gi, (w) => w.toLowerCase());
|
|
110
|
+
s = s.replace(/^m(?:maj|M)(?=\d|$)/, "mMaj");
|
|
111
|
+
if (s === "mMaj")
|
|
112
|
+
s = "mMaj7";
|
|
113
|
+
if (s === "maj" || s === "")
|
|
114
|
+
s = "M";
|
|
115
|
+
if (s === "+")
|
|
116
|
+
s = "aug";
|
|
117
|
+
s = s.replace(/sus(?![24])/, "sus4").replace(/add2/, "add9");
|
|
118
|
+
return s;
|
|
119
|
+
}
|
|
120
|
+
/** Resolve a typed quality to a chord shape, or null when it is not a chord. */
|
|
121
|
+
function shapeForQuality(raw) {
|
|
122
|
+
const s = normalizeQuality(raw);
|
|
123
|
+
const t = ChordType.get(s);
|
|
124
|
+
if (!t.empty) {
|
|
125
|
+
return shapeFromIntervals(CANONICAL_TYPE[t.aliases[0]] ?? t.aliases[0], t.intervals);
|
|
126
|
+
}
|
|
127
|
+
// Names tonal does not know but `resolveChord` builds (m6/9, 7omit3,
|
|
128
|
+
// compound alterations like maj9#5#13): reuse its fallback rather than
|
|
129
|
+
// re-deriving those chords here.
|
|
130
|
+
try {
|
|
131
|
+
const resolved = resolveChord(`C${s}`);
|
|
132
|
+
return resolved.intervals?.length ? shapeFromIntervals(s, resolved.intervals) : null;
|
|
133
|
+
}
|
|
134
|
+
catch {
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Common chord types first, so that when one set of notes spells several
|
|
140
|
+
* names over the same bass the familiar one leads ("Abmaj7#5" before
|
|
141
|
+
* "AbM7b6"). Types not listed keep tonal's dictionary order after these.
|
|
142
|
+
*/
|
|
143
|
+
const TYPE_PRIORITY = [
|
|
144
|
+
"M", "m", "7", "maj7", "m7", "dim", "aug", "sus4", "sus2", "m7b5", "dim7",
|
|
145
|
+
"6", "m6", "add9", "madd9", "7sus4", "9", "maj9", "m9", "maj7#5", "mMaj7",
|
|
146
|
+
];
|
|
147
|
+
const TONAL_ORDER = new Map(TONAL_SHAPES.map((s, i) => [s.type, i]));
|
|
148
|
+
function typePriority(type) {
|
|
149
|
+
const i = TYPE_PRIORITY.indexOf(type);
|
|
150
|
+
return i >= 0 ? i : TYPE_PRIORITY.length + (TONAL_ORDER.get(type) ?? TONAL_SHAPES.length);
|
|
151
|
+
}
|
|
152
|
+
const displaySuffix = (type) => (type === "M" ? "" : type);
|
|
153
|
+
function allowedTypes(chordTypes) {
|
|
154
|
+
if (!chordTypes)
|
|
155
|
+
return null;
|
|
156
|
+
const set = new Set();
|
|
157
|
+
for (const t of chordTypes) {
|
|
158
|
+
set.add(shapeForQuality(t)?.type ?? normalizeQuality(t));
|
|
159
|
+
}
|
|
160
|
+
return set;
|
|
161
|
+
}
|
|
162
|
+
/** Parse a typed chord symbol: root, quality, optional "/bass". */
|
|
163
|
+
function parseSymbol(input) {
|
|
164
|
+
const m = input
|
|
165
|
+
.trim()
|
|
166
|
+
.replace(/♯/g, "#")
|
|
167
|
+
.replace(/♭/g, "b")
|
|
168
|
+
.match(/^([A-Ga-g])\s*([#b]?)(.*)$/);
|
|
169
|
+
if (!m)
|
|
170
|
+
return null;
|
|
171
|
+
const root = m[1].toUpperCase() + m[2];
|
|
172
|
+
let quality = m[3];
|
|
173
|
+
let bass;
|
|
174
|
+
const slash = quality.match(/^(.*?)\/\s*([A-Ga-g]\s*[#b]?)\s*$/);
|
|
175
|
+
if (slash) {
|
|
176
|
+
quality = slash[1];
|
|
177
|
+
const spelled = spellNote(slash[2]);
|
|
178
|
+
if (!spelled)
|
|
179
|
+
return null;
|
|
180
|
+
bass = spelled;
|
|
181
|
+
}
|
|
182
|
+
const shape = shapeForQuality(quality);
|
|
183
|
+
if (!shape || !(root in PC_SEMITONES))
|
|
184
|
+
return null;
|
|
185
|
+
return {
|
|
186
|
+
root,
|
|
187
|
+
rootPc: PC_SEMITONES[root],
|
|
188
|
+
shape,
|
|
189
|
+
bass,
|
|
190
|
+
bassPc: bass === undefined ? undefined : PC_SEMITONES[bass],
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Does `shape` on `root`, with an optional slash bass, spell exactly `target`?
|
|
195
|
+
* Tries the whole chord first, then — if allowed — the chord minus its
|
|
196
|
+
* perfect 5th. A pedal bass (one that is not a chord tone, "C/Ab") requires
|
|
197
|
+
* the whole chord above it: omitting the 5th there yields names like
|
|
198
|
+
* "Abmaj7/E" that describe the notes but no musician would write.
|
|
199
|
+
*/
|
|
200
|
+
function spells(shape, root, target, bassPc, allowOmittedFifth) {
|
|
201
|
+
const chord = transpose(shape.mask, root);
|
|
202
|
+
const bassBit = bassPc === undefined ? 0 : bit(bassPc);
|
|
203
|
+
const full = chord | bassBit;
|
|
204
|
+
if (full === target)
|
|
205
|
+
return { ok: true };
|
|
206
|
+
const isPedal = bassBit !== 0 && !(chord & bassBit);
|
|
207
|
+
const fifthPc = (root + FIFTH) % 12;
|
|
208
|
+
// The 5th cannot be "omitted" while it is sounding as the bass.
|
|
209
|
+
if (allowOmittedFifth && !isPedal && shape.mask & bit(FIFTH) && bassPc !== fifthPc) {
|
|
210
|
+
const without = full & ~bit(fifthPc);
|
|
211
|
+
if (without === target && popcount(without) >= MIN_NOTES_AFTER_OMISSION) {
|
|
212
|
+
return { ok: true, omitted: ["5"] };
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
return { ok: false };
|
|
216
|
+
}
|
|
217
|
+
function makeCandidate(root, type, bass, omitted) {
|
|
218
|
+
const c = {
|
|
219
|
+
symbol: root + displaySuffix(type) + (bass ? `/${bass}` : ""),
|
|
220
|
+
root,
|
|
221
|
+
type,
|
|
222
|
+
};
|
|
223
|
+
if (bass)
|
|
224
|
+
c.bass = bass;
|
|
225
|
+
if (omitted)
|
|
226
|
+
c.omitted = omitted;
|
|
227
|
+
return c;
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Every chord name the given notes spell.
|
|
231
|
+
*
|
|
232
|
+
* Root-position names come first (the name whose root is the first note given
|
|
233
|
+
* leads), then omitted-5th readings, then slash names. Within each of those
|
|
234
|
+
* groups, common chord types come before rare ones (see `TYPE_PRIORITY`). A black-key root is
|
|
235
|
+
* offered in both spellings ("C#" and "Db") as separate candidates. Slash
|
|
236
|
+
* names returned here are pedal basses — a non-chord-tone under a chord
|
|
237
|
+
* ("C/Ab") — plus, when `inversionAgnostic` is false, inversions ("C/E").
|
|
238
|
+
* Returns `[]` when any note is unparseable or nothing matches.
|
|
239
|
+
*/
|
|
240
|
+
export function identifyChords(notes, opts = {}) {
|
|
241
|
+
const { allowSlash = true, allowOmittedFifth = true, inversionAgnostic = true } = opts;
|
|
242
|
+
const parsed = parseNotes(notes);
|
|
243
|
+
if (!parsed)
|
|
244
|
+
return [];
|
|
245
|
+
const allowed = allowedTypes(opts.chordTypes);
|
|
246
|
+
const shapes = allowed ? TONAL_SHAPES.filter((s) => allowed.has(s.type)) : TONAL_SHAPES;
|
|
247
|
+
const found = [];
|
|
248
|
+
const push = (rootPc, type, bassPc, omitted) => {
|
|
249
|
+
const bass = bassPc === undefined ? undefined : parsed.spelling.get(bassPc);
|
|
250
|
+
const rank = (bass ? 4 : 0) + (omitted ? 2 : 0) + (rootPc === parsed.bass && !bass ? 0 : 1);
|
|
251
|
+
for (const root of rootSpellings(rootPc)) {
|
|
252
|
+
found.push({ c: makeCandidate(root, type, bass, omitted), rank, priority: typePriority(type) });
|
|
253
|
+
}
|
|
254
|
+
};
|
|
255
|
+
// Plain names: the notes are exactly the chord (or the chord minus its 5th).
|
|
256
|
+
for (const root of pcsOf(parsed.mask)) {
|
|
257
|
+
for (const shape of shapes) {
|
|
258
|
+
const r = spells(shape, root, parsed.mask, undefined, allowOmittedFifth);
|
|
259
|
+
if (!r.ok)
|
|
260
|
+
continue;
|
|
261
|
+
if (inversionAgnostic || root === parsed.bass)
|
|
262
|
+
push(root, shape.type, undefined, r.omitted);
|
|
263
|
+
else if (allowSlash)
|
|
264
|
+
push(root, shape.type, parsed.bass, r.omitted);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
// Pedal basses: one note under a chord that does not contain it.
|
|
268
|
+
if (allowSlash) {
|
|
269
|
+
const basses = inversionAgnostic ? pcsOf(parsed.mask) : [parsed.bass];
|
|
270
|
+
for (const b of basses) {
|
|
271
|
+
const upper = parsed.mask & ~bit(b);
|
|
272
|
+
if (popcount(upper) < MIN_PEDAL_UPPER_NOTES)
|
|
273
|
+
continue;
|
|
274
|
+
for (const root of pcsOf(upper)) {
|
|
275
|
+
for (const shape of shapes) {
|
|
276
|
+
// A chord that contains the bass is an inversion, named above.
|
|
277
|
+
if (transpose(shape.mask, root) & bit(b))
|
|
278
|
+
continue;
|
|
279
|
+
const r = spells(shape, root, parsed.mask, b, allowOmittedFifth);
|
|
280
|
+
if (r.ok)
|
|
281
|
+
push(root, shape.type, b, r.omitted);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
const seen = new Set();
|
|
287
|
+
return found
|
|
288
|
+
.map((f, i) => ({ ...f, i }))
|
|
289
|
+
.sort((a, b) => a.rank - b.rank || a.priority - b.priority || a.i - b.i)
|
|
290
|
+
.map((f) => f.c)
|
|
291
|
+
.filter((c) => (seen.has(c.symbol) ? false : (seen.add(c.symbol), true)));
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Check a typed chord name against a set of notes.
|
|
295
|
+
*
|
|
296
|
+
* The name is parsed tolerantly (see `normalizeQuality`) and is correct when
|
|
297
|
+
* its pitch-class set equals the notes' set — or equals it with the perfect
|
|
298
|
+
* 5th omitted, when `allowOmittedFifth`. A slash bass must be one of the
|
|
299
|
+
* notes; the chord above it may contain it (an inversion, "C/E") or not (a
|
|
300
|
+
* pedal, "C/Ab"). `normalized` is the canonical spelling of whatever parsed,
|
|
301
|
+
* right or wrong, so a UI can echo it back.
|
|
302
|
+
*/
|
|
303
|
+
export function matchesChordName(input, notes, opts = {}) {
|
|
304
|
+
const { allowSlash = true, allowOmittedFifth = true, inversionAgnostic = true } = opts;
|
|
305
|
+
const candidates = identifyChords(notes, opts);
|
|
306
|
+
const sym = parseSymbol(input);
|
|
307
|
+
if (!sym)
|
|
308
|
+
return { ok: false, candidates };
|
|
309
|
+
const normalized = makeCandidate(sym.root, sym.shape.type, sym.bass, undefined).symbol;
|
|
310
|
+
const fail = { ok: false, normalized, candidates };
|
|
311
|
+
const parsed = parseNotes(notes);
|
|
312
|
+
if (!parsed || popcount(parsed.mask) < 2)
|
|
313
|
+
return fail;
|
|
314
|
+
const allowed = allowedTypes(opts.chordTypes);
|
|
315
|
+
if (allowed && !allowed.has(sym.shape.type))
|
|
316
|
+
return fail;
|
|
317
|
+
const lowest = sym.bassPc ?? sym.rootPc;
|
|
318
|
+
if (sym.bassPc !== undefined) {
|
|
319
|
+
if (!allowSlash || !(parsed.mask & bit(sym.bassPc)))
|
|
320
|
+
return fail;
|
|
321
|
+
}
|
|
322
|
+
if (!inversionAgnostic && lowest !== parsed.bass)
|
|
323
|
+
return fail;
|
|
324
|
+
const r = spells(sym.shape, sym.rootPc, parsed.mask, sym.bassPc, allowOmittedFifth);
|
|
325
|
+
if (!r.ok)
|
|
326
|
+
return fail;
|
|
327
|
+
return {
|
|
328
|
+
ok: true,
|
|
329
|
+
normalized,
|
|
330
|
+
matched: makeCandidate(sym.root, sym.shape.type, sym.bass, r.omitted),
|
|
331
|
+
candidates,
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
//# sourceMappingURL=chord-identify.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chord-identify.js","sourceRoot":"","sources":["../../src/theory/chord-identify.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { VoicingQuality, VoicingVariant } from "@pepperhorn/chordl-voicings";
|
|
2
|
+
import type { ConstrainedVoicing, HandConstraints } from "./hand-constraints.js";
|
|
3
|
+
/**
|
|
4
|
+
* A source voicing refitted to a hand.
|
|
5
|
+
*
|
|
6
|
+
* `id` and `label` name the character of the *source* voicing — "Drop 2+4",
|
|
7
|
+
* "Rootless A" — not the shape of `voicing.notes`. `VoicingVariant.notes` is
|
|
8
|
+
* pitch classes only, with no octave information, so those pitch classes are
|
|
9
|
+
* re-stacked close-position from `baseOctave` and then folded and reduced to
|
|
10
|
+
* fit the hand. A voicing whose real intervals span fifteen semitones comes
|
|
11
|
+
* back inside the hand's reach, and the label still says "Drop 2+4".
|
|
12
|
+
*
|
|
13
|
+
* So: read the label as provenance, not as geometry. A consumer that needs the
|
|
14
|
+
* true open-position shape should realize the voicing through chordl-voicings
|
|
15
|
+
* directly rather than infer it from this label.
|
|
16
|
+
*/
|
|
17
|
+
export interface ConstrainedVariant {
|
|
18
|
+
id: string;
|
|
19
|
+
label: string;
|
|
20
|
+
source: VoicingVariant["source"];
|
|
21
|
+
voicing: ConstrainedVoicing;
|
|
22
|
+
}
|
|
23
|
+
export interface GenerateConstrainedOptions {
|
|
24
|
+
/** Tonal interval names, e.g. ["1P","3M","5P","7M"]. */
|
|
25
|
+
intervals?: string[];
|
|
26
|
+
/** Tonal chord type, e.g. "major seventh". */
|
|
27
|
+
chordType?: string;
|
|
28
|
+
styleHint?: string;
|
|
29
|
+
excludeIds?: string[];
|
|
30
|
+
baseOctave?: number;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Generate voicing variants and fit each to a hand.
|
|
34
|
+
*
|
|
35
|
+
* Variants that satisfy the constraints are returned first, then those that
|
|
36
|
+
* could not be satisfied without losing a chord tone. Ordering matters because
|
|
37
|
+
* an inversion often fits where root position cannot: Cmaj7 spans 11 semitones
|
|
38
|
+
* in root position but 8 in first inversion.
|
|
39
|
+
*
|
|
40
|
+
* @param root - root note, e.g. "C"
|
|
41
|
+
* @param quality - voicing quality from mapToVoicingQuality, may be undefined
|
|
42
|
+
* @param resolvedNotes - pitch classes in root position
|
|
43
|
+
* @param count - how many variants to generate before constraining
|
|
44
|
+
* @param constraints - the hand's reach and note count
|
|
45
|
+
*/
|
|
46
|
+
export declare function generateConstrainedVariants(root: string, quality: VoicingQuality | undefined, resolvedNotes: string[], count: number, constraints: HandConstraints, options?: GenerateConstrainedOptions): ConstrainedVariant[];
|