@musodojo/music-theory-data 17.0.0 → 18.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -13,9 +13,9 @@ more.**
13
13
  ## Verified Note Collections
14
14
 
15
15
  - ✅ Diatonic Modes
16
- - 🛠️ Pentatonic Variants
17
- - 🛠️ Major Variants
18
- - 🛠️ Minor Variants
16
+ - Pentatonic Variants
17
+ - Major Variants
18
+ - Minor Variants
19
19
  - 🛠️ Dominant Variants
20
20
  - ✅ Harmonic Minor Modes
21
21
  - ✅ Melodic Minor Modes
@@ -38,16 +38,16 @@ more.**
38
38
 
39
39
  ### Deno / JSR
40
40
 
41
- Import directly from JSR in your Deno project:
41
+ Install the package from the JSR registry:
42
42
 
43
- ```ts
44
- import * as music_theory_data from "@musodojo/music-theory-data";
43
+ ```bash
44
+ deno add jsr:@musodojo/music-theory-data
45
45
  ```
46
46
 
47
- or
47
+ Then import it into your project:
48
48
 
49
49
  ```ts
50
- import * as music_theory_data from "jsr:@musodojo/music-theory-data";
50
+ import * as music_theory_data from "@musodojo/music-theory-data";
51
51
  ```
52
52
 
53
53
  ### Node.js / npm
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@musodojo/music-theory-data",
3
- "version": "17.0.0",
3
+ "version": "18.0.0",
4
4
  "description": "The musician-friendly TypeScript library for modes, scales, chords, and more.",
5
5
  "keywords": [
6
6
  "music",
@@ -1,4 +1,4 @@
1
- export type NoteInteger = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11;
1
+ export type RootNoteInteger = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11;
2
2
 
3
3
  const _noteLetters = [
4
4
  "C",
@@ -53,15 +53,16 @@ export const noteNames: readonly NoteName[] = enharmonicNoteNameGroups.flat();
53
53
 
54
54
  export const noteNamesSet: ReadonlySet<NoteName> = new Set(noteNames);
55
55
 
56
- export const noteNameToIntegerMap: ReadonlyMap<NoteName, NoteInteger> = (() => {
57
- const map = new Map<NoteName, NoteInteger>();
58
- _enharmonicNoteNameGroups.forEach((group, index) => {
59
- group.forEach((note) => {
60
- map.set(note, index as NoteInteger);
56
+ export const noteNameToIntegerMap: ReadonlyMap<NoteName, RootNoteInteger> =
57
+ (() => {
58
+ const map = new Map<NoteName, RootNoteInteger>();
59
+ _enharmonicNoteNameGroups.forEach((group, index) => {
60
+ group.forEach((note) => {
61
+ map.set(note, index as RootNoteInteger);
62
+ });
61
63
  });
62
- });
63
- return map;
64
- })();
64
+ return map;
65
+ })();
65
66
 
66
67
  const _enharmonicRootNoteGroups = [
67
68
  ["C", "B♯"],
@@ -87,15 +88,16 @@ export const rootNotes: readonly RootNote[] = enharmonicRootNoteGroups.flat();
87
88
 
88
89
  export const rootNotesSet: ReadonlySet<RootNote> = new Set(rootNotes);
89
90
 
90
- export const rootNoteToIntegerMap: ReadonlyMap<RootNote, NoteInteger> = (() => {
91
- const map = new Map<RootNote, NoteInteger>();
92
- enharmonicRootNoteGroups.forEach((group, index) => {
93
- group.forEach((note) => {
94
- map.set(note, index as NoteInteger);
91
+ export const rootNoteToIntegerMap: ReadonlyMap<RootNote, RootNoteInteger> =
92
+ (() => {
93
+ const map = new Map<RootNote, RootNoteInteger>();
94
+ enharmonicRootNoteGroups.forEach((group, index) => {
95
+ group.forEach((note) => {
96
+ map.set(note, index as RootNoteInteger);
97
+ });
95
98
  });
96
- });
97
- return map;
98
- })();
99
+ return map;
100
+ })();
99
101
 
100
102
  export type SimpleIntervalNumber =
101
103
  | "1"
@@ -1,6 +1,10 @@
1
- import type { ScaleCollection } from "../../types/note-collections.d.ts";
1
+ import type {
2
+ ModalScaleCollection,
3
+ ParentScaleCollection,
4
+ ScaleCollection,
5
+ } from "../../types/note-collections.d.ts";
2
6
 
3
- const ionian: ScaleCollection = {
7
+ const ionian: ParentScaleCollection = {
4
8
  category: "scale",
5
9
  rotation: 0,
6
10
  primaryName: "Major",
@@ -41,9 +45,10 @@ const ionian: ScaleCollection = {
41
45
  patternShort: ["W", "W", "H", "W", "W", "W", "H"],
42
46
  } as const;
43
47
 
44
- const dorian: ScaleCollection = {
48
+ const dorian: ModalScaleCollection = {
45
49
  category: "scale",
46
50
  rotation: 1,
51
+ parentScale: "ionian",
47
52
  primaryName: "Dorian",
48
53
  names: [
49
54
  "Dorian",
@@ -80,9 +85,10 @@ const dorian: ScaleCollection = {
80
85
  patternShort: ["W", "H", "W", "W", "W", "H", "W"],
81
86
  } as const;
82
87
 
83
- const phrygian: ScaleCollection = {
88
+ const phrygian: ModalScaleCollection = {
84
89
  category: "scale",
85
90
  rotation: 2,
91
+ parentScale: "ionian",
86
92
  primaryName: "Phrygian",
87
93
  names: [
88
94
  "Phrygian",
@@ -117,9 +123,10 @@ const phrygian: ScaleCollection = {
117
123
  patternShort: ["H", "W", "W", "W", "H", "W", "W"],
118
124
  } as const;
119
125
 
120
- const lydian: ScaleCollection = {
126
+ const lydian: ModalScaleCollection = {
121
127
  category: "scale",
122
128
  rotation: 3,
129
+ parentScale: "ionian",
123
130
  primaryName: "Lydian",
124
131
  names: ["Lydian", "Major ♯4", "Lydian Mode"],
125
132
  intervals: ["1", "2", "3", "♯4", "5", "6", "7", "8"],
@@ -148,9 +155,10 @@ const lydian: ScaleCollection = {
148
155
  patternShort: ["W", "W", "W", "H", "W", "W", "H"],
149
156
  } as const;
150
157
 
151
- const mixolydian: ScaleCollection = {
158
+ const mixolydian: ModalScaleCollection = {
152
159
  category: "scale",
153
160
  rotation: 4,
161
+ parentScale: "ionian",
154
162
  primaryName: "Mixolydian",
155
163
  names: [
156
164
  "Mixolydian",
@@ -185,9 +193,10 @@ const mixolydian: ScaleCollection = {
185
193
  patternShort: ["W", "W", "H", "W", "W", "H", "W"],
186
194
  } as const;
187
195
 
188
- const aeolian: ScaleCollection = {
196
+ const aeolian: ModalScaleCollection = {
189
197
  category: "scale",
190
198
  rotation: 5,
199
+ parentScale: "ionian",
191
200
  primaryName: "Minor",
192
201
  names: [
193
202
  "Minor",
@@ -223,9 +232,10 @@ const aeolian: ScaleCollection = {
223
232
  patternShort: ["W", "H", "W", "W", "H", "W", "W"],
224
233
  } as const;
225
234
 
226
- const locrian: ScaleCollection = {
235
+ const locrian: ModalScaleCollection = {
227
236
  category: "scale",
228
237
  rotation: 6,
238
+ parentScale: "ionian",
229
239
  primaryName: "Locrian",
230
240
  names: [
231
241
  "Locrian",
@@ -1,7 +1,8 @@
1
1
  import type {
2
2
  ChordCollection,
3
+ ModalScaleCollection,
3
4
  NoteCollection,
4
- ScaleCollection,
5
+ ParentScaleCollection,
5
6
  } from "../../types/note-collections.d.ts";
6
7
 
7
8
  const diminishedTriad: ChordCollection = {
@@ -40,7 +41,7 @@ const halfDiminished7: ChordCollection = {
40
41
  patternShort: ["m3", "m3", "M3"],
41
42
  } as const;
42
43
 
43
- const wholeHalfDiminished: ScaleCollection = {
44
+ const wholeHalfDiminished: ParentScaleCollection = {
44
45
  category: "scale",
45
46
  rotation: 0,
46
47
  primaryName: "Whole Half Diminished",
@@ -53,9 +54,10 @@ const wholeHalfDiminished: ScaleCollection = {
53
54
  patternShort: ["W", "H", "W", "H", "W", "H", "W", "H"],
54
55
  } as const;
55
56
 
56
- const halfWholeDiminished: ScaleCollection = {
57
+ const halfWholeDiminished: ModalScaleCollection = {
57
58
  category: "scale",
58
59
  rotation: 1,
60
+ parentScale: "wholeHalfDiminished",
59
61
  primaryName: "Half Whole Diminished",
60
62
  names: ["Half Whole Diminished", "Dominant Diminished"],
61
63
  intervals: ["1", "♭2", "♭3", "3", "♯4", "5", "6", "♭7", "8"],
@@ -1,6 +1,10 @@
1
- import type { ScaleCollection } from "../../types/note-collections.d.ts";
1
+ import type {
2
+ ModalScaleCollection,
3
+ ParentScaleCollection,
4
+ ScaleCollection,
5
+ } from "../../types/note-collections.d.ts";
2
6
 
3
- const harmonicMinor: ScaleCollection = {
7
+ const harmonicMinor: ParentScaleCollection = {
4
8
  category: "scale",
5
9
  rotation: 0,
6
10
  primaryName: "Harmonic Minor",
@@ -34,9 +38,10 @@ const harmonicMinor: ScaleCollection = {
34
38
  patternShort: ["W", "H", "W", "W", "H", "A2", "H"],
35
39
  } as const;
36
40
 
37
- const locrianNatural6: ScaleCollection = {
41
+ const locrianNatural6: ModalScaleCollection = {
38
42
  category: "scale",
39
43
  rotation: 1,
44
+ parentScale: "harmonicMinor",
40
45
  primaryName: "Locrian ♮6",
41
46
  names: ["Locrian ♮6", "Locrian Natural Sixth", "Locrian Raised Sixth"],
42
47
  intervals: ["1", "♭2", "♭3", "4", "♭5", "6", "♭7", "8"],
@@ -61,9 +66,10 @@ const locrianNatural6: ScaleCollection = {
61
66
  patternShort: ["H", "W", "W", "H", "A2", "H", "W"],
62
67
  } as const;
63
68
 
64
- const ionianSharp5: ScaleCollection = {
69
+ const ionianSharp5: ModalScaleCollection = {
65
70
  category: "scale",
66
71
  rotation: 2,
72
+ parentScale: "harmonicMinor",
67
73
  primaryName: "Ionian ♯5",
68
74
  names: [
69
75
  "Ionian ♯5",
@@ -100,9 +106,10 @@ const ionianSharp5: ScaleCollection = {
100
106
  patternShort: ["W", "W", "H", "A2", "H", "W", "H"],
101
107
  } as const;
102
108
 
103
- const dorianSharp4: ScaleCollection = {
109
+ const dorianSharp4: ModalScaleCollection = {
104
110
  category: "scale",
105
111
  rotation: 3,
112
+ parentScale: "harmonicMinor",
106
113
  primaryName: "Dorian ♯4",
107
114
  names: [
108
115
  "Dorian ♯4",
@@ -133,9 +140,10 @@ const dorianSharp4: ScaleCollection = {
133
140
  patternShort: ["W", "H", "A2", "H", "W", "H", "W"],
134
141
  } as const;
135
142
 
136
- const phrygianDominant: ScaleCollection = {
143
+ const phrygianDominant: ModalScaleCollection = {
137
144
  category: "scale",
138
145
  rotation: 4,
146
+ parentScale: "harmonicMinor",
139
147
  primaryName: "Phrygian Dominant",
140
148
  names: [
141
149
  "Phrygian Dominant",
@@ -172,9 +180,10 @@ const phrygianDominant: ScaleCollection = {
172
180
  patternShort: ["H", "A2", "H", "W", "H", "W", "W"],
173
181
  } as const;
174
182
 
175
- const lydianSharp2: ScaleCollection = {
183
+ const lydianSharp2: ModalScaleCollection = {
176
184
  category: "scale",
177
185
  rotation: 5,
186
+ parentScale: "harmonicMinor",
178
187
  primaryName: "Lydian ♯2",
179
188
  names: [
180
189
  "Lydian ♯2",
@@ -204,9 +213,10 @@ const lydianSharp2: ScaleCollection = {
204
213
  patternShort: ["A2", "H", "W", "H", "W", "W", "H"],
205
214
  } as const;
206
215
 
207
- const superLocrianDoubleFlat7: ScaleCollection = {
216
+ const superLocrianDoubleFlat7: ModalScaleCollection = {
208
217
  category: "scale",
209
218
  rotation: 6,
219
+ parentScale: "harmonicMinor",
210
220
  primaryName: "Super Locrian 𝄫7",
211
221
  names: [
212
222
  "Super Locrian 𝄫7",
@@ -61,7 +61,7 @@ const major9: ChordCollection = {
61
61
  primaryName: "M9",
62
62
  names: ["M9", "maj9", "Major 9th", "Major Ninth", "Δ9"],
63
63
  intervals: ["1", "3", "5", "7", "9"],
64
- integers: [0, 2, 4, 7, 11],
64
+ integers: [0, 4, 7, 11, 14],
65
65
  type: ["major", "chord", "arpeggio", "pentad"],
66
66
  characteristics: [
67
67
  "stable",
@@ -81,7 +81,7 @@ const majorAdd9: ChordCollection = {
81
81
  primaryName: "add9",
82
82
  names: ["add9", "maj(add9)", "M(add9)", "Major add 9"],
83
83
  intervals: ["1", "3", "5", "9"],
84
- integers: [0, 2, 4, 7],
84
+ integers: [0, 4, 7, 14],
85
85
  type: ["major", "chord", "arpeggio", "tetrad"],
86
86
  characteristics: [
87
87
  "stable",
@@ -101,7 +101,7 @@ const major6Add9: ChordCollection = {
101
101
  primaryName: "6/9",
102
102
  names: ["6/9", "M6/9", "maj6/9", "Major 6/9", "6add9", "Major add 6 add 9"],
103
103
  intervals: ["1", "3", "5", "6", "9"],
104
- integers: [0, 2, 4, 7, 9],
104
+ integers: [0, 4, 7, 9, 14],
105
105
  type: ["major", "chord", "arpeggio", "pentad"],
106
106
  characteristics: [
107
107
  "stable",
@@ -1,6 +1,10 @@
1
- import type { ScaleCollection } from "../../types/note-collections.d.ts";
1
+ import type {
2
+ ModalScaleCollection,
3
+ ParentScaleCollection,
4
+ ScaleCollection,
5
+ } from "../../types/note-collections.d.ts";
2
6
 
3
- const melodicMinor: ScaleCollection = {
7
+ const melodicMinor: ParentScaleCollection = {
4
8
  category: "scale",
5
9
  rotation: 0,
6
10
  primaryName: "Melodic Minor",
@@ -33,9 +37,10 @@ const melodicMinor: ScaleCollection = {
33
37
  patternShort: ["W", "H", "W", "W", "W", "W", "H"],
34
38
  } as const;
35
39
 
36
- const dorianFlat2: ScaleCollection = {
40
+ const dorianFlat2: ModalScaleCollection = {
37
41
  category: "scale",
38
42
  rotation: 1,
43
+ parentScale: "melodicMinor",
39
44
  primaryName: "Dorian ♭2",
40
45
  names: [
41
46
  "Dorian ♭2",
@@ -59,9 +64,10 @@ const dorianFlat2: ScaleCollection = {
59
64
  patternShort: ["H", "W", "W", "W", "W", "H", "W"],
60
65
  } as const;
61
66
 
62
- const lydianAugmented: ScaleCollection = {
67
+ const lydianAugmented: ModalScaleCollection = {
63
68
  category: "scale",
64
69
  rotation: 2,
70
+ parentScale: "melodicMinor",
65
71
  primaryName: "Lydian Augmented",
66
72
  names: ["Lydian Augmented", "Lydian ♯5", "Lydian Sharp Fifth"],
67
73
  intervals: ["1", "2", "3", "♯4", "♯5", "6", "7", "8"],
@@ -86,9 +92,10 @@ const lydianAugmented: ScaleCollection = {
86
92
  patternShort: ["W", "W", "W", "W", "H", "W", "H"],
87
93
  } as const;
88
94
 
89
- const lydianDominant: ScaleCollection = {
95
+ const lydianDominant: ModalScaleCollection = {
90
96
  category: "scale",
91
97
  rotation: 3,
98
+ parentScale: "melodicMinor",
92
99
  primaryName: "Lydian Dominant",
93
100
  names: [
94
101
  "Lydian Dominant",
@@ -116,9 +123,10 @@ const lydianDominant: ScaleCollection = {
116
123
  patternShort: ["W", "W", "W", "H", "W", "H", "W"],
117
124
  } as const;
118
125
 
119
- const mixolydianFlat6: ScaleCollection = {
126
+ const mixolydianFlat6: ModalScaleCollection = {
120
127
  category: "scale",
121
128
  rotation: 4,
129
+ parentScale: "melodicMinor",
122
130
  primaryName: "Mixolydian ♭6",
123
131
  names: [
124
132
  "Mixolydian ♭6",
@@ -143,9 +151,10 @@ const mixolydianFlat6: ScaleCollection = {
143
151
  patternShort: ["W", "W", "H", "W", "H", "W", "W"],
144
152
  } as const;
145
153
 
146
- const aeolianFlat5: ScaleCollection = {
154
+ const aeolianFlat5: ModalScaleCollection = {
147
155
  category: "scale",
148
156
  rotation: 5,
157
+ parentScale: "melodicMinor",
149
158
  primaryName: "Aeolian ♭5",
150
159
  names: [
151
160
  "Aeolian ♭5",
@@ -170,9 +179,10 @@ const aeolianFlat5: ScaleCollection = {
170
179
  patternShort: ["W", "H", "W", "H", "W", "W", "W"],
171
180
  } as const;
172
181
 
173
- const altered: ScaleCollection = {
182
+ const altered: ModalScaleCollection = {
174
183
  category: "scale",
175
184
  rotation: 6,
185
+ parentScale: "melodicMinor",
176
186
  primaryName: "Altered Scale",
177
187
  names: [
178
188
  "Altered Scale",
@@ -46,12 +46,35 @@ const minor7: ChordCollection = {
46
46
  patternShort: ["m3", "M3", "m3"],
47
47
  } as const;
48
48
 
49
+ const minorMajor7: ChordCollection = {
50
+ category: "chord",
51
+ primaryName: "m(M7)",
52
+ names: [
53
+ "m(M7)",
54
+ "min(M7)",
55
+ "Minor (Major 7th)",
56
+ "Minor Major Seventh",
57
+ "mM7",
58
+ "-M7",
59
+ "-(maj7)",
60
+ ],
61
+ intervals: ["1", "♭3", "5", "7"],
62
+ integers: [0, 3, 7, 11],
63
+ type: ["minor", "chord", "arpeggio", "tetrad"],
64
+ characteristics: [
65
+ "smooth",
66
+ "jazzy",
67
+ ],
68
+ pattern: ["minor third", "major third", "major third"],
69
+ patternShort: ["m3", "M3", "M3"],
70
+ };
71
+
49
72
  const minor9: ChordCollection = {
50
73
  category: "chord",
51
74
  primaryName: "m9",
52
75
  names: ["m9", "min9", "Minor 9th", "Minor Ninth", "-9"],
53
76
  intervals: ["1", "♭3", "5", "♭7", "9"],
54
- integers: [0, 2, 3, 7, 10],
77
+ integers: [0, 3, 7, 10, 14],
55
78
  type: ["minor", "chord", "arpeggio", "pentad"],
56
79
  characteristics: ["rich", "lush", "sophisticated", "common in jazz"],
57
80
  pattern: ["minor third", "major third", "minor third", "major third"],
@@ -63,7 +86,7 @@ const minorAdd9: ChordCollection = {
63
86
  primaryName: "m(add9)",
64
87
  names: ["m(add9)", "min(add9)", "Minor add 9"],
65
88
  intervals: ["1", "♭3", "5", "9"],
66
- integers: [0, 2, 3, 7],
89
+ integers: [0, 3, 7, 14],
67
90
  type: ["minor", "chord", "arpeggio", "tetrad"],
68
91
  characteristics: [
69
92
  "open",
@@ -78,9 +101,9 @@ const minorAdd9: ChordCollection = {
78
101
  const minor6Add9: ChordCollection = {
79
102
  category: "chord",
80
103
  primaryName: "m6/9",
81
- names: ["m6/9", "min6/9", "Minor 6/9"],
104
+ names: ["m6/9", "min6/9", "Minor 6/9", "-6/9"],
82
105
  intervals: ["1", "♭3", "5", "6", "9"],
83
- integers: [0, 2, 3, 7, 9],
106
+ integers: [0, 3, 7, 9, 14],
84
107
  type: ["minor", "chord", "arpeggio", "pentad"],
85
108
  characteristics: [
86
109
  "rich",
@@ -96,6 +119,7 @@ export const _minorVariants = {
96
119
  minor,
97
120
  minor6,
98
121
  minor7,
122
+ minorMajor7,
99
123
  minor9,
100
124
  minorAdd9,
101
125
  minor6Add9,
@@ -49,11 +49,8 @@ const chromatic: ScaleCollection = {
49
49
 
50
50
  const wholeTone: ScaleCollection = {
51
51
  category: "scale",
52
- rotation: 0,
53
52
  primaryName: "Whole Tone Scale",
54
- names: [
55
- "Whole Tone Scale",
56
- ],
53
+ names: ["Whole Tone Scale"],
57
54
  intervals: ["1", "2", "3", "♯4", "♯5", "♯6", "8"],
58
55
  integers: [0, 2, 4, 6, 8, 10],
59
56
  type: ["whole tone", "scale", "symmetrical", "hexatonic"],
@@ -1,6 +1,10 @@
1
- import type { ScaleCollection } from "../../types/note-collections.d.ts";
1
+ import type {
2
+ ModalScaleCollection,
3
+ ParentScaleCollection,
4
+ ScaleCollection,
5
+ } from "../../types/note-collections.d.ts";
2
6
 
3
- const majorPentatonic: ScaleCollection = {
7
+ const majorPentatonic: ParentScaleCollection = {
4
8
  category: "scale",
5
9
  rotation: 0,
6
10
  primaryName: "Major Pentatonic",
@@ -20,48 +24,52 @@ const majorPentatonic: ScaleCollection = {
20
24
  patternShort: ["W", "W", "m3", "W", "m3"],
21
25
  } as const;
22
26
 
23
- const suspendedPentatonic: ScaleCollection = {
27
+ const suspendedPentatonic: ModalScaleCollection = {
24
28
  category: "scale",
25
29
  rotation: 1,
30
+ parentScale: "majorPentatonic",
26
31
  primaryName: "Suspended Pentatonic",
27
32
  names: ["Suspended Pentatonic", "Egyptian Pentatonic"],
28
33
  intervals: ["1", "2", "4", "5", "♭7", "8"],
29
34
  integers: [0, 2, 5, 7, 10],
30
35
  type: ["suspended", "pentatonic", "scale", "gapped scale"],
31
36
  characteristics: ["open", "stable", "neutral", "neither major nor minor"],
32
- pattern: ["whole", "minor third", "whole", "minor third"],
33
- patternShort: ["W", "m3", "W", "m3"],
37
+ pattern: ["whole", "minor third", "whole", "minor third", "whole"],
38
+ patternShort: ["W", "m3", "W", "m3", "W"],
34
39
  } as const;
35
40
 
36
- const bluesMinorPentatonic: ScaleCollection = {
41
+ const bluesMinorPentatonic: ModalScaleCollection = {
37
42
  category: "scale",
38
43
  rotation: 2,
44
+ parentScale: "majorPentatonic",
39
45
  primaryName: "Blues Minor Pentatonic",
40
46
  names: ["Blues Minor Pentatonic"],
41
- intervals: ["1", "♭3", "4", "♭5", "♭7", "8"],
47
+ intervals: ["1", "♭3", "4", "♭6", "♭7", "8"],
42
48
  integers: [0, 3, 5, 8, 10],
43
49
  type: ["minor", "pentatonic", "scale", "gapped scale", "blues"],
44
- characteristics: ["bluesy", "tense", "minor with a blue note"],
45
- pattern: ["minor third", "whole", "half", "minor third"],
46
- patternShort: ["m3", "W", "H", "m3"],
50
+ characteristics: ["bluesy", "tense"],
51
+ pattern: ["minor third", "whole", "minor third", "whole", "whole"],
52
+ patternShort: ["m3", "W", "m3", "W", "W"],
47
53
  } as const;
48
54
 
49
- const bluesMajorPentatonic: ScaleCollection = {
55
+ const bluesMajorPentatonic: ModalScaleCollection = {
50
56
  category: "scale",
51
57
  rotation: 3,
58
+ parentScale: "majorPentatonic",
52
59
  primaryName: "Blues Major Pentatonic",
53
60
  names: ["Blues Major Pentatonic"],
54
- intervals: ["1", "2", "♭3", "5", "6", "8"],
61
+ intervals: ["1", "2", "4", "5", "6", "8"],
55
62
  integers: [0, 2, 5, 7, 9],
56
63
  type: ["major", "pentatonic", "scale", "gapped scale", "blues"],
57
- characteristics: ["bluesy", "country", "major with a blue note"],
58
- pattern: ["whole", "half", "major third", "whole"],
59
- patternShort: ["W", "H", "M3", "W"],
64
+ characteristics: ["bluesy", "country"],
65
+ pattern: ["whole", "minor third", "whole", "whole", "minor third"],
66
+ patternShort: ["W", "m3", "W", "W", "m3"],
60
67
  } as const;
61
68
 
62
- const minorPentatonic: ScaleCollection = {
69
+ const minorPentatonic: ModalScaleCollection = {
63
70
  category: "scale",
64
71
  rotation: 4,
72
+ parentScale: "majorPentatonic",
65
73
  primaryName: "Minor Pentatonic",
66
74
  names: ["Minor Pentatonic"],
67
75
  intervals: ["1", "♭3", "4", "5", "♭7", "8"],
@@ -1,4 +1,4 @@
1
- import type { Interval, NoteInteger } from "../data/labels/note-labels.ts";
1
+ import type { Interval } from "../data/labels/note-labels.ts";
2
2
 
3
3
  export type CollectionCategory = "scale" | "chord";
4
4
 
@@ -20,10 +20,11 @@ interface NoteCollectionBase {
20
20
  */
21
21
  readonly intervals: readonly Interval[];
22
22
  /**
23
- * The set of pitch classes as integers (0-11), representing semitones from the root.
24
- * This set never includes the octave.
23
+ * The set of semitone values from the root.
24
+ * - For **scales**, this is a pitch class set (0-11) and does not include the octave.
25
+ * - For **chords**, this can include values > 11 to represent extensions (e.g., 14 for a 9th).
25
26
  */
26
- readonly integers: readonly NoteInteger[];
27
+ readonly integers: readonly number[];
27
28
  /**
28
29
  * An array of tags used for classification and filtering.
29
30
  * e.g., ["major", "scale", "heptatonic", "diatonic mode"]
@@ -48,20 +49,37 @@ interface NoteCollectionBase {
48
49
  readonly patternShort: readonly string[];
49
50
  }
50
51
 
51
- export interface ScaleCollection extends NoteCollectionBase {
52
+ /** A scale that is the parent of a set of modes (e.g., Ionian, Melodic Minor). */
53
+ interface ParentScaleCollection extends NoteCollectionBase {
52
54
  /**
53
55
  * The fundamental classification of the collection. For scales, this is always "scale".
54
- * This influences the interpretation of other properties:
55
- * - `intervals` conventionally includes the octave ("8").
56
- * - `pattern` represents steps between consecutive notes.
57
56
  */
58
57
  readonly category: "scale";
59
58
  /**
60
- * The rotation index relative to a parent scale (e.g., for diatonic modes).
61
- * Ionian is 0, Dorian is 1, etc. This property is optional and only applies
62
- * to collections that are modes of another scale.
59
+ * The rotation index for a parent scale is always 0.
63
60
  */
64
- readonly rotation?: number;
61
+ readonly rotation: 0;
62
+ readonly parentScale?: never;
63
+ }
64
+
65
+ /** A scale that is a mode of a parent scale (e.g., Dorian, Lydian Augmented). */
66
+ interface ModalScaleCollection extends NoteCollectionBase {
67
+ readonly category: "scale";
68
+ /**
69
+ * The rotation index relative to a parent scale. e.g., Dorian is 1.
70
+ */
71
+ readonly rotation: number;
72
+ /**
73
+ * The key-name (e.g., "ionian") of the parent scale from which this mode is derived.
74
+ */
75
+ readonly parentScale: string;
76
+ }
77
+
78
+ /** A scale that is not a mode of another scale in this collection. */
79
+ interface NonModalScaleCollection extends NoteCollectionBase {
80
+ readonly category: "scale";
81
+ readonly rotation?: never;
82
+ readonly parentScale?: never;
65
83
  }
66
84
 
67
85
  export interface ChordCollection extends NoteCollectionBase {
@@ -69,4 +87,9 @@ export interface ChordCollection extends NoteCollectionBase {
69
87
  readonly rotation?: never;
70
88
  }
71
89
 
90
+ export type ScaleCollection =
91
+ | ParentScaleCollection
92
+ | ModalScaleCollection
93
+ | NonModalScaleCollection;
94
+
72
95
  export type NoteCollection = ScaleCollection | ChordCollection;
package/src/utils/midi.ts CHANGED
@@ -1,15 +1,15 @@
1
1
  import {
2
2
  type Interval,
3
3
  intervalToIntegerMap,
4
- type NoteInteger,
5
4
  type NoteName,
6
5
  noteNameToIntegerMap,
6
+ type RootNoteInteger,
7
7
  } from "../data/labels/note-labels.ts";
8
8
 
9
9
  import type { MidiNoteNumber, OctaveNumber } from "../types/midi.d.ts";
10
10
 
11
11
  export function rootIntegerAndIntervalToMidi(
12
- rootNoteInteger: NoteInteger,
12
+ rootNoteInteger: RootNoteInteger,
13
13
  interval: Interval,
14
14
  rootNoteOctaveNumber: OctaveNumber = 4,
15
15
  ): MidiNoteNumber | undefined {
@@ -2,13 +2,13 @@ import {
2
2
  enharmonicNoteNameGroups,
3
3
  type Interval,
4
4
  intervalToIntegerMap,
5
- type NoteInteger,
6
5
  type NoteLetter,
7
6
  noteLetters,
8
7
  type NoteName,
9
8
  noteNamesSet,
10
9
  noteNameToIntegerMap,
11
10
  type RootNote,
11
+ type RootNoteInteger,
12
12
  rootNotesSet,
13
13
  } from "../data/labels/note-labels.ts";
14
14
  import {
@@ -124,13 +124,13 @@ export function normalizeRootNoteString(name: string): RootNote | undefined {
124
124
 
125
125
  export function noteNameToInteger(
126
126
  noteName: NoteName,
127
- ): NoteInteger | undefined {
127
+ ): RootNoteInteger | undefined {
128
128
  return noteNameToIntegerMap.get(noteName);
129
129
  }
130
130
 
131
131
  export function noteNameStringToInteger(
132
132
  noteName: string,
133
- ): NoteInteger | undefined {
133
+ ): RootNoteInteger | undefined {
134
134
  const normalized = normalizeNoteNameString(noteName);
135
135
  if (!normalized) return undefined;
136
136
  return noteNameToInteger(normalized);