@tonaljs/scale 4.6.4 → 4.6.10
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/dist/index.d.ts +114 -112
- package/dist/index.js +161 -249
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +132 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +11 -9
- package/dist/index.es.js +0 -216
- package/dist/index.es.js.map +0 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,112 +1,114 @@
|
|
|
1
|
-
import { NoteName } from
|
|
2
|
-
import { names as
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* @
|
|
20
|
-
* @
|
|
21
|
-
* @
|
|
22
|
-
*
|
|
23
|
-
* tokenize("
|
|
24
|
-
* tokenize() // => ["", ""]
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
*
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
* @
|
|
42
|
-
* @
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
* @
|
|
54
|
-
* @
|
|
55
|
-
* @
|
|
56
|
-
*
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
* @
|
|
65
|
-
* @
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
* @
|
|
77
|
-
* @
|
|
78
|
-
* @
|
|
79
|
-
*
|
|
80
|
-
* scaleNotes(['
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
declare
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
* @
|
|
89
|
-
* @
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
* ["
|
|
93
|
-
* ["
|
|
94
|
-
* ["
|
|
95
|
-
* ["
|
|
96
|
-
* ]
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
declare
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
1
|
+
import { NoteName } from '@tonaljs/core';
|
|
2
|
+
import { ScaleType, names as names$1 } from '@tonaljs/scale-type';
|
|
3
|
+
|
|
4
|
+
type ScaleName = string;
|
|
5
|
+
type ScaleNameTokens = [string, string];
|
|
6
|
+
interface Scale extends ScaleType {
|
|
7
|
+
tonic: string | null;
|
|
8
|
+
type: string;
|
|
9
|
+
notes: NoteName[];
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Given a string with a scale name and (optionally) a tonic, split
|
|
13
|
+
* that components.
|
|
14
|
+
*
|
|
15
|
+
* It retuns an array with the form [ name, tonic ] where tonic can be a
|
|
16
|
+
* note name or null and name can be any arbitrary string
|
|
17
|
+
* (this function doesn"t check if that scale name exists)
|
|
18
|
+
*
|
|
19
|
+
* @function
|
|
20
|
+
* @param {string} name - the scale name
|
|
21
|
+
* @return {Array} an array [tonic, name]
|
|
22
|
+
* @example
|
|
23
|
+
* tokenize("C mixolydean") // => ["C", "mixolydean"]
|
|
24
|
+
* tokenize("anything is valid") // => ["", "anything is valid"]
|
|
25
|
+
* tokenize() // => ["", ""]
|
|
26
|
+
*/
|
|
27
|
+
declare function tokenize(name: ScaleName): ScaleNameTokens;
|
|
28
|
+
/**
|
|
29
|
+
* Get all scale names
|
|
30
|
+
* @function
|
|
31
|
+
*/
|
|
32
|
+
declare const names: typeof names$1;
|
|
33
|
+
/**
|
|
34
|
+
* Get a Scale from a scale name.
|
|
35
|
+
*/
|
|
36
|
+
declare function get(src: ScaleName | ScaleNameTokens): Scale;
|
|
37
|
+
declare const scale: (this: unknown, ...args: unknown[]) => Scale;
|
|
38
|
+
/**
|
|
39
|
+
* Get all chords that fits a given scale
|
|
40
|
+
*
|
|
41
|
+
* @function
|
|
42
|
+
* @param {string} name - the scale name
|
|
43
|
+
* @return {Array<string>} - the chord names
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* scaleChords("pentatonic") // => ["5", "64", "M", "M6", "Madd9", "Msus2"]
|
|
47
|
+
*/
|
|
48
|
+
declare function scaleChords(name: string): string[];
|
|
49
|
+
/**
|
|
50
|
+
* Get all scales names that are a superset of the given one
|
|
51
|
+
* (has the same notes and at least one more)
|
|
52
|
+
*
|
|
53
|
+
* @function
|
|
54
|
+
* @param {string} name
|
|
55
|
+
* @return {Array} a list of scale names
|
|
56
|
+
* @example
|
|
57
|
+
* extended("major") // => ["bebop", "bebop dominant", "bebop major", "chromatic", "ichikosucho"]
|
|
58
|
+
*/
|
|
59
|
+
declare function extended(name: string): string[];
|
|
60
|
+
/**
|
|
61
|
+
* Find all scales names that are a subset of the given one
|
|
62
|
+
* (has less notes but all from the given scale)
|
|
63
|
+
*
|
|
64
|
+
* @function
|
|
65
|
+
* @param {string} name
|
|
66
|
+
* @return {Array} a list of scale names
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* reduced("major") // => ["ionian pentatonic", "major pentatonic", "ritusen"]
|
|
70
|
+
*/
|
|
71
|
+
declare function reduced(name: string): string[];
|
|
72
|
+
/**
|
|
73
|
+
* Given an array of notes, return the scale: a pitch class set starting from
|
|
74
|
+
* the first note of the array
|
|
75
|
+
*
|
|
76
|
+
* @function
|
|
77
|
+
* @param {string[]} notes
|
|
78
|
+
* @return {string[]} pitch classes with same tonic
|
|
79
|
+
* @example
|
|
80
|
+
* scaleNotes(['C4', 'c3', 'C5', 'C4', 'c4']) // => ["C"]
|
|
81
|
+
* scaleNotes(['D4', 'c#5', 'A5', 'F#6']) // => ["D", "F#", "A", "C#"]
|
|
82
|
+
*/
|
|
83
|
+
declare function scaleNotes(notes: NoteName[]): string[];
|
|
84
|
+
type ScaleMode = [string, string];
|
|
85
|
+
/**
|
|
86
|
+
* Find mode names of a scale
|
|
87
|
+
*
|
|
88
|
+
* @function
|
|
89
|
+
* @param {string} name - scale name
|
|
90
|
+
* @example
|
|
91
|
+
* modeNames("C pentatonic") // => [
|
|
92
|
+
* ["C", "major pentatonic"],
|
|
93
|
+
* ["D", "egyptian"],
|
|
94
|
+
* ["E", "malkos raga"],
|
|
95
|
+
* ["G", "ritusen"],
|
|
96
|
+
* ["A", "minor pentatonic"]
|
|
97
|
+
* ]
|
|
98
|
+
*/
|
|
99
|
+
declare function modeNames(name: string): ScaleMode[];
|
|
100
|
+
declare function rangeOf(scale: string | string[]): (fromNote: string, toNote: string) => (string | undefined)[];
|
|
101
|
+
declare const _default: {
|
|
102
|
+
get: typeof get;
|
|
103
|
+
names: typeof names$1;
|
|
104
|
+
extended: typeof extended;
|
|
105
|
+
modeNames: typeof modeNames;
|
|
106
|
+
reduced: typeof reduced;
|
|
107
|
+
scaleChords: typeof scaleChords;
|
|
108
|
+
scaleNotes: typeof scaleNotes;
|
|
109
|
+
tokenize: typeof tokenize;
|
|
110
|
+
rangeOf: typeof rangeOf;
|
|
111
|
+
scale: (this: unknown, ...args: unknown[]) => Scale;
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
export { Scale, _default as default, extended, get, modeNames, names, rangeOf, reduced, scale, scaleChords, scaleNotes, tokenize };
|
package/dist/index.js
CHANGED
|
@@ -1,250 +1,162 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
6
19
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
* the first note of the array
|
|
151
|
-
*
|
|
152
|
-
* @function
|
|
153
|
-
* @param {string[]} notes
|
|
154
|
-
* @return {string[]} pitch classes with same tonic
|
|
155
|
-
* @example
|
|
156
|
-
* scaleNotes(['C4', 'c3', 'C5', 'C4', 'c4']) // => ["C"]
|
|
157
|
-
* scaleNotes(['D4', 'c#5', 'A5', 'F#6']) // => ["D", "F#", "A", "C#"]
|
|
158
|
-
*/
|
|
159
|
-
function scaleNotes(notes) {
|
|
160
|
-
var pcset = notes.map(function (n) { return core.note(n).pc; }).filter(function (x) { return x; });
|
|
161
|
-
var tonic = pcset[0];
|
|
162
|
-
var scale = note.sortedUniqNames(pcset);
|
|
163
|
-
return collection.rotate(scale.indexOf(tonic), scale);
|
|
164
|
-
}
|
|
165
|
-
/**
|
|
166
|
-
* Find mode names of a scale
|
|
167
|
-
*
|
|
168
|
-
* @function
|
|
169
|
-
* @param {string} name - scale name
|
|
170
|
-
* @example
|
|
171
|
-
* modeNames("C pentatonic") // => [
|
|
172
|
-
* ["C", "major pentatonic"],
|
|
173
|
-
* ["D", "egyptian"],
|
|
174
|
-
* ["E", "malkos raga"],
|
|
175
|
-
* ["G", "ritusen"],
|
|
176
|
-
* ["A", "minor pentatonic"]
|
|
177
|
-
* ]
|
|
178
|
-
*/
|
|
179
|
-
function modeNames(name) {
|
|
180
|
-
var s = get(name);
|
|
181
|
-
if (s.empty) {
|
|
182
|
-
return [];
|
|
183
|
-
}
|
|
184
|
-
var tonics = s.tonic ? s.notes : s.intervals;
|
|
185
|
-
return pcset.modes(s.chroma)
|
|
186
|
-
.map(function (chroma, i) {
|
|
187
|
-
var modeName = get(chroma).name;
|
|
188
|
-
return modeName ? [tonics[i], modeName] : ["", ""];
|
|
189
|
-
})
|
|
190
|
-
.filter(function (x) { return x[0]; });
|
|
191
|
-
}
|
|
192
|
-
function getNoteNameOf(scale) {
|
|
193
|
-
var names = Array.isArray(scale) ? scaleNotes(scale) : get(scale).notes;
|
|
194
|
-
var chromas = names.map(function (name) { return core.note(name).chroma; });
|
|
195
|
-
return function (noteOrMidi) {
|
|
196
|
-
var currNote = typeof noteOrMidi === "number"
|
|
197
|
-
? core.note(note.fromMidi(noteOrMidi))
|
|
198
|
-
: core.note(noteOrMidi);
|
|
199
|
-
var height = currNote.height;
|
|
200
|
-
if (height === undefined)
|
|
201
|
-
return undefined;
|
|
202
|
-
var chroma = height % 12;
|
|
203
|
-
var position = chromas.indexOf(chroma);
|
|
204
|
-
if (position === -1)
|
|
205
|
-
return undefined;
|
|
206
|
-
return note.enharmonic(currNote.name, names[position]);
|
|
207
|
-
};
|
|
208
|
-
}
|
|
209
|
-
function rangeOf(scale) {
|
|
210
|
-
var getName = getNoteNameOf(scale);
|
|
211
|
-
return function (fromNote, toNote) {
|
|
212
|
-
var from = core.note(fromNote).height;
|
|
213
|
-
var to = core.note(toNote).height;
|
|
214
|
-
if (from === undefined || to === undefined)
|
|
215
|
-
return [];
|
|
216
|
-
return collection.range(from, to)
|
|
217
|
-
.map(getName)
|
|
218
|
-
.filter(function (x) { return x; });
|
|
219
|
-
};
|
|
220
|
-
}
|
|
221
|
-
var index = {
|
|
222
|
-
get: get,
|
|
223
|
-
names: names,
|
|
224
|
-
extended: extended,
|
|
225
|
-
modeNames: modeNames,
|
|
226
|
-
reduced: reduced,
|
|
227
|
-
scaleChords: scaleChords,
|
|
228
|
-
scaleNotes: scaleNotes,
|
|
229
|
-
tokenize: tokenize,
|
|
230
|
-
rangeOf: rangeOf,
|
|
231
|
-
// deprecated
|
|
232
|
-
scale: scale,
|
|
233
|
-
};
|
|
234
|
-
|
|
235
|
-
exports['default'] = index;
|
|
236
|
-
exports.extended = extended;
|
|
237
|
-
exports.get = get;
|
|
238
|
-
exports.modeNames = modeNames;
|
|
239
|
-
exports.names = names;
|
|
240
|
-
exports.rangeOf = rangeOf;
|
|
241
|
-
exports.reduced = reduced;
|
|
242
|
-
exports.scale = scale;
|
|
243
|
-
exports.scaleChords = scaleChords;
|
|
244
|
-
exports.scaleNotes = scaleNotes;
|
|
245
|
-
exports.tokenize = tokenize;
|
|
246
|
-
|
|
247
|
-
Object.defineProperty(exports, '__esModule', { value: true });
|
|
248
|
-
|
|
249
|
-
})));
|
|
250
|
-
//# sourceMappingURL=index.js.map
|
|
20
|
+
// index.ts
|
|
21
|
+
var scale_exports = {};
|
|
22
|
+
__export(scale_exports, {
|
|
23
|
+
default: () => scale_default,
|
|
24
|
+
extended: () => extended,
|
|
25
|
+
get: () => get,
|
|
26
|
+
modeNames: () => modeNames,
|
|
27
|
+
names: () => names,
|
|
28
|
+
rangeOf: () => rangeOf,
|
|
29
|
+
reduced: () => reduced,
|
|
30
|
+
scale: () => scale,
|
|
31
|
+
scaleChords: () => scaleChords,
|
|
32
|
+
scaleNotes: () => scaleNotes,
|
|
33
|
+
tokenize: () => tokenize
|
|
34
|
+
});
|
|
35
|
+
module.exports = __toCommonJS(scale_exports);
|
|
36
|
+
var import_chord_type = require("@tonaljs/chord-type");
|
|
37
|
+
var import_collection = require("@tonaljs/collection");
|
|
38
|
+
var import_core = require("@tonaljs/core");
|
|
39
|
+
var import_note = require("@tonaljs/note");
|
|
40
|
+
var import_pcset = require("@tonaljs/pcset");
|
|
41
|
+
var import_scale_type = require("@tonaljs/scale-type");
|
|
42
|
+
var NoScale = {
|
|
43
|
+
empty: true,
|
|
44
|
+
name: "",
|
|
45
|
+
type: "",
|
|
46
|
+
tonic: null,
|
|
47
|
+
setNum: NaN,
|
|
48
|
+
chroma: "",
|
|
49
|
+
normalized: "",
|
|
50
|
+
aliases: [],
|
|
51
|
+
notes: [],
|
|
52
|
+
intervals: []
|
|
53
|
+
};
|
|
54
|
+
function tokenize(name) {
|
|
55
|
+
if (typeof name !== "string") {
|
|
56
|
+
return ["", ""];
|
|
57
|
+
}
|
|
58
|
+
const i = name.indexOf(" ");
|
|
59
|
+
const tonic = (0, import_core.note)(name.substring(0, i));
|
|
60
|
+
if (tonic.empty) {
|
|
61
|
+
const n = (0, import_core.note)(name);
|
|
62
|
+
return n.empty ? ["", name] : [n.name, ""];
|
|
63
|
+
}
|
|
64
|
+
const type = name.substring(tonic.name.length + 1);
|
|
65
|
+
return [tonic.name, type.length ? type : ""];
|
|
66
|
+
}
|
|
67
|
+
var names = import_scale_type.names;
|
|
68
|
+
function get(src) {
|
|
69
|
+
const tokens = Array.isArray(src) ? src : tokenize(src);
|
|
70
|
+
const tonic = (0, import_core.note)(tokens[0]).name;
|
|
71
|
+
const st = (0, import_scale_type.get)(tokens[1]);
|
|
72
|
+
if (st.empty) {
|
|
73
|
+
return NoScale;
|
|
74
|
+
}
|
|
75
|
+
const type = st.name;
|
|
76
|
+
const notes = tonic ? st.intervals.map((i) => (0, import_core.transpose)(tonic, i)) : [];
|
|
77
|
+
const name = tonic ? tonic + " " + type : type;
|
|
78
|
+
return { ...st, name, type, tonic, notes };
|
|
79
|
+
}
|
|
80
|
+
var scale = (0, import_core.deprecate)("Scale.scale", "Scale.get", get);
|
|
81
|
+
function scaleChords(name) {
|
|
82
|
+
const s = get(name);
|
|
83
|
+
const inScale = (0, import_pcset.isSubsetOf)(s.chroma);
|
|
84
|
+
return (0, import_chord_type.all)().filter((chord) => inScale(chord.chroma)).map((chord) => chord.aliases[0]);
|
|
85
|
+
}
|
|
86
|
+
function extended(name) {
|
|
87
|
+
const s = get(name);
|
|
88
|
+
const isSuperset = (0, import_pcset.isSupersetOf)(s.chroma);
|
|
89
|
+
return (0, import_scale_type.all)().filter((scale2) => isSuperset(scale2.chroma)).map((scale2) => scale2.name);
|
|
90
|
+
}
|
|
91
|
+
function reduced(name) {
|
|
92
|
+
const isSubset = (0, import_pcset.isSubsetOf)(get(name).chroma);
|
|
93
|
+
return (0, import_scale_type.all)().filter((scale2) => isSubset(scale2.chroma)).map((scale2) => scale2.name);
|
|
94
|
+
}
|
|
95
|
+
function scaleNotes(notes) {
|
|
96
|
+
const pcset = notes.map((n) => (0, import_core.note)(n).pc).filter((x) => x);
|
|
97
|
+
const tonic = pcset[0];
|
|
98
|
+
const scale2 = (0, import_note.sortedUniqNames)(pcset);
|
|
99
|
+
return (0, import_collection.rotate)(scale2.indexOf(tonic), scale2);
|
|
100
|
+
}
|
|
101
|
+
function modeNames(name) {
|
|
102
|
+
const s = get(name);
|
|
103
|
+
if (s.empty) {
|
|
104
|
+
return [];
|
|
105
|
+
}
|
|
106
|
+
const tonics = s.tonic ? s.notes : s.intervals;
|
|
107
|
+
return (0, import_pcset.modes)(s.chroma).map((chroma, i) => {
|
|
108
|
+
const modeName = get(chroma).name;
|
|
109
|
+
return modeName ? [tonics[i], modeName] : ["", ""];
|
|
110
|
+
}).filter((x) => x[0]);
|
|
111
|
+
}
|
|
112
|
+
function getNoteNameOf(scale2) {
|
|
113
|
+
const names2 = Array.isArray(scale2) ? scaleNotes(scale2) : get(scale2).notes;
|
|
114
|
+
const chromas = names2.map((name) => (0, import_core.note)(name).chroma);
|
|
115
|
+
return (noteOrMidi) => {
|
|
116
|
+
const currNote = typeof noteOrMidi === "number" ? (0, import_core.note)((0, import_note.fromMidi)(noteOrMidi)) : (0, import_core.note)(noteOrMidi);
|
|
117
|
+
const height = currNote.height;
|
|
118
|
+
if (height === void 0)
|
|
119
|
+
return void 0;
|
|
120
|
+
const chroma = height % 12;
|
|
121
|
+
const position = chromas.indexOf(chroma);
|
|
122
|
+
if (position === -1)
|
|
123
|
+
return void 0;
|
|
124
|
+
return (0, import_note.enharmonic)(currNote.name, names2[position]);
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
function rangeOf(scale2) {
|
|
128
|
+
const getName = getNoteNameOf(scale2);
|
|
129
|
+
return (fromNote, toNote) => {
|
|
130
|
+
const from = (0, import_core.note)(fromNote).height;
|
|
131
|
+
const to = (0, import_core.note)(toNote).height;
|
|
132
|
+
if (from === void 0 || to === void 0)
|
|
133
|
+
return [];
|
|
134
|
+
return (0, import_collection.range)(from, to).map(getName).filter((x) => x);
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
var scale_default = {
|
|
138
|
+
get,
|
|
139
|
+
names,
|
|
140
|
+
extended,
|
|
141
|
+
modeNames,
|
|
142
|
+
reduced,
|
|
143
|
+
scaleChords,
|
|
144
|
+
scaleNotes,
|
|
145
|
+
tokenize,
|
|
146
|
+
rangeOf,
|
|
147
|
+
scale
|
|
148
|
+
};
|
|
149
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
150
|
+
0 && (module.exports = {
|
|
151
|
+
extended,
|
|
152
|
+
get,
|
|
153
|
+
modeNames,
|
|
154
|
+
names,
|
|
155
|
+
rangeOf,
|
|
156
|
+
reduced,
|
|
157
|
+
scale,
|
|
158
|
+
scaleChords,
|
|
159
|
+
scaleNotes,
|
|
160
|
+
tokenize
|
|
161
|
+
});
|
|
162
|
+
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
1
|
+
{"version":3,"sources":["../index.ts"],"sourcesContent":["/**\n * References:\n * - https://www.researchgate.net/publication/327567188_An_Algorithm_for_Spelling_the_Pitches_of_Any_Musical_Scale\n * @module scale\n */\nimport { all as chordTypes } from \"@tonaljs/chord-type\";\nimport { rotate, range as nums } from \"@tonaljs/collection\";\nimport { deprecate, note, NoteName, transpose } from \"@tonaljs/core\";\nimport { sortedUniqNames, fromMidi, enharmonic } from \"@tonaljs/note\";\nimport { isSubsetOf, isSupersetOf, modes } from \"@tonaljs/pcset\";\nimport {\n all as scaleTypes,\n get as getScaleType,\n names as scaleTypeNames,\n ScaleType,\n} from \"@tonaljs/scale-type\";\n\ntype ScaleName = string;\ntype ScaleNameTokens = [string, string]; // [TONIC, SCALE TYPE]\n\nexport interface Scale extends ScaleType {\n tonic: string | null;\n type: string;\n notes: NoteName[];\n}\n\nconst NoScale: Scale = {\n empty: true,\n name: \"\",\n type: \"\",\n tonic: null,\n setNum: NaN,\n chroma: \"\",\n normalized: \"\",\n aliases: [],\n notes: [],\n intervals: [],\n};\n\n/**\n * Given a string with a scale name and (optionally) a tonic, split\n * that components.\n *\n * It retuns an array with the form [ name, tonic ] where tonic can be a\n * note name or null and name can be any arbitrary string\n * (this function doesn\"t check if that scale name exists)\n *\n * @function\n * @param {string} name - the scale name\n * @return {Array} an array [tonic, name]\n * @example\n * tokenize(\"C mixolydean\") // => [\"C\", \"mixolydean\"]\n * tokenize(\"anything is valid\") // => [\"\", \"anything is valid\"]\n * tokenize() // => [\"\", \"\"]\n */\nexport function tokenize(name: ScaleName): ScaleNameTokens {\n if (typeof name !== \"string\") {\n return [\"\", \"\"];\n }\n const i = name.indexOf(\" \");\n const tonic = note(name.substring(0, i));\n if (tonic.empty) {\n const n = note(name);\n return n.empty ? [\"\", name] : [n.name, \"\"];\n }\n\n const type = name.substring(tonic.name.length + 1);\n return [tonic.name, type.length ? type : \"\"];\n}\n\n/**\n * Get all scale names\n * @function\n */\nexport const names = scaleTypeNames;\n\n/**\n * Get a Scale from a scale name.\n */\nexport function get(src: ScaleName | ScaleNameTokens): Scale {\n const tokens = Array.isArray(src) ? src : tokenize(src);\n const tonic = note(tokens[0]).name;\n const st = getScaleType(tokens[1]);\n if (st.empty) {\n return NoScale;\n }\n\n const type = st.name;\n const notes: string[] = tonic\n ? st.intervals.map((i) => transpose(tonic, i))\n : [];\n\n const name = tonic ? tonic + \" \" + type : type;\n\n return { ...st, name, type, tonic, notes };\n}\n\nexport const scale = deprecate(\"Scale.scale\", \"Scale.get\", get);\n\n/**\n * Get all chords that fits a given scale\n *\n * @function\n * @param {string} name - the scale name\n * @return {Array<string>} - the chord names\n *\n * @example\n * scaleChords(\"pentatonic\") // => [\"5\", \"64\", \"M\", \"M6\", \"Madd9\", \"Msus2\"]\n */\nexport function scaleChords(name: string): string[] {\n const s = get(name);\n const inScale = isSubsetOf(s.chroma);\n return chordTypes()\n .filter((chord) => inScale(chord.chroma))\n .map((chord) => chord.aliases[0]);\n}\n/**\n * Get all scales names that are a superset of the given one\n * (has the same notes and at least one more)\n *\n * @function\n * @param {string} name\n * @return {Array} a list of scale names\n * @example\n * extended(\"major\") // => [\"bebop\", \"bebop dominant\", \"bebop major\", \"chromatic\", \"ichikosucho\"]\n */\nexport function extended(name: string): string[] {\n const s = get(name);\n const isSuperset = isSupersetOf(s.chroma);\n return scaleTypes()\n .filter((scale) => isSuperset(scale.chroma))\n .map((scale) => scale.name);\n}\n\n/**\n * Find all scales names that are a subset of the given one\n * (has less notes but all from the given scale)\n *\n * @function\n * @param {string} name\n * @return {Array} a list of scale names\n *\n * @example\n * reduced(\"major\") // => [\"ionian pentatonic\", \"major pentatonic\", \"ritusen\"]\n */\nexport function reduced(name: string): string[] {\n const isSubset = isSubsetOf(get(name).chroma);\n return scaleTypes()\n .filter((scale) => isSubset(scale.chroma))\n .map((scale) => scale.name);\n}\n\n/**\n * Given an array of notes, return the scale: a pitch class set starting from\n * the first note of the array\n *\n * @function\n * @param {string[]} notes\n * @return {string[]} pitch classes with same tonic\n * @example\n * scaleNotes(['C4', 'c3', 'C5', 'C4', 'c4']) // => [\"C\"]\n * scaleNotes(['D4', 'c#5', 'A5', 'F#6']) // => [\"D\", \"F#\", \"A\", \"C#\"]\n */\nexport function scaleNotes(notes: NoteName[]) {\n const pcset: string[] = notes.map((n) => note(n).pc).filter((x) => x);\n const tonic = pcset[0];\n const scale = sortedUniqNames(pcset);\n return rotate(scale.indexOf(tonic), scale);\n}\n\ntype ScaleMode = [string, string];\n/**\n * Find mode names of a scale\n *\n * @function\n * @param {string} name - scale name\n * @example\n * modeNames(\"C pentatonic\") // => [\n * [\"C\", \"major pentatonic\"],\n * [\"D\", \"egyptian\"],\n * [\"E\", \"malkos raga\"],\n * [\"G\", \"ritusen\"],\n * [\"A\", \"minor pentatonic\"]\n * ]\n */\nexport function modeNames(name: string): ScaleMode[] {\n const s = get(name);\n if (s.empty) {\n return [];\n }\n\n const tonics = s.tonic ? s.notes : s.intervals;\n return modes(s.chroma)\n .map((chroma: string, i: number): ScaleMode => {\n const modeName = get(chroma).name;\n return modeName ? [tonics[i], modeName] : [\"\", \"\"];\n })\n .filter((x) => x[0]);\n}\n\nfunction getNoteNameOf(scale: string | string[]) {\n const names = Array.isArray(scale) ? scaleNotes(scale) : get(scale).notes;\n const chromas = names.map((name) => note(name).chroma);\n\n return (noteOrMidi: string | number): string | undefined => {\n const currNote =\n typeof noteOrMidi === \"number\"\n ? note(fromMidi(noteOrMidi))\n : note(noteOrMidi);\n const height = currNote.height;\n\n if (height === undefined) return undefined;\n const chroma = height % 12;\n const position = chromas.indexOf(chroma);\n if (position === -1) return undefined;\n return enharmonic(currNote.name, names[position]);\n };\n}\n\nexport function rangeOf(scale: string | string[]) {\n const getName = getNoteNameOf(scale);\n return (fromNote: string, toNote: string) => {\n const from = note(fromNote).height;\n const to = note(toNote).height;\n if (from === undefined || to === undefined) return [];\n\n return nums(from, to)\n .map(getName)\n .filter((x) => x);\n };\n}\n\nexport default {\n get,\n names,\n extended,\n modeNames,\n reduced,\n scaleChords,\n scaleNotes,\n tokenize,\n rangeOf,\n // deprecated\n scale,\n};\n"],"mappings":"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","names":["scaleTypeNames","getScaleType","chordTypes","scaleTypes","scale","names","nums"]}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
// index.ts
|
|
2
|
+
import { all as chordTypes } from "@tonaljs/chord-type";
|
|
3
|
+
import { rotate, range as nums } from "@tonaljs/collection";
|
|
4
|
+
import { deprecate, note, transpose } from "@tonaljs/core";
|
|
5
|
+
import { sortedUniqNames, fromMidi, enharmonic } from "@tonaljs/note";
|
|
6
|
+
import { isSubsetOf, isSupersetOf, modes } from "@tonaljs/pcset";
|
|
7
|
+
import {
|
|
8
|
+
all as scaleTypes,
|
|
9
|
+
get as getScaleType,
|
|
10
|
+
names as scaleTypeNames
|
|
11
|
+
} from "@tonaljs/scale-type";
|
|
12
|
+
var NoScale = {
|
|
13
|
+
empty: true,
|
|
14
|
+
name: "",
|
|
15
|
+
type: "",
|
|
16
|
+
tonic: null,
|
|
17
|
+
setNum: NaN,
|
|
18
|
+
chroma: "",
|
|
19
|
+
normalized: "",
|
|
20
|
+
aliases: [],
|
|
21
|
+
notes: [],
|
|
22
|
+
intervals: []
|
|
23
|
+
};
|
|
24
|
+
function tokenize(name) {
|
|
25
|
+
if (typeof name !== "string") {
|
|
26
|
+
return ["", ""];
|
|
27
|
+
}
|
|
28
|
+
const i = name.indexOf(" ");
|
|
29
|
+
const tonic = note(name.substring(0, i));
|
|
30
|
+
if (tonic.empty) {
|
|
31
|
+
const n = note(name);
|
|
32
|
+
return n.empty ? ["", name] : [n.name, ""];
|
|
33
|
+
}
|
|
34
|
+
const type = name.substring(tonic.name.length + 1);
|
|
35
|
+
return [tonic.name, type.length ? type : ""];
|
|
36
|
+
}
|
|
37
|
+
var names = scaleTypeNames;
|
|
38
|
+
function get(src) {
|
|
39
|
+
const tokens = Array.isArray(src) ? src : tokenize(src);
|
|
40
|
+
const tonic = note(tokens[0]).name;
|
|
41
|
+
const st = getScaleType(tokens[1]);
|
|
42
|
+
if (st.empty) {
|
|
43
|
+
return NoScale;
|
|
44
|
+
}
|
|
45
|
+
const type = st.name;
|
|
46
|
+
const notes = tonic ? st.intervals.map((i) => transpose(tonic, i)) : [];
|
|
47
|
+
const name = tonic ? tonic + " " + type : type;
|
|
48
|
+
return { ...st, name, type, tonic, notes };
|
|
49
|
+
}
|
|
50
|
+
var scale = deprecate("Scale.scale", "Scale.get", get);
|
|
51
|
+
function scaleChords(name) {
|
|
52
|
+
const s = get(name);
|
|
53
|
+
const inScale = isSubsetOf(s.chroma);
|
|
54
|
+
return chordTypes().filter((chord) => inScale(chord.chroma)).map((chord) => chord.aliases[0]);
|
|
55
|
+
}
|
|
56
|
+
function extended(name) {
|
|
57
|
+
const s = get(name);
|
|
58
|
+
const isSuperset = isSupersetOf(s.chroma);
|
|
59
|
+
return scaleTypes().filter((scale2) => isSuperset(scale2.chroma)).map((scale2) => scale2.name);
|
|
60
|
+
}
|
|
61
|
+
function reduced(name) {
|
|
62
|
+
const isSubset = isSubsetOf(get(name).chroma);
|
|
63
|
+
return scaleTypes().filter((scale2) => isSubset(scale2.chroma)).map((scale2) => scale2.name);
|
|
64
|
+
}
|
|
65
|
+
function scaleNotes(notes) {
|
|
66
|
+
const pcset = notes.map((n) => note(n).pc).filter((x) => x);
|
|
67
|
+
const tonic = pcset[0];
|
|
68
|
+
const scale2 = sortedUniqNames(pcset);
|
|
69
|
+
return rotate(scale2.indexOf(tonic), scale2);
|
|
70
|
+
}
|
|
71
|
+
function modeNames(name) {
|
|
72
|
+
const s = get(name);
|
|
73
|
+
if (s.empty) {
|
|
74
|
+
return [];
|
|
75
|
+
}
|
|
76
|
+
const tonics = s.tonic ? s.notes : s.intervals;
|
|
77
|
+
return modes(s.chroma).map((chroma, i) => {
|
|
78
|
+
const modeName = get(chroma).name;
|
|
79
|
+
return modeName ? [tonics[i], modeName] : ["", ""];
|
|
80
|
+
}).filter((x) => x[0]);
|
|
81
|
+
}
|
|
82
|
+
function getNoteNameOf(scale2) {
|
|
83
|
+
const names2 = Array.isArray(scale2) ? scaleNotes(scale2) : get(scale2).notes;
|
|
84
|
+
const chromas = names2.map((name) => note(name).chroma);
|
|
85
|
+
return (noteOrMidi) => {
|
|
86
|
+
const currNote = typeof noteOrMidi === "number" ? note(fromMidi(noteOrMidi)) : note(noteOrMidi);
|
|
87
|
+
const height = currNote.height;
|
|
88
|
+
if (height === void 0)
|
|
89
|
+
return void 0;
|
|
90
|
+
const chroma = height % 12;
|
|
91
|
+
const position = chromas.indexOf(chroma);
|
|
92
|
+
if (position === -1)
|
|
93
|
+
return void 0;
|
|
94
|
+
return enharmonic(currNote.name, names2[position]);
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
function rangeOf(scale2) {
|
|
98
|
+
const getName = getNoteNameOf(scale2);
|
|
99
|
+
return (fromNote, toNote) => {
|
|
100
|
+
const from = note(fromNote).height;
|
|
101
|
+
const to = note(toNote).height;
|
|
102
|
+
if (from === void 0 || to === void 0)
|
|
103
|
+
return [];
|
|
104
|
+
return nums(from, to).map(getName).filter((x) => x);
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
var scale_default = {
|
|
108
|
+
get,
|
|
109
|
+
names,
|
|
110
|
+
extended,
|
|
111
|
+
modeNames,
|
|
112
|
+
reduced,
|
|
113
|
+
scaleChords,
|
|
114
|
+
scaleNotes,
|
|
115
|
+
tokenize,
|
|
116
|
+
rangeOf,
|
|
117
|
+
scale
|
|
118
|
+
};
|
|
119
|
+
export {
|
|
120
|
+
scale_default as default,
|
|
121
|
+
extended,
|
|
122
|
+
get,
|
|
123
|
+
modeNames,
|
|
124
|
+
names,
|
|
125
|
+
rangeOf,
|
|
126
|
+
reduced,
|
|
127
|
+
scale,
|
|
128
|
+
scaleChords,
|
|
129
|
+
scaleNotes,
|
|
130
|
+
tokenize
|
|
131
|
+
};
|
|
132
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../index.ts"],"sourcesContent":["/**\n * References:\n * - https://www.researchgate.net/publication/327567188_An_Algorithm_for_Spelling_the_Pitches_of_Any_Musical_Scale\n * @module scale\n */\nimport { all as chordTypes } from \"@tonaljs/chord-type\";\nimport { rotate, range as nums } from \"@tonaljs/collection\";\nimport { deprecate, note, NoteName, transpose } from \"@tonaljs/core\";\nimport { sortedUniqNames, fromMidi, enharmonic } from \"@tonaljs/note\";\nimport { isSubsetOf, isSupersetOf, modes } from \"@tonaljs/pcset\";\nimport {\n all as scaleTypes,\n get as getScaleType,\n names as scaleTypeNames,\n ScaleType,\n} from \"@tonaljs/scale-type\";\n\ntype ScaleName = string;\ntype ScaleNameTokens = [string, string]; // [TONIC, SCALE TYPE]\n\nexport interface Scale extends ScaleType {\n tonic: string | null;\n type: string;\n notes: NoteName[];\n}\n\nconst NoScale: Scale = {\n empty: true,\n name: \"\",\n type: \"\",\n tonic: null,\n setNum: NaN,\n chroma: \"\",\n normalized: \"\",\n aliases: [],\n notes: [],\n intervals: [],\n};\n\n/**\n * Given a string with a scale name and (optionally) a tonic, split\n * that components.\n *\n * It retuns an array with the form [ name, tonic ] where tonic can be a\n * note name or null and name can be any arbitrary string\n * (this function doesn\"t check if that scale name exists)\n *\n * @function\n * @param {string} name - the scale name\n * @return {Array} an array [tonic, name]\n * @example\n * tokenize(\"C mixolydean\") // => [\"C\", \"mixolydean\"]\n * tokenize(\"anything is valid\") // => [\"\", \"anything is valid\"]\n * tokenize() // => [\"\", \"\"]\n */\nexport function tokenize(name: ScaleName): ScaleNameTokens {\n if (typeof name !== \"string\") {\n return [\"\", \"\"];\n }\n const i = name.indexOf(\" \");\n const tonic = note(name.substring(0, i));\n if (tonic.empty) {\n const n = note(name);\n return n.empty ? [\"\", name] : [n.name, \"\"];\n }\n\n const type = name.substring(tonic.name.length + 1);\n return [tonic.name, type.length ? type : \"\"];\n}\n\n/**\n * Get all scale names\n * @function\n */\nexport const names = scaleTypeNames;\n\n/**\n * Get a Scale from a scale name.\n */\nexport function get(src: ScaleName | ScaleNameTokens): Scale {\n const tokens = Array.isArray(src) ? src : tokenize(src);\n const tonic = note(tokens[0]).name;\n const st = getScaleType(tokens[1]);\n if (st.empty) {\n return NoScale;\n }\n\n const type = st.name;\n const notes: string[] = tonic\n ? st.intervals.map((i) => transpose(tonic, i))\n : [];\n\n const name = tonic ? tonic + \" \" + type : type;\n\n return { ...st, name, type, tonic, notes };\n}\n\nexport const scale = deprecate(\"Scale.scale\", \"Scale.get\", get);\n\n/**\n * Get all chords that fits a given scale\n *\n * @function\n * @param {string} name - the scale name\n * @return {Array<string>} - the chord names\n *\n * @example\n * scaleChords(\"pentatonic\") // => [\"5\", \"64\", \"M\", \"M6\", \"Madd9\", \"Msus2\"]\n */\nexport function scaleChords(name: string): string[] {\n const s = get(name);\n const inScale = isSubsetOf(s.chroma);\n return chordTypes()\n .filter((chord) => inScale(chord.chroma))\n .map((chord) => chord.aliases[0]);\n}\n/**\n * Get all scales names that are a superset of the given one\n * (has the same notes and at least one more)\n *\n * @function\n * @param {string} name\n * @return {Array} a list of scale names\n * @example\n * extended(\"major\") // => [\"bebop\", \"bebop dominant\", \"bebop major\", \"chromatic\", \"ichikosucho\"]\n */\nexport function extended(name: string): string[] {\n const s = get(name);\n const isSuperset = isSupersetOf(s.chroma);\n return scaleTypes()\n .filter((scale) => isSuperset(scale.chroma))\n .map((scale) => scale.name);\n}\n\n/**\n * Find all scales names that are a subset of the given one\n * (has less notes but all from the given scale)\n *\n * @function\n * @param {string} name\n * @return {Array} a list of scale names\n *\n * @example\n * reduced(\"major\") // => [\"ionian pentatonic\", \"major pentatonic\", \"ritusen\"]\n */\nexport function reduced(name: string): string[] {\n const isSubset = isSubsetOf(get(name).chroma);\n return scaleTypes()\n .filter((scale) => isSubset(scale.chroma))\n .map((scale) => scale.name);\n}\n\n/**\n * Given an array of notes, return the scale: a pitch class set starting from\n * the first note of the array\n *\n * @function\n * @param {string[]} notes\n * @return {string[]} pitch classes with same tonic\n * @example\n * scaleNotes(['C4', 'c3', 'C5', 'C4', 'c4']) // => [\"C\"]\n * scaleNotes(['D4', 'c#5', 'A5', 'F#6']) // => [\"D\", \"F#\", \"A\", \"C#\"]\n */\nexport function scaleNotes(notes: NoteName[]) {\n const pcset: string[] = notes.map((n) => note(n).pc).filter((x) => x);\n const tonic = pcset[0];\n const scale = sortedUniqNames(pcset);\n return rotate(scale.indexOf(tonic), scale);\n}\n\ntype ScaleMode = [string, string];\n/**\n * Find mode names of a scale\n *\n * @function\n * @param {string} name - scale name\n * @example\n * modeNames(\"C pentatonic\") // => [\n * [\"C\", \"major pentatonic\"],\n * [\"D\", \"egyptian\"],\n * [\"E\", \"malkos raga\"],\n * [\"G\", \"ritusen\"],\n * [\"A\", \"minor pentatonic\"]\n * ]\n */\nexport function modeNames(name: string): ScaleMode[] {\n const s = get(name);\n if (s.empty) {\n return [];\n }\n\n const tonics = s.tonic ? s.notes : s.intervals;\n return modes(s.chroma)\n .map((chroma: string, i: number): ScaleMode => {\n const modeName = get(chroma).name;\n return modeName ? [tonics[i], modeName] : [\"\", \"\"];\n })\n .filter((x) => x[0]);\n}\n\nfunction getNoteNameOf(scale: string | string[]) {\n const names = Array.isArray(scale) ? scaleNotes(scale) : get(scale).notes;\n const chromas = names.map((name) => note(name).chroma);\n\n return (noteOrMidi: string | number): string | undefined => {\n const currNote =\n typeof noteOrMidi === \"number\"\n ? note(fromMidi(noteOrMidi))\n : note(noteOrMidi);\n const height = currNote.height;\n\n if (height === undefined) return undefined;\n const chroma = height % 12;\n const position = chromas.indexOf(chroma);\n if (position === -1) return undefined;\n return enharmonic(currNote.name, names[position]);\n };\n}\n\nexport function rangeOf(scale: string | string[]) {\n const getName = getNoteNameOf(scale);\n return (fromNote: string, toNote: string) => {\n const from = note(fromNote).height;\n const to = note(toNote).height;\n if (from === undefined || to === undefined) return [];\n\n return nums(from, to)\n .map(getName)\n .filter((x) => x);\n };\n}\n\nexport default {\n get,\n names,\n extended,\n modeNames,\n reduced,\n scaleChords,\n scaleNotes,\n tokenize,\n rangeOf,\n // deprecated\n scale,\n};\n"],"mappings":"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","names":["scale","names"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tonaljs/scale",
|
|
3
|
-
"version": "4.6.
|
|
3
|
+
"version": "4.6.10",
|
|
4
4
|
"description": "Musical scales and its relations",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"scale",
|
|
@@ -10,23 +10,25 @@
|
|
|
10
10
|
"@tonaljs"
|
|
11
11
|
],
|
|
12
12
|
"main": "dist/index.js",
|
|
13
|
-
"module": "dist/index.
|
|
13
|
+
"module": "dist/index.mjs",
|
|
14
14
|
"files": [
|
|
15
15
|
"dist"
|
|
16
16
|
],
|
|
17
17
|
"types": "dist/index.d.ts",
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"@tonaljs/chord-type": "^4.6.
|
|
20
|
-
"@tonaljs/collection": "^4.6.
|
|
21
|
-
"@tonaljs/core": "^4.6.
|
|
22
|
-
"@tonaljs/note": "^4.6.
|
|
23
|
-
"@tonaljs/pcset": "^4.6.
|
|
24
|
-
"@tonaljs/scale-type": "^4.6.
|
|
19
|
+
"@tonaljs/chord-type": "^4.6.10",
|
|
20
|
+
"@tonaljs/collection": "^4.6.10",
|
|
21
|
+
"@tonaljs/core": "^4.6.10",
|
|
22
|
+
"@tonaljs/note": "^4.6.10",
|
|
23
|
+
"@tonaljs/pcset": "^4.6.10",
|
|
24
|
+
"@tonaljs/scale-type": "^4.6.10"
|
|
25
25
|
},
|
|
26
26
|
"author": "danigb@gmail.com",
|
|
27
27
|
"license": "MIT",
|
|
28
28
|
"publishConfig": {
|
|
29
29
|
"access": "public"
|
|
30
30
|
},
|
|
31
|
-
"
|
|
31
|
+
"scripts": {
|
|
32
|
+
"build": "tsup index.ts --sourcemap --dts --format esm,cjs"
|
|
33
|
+
}
|
|
32
34
|
}
|
package/dist/index.es.js
DELETED
|
@@ -1,216 +0,0 @@
|
|
|
1
|
-
import { all } from '@tonaljs/chord-type';
|
|
2
|
-
import { rotate, range } from '@tonaljs/collection';
|
|
3
|
-
import { deprecate, note, transpose } from '@tonaljs/core';
|
|
4
|
-
import { sortedUniqNames, fromMidi, enharmonic } from '@tonaljs/note';
|
|
5
|
-
import { isSubsetOf, isSupersetOf, modes } from '@tonaljs/pcset';
|
|
6
|
-
import { names as names$1, get as get$1, all as all$1 } from '@tonaljs/scale-type';
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* References:
|
|
10
|
-
* - https://www.researchgate.net/publication/327567188_An_Algorithm_for_Spelling_the_Pitches_of_Any_Musical_Scale
|
|
11
|
-
* @module scale
|
|
12
|
-
*/
|
|
13
|
-
const NoScale = {
|
|
14
|
-
empty: true,
|
|
15
|
-
name: "",
|
|
16
|
-
type: "",
|
|
17
|
-
tonic: null,
|
|
18
|
-
setNum: NaN,
|
|
19
|
-
chroma: "",
|
|
20
|
-
normalized: "",
|
|
21
|
-
aliases: [],
|
|
22
|
-
notes: [],
|
|
23
|
-
intervals: [],
|
|
24
|
-
};
|
|
25
|
-
/**
|
|
26
|
-
* Given a string with a scale name and (optionally) a tonic, split
|
|
27
|
-
* that components.
|
|
28
|
-
*
|
|
29
|
-
* It retuns an array with the form [ name, tonic ] where tonic can be a
|
|
30
|
-
* note name or null and name can be any arbitrary string
|
|
31
|
-
* (this function doesn"t check if that scale name exists)
|
|
32
|
-
*
|
|
33
|
-
* @function
|
|
34
|
-
* @param {string} name - the scale name
|
|
35
|
-
* @return {Array} an array [tonic, name]
|
|
36
|
-
* @example
|
|
37
|
-
* tokenize("C mixolydean") // => ["C", "mixolydean"]
|
|
38
|
-
* tokenize("anything is valid") // => ["", "anything is valid"]
|
|
39
|
-
* tokenize() // => ["", ""]
|
|
40
|
-
*/
|
|
41
|
-
function tokenize(name) {
|
|
42
|
-
if (typeof name !== "string") {
|
|
43
|
-
return ["", ""];
|
|
44
|
-
}
|
|
45
|
-
const i = name.indexOf(" ");
|
|
46
|
-
const tonic = note(name.substring(0, i));
|
|
47
|
-
if (tonic.empty) {
|
|
48
|
-
const n = note(name);
|
|
49
|
-
return n.empty ? ["", name] : [n.name, ""];
|
|
50
|
-
}
|
|
51
|
-
const type = name.substring(tonic.name.length + 1);
|
|
52
|
-
return [tonic.name, type.length ? type : ""];
|
|
53
|
-
}
|
|
54
|
-
/**
|
|
55
|
-
* Get all scale names
|
|
56
|
-
* @function
|
|
57
|
-
*/
|
|
58
|
-
const names = names$1;
|
|
59
|
-
/**
|
|
60
|
-
* Get a Scale from a scale name.
|
|
61
|
-
*/
|
|
62
|
-
function get(src) {
|
|
63
|
-
const tokens = Array.isArray(src) ? src : tokenize(src);
|
|
64
|
-
const tonic = note(tokens[0]).name;
|
|
65
|
-
const st = get$1(tokens[1]);
|
|
66
|
-
if (st.empty) {
|
|
67
|
-
return NoScale;
|
|
68
|
-
}
|
|
69
|
-
const type = st.name;
|
|
70
|
-
const notes = tonic
|
|
71
|
-
? st.intervals.map((i) => transpose(tonic, i))
|
|
72
|
-
: [];
|
|
73
|
-
const name = tonic ? tonic + " " + type : type;
|
|
74
|
-
return { ...st, name, type, tonic, notes };
|
|
75
|
-
}
|
|
76
|
-
const scale = deprecate("Scale.scale", "Scale.get", get);
|
|
77
|
-
/**
|
|
78
|
-
* Get all chords that fits a given scale
|
|
79
|
-
*
|
|
80
|
-
* @function
|
|
81
|
-
* @param {string} name - the scale name
|
|
82
|
-
* @return {Array<string>} - the chord names
|
|
83
|
-
*
|
|
84
|
-
* @example
|
|
85
|
-
* scaleChords("pentatonic") // => ["5", "64", "M", "M6", "Madd9", "Msus2"]
|
|
86
|
-
*/
|
|
87
|
-
function scaleChords(name) {
|
|
88
|
-
const s = get(name);
|
|
89
|
-
const inScale = isSubsetOf(s.chroma);
|
|
90
|
-
return all()
|
|
91
|
-
.filter((chord) => inScale(chord.chroma))
|
|
92
|
-
.map((chord) => chord.aliases[0]);
|
|
93
|
-
}
|
|
94
|
-
/**
|
|
95
|
-
* Get all scales names that are a superset of the given one
|
|
96
|
-
* (has the same notes and at least one more)
|
|
97
|
-
*
|
|
98
|
-
* @function
|
|
99
|
-
* @param {string} name
|
|
100
|
-
* @return {Array} a list of scale names
|
|
101
|
-
* @example
|
|
102
|
-
* extended("major") // => ["bebop", "bebop dominant", "bebop major", "chromatic", "ichikosucho"]
|
|
103
|
-
*/
|
|
104
|
-
function extended(name) {
|
|
105
|
-
const s = get(name);
|
|
106
|
-
const isSuperset = isSupersetOf(s.chroma);
|
|
107
|
-
return all$1()
|
|
108
|
-
.filter((scale) => isSuperset(scale.chroma))
|
|
109
|
-
.map((scale) => scale.name);
|
|
110
|
-
}
|
|
111
|
-
/**
|
|
112
|
-
* Find all scales names that are a subset of the given one
|
|
113
|
-
* (has less notes but all from the given scale)
|
|
114
|
-
*
|
|
115
|
-
* @function
|
|
116
|
-
* @param {string} name
|
|
117
|
-
* @return {Array} a list of scale names
|
|
118
|
-
*
|
|
119
|
-
* @example
|
|
120
|
-
* reduced("major") // => ["ionian pentatonic", "major pentatonic", "ritusen"]
|
|
121
|
-
*/
|
|
122
|
-
function reduced(name) {
|
|
123
|
-
const isSubset = isSubsetOf(get(name).chroma);
|
|
124
|
-
return all$1()
|
|
125
|
-
.filter((scale) => isSubset(scale.chroma))
|
|
126
|
-
.map((scale) => scale.name);
|
|
127
|
-
}
|
|
128
|
-
/**
|
|
129
|
-
* Given an array of notes, return the scale: a pitch class set starting from
|
|
130
|
-
* the first note of the array
|
|
131
|
-
*
|
|
132
|
-
* @function
|
|
133
|
-
* @param {string[]} notes
|
|
134
|
-
* @return {string[]} pitch classes with same tonic
|
|
135
|
-
* @example
|
|
136
|
-
* scaleNotes(['C4', 'c3', 'C5', 'C4', 'c4']) // => ["C"]
|
|
137
|
-
* scaleNotes(['D4', 'c#5', 'A5', 'F#6']) // => ["D", "F#", "A", "C#"]
|
|
138
|
-
*/
|
|
139
|
-
function scaleNotes(notes) {
|
|
140
|
-
const pcset = notes.map((n) => note(n).pc).filter((x) => x);
|
|
141
|
-
const tonic = pcset[0];
|
|
142
|
-
const scale = sortedUniqNames(pcset);
|
|
143
|
-
return rotate(scale.indexOf(tonic), scale);
|
|
144
|
-
}
|
|
145
|
-
/**
|
|
146
|
-
* Find mode names of a scale
|
|
147
|
-
*
|
|
148
|
-
* @function
|
|
149
|
-
* @param {string} name - scale name
|
|
150
|
-
* @example
|
|
151
|
-
* modeNames("C pentatonic") // => [
|
|
152
|
-
* ["C", "major pentatonic"],
|
|
153
|
-
* ["D", "egyptian"],
|
|
154
|
-
* ["E", "malkos raga"],
|
|
155
|
-
* ["G", "ritusen"],
|
|
156
|
-
* ["A", "minor pentatonic"]
|
|
157
|
-
* ]
|
|
158
|
-
*/
|
|
159
|
-
function modeNames(name) {
|
|
160
|
-
const s = get(name);
|
|
161
|
-
if (s.empty) {
|
|
162
|
-
return [];
|
|
163
|
-
}
|
|
164
|
-
const tonics = s.tonic ? s.notes : s.intervals;
|
|
165
|
-
return modes(s.chroma)
|
|
166
|
-
.map((chroma, i) => {
|
|
167
|
-
const modeName = get(chroma).name;
|
|
168
|
-
return modeName ? [tonics[i], modeName] : ["", ""];
|
|
169
|
-
})
|
|
170
|
-
.filter((x) => x[0]);
|
|
171
|
-
}
|
|
172
|
-
function getNoteNameOf(scale) {
|
|
173
|
-
const names = Array.isArray(scale) ? scaleNotes(scale) : get(scale).notes;
|
|
174
|
-
const chromas = names.map((name) => note(name).chroma);
|
|
175
|
-
return (noteOrMidi) => {
|
|
176
|
-
const currNote = typeof noteOrMidi === "number"
|
|
177
|
-
? note(fromMidi(noteOrMidi))
|
|
178
|
-
: note(noteOrMidi);
|
|
179
|
-
const height = currNote.height;
|
|
180
|
-
if (height === undefined)
|
|
181
|
-
return undefined;
|
|
182
|
-
const chroma = height % 12;
|
|
183
|
-
const position = chromas.indexOf(chroma);
|
|
184
|
-
if (position === -1)
|
|
185
|
-
return undefined;
|
|
186
|
-
return enharmonic(currNote.name, names[position]);
|
|
187
|
-
};
|
|
188
|
-
}
|
|
189
|
-
function rangeOf(scale) {
|
|
190
|
-
const getName = getNoteNameOf(scale);
|
|
191
|
-
return (fromNote, toNote) => {
|
|
192
|
-
const from = note(fromNote).height;
|
|
193
|
-
const to = note(toNote).height;
|
|
194
|
-
if (from === undefined || to === undefined)
|
|
195
|
-
return [];
|
|
196
|
-
return range(from, to)
|
|
197
|
-
.map(getName)
|
|
198
|
-
.filter((x) => x);
|
|
199
|
-
};
|
|
200
|
-
}
|
|
201
|
-
var index = {
|
|
202
|
-
get,
|
|
203
|
-
names,
|
|
204
|
-
extended,
|
|
205
|
-
modeNames,
|
|
206
|
-
reduced,
|
|
207
|
-
scaleChords,
|
|
208
|
-
scaleNotes,
|
|
209
|
-
tokenize,
|
|
210
|
-
rangeOf,
|
|
211
|
-
// deprecated
|
|
212
|
-
scale,
|
|
213
|
-
};
|
|
214
|
-
|
|
215
|
-
export { index as default, extended, get, modeNames, names, rangeOf, reduced, scale, scaleChords, scaleNotes, tokenize };
|
|
216
|
-
//# sourceMappingURL=index.es.js.map
|
package/dist/index.es.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.es.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|