@tonaljs/chord 5.0.1 → 6.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 +43 -35
- package/dist/index.d.mts +21 -12
- package/dist/index.d.ts +21 -12
- package/dist/index.js +78 -44
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +77 -46
- package/dist/index.mjs.map +1 -1
- package/package.json +15 -8
package/README.md
CHANGED
|
@@ -18,62 +18,70 @@ const { Chord } = require("tonal");
|
|
|
18
18
|
|
|
19
19
|
#### `Chord.getChord(type: string, tonic?: string, root?: string) => Chord`
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
#### `Chord.get(name: string | [string, string] | [string, string, string]) => Chord`
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
Given a chord symbol or tokens, it returns the chord properties.
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
Chord properties is the the same object that `ChordType.get` but with additional fields:
|
|
26
|
+
|
|
27
|
+
- symbol: the chord symbol (a combination of the tonic, chord type shortname and root, if present). For example: `Cmaj7`, `Db7b5/F`. The symbol always uses pitch classes (note names without octaves) for both the tonic and root.
|
|
26
28
|
- tonic: the tonic of the chord (or an empty string if not present)
|
|
27
|
-
-
|
|
28
|
-
-
|
|
29
|
-
-
|
|
29
|
+
- bass: the bass of the chord (or an empty string if not present). The bass can be any pitch class.
|
|
30
|
+
- root: the root of the chord (or an empty string if not present). The root is present if the bass not belongs to the chord. It could be chords with bass without root field, but not the opposite.
|
|
31
|
+
- rootDegree: the degree of the root. NaN if root not present. A number greater than 0 if present, where 1 indicates the tonic, 2 the second note (normally the 3th), 2 the third note (normally the 5th), etc.
|
|
32
|
+
- notes: an array of notes, or empty array if tonic is not present. The notes will be always pitch classes.
|
|
30
33
|
|
|
31
34
|
Example:
|
|
32
35
|
|
|
33
36
|
```js
|
|
34
|
-
Chord.
|
|
37
|
+
Chord.get("Cmaj7/B"); // =>
|
|
35
38
|
// {
|
|
36
39
|
// empty: false,
|
|
37
|
-
// name:
|
|
38
|
-
// symbol: "Gmaj7/B",
|
|
39
|
-
// tonic: "G4",
|
|
40
|
-
// root: "B4",
|
|
41
|
-
// rootDegree: 2,
|
|
40
|
+
// name: 'C major seventh over B',
|
|
42
41
|
// setNum: 2193,
|
|
43
|
-
//
|
|
44
|
-
//
|
|
45
|
-
//
|
|
46
|
-
//
|
|
47
|
-
//
|
|
48
|
-
//
|
|
49
|
-
//
|
|
42
|
+
// chroma: '100010010001',
|
|
43
|
+
// normalized: '100010010001',
|
|
44
|
+
// intervals: [ '7M', '8P', '10M', '12P' ],
|
|
45
|
+
// quality: 'Major',
|
|
46
|
+
// aliases: [ 'maj7', 'Δ', 'ma7', 'M7', 'Maj7', '^7' ],
|
|
47
|
+
// symbol: 'Cmaj7/B',
|
|
48
|
+
// tonic: 'C',
|
|
49
|
+
// type: 'major seventh',
|
|
50
|
+
// root: 'B',
|
|
51
|
+
// bass: 'B',
|
|
52
|
+
// rootDegree: 4,
|
|
53
|
+
// notes: [ 'B', 'C', 'E', 'G' ]
|
|
50
54
|
// }
|
|
51
55
|
```
|
|
52
56
|
|
|
53
|
-
|
|
57
|
+
`Chord.chord` is an alias that is handy if using the `@tonaljs/chord` directly:
|
|
58
|
+
|
|
59
|
+
```js
|
|
60
|
+
import { chord } from "@tonaljs/chord";
|
|
61
|
+
|
|
62
|
+
chord("C6add2");
|
|
63
|
+
```
|
|
54
64
|
|
|
55
|
-
|
|
65
|
+
`Chord.getChord(chordType, tonic, bass)` is very similar but with arguments for each chord part:
|
|
56
66
|
|
|
57
67
|
```js
|
|
58
|
-
Chord.get("Cmaj7");
|
|
59
|
-
// same as
|
|
60
|
-
Chord.get(["C", "maj7"]);
|
|
61
|
-
// same as
|
|
62
|
-
Chord.getChord("maj7", "C");
|
|
68
|
+
Chord.getChord("maj7", "C", "B") === Chord.get("Cmaj7/B");
|
|
63
69
|
```
|
|
64
70
|
|
|
65
|
-
|
|
71
|
+
### `Chord.notes(chordType: string, tonic?: string) => string[]`
|
|
72
|
+
|
|
73
|
+
Print the notes of the given chord at the given tonic:
|
|
66
74
|
|
|
67
75
|
```js
|
|
68
|
-
Chord.
|
|
76
|
+
Chord.notes("maj4", "C4"); // => ["C4", "E4", "G4", "B4"]
|
|
69
77
|
```
|
|
70
78
|
|
|
71
|
-
### `Chord.degrees(
|
|
79
|
+
### `Chord.degrees(chordType: string, tonic?: string) => (degree: number) => string`
|
|
72
80
|
|
|
73
81
|
`Scale.degrees` returns a function to get a note name from a scale degree:
|
|
74
82
|
|
|
75
83
|
```js
|
|
76
|
-
const c4m7 = Chord.degrees(
|
|
84
|
+
const c4m7 = Chord.degrees("m7", "C4");
|
|
77
85
|
c4m7(1); // => "C4"
|
|
78
86
|
c4m7(2); // => "Eb4"
|
|
79
87
|
c4m7(3); // => "G4"
|
|
@@ -81,13 +89,13 @@ c4m7(4); // => "Bb4"
|
|
|
81
89
|
c4m7(1); // => "C5"
|
|
82
90
|
```
|
|
83
91
|
|
|
84
|
-
It can be used to
|
|
92
|
+
It can be used, for example, to get the notes of chord inversions:
|
|
85
93
|
|
|
86
94
|
```js
|
|
87
|
-
[1, 2, 3, 4].map(
|
|
88
|
-
[2, 3, 4, 5].map(
|
|
89
|
-
[3, 4, 5, 6].map(
|
|
90
|
-
[4, 5, 6, 7].map(
|
|
95
|
+
[1, 2, 3, 4].map(c4m7); // => ["C4", "Eb4", "G4", "Bb4"]
|
|
96
|
+
[2, 3, 4, 5].map(c4m7); // => ["Eb4", "G4", "Bb4", "C5"]
|
|
97
|
+
[3, 4, 5, 6].map(c4m7); // => ["G4", "Bb4", "C5", "Eb5"]
|
|
98
|
+
[4, 5, 6, 7].map(c4m7); // => ["Bb4", "C5", "Eb5", "G5"]
|
|
91
99
|
```
|
|
92
100
|
|
|
93
101
|
Bear in mind that degree numbers starts with 1 and 0 returns an empty string:
|
package/dist/index.d.mts
CHANGED
|
@@ -1,28 +1,32 @@
|
|
|
1
1
|
import { detect } from '@tonaljs/chord-detect';
|
|
2
2
|
export { detect } from '@tonaljs/chord-detect';
|
|
3
3
|
import { ChordType } from '@tonaljs/chord-type';
|
|
4
|
-
import { NoteName } from '@tonaljs/
|
|
4
|
+
import { NoteName } from '@tonaljs/pitch-note';
|
|
5
5
|
|
|
6
|
-
type
|
|
7
|
-
type ChordNameTokens = [string, string];
|
|
6
|
+
type ChordNameOrTokens = string | [string] | [string, string] | [string, string, string];
|
|
7
|
+
type ChordNameTokens = [string, string, string];
|
|
8
8
|
interface Chord extends ChordType {
|
|
9
9
|
tonic: string | null;
|
|
10
10
|
type: string;
|
|
11
11
|
root: string;
|
|
12
|
+
bass: string;
|
|
12
13
|
rootDegree: number;
|
|
13
14
|
symbol: string;
|
|
14
15
|
notes: NoteName[];
|
|
15
16
|
}
|
|
16
17
|
/**
|
|
17
|
-
* Tokenize a chord name. It returns an array with the tonic
|
|
18
|
+
* Tokenize a chord name. It returns an array with the tonic, chord type and bass
|
|
18
19
|
* If not tonic is found, all the name is considered the chord name.
|
|
19
20
|
*
|
|
20
21
|
* This function does NOT check if the chord type exists or not. It only tries
|
|
21
22
|
* to split the tonic and chord type.
|
|
22
23
|
*
|
|
24
|
+
* This function does NOT check if the bass is part of the chord or not but it
|
|
25
|
+
* only accepts a pitch class as bass
|
|
26
|
+
*
|
|
23
27
|
* @function
|
|
24
28
|
* @param {string} name - the chord name
|
|
25
|
-
* @return {Array} an array with [tonic, type]
|
|
29
|
+
* @return {Array} an array with [tonic, type, bass]
|
|
26
30
|
* @example
|
|
27
31
|
* tokenize("Cmaj7") // => [ "C", "maj7" ]
|
|
28
32
|
* tokenize("C7") // => [ "C", "7" ]
|
|
@@ -33,7 +37,7 @@ declare function tokenize(name: string): ChordNameTokens;
|
|
|
33
37
|
/**
|
|
34
38
|
* Get a Chord from a chord name.
|
|
35
39
|
*/
|
|
36
|
-
declare function get(src:
|
|
40
|
+
declare function get(src: ChordNameOrTokens): Chord;
|
|
37
41
|
/**
|
|
38
42
|
* Get chord properties
|
|
39
43
|
*
|
|
@@ -41,8 +45,8 @@ declare function get(src: ChordName | ChordNameTokens): Chord;
|
|
|
41
45
|
* @param [tonic] - Optional tonic
|
|
42
46
|
* @param [root] - Optional root (requires a tonic)
|
|
43
47
|
*/
|
|
44
|
-
declare function getChord(typeName: string, optionalTonic?: string,
|
|
45
|
-
declare const chord:
|
|
48
|
+
declare function getChord(typeName: string, optionalTonic?: string, optionalBass?: string): Chord;
|
|
49
|
+
declare const chord: typeof get;
|
|
46
50
|
/**
|
|
47
51
|
* Transpose a chord name
|
|
48
52
|
*
|
|
@@ -78,6 +82,10 @@ declare function extended(chordName: string): string[];
|
|
|
78
82
|
* @example
|
|
79
83
|
*/
|
|
80
84
|
declare function reduced(chordName: string): string[];
|
|
85
|
+
/**
|
|
86
|
+
* Return the chord notes
|
|
87
|
+
*/
|
|
88
|
+
declare function notes(chordName: ChordNameOrTokens, tonic?: string): string[];
|
|
81
89
|
/**
|
|
82
90
|
* Returns a function to get a note name from the scale degree.
|
|
83
91
|
*
|
|
@@ -85,11 +93,11 @@ declare function reduced(chordName: string): string[];
|
|
|
85
93
|
* [1, 2, 3, 4].map(Chord.degrees("C")) => ["C", "E", "G", "C"]
|
|
86
94
|
* [1, 2, 3, 4].map(Chord.degrees("C4")) => ["C4", "E4", "G4", "C5"]
|
|
87
95
|
*/
|
|
88
|
-
declare function degrees(chordName:
|
|
96
|
+
declare function degrees(chordName: ChordNameOrTokens, tonic?: string): (degree: number) => string;
|
|
89
97
|
/**
|
|
90
98
|
* Sames as `degree` but with 0-based index
|
|
91
99
|
*/
|
|
92
|
-
declare function steps(chordName:
|
|
100
|
+
declare function steps(chordName: ChordNameOrTokens, tonic?: string): (normalized: number) => string;
|
|
93
101
|
declare const _default: {
|
|
94
102
|
getChord: typeof getChord;
|
|
95
103
|
get: typeof get;
|
|
@@ -101,7 +109,8 @@ declare const _default: {
|
|
|
101
109
|
transpose: typeof transpose;
|
|
102
110
|
degrees: typeof degrees;
|
|
103
111
|
steps: typeof steps;
|
|
104
|
-
|
|
112
|
+
notes: typeof notes;
|
|
113
|
+
chord: typeof get;
|
|
105
114
|
};
|
|
106
115
|
|
|
107
|
-
export { type Chord, chord, chordScales, _default as default, degrees, extended, get, getChord, reduced, steps, tokenize, transpose };
|
|
116
|
+
export { type Chord, chord, chordScales, _default as default, degrees, extended, get, getChord, notes, reduced, steps, tokenize, transpose };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,28 +1,32 @@
|
|
|
1
1
|
import { detect } from '@tonaljs/chord-detect';
|
|
2
2
|
export { detect } from '@tonaljs/chord-detect';
|
|
3
3
|
import { ChordType } from '@tonaljs/chord-type';
|
|
4
|
-
import { NoteName } from '@tonaljs/
|
|
4
|
+
import { NoteName } from '@tonaljs/pitch-note';
|
|
5
5
|
|
|
6
|
-
type
|
|
7
|
-
type ChordNameTokens = [string, string];
|
|
6
|
+
type ChordNameOrTokens = string | [string] | [string, string] | [string, string, string];
|
|
7
|
+
type ChordNameTokens = [string, string, string];
|
|
8
8
|
interface Chord extends ChordType {
|
|
9
9
|
tonic: string | null;
|
|
10
10
|
type: string;
|
|
11
11
|
root: string;
|
|
12
|
+
bass: string;
|
|
12
13
|
rootDegree: number;
|
|
13
14
|
symbol: string;
|
|
14
15
|
notes: NoteName[];
|
|
15
16
|
}
|
|
16
17
|
/**
|
|
17
|
-
* Tokenize a chord name. It returns an array with the tonic
|
|
18
|
+
* Tokenize a chord name. It returns an array with the tonic, chord type and bass
|
|
18
19
|
* If not tonic is found, all the name is considered the chord name.
|
|
19
20
|
*
|
|
20
21
|
* This function does NOT check if the chord type exists or not. It only tries
|
|
21
22
|
* to split the tonic and chord type.
|
|
22
23
|
*
|
|
24
|
+
* This function does NOT check if the bass is part of the chord or not but it
|
|
25
|
+
* only accepts a pitch class as bass
|
|
26
|
+
*
|
|
23
27
|
* @function
|
|
24
28
|
* @param {string} name - the chord name
|
|
25
|
-
* @return {Array} an array with [tonic, type]
|
|
29
|
+
* @return {Array} an array with [tonic, type, bass]
|
|
26
30
|
* @example
|
|
27
31
|
* tokenize("Cmaj7") // => [ "C", "maj7" ]
|
|
28
32
|
* tokenize("C7") // => [ "C", "7" ]
|
|
@@ -33,7 +37,7 @@ declare function tokenize(name: string): ChordNameTokens;
|
|
|
33
37
|
/**
|
|
34
38
|
* Get a Chord from a chord name.
|
|
35
39
|
*/
|
|
36
|
-
declare function get(src:
|
|
40
|
+
declare function get(src: ChordNameOrTokens): Chord;
|
|
37
41
|
/**
|
|
38
42
|
* Get chord properties
|
|
39
43
|
*
|
|
@@ -41,8 +45,8 @@ declare function get(src: ChordName | ChordNameTokens): Chord;
|
|
|
41
45
|
* @param [tonic] - Optional tonic
|
|
42
46
|
* @param [root] - Optional root (requires a tonic)
|
|
43
47
|
*/
|
|
44
|
-
declare function getChord(typeName: string, optionalTonic?: string,
|
|
45
|
-
declare const chord:
|
|
48
|
+
declare function getChord(typeName: string, optionalTonic?: string, optionalBass?: string): Chord;
|
|
49
|
+
declare const chord: typeof get;
|
|
46
50
|
/**
|
|
47
51
|
* Transpose a chord name
|
|
48
52
|
*
|
|
@@ -78,6 +82,10 @@ declare function extended(chordName: string): string[];
|
|
|
78
82
|
* @example
|
|
79
83
|
*/
|
|
80
84
|
declare function reduced(chordName: string): string[];
|
|
85
|
+
/**
|
|
86
|
+
* Return the chord notes
|
|
87
|
+
*/
|
|
88
|
+
declare function notes(chordName: ChordNameOrTokens, tonic?: string): string[];
|
|
81
89
|
/**
|
|
82
90
|
* Returns a function to get a note name from the scale degree.
|
|
83
91
|
*
|
|
@@ -85,11 +93,11 @@ declare function reduced(chordName: string): string[];
|
|
|
85
93
|
* [1, 2, 3, 4].map(Chord.degrees("C")) => ["C", "E", "G", "C"]
|
|
86
94
|
* [1, 2, 3, 4].map(Chord.degrees("C4")) => ["C4", "E4", "G4", "C5"]
|
|
87
95
|
*/
|
|
88
|
-
declare function degrees(chordName:
|
|
96
|
+
declare function degrees(chordName: ChordNameOrTokens, tonic?: string): (degree: number) => string;
|
|
89
97
|
/**
|
|
90
98
|
* Sames as `degree` but with 0-based index
|
|
91
99
|
*/
|
|
92
|
-
declare function steps(chordName:
|
|
100
|
+
declare function steps(chordName: ChordNameOrTokens, tonic?: string): (normalized: number) => string;
|
|
93
101
|
declare const _default: {
|
|
94
102
|
getChord: typeof getChord;
|
|
95
103
|
get: typeof get;
|
|
@@ -101,7 +109,8 @@ declare const _default: {
|
|
|
101
109
|
transpose: typeof transpose;
|
|
102
110
|
degrees: typeof degrees;
|
|
103
111
|
steps: typeof steps;
|
|
104
|
-
|
|
112
|
+
notes: typeof notes;
|
|
113
|
+
chord: typeof get;
|
|
105
114
|
};
|
|
106
115
|
|
|
107
|
-
export { type Chord, chord, chordScales, _default as default, degrees, extended, get, getChord, reduced, steps, tokenize, transpose };
|
|
116
|
+
export { type Chord, chord, chordScales, _default as default, degrees, extended, get, getChord, notes, reduced, steps, tokenize, transpose };
|
package/dist/index.js
CHANGED
|
@@ -28,6 +28,7 @@ __export(chord_exports, {
|
|
|
28
28
|
extended: () => extended,
|
|
29
29
|
get: () => get,
|
|
30
30
|
getChord: () => getChord,
|
|
31
|
+
notes: () => notes,
|
|
31
32
|
reduced: () => reduced,
|
|
32
33
|
steps: () => steps,
|
|
33
34
|
tokenize: () => tokenize,
|
|
@@ -36,9 +37,10 @@ __export(chord_exports, {
|
|
|
36
37
|
module.exports = __toCommonJS(chord_exports);
|
|
37
38
|
var import_chord_detect = require("@tonaljs/chord-detect");
|
|
38
39
|
var import_chord_type = require("@tonaljs/chord-type");
|
|
39
|
-
var
|
|
40
|
-
var import_core2 = require("@tonaljs/core");
|
|
40
|
+
var import_interval = require("@tonaljs/interval");
|
|
41
41
|
var import_pcset = require("@tonaljs/pcset");
|
|
42
|
+
var import_pitch_distance = require("@tonaljs/pitch-distance");
|
|
43
|
+
var import_pitch_note = require("@tonaljs/pitch-note");
|
|
42
44
|
var import_scale_type = require("@tonaljs/scale-type");
|
|
43
45
|
var import_chord_detect2 = require("@tonaljs/chord-detect");
|
|
44
46
|
var NoChord = {
|
|
@@ -46,6 +48,7 @@ var NoChord = {
|
|
|
46
48
|
name: "",
|
|
47
49
|
symbol: "",
|
|
48
50
|
root: "",
|
|
51
|
+
bass: "",
|
|
49
52
|
rootDegree: 0,
|
|
50
53
|
type: "",
|
|
51
54
|
tonic: null,
|
|
@@ -58,70 +61,91 @@ var NoChord = {
|
|
|
58
61
|
intervals: []
|
|
59
62
|
};
|
|
60
63
|
function tokenize(name) {
|
|
61
|
-
const [letter, acc, oct, type] = (0,
|
|
64
|
+
const [letter, acc, oct, type] = (0, import_pitch_note.tokenizeNote)(name);
|
|
62
65
|
if (letter === "") {
|
|
63
|
-
return
|
|
66
|
+
return tokenizeBass("", name);
|
|
67
|
+
} else if (letter === "A" && type === "ug") {
|
|
68
|
+
return tokenizeBass("", "aug");
|
|
69
|
+
} else {
|
|
70
|
+
return tokenizeBass(letter + acc, oct + type);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
function tokenizeBass(note2, chord2) {
|
|
74
|
+
const split = chord2.split("/");
|
|
75
|
+
if (split.length === 1) {
|
|
76
|
+
return [note2, split[0], ""];
|
|
64
77
|
}
|
|
65
|
-
|
|
66
|
-
|
|
78
|
+
const [letter, acc, oct, type] = (0, import_pitch_note.tokenizeNote)(split[1]);
|
|
79
|
+
if (letter !== "" && oct === "" && type === "") {
|
|
80
|
+
return [note2, split[0], letter + acc];
|
|
81
|
+
} else {
|
|
82
|
+
return [note2, chord2, ""];
|
|
67
83
|
}
|
|
68
|
-
return [letter + acc, oct + type];
|
|
69
84
|
}
|
|
70
85
|
function get(src) {
|
|
71
|
-
if (src
|
|
86
|
+
if (Array.isArray(src)) {
|
|
87
|
+
return getChord(src[1] || "", src[0], src[2]);
|
|
88
|
+
} else if (src === "") {
|
|
72
89
|
return NoChord;
|
|
73
|
-
}
|
|
74
|
-
if (Array.isArray(src) && src.length === 2) {
|
|
75
|
-
return getChord(src[1], src[0]);
|
|
76
90
|
} else {
|
|
77
|
-
const [tonic, type] = tokenize(src);
|
|
78
|
-
const chord2 = getChord(type, tonic);
|
|
91
|
+
const [tonic, type, bass] = tokenize(src);
|
|
92
|
+
const chord2 = getChord(type, tonic, bass);
|
|
79
93
|
return chord2.empty ? getChord(src) : chord2;
|
|
80
94
|
}
|
|
81
95
|
}
|
|
82
|
-
function getChord(typeName, optionalTonic,
|
|
96
|
+
function getChord(typeName, optionalTonic, optionalBass) {
|
|
83
97
|
const type = (0, import_chord_type.get)(typeName);
|
|
84
|
-
const tonic = (0,
|
|
85
|
-
const
|
|
86
|
-
if (type.empty || optionalTonic && tonic.empty ||
|
|
87
|
-
return NoChord;
|
|
88
|
-
}
|
|
89
|
-
const rootInterval = (0, import_core2.distance)(tonic.pc, root.pc);
|
|
90
|
-
const rootDegree = type.intervals.indexOf(rootInterval) + 1;
|
|
91
|
-
if (!root.empty && !rootDegree) {
|
|
98
|
+
const tonic = (0, import_pitch_note.note)(optionalTonic || "");
|
|
99
|
+
const bass = (0, import_pitch_note.note)(optionalBass || "");
|
|
100
|
+
if (type.empty || optionalTonic && tonic.empty || optionalBass && bass.empty) {
|
|
92
101
|
return NoChord;
|
|
93
102
|
}
|
|
103
|
+
const bassInterval = (0, import_pitch_distance.distance)(tonic.pc, bass.pc);
|
|
104
|
+
const bassIndex = type.intervals.indexOf(bassInterval);
|
|
105
|
+
const hasRoot = bassIndex >= 0;
|
|
106
|
+
const root = hasRoot ? bass : (0, import_pitch_note.note)("");
|
|
107
|
+
const rootDegree = bassIndex === -1 ? NaN : bassIndex + 1;
|
|
108
|
+
const hasBass = bass.pc && bass.pc !== tonic.pc;
|
|
94
109
|
const intervals = Array.from(type.intervals);
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
110
|
+
if (hasRoot) {
|
|
111
|
+
for (let i = 1; i < rootDegree; i++) {
|
|
112
|
+
const num = intervals[0][0];
|
|
113
|
+
const quality = intervals[0][1];
|
|
114
|
+
const newNum = parseInt(num, 10) + 7;
|
|
115
|
+
intervals.push(`${newNum}${quality}`);
|
|
116
|
+
intervals.shift();
|
|
117
|
+
}
|
|
118
|
+
} else if (hasBass) {
|
|
119
|
+
const ivl = (0, import_interval.subtract)((0, import_pitch_distance.distance)(tonic.pc, bass.pc), "8P");
|
|
120
|
+
if (ivl)
|
|
121
|
+
intervals.unshift(ivl);
|
|
101
122
|
}
|
|
102
|
-
const
|
|
123
|
+
const notes2 = tonic.empty ? [] : intervals.map((i) => (0, import_pitch_distance.transpose)(tonic.pc, i));
|
|
103
124
|
typeName = type.aliases.indexOf(typeName) !== -1 ? typeName : type.aliases[0];
|
|
104
|
-
const symbol = `${tonic.empty ? "" : tonic.pc}${typeName}${
|
|
105
|
-
const name = `${optionalTonic ? tonic.pc + " " : ""}${type.name}${rootDegree > 1
|
|
125
|
+
const symbol = `${tonic.empty ? "" : tonic.pc}${typeName}${hasRoot && rootDegree > 1 ? "/" + root.pc : hasBass ? "/" + bass.pc : ""}`;
|
|
126
|
+
const name = `${optionalTonic ? tonic.pc + " " : ""}${type.name}${hasRoot && rootDegree > 1 ? " over " + root.pc : hasBass ? " over " + bass.pc : ""}`;
|
|
106
127
|
return {
|
|
107
128
|
...type,
|
|
108
129
|
name,
|
|
109
130
|
symbol,
|
|
131
|
+
tonic: tonic.pc,
|
|
110
132
|
type: type.name,
|
|
111
|
-
root: root.
|
|
133
|
+
root: root.pc,
|
|
134
|
+
bass: hasBass ? bass.pc : "",
|
|
112
135
|
intervals,
|
|
113
136
|
rootDegree,
|
|
114
|
-
|
|
115
|
-
notes
|
|
137
|
+
notes: notes2
|
|
116
138
|
};
|
|
117
139
|
}
|
|
118
|
-
var chord =
|
|
140
|
+
var chord = get;
|
|
119
141
|
function transpose(chordName, interval) {
|
|
120
|
-
const [tonic, type] = tokenize(chordName);
|
|
142
|
+
const [tonic, type, bass] = tokenize(chordName);
|
|
121
143
|
if (!tonic) {
|
|
122
144
|
return chordName;
|
|
123
145
|
}
|
|
124
|
-
|
|
146
|
+
const tr = (0, import_pitch_distance.transpose)(bass, interval);
|
|
147
|
+
const slash = tr ? "/" + tr : "";
|
|
148
|
+
return (0, import_pitch_distance.transpose)(tonic, interval) + type + slash;
|
|
125
149
|
}
|
|
126
150
|
function chordScales(name) {
|
|
127
151
|
const s = get(name);
|
|
@@ -138,14 +162,23 @@ function reduced(chordName) {
|
|
|
138
162
|
const isSubset = (0, import_pcset.isSubsetOf)(s.chroma);
|
|
139
163
|
return (0, import_chord_type.all)().filter((chord2) => isSubset(chord2.chroma)).map((chord2) => s.tonic + chord2.aliases[0]);
|
|
140
164
|
}
|
|
141
|
-
function
|
|
142
|
-
const
|
|
143
|
-
const
|
|
165
|
+
function notes(chordName, tonic) {
|
|
166
|
+
const chord2 = get(chordName);
|
|
167
|
+
const note2 = tonic || chord2.tonic;
|
|
168
|
+
if (!note2 || chord2.empty)
|
|
169
|
+
return [];
|
|
170
|
+
return chord2.intervals.map((ivl) => (0, import_pitch_distance.transpose)(note2, ivl));
|
|
171
|
+
}
|
|
172
|
+
function degrees(chordName, tonic) {
|
|
173
|
+
const chord2 = get(chordName);
|
|
174
|
+
const note2 = tonic || chord2.tonic;
|
|
175
|
+
const transpose2 = (0, import_pitch_distance.tonicIntervalsTransposer)(chord2.intervals, note2);
|
|
144
176
|
return (degree) => degree ? transpose2(degree > 0 ? degree - 1 : degree) : "";
|
|
145
177
|
}
|
|
146
|
-
function steps(chordName) {
|
|
147
|
-
const
|
|
148
|
-
|
|
178
|
+
function steps(chordName, tonic) {
|
|
179
|
+
const chord2 = get(chordName);
|
|
180
|
+
const note2 = tonic || chord2.tonic;
|
|
181
|
+
return (0, import_pitch_distance.tonicIntervalsTransposer)(chord2.intervals, note2);
|
|
149
182
|
}
|
|
150
183
|
var chord_default = {
|
|
151
184
|
getChord,
|
|
@@ -158,7 +191,7 @@ var chord_default = {
|
|
|
158
191
|
transpose,
|
|
159
192
|
degrees,
|
|
160
193
|
steps,
|
|
161
|
-
|
|
194
|
+
notes,
|
|
162
195
|
chord
|
|
163
196
|
};
|
|
164
197
|
// Annotate the CommonJS export names for ESM import in node:
|
|
@@ -170,6 +203,7 @@ var chord_default = {
|
|
|
170
203
|
extended,
|
|
171
204
|
get,
|
|
172
205
|
getChord,
|
|
206
|
+
notes,
|
|
173
207
|
reduced,
|
|
174
208
|
steps,
|
|
175
209
|
tokenize,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../index.ts"],"sourcesContent":["import { detect } from \"@tonaljs/chord-detect\";\nimport {\n ChordType,\n all as chordTypes,\n get as getChordType,\n} from \"@tonaljs/chord-type\";\nimport { tonicIntervalsTransposer } from \"@tonaljs/core\";\n\nimport {\n deprecate,\n distance,\n note,\n NoteName,\n tokenizeNote,\n transpose as transposeNote,\n} from \"@tonaljs/core\";\n\nimport { isSubsetOf, isSupersetOf } from \"@tonaljs/pcset\";\n\nimport { all as scaleTypes } from \"@tonaljs/scale-type\";\nexport { detect } from \"@tonaljs/chord-detect\";\n\ntype ChordName = string;\ntype ChordNameTokens = [string, string]; // [TONIC, SCALE TYPE]\n\nexport interface Chord extends ChordType {\n tonic: string | null;\n type: string;\n root: string;\n rootDegree: number;\n symbol: string;\n notes: NoteName[];\n}\n\nconst NoChord: Chord = {\n empty: true,\n name: \"\",\n symbol: \"\",\n root: \"\",\n rootDegree: 0,\n type: \"\",\n tonic: null,\n setNum: NaN,\n quality: \"Unknown\",\n chroma: \"\",\n normalized: \"\",\n aliases: [],\n notes: [],\n intervals: [],\n};\n\n// 6, 64, 7, 9, 11 and 13 are consider part of the chord\n// (see https://github.com/danigb/tonal/issues/55)\n//const NUM_TYPES = /^(6|64|7|9|11|13)$/;\n/**\n * Tokenize a chord name. It returns an array with the tonic and chord type\n * If not tonic is found, all the name is considered the chord name.\n *\n * This function does NOT check if the chord type exists or not. It only tries\n * to split the tonic and chord type.\n *\n * @function\n * @param {string} name - the chord name\n * @return {Array} an array with [tonic, type]\n * @example\n * tokenize(\"Cmaj7\") // => [ \"C\", \"maj7\" ]\n * tokenize(\"C7\") // => [ \"C\", \"7\" ]\n * tokenize(\"mMaj7\") // => [ null, \"mMaj7\" ]\n * tokenize(\"Cnonsense\") // => [ null, \"nonsense\" ]\n */\nexport function tokenize(name: string): ChordNameTokens {\n const [letter, acc, oct, type] = tokenizeNote(name);\n if (letter === \"\") {\n return [\"\", name];\n }\n // aug is augmented (see https://github.com/danigb/tonal/issues/55)\n if (letter === \"A\" && type === \"ug\") {\n return [\"\", \"aug\"];\n }\n return [letter + acc, oct + type];\n}\n\n/**\n * Get a Chord from a chord name.\n */\nexport function get(src: ChordName | ChordNameTokens): Chord {\n if (src === \"\") {\n return NoChord;\n }\n if (Array.isArray(src) && src.length === 2) {\n return getChord(src[1], src[0]);\n } else {\n const [tonic, type] = tokenize(src);\n const chord = getChord(type, tonic);\n return chord.empty ? getChord(src) : chord;\n }\n}\n\n/**\n * Get chord properties\n *\n * @param typeName - the chord type name\n * @param [tonic] - Optional tonic\n * @param [root] - Optional root (requires a tonic)\n */\nexport function getChord(\n typeName: string,\n optionalTonic?: string,\n optionalRoot?: string,\n): Chord {\n const type = getChordType(typeName);\n const tonic = note(optionalTonic || \"\");\n const root = note(optionalRoot || \"\");\n\n if (\n type.empty ||\n (optionalTonic && tonic.empty) ||\n (optionalRoot && root.empty)\n ) {\n return NoChord;\n }\n\n const rootInterval = distance(tonic.pc, root.pc);\n const rootDegree = type.intervals.indexOf(rootInterval) + 1;\n if (!root.empty && !rootDegree) {\n return NoChord;\n }\n\n const intervals = Array.from(type.intervals);\n\n for (let i = 1; i < rootDegree; i++) {\n const num = intervals[0][0];\n const quality = intervals[0][1];\n const newNum = parseInt(num, 10) + 7;\n intervals.push(`${newNum}${quality}`);\n intervals.shift();\n }\n\n const notes = tonic.empty\n ? []\n : intervals.map((i) => transposeNote(tonic, i));\n\n typeName = type.aliases.indexOf(typeName) !== -1 ? typeName : type.aliases[0];\n const symbol = `${tonic.empty ? \"\" : tonic.pc}${typeName}${\n root.empty || rootDegree <= 1 ? \"\" : \"/\" + root.pc\n }`;\n const name = `${optionalTonic ? tonic.pc + \" \" : \"\"}${type.name}${\n rootDegree > 1 && optionalRoot ? \" over \" + root.pc : \"\"\n }`;\n return {\n ...type,\n name,\n symbol,\n type: type.name,\n root: root.name,\n intervals,\n rootDegree,\n tonic: tonic.name,\n notes,\n };\n}\n\nexport const chord = deprecate(\"Chord.chord\", \"Chord.get\", get);\n\n/**\n * Transpose a chord name\n *\n * @param {string} chordName - the chord name\n * @return {string} the transposed chord\n *\n * @example\n * transpose('Dm7', 'P4') // => 'Gm7\n */\nexport function transpose(chordName: string, interval: string): string {\n const [tonic, type] = tokenize(chordName);\n if (!tonic) {\n return chordName;\n }\n return transposeNote(tonic, interval) + type;\n}\n\n/**\n * Get all scales where the given chord fits\n *\n * @example\n * chordScales('C7b9')\n * // => [\"phrygian dominant\", \"flamenco\", \"spanish heptatonic\", \"half-whole diminished\", \"chromatic\"]\n */\nexport function chordScales(name: string): string[] {\n const s = get(name);\n const isChordIncluded = isSupersetOf(s.chroma);\n return scaleTypes()\n .filter((scale) => isChordIncluded(scale.chroma))\n .map((scale) => scale.name);\n}\n/**\n * Get all chords names that are a superset of the given one\n * (has the same notes and at least one more)\n *\n * @function\n * @example\n * extended(\"CMaj7\")\n * // => [ 'Cmaj#4', 'Cmaj7#9#11', 'Cmaj9', 'CM7add13', 'Cmaj13', 'Cmaj9#11', 'CM13#11', 'CM7b9' ]\n */\nexport function extended(chordName: string): string[] {\n const s = get(chordName);\n const isSuperset = isSupersetOf(s.chroma);\n return chordTypes()\n .filter((chord) => isSuperset(chord.chroma))\n .map((chord) => s.tonic + chord.aliases[0]);\n}\n\n/**\n * Find all chords names that are a subset of the given one\n * (has less notes but all from the given chord)\n *\n * @example\n */\nexport function reduced(chordName: string): string[] {\n const s = get(chordName);\n const isSubset = isSubsetOf(s.chroma);\n return chordTypes()\n .filter((chord) => isSubset(chord.chroma))\n .map((chord) => s.tonic + chord.aliases[0]);\n}\n\n/**\n * Returns a function to get a note name from the scale degree.\n *\n * @example\n * [1, 2, 3, 4].map(Chord.degrees(\"C\")) => [\"C\", \"E\", \"G\", \"C\"]\n * [1, 2, 3, 4].map(Chord.degrees(\"C4\")) => [\"C4\", \"E4\", \"G4\", \"C5\"]\n */\nexport function degrees(chordName: string | ChordNameTokens) {\n const { intervals, tonic } = get(chordName);\n const transpose = tonicIntervalsTransposer(intervals, tonic);\n return (degree: number) =>\n degree ? transpose(degree > 0 ? degree - 1 : degree) : \"\";\n}\n\n/**\n * Sames as `degree` but with 0-based index\n */\nexport function steps(chordName: string | ChordNameTokens) {\n const { intervals, tonic } = get(chordName);\n return tonicIntervalsTransposer(intervals, tonic);\n}\n\nexport default {\n getChord,\n get,\n detect,\n chordScales,\n extended,\n reduced,\n tokenize,\n transpose,\n degrees,\n steps,\n\n // deprecate\n chord,\n};\n"],"mappings":"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","names":["import_core","import_chord_detect","chord","getChordType","transposeNote","scaleTypes","chordTypes","transpose"]}
|
|
1
|
+
{"version":3,"sources":["../index.ts"],"sourcesContent":["import { detect } from \"@tonaljs/chord-detect\";\nimport {\n ChordType,\n all as chordTypes,\n get as getChordType,\n} from \"@tonaljs/chord-type\";\nimport { subtract } from \"@tonaljs/interval\";\nimport { isSubsetOf, isSupersetOf } from \"@tonaljs/pcset\";\nimport {\n distance,\n tonicIntervalsTransposer,\n transpose as transposeNote,\n} from \"@tonaljs/pitch-distance\";\nimport { NoteName, note, tokenizeNote } from \"@tonaljs/pitch-note\";\nimport { all as scaleTypes } from \"@tonaljs/scale-type\";\n\nexport { detect } from \"@tonaljs/chord-detect\";\n\ntype ChordNameOrTokens =\n | string // full name to be parsed\n | [string] // only the name\n | [string, string] // tonic, name\n | [string, string, string]; // tonic, name, bass\ntype ChordNameTokens = [string, string, string]; // [TONIC, SCALE TYPE, BASS]\n\nexport interface Chord extends ChordType {\n tonic: string | null;\n type: string;\n root: string;\n bass: string;\n rootDegree: number;\n symbol: string;\n notes: NoteName[];\n}\n\nconst NoChord: Chord = {\n empty: true,\n name: \"\",\n symbol: \"\",\n root: \"\",\n bass: \"\",\n rootDegree: 0,\n type: \"\",\n tonic: null,\n setNum: NaN,\n quality: \"Unknown\",\n chroma: \"\",\n normalized: \"\",\n aliases: [],\n notes: [],\n intervals: [],\n};\n\n// 6, 64, 7, 9, 11 and 13 are consider part of the chord\n// (see https://github.com/danigb/tonal/issues/55)\n//const NUM_TYPES = /^(6|64|7|9|11|13)$/;\n/**\n * Tokenize a chord name. It returns an array with the tonic, chord type and bass\n * If not tonic is found, all the name is considered the chord name.\n *\n * This function does NOT check if the chord type exists or not. It only tries\n * to split the tonic and chord type.\n *\n * This function does NOT check if the bass is part of the chord or not but it\n * only accepts a pitch class as bass\n *\n * @function\n * @param {string} name - the chord name\n * @return {Array} an array with [tonic, type, bass]\n * @example\n * tokenize(\"Cmaj7\") // => [ \"C\", \"maj7\" ]\n * tokenize(\"C7\") // => [ \"C\", \"7\" ]\n * tokenize(\"mMaj7\") // => [ null, \"mMaj7\" ]\n * tokenize(\"Cnonsense\") // => [ null, \"nonsense\" ]\n */\nexport function tokenize(name: string): ChordNameTokens {\n const [letter, acc, oct, type] = tokenizeNote(name);\n if (letter === \"\") {\n return tokenizeBass(\"\", name);\n } else if (letter === \"A\" && type === \"ug\") {\n return tokenizeBass(\"\", \"aug\");\n } else {\n return tokenizeBass(letter + acc, oct + type);\n }\n}\n\nfunction tokenizeBass(note: string, chord: string): ChordNameTokens {\n const split = chord.split(\"/\");\n if (split.length === 1) {\n return [note, split[0], \"\"];\n }\n const [letter, acc, oct, type] = tokenizeNote(split[1]);\n // Only a pitch class is accepted as bass note\n if (letter !== \"\" && oct === \"\" && type === \"\") {\n return [note, split[0], letter + acc];\n } else {\n return [note, chord, \"\"];\n }\n}\n\n/**\n * Get a Chord from a chord name.\n */\nexport function get(src: ChordNameOrTokens): Chord {\n if (Array.isArray(src)) {\n return getChord(src[1] || \"\", src[0], src[2]);\n } else if (src === \"\") {\n return NoChord;\n } else {\n const [tonic, type, bass] = tokenize(src);\n const chord = getChord(type, tonic, bass);\n return chord.empty ? getChord(src) : chord;\n }\n}\n\n/**\n * Get chord properties\n *\n * @param typeName - the chord type name\n * @param [tonic] - Optional tonic\n * @param [root] - Optional root (requires a tonic)\n */\nexport function getChord(\n typeName: string,\n optionalTonic?: string,\n optionalBass?: string,\n): Chord {\n const type = getChordType(typeName);\n const tonic = note(optionalTonic || \"\");\n const bass = note(optionalBass || \"\");\n\n if (\n type.empty ||\n (optionalTonic && tonic.empty) ||\n (optionalBass && bass.empty)\n ) {\n return NoChord;\n }\n\n const bassInterval = distance(tonic.pc, bass.pc);\n const bassIndex = type.intervals.indexOf(bassInterval);\n const hasRoot = bassIndex >= 0;\n const root = hasRoot ? bass : note(\"\");\n const rootDegree = bassIndex === -1 ? NaN : bassIndex + 1;\n const hasBass = bass.pc && bass.pc !== tonic.pc;\n\n const intervals = Array.from(type.intervals);\n\n if (hasRoot) {\n for (let i = 1; i < rootDegree; i++) {\n const num = intervals[0][0];\n const quality = intervals[0][1];\n const newNum = parseInt(num, 10) + 7;\n intervals.push(`${newNum}${quality}`);\n intervals.shift();\n }\n } else if (hasBass) {\n const ivl = subtract(distance(tonic.pc, bass.pc), \"8P\");\n if (ivl) intervals.unshift(ivl);\n }\n\n const notes = tonic.empty\n ? []\n : intervals.map((i) => transposeNote(tonic.pc, i));\n\n typeName = type.aliases.indexOf(typeName) !== -1 ? typeName : type.aliases[0];\n const symbol = `${tonic.empty ? \"\" : tonic.pc}${typeName}${\n hasRoot && rootDegree > 1 ? \"/\" + root.pc : hasBass ? \"/\" + bass.pc : \"\"\n }`;\n const name = `${optionalTonic ? tonic.pc + \" \" : \"\"}${type.name}${\n hasRoot && rootDegree > 1\n ? \" over \" + root.pc\n : hasBass\n ? \" over \" + bass.pc\n : \"\"\n }`;\n return {\n ...type,\n name,\n symbol,\n tonic: tonic.pc,\n type: type.name,\n root: root.pc,\n bass: hasBass ? bass.pc : \"\",\n intervals,\n rootDegree,\n notes,\n };\n}\n\nexport const chord = get;\n\n/**\n * Transpose a chord name\n *\n * @param {string} chordName - the chord name\n * @return {string} the transposed chord\n *\n * @example\n * transpose('Dm7', 'P4') // => 'Gm7\n */\nexport function transpose(chordName: string, interval: string): string {\n const [tonic, type, bass] = tokenize(chordName);\n if (!tonic) {\n return chordName;\n }\n const tr = transposeNote(bass, interval);\n const slash = tr ? \"/\" + tr : \"\";\n return transposeNote(tonic, interval) + type + slash;\n}\n\n/**\n * Get all scales where the given chord fits\n *\n * @example\n * chordScales('C7b9')\n * // => [\"phrygian dominant\", \"flamenco\", \"spanish heptatonic\", \"half-whole diminished\", \"chromatic\"]\n */\nexport function chordScales(name: string): string[] {\n const s = get(name);\n const isChordIncluded = isSupersetOf(s.chroma);\n return scaleTypes()\n .filter((scale) => isChordIncluded(scale.chroma))\n .map((scale) => scale.name);\n}\n/**\n * Get all chords names that are a superset of the given one\n * (has the same notes and at least one more)\n *\n * @function\n * @example\n * extended(\"CMaj7\")\n * // => [ 'Cmaj#4', 'Cmaj7#9#11', 'Cmaj9', 'CM7add13', 'Cmaj13', 'Cmaj9#11', 'CM13#11', 'CM7b9' ]\n */\nexport function extended(chordName: string): string[] {\n const s = get(chordName);\n const isSuperset = isSupersetOf(s.chroma);\n return chordTypes()\n .filter((chord) => isSuperset(chord.chroma))\n .map((chord) => s.tonic + chord.aliases[0]);\n}\n\n/**\n * Find all chords names that are a subset of the given one\n * (has less notes but all from the given chord)\n *\n * @example\n */\nexport function reduced(chordName: string): string[] {\n const s = get(chordName);\n const isSubset = isSubsetOf(s.chroma);\n return chordTypes()\n .filter((chord) => isSubset(chord.chroma))\n .map((chord) => s.tonic + chord.aliases[0]);\n}\n\n/**\n * Return the chord notes\n */\nexport function notes(chordName: ChordNameOrTokens, tonic?: string): string[] {\n const chord = get(chordName);\n const note = tonic || chord.tonic;\n if (!note || chord.empty) return [];\n return chord.intervals.map((ivl) => transposeNote(note, ivl));\n}\n\n/**\n * Returns a function to get a note name from the scale degree.\n *\n * @example\n * [1, 2, 3, 4].map(Chord.degrees(\"C\")) => [\"C\", \"E\", \"G\", \"C\"]\n * [1, 2, 3, 4].map(Chord.degrees(\"C4\")) => [\"C4\", \"E4\", \"G4\", \"C5\"]\n */\nexport function degrees(chordName: ChordNameOrTokens, tonic?: string) {\n const chord = get(chordName);\n const note = tonic || chord.tonic;\n const transpose = tonicIntervalsTransposer(chord.intervals, note);\n return (degree: number) =>\n degree ? transpose(degree > 0 ? degree - 1 : degree) : \"\";\n}\n\n/**\n * Sames as `degree` but with 0-based index\n */\nexport function steps(chordName: ChordNameOrTokens, tonic?: string) {\n const chord = get(chordName);\n const note = tonic || chord.tonic;\n return tonicIntervalsTransposer(chord.intervals, note);\n}\n\nexport default {\n getChord,\n get,\n detect,\n chordScales,\n extended,\n reduced,\n tokenize,\n transpose,\n degrees,\n steps,\n notes,\n chord,\n};\n"],"mappings":"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","names":["import_chord_detect","note","chord","getChordType","notes","transposeNote","scaleTypes","chordTypes","transpose"]}
|
package/dist/index.mjs
CHANGED
|
@@ -4,15 +4,14 @@ import {
|
|
|
4
4
|
all as chordTypes,
|
|
5
5
|
get as getChordType
|
|
6
6
|
} from "@tonaljs/chord-type";
|
|
7
|
-
import {
|
|
7
|
+
import { subtract } from "@tonaljs/interval";
|
|
8
|
+
import { isSubsetOf, isSupersetOf } from "@tonaljs/pcset";
|
|
8
9
|
import {
|
|
9
|
-
deprecate,
|
|
10
10
|
distance,
|
|
11
|
-
|
|
12
|
-
tokenizeNote,
|
|
11
|
+
tonicIntervalsTransposer,
|
|
13
12
|
transpose as transposeNote
|
|
14
|
-
} from "@tonaljs/
|
|
15
|
-
import {
|
|
13
|
+
} from "@tonaljs/pitch-distance";
|
|
14
|
+
import { note, tokenizeNote } from "@tonaljs/pitch-note";
|
|
16
15
|
import { all as scaleTypes } from "@tonaljs/scale-type";
|
|
17
16
|
import { detect as detect2 } from "@tonaljs/chord-detect";
|
|
18
17
|
var NoChord = {
|
|
@@ -20,6 +19,7 @@ var NoChord = {
|
|
|
20
19
|
name: "",
|
|
21
20
|
symbol: "",
|
|
22
21
|
root: "",
|
|
22
|
+
bass: "",
|
|
23
23
|
rootDegree: 0,
|
|
24
24
|
type: "",
|
|
25
25
|
tonic: null,
|
|
@@ -34,68 +34,89 @@ var NoChord = {
|
|
|
34
34
|
function tokenize(name) {
|
|
35
35
|
const [letter, acc, oct, type] = tokenizeNote(name);
|
|
36
36
|
if (letter === "") {
|
|
37
|
-
return
|
|
37
|
+
return tokenizeBass("", name);
|
|
38
|
+
} else if (letter === "A" && type === "ug") {
|
|
39
|
+
return tokenizeBass("", "aug");
|
|
40
|
+
} else {
|
|
41
|
+
return tokenizeBass(letter + acc, oct + type);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
function tokenizeBass(note2, chord2) {
|
|
45
|
+
const split = chord2.split("/");
|
|
46
|
+
if (split.length === 1) {
|
|
47
|
+
return [note2, split[0], ""];
|
|
38
48
|
}
|
|
39
|
-
|
|
40
|
-
|
|
49
|
+
const [letter, acc, oct, type] = tokenizeNote(split[1]);
|
|
50
|
+
if (letter !== "" && oct === "" && type === "") {
|
|
51
|
+
return [note2, split[0], letter + acc];
|
|
52
|
+
} else {
|
|
53
|
+
return [note2, chord2, ""];
|
|
41
54
|
}
|
|
42
|
-
return [letter + acc, oct + type];
|
|
43
55
|
}
|
|
44
56
|
function get(src) {
|
|
45
|
-
if (src
|
|
57
|
+
if (Array.isArray(src)) {
|
|
58
|
+
return getChord(src[1] || "", src[0], src[2]);
|
|
59
|
+
} else if (src === "") {
|
|
46
60
|
return NoChord;
|
|
47
|
-
}
|
|
48
|
-
if (Array.isArray(src) && src.length === 2) {
|
|
49
|
-
return getChord(src[1], src[0]);
|
|
50
61
|
} else {
|
|
51
|
-
const [tonic, type] = tokenize(src);
|
|
52
|
-
const chord2 = getChord(type, tonic);
|
|
62
|
+
const [tonic, type, bass] = tokenize(src);
|
|
63
|
+
const chord2 = getChord(type, tonic, bass);
|
|
53
64
|
return chord2.empty ? getChord(src) : chord2;
|
|
54
65
|
}
|
|
55
66
|
}
|
|
56
|
-
function getChord(typeName, optionalTonic,
|
|
67
|
+
function getChord(typeName, optionalTonic, optionalBass) {
|
|
57
68
|
const type = getChordType(typeName);
|
|
58
69
|
const tonic = note(optionalTonic || "");
|
|
59
|
-
const
|
|
60
|
-
if (type.empty || optionalTonic && tonic.empty ||
|
|
61
|
-
return NoChord;
|
|
62
|
-
}
|
|
63
|
-
const rootInterval = distance(tonic.pc, root.pc);
|
|
64
|
-
const rootDegree = type.intervals.indexOf(rootInterval) + 1;
|
|
65
|
-
if (!root.empty && !rootDegree) {
|
|
70
|
+
const bass = note(optionalBass || "");
|
|
71
|
+
if (type.empty || optionalTonic && tonic.empty || optionalBass && bass.empty) {
|
|
66
72
|
return NoChord;
|
|
67
73
|
}
|
|
74
|
+
const bassInterval = distance(tonic.pc, bass.pc);
|
|
75
|
+
const bassIndex = type.intervals.indexOf(bassInterval);
|
|
76
|
+
const hasRoot = bassIndex >= 0;
|
|
77
|
+
const root = hasRoot ? bass : note("");
|
|
78
|
+
const rootDegree = bassIndex === -1 ? NaN : bassIndex + 1;
|
|
79
|
+
const hasBass = bass.pc && bass.pc !== tonic.pc;
|
|
68
80
|
const intervals = Array.from(type.intervals);
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
81
|
+
if (hasRoot) {
|
|
82
|
+
for (let i = 1; i < rootDegree; i++) {
|
|
83
|
+
const num = intervals[0][0];
|
|
84
|
+
const quality = intervals[0][1];
|
|
85
|
+
const newNum = parseInt(num, 10) + 7;
|
|
86
|
+
intervals.push(`${newNum}${quality}`);
|
|
87
|
+
intervals.shift();
|
|
88
|
+
}
|
|
89
|
+
} else if (hasBass) {
|
|
90
|
+
const ivl = subtract(distance(tonic.pc, bass.pc), "8P");
|
|
91
|
+
if (ivl)
|
|
92
|
+
intervals.unshift(ivl);
|
|
75
93
|
}
|
|
76
|
-
const
|
|
94
|
+
const notes2 = tonic.empty ? [] : intervals.map((i) => transposeNote(tonic.pc, i));
|
|
77
95
|
typeName = type.aliases.indexOf(typeName) !== -1 ? typeName : type.aliases[0];
|
|
78
|
-
const symbol = `${tonic.empty ? "" : tonic.pc}${typeName}${
|
|
79
|
-
const name = `${optionalTonic ? tonic.pc + " " : ""}${type.name}${rootDegree > 1
|
|
96
|
+
const symbol = `${tonic.empty ? "" : tonic.pc}${typeName}${hasRoot && rootDegree > 1 ? "/" + root.pc : hasBass ? "/" + bass.pc : ""}`;
|
|
97
|
+
const name = `${optionalTonic ? tonic.pc + " " : ""}${type.name}${hasRoot && rootDegree > 1 ? " over " + root.pc : hasBass ? " over " + bass.pc : ""}`;
|
|
80
98
|
return {
|
|
81
99
|
...type,
|
|
82
100
|
name,
|
|
83
101
|
symbol,
|
|
102
|
+
tonic: tonic.pc,
|
|
84
103
|
type: type.name,
|
|
85
|
-
root: root.
|
|
104
|
+
root: root.pc,
|
|
105
|
+
bass: hasBass ? bass.pc : "",
|
|
86
106
|
intervals,
|
|
87
107
|
rootDegree,
|
|
88
|
-
|
|
89
|
-
notes
|
|
108
|
+
notes: notes2
|
|
90
109
|
};
|
|
91
110
|
}
|
|
92
|
-
var chord =
|
|
111
|
+
var chord = get;
|
|
93
112
|
function transpose(chordName, interval) {
|
|
94
|
-
const [tonic, type] = tokenize(chordName);
|
|
113
|
+
const [tonic, type, bass] = tokenize(chordName);
|
|
95
114
|
if (!tonic) {
|
|
96
115
|
return chordName;
|
|
97
116
|
}
|
|
98
|
-
|
|
117
|
+
const tr = transposeNote(bass, interval);
|
|
118
|
+
const slash = tr ? "/" + tr : "";
|
|
119
|
+
return transposeNote(tonic, interval) + type + slash;
|
|
99
120
|
}
|
|
100
121
|
function chordScales(name) {
|
|
101
122
|
const s = get(name);
|
|
@@ -112,14 +133,23 @@ function reduced(chordName) {
|
|
|
112
133
|
const isSubset = isSubsetOf(s.chroma);
|
|
113
134
|
return chordTypes().filter((chord2) => isSubset(chord2.chroma)).map((chord2) => s.tonic + chord2.aliases[0]);
|
|
114
135
|
}
|
|
115
|
-
function
|
|
116
|
-
const
|
|
117
|
-
const
|
|
136
|
+
function notes(chordName, tonic) {
|
|
137
|
+
const chord2 = get(chordName);
|
|
138
|
+
const note2 = tonic || chord2.tonic;
|
|
139
|
+
if (!note2 || chord2.empty)
|
|
140
|
+
return [];
|
|
141
|
+
return chord2.intervals.map((ivl) => transposeNote(note2, ivl));
|
|
142
|
+
}
|
|
143
|
+
function degrees(chordName, tonic) {
|
|
144
|
+
const chord2 = get(chordName);
|
|
145
|
+
const note2 = tonic || chord2.tonic;
|
|
146
|
+
const transpose2 = tonicIntervalsTransposer(chord2.intervals, note2);
|
|
118
147
|
return (degree) => degree ? transpose2(degree > 0 ? degree - 1 : degree) : "";
|
|
119
148
|
}
|
|
120
|
-
function steps(chordName) {
|
|
121
|
-
const
|
|
122
|
-
|
|
149
|
+
function steps(chordName, tonic) {
|
|
150
|
+
const chord2 = get(chordName);
|
|
151
|
+
const note2 = tonic || chord2.tonic;
|
|
152
|
+
return tonicIntervalsTransposer(chord2.intervals, note2);
|
|
123
153
|
}
|
|
124
154
|
var chord_default = {
|
|
125
155
|
getChord,
|
|
@@ -132,7 +162,7 @@ var chord_default = {
|
|
|
132
162
|
transpose,
|
|
133
163
|
degrees,
|
|
134
164
|
steps,
|
|
135
|
-
|
|
165
|
+
notes,
|
|
136
166
|
chord
|
|
137
167
|
};
|
|
138
168
|
export {
|
|
@@ -144,6 +174,7 @@ export {
|
|
|
144
174
|
extended,
|
|
145
175
|
get,
|
|
146
176
|
getChord,
|
|
177
|
+
notes,
|
|
147
178
|
reduced,
|
|
148
179
|
steps,
|
|
149
180
|
tokenize,
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../index.ts"],"sourcesContent":["import { detect } from \"@tonaljs/chord-detect\";\nimport {\n ChordType,\n all as chordTypes,\n get as getChordType,\n} from \"@tonaljs/chord-type\";\nimport { tonicIntervalsTransposer } from \"@tonaljs/core\";\n\nimport {\n deprecate,\n distance,\n note,\n NoteName,\n tokenizeNote,\n transpose as transposeNote,\n} from \"@tonaljs/core\";\n\nimport { isSubsetOf, isSupersetOf } from \"@tonaljs/pcset\";\n\nimport { all as scaleTypes } from \"@tonaljs/scale-type\";\nexport { detect } from \"@tonaljs/chord-detect\";\n\ntype ChordName = string;\ntype ChordNameTokens = [string, string]; // [TONIC, SCALE TYPE]\n\nexport interface Chord extends ChordType {\n tonic: string | null;\n type: string;\n root: string;\n rootDegree: number;\n symbol: string;\n notes: NoteName[];\n}\n\nconst NoChord: Chord = {\n empty: true,\n name: \"\",\n symbol: \"\",\n root: \"\",\n rootDegree: 0,\n type: \"\",\n tonic: null,\n setNum: NaN,\n quality: \"Unknown\",\n chroma: \"\",\n normalized: \"\",\n aliases: [],\n notes: [],\n intervals: [],\n};\n\n// 6, 64, 7, 9, 11 and 13 are consider part of the chord\n// (see https://github.com/danigb/tonal/issues/55)\n//const NUM_TYPES = /^(6|64|7|9|11|13)$/;\n/**\n * Tokenize a chord name. It returns an array with the tonic and chord type\n * If not tonic is found, all the name is considered the chord name.\n *\n * This function does NOT check if the chord type exists or not. It only tries\n * to split the tonic and chord type.\n *\n * @function\n * @param {string} name - the chord name\n * @return {Array} an array with [tonic, type]\n * @example\n * tokenize(\"Cmaj7\") // => [ \"C\", \"maj7\" ]\n * tokenize(\"C7\") // => [ \"C\", \"7\" ]\n * tokenize(\"mMaj7\") // => [ null, \"mMaj7\" ]\n * tokenize(\"Cnonsense\") // => [ null, \"nonsense\" ]\n */\nexport function tokenize(name: string): ChordNameTokens {\n const [letter, acc, oct, type] = tokenizeNote(name);\n if (letter === \"\") {\n return [\"\", name];\n }\n // aug is augmented (see https://github.com/danigb/tonal/issues/55)\n if (letter === \"A\" && type === \"ug\") {\n return [\"\", \"aug\"];\n }\n return [letter + acc, oct + type];\n}\n\n/**\n * Get a Chord from a chord name.\n */\nexport function get(src: ChordName | ChordNameTokens): Chord {\n if (src === \"\") {\n return NoChord;\n }\n if (Array.isArray(src) && src.length === 2) {\n return getChord(src[1], src[0]);\n } else {\n const [tonic, type] = tokenize(src);\n const chord = getChord(type, tonic);\n return chord.empty ? getChord(src) : chord;\n }\n}\n\n/**\n * Get chord properties\n *\n * @param typeName - the chord type name\n * @param [tonic] - Optional tonic\n * @param [root] - Optional root (requires a tonic)\n */\nexport function getChord(\n typeName: string,\n optionalTonic?: string,\n optionalRoot?: string,\n): Chord {\n const type = getChordType(typeName);\n const tonic = note(optionalTonic || \"\");\n const root = note(optionalRoot || \"\");\n\n if (\n type.empty ||\n (optionalTonic && tonic.empty) ||\n (optionalRoot && root.empty)\n ) {\n return NoChord;\n }\n\n const rootInterval = distance(tonic.pc, root.pc);\n const rootDegree = type.intervals.indexOf(rootInterval) + 1;\n if (!root.empty && !rootDegree) {\n return NoChord;\n }\n\n const intervals = Array.from(type.intervals);\n\n for (let i = 1; i < rootDegree; i++) {\n const num = intervals[0][0];\n const quality = intervals[0][1];\n const newNum = parseInt(num, 10) + 7;\n intervals.push(`${newNum}${quality}`);\n intervals.shift();\n }\n\n const notes = tonic.empty\n ? []\n : intervals.map((i) => transposeNote(tonic, i));\n\n typeName = type.aliases.indexOf(typeName) !== -1 ? typeName : type.aliases[0];\n const symbol = `${tonic.empty ? \"\" : tonic.pc}${typeName}${\n root.empty || rootDegree <= 1 ? \"\" : \"/\" + root.pc\n }`;\n const name = `${optionalTonic ? tonic.pc + \" \" : \"\"}${type.name}${\n rootDegree > 1 && optionalRoot ? \" over \" + root.pc : \"\"\n }`;\n return {\n ...type,\n name,\n symbol,\n type: type.name,\n root: root.name,\n intervals,\n rootDegree,\n tonic: tonic.name,\n notes,\n };\n}\n\nexport const chord = deprecate(\"Chord.chord\", \"Chord.get\", get);\n\n/**\n * Transpose a chord name\n *\n * @param {string} chordName - the chord name\n * @return {string} the transposed chord\n *\n * @example\n * transpose('Dm7', 'P4') // => 'Gm7\n */\nexport function transpose(chordName: string, interval: string): string {\n const [tonic, type] = tokenize(chordName);\n if (!tonic) {\n return chordName;\n }\n return transposeNote(tonic, interval) + type;\n}\n\n/**\n * Get all scales where the given chord fits\n *\n * @example\n * chordScales('C7b9')\n * // => [\"phrygian dominant\", \"flamenco\", \"spanish heptatonic\", \"half-whole diminished\", \"chromatic\"]\n */\nexport function chordScales(name: string): string[] {\n const s = get(name);\n const isChordIncluded = isSupersetOf(s.chroma);\n return scaleTypes()\n .filter((scale) => isChordIncluded(scale.chroma))\n .map((scale) => scale.name);\n}\n/**\n * Get all chords names that are a superset of the given one\n * (has the same notes and at least one more)\n *\n * @function\n * @example\n * extended(\"CMaj7\")\n * // => [ 'Cmaj#4', 'Cmaj7#9#11', 'Cmaj9', 'CM7add13', 'Cmaj13', 'Cmaj9#11', 'CM13#11', 'CM7b9' ]\n */\nexport function extended(chordName: string): string[] {\n const s = get(chordName);\n const isSuperset = isSupersetOf(s.chroma);\n return chordTypes()\n .filter((chord) => isSuperset(chord.chroma))\n .map((chord) => s.tonic + chord.aliases[0]);\n}\n\n/**\n * Find all chords names that are a subset of the given one\n * (has less notes but all from the given chord)\n *\n * @example\n */\nexport function reduced(chordName: string): string[] {\n const s = get(chordName);\n const isSubset = isSubsetOf(s.chroma);\n return chordTypes()\n .filter((chord) => isSubset(chord.chroma))\n .map((chord) => s.tonic + chord.aliases[0]);\n}\n\n/**\n * Returns a function to get a note name from the scale degree.\n *\n * @example\n * [1, 2, 3, 4].map(Chord.degrees(\"C\")) => [\"C\", \"E\", \"G\", \"C\"]\n * [1, 2, 3, 4].map(Chord.degrees(\"C4\")) => [\"C4\", \"E4\", \"G4\", \"C5\"]\n */\nexport function degrees(chordName: string | ChordNameTokens) {\n const { intervals, tonic } = get(chordName);\n const transpose = tonicIntervalsTransposer(intervals, tonic);\n return (degree: number) =>\n degree ? transpose(degree > 0 ? degree - 1 : degree) : \"\";\n}\n\n/**\n * Sames as `degree` but with 0-based index\n */\nexport function steps(chordName: string | ChordNameTokens) {\n const { intervals, tonic } = get(chordName);\n return tonicIntervalsTransposer(intervals, tonic);\n}\n\nexport default {\n getChord,\n get,\n detect,\n chordScales,\n extended,\n reduced,\n tokenize,\n transpose,\n degrees,\n steps,\n\n // deprecate\n chord,\n};\n"],"mappings":"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","names":["detect","chord","transpose"]}
|
|
1
|
+
{"version":3,"sources":["../index.ts"],"sourcesContent":["import { detect } from \"@tonaljs/chord-detect\";\nimport {\n ChordType,\n all as chordTypes,\n get as getChordType,\n} from \"@tonaljs/chord-type\";\nimport { subtract } from \"@tonaljs/interval\";\nimport { isSubsetOf, isSupersetOf } from \"@tonaljs/pcset\";\nimport {\n distance,\n tonicIntervalsTransposer,\n transpose as transposeNote,\n} from \"@tonaljs/pitch-distance\";\nimport { NoteName, note, tokenizeNote } from \"@tonaljs/pitch-note\";\nimport { all as scaleTypes } from \"@tonaljs/scale-type\";\n\nexport { detect } from \"@tonaljs/chord-detect\";\n\ntype ChordNameOrTokens =\n | string // full name to be parsed\n | [string] // only the name\n | [string, string] // tonic, name\n | [string, string, string]; // tonic, name, bass\ntype ChordNameTokens = [string, string, string]; // [TONIC, SCALE TYPE, BASS]\n\nexport interface Chord extends ChordType {\n tonic: string | null;\n type: string;\n root: string;\n bass: string;\n rootDegree: number;\n symbol: string;\n notes: NoteName[];\n}\n\nconst NoChord: Chord = {\n empty: true,\n name: \"\",\n symbol: \"\",\n root: \"\",\n bass: \"\",\n rootDegree: 0,\n type: \"\",\n tonic: null,\n setNum: NaN,\n quality: \"Unknown\",\n chroma: \"\",\n normalized: \"\",\n aliases: [],\n notes: [],\n intervals: [],\n};\n\n// 6, 64, 7, 9, 11 and 13 are consider part of the chord\n// (see https://github.com/danigb/tonal/issues/55)\n//const NUM_TYPES = /^(6|64|7|9|11|13)$/;\n/**\n * Tokenize a chord name. It returns an array with the tonic, chord type and bass\n * If not tonic is found, all the name is considered the chord name.\n *\n * This function does NOT check if the chord type exists or not. It only tries\n * to split the tonic and chord type.\n *\n * This function does NOT check if the bass is part of the chord or not but it\n * only accepts a pitch class as bass\n *\n * @function\n * @param {string} name - the chord name\n * @return {Array} an array with [tonic, type, bass]\n * @example\n * tokenize(\"Cmaj7\") // => [ \"C\", \"maj7\" ]\n * tokenize(\"C7\") // => [ \"C\", \"7\" ]\n * tokenize(\"mMaj7\") // => [ null, \"mMaj7\" ]\n * tokenize(\"Cnonsense\") // => [ null, \"nonsense\" ]\n */\nexport function tokenize(name: string): ChordNameTokens {\n const [letter, acc, oct, type] = tokenizeNote(name);\n if (letter === \"\") {\n return tokenizeBass(\"\", name);\n } else if (letter === \"A\" && type === \"ug\") {\n return tokenizeBass(\"\", \"aug\");\n } else {\n return tokenizeBass(letter + acc, oct + type);\n }\n}\n\nfunction tokenizeBass(note: string, chord: string): ChordNameTokens {\n const split = chord.split(\"/\");\n if (split.length === 1) {\n return [note, split[0], \"\"];\n }\n const [letter, acc, oct, type] = tokenizeNote(split[1]);\n // Only a pitch class is accepted as bass note\n if (letter !== \"\" && oct === \"\" && type === \"\") {\n return [note, split[0], letter + acc];\n } else {\n return [note, chord, \"\"];\n }\n}\n\n/**\n * Get a Chord from a chord name.\n */\nexport function get(src: ChordNameOrTokens): Chord {\n if (Array.isArray(src)) {\n return getChord(src[1] || \"\", src[0], src[2]);\n } else if (src === \"\") {\n return NoChord;\n } else {\n const [tonic, type, bass] = tokenize(src);\n const chord = getChord(type, tonic, bass);\n return chord.empty ? getChord(src) : chord;\n }\n}\n\n/**\n * Get chord properties\n *\n * @param typeName - the chord type name\n * @param [tonic] - Optional tonic\n * @param [root] - Optional root (requires a tonic)\n */\nexport function getChord(\n typeName: string,\n optionalTonic?: string,\n optionalBass?: string,\n): Chord {\n const type = getChordType(typeName);\n const tonic = note(optionalTonic || \"\");\n const bass = note(optionalBass || \"\");\n\n if (\n type.empty ||\n (optionalTonic && tonic.empty) ||\n (optionalBass && bass.empty)\n ) {\n return NoChord;\n }\n\n const bassInterval = distance(tonic.pc, bass.pc);\n const bassIndex = type.intervals.indexOf(bassInterval);\n const hasRoot = bassIndex >= 0;\n const root = hasRoot ? bass : note(\"\");\n const rootDegree = bassIndex === -1 ? NaN : bassIndex + 1;\n const hasBass = bass.pc && bass.pc !== tonic.pc;\n\n const intervals = Array.from(type.intervals);\n\n if (hasRoot) {\n for (let i = 1; i < rootDegree; i++) {\n const num = intervals[0][0];\n const quality = intervals[0][1];\n const newNum = parseInt(num, 10) + 7;\n intervals.push(`${newNum}${quality}`);\n intervals.shift();\n }\n } else if (hasBass) {\n const ivl = subtract(distance(tonic.pc, bass.pc), \"8P\");\n if (ivl) intervals.unshift(ivl);\n }\n\n const notes = tonic.empty\n ? []\n : intervals.map((i) => transposeNote(tonic.pc, i));\n\n typeName = type.aliases.indexOf(typeName) !== -1 ? typeName : type.aliases[0];\n const symbol = `${tonic.empty ? \"\" : tonic.pc}${typeName}${\n hasRoot && rootDegree > 1 ? \"/\" + root.pc : hasBass ? \"/\" + bass.pc : \"\"\n }`;\n const name = `${optionalTonic ? tonic.pc + \" \" : \"\"}${type.name}${\n hasRoot && rootDegree > 1\n ? \" over \" + root.pc\n : hasBass\n ? \" over \" + bass.pc\n : \"\"\n }`;\n return {\n ...type,\n name,\n symbol,\n tonic: tonic.pc,\n type: type.name,\n root: root.pc,\n bass: hasBass ? bass.pc : \"\",\n intervals,\n rootDegree,\n notes,\n };\n}\n\nexport const chord = get;\n\n/**\n * Transpose a chord name\n *\n * @param {string} chordName - the chord name\n * @return {string} the transposed chord\n *\n * @example\n * transpose('Dm7', 'P4') // => 'Gm7\n */\nexport function transpose(chordName: string, interval: string): string {\n const [tonic, type, bass] = tokenize(chordName);\n if (!tonic) {\n return chordName;\n }\n const tr = transposeNote(bass, interval);\n const slash = tr ? \"/\" + tr : \"\";\n return transposeNote(tonic, interval) + type + slash;\n}\n\n/**\n * Get all scales where the given chord fits\n *\n * @example\n * chordScales('C7b9')\n * // => [\"phrygian dominant\", \"flamenco\", \"spanish heptatonic\", \"half-whole diminished\", \"chromatic\"]\n */\nexport function chordScales(name: string): string[] {\n const s = get(name);\n const isChordIncluded = isSupersetOf(s.chroma);\n return scaleTypes()\n .filter((scale) => isChordIncluded(scale.chroma))\n .map((scale) => scale.name);\n}\n/**\n * Get all chords names that are a superset of the given one\n * (has the same notes and at least one more)\n *\n * @function\n * @example\n * extended(\"CMaj7\")\n * // => [ 'Cmaj#4', 'Cmaj7#9#11', 'Cmaj9', 'CM7add13', 'Cmaj13', 'Cmaj9#11', 'CM13#11', 'CM7b9' ]\n */\nexport function extended(chordName: string): string[] {\n const s = get(chordName);\n const isSuperset = isSupersetOf(s.chroma);\n return chordTypes()\n .filter((chord) => isSuperset(chord.chroma))\n .map((chord) => s.tonic + chord.aliases[0]);\n}\n\n/**\n * Find all chords names that are a subset of the given one\n * (has less notes but all from the given chord)\n *\n * @example\n */\nexport function reduced(chordName: string): string[] {\n const s = get(chordName);\n const isSubset = isSubsetOf(s.chroma);\n return chordTypes()\n .filter((chord) => isSubset(chord.chroma))\n .map((chord) => s.tonic + chord.aliases[0]);\n}\n\n/**\n * Return the chord notes\n */\nexport function notes(chordName: ChordNameOrTokens, tonic?: string): string[] {\n const chord = get(chordName);\n const note = tonic || chord.tonic;\n if (!note || chord.empty) return [];\n return chord.intervals.map((ivl) => transposeNote(note, ivl));\n}\n\n/**\n * Returns a function to get a note name from the scale degree.\n *\n * @example\n * [1, 2, 3, 4].map(Chord.degrees(\"C\")) => [\"C\", \"E\", \"G\", \"C\"]\n * [1, 2, 3, 4].map(Chord.degrees(\"C4\")) => [\"C4\", \"E4\", \"G4\", \"C5\"]\n */\nexport function degrees(chordName: ChordNameOrTokens, tonic?: string) {\n const chord = get(chordName);\n const note = tonic || chord.tonic;\n const transpose = tonicIntervalsTransposer(chord.intervals, note);\n return (degree: number) =>\n degree ? transpose(degree > 0 ? degree - 1 : degree) : \"\";\n}\n\n/**\n * Sames as `degree` but with 0-based index\n */\nexport function steps(chordName: ChordNameOrTokens, tonic?: string) {\n const chord = get(chordName);\n const note = tonic || chord.tonic;\n return tonicIntervalsTransposer(chord.intervals, note);\n}\n\nexport default {\n getChord,\n get,\n detect,\n chordScales,\n extended,\n reduced,\n tokenize,\n transpose,\n degrees,\n steps,\n notes,\n chord,\n};\n"],"mappings":"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","names":["detect","note","chord","notes","transpose"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tonaljs/chord",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "6.0.0",
|
|
4
4
|
"description": "Musical chords and its relations",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"chord",
|
|
@@ -16,19 +16,26 @@
|
|
|
16
16
|
],
|
|
17
17
|
"types": "dist/index.d.ts",
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"@tonaljs/chord-detect": "
|
|
20
|
-
"@tonaljs/chord-type": "
|
|
21
|
-
"@tonaljs/collection": "
|
|
22
|
-
"@tonaljs/
|
|
23
|
-
"@tonaljs/pcset": "
|
|
24
|
-
"@tonaljs/
|
|
19
|
+
"@tonaljs/chord-detect": "4.8.5",
|
|
20
|
+
"@tonaljs/chord-type": "5.0.5",
|
|
21
|
+
"@tonaljs/collection": "4.8.1",
|
|
22
|
+
"@tonaljs/interval": "^5.0.0",
|
|
23
|
+
"@tonaljs/pcset": "4.9.2",
|
|
24
|
+
"@tonaljs/pitch-distance": "5.0.3",
|
|
25
|
+
"@tonaljs/pitch-note": "6.0.0",
|
|
26
|
+
"@tonaljs/scale-type": "4.8.5"
|
|
25
27
|
},
|
|
26
28
|
"author": "danigb@gmail.com",
|
|
27
29
|
"license": "MIT",
|
|
28
30
|
"publishConfig": {
|
|
29
31
|
"access": "public"
|
|
30
32
|
},
|
|
33
|
+
"jest": {
|
|
34
|
+
"preset": "ts-jest",
|
|
35
|
+
"testEnvironment": "node"
|
|
36
|
+
},
|
|
31
37
|
"scripts": {
|
|
32
|
-
"build": "tsup index.ts --sourcemap --dts --format esm,cjs"
|
|
38
|
+
"build": "tsup index.ts --sourcemap --dts --format esm,cjs",
|
|
39
|
+
"test": "jest --coverage"
|
|
33
40
|
}
|
|
34
41
|
}
|