@musodojo/music-theory-data 21.1.1 → 23.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/esm/src/data/labels/note-label-collections.d.ts +30 -6
- package/esm/src/data/labels/note-label-collections.d.ts.map +1 -1
- package/esm/src/data/labels/note-label-collections.js +56 -6
- package/esm/src/utils/intervals.d.ts +49 -6
- package/esm/src/utils/intervals.d.ts.map +1 -1
- package/esm/src/utils/intervals.js +46 -4
- package/esm/src/utils/note-names.d.ts +1 -1
- package/esm/src/utils/note-names.d.ts.map +1 -1
- package/esm/src/utils/note-names.js +22 -55
- package/package.json +1 -1
- package/script/src/data/labels/note-label-collections.d.ts +30 -6
- package/script/src/data/labels/note-label-collections.d.ts.map +1 -1
- package/script/src/data/labels/note-label-collections.js +56 -6
- package/script/src/utils/intervals.d.ts +49 -6
- package/script/src/utils/intervals.d.ts.map +1 -1
- package/script/src/utils/intervals.js +46 -4
- package/script/src/utils/note-names.d.ts +1 -1
- package/script/src/utils/note-names.d.ts.map +1 -1
- package/script/src/utils/note-names.js +22 -55
|
@@ -21,18 +21,42 @@ export interface NoteLabelCollection {
|
|
|
21
21
|
readonly labels: NoteLabelGroup;
|
|
22
22
|
}
|
|
23
23
|
declare const _noteLabelCollections: {
|
|
24
|
-
readonly
|
|
25
|
-
readonly name: "Flat
|
|
26
|
-
readonly shortName: "Flat";
|
|
24
|
+
readonly noteNamesFlat: {
|
|
25
|
+
readonly name: "Flat Note Names";
|
|
26
|
+
readonly shortName: "Flat Notes";
|
|
27
27
|
readonly isRelative: false;
|
|
28
28
|
readonly labels: readonly ["C", "D♭", "D", "E♭", "E", "F", "G♭", "G", "A♭", "A", "B♭", "B"];
|
|
29
29
|
};
|
|
30
|
-
readonly
|
|
31
|
-
readonly name: "Sharp
|
|
32
|
-
readonly shortName: "Sharp";
|
|
30
|
+
readonly noteNamesSharp: {
|
|
31
|
+
readonly name: "Sharp Note Names";
|
|
32
|
+
readonly shortName: "Sharp Notes";
|
|
33
33
|
readonly isRelative: false;
|
|
34
34
|
readonly labels: readonly ["C", "C♯", "D", "D♯", "E", "F", "F♯", "G", "G♯", "A", "A♯", "B"];
|
|
35
35
|
};
|
|
36
|
+
readonly intervalsFlat: {
|
|
37
|
+
readonly name: "Flat Note Intervals";
|
|
38
|
+
readonly shortName: "Flat Intervals";
|
|
39
|
+
readonly isRelative: true;
|
|
40
|
+
readonly labels: readonly ["1", "♭2", "2", "♭3", "3", "4", "♭5", "5", "♭6", "6", "♭7", "7"];
|
|
41
|
+
};
|
|
42
|
+
readonly intervalsSharp: {
|
|
43
|
+
readonly name: "Sharp Note Intervals";
|
|
44
|
+
readonly shortName: "Sharp Intervals";
|
|
45
|
+
readonly isRelative: true;
|
|
46
|
+
readonly labels: readonly ["1", "♯1", "2", "♯2", "3", "4", "♯4", "5", "♯5", "6", "♯6", "7"];
|
|
47
|
+
};
|
|
48
|
+
readonly extensionsFlat: {
|
|
49
|
+
readonly name: "Flat Note Extensions";
|
|
50
|
+
readonly shortName: "Flat Extensions";
|
|
51
|
+
readonly isRelative: true;
|
|
52
|
+
readonly labels: readonly ["1", "♭9", "9", "♭3", "3", "11", "♭5", "5", "♭13", "13", "♭7", "7"];
|
|
53
|
+
};
|
|
54
|
+
readonly extensionsSharp: {
|
|
55
|
+
readonly name: "Sharp Note Extensions";
|
|
56
|
+
readonly shortName: "Sharp Extensions";
|
|
57
|
+
readonly isRelative: true;
|
|
58
|
+
readonly labels: readonly ["1", "♯1", "9", "♯9", "3", "11", "♯11", "5", "♯5", "13", "♯13", "7"];
|
|
59
|
+
};
|
|
36
60
|
readonly fixedDoFlat: {
|
|
37
61
|
readonly name: "Solfege Fixed Do Flat Notes";
|
|
38
62
|
readonly shortName: "Fixed Do Flat";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"note-label-collections.d.ts","sourceRoot":"","sources":["../../../../src/src/data/labels/note-label-collections.ts"],"names":[],"mappings":"AAAA,yFAAyF;AACzF,MAAM,MAAM,cAAc,GAAG,SAAS;IACpC,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;CACP,CAAC;AAEF,iFAAiF;AACjF,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAC7B,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC;CACjC;AAED,QAAA,MAAM,qBAAqB
|
|
1
|
+
{"version":3,"file":"note-label-collections.d.ts","sourceRoot":"","sources":["../../../../src/src/data/labels/note-label-collections.ts"],"names":[],"mappings":"AAAA,yFAAyF;AACzF,MAAM,MAAM,cAAc,GAAG,SAAS;IACpC,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;CACP,CAAC;AAEF,iFAAiF;AACjF,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAC7B,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC;CACjC;AAED,QAAA,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoJjB,CAAC;AAEX,+EAA+E;AAC/E,MAAM,MAAM,sBAAsB,GAAG,MAAM,OAAO,qBAAqB,CAAC;AAExE,yGAAyG;AACzG,eAAO,MAAM,oBAAoB,EAAE,MAAM,CACvC,sBAAsB,EACtB,mBAAmB,CACI,CAAC"}
|
|
@@ -1,16 +1,66 @@
|
|
|
1
1
|
const _noteLabelCollections = {
|
|
2
|
-
|
|
3
|
-
name: "Flat
|
|
4
|
-
shortName: "Flat",
|
|
2
|
+
noteNamesFlat: {
|
|
3
|
+
name: "Flat Note Names",
|
|
4
|
+
shortName: "Flat Notes",
|
|
5
5
|
isRelative: false,
|
|
6
6
|
labels: ["C", "D♭", "D", "E♭", "E", "F", "G♭", "G", "A♭", "A", "B♭", "B"],
|
|
7
7
|
},
|
|
8
|
-
|
|
9
|
-
name: "Sharp
|
|
10
|
-
shortName: "Sharp",
|
|
8
|
+
noteNamesSharp: {
|
|
9
|
+
name: "Sharp Note Names",
|
|
10
|
+
shortName: "Sharp Notes",
|
|
11
11
|
isRelative: false,
|
|
12
12
|
labels: ["C", "C♯", "D", "D♯", "E", "F", "F♯", "G", "G♯", "A", "A♯", "B"],
|
|
13
13
|
},
|
|
14
|
+
intervalsFlat: {
|
|
15
|
+
name: "Flat Note Intervals",
|
|
16
|
+
shortName: "Flat Intervals",
|
|
17
|
+
isRelative: true,
|
|
18
|
+
labels: ["1", "♭2", "2", "♭3", "3", "4", "♭5", "5", "♭6", "6", "♭7", "7"],
|
|
19
|
+
},
|
|
20
|
+
intervalsSharp: {
|
|
21
|
+
name: "Sharp Note Intervals",
|
|
22
|
+
shortName: "Sharp Intervals",
|
|
23
|
+
isRelative: true,
|
|
24
|
+
labels: ["1", "♯1", "2", "♯2", "3", "4", "♯4", "5", "♯5", "6", "♯6", "7"],
|
|
25
|
+
},
|
|
26
|
+
extensionsFlat: {
|
|
27
|
+
name: "Flat Note Extensions",
|
|
28
|
+
shortName: "Flat Extensions",
|
|
29
|
+
isRelative: true,
|
|
30
|
+
labels: [
|
|
31
|
+
"1",
|
|
32
|
+
"♭9",
|
|
33
|
+
"9",
|
|
34
|
+
"♭3",
|
|
35
|
+
"3",
|
|
36
|
+
"11",
|
|
37
|
+
"♭5",
|
|
38
|
+
"5",
|
|
39
|
+
"♭13",
|
|
40
|
+
"13",
|
|
41
|
+
"♭7",
|
|
42
|
+
"7",
|
|
43
|
+
],
|
|
44
|
+
},
|
|
45
|
+
extensionsSharp: {
|
|
46
|
+
name: "Sharp Note Extensions",
|
|
47
|
+
shortName: "Sharp Extensions",
|
|
48
|
+
isRelative: true,
|
|
49
|
+
labels: [
|
|
50
|
+
"1",
|
|
51
|
+
"♯1",
|
|
52
|
+
"9",
|
|
53
|
+
"♯9",
|
|
54
|
+
"3",
|
|
55
|
+
"11",
|
|
56
|
+
"♯11",
|
|
57
|
+
"5",
|
|
58
|
+
"♯5",
|
|
59
|
+
"13",
|
|
60
|
+
"♯13",
|
|
61
|
+
"7",
|
|
62
|
+
],
|
|
63
|
+
},
|
|
14
64
|
fixedDoFlat: {
|
|
15
65
|
name: "Solfege Fixed Do Flat Notes",
|
|
16
66
|
shortName: "Fixed Do Flat",
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { type Interval, type IntervalQuality } from "../data/labels/note-labels.js";
|
|
2
2
|
import type { NoteCollection } from "../types/note-collections";
|
|
3
|
-
import type
|
|
3
|
+
import { type NoteCollectionKey } from "../data/note-collections/mod.js";
|
|
4
4
|
/**
|
|
5
5
|
* Removes octave intervals (such as "8" or "♮8") from a given list of intervals.
|
|
6
|
-
* Highly useful for standardizing chord definitions
|
|
6
|
+
* Highly useful for standardizing chord and scale definitions (scales conventionally include the octave,
|
|
7
|
+
* chords conventionally do not).
|
|
7
8
|
*
|
|
8
9
|
* @param intervals The array of intervals to filter.
|
|
9
10
|
* @returns A new array excluding any octave intervals.
|
|
@@ -19,14 +20,56 @@ export declare function sortIntervals(intervals: readonly Interval[]): Interval[
|
|
|
19
20
|
/** Specifies a direction for converting between simple and compound/extension intervals. */
|
|
20
21
|
export type IntervalTransformation = "simpleToExtension" | "extensionToSimple" | "simpleToCompound" | "compoundToSimple";
|
|
21
22
|
/** Options for grouping and preprocessing intervals before they are evaluated. */
|
|
22
|
-
export
|
|
23
|
+
export type TransformIntervalsOptions = {
|
|
24
|
+
/**
|
|
25
|
+
* Transforms intervals between simple, compound, and extended forms.
|
|
26
|
+
* For example, "simpleToExtension" might change "2" into "9".
|
|
27
|
+
*/
|
|
23
28
|
intervalTransformation?: IntervalTransformation;
|
|
29
|
+
/**
|
|
30
|
+
* Continues to filter out octave intervals (like "8") from the results.
|
|
31
|
+
* Typically useful for scales where octaves are included by default but not needed for some applications.
|
|
32
|
+
*/
|
|
24
33
|
filterOutOctave?: boolean;
|
|
34
|
+
/**
|
|
35
|
+
* Will sort intervals in ascending order based on their integer value.
|
|
36
|
+
* If `fillChromatic` is true, sorting is ignored as the array is fixed to the 12 semitones.
|
|
37
|
+
*/
|
|
25
38
|
shouldSort?: boolean;
|
|
26
|
-
|
|
27
|
-
|
|
39
|
+
/**
|
|
40
|
+
* A fixed number of steps to rotate the array left (positive) or right (negative).
|
|
41
|
+
* Rotation pushes elements from the beginning of the array to the end (left) or vice versa.
|
|
42
|
+
*/
|
|
43
|
+
rotateLeft?: number;
|
|
44
|
+
} & ({
|
|
45
|
+
/**
|
|
46
|
+
* When true, generates a 12-element array representing the chromatic scale (0-11).
|
|
47
|
+
* Missing semitones are filled with standard flat intervals (like "♭2").
|
|
48
|
+
* Compound intervals are placed in their respective integer modulo 12 slot.
|
|
49
|
+
*/
|
|
50
|
+
fillChromatic: true;
|
|
51
|
+
/**
|
|
52
|
+
* If `fillChromatic` is true, this optionally overlays intervals from a known
|
|
53
|
+
* note collection (like a major scale) to provide better enharmonic spelling
|
|
54
|
+
* for the "background" chromatic notes.
|
|
55
|
+
*/
|
|
28
56
|
mostSimilarScale?: NoteCollectionKey;
|
|
29
|
-
|
|
57
|
+
/**
|
|
58
|
+
* If provided, allows for absolute rotations (like rotating to C=0).
|
|
59
|
+
*/
|
|
60
|
+
rootNoteInteger?: number;
|
|
61
|
+
/**
|
|
62
|
+
* Rotates the returned array so that the note corresponding to root C (integer 0)
|
|
63
|
+
* is positioned at index 0. Has no semantic effect on purely relative intervals.
|
|
64
|
+
* Only applicable when fillChromatic is true and rootNoteInteger is provided.
|
|
65
|
+
*/
|
|
66
|
+
rotateToRootInteger0?: boolean;
|
|
67
|
+
} | {
|
|
68
|
+
fillChromatic?: false;
|
|
69
|
+
mostSimilarScale?: never;
|
|
70
|
+
rootNoteInteger?: never;
|
|
71
|
+
rotateToRootInteger0?: never;
|
|
72
|
+
});
|
|
30
73
|
/**
|
|
31
74
|
* Applies a series of formatting steps to an array of intervals, such as changing compound formats,
|
|
32
75
|
* filtering octaves, and sorting.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"intervals.d.ts","sourceRoot":"","sources":["../../../src/src/utils/intervals.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,QAAQ,EACb,KAAK,eAAe,EAMrB,MAAM,+BAA+B,CAAC;AACvC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"intervals.d.ts","sourceRoot":"","sources":["../../../src/src/utils/intervals.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,QAAQ,EACb,KAAK,eAAe,EAMrB,MAAM,+BAA+B,CAAC;AACvC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,EACL,KAAK,iBAAiB,EAEvB,MAAM,iCAAiC,CAAC;AAIzC;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,SAAS,QAAQ,EAAE,GAC7B,QAAQ,EAAE,CAEZ;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,SAAS,EAAE,SAAS,QAAQ,EAAE,GAAG,QAAQ,EAAE,CAOxE;AAED,4FAA4F;AAC5F,MAAM,MAAM,sBAAsB,GAC9B,mBAAmB,GACnB,mBAAmB,GACnB,kBAAkB,GAClB,kBAAkB,CAAC;AAEvB,kFAAkF;AAClF,MAAM,MAAM,yBAAyB,GAAG;IACtC;;;OAGG;IACH,sBAAsB,CAAC,EAAE,sBAAsB,CAAC;IAChD;;;OAGG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,GAAG,CACA;IACE;;;;OAIG;IACH,aAAa,EAAE,IAAI,CAAC;IACpB;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,iBAAiB,CAAC;IACrC;;OAEG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;;;OAIG;IACH,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAChC,GACD;IACE,aAAa,CAAC,EAAE,KAAK,CAAC;IACtB,gBAAgB,CAAC,EAAE,KAAK,CAAC;IACzB,eAAe,CAAC,EAAE,KAAK,CAAC;IACxB,oBAAoB,CAAC,EAAE,KAAK,CAAC;CAC9B,CACJ,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,SAAS,QAAQ,EAAE,EAC9B,OAAO,GAAE,yBAA8B,GACtC,QAAQ,EAAE,CAiFZ;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CACvC,SAAS,EAAE,SAAS,QAAQ,EAAE,GAC7B,eAAe,EAAE,CAKnB;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CACvC,SAAS,EAAE,eAAe,EAAE,GAC3B,QAAQ,EAAE,CAKZ;AAED;;;;GAIG;AACH,wBAAgB,8BAA8B,CAC5C,UAAU,EAAE,cAAc,GACzB,eAAe,EAAE,CAEnB"}
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import { compoundToSimpleIntervalMap, extensionToSimpleIntervalMap, intervalQualityToIntervalMap, intervalToIntegerMap, intervalToIntervalQualityMap, simpleToCompoundIntervalMap, simpleToExtensionIntervalMap, } from "../data/labels/note-labels.js";
|
|
2
|
+
import { noteCollections, } from "../data/note-collections/mod.js";
|
|
3
|
+
import { noteLabelCollections } from "../mod.js";
|
|
4
|
+
import { rotateArrayLeft } from "./rotate-array.js";
|
|
2
5
|
/**
|
|
3
6
|
* Removes octave intervals (such as "8" or "♮8") from a given list of intervals.
|
|
4
|
-
* Highly useful for standardizing chord definitions
|
|
7
|
+
* Highly useful for standardizing chord and scale definitions (scales conventionally include the octave,
|
|
8
|
+
* chords conventionally do not).
|
|
5
9
|
*
|
|
6
10
|
* @param intervals The array of intervals to filter.
|
|
7
11
|
* @returns A new array excluding any octave intervals.
|
|
@@ -33,7 +37,7 @@ export function sortIntervals(intervals) {
|
|
|
33
37
|
* @returns A new transformed array of intervals.
|
|
34
38
|
*/
|
|
35
39
|
export function transformIntervals(intervals, options = {}) {
|
|
36
|
-
const { intervalTransformation, filterOutOctave = false, shouldSort = true, } = options;
|
|
40
|
+
const { intervalTransformation, filterOutOctave = false, shouldSort = true, fillChromatic = false, mostSimilarScale, rotateLeft, } = options;
|
|
37
41
|
const intervalMap = (() => {
|
|
38
42
|
switch (intervalTransformation) {
|
|
39
43
|
case "simpleToExtension":
|
|
@@ -51,8 +55,46 @@ export function transformIntervals(intervals, options = {}) {
|
|
|
51
55
|
const fundamentalIntervals = filterOutOctave
|
|
52
56
|
? filterOutOctaveIntervals(intervals)
|
|
53
57
|
: intervals;
|
|
54
|
-
const
|
|
55
|
-
|
|
58
|
+
const transformedIntervals = fundamentalIntervals.map((interval) => intervalMap.get(interval) ?? interval);
|
|
59
|
+
if (fillChromatic) {
|
|
60
|
+
const chromaticMap = [
|
|
61
|
+
...noteLabelCollections.intervalsFlat.labels,
|
|
62
|
+
];
|
|
63
|
+
if (mostSimilarScale) {
|
|
64
|
+
const collection = noteCollections[mostSimilarScale];
|
|
65
|
+
if (collection && collection.intervals !== intervals) {
|
|
66
|
+
collection.intervals.forEach((interval) => {
|
|
67
|
+
const transformed = intervalMap.get(interval) ?? interval;
|
|
68
|
+
const semitones = intervalToIntegerMap.get(transformed);
|
|
69
|
+
if (semitones !== undefined) {
|
|
70
|
+
chromaticMap[semitones % 12] = transformed;
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
// Now overlay the provided parsed intervals
|
|
76
|
+
transformedIntervals.forEach((interval) => {
|
|
77
|
+
const semitones = intervalToIntegerMap.get(interval);
|
|
78
|
+
if (semitones !== undefined) {
|
|
79
|
+
chromaticMap[semitones % 12] = interval;
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
let result = chromaticMap;
|
|
83
|
+
if (options.rotateToRootInteger0 && options.rootNoteInteger !== undefined) {
|
|
84
|
+
result = rotateArrayLeft(result, -options.rootNoteInteger);
|
|
85
|
+
}
|
|
86
|
+
if (rotateLeft !== undefined) {
|
|
87
|
+
result = rotateArrayLeft(result, rotateLeft);
|
|
88
|
+
}
|
|
89
|
+
return result;
|
|
90
|
+
}
|
|
91
|
+
let result = shouldSort
|
|
92
|
+
? sortIntervals(transformedIntervals)
|
|
93
|
+
: transformedIntervals;
|
|
94
|
+
if (rotateLeft !== undefined) {
|
|
95
|
+
result = rotateArrayLeft(result, rotateLeft);
|
|
96
|
+
}
|
|
97
|
+
return result;
|
|
56
98
|
}
|
|
57
99
|
/**
|
|
58
100
|
* Extracts generic interval qualities (e.g., "P5", "m3" becomes "P", "m") from a list of intervals.
|
|
@@ -44,5 +44,5 @@ export declare function getNoteNamesFromRootAndIntervals(rootNote: RootNote, int
|
|
|
44
44
|
* @param options Optional settings for interval transformations or output formatting.
|
|
45
45
|
* @returns An array of computed note names.
|
|
46
46
|
*/
|
|
47
|
-
export declare function getNoteNamesFromRootAndCollectionKey(rootNote: RootNote, noteCollectionKey: NoteCollectionKey, options?: TransformIntervalsOptions): NoteName[];
|
|
47
|
+
export declare function getNoteNamesFromRootAndCollectionKey(rootNote: RootNote, noteCollectionKey: NoteCollectionKey, options?: Omit<TransformIntervalsOptions, "mostSimilarScale">): NoteName[];
|
|
48
48
|
//# sourceMappingURL=note-names.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"note-names.d.ts","sourceRoot":"","sources":["../../../src/src/utils/note-names.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,QAAQ,EAIb,KAAK,QAAQ,EAGb,KAAK,QAAQ,EACb,KAAK,eAAe,EAErB,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"note-names.d.ts","sourceRoot":"","sources":["../../../src/src/utils/note-names.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,QAAQ,EAIb,KAAK,QAAQ,EAGb,KAAK,QAAQ,EACb,KAAK,eAAe,EAErB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EACL,KAAK,iBAAiB,EAEvB,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAEL,KAAK,yBAAyB,EAC/B,MAAM,gBAAgB,CAAC;AAQxB;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,CAsE1E;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,CAQ1E;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,MAAM,GACf,eAAe,GAAG,SAAS,CAI7B;AA4CD;;;;;;;;;GASG;AACH,wBAAgB,gCAAgC,CAC9C,QAAQ,EAAE,QAAQ,EAClB,SAAS,EAAE,SAAS,QAAQ,EAAE,EAC9B,OAAO,GAAE,yBAA8B,GACtC,QAAQ,EAAE,CAgCZ;AAED;;;;;;;;;GASG;AACH,wBAAgB,oCAAoC,CAClD,QAAQ,EAAE,QAAQ,EAClB,iBAAiB,EAAE,iBAAiB,EACpC,OAAO,GAAE,IAAI,CAAC,yBAAyB,EAAE,kBAAkB,CAAM,GAChE,QAAQ,EAAE,CAuBZ"}
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import { enharmonicNoteNameGroups, intervalToIntegerMap, noteLetters, noteNamesSet, noteNameToIntegerMap, rootNotesSet, } from "../data/labels/note-labels.js";
|
|
2
|
-
import { noteLabelCollections } from "../data/labels/note-label-collections.js";
|
|
3
2
|
import { noteCollections, } from "../data/note-collections/mod.js";
|
|
4
3
|
import { transformIntervals, } from "./intervals.js";
|
|
5
4
|
import { isValidNoteCollectionKey } from "./note-collections.js";
|
|
6
|
-
import { rotateArrayLeft } from "./rotate-array.js";
|
|
7
5
|
const NOTE_LETTER_REGEX = /^[A-Ga-g]/;
|
|
8
6
|
const ACCIDENTAL_REGEX = /([#♯xX𝄪]+)|([b♭𝄫]+)/gu;
|
|
9
7
|
const INTERVAL_NUMBER_REGEX = /\d+/;
|
|
@@ -148,56 +146,21 @@ export function getNoteNamesFromRootAndIntervals(rootNote, intervals, options =
|
|
|
148
146
|
const rootNoteLetter = rootNote.charAt(0).toUpperCase();
|
|
149
147
|
const rootNoteLetterIndex = noteLetters.indexOf(rootNoteLetter);
|
|
150
148
|
// 2. Transform Intervals
|
|
151
|
-
const
|
|
152
|
-
?
|
|
149
|
+
const enhancedOptions = options.fillChromatic
|
|
150
|
+
? {
|
|
151
|
+
...options,
|
|
152
|
+
...(options.rotateToRootInteger0 ? { rootNoteInteger } : {}),
|
|
153
|
+
}
|
|
154
|
+
: options;
|
|
155
|
+
const intervalsToConvert = Object.keys(enhancedOptions).length > 0
|
|
156
|
+
? transformIntervals(intervals, enhancedOptions)
|
|
153
157
|
: intervals;
|
|
154
|
-
let noteNames;
|
|
155
158
|
// 3. Generate Note Names
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
const absoluteInteger = (rootNoteInteger + i) % 12;
|
|
162
|
-
return flatNotes[absoluteInteger];
|
|
163
|
-
});
|
|
164
|
-
// 3a. Overlay mostSimilarScale if provided (to provide better accidental contexts)
|
|
165
|
-
if (options.mostSimilarScale) {
|
|
166
|
-
const similarCollection = noteCollections[options.mostSimilarScale];
|
|
167
|
-
if (similarCollection && similarCollection.intervals !== intervals) {
|
|
168
|
-
similarCollection.intervals.forEach((interval) => {
|
|
169
|
-
const result = getNoteFromRootAndInterval(rootNoteInteger, rootNoteLetterIndex, interval);
|
|
170
|
-
if (result) {
|
|
171
|
-
noteNames[result.semitoneOffset] = result.noteName;
|
|
172
|
-
}
|
|
173
|
-
});
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
// Overwrite default notes with specific notes calculated from intervals
|
|
177
|
-
intervalsToConvert.forEach((interval) => {
|
|
178
|
-
const result = getNoteFromRootAndInterval(rootNoteInteger, rootNoteLetterIndex, interval);
|
|
179
|
-
if (result) {
|
|
180
|
-
noteNames[result.semitoneOffset] = result.noteName;
|
|
181
|
-
}
|
|
182
|
-
});
|
|
183
|
-
}
|
|
184
|
-
else {
|
|
185
|
-
// Map intervals directly to note names
|
|
186
|
-
noteNames = intervalsToConvert.flatMap((interval) => {
|
|
187
|
-
const result = getNoteFromRootAndInterval(rootNoteInteger, rootNoteLetterIndex, interval);
|
|
188
|
-
return result ? [result.noteName] : [];
|
|
189
|
-
});
|
|
190
|
-
}
|
|
191
|
-
// 4. Rotate Array (Optional)
|
|
192
|
-
if (options.rotateToRootInteger0) {
|
|
193
|
-
// Rotate so that the note corresponding to integer 0 (C) is at index 0.
|
|
194
|
-
// e.g., if Root is D (2), the array currently starts at D.
|
|
195
|
-
// To move C (currently at index 10) to index 0, we rotate right by 2 (rootNoteInteger).
|
|
196
|
-
// rotateArrayLeft performs a left shift for positive values.
|
|
197
|
-
// To move C (at index -rootNoteInteger) to 0, we need to shift right by rootNoteInteger.
|
|
198
|
-
// So we rotate by -rootNoteInteger.
|
|
199
|
-
noteNames = rotateArrayLeft(noteNames, -rootNoteInteger);
|
|
200
|
-
}
|
|
159
|
+
// Map intervals directly to note names
|
|
160
|
+
const noteNames = intervalsToConvert.flatMap((interval) => {
|
|
161
|
+
const result = getNoteFromRootAndInterval(rootNoteInteger, rootNoteLetterIndex, interval);
|
|
162
|
+
return result ? [result.noteName] : [];
|
|
163
|
+
});
|
|
201
164
|
return noteNames;
|
|
202
165
|
}
|
|
203
166
|
/**
|
|
@@ -214,11 +177,15 @@ export function getNoteNamesFromRootAndCollectionKey(rootNote, noteCollectionKey
|
|
|
214
177
|
if (!isValidNoteCollectionKey(noteCollectionKey))
|
|
215
178
|
return [];
|
|
216
179
|
const collection = noteCollections[noteCollectionKey];
|
|
217
|
-
const mostSimilarScale = "mostSimilarScale" in collection
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
? {
|
|
180
|
+
const mostSimilarScale = "mostSimilarScale" in collection ? collection.mostSimilarScale : undefined;
|
|
181
|
+
const finalOptions = options.fillChromatic &&
|
|
182
|
+
mostSimilarScale &&
|
|
183
|
+
mostSimilarScale !== noteCollectionKey
|
|
184
|
+
? {
|
|
185
|
+
...options,
|
|
186
|
+
fillChromatic: true,
|
|
187
|
+
mostSimilarScale: mostSimilarScale,
|
|
188
|
+
}
|
|
222
189
|
: options;
|
|
223
190
|
return getNoteNamesFromRootAndIntervals(rootNote, collection.intervals, finalOptions);
|
|
224
191
|
}
|
package/package.json
CHANGED
|
@@ -21,18 +21,42 @@ export interface NoteLabelCollection {
|
|
|
21
21
|
readonly labels: NoteLabelGroup;
|
|
22
22
|
}
|
|
23
23
|
declare const _noteLabelCollections: {
|
|
24
|
-
readonly
|
|
25
|
-
readonly name: "Flat
|
|
26
|
-
readonly shortName: "Flat";
|
|
24
|
+
readonly noteNamesFlat: {
|
|
25
|
+
readonly name: "Flat Note Names";
|
|
26
|
+
readonly shortName: "Flat Notes";
|
|
27
27
|
readonly isRelative: false;
|
|
28
28
|
readonly labels: readonly ["C", "D♭", "D", "E♭", "E", "F", "G♭", "G", "A♭", "A", "B♭", "B"];
|
|
29
29
|
};
|
|
30
|
-
readonly
|
|
31
|
-
readonly name: "Sharp
|
|
32
|
-
readonly shortName: "Sharp";
|
|
30
|
+
readonly noteNamesSharp: {
|
|
31
|
+
readonly name: "Sharp Note Names";
|
|
32
|
+
readonly shortName: "Sharp Notes";
|
|
33
33
|
readonly isRelative: false;
|
|
34
34
|
readonly labels: readonly ["C", "C♯", "D", "D♯", "E", "F", "F♯", "G", "G♯", "A", "A♯", "B"];
|
|
35
35
|
};
|
|
36
|
+
readonly intervalsFlat: {
|
|
37
|
+
readonly name: "Flat Note Intervals";
|
|
38
|
+
readonly shortName: "Flat Intervals";
|
|
39
|
+
readonly isRelative: true;
|
|
40
|
+
readonly labels: readonly ["1", "♭2", "2", "♭3", "3", "4", "♭5", "5", "♭6", "6", "♭7", "7"];
|
|
41
|
+
};
|
|
42
|
+
readonly intervalsSharp: {
|
|
43
|
+
readonly name: "Sharp Note Intervals";
|
|
44
|
+
readonly shortName: "Sharp Intervals";
|
|
45
|
+
readonly isRelative: true;
|
|
46
|
+
readonly labels: readonly ["1", "♯1", "2", "♯2", "3", "4", "♯4", "5", "♯5", "6", "♯6", "7"];
|
|
47
|
+
};
|
|
48
|
+
readonly extensionsFlat: {
|
|
49
|
+
readonly name: "Flat Note Extensions";
|
|
50
|
+
readonly shortName: "Flat Extensions";
|
|
51
|
+
readonly isRelative: true;
|
|
52
|
+
readonly labels: readonly ["1", "♭9", "9", "♭3", "3", "11", "♭5", "5", "♭13", "13", "♭7", "7"];
|
|
53
|
+
};
|
|
54
|
+
readonly extensionsSharp: {
|
|
55
|
+
readonly name: "Sharp Note Extensions";
|
|
56
|
+
readonly shortName: "Sharp Extensions";
|
|
57
|
+
readonly isRelative: true;
|
|
58
|
+
readonly labels: readonly ["1", "♯1", "9", "♯9", "3", "11", "♯11", "5", "♯5", "13", "♯13", "7"];
|
|
59
|
+
};
|
|
36
60
|
readonly fixedDoFlat: {
|
|
37
61
|
readonly name: "Solfege Fixed Do Flat Notes";
|
|
38
62
|
readonly shortName: "Fixed Do Flat";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"note-label-collections.d.ts","sourceRoot":"","sources":["../../../../src/src/data/labels/note-label-collections.ts"],"names":[],"mappings":"AAAA,yFAAyF;AACzF,MAAM,MAAM,cAAc,GAAG,SAAS;IACpC,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;CACP,CAAC;AAEF,iFAAiF;AACjF,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAC7B,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC;CACjC;AAED,QAAA,MAAM,qBAAqB
|
|
1
|
+
{"version":3,"file":"note-label-collections.d.ts","sourceRoot":"","sources":["../../../../src/src/data/labels/note-label-collections.ts"],"names":[],"mappings":"AAAA,yFAAyF;AACzF,MAAM,MAAM,cAAc,GAAG,SAAS;IACpC,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;CACP,CAAC;AAEF,iFAAiF;AACjF,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAC7B,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC;CACjC;AAED,QAAA,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoJjB,CAAC;AAEX,+EAA+E;AAC/E,MAAM,MAAM,sBAAsB,GAAG,MAAM,OAAO,qBAAqB,CAAC;AAExE,yGAAyG;AACzG,eAAO,MAAM,oBAAoB,EAAE,MAAM,CACvC,sBAAsB,EACtB,mBAAmB,CACI,CAAC"}
|
|
@@ -2,18 +2,68 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.noteLabelCollections = void 0;
|
|
4
4
|
const _noteLabelCollections = {
|
|
5
|
-
|
|
6
|
-
name: "Flat
|
|
7
|
-
shortName: "Flat",
|
|
5
|
+
noteNamesFlat: {
|
|
6
|
+
name: "Flat Note Names",
|
|
7
|
+
shortName: "Flat Notes",
|
|
8
8
|
isRelative: false,
|
|
9
9
|
labels: ["C", "D♭", "D", "E♭", "E", "F", "G♭", "G", "A♭", "A", "B♭", "B"],
|
|
10
10
|
},
|
|
11
|
-
|
|
12
|
-
name: "Sharp
|
|
13
|
-
shortName: "Sharp",
|
|
11
|
+
noteNamesSharp: {
|
|
12
|
+
name: "Sharp Note Names",
|
|
13
|
+
shortName: "Sharp Notes",
|
|
14
14
|
isRelative: false,
|
|
15
15
|
labels: ["C", "C♯", "D", "D♯", "E", "F", "F♯", "G", "G♯", "A", "A♯", "B"],
|
|
16
16
|
},
|
|
17
|
+
intervalsFlat: {
|
|
18
|
+
name: "Flat Note Intervals",
|
|
19
|
+
shortName: "Flat Intervals",
|
|
20
|
+
isRelative: true,
|
|
21
|
+
labels: ["1", "♭2", "2", "♭3", "3", "4", "♭5", "5", "♭6", "6", "♭7", "7"],
|
|
22
|
+
},
|
|
23
|
+
intervalsSharp: {
|
|
24
|
+
name: "Sharp Note Intervals",
|
|
25
|
+
shortName: "Sharp Intervals",
|
|
26
|
+
isRelative: true,
|
|
27
|
+
labels: ["1", "♯1", "2", "♯2", "3", "4", "♯4", "5", "♯5", "6", "♯6", "7"],
|
|
28
|
+
},
|
|
29
|
+
extensionsFlat: {
|
|
30
|
+
name: "Flat Note Extensions",
|
|
31
|
+
shortName: "Flat Extensions",
|
|
32
|
+
isRelative: true,
|
|
33
|
+
labels: [
|
|
34
|
+
"1",
|
|
35
|
+
"♭9",
|
|
36
|
+
"9",
|
|
37
|
+
"♭3",
|
|
38
|
+
"3",
|
|
39
|
+
"11",
|
|
40
|
+
"♭5",
|
|
41
|
+
"5",
|
|
42
|
+
"♭13",
|
|
43
|
+
"13",
|
|
44
|
+
"♭7",
|
|
45
|
+
"7",
|
|
46
|
+
],
|
|
47
|
+
},
|
|
48
|
+
extensionsSharp: {
|
|
49
|
+
name: "Sharp Note Extensions",
|
|
50
|
+
shortName: "Sharp Extensions",
|
|
51
|
+
isRelative: true,
|
|
52
|
+
labels: [
|
|
53
|
+
"1",
|
|
54
|
+
"♯1",
|
|
55
|
+
"9",
|
|
56
|
+
"♯9",
|
|
57
|
+
"3",
|
|
58
|
+
"11",
|
|
59
|
+
"♯11",
|
|
60
|
+
"5",
|
|
61
|
+
"♯5",
|
|
62
|
+
"13",
|
|
63
|
+
"♯13",
|
|
64
|
+
"7",
|
|
65
|
+
],
|
|
66
|
+
},
|
|
17
67
|
fixedDoFlat: {
|
|
18
68
|
name: "Solfege Fixed Do Flat Notes",
|
|
19
69
|
shortName: "Fixed Do Flat",
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { type Interval, type IntervalQuality } from "../data/labels/note-labels.js";
|
|
2
2
|
import type { NoteCollection } from "../types/note-collections";
|
|
3
|
-
import type
|
|
3
|
+
import { type NoteCollectionKey } from "../data/note-collections/mod.js";
|
|
4
4
|
/**
|
|
5
5
|
* Removes octave intervals (such as "8" or "♮8") from a given list of intervals.
|
|
6
|
-
* Highly useful for standardizing chord definitions
|
|
6
|
+
* Highly useful for standardizing chord and scale definitions (scales conventionally include the octave,
|
|
7
|
+
* chords conventionally do not).
|
|
7
8
|
*
|
|
8
9
|
* @param intervals The array of intervals to filter.
|
|
9
10
|
* @returns A new array excluding any octave intervals.
|
|
@@ -19,14 +20,56 @@ export declare function sortIntervals(intervals: readonly Interval[]): Interval[
|
|
|
19
20
|
/** Specifies a direction for converting between simple and compound/extension intervals. */
|
|
20
21
|
export type IntervalTransformation = "simpleToExtension" | "extensionToSimple" | "simpleToCompound" | "compoundToSimple";
|
|
21
22
|
/** Options for grouping and preprocessing intervals before they are evaluated. */
|
|
22
|
-
export
|
|
23
|
+
export type TransformIntervalsOptions = {
|
|
24
|
+
/**
|
|
25
|
+
* Transforms intervals between simple, compound, and extended forms.
|
|
26
|
+
* For example, "simpleToExtension" might change "2" into "9".
|
|
27
|
+
*/
|
|
23
28
|
intervalTransformation?: IntervalTransformation;
|
|
29
|
+
/**
|
|
30
|
+
* Continues to filter out octave intervals (like "8") from the results.
|
|
31
|
+
* Typically useful for scales where octaves are included by default but not needed for some applications.
|
|
32
|
+
*/
|
|
24
33
|
filterOutOctave?: boolean;
|
|
34
|
+
/**
|
|
35
|
+
* Will sort intervals in ascending order based on their integer value.
|
|
36
|
+
* If `fillChromatic` is true, sorting is ignored as the array is fixed to the 12 semitones.
|
|
37
|
+
*/
|
|
25
38
|
shouldSort?: boolean;
|
|
26
|
-
|
|
27
|
-
|
|
39
|
+
/**
|
|
40
|
+
* A fixed number of steps to rotate the array left (positive) or right (negative).
|
|
41
|
+
* Rotation pushes elements from the beginning of the array to the end (left) or vice versa.
|
|
42
|
+
*/
|
|
43
|
+
rotateLeft?: number;
|
|
44
|
+
} & ({
|
|
45
|
+
/**
|
|
46
|
+
* When true, generates a 12-element array representing the chromatic scale (0-11).
|
|
47
|
+
* Missing semitones are filled with standard flat intervals (like "♭2").
|
|
48
|
+
* Compound intervals are placed in their respective integer modulo 12 slot.
|
|
49
|
+
*/
|
|
50
|
+
fillChromatic: true;
|
|
51
|
+
/**
|
|
52
|
+
* If `fillChromatic` is true, this optionally overlays intervals from a known
|
|
53
|
+
* note collection (like a major scale) to provide better enharmonic spelling
|
|
54
|
+
* for the "background" chromatic notes.
|
|
55
|
+
*/
|
|
28
56
|
mostSimilarScale?: NoteCollectionKey;
|
|
29
|
-
|
|
57
|
+
/**
|
|
58
|
+
* If provided, allows for absolute rotations (like rotating to C=0).
|
|
59
|
+
*/
|
|
60
|
+
rootNoteInteger?: number;
|
|
61
|
+
/**
|
|
62
|
+
* Rotates the returned array so that the note corresponding to root C (integer 0)
|
|
63
|
+
* is positioned at index 0. Has no semantic effect on purely relative intervals.
|
|
64
|
+
* Only applicable when fillChromatic is true and rootNoteInteger is provided.
|
|
65
|
+
*/
|
|
66
|
+
rotateToRootInteger0?: boolean;
|
|
67
|
+
} | {
|
|
68
|
+
fillChromatic?: false;
|
|
69
|
+
mostSimilarScale?: never;
|
|
70
|
+
rootNoteInteger?: never;
|
|
71
|
+
rotateToRootInteger0?: never;
|
|
72
|
+
});
|
|
30
73
|
/**
|
|
31
74
|
* Applies a series of formatting steps to an array of intervals, such as changing compound formats,
|
|
32
75
|
* filtering octaves, and sorting.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"intervals.d.ts","sourceRoot":"","sources":["../../../src/src/utils/intervals.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,QAAQ,EACb,KAAK,eAAe,EAMrB,MAAM,+BAA+B,CAAC;AACvC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"intervals.d.ts","sourceRoot":"","sources":["../../../src/src/utils/intervals.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,QAAQ,EACb,KAAK,eAAe,EAMrB,MAAM,+BAA+B,CAAC;AACvC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,EACL,KAAK,iBAAiB,EAEvB,MAAM,iCAAiC,CAAC;AAIzC;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,SAAS,QAAQ,EAAE,GAC7B,QAAQ,EAAE,CAEZ;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,SAAS,EAAE,SAAS,QAAQ,EAAE,GAAG,QAAQ,EAAE,CAOxE;AAED,4FAA4F;AAC5F,MAAM,MAAM,sBAAsB,GAC9B,mBAAmB,GACnB,mBAAmB,GACnB,kBAAkB,GAClB,kBAAkB,CAAC;AAEvB,kFAAkF;AAClF,MAAM,MAAM,yBAAyB,GAAG;IACtC;;;OAGG;IACH,sBAAsB,CAAC,EAAE,sBAAsB,CAAC;IAChD;;;OAGG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,GAAG,CACA;IACE;;;;OAIG;IACH,aAAa,EAAE,IAAI,CAAC;IACpB;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,iBAAiB,CAAC;IACrC;;OAEG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;;;OAIG;IACH,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAChC,GACD;IACE,aAAa,CAAC,EAAE,KAAK,CAAC;IACtB,gBAAgB,CAAC,EAAE,KAAK,CAAC;IACzB,eAAe,CAAC,EAAE,KAAK,CAAC;IACxB,oBAAoB,CAAC,EAAE,KAAK,CAAC;CAC9B,CACJ,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,SAAS,QAAQ,EAAE,EAC9B,OAAO,GAAE,yBAA8B,GACtC,QAAQ,EAAE,CAiFZ;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CACvC,SAAS,EAAE,SAAS,QAAQ,EAAE,GAC7B,eAAe,EAAE,CAKnB;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CACvC,SAAS,EAAE,eAAe,EAAE,GAC3B,QAAQ,EAAE,CAKZ;AAED;;;;GAIG;AACH,wBAAgB,8BAA8B,CAC5C,UAAU,EAAE,cAAc,GACzB,eAAe,EAAE,CAEnB"}
|
|
@@ -7,9 +7,13 @@ exports.getQualitiesFromIntervals = getQualitiesFromIntervals;
|
|
|
7
7
|
exports.getIntervalsFromQualities = getIntervalsFromQualities;
|
|
8
8
|
exports.getQualitiesFromNoteCollection = getQualitiesFromNoteCollection;
|
|
9
9
|
const note_labels_js_1 = require("../data/labels/note-labels.js");
|
|
10
|
+
const mod_js_1 = require("../data/note-collections/mod.js");
|
|
11
|
+
const mod_js_2 = require("../mod.js");
|
|
12
|
+
const rotate_array_js_1 = require("./rotate-array.js");
|
|
10
13
|
/**
|
|
11
14
|
* Removes octave intervals (such as "8" or "♮8") from a given list of intervals.
|
|
12
|
-
* Highly useful for standardizing chord definitions
|
|
15
|
+
* Highly useful for standardizing chord and scale definitions (scales conventionally include the octave,
|
|
16
|
+
* chords conventionally do not).
|
|
13
17
|
*
|
|
14
18
|
* @param intervals The array of intervals to filter.
|
|
15
19
|
* @returns A new array excluding any octave intervals.
|
|
@@ -41,7 +45,7 @@ function sortIntervals(intervals) {
|
|
|
41
45
|
* @returns A new transformed array of intervals.
|
|
42
46
|
*/
|
|
43
47
|
function transformIntervals(intervals, options = {}) {
|
|
44
|
-
const { intervalTransformation, filterOutOctave = false, shouldSort = true, } = options;
|
|
48
|
+
const { intervalTransformation, filterOutOctave = false, shouldSort = true, fillChromatic = false, mostSimilarScale, rotateLeft, } = options;
|
|
45
49
|
const intervalMap = (() => {
|
|
46
50
|
switch (intervalTransformation) {
|
|
47
51
|
case "simpleToExtension":
|
|
@@ -59,8 +63,46 @@ function transformIntervals(intervals, options = {}) {
|
|
|
59
63
|
const fundamentalIntervals = filterOutOctave
|
|
60
64
|
? filterOutOctaveIntervals(intervals)
|
|
61
65
|
: intervals;
|
|
62
|
-
const
|
|
63
|
-
|
|
66
|
+
const transformedIntervals = fundamentalIntervals.map((interval) => intervalMap.get(interval) ?? interval);
|
|
67
|
+
if (fillChromatic) {
|
|
68
|
+
const chromaticMap = [
|
|
69
|
+
...mod_js_2.noteLabelCollections.intervalsFlat.labels,
|
|
70
|
+
];
|
|
71
|
+
if (mostSimilarScale) {
|
|
72
|
+
const collection = mod_js_1.noteCollections[mostSimilarScale];
|
|
73
|
+
if (collection && collection.intervals !== intervals) {
|
|
74
|
+
collection.intervals.forEach((interval) => {
|
|
75
|
+
const transformed = intervalMap.get(interval) ?? interval;
|
|
76
|
+
const semitones = note_labels_js_1.intervalToIntegerMap.get(transformed);
|
|
77
|
+
if (semitones !== undefined) {
|
|
78
|
+
chromaticMap[semitones % 12] = transformed;
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
// Now overlay the provided parsed intervals
|
|
84
|
+
transformedIntervals.forEach((interval) => {
|
|
85
|
+
const semitones = note_labels_js_1.intervalToIntegerMap.get(interval);
|
|
86
|
+
if (semitones !== undefined) {
|
|
87
|
+
chromaticMap[semitones % 12] = interval;
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
let result = chromaticMap;
|
|
91
|
+
if (options.rotateToRootInteger0 && options.rootNoteInteger !== undefined) {
|
|
92
|
+
result = (0, rotate_array_js_1.rotateArrayLeft)(result, -options.rootNoteInteger);
|
|
93
|
+
}
|
|
94
|
+
if (rotateLeft !== undefined) {
|
|
95
|
+
result = (0, rotate_array_js_1.rotateArrayLeft)(result, rotateLeft);
|
|
96
|
+
}
|
|
97
|
+
return result;
|
|
98
|
+
}
|
|
99
|
+
let result = shouldSort
|
|
100
|
+
? sortIntervals(transformedIntervals)
|
|
101
|
+
: transformedIntervals;
|
|
102
|
+
if (rotateLeft !== undefined) {
|
|
103
|
+
result = (0, rotate_array_js_1.rotateArrayLeft)(result, rotateLeft);
|
|
104
|
+
}
|
|
105
|
+
return result;
|
|
64
106
|
}
|
|
65
107
|
/**
|
|
66
108
|
* Extracts generic interval qualities (e.g., "P5", "m3" becomes "P", "m") from a list of intervals.
|
|
@@ -44,5 +44,5 @@ export declare function getNoteNamesFromRootAndIntervals(rootNote: RootNote, int
|
|
|
44
44
|
* @param options Optional settings for interval transformations or output formatting.
|
|
45
45
|
* @returns An array of computed note names.
|
|
46
46
|
*/
|
|
47
|
-
export declare function getNoteNamesFromRootAndCollectionKey(rootNote: RootNote, noteCollectionKey: NoteCollectionKey, options?: TransformIntervalsOptions): NoteName[];
|
|
47
|
+
export declare function getNoteNamesFromRootAndCollectionKey(rootNote: RootNote, noteCollectionKey: NoteCollectionKey, options?: Omit<TransformIntervalsOptions, "mostSimilarScale">): NoteName[];
|
|
48
48
|
//# sourceMappingURL=note-names.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"note-names.d.ts","sourceRoot":"","sources":["../../../src/src/utils/note-names.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,QAAQ,EAIb,KAAK,QAAQ,EAGb,KAAK,QAAQ,EACb,KAAK,eAAe,EAErB,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"note-names.d.ts","sourceRoot":"","sources":["../../../src/src/utils/note-names.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,QAAQ,EAIb,KAAK,QAAQ,EAGb,KAAK,QAAQ,EACb,KAAK,eAAe,EAErB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EACL,KAAK,iBAAiB,EAEvB,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAEL,KAAK,yBAAyB,EAC/B,MAAM,gBAAgB,CAAC;AAQxB;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,CAsE1E;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,CAQ1E;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,MAAM,GACf,eAAe,GAAG,SAAS,CAI7B;AA4CD;;;;;;;;;GASG;AACH,wBAAgB,gCAAgC,CAC9C,QAAQ,EAAE,QAAQ,EAClB,SAAS,EAAE,SAAS,QAAQ,EAAE,EAC9B,OAAO,GAAE,yBAA8B,GACtC,QAAQ,EAAE,CAgCZ;AAED;;;;;;;;;GASG;AACH,wBAAgB,oCAAoC,CAClD,QAAQ,EAAE,QAAQ,EAClB,iBAAiB,EAAE,iBAAiB,EACpC,OAAO,GAAE,IAAI,CAAC,yBAAyB,EAAE,kBAAkB,CAAM,GAChE,QAAQ,EAAE,CAuBZ"}
|
|
@@ -6,11 +6,9 @@ exports.getNoteIntegerFromString = getNoteIntegerFromString;
|
|
|
6
6
|
exports.getNoteNamesFromRootAndIntervals = getNoteNamesFromRootAndIntervals;
|
|
7
7
|
exports.getNoteNamesFromRootAndCollectionKey = getNoteNamesFromRootAndCollectionKey;
|
|
8
8
|
const note_labels_js_1 = require("../data/labels/note-labels.js");
|
|
9
|
-
const note_label_collections_js_1 = require("../data/labels/note-label-collections.js");
|
|
10
9
|
const mod_js_1 = require("../data/note-collections/mod.js");
|
|
11
10
|
const intervals_js_1 = require("./intervals.js");
|
|
12
11
|
const note_collections_js_1 = require("./note-collections.js");
|
|
13
|
-
const rotate_array_js_1 = require("./rotate-array.js");
|
|
14
12
|
const NOTE_LETTER_REGEX = /^[A-Ga-g]/;
|
|
15
13
|
const ACCIDENTAL_REGEX = /([#♯xX𝄪]+)|([b♭𝄫]+)/gu;
|
|
16
14
|
const INTERVAL_NUMBER_REGEX = /\d+/;
|
|
@@ -155,56 +153,21 @@ function getNoteNamesFromRootAndIntervals(rootNote, intervals, options = {}) {
|
|
|
155
153
|
const rootNoteLetter = rootNote.charAt(0).toUpperCase();
|
|
156
154
|
const rootNoteLetterIndex = note_labels_js_1.noteLetters.indexOf(rootNoteLetter);
|
|
157
155
|
// 2. Transform Intervals
|
|
158
|
-
const
|
|
159
|
-
?
|
|
156
|
+
const enhancedOptions = options.fillChromatic
|
|
157
|
+
? {
|
|
158
|
+
...options,
|
|
159
|
+
...(options.rotateToRootInteger0 ? { rootNoteInteger } : {}),
|
|
160
|
+
}
|
|
161
|
+
: options;
|
|
162
|
+
const intervalsToConvert = Object.keys(enhancedOptions).length > 0
|
|
163
|
+
? (0, intervals_js_1.transformIntervals)(intervals, enhancedOptions)
|
|
160
164
|
: intervals;
|
|
161
|
-
let noteNames;
|
|
162
165
|
// 3. Generate Note Names
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
const absoluteInteger = (rootNoteInteger + i) % 12;
|
|
169
|
-
return flatNotes[absoluteInteger];
|
|
170
|
-
});
|
|
171
|
-
// 3a. Overlay mostSimilarScale if provided (to provide better accidental contexts)
|
|
172
|
-
if (options.mostSimilarScale) {
|
|
173
|
-
const similarCollection = mod_js_1.noteCollections[options.mostSimilarScale];
|
|
174
|
-
if (similarCollection && similarCollection.intervals !== intervals) {
|
|
175
|
-
similarCollection.intervals.forEach((interval) => {
|
|
176
|
-
const result = getNoteFromRootAndInterval(rootNoteInteger, rootNoteLetterIndex, interval);
|
|
177
|
-
if (result) {
|
|
178
|
-
noteNames[result.semitoneOffset] = result.noteName;
|
|
179
|
-
}
|
|
180
|
-
});
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
// Overwrite default notes with specific notes calculated from intervals
|
|
184
|
-
intervalsToConvert.forEach((interval) => {
|
|
185
|
-
const result = getNoteFromRootAndInterval(rootNoteInteger, rootNoteLetterIndex, interval);
|
|
186
|
-
if (result) {
|
|
187
|
-
noteNames[result.semitoneOffset] = result.noteName;
|
|
188
|
-
}
|
|
189
|
-
});
|
|
190
|
-
}
|
|
191
|
-
else {
|
|
192
|
-
// Map intervals directly to note names
|
|
193
|
-
noteNames = intervalsToConvert.flatMap((interval) => {
|
|
194
|
-
const result = getNoteFromRootAndInterval(rootNoteInteger, rootNoteLetterIndex, interval);
|
|
195
|
-
return result ? [result.noteName] : [];
|
|
196
|
-
});
|
|
197
|
-
}
|
|
198
|
-
// 4. Rotate Array (Optional)
|
|
199
|
-
if (options.rotateToRootInteger0) {
|
|
200
|
-
// Rotate so that the note corresponding to integer 0 (C) is at index 0.
|
|
201
|
-
// e.g., if Root is D (2), the array currently starts at D.
|
|
202
|
-
// To move C (currently at index 10) to index 0, we rotate right by 2 (rootNoteInteger).
|
|
203
|
-
// rotateArrayLeft performs a left shift for positive values.
|
|
204
|
-
// To move C (at index -rootNoteInteger) to 0, we need to shift right by rootNoteInteger.
|
|
205
|
-
// So we rotate by -rootNoteInteger.
|
|
206
|
-
noteNames = (0, rotate_array_js_1.rotateArrayLeft)(noteNames, -rootNoteInteger);
|
|
207
|
-
}
|
|
166
|
+
// Map intervals directly to note names
|
|
167
|
+
const noteNames = intervalsToConvert.flatMap((interval) => {
|
|
168
|
+
const result = getNoteFromRootAndInterval(rootNoteInteger, rootNoteLetterIndex, interval);
|
|
169
|
+
return result ? [result.noteName] : [];
|
|
170
|
+
});
|
|
208
171
|
return noteNames;
|
|
209
172
|
}
|
|
210
173
|
/**
|
|
@@ -221,11 +184,15 @@ function getNoteNamesFromRootAndCollectionKey(rootNote, noteCollectionKey, optio
|
|
|
221
184
|
if (!(0, note_collections_js_1.isValidNoteCollectionKey)(noteCollectionKey))
|
|
222
185
|
return [];
|
|
223
186
|
const collection = mod_js_1.noteCollections[noteCollectionKey];
|
|
224
|
-
const mostSimilarScale = "mostSimilarScale" in collection
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
? {
|
|
187
|
+
const mostSimilarScale = "mostSimilarScale" in collection ? collection.mostSimilarScale : undefined;
|
|
188
|
+
const finalOptions = options.fillChromatic &&
|
|
189
|
+
mostSimilarScale &&
|
|
190
|
+
mostSimilarScale !== noteCollectionKey
|
|
191
|
+
? {
|
|
192
|
+
...options,
|
|
193
|
+
fillChromatic: true,
|
|
194
|
+
mostSimilarScale: mostSimilarScale,
|
|
195
|
+
}
|
|
229
196
|
: options;
|
|
230
197
|
return getNoteNamesFromRootAndIntervals(rootNote, collection.intervals, finalOptions);
|
|
231
198
|
}
|