@musodojo/music-theory-data 18.0.0 → 19.0.1
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/package.json +1 -1
- package/src/data/note-collections/diatonic-modes.ts +4 -7
- package/src/data/note-collections/diminished-variants.ts +2 -2
- package/src/data/note-collections/dominant-variants.ts +2 -2
- package/src/data/note-collections/harmonic-minor-modes.ts +7 -8
- package/src/data/note-collections/melodic-minor-modes.ts +7 -8
- package/src/data/note-collections/pentatonic-variants.ts +7 -8
- package/src/types/midi.d.ts +0 -2
- package/src/types/note-collections.d.ts +3 -12
- package/src/utils/chords.ts +0 -15
- package/src/utils/midi-note-sequences.ts +3 -3
- package/src/utils/midi.ts +27 -26
- package/src/utils/note-names.ts +3 -9
package/package.json
CHANGED
|
@@ -1,12 +1,9 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
ModalScaleCollection,
|
|
3
|
-
ParentScaleCollection,
|
|
4
|
-
ScaleCollection,
|
|
5
|
-
} from "../../types/note-collections.d.ts";
|
|
1
|
+
import type { ModalScaleCollection } from "../../types/note-collections.d.ts";
|
|
6
2
|
|
|
7
|
-
const ionian:
|
|
3
|
+
const ionian: ModalScaleCollection = {
|
|
8
4
|
category: "scale",
|
|
9
5
|
rotation: 0,
|
|
6
|
+
parentScale: "ionian",
|
|
10
7
|
primaryName: "Major",
|
|
11
8
|
names: [
|
|
12
9
|
"Major",
|
|
@@ -280,5 +277,5 @@ const _diatonicModes = {
|
|
|
280
277
|
|
|
281
278
|
export type DiatonicModeKey = keyof typeof _diatonicModes;
|
|
282
279
|
|
|
283
|
-
export const diatonicModes: Record<DiatonicModeKey,
|
|
280
|
+
export const diatonicModes: Record<DiatonicModeKey, ModalScaleCollection> =
|
|
284
281
|
_diatonicModes;
|
|
@@ -2,7 +2,6 @@ import type {
|
|
|
2
2
|
ChordCollection,
|
|
3
3
|
ModalScaleCollection,
|
|
4
4
|
NoteCollection,
|
|
5
|
-
ParentScaleCollection,
|
|
6
5
|
} from "../../types/note-collections.d.ts";
|
|
7
6
|
|
|
8
7
|
const diminishedTriad: ChordCollection = {
|
|
@@ -41,9 +40,10 @@ const halfDiminished7: ChordCollection = {
|
|
|
41
40
|
patternShort: ["m3", "m3", "M3"],
|
|
42
41
|
} as const;
|
|
43
42
|
|
|
44
|
-
const wholeHalfDiminished:
|
|
43
|
+
const wholeHalfDiminished: ModalScaleCollection = {
|
|
45
44
|
category: "scale",
|
|
46
45
|
rotation: 0,
|
|
46
|
+
parentScale: "wholeHalfDiminished",
|
|
47
47
|
primaryName: "Whole Half Diminished",
|
|
48
48
|
names: ["Whole Half Diminished"],
|
|
49
49
|
intervals: ["1", "2", "♭3", "4", "♭5", "♭6", "6", "7", "8"],
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
ChordCollection,
|
|
3
|
+
NonModalScaleCollection,
|
|
3
4
|
NoteCollection,
|
|
4
|
-
ScaleCollection,
|
|
5
5
|
} from "../../types/note-collections.d.ts";
|
|
6
6
|
|
|
7
7
|
const dominant7: ChordCollection = {
|
|
@@ -105,7 +105,7 @@ const dominant13: ChordCollection = {
|
|
|
105
105
|
patternShort: ["M3", "m3", "m3", "M3", "m3", "m3"],
|
|
106
106
|
} as const;
|
|
107
107
|
|
|
108
|
-
const dominantPentatonic:
|
|
108
|
+
const dominantPentatonic: NonModalScaleCollection = {
|
|
109
109
|
category: "scale",
|
|
110
110
|
primaryName: "Dominant Pentatonic",
|
|
111
111
|
names: ["Dominant Pentatonic"],
|
|
@@ -1,12 +1,9 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
ModalScaleCollection,
|
|
3
|
-
ParentScaleCollection,
|
|
4
|
-
ScaleCollection,
|
|
5
|
-
} from "../../types/note-collections.d.ts";
|
|
1
|
+
import type { ModalScaleCollection } from "../../types/note-collections.d.ts";
|
|
6
2
|
|
|
7
|
-
const harmonicMinor:
|
|
3
|
+
const harmonicMinor: ModalScaleCollection = {
|
|
8
4
|
category: "scale",
|
|
9
5
|
rotation: 0,
|
|
6
|
+
parentScale: "harmonicMinor",
|
|
10
7
|
primaryName: "Harmonic Minor",
|
|
11
8
|
names: [
|
|
12
9
|
"Harmonic Minor",
|
|
@@ -258,5 +255,7 @@ export const _harmonicMinorModes = {
|
|
|
258
255
|
|
|
259
256
|
export type HarmonicMinorModeKey = keyof typeof _harmonicMinorModes;
|
|
260
257
|
|
|
261
|
-
export const harmonicMinorModes: Record<
|
|
262
|
-
|
|
258
|
+
export const harmonicMinorModes: Record<
|
|
259
|
+
HarmonicMinorModeKey,
|
|
260
|
+
ModalScaleCollection
|
|
261
|
+
> = _harmonicMinorModes;
|
|
@@ -1,12 +1,9 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
ModalScaleCollection,
|
|
3
|
-
ParentScaleCollection,
|
|
4
|
-
ScaleCollection,
|
|
5
|
-
} from "../../types/note-collections.d.ts";
|
|
1
|
+
import type { ModalScaleCollection } from "../../types/note-collections.d.ts";
|
|
6
2
|
|
|
7
|
-
const melodicMinor:
|
|
3
|
+
const melodicMinor: ModalScaleCollection = {
|
|
8
4
|
category: "scale",
|
|
9
5
|
rotation: 0,
|
|
6
|
+
parentScale: "melodicMinor",
|
|
10
7
|
primaryName: "Melodic Minor",
|
|
11
8
|
names: [
|
|
12
9
|
"Melodic Minor",
|
|
@@ -218,5 +215,7 @@ export const _melodicMinorModes = {
|
|
|
218
215
|
|
|
219
216
|
export type MelodicMinorModeKey = keyof typeof _melodicMinorModes;
|
|
220
217
|
|
|
221
|
-
export const melodicMinorModes: Record<
|
|
222
|
-
|
|
218
|
+
export const melodicMinorModes: Record<
|
|
219
|
+
MelodicMinorModeKey,
|
|
220
|
+
ModalScaleCollection
|
|
221
|
+
> = _melodicMinorModes;
|
|
@@ -1,12 +1,9 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
ModalScaleCollection,
|
|
3
|
-
ParentScaleCollection,
|
|
4
|
-
ScaleCollection,
|
|
5
|
-
} from "../../types/note-collections.d.ts";
|
|
1
|
+
import type { ModalScaleCollection } from "../../types/note-collections.d.ts";
|
|
6
2
|
|
|
7
|
-
const majorPentatonic:
|
|
3
|
+
const majorPentatonic: ModalScaleCollection = {
|
|
8
4
|
category: "scale",
|
|
9
5
|
rotation: 0,
|
|
6
|
+
parentScale: "majorPentatonic",
|
|
10
7
|
primaryName: "Major Pentatonic",
|
|
11
8
|
names: ["Major Pentatonic"],
|
|
12
9
|
intervals: ["1", "2", "3", "5", "6", "8"],
|
|
@@ -96,5 +93,7 @@ export const _pentatonicVariants = {
|
|
|
96
93
|
|
|
97
94
|
export type PentatonicVariantKey = keyof typeof _pentatonicVariants;
|
|
98
95
|
|
|
99
|
-
export const pentatonicVariants: Record<
|
|
100
|
-
|
|
96
|
+
export const pentatonicVariants: Record<
|
|
97
|
+
PentatonicVariantKey,
|
|
98
|
+
ModalScaleCollection
|
|
99
|
+
> = _pentatonicVariants;
|
package/src/types/midi.d.ts
CHANGED
|
@@ -49,28 +49,20 @@ interface NoteCollectionBase {
|
|
|
49
49
|
readonly patternShort: readonly string[];
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
/** A scale that
|
|
53
|
-
interface
|
|
52
|
+
/** A scale that can be thought of as a mode of a parent scale (e.g., Ionian, Dorian, Lydian Augmented). */
|
|
53
|
+
interface ModalScaleCollection extends NoteCollectionBase {
|
|
54
54
|
/**
|
|
55
55
|
* The fundamental classification of the collection. For scales, this is always "scale".
|
|
56
56
|
*/
|
|
57
57
|
readonly category: "scale";
|
|
58
58
|
/**
|
|
59
59
|
* The rotation index for a parent scale is always 0.
|
|
60
|
-
*/
|
|
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
60
|
* The rotation index relative to a parent scale. e.g., Dorian is 1.
|
|
70
61
|
*/
|
|
71
62
|
readonly rotation: number;
|
|
72
63
|
/**
|
|
73
64
|
* The key-name (e.g., "ionian") of the parent scale from which this mode is derived.
|
|
65
|
+
* The parent scale has itself as parentScale!
|
|
74
66
|
*/
|
|
75
67
|
readonly parentScale: string;
|
|
76
68
|
}
|
|
@@ -88,7 +80,6 @@ export interface ChordCollection extends NoteCollectionBase {
|
|
|
88
80
|
}
|
|
89
81
|
|
|
90
82
|
export type ScaleCollection =
|
|
91
|
-
| ParentScaleCollection
|
|
92
83
|
| ModalScaleCollection
|
|
93
84
|
| NonModalScaleCollection;
|
|
94
85
|
|
package/src/utils/chords.ts
CHANGED
|
@@ -100,11 +100,6 @@ export function getChordDetailsForDiatonicMode(
|
|
|
100
100
|
diatonicModeKey: DiatonicModeKey,
|
|
101
101
|
): ChordDetails[] {
|
|
102
102
|
const mode = diatonicModes[diatonicModeKey];
|
|
103
|
-
if (mode.rotation === undefined) {
|
|
104
|
-
throw new Error(
|
|
105
|
-
`Mode "${diatonicModeKey}" is missing the 'rotation' property.`,
|
|
106
|
-
);
|
|
107
|
-
}
|
|
108
103
|
const rotation = mode.rotation;
|
|
109
104
|
const rotatedTriads = rotateArray(diatonicTriads, rotation);
|
|
110
105
|
const rotatedSeventhChords = rotateArray(diatonicSeventhChords, rotation);
|
|
@@ -121,11 +116,6 @@ export function getChordDetailsForHarmonicMinorMode(
|
|
|
121
116
|
harmonicMinorModeKey: HarmonicMinorModeKey,
|
|
122
117
|
): ChordDetails[] {
|
|
123
118
|
const mode = harmonicMinorModes[harmonicMinorModeKey];
|
|
124
|
-
if (mode.rotation === undefined) {
|
|
125
|
-
throw new Error(
|
|
126
|
-
`Mode "${harmonicMinorModeKey}" is missing the 'rotation' property.`,
|
|
127
|
-
);
|
|
128
|
-
}
|
|
129
119
|
const rotation = mode.rotation;
|
|
130
120
|
const rotatedTriads = rotateArray(harmonicMinorTriads, rotation);
|
|
131
121
|
const rotatedSeventhChords = rotateArray(
|
|
@@ -145,11 +135,6 @@ export function getChordDetailsForMelodicMinorMode(
|
|
|
145
135
|
melodicMinorModeKey: MelodicMinorModeKey,
|
|
146
136
|
): ChordDetails[] {
|
|
147
137
|
const mode = melodicMinorModes[melodicMinorModeKey];
|
|
148
|
-
if (mode.rotation === undefined) {
|
|
149
|
-
throw new Error(
|
|
150
|
-
`Mode "${melodicMinorModeKey}" is missing the 'rotation' property.`,
|
|
151
|
-
);
|
|
152
|
-
}
|
|
153
138
|
const rotation = mode.rotation;
|
|
154
139
|
const rotatedTriads = rotateArray(melodicMinorTriads, rotation);
|
|
155
140
|
const rotatedSeventhChords = rotateArray(melodicMinorSeventhChords, rotation);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Interval } from "../data/labels/note-labels.ts";
|
|
2
2
|
import type { MidiNoteNumber, MidiNoteSequence } from "../types/midi.d.ts";
|
|
3
|
-
import {
|
|
3
|
+
import { noteMidiAndIntervalToMidi } from "./midi.ts";
|
|
4
4
|
|
|
5
5
|
export type MidiNoteSequenceDirection =
|
|
6
6
|
| "ascending"
|
|
@@ -50,7 +50,7 @@ function getMonotonicMidiNoteSequence(
|
|
|
50
50
|
intervalIndex = (startFromIndex + i) % intervalsLength;
|
|
51
51
|
octaveOffset = Math.floor((startFromIndex + i) / intervalsLength) * 12;
|
|
52
52
|
const interval = intervals[intervalIndex];
|
|
53
|
-
const note =
|
|
53
|
+
const note = noteMidiAndIntervalToMidi(rootNoteMidi, interval);
|
|
54
54
|
if (note === undefined) {
|
|
55
55
|
throw new Error(
|
|
56
56
|
`Could not calculate MIDI note for interval ${interval} at index ${intervalIndex}`,
|
|
@@ -75,7 +75,7 @@ function getMonotonicMidiNoteSequence(
|
|
|
75
75
|
Math.max(0, Math.ceil((i - startFromIndex) / intervalsLength)) * 12;
|
|
76
76
|
const interval = intervals[intervalIndex];
|
|
77
77
|
// Subtract octaveOffset from root before applying interval
|
|
78
|
-
const note =
|
|
78
|
+
const note = noteMidiAndIntervalToMidi(
|
|
79
79
|
(rootNoteMidi - octaveOffset) as MidiNoteNumber,
|
|
80
80
|
interval,
|
|
81
81
|
);
|
package/src/utils/midi.ts
CHANGED
|
@@ -3,48 +3,49 @@ import {
|
|
|
3
3
|
intervalToIntegerMap,
|
|
4
4
|
type NoteName,
|
|
5
5
|
noteNameToIntegerMap,
|
|
6
|
-
type RootNoteInteger,
|
|
7
6
|
} from "../data/labels/note-labels.ts";
|
|
8
7
|
|
|
9
|
-
import type { MidiNoteNumber
|
|
8
|
+
import type { MidiNoteNumber } from "../types/midi.d.ts";
|
|
10
9
|
|
|
11
|
-
export function
|
|
12
|
-
|
|
10
|
+
export function noteIntegerAndIntervalToMidi(
|
|
11
|
+
noteInteger: number,
|
|
12
|
+
noteOctaveNumber: number,
|
|
13
13
|
interval: Interval,
|
|
14
|
-
rootNoteOctaveNumber: OctaveNumber = 4,
|
|
15
14
|
): MidiNoteNumber | undefined {
|
|
16
|
-
const
|
|
17
|
-
if (
|
|
18
|
-
return (
|
|
19
|
-
|
|
15
|
+
const intervalInteger = intervalToIntegerMap.get(interval);
|
|
16
|
+
if (intervalInteger === undefined) return undefined;
|
|
17
|
+
return (noteOctaveNumber + 1) * 12 + noteInteger +
|
|
18
|
+
intervalInteger as MidiNoteNumber;
|
|
20
19
|
}
|
|
21
20
|
|
|
22
|
-
export function
|
|
23
|
-
|
|
21
|
+
export function noteNameAndIntervalToMidi(
|
|
22
|
+
noteName: NoteName,
|
|
23
|
+
noteOctaveNumber: number,
|
|
24
24
|
interval: Interval,
|
|
25
25
|
): MidiNoteNumber | undefined {
|
|
26
|
-
const
|
|
27
|
-
if (
|
|
28
|
-
return
|
|
26
|
+
const noteInteger = noteNameToIntegerMap.get(noteName);
|
|
27
|
+
if (noteInteger === undefined) return undefined;
|
|
28
|
+
return noteIntegerAndIntervalToMidi(
|
|
29
|
+
noteInteger,
|
|
30
|
+
noteOctaveNumber,
|
|
31
|
+
interval,
|
|
32
|
+
);
|
|
29
33
|
}
|
|
30
34
|
|
|
31
|
-
export function
|
|
32
|
-
|
|
33
|
-
|
|
35
|
+
export function noteMidiAndIntervalToMidi(
|
|
36
|
+
noteMidi: MidiNoteNumber,
|
|
37
|
+
interval: Interval,
|
|
34
38
|
): MidiNoteNumber | undefined {
|
|
35
|
-
const
|
|
36
|
-
if (
|
|
37
|
-
return
|
|
39
|
+
const intervalValue = intervalToIntegerMap.get(interval);
|
|
40
|
+
if (intervalValue === undefined) return undefined;
|
|
41
|
+
return noteMidi + intervalValue as MidiNoteNumber;
|
|
38
42
|
}
|
|
39
43
|
|
|
40
|
-
export function
|
|
44
|
+
export function noteNameToMidi(
|
|
41
45
|
noteName: NoteName,
|
|
42
|
-
|
|
43
|
-
octaveNumber: OctaveNumber = 4,
|
|
46
|
+
noteOctaveNumber: number,
|
|
44
47
|
): MidiNoteNumber | undefined {
|
|
45
48
|
const noteValue = noteNameToIntegerMap.get(noteName);
|
|
46
49
|
if (noteValue === undefined) return undefined;
|
|
47
|
-
|
|
48
|
-
if (intervalValue === undefined) return undefined;
|
|
49
|
-
return noteValue + (octaveNumber + 1) * 12 as MidiNoteNumber;
|
|
50
|
+
return noteValue + (noteOctaveNumber + 1) * 12 as MidiNoteNumber;
|
|
50
51
|
}
|
package/src/utils/note-names.ts
CHANGED
|
@@ -122,18 +122,12 @@ export function normalizeRootNoteString(name: string): RootNote | undefined {
|
|
|
122
122
|
return undefined;
|
|
123
123
|
}
|
|
124
124
|
|
|
125
|
-
export function
|
|
126
|
-
noteName: NoteName,
|
|
127
|
-
): RootNoteInteger | undefined {
|
|
128
|
-
return noteNameToIntegerMap.get(noteName);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
export function noteNameStringToInteger(
|
|
125
|
+
export function getNoteIntegerFromString(
|
|
132
126
|
noteName: string,
|
|
133
127
|
): RootNoteInteger | undefined {
|
|
134
128
|
const normalized = normalizeNoteNameString(noteName);
|
|
135
129
|
if (!normalized) return undefined;
|
|
136
|
-
return
|
|
130
|
+
return noteNameToIntegerMap.get(normalized);
|
|
137
131
|
}
|
|
138
132
|
|
|
139
133
|
export function getNoteNamesFromRootAndIntervals(
|
|
@@ -141,7 +135,7 @@ export function getNoteNamesFromRootAndIntervals(
|
|
|
141
135
|
intervals: readonly Interval[],
|
|
142
136
|
options: TransformIntervalsOptions = {},
|
|
143
137
|
): NoteName[] {
|
|
144
|
-
const rootNoteInteger =
|
|
138
|
+
const rootNoteInteger = noteNameToIntegerMap.get(rootNote);
|
|
145
139
|
if (rootNoteInteger === undefined) return [];
|
|
146
140
|
const rootNoteLetter = rootNote.charAt(0).toUpperCase();
|
|
147
141
|
const rootNoteLetterIndex = noteLetters.indexOf(rootNoteLetter as NoteLetter);
|