@musodojo/music-theory-data 16.1.2 → 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,12 +13,12 @@ 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
- - 🛠️ Melodic Minor Modes
21
+ - Melodic Minor Modes
22
22
  - 🛠️ Diminished Variants
23
23
  - 🛠️ Augmented Variants
24
24
  - 🛠️ Other Note Collections
@@ -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": "16.1.2",
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,8 +41,9 @@ 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",
46
+ rotation: 0,
45
47
  primaryName: "Whole Half Diminished",
46
48
  names: ["Whole Half Diminished"],
47
49
  intervals: ["1", "2", "♭3", "4", "♭5", "♭6", "6", "7", "8"],
@@ -52,8 +54,10 @@ const wholeHalfDiminished: ScaleCollection = {
52
54
  patternShort: ["W", "H", "W", "H", "W", "H", "W", "H"],
53
55
  } as const;
54
56
 
55
- const halfWholeDiminished: ScaleCollection = {
57
+ const halfWholeDiminished: ModalScaleCollection = {
56
58
  category: "scale",
59
+ rotation: 1,
60
+ parentScale: "wholeHalfDiminished",
57
61
  primaryName: "Half Whole Diminished",
58
62
  names: ["Half Whole Diminished", "Dominant Diminished"],
59
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",
@@ -114,8 +121,13 @@ const dorianSharp4: ScaleCollection = {
114
121
  ],
115
122
  intervals: ["1", "2", "♭3", "♯4", "5", "6", "♭7", "8"],
116
123
  integers: [0, 2, 3, 6, 7, 9, 10],
117
- type: ["harmonic minor mode", "minor", "scale", "heptatonic"],
118
- characteristics: ["exotic minor", "eastern european folk", "gypsy"],
124
+ type: ["harmonic minor mode", "minor", "scale", "mode", "heptatonic"],
125
+ characteristics: [
126
+ "exotic minor",
127
+ "eastern european folk",
128
+ "gypsy",
129
+ "fourth mode of harmonic minor",
130
+ ],
119
131
  pattern: [
120
132
  "whole",
121
133
  "half",
@@ -128,9 +140,10 @@ const dorianSharp4: ScaleCollection = {
128
140
  patternShort: ["W", "H", "A2", "H", "W", "H", "W"],
129
141
  } as const;
130
142
 
131
- const phrygianDominant: ScaleCollection = {
143
+ const phrygianDominant: ModalScaleCollection = {
132
144
  category: "scale",
133
145
  rotation: 4,
146
+ parentScale: "harmonicMinor",
134
147
  primaryName: "Phrygian Dominant",
135
148
  names: [
136
149
  "Phrygian Dominant",
@@ -144,8 +157,9 @@ const phrygianDominant: ScaleCollection = {
144
157
  ],
145
158
  intervals: ["1", "♭2", "3", "4", "5", "♭6", "♭7", "8"],
146
159
  integers: [0, 1, 4, 5, 7, 8, 10],
147
- type: ["harmonic minor mode", "dominant", "scale", "heptatonic"],
160
+ type: ["harmonic minor mode", "dominant", "scale", "mode", "heptatonic"],
148
161
  characteristics: [
162
+ "fifth mode of harmonic minor",
149
163
  "very exotic",
150
164
  "spanish",
151
165
  "flamenco",
@@ -166,9 +180,10 @@ const phrygianDominant: ScaleCollection = {
166
180
  patternShort: ["H", "A2", "H", "W", "H", "W", "W"],
167
181
  } as const;
168
182
 
169
- const lydianSharp2: ScaleCollection = {
183
+ const lydianSharp2: ModalScaleCollection = {
170
184
  category: "scale",
171
185
  rotation: 5,
186
+ parentScale: "harmonicMinor",
172
187
  primaryName: "Lydian ♯2",
173
188
  names: [
174
189
  "Lydian ♯2",
@@ -178,8 +193,14 @@ const lydianSharp2: ScaleCollection = {
178
193
  ],
179
194
  intervals: ["1", "♯2", "3", "♯4", "5", "6", "7", "8"],
180
195
  integers: [0, 3, 4, 6, 7, 9, 11],
181
- type: ["harmonic minor mode", "major", "scale", "heptatonic"],
182
- characteristics: ["very bright", "unusual", "double augmented", "exotic"],
196
+ type: ["harmonic minor mode", "major", "scale", "mode", "heptatonic"],
197
+ characteristics: [
198
+ "very bright",
199
+ "unusual",
200
+ "double augmented",
201
+ "exotic",
202
+ "sixth mode of harmonic minor",
203
+ ],
183
204
  pattern: [
184
205
  "augmented second",
185
206
  "half",
@@ -192,9 +213,10 @@ const lydianSharp2: ScaleCollection = {
192
213
  patternShort: ["A2", "H", "W", "H", "W", "W", "H"],
193
214
  } as const;
194
215
 
195
- const superLocrianDoubleFlat7: ScaleCollection = {
216
+ const superLocrianDoubleFlat7: ModalScaleCollection = {
196
217
  category: "scale",
197
218
  rotation: 6,
219
+ parentScale: "harmonicMinor",
198
220
  primaryName: "Super Locrian 𝄫7",
199
221
  names: [
200
222
  "Super Locrian 𝄫7",
@@ -204,12 +226,13 @@ const superLocrianDoubleFlat7: ScaleCollection = {
204
226
  ],
205
227
  intervals: ["1", "♭2", "♭3", "♭4", "♭5", "♭6", "𝄫7", "8"],
206
228
  integers: [0, 1, 3, 4, 6, 8, 9],
207
- type: ["harmonic minor mode", "diminished", "scale", "heptatonic"],
229
+ type: ["harmonic minor mode", "diminished", "scale", "mode", "heptatonic"],
208
230
  characteristics: [
209
231
  "extremely tense",
210
232
  "highly dissonant",
211
233
  "altered",
212
234
  "theoretical",
235
+ "seventh mode of harmonic minor",
213
236
  ],
214
237
  pattern: [
215
238
  "half",
@@ -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",
@@ -109,16 +116,17 @@ const lydianDominant: ScaleCollection = {
109
116
  "quirky",
110
117
  "bluesy",
111
118
  "jazzy",
112
- "a very common scale in jazz for non-resolving dominant chords",
119
+ "used in jazz for non-resolving dominant chords",
113
120
  "fourth mode of melodic minor",
114
121
  ],
115
122
  pattern: ["whole", "whole", "whole", "half", "whole", "half", "whole"],
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",
@@ -181,7 +191,7 @@ const altered: ScaleCollection = {
181
191
  "Locrian ♭4",
182
192
  "Locrian Flat Fourth",
183
193
  ],
184
- intervals: ["1", "♭2", "♭3", "♭4", "♭5", "♭7", "8"],
194
+ intervals: ["1", "♭2", "♭3", "♭4", "♭5", "♭6", "♭7", "8"],
185
195
  integers: [0, 1, 3, 4, 6, 8, 10],
186
196
  type: ["melodic minor mode", "dominant", "mode", "scale", "heptatonic"],
187
197
  characteristics: [
@@ -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,
@@ -50,9 +50,7 @@ const chromatic: ScaleCollection = {
50
50
  const wholeTone: ScaleCollection = {
51
51
  category: "scale",
52
52
  primaryName: "Whole Tone Scale",
53
- names: [
54
- "Whole Tone Scale",
55
- ],
53
+ names: ["Whole Tone Scale"],
56
54
  intervals: ["1", "2", "3", "♯4", "♯5", "♯6", "8"],
57
55
  integers: [0, 2, 4, 6, 8, 10],
58
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);