@tspro/web-music-score 1.0.0 → 2.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/CHANGELOG.md +19 -0
- package/README.md +271 -224
- package/dist/audio/index.d.mts +22 -0
- package/dist/audio/index.d.ts +22 -0
- package/dist/audio/index.js +147 -0
- package/dist/audio/index.mjs +109 -0
- package/dist/audio-cg/index.d.mts +4 -0
- package/dist/audio-cg/index.d.ts +4 -0
- package/dist/audio-cg/index.js +124 -0
- package/dist/audio-cg/index.mjs +91 -0
- package/dist/chunk-2EPWQZKJ.mjs +9 -0
- package/dist/core/index.d.mts +21 -0
- package/dist/core/index.d.ts +21 -0
- package/dist/core/index.js +72 -0
- package/dist/core/index.mjs +45 -0
- package/dist/guitar-BIFwFT31.d.ts +24 -0
- package/dist/guitar-kbJYu3Am.d.mts +24 -0
- package/dist/iife/index.global.js +222 -0
- package/dist/note-B5ZtlHc8.d.ts +99 -0
- package/dist/note-CraqEy8x.d.mts +99 -0
- package/dist/pieces/index.d.mts +15 -0
- package/dist/pieces/index.d.ts +15 -0
- package/dist/pieces/index.js +104 -0
- package/dist/pieces/index.mjs +77 -0
- package/dist/react-ui/index.d.mts +169 -0
- package/dist/react-ui/index.d.ts +169 -0
- package/dist/react-ui/index.js +624 -0
- package/dist/react-ui/index.mjs +582 -0
- package/dist/score/index.d.mts +1558 -0
- package/dist/score/index.d.ts +1558 -0
- package/dist/score/index.js +6937 -0
- package/dist/score/index.mjs +6863 -0
- package/dist/tempo--588tdcv.d.ts +203 -0
- package/dist/tempo-BEJBHZ5I.d.mts +203 -0
- package/dist/theory/index.d.mts +47 -0
- package/dist/theory/index.d.ts +47 -0
- package/dist/theory/index.js +1783 -0
- package/dist/theory/index.mjs +1716 -0
- package/package.json +99 -56
- package/dist/index.cjs.js +0 -40708
- package/dist/index.d.ts +0 -1258
- package/dist/index.esm.mjs +0 -40699
- package/dist/index.umd.min.js +0 -9
|
@@ -0,0 +1,1783 @@
|
|
|
1
|
+
/* WebMusicScore v2.0.0 | (c) 2023 PahkaSoft | MIT License | Includes: Tone.js (MIT License) */
|
|
2
|
+
"use strict";
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toCommonJS = (mod2) => __copyProps(__defProp({}, "__esModule", { value: true }), mod2);
|
|
21
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
22
|
+
|
|
23
|
+
// src/theory/index.ts
|
|
24
|
+
var theory_exports = {};
|
|
25
|
+
__export(theory_exports, {
|
|
26
|
+
AccidentalType: () => AccidentalType,
|
|
27
|
+
Chord: () => Chord,
|
|
28
|
+
DefaultGuitarNoteLabel: () => DefaultGuitarNoteLabel,
|
|
29
|
+
DefaultHandedness: () => DefaultHandedness,
|
|
30
|
+
DefaultPitchNotation: () => DefaultPitchNotation,
|
|
31
|
+
DefaultTuningName: () => DefaultTuningName,
|
|
32
|
+
GuitarNoteLabel: () => GuitarNoteLabel,
|
|
33
|
+
GuitarNoteLabelList: () => GuitarNoteLabelList,
|
|
34
|
+
Handedness: () => Handedness,
|
|
35
|
+
Interval: () => Interval,
|
|
36
|
+
KeySignature: () => KeySignature,
|
|
37
|
+
MaxNoteLength: () => MaxNoteLength,
|
|
38
|
+
MinNoteLength: () => MinNoteLength,
|
|
39
|
+
Mode: () => Mode,
|
|
40
|
+
Note: () => Note,
|
|
41
|
+
NoteLength: () => NoteLength,
|
|
42
|
+
PitchNotation: () => PitchNotation,
|
|
43
|
+
PitchNotationList: () => PitchNotationList,
|
|
44
|
+
RhythmProps: () => RhythmProps,
|
|
45
|
+
Scale: () => Scale,
|
|
46
|
+
ScaleFactory: () => ScaleFactory,
|
|
47
|
+
ScaleType: () => ScaleType,
|
|
48
|
+
SymbolSet: () => SymbolSet,
|
|
49
|
+
TimeSignature: () => TimeSignature,
|
|
50
|
+
TuningNameList: () => TuningNameList,
|
|
51
|
+
alterTempoSpeed: () => alterTempoSpeed,
|
|
52
|
+
getDefaultKeySignature: () => getDefaultKeySignature,
|
|
53
|
+
getDefaultScale: () => getDefaultScale,
|
|
54
|
+
getDefaultTempo: () => getDefaultTempo,
|
|
55
|
+
getDefaultTimeSignature: () => getDefaultTimeSignature,
|
|
56
|
+
getPitchNotationName: () => getPitchNotationName,
|
|
57
|
+
getScale: () => getScale,
|
|
58
|
+
getScaleFactory: () => getScaleFactory,
|
|
59
|
+
getScaleFactoryList: () => getScaleFactoryList,
|
|
60
|
+
getTempoString: () => getTempoString,
|
|
61
|
+
getTuningStrings: () => getTuningStrings,
|
|
62
|
+
validateGuitarNoteLabel: () => validateGuitarNoteLabel,
|
|
63
|
+
validateHandedness: () => validateHandedness,
|
|
64
|
+
validateIntervalQuality: () => validateIntervalQuality,
|
|
65
|
+
validateNoteLength: () => validateNoteLength,
|
|
66
|
+
validatePitchNotation: () => validatePitchNotation,
|
|
67
|
+
validateScaleType: () => validateScaleType,
|
|
68
|
+
validateTuningName: () => validateTuningName
|
|
69
|
+
});
|
|
70
|
+
module.exports = __toCommonJS(theory_exports);
|
|
71
|
+
|
|
72
|
+
// src/theory/chord.ts
|
|
73
|
+
var import_ts_utils_lib6 = require("@tspro/ts-utils-lib");
|
|
74
|
+
|
|
75
|
+
// src/theory/note.ts
|
|
76
|
+
var import_ts_utils_lib2 = require("@tspro/ts-utils-lib");
|
|
77
|
+
|
|
78
|
+
// src/theory/types.ts
|
|
79
|
+
var import_ts_utils_lib = require("@tspro/ts-utils-lib");
|
|
80
|
+
var import_core = require("@tspro/web-music-score/core");
|
|
81
|
+
var SymbolSet = /* @__PURE__ */ ((SymbolSet2) => {
|
|
82
|
+
SymbolSet2[SymbolSet2["Ascii"] = 0] = "Ascii";
|
|
83
|
+
SymbolSet2[SymbolSet2["Unicode"] = 1] = "Unicode";
|
|
84
|
+
return SymbolSet2;
|
|
85
|
+
})(SymbolSet || {});
|
|
86
|
+
var PitchNotation = /* @__PURE__ */ ((PitchNotation2) => {
|
|
87
|
+
PitchNotation2[PitchNotation2["Scientific"] = 0] = "Scientific";
|
|
88
|
+
PitchNotation2[PitchNotation2["Helmholtz"] = 1] = "Helmholtz";
|
|
89
|
+
return PitchNotation2;
|
|
90
|
+
})(PitchNotation || {});
|
|
91
|
+
var PitchNotationList = import_ts_utils_lib.Utils.Enum.getEnumValues(PitchNotation);
|
|
92
|
+
var DefaultPitchNotation = 0 /* Scientific */;
|
|
93
|
+
function validatePitchNotation(pn) {
|
|
94
|
+
if (!import_ts_utils_lib.Utils.Is.isEnumValue(pn, PitchNotation)) {
|
|
95
|
+
throw new import_core.MusicError(import_core.MusicErrorType.InvalidArg, `Invalid pitchNotation: ${pn}`);
|
|
96
|
+
} else {
|
|
97
|
+
return pn;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
function getPitchNotationName(pn) {
|
|
101
|
+
return PitchNotation[validatePitchNotation(pn)];
|
|
102
|
+
}
|
|
103
|
+
var GuitarNoteLabel = /* @__PURE__ */ ((GuitarNoteLabel2) => {
|
|
104
|
+
GuitarNoteLabel2["Default"] = "Default";
|
|
105
|
+
GuitarNoteLabel2["OmitOctave"] = "Omit Octave";
|
|
106
|
+
GuitarNoteLabel2["Interval"] = "Interval";
|
|
107
|
+
return GuitarNoteLabel2;
|
|
108
|
+
})(GuitarNoteLabel || {});
|
|
109
|
+
var DefaultGuitarNoteLabel = "Default" /* Default */;
|
|
110
|
+
var GuitarNoteLabelList = import_ts_utils_lib.Utils.Enum.getEnumValues(GuitarNoteLabel);
|
|
111
|
+
function validateGuitarNoteLabel(label) {
|
|
112
|
+
if (!import_ts_utils_lib.Utils.Is.isEnumValue(label, GuitarNoteLabel)) {
|
|
113
|
+
throw new import_core.MusicError(import_core.MusicErrorType.Timesignature, `Invalid guitarNoteLabel: ${label}`);
|
|
114
|
+
} else {
|
|
115
|
+
return label;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// src/theory/note.ts
|
|
120
|
+
var import_core2 = require("@tspro/web-music-score/core");
|
|
121
|
+
function mod(n, m) {
|
|
122
|
+
return (n % m + m) % m;
|
|
123
|
+
}
|
|
124
|
+
var C0_chromaticId = 12;
|
|
125
|
+
var C0_diatonicId = 7;
|
|
126
|
+
var AccidentalAsciiSymbolMap = /* @__PURE__ */ new Map([[-2, "bb"], [-1, "b"], [0, ""], [1, "#"], [2, "x"]]);
|
|
127
|
+
var AccidentalUnicodeSymbolMap = /* @__PURE__ */ new Map([[-2, "\u{1D12B}"], [-1, "\u266D"], [0, ""], [1, "\u266F"], [2, "\u{1D12A}"]]);
|
|
128
|
+
var AccidentalMap = /* @__PURE__ */ new Map([["", 0], ["bb", -2], ["b", -1], ["#", 1], ["x", 2], ["\u{1D12B}", -2], ["\u266D", -1], ["\u266F", 1], ["\u{1D12A}", 2]]);
|
|
129
|
+
var NoteLetters = ["C", "D", "E", "F", "G", "A", "B"];
|
|
130
|
+
var DiatonicToChromaticMap = [0, 2, 4, 5, 7, 9, 11];
|
|
131
|
+
var NoteNameRegex = /^([A-G])((?:bb|𝄫|♭|b|#|♯|x|𝄪)?)?(-?\d+)?$/;
|
|
132
|
+
var _Note = class _Note {
|
|
133
|
+
constructor(arg, accidental, octave) {
|
|
134
|
+
__publicField(this, "diatonicClass");
|
|
135
|
+
__publicField(this, "accidental");
|
|
136
|
+
__publicField(this, "octave");
|
|
137
|
+
if (typeof arg === "number" && typeof accidental === "number" && octave === void 0) {
|
|
138
|
+
_Note.validateDiatonicId(arg);
|
|
139
|
+
this.diatonicClass = _Note.getDiatonicClass(arg);
|
|
140
|
+
this.accidental = _Note.validateAccidental(accidental);
|
|
141
|
+
this.octave = _Note.getOctaveFromDiatonicId(arg);
|
|
142
|
+
} else if (typeof arg === "number" && typeof accidental === "number" && typeof octave === "number") {
|
|
143
|
+
this.diatonicClass = _Note.validateDiatonicClass(arg);
|
|
144
|
+
this.accidental = _Note.validateAccidental(accidental);
|
|
145
|
+
this.octave = _Note.validateOctave(octave);
|
|
146
|
+
} else if (typeof arg === "string" && typeof accidental === "number" && typeof octave === "number") {
|
|
147
|
+
this.diatonicClass = _Note.getDiatonicClass(arg);
|
|
148
|
+
this.accidental = _Note.validateAccidental(accidental);
|
|
149
|
+
this.octave = _Note.validateOctave(octave);
|
|
150
|
+
} else {
|
|
151
|
+
throw new import_core2.MusicError(import_core2.MusicErrorType.Note, `Invalid args: ${arg}, ${accidental}, ${octave}`);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
get diatonicId() {
|
|
155
|
+
return _Note.getDiatonicIdInOctave(this.diatonicClass, this.octave);
|
|
156
|
+
}
|
|
157
|
+
get chromaticId() {
|
|
158
|
+
return _Note.getChromaticIdInOctave(DiatonicToChromaticMap[this.diatonicClass] + this.accidental, this.octave);
|
|
159
|
+
}
|
|
160
|
+
get midiNumber() {
|
|
161
|
+
return this.chromaticId;
|
|
162
|
+
}
|
|
163
|
+
get chromaticClass() {
|
|
164
|
+
return _Note.getChromaticClass(DiatonicToChromaticMap[this.diatonicClass] + this.accidental);
|
|
165
|
+
}
|
|
166
|
+
get noteLetter() {
|
|
167
|
+
return NoteLetters[this.diatonicClass];
|
|
168
|
+
}
|
|
169
|
+
format(pitchNotation, symbolSet) {
|
|
170
|
+
let { noteLetter, octave } = this;
|
|
171
|
+
let accidentalSymbol = _Note.getAccidentalSymbol(this.accidental, symbolSet);
|
|
172
|
+
if (pitchNotation === 1 /* Helmholtz */) {
|
|
173
|
+
if (octave >= 3) {
|
|
174
|
+
return noteLetter.toLowerCase() + accidentalSymbol + "\u2032".repeat(octave - 3);
|
|
175
|
+
} else {
|
|
176
|
+
return noteLetter.toUpperCase() + accidentalSymbol + "\u0375".repeat(2 - octave);
|
|
177
|
+
}
|
|
178
|
+
} else {
|
|
179
|
+
return noteLetter + accidentalSymbol + octave;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
formatOmitOctave(symbolSet) {
|
|
183
|
+
let noteLetter = NoteLetters[this.diatonicClass];
|
|
184
|
+
let accidental = _Note.getAccidentalSymbol(this.accidental, symbolSet);
|
|
185
|
+
return noteLetter + accidental;
|
|
186
|
+
}
|
|
187
|
+
static getNote(noteName) {
|
|
188
|
+
let note = this.noteByNameCache.get(noteName);
|
|
189
|
+
if (note === void 0) {
|
|
190
|
+
let p = _Note.parseNote(noteName);
|
|
191
|
+
if (!p) {
|
|
192
|
+
throw new import_core2.MusicError(import_core2.MusicErrorType.Note, `Invalid noteName: ${noteName}`);
|
|
193
|
+
}
|
|
194
|
+
if (p.octave === void 0) {
|
|
195
|
+
throw new import_core2.MusicError(import_core2.MusicErrorType.Note, `Octave is required for note.`);
|
|
196
|
+
}
|
|
197
|
+
note = new _Note(p.noteLetter, p.accidental, p.octave);
|
|
198
|
+
this.noteByNameCache.set(noteName, note);
|
|
199
|
+
}
|
|
200
|
+
return note;
|
|
201
|
+
}
|
|
202
|
+
static getChromaticNote(chromaticId) {
|
|
203
|
+
let note = this.chromaticNoteCache.get(chromaticId);
|
|
204
|
+
if (note === void 0) {
|
|
205
|
+
const NoteNameList = ["C/B#", "C#/Db", "D", "D#/Eb", "E/Fb", "F/E#", "F#/Gb", "G", "G#/Ab", "A", "A#/Bb", "B/Cb"];
|
|
206
|
+
let noteName = NoteNameList[_Note.getChromaticClass(chromaticId)].split("/")[0] + _Note.getOctaveFromChromaticId(chromaticId);
|
|
207
|
+
let p = _Note.parseNote(noteName);
|
|
208
|
+
if (!p) {
|
|
209
|
+
throw new import_core2.MusicError(import_core2.MusicErrorType.Note, `Invalid noteName: ${noteName}`);
|
|
210
|
+
}
|
|
211
|
+
if (p.octave === void 0) {
|
|
212
|
+
throw new import_core2.MusicError(import_core2.MusicErrorType.Note, `Octave is required for note.`);
|
|
213
|
+
}
|
|
214
|
+
note = new _Note(p.noteLetter, p.accidental, p.octave);
|
|
215
|
+
this.chromaticNoteCache.set(chromaticId, note);
|
|
216
|
+
}
|
|
217
|
+
return note;
|
|
218
|
+
}
|
|
219
|
+
static getDiatonicClass(arg) {
|
|
220
|
+
if (typeof arg === "number") {
|
|
221
|
+
return mod(arg, 7);
|
|
222
|
+
} else if (typeof arg === "string" && arg.length > 0) {
|
|
223
|
+
return NoteLetters.indexOf(_Note.validateNoteLetter(arg[0]));
|
|
224
|
+
} else {
|
|
225
|
+
throw new import_core2.MusicError(import_core2.MusicErrorType.Note, `Invalid arg: ${arg}`);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
static getOctaveFromDiatonicId(diatonicId) {
|
|
229
|
+
return Math.floor((diatonicId - C0_diatonicId) / 7);
|
|
230
|
+
}
|
|
231
|
+
static getDiatonicIdInOctave(diatonicId, octave) {
|
|
232
|
+
return _Note.getDiatonicClass(diatonicId) + octave * 7 + C0_diatonicId;
|
|
233
|
+
}
|
|
234
|
+
static getChromaticClass(chromaticId) {
|
|
235
|
+
return mod(chromaticId, 12);
|
|
236
|
+
}
|
|
237
|
+
static getOctaveFromChromaticId(chromaticId) {
|
|
238
|
+
return Math.floor((chromaticId - C0_chromaticId) / 12);
|
|
239
|
+
}
|
|
240
|
+
static getChromaticIdInOctave(chromaticId, octave) {
|
|
241
|
+
return _Note.getChromaticClass(chromaticId) + octave * 12 + C0_chromaticId;
|
|
242
|
+
}
|
|
243
|
+
static equals(a, b) {
|
|
244
|
+
if (a == null && b == null) {
|
|
245
|
+
return true;
|
|
246
|
+
} else if (a == null || b == null) {
|
|
247
|
+
return false;
|
|
248
|
+
} else {
|
|
249
|
+
return a === b || a.diatonicId === b.diatonicId && a.accidental === b.accidental;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
static replaceAccidentalSymbols(str, symbolSet) {
|
|
253
|
+
if (symbolSet === 1 /* Unicode */) {
|
|
254
|
+
return str.replace("bb", "\u{1D12B}").replace("b", "\u266D").replace("#", "\u266F").replace("x", "\u{1D12A}");
|
|
255
|
+
} else {
|
|
256
|
+
return str.replace("\u{1D12B}", "bb").replace("\u266D", "b").replace("\u266F", "#").replace("\u{1D12A}", "x");
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
static isValidNoteName(noteName) {
|
|
260
|
+
return NoteNameRegex.test(noteName);
|
|
261
|
+
}
|
|
262
|
+
static parseNote(noteName) {
|
|
263
|
+
var _a;
|
|
264
|
+
let m = NoteNameRegex.exec(noteName);
|
|
265
|
+
if (!m) {
|
|
266
|
+
return void 0;
|
|
267
|
+
}
|
|
268
|
+
let noteLetter = _Note.validateNoteLetter(m[1]);
|
|
269
|
+
let accidentalStr = m[2];
|
|
270
|
+
let accidental = _Note.validateAccidental((_a = AccidentalMap.get(accidentalStr)) != null ? _a : 0);
|
|
271
|
+
let octaveStr = m[3];
|
|
272
|
+
let octave = octaveStr ? _Note.validateOctave(+octaveStr) : void 0;
|
|
273
|
+
return { noteLetter, accidental, octave };
|
|
274
|
+
}
|
|
275
|
+
static getScientificNoteName(noteName, symbolSet) {
|
|
276
|
+
let p = _Note.parseNote(noteName);
|
|
277
|
+
if (!p) {
|
|
278
|
+
throw new import_core2.MusicError(import_core2.MusicErrorType.Note, `Invalid noteName: ${noteName}`);
|
|
279
|
+
}
|
|
280
|
+
let { noteLetter, accidental, octave } = p;
|
|
281
|
+
return noteLetter + _Note.getAccidentalSymbol(accidental, symbolSet) + (octave != null ? octave : "");
|
|
282
|
+
}
|
|
283
|
+
static getAccidentalSymbol(accidental, symbolsSet) {
|
|
284
|
+
return symbolsSet === 1 /* Unicode */ ? AccidentalUnicodeSymbolMap.get(accidental) : AccidentalAsciiSymbolMap.get(accidental);
|
|
285
|
+
}
|
|
286
|
+
static getAccidental(accidentalSymbol) {
|
|
287
|
+
let accidental = AccidentalMap.get(accidentalSymbol);
|
|
288
|
+
if (accidental === void 0) {
|
|
289
|
+
throw new import_core2.MusicError(import_core2.MusicErrorType.Note, `Invalid accidental: ${accidentalSymbol}`);
|
|
290
|
+
}
|
|
291
|
+
return accidental;
|
|
292
|
+
}
|
|
293
|
+
static getNoteLetter(diatonicId) {
|
|
294
|
+
return NoteLetters[_Note.getDiatonicClass(diatonicId)];
|
|
295
|
+
}
|
|
296
|
+
static findNextDiatonicIdAbove(diatonicId, bottomDiatonicId, addOctaveIfEqual) {
|
|
297
|
+
let diatonicClass = _Note.getDiatonicClass(diatonicId);
|
|
298
|
+
let bottomDiatonicClass = _Note.getDiatonicClass(bottomDiatonicId);
|
|
299
|
+
let addOctave = addOctaveIfEqual ? diatonicClass <= bottomDiatonicClass ? 1 : 0 : diatonicClass < bottomDiatonicClass ? 1 : 0;
|
|
300
|
+
return _Note.getDiatonicIdInOctave(diatonicClass, _Note.getOctaveFromDiatonicId(bottomDiatonicId) + addOctave);
|
|
301
|
+
}
|
|
302
|
+
static validateDiatonicId(diatonicId) {
|
|
303
|
+
if (import_ts_utils_lib2.Utils.Is.isInteger(diatonicId)) {
|
|
304
|
+
return diatonicId;
|
|
305
|
+
} else {
|
|
306
|
+
throw new import_core2.MusicError(import_core2.MusicErrorType.Note, `Invalid diatonicId: ${diatonicId}`);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
static validateDiatonicClass(diatonicClass) {
|
|
310
|
+
if (import_ts_utils_lib2.Utils.Is.isInteger(diatonicClass) && diatonicClass >= 0 && diatonicClass < 7) {
|
|
311
|
+
return diatonicClass;
|
|
312
|
+
} else {
|
|
313
|
+
throw new import_core2.MusicError(import_core2.MusicErrorType.Note, `Invalid diatonicClass: ${diatonicClass}`);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
static validateChromaticId(chromaticId) {
|
|
317
|
+
if (import_ts_utils_lib2.Utils.Is.isInteger(chromaticId)) {
|
|
318
|
+
return chromaticId;
|
|
319
|
+
} else {
|
|
320
|
+
throw new import_core2.MusicError(import_core2.MusicErrorType.Note, `Invalid chromaticId: ${chromaticId}`);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
static validatechromaticClass(chromaticClass) {
|
|
324
|
+
if (import_ts_utils_lib2.Utils.Is.isInteger(chromaticClass) && chromaticClass >= 0 && chromaticClass < 12) {
|
|
325
|
+
return chromaticClass;
|
|
326
|
+
} else {
|
|
327
|
+
throw new import_core2.MusicError(import_core2.MusicErrorType.Note, `Invalid chromaticClass: ${chromaticClass}`);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
static validateNoteLetter(note) {
|
|
331
|
+
if (NoteLetters.some((n) => n === note)) {
|
|
332
|
+
return note;
|
|
333
|
+
} else {
|
|
334
|
+
throw new import_core2.MusicError(import_core2.MusicErrorType.Note, `Invalid note: ${note}`);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
static validateOctave(octave) {
|
|
338
|
+
if (import_ts_utils_lib2.Utils.Is.isInteger(octave)) {
|
|
339
|
+
return octave;
|
|
340
|
+
} else {
|
|
341
|
+
throw new import_core2.MusicError(import_core2.MusicErrorType.Note, `Invalid octave: ${octave}`);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
static validateAccidental(acc) {
|
|
345
|
+
if (import_ts_utils_lib2.Utils.Is.isInteger(acc) && acc >= -2 && acc <= 2) {
|
|
346
|
+
return acc;
|
|
347
|
+
} else {
|
|
348
|
+
throw new import_core2.MusicError(import_core2.MusicErrorType.Note, `Invalid accidental: ${acc}`);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* Sort notes by diatonicId in ascending order.
|
|
353
|
+
* @param notes - Array of notes.
|
|
354
|
+
* @returns Sorted array of notes.
|
|
355
|
+
*/
|
|
356
|
+
static sort(notes) {
|
|
357
|
+
return notes.slice().sort(_Note.compareFunc);
|
|
358
|
+
}
|
|
359
|
+
/**
|
|
360
|
+
* Remove duplicate notes.
|
|
361
|
+
* @param notes - Array of notes.
|
|
362
|
+
* @returns Sorted set of notes.
|
|
363
|
+
*/
|
|
364
|
+
static removeDuplicates(notes) {
|
|
365
|
+
let uniqueSet = [];
|
|
366
|
+
notes.forEach((note) => {
|
|
367
|
+
if (uniqueSet.find((n) => _Note.equals(note, n)) === void 0) {
|
|
368
|
+
uniqueSet.push(note);
|
|
369
|
+
}
|
|
370
|
+
});
|
|
371
|
+
return uniqueSet;
|
|
372
|
+
}
|
|
373
|
+
static compareFunc(a, b) {
|
|
374
|
+
if (a.diatonicId < b.diatonicId) {
|
|
375
|
+
return -1;
|
|
376
|
+
} else if (a.diatonicId > b.diatonicId) {
|
|
377
|
+
return 1;
|
|
378
|
+
} else {
|
|
379
|
+
if (a.accidental < b.accidental) {
|
|
380
|
+
return -1;
|
|
381
|
+
} else if (a.accidental > b.accidental) {
|
|
382
|
+
return 1;
|
|
383
|
+
} else {
|
|
384
|
+
return 0;
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
};
|
|
389
|
+
__publicField(_Note, "noteByNameCache", /* @__PURE__ */ new Map());
|
|
390
|
+
__publicField(_Note, "chromaticNoteCache", /* @__PURE__ */ new Map());
|
|
391
|
+
var Note = _Note;
|
|
392
|
+
|
|
393
|
+
// src/theory/scale.ts
|
|
394
|
+
var import_ts_utils_lib5 = require("@tspro/ts-utils-lib");
|
|
395
|
+
|
|
396
|
+
// src/theory/key-signature.ts
|
|
397
|
+
var import_ts_utils_lib3 = require("@tspro/ts-utils-lib");
|
|
398
|
+
var import_core3 = require("@tspro/web-music-score/core");
|
|
399
|
+
function getAccidental(chromaticId, diatonicId) {
|
|
400
|
+
let a = Note.getChromaticClass(chromaticId) - new Note(diatonicId, 0).chromaticClass;
|
|
401
|
+
while (a > 2) {
|
|
402
|
+
a -= 12;
|
|
403
|
+
}
|
|
404
|
+
while (a < -2) {
|
|
405
|
+
a += 12;
|
|
406
|
+
}
|
|
407
|
+
return Note.validateAccidental(a);
|
|
408
|
+
}
|
|
409
|
+
var DegreeRule = /^(bb?|b?|#?|x?)([0-9]*)$/;
|
|
410
|
+
function parseDegree(degree) {
|
|
411
|
+
var _a, _b;
|
|
412
|
+
let m = DegreeRule.exec("" + degree);
|
|
413
|
+
if (!m) {
|
|
414
|
+
throw new import_core3.MusicError(import_core3.MusicErrorType.KeySignature, `Invalid degree: ${degree}`);
|
|
415
|
+
}
|
|
416
|
+
let acc = (_b = Note.getAccidental((_a = m[1]) != null ? _a : "")) != null ? _b : 0;
|
|
417
|
+
let deg = +m[2];
|
|
418
|
+
if (!import_ts_utils_lib3.Utils.Is.isInteger(acc) || acc < -2 || acc > 2 || !import_ts_utils_lib3.Utils.Is.isInteger(deg) || deg < 1) {
|
|
419
|
+
throw new import_core3.MusicError(import_core3.MusicErrorType.KeySignature, `Invalid degree: ${degree}`);
|
|
420
|
+
} else {
|
|
421
|
+
return { deg, acc };
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
var Mode = /* @__PURE__ */ ((Mode2) => {
|
|
425
|
+
Mode2[Mode2["Ionian"] = 1] = "Ionian";
|
|
426
|
+
Mode2[Mode2["Dorian"] = 2] = "Dorian";
|
|
427
|
+
Mode2[Mode2["Phrygian"] = 3] = "Phrygian";
|
|
428
|
+
Mode2[Mode2["Lydian"] = 4] = "Lydian";
|
|
429
|
+
Mode2[Mode2["Mixolydian"] = 5] = "Mixolydian";
|
|
430
|
+
Mode2[Mode2["Aeolian"] = 6] = "Aeolian";
|
|
431
|
+
Mode2[Mode2["Locrian"] = 7] = "Locrian";
|
|
432
|
+
return Mode2;
|
|
433
|
+
})(Mode || {});
|
|
434
|
+
var AccidentalType = /* @__PURE__ */ ((AccidentalType2) => {
|
|
435
|
+
AccidentalType2[AccidentalType2["Natural"] = 0] = "Natural";
|
|
436
|
+
AccidentalType2[AccidentalType2["Flats"] = 1] = "Flats";
|
|
437
|
+
AccidentalType2[AccidentalType2["Sharps"] = 2] = "Sharps";
|
|
438
|
+
return AccidentalType2;
|
|
439
|
+
})(AccidentalType || {});
|
|
440
|
+
function getDefaultKeySignature() {
|
|
441
|
+
return getScale("C", "Major" /* Major */);
|
|
442
|
+
}
|
|
443
|
+
var _KeySignature = class _KeySignature {
|
|
444
|
+
/**
|
|
445
|
+
* @param tonic - Tonic/root note.
|
|
446
|
+
* @param mode - Mode: Ionian/Major = 1, Dorian = 2, ..., Locrian = 7
|
|
447
|
+
*/
|
|
448
|
+
constructor(tonic, mode) {
|
|
449
|
+
this.tonic = tonic;
|
|
450
|
+
this.mode = mode;
|
|
451
|
+
__publicField(this, "naturalScaleNotes");
|
|
452
|
+
__publicField(this, "accidentalByDiatonicClass");
|
|
453
|
+
__publicField(this, "orderedAccidentedNotes");
|
|
454
|
+
if (!import_ts_utils_lib3.Utils.Is.isEnumValue(mode, Mode)) {
|
|
455
|
+
throw new import_core3.MusicError(import_core3.MusicErrorType.KeySignature, `Invalid mode: ${mode}`);
|
|
456
|
+
}
|
|
457
|
+
let intervals = [2, 2, 1, 2, 2, 2, 1];
|
|
458
|
+
for (let i = 1; i < mode; i++) {
|
|
459
|
+
intervals.push(intervals.shift());
|
|
460
|
+
}
|
|
461
|
+
this.naturalScaleNotes = [];
|
|
462
|
+
this.accidentalByDiatonicClass = [];
|
|
463
|
+
let diatonicId = Note.getDiatonicClass(tonic[0]);
|
|
464
|
+
let chromaticId = Note.getNote(tonic + "0").chromaticId;
|
|
465
|
+
for (let id = 0; id < 7; diatonicId++, chromaticId += intervals[id], id++) {
|
|
466
|
+
let note = new Note(Note.getDiatonicClass(diatonicId), getAccidental(chromaticId, diatonicId));
|
|
467
|
+
if (Math.abs(note.accidental) >= 2) {
|
|
468
|
+
throw new import_core3.MusicError(import_core3.MusicErrorType.KeySignature, "Key signature contains double accidental.");
|
|
469
|
+
}
|
|
470
|
+
this.naturalScaleNotes[id] = note;
|
|
471
|
+
this.accidentalByDiatonicClass[note.diatonicClass] = note.accidental;
|
|
472
|
+
}
|
|
473
|
+
let sharps = this.naturalScaleNotes.filter((n) => n.accidental > 0).sort((a, b) => {
|
|
474
|
+
let ai = _KeySignature.OrderOfSharps.indexOf(a.noteLetter);
|
|
475
|
+
let bi = _KeySignature.OrderOfSharps.indexOf(b.noteLetter);
|
|
476
|
+
if (ai === -1 || bi === -1) {
|
|
477
|
+
throw new import_core3.MusicError(import_core3.MusicErrorType.KeySignature, "Unexpected note in key signature.");
|
|
478
|
+
}
|
|
479
|
+
return ai - bi;
|
|
480
|
+
});
|
|
481
|
+
let flats = this.naturalScaleNotes.filter((n) => n.accidental < 0).sort((a, b) => {
|
|
482
|
+
let ai = _KeySignature.OrderOfFlats.indexOf(a.noteLetter);
|
|
483
|
+
let bi = _KeySignature.OrderOfFlats.indexOf(b.noteLetter);
|
|
484
|
+
if (ai === -1 || bi === -1) {
|
|
485
|
+
throw new import_core3.MusicError(import_core3.MusicErrorType.KeySignature, "Unexpected note in key signature.");
|
|
486
|
+
}
|
|
487
|
+
return ai - bi;
|
|
488
|
+
});
|
|
489
|
+
if (sharps.length !== 0 && flats.length !== 0) {
|
|
490
|
+
throw new import_core3.MusicError(import_core3.MusicErrorType.KeySignature, "Key Signature has both sharps and flats.");
|
|
491
|
+
}
|
|
492
|
+
this.orderedAccidentedNotes = flats.length > 0 ? flats : sharps;
|
|
493
|
+
}
|
|
494
|
+
getAccidentalType() {
|
|
495
|
+
if (this.orderedAccidentedNotes.length === 0) {
|
|
496
|
+
return 0 /* Natural */;
|
|
497
|
+
} else if (this.orderedAccidentedNotes[0].accidental < 0) {
|
|
498
|
+
return 1 /* Flats */;
|
|
499
|
+
} else {
|
|
500
|
+
return 2 /* Sharps */;
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
getNaturalScaleNotes() {
|
|
504
|
+
return this.naturalScaleNotes;
|
|
505
|
+
}
|
|
506
|
+
getAccidental(diatonicId) {
|
|
507
|
+
var _a;
|
|
508
|
+
return (_a = this.accidentalByDiatonicClass[Note.getDiatonicClass(diatonicId)]) != null ? _a : 0;
|
|
509
|
+
}
|
|
510
|
+
getNumAccidentals() {
|
|
511
|
+
return this.orderedAccidentedNotes.length;
|
|
512
|
+
}
|
|
513
|
+
getOrderedAccidentalNotes() {
|
|
514
|
+
return this.orderedAccidentedNotes;
|
|
515
|
+
}
|
|
516
|
+
/**
|
|
517
|
+
*
|
|
518
|
+
* @param degree - number 1..7 or string e.g "b5" or "#4"
|
|
519
|
+
* @returns
|
|
520
|
+
*/
|
|
521
|
+
getNoteByDegree(degree) {
|
|
522
|
+
let { deg, acc } = parseDegree(degree);
|
|
523
|
+
if (acc === 0) {
|
|
524
|
+
return this.naturalScaleNotes[(deg - 1) % 7];
|
|
525
|
+
} else {
|
|
526
|
+
let note = this.naturalScaleNotes[(deg - 1) % 7];
|
|
527
|
+
return new Note(note.diatonicId, note.accidental + acc);
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
static equals(a, b) {
|
|
531
|
+
if (a == null && b == null) {
|
|
532
|
+
return true;
|
|
533
|
+
} else if (a == null || b == null) {
|
|
534
|
+
return false;
|
|
535
|
+
} else {
|
|
536
|
+
return a === b || a.tonic === b.tonic && a.mode === b.mode;
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
};
|
|
540
|
+
__publicField(_KeySignature, "OrderOfSharps", "FCGDAEB");
|
|
541
|
+
__publicField(_KeySignature, "OrderOfFlats", "BEADGCF");
|
|
542
|
+
var KeySignature = _KeySignature;
|
|
543
|
+
|
|
544
|
+
// src/theory/interval.ts
|
|
545
|
+
var import_ts_utils_lib4 = require("@tspro/ts-utils-lib");
|
|
546
|
+
var import_core4 = require("@tspro/web-music-score/core");
|
|
547
|
+
var IntervalQualityAbbrMap = /* @__PURE__ */ new Map([
|
|
548
|
+
["Major", "M"],
|
|
549
|
+
["minor", "m"],
|
|
550
|
+
["Perfect", "P"],
|
|
551
|
+
["diminished", "d"],
|
|
552
|
+
["Augmented", "A"],
|
|
553
|
+
["doubly diminished", "dd"],
|
|
554
|
+
["Doubly Augmented", "AA"]
|
|
555
|
+
]);
|
|
556
|
+
var IntervalQualities = {
|
|
557
|
+
"1": {
|
|
558
|
+
// Unison
|
|
559
|
+
"0": "Perfect",
|
|
560
|
+
"1": "Augmented",
|
|
561
|
+
"-1": "diminished",
|
|
562
|
+
"2": "Doubly Augmented",
|
|
563
|
+
"-2": "doubly diminished"
|
|
564
|
+
},
|
|
565
|
+
"2": {
|
|
566
|
+
// Second
|
|
567
|
+
"2": "Major",
|
|
568
|
+
"1": "minor",
|
|
569
|
+
"3": "Augmented",
|
|
570
|
+
"0": "diminished",
|
|
571
|
+
"4": "Doubly Augmented",
|
|
572
|
+
"-1": "doubly diminished"
|
|
573
|
+
},
|
|
574
|
+
"3": {
|
|
575
|
+
// Third
|
|
576
|
+
"4": "Major",
|
|
577
|
+
"3": "minor",
|
|
578
|
+
"5": "Augmented",
|
|
579
|
+
"2": "diminished",
|
|
580
|
+
"6": "Doubly Augmented",
|
|
581
|
+
"1": "doubly diminished"
|
|
582
|
+
},
|
|
583
|
+
"4": {
|
|
584
|
+
// Fourth
|
|
585
|
+
"5": "Perfect",
|
|
586
|
+
"6": "Augmented",
|
|
587
|
+
"4": "diminished",
|
|
588
|
+
"7": "Doubly Augmented",
|
|
589
|
+
"3": "doubly diminished"
|
|
590
|
+
},
|
|
591
|
+
"5": {
|
|
592
|
+
// Fifth
|
|
593
|
+
"7": "Perfect",
|
|
594
|
+
"8": "Augmented",
|
|
595
|
+
"6": "diminished",
|
|
596
|
+
"9": "Doubly Augmented",
|
|
597
|
+
"5": "doubly diminished"
|
|
598
|
+
},
|
|
599
|
+
"6": {
|
|
600
|
+
// Sixth
|
|
601
|
+
"9": "Major",
|
|
602
|
+
"8": "minor",
|
|
603
|
+
"10": "Augmented",
|
|
604
|
+
"7": "diminished",
|
|
605
|
+
"11": "Doubly Augmented",
|
|
606
|
+
"6": "doubly diminished"
|
|
607
|
+
},
|
|
608
|
+
"7": {
|
|
609
|
+
// Seventh
|
|
610
|
+
"11": "Major",
|
|
611
|
+
"10": "minor",
|
|
612
|
+
"12": "Augmented",
|
|
613
|
+
"9": "diminished",
|
|
614
|
+
"13": "Doubly Augmented",
|
|
615
|
+
"8": "doubly diminished"
|
|
616
|
+
},
|
|
617
|
+
"8": {
|
|
618
|
+
// Octave
|
|
619
|
+
"12": "Perfect",
|
|
620
|
+
"13": "Augmented",
|
|
621
|
+
"11": "diminished",
|
|
622
|
+
"14": "Doubly Augmented",
|
|
623
|
+
"10": "doubly diminished"
|
|
624
|
+
}
|
|
625
|
+
};
|
|
626
|
+
function getIntervalQuality(diatonicInterval, chromaticInterval) {
|
|
627
|
+
while (diatonicInterval < 1) {
|
|
628
|
+
diatonicInterval += 7;
|
|
629
|
+
chromaticInterval += 12;
|
|
630
|
+
}
|
|
631
|
+
while (diatonicInterval > 8) {
|
|
632
|
+
diatonicInterval -= 7;
|
|
633
|
+
chromaticInterval -= 12;
|
|
634
|
+
}
|
|
635
|
+
const qualities = IntervalQualities[diatonicInterval];
|
|
636
|
+
if (qualities) {
|
|
637
|
+
return qualities[chromaticInterval];
|
|
638
|
+
} else {
|
|
639
|
+
return void 0;
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
function validateIntervalQuality(q) {
|
|
643
|
+
if (!(q === "Perfect" || q === "Major" || q === "minor" || q === "Augmented" || q === "diminished" || q === "Doubly Augmented" || q === "doubly diminished")) {
|
|
644
|
+
throw new import_core4.MusicError(import_core4.MusicErrorType.InvalidArg, `Invalid interval quality: ${q}`);
|
|
645
|
+
} else {
|
|
646
|
+
return q;
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
function formatQuantity(q) {
|
|
650
|
+
if (!import_ts_utils_lib4.Utils.Is.isIntegerGte(q, 1)) {
|
|
651
|
+
throw new import_core4.MusicError(import_core4.MusicErrorType.InvalidArg, `Invalid interval quantity: ${q}`);
|
|
652
|
+
} else {
|
|
653
|
+
return import_ts_utils_lib4.Utils.Math.toOrdinalNumber(q);
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
var InvalidIntervalException = class extends Error {
|
|
657
|
+
constructor(msg) {
|
|
658
|
+
super(msg);
|
|
659
|
+
this.msg = msg;
|
|
660
|
+
this.name = "InvalidInterval";
|
|
661
|
+
}
|
|
662
|
+
};
|
|
663
|
+
var Interval = class _Interval {
|
|
664
|
+
constructor(note1, note2) {
|
|
665
|
+
this.note1 = note1;
|
|
666
|
+
this.note2 = note2;
|
|
667
|
+
__publicField(this, "direction");
|
|
668
|
+
__publicField(this, "semitones");
|
|
669
|
+
__publicField(this, "quantity");
|
|
670
|
+
__publicField(this, "quality");
|
|
671
|
+
if (note2.diatonicId >= note1.diatonicId) {
|
|
672
|
+
this.direction = note2.diatonicId === note1.diatonicId ? "Unison" : "Ascending";
|
|
673
|
+
this.quantity = note2.diatonicId - note1.diatonicId + 1;
|
|
674
|
+
this.semitones = note2.chromaticId - note1.chromaticId;
|
|
675
|
+
} else {
|
|
676
|
+
this.direction = "Descending";
|
|
677
|
+
this.quantity = note1.diatonicId - note2.diatonicId + 1;
|
|
678
|
+
this.semitones = note1.chromaticId - note2.chromaticId;
|
|
679
|
+
}
|
|
680
|
+
let quality = getIntervalQuality(this.quantity, this.semitones);
|
|
681
|
+
if (quality) {
|
|
682
|
+
this.quality = quality;
|
|
683
|
+
} else {
|
|
684
|
+
throw new InvalidIntervalException("Unknown interval quality");
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
static get(note1, note2) {
|
|
688
|
+
try {
|
|
689
|
+
return new _Interval(note1, note2);
|
|
690
|
+
} catch (err) {
|
|
691
|
+
if (err instanceof InvalidIntervalException) {
|
|
692
|
+
return void 0;
|
|
693
|
+
} else {
|
|
694
|
+
throw err;
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
toString() {
|
|
699
|
+
let direction = this.direction === "Unison" ? "" : this.direction + " ";
|
|
700
|
+
let quality = this.quality + " ";
|
|
701
|
+
let quantity = this.direction === "Unison" ? "Unison" : formatQuantity(this.quantity);
|
|
702
|
+
return direction + quality + quantity;
|
|
703
|
+
}
|
|
704
|
+
toAbbrString() {
|
|
705
|
+
var _a;
|
|
706
|
+
let direction = this.direction === "Descending" ? "\u2193" : "";
|
|
707
|
+
let quality = (_a = IntervalQualityAbbrMap.get(this.quality)) != null ? _a : "?";
|
|
708
|
+
let quantity = this.quantity;
|
|
709
|
+
return direction + quality + quantity;
|
|
710
|
+
}
|
|
711
|
+
};
|
|
712
|
+
|
|
713
|
+
// src/theory/scale.ts
|
|
714
|
+
var import_core5 = require("@tspro/web-music-score/core");
|
|
715
|
+
function getNaturalDiatonicId(chromaticId) {
|
|
716
|
+
let diatonicClass = Note.getDiatonicClass("CCDDEFFGGAAB"[Note.getChromaticClass(chromaticId)]);
|
|
717
|
+
let octave = Note.getOctaveFromChromaticId(chromaticId);
|
|
718
|
+
return Note.getDiatonicIdInOctave(diatonicClass, octave);
|
|
719
|
+
}
|
|
720
|
+
var FullTonicList = [
|
|
721
|
+
"Cb",
|
|
722
|
+
"C",
|
|
723
|
+
"C#",
|
|
724
|
+
"Db",
|
|
725
|
+
"D",
|
|
726
|
+
"D#",
|
|
727
|
+
"Eb",
|
|
728
|
+
"E",
|
|
729
|
+
"E#",
|
|
730
|
+
"Fb",
|
|
731
|
+
"F",
|
|
732
|
+
"F#",
|
|
733
|
+
"Gb",
|
|
734
|
+
"G",
|
|
735
|
+
"G#",
|
|
736
|
+
"Ab",
|
|
737
|
+
"A",
|
|
738
|
+
"A#",
|
|
739
|
+
"Bb",
|
|
740
|
+
"B",
|
|
741
|
+
"B#"
|
|
742
|
+
];
|
|
743
|
+
var ScaleType = /* @__PURE__ */ ((ScaleType2) => {
|
|
744
|
+
ScaleType2["Major"] = "Major";
|
|
745
|
+
ScaleType2["NaturalMinor"] = "Natural Minor";
|
|
746
|
+
ScaleType2["HarmonicMinor"] = "Harmonic Minor";
|
|
747
|
+
ScaleType2["Ionian"] = "Ionian";
|
|
748
|
+
ScaleType2["Dorian"] = "Dorian";
|
|
749
|
+
ScaleType2["Phrygian"] = "Phrygian";
|
|
750
|
+
ScaleType2["Lydian"] = "Lydian";
|
|
751
|
+
ScaleType2["Mixolydian"] = "Mixolydian";
|
|
752
|
+
ScaleType2["Aeolian"] = "Aeolian";
|
|
753
|
+
ScaleType2["Locrian"] = "Locrian";
|
|
754
|
+
ScaleType2["MajorPentatonic"] = "Major Pentatonic";
|
|
755
|
+
ScaleType2["MinorPentatonic"] = "Minor Pentatonic";
|
|
756
|
+
ScaleType2["MajorHexatonicBlues"] = "Major Hexatonic Blues";
|
|
757
|
+
ScaleType2["MinorHexatonicBlues"] = "Minor Hexatonic Blues";
|
|
758
|
+
ScaleType2["HeptatonicBlues"] = "Heptatonic Blues";
|
|
759
|
+
return ScaleType2;
|
|
760
|
+
})(ScaleType || {});
|
|
761
|
+
function getMode(scaleType) {
|
|
762
|
+
switch (scaleType) {
|
|
763
|
+
case "Major" /* Major */:
|
|
764
|
+
return 1;
|
|
765
|
+
case "Natural Minor" /* NaturalMinor */:
|
|
766
|
+
return 6;
|
|
767
|
+
case "Harmonic Minor" /* HarmonicMinor */:
|
|
768
|
+
return 6;
|
|
769
|
+
case "Ionian" /* Ionian */:
|
|
770
|
+
return 1;
|
|
771
|
+
case "Dorian" /* Dorian */:
|
|
772
|
+
return 2;
|
|
773
|
+
case "Phrygian" /* Phrygian */:
|
|
774
|
+
return 3;
|
|
775
|
+
case "Lydian" /* Lydian */:
|
|
776
|
+
return 4;
|
|
777
|
+
case "Mixolydian" /* Mixolydian */:
|
|
778
|
+
return 5;
|
|
779
|
+
case "Aeolian" /* Aeolian */:
|
|
780
|
+
return 6;
|
|
781
|
+
case "Locrian" /* Locrian */:
|
|
782
|
+
return 7;
|
|
783
|
+
case "Major Pentatonic" /* MajorPentatonic */:
|
|
784
|
+
return 1;
|
|
785
|
+
case "Minor Pentatonic" /* MinorPentatonic */:
|
|
786
|
+
return 6;
|
|
787
|
+
case "Major Hexatonic Blues" /* MajorHexatonicBlues */:
|
|
788
|
+
return 1;
|
|
789
|
+
case "Minor Hexatonic Blues" /* MinorHexatonicBlues */:
|
|
790
|
+
return 6;
|
|
791
|
+
case "Heptatonic Blues" /* HeptatonicBlues */:
|
|
792
|
+
return 1;
|
|
793
|
+
default:
|
|
794
|
+
throw new import_core5.MusicError(import_core5.MusicErrorType.Scale, `Invalid scaleType: ${scaleType}`);
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
var Scale = class extends KeySignature {
|
|
798
|
+
constructor(tonic, scaleType) {
|
|
799
|
+
super(tonic, getMode(scaleType));
|
|
800
|
+
this.tonic = tonic;
|
|
801
|
+
this.scaleType = scaleType;
|
|
802
|
+
__publicField(this, "scaleDegrees");
|
|
803
|
+
__publicField(this, "scaleNotes");
|
|
804
|
+
__publicField(this, "chromaticClassDegree");
|
|
805
|
+
__publicField(this, "preferredChromaticNoteCache", /* @__PURE__ */ new Map());
|
|
806
|
+
switch (scaleType) {
|
|
807
|
+
case "Harmonic Minor" /* HarmonicMinor */:
|
|
808
|
+
this.scaleDegrees = [1, 2, 3, 4, 5, 6, "#7"];
|
|
809
|
+
break;
|
|
810
|
+
case "Major Pentatonic" /* MajorPentatonic */:
|
|
811
|
+
this.scaleDegrees = [1, 2, 3, 5, 6];
|
|
812
|
+
break;
|
|
813
|
+
case "Minor Pentatonic" /* MinorPentatonic */:
|
|
814
|
+
this.scaleDegrees = [1, 3, 4, 5, 7];
|
|
815
|
+
break;
|
|
816
|
+
case "Major Hexatonic Blues" /* MajorHexatonicBlues */:
|
|
817
|
+
this.scaleDegrees = [1, 2, "b3", 3, 5, 6];
|
|
818
|
+
break;
|
|
819
|
+
case "Minor Hexatonic Blues" /* MinorHexatonicBlues */:
|
|
820
|
+
this.scaleDegrees = [1, 3, 4, "b5", 5, 7];
|
|
821
|
+
break;
|
|
822
|
+
case "Heptatonic Blues" /* HeptatonicBlues */:
|
|
823
|
+
this.scaleDegrees = [1, 2, "b3", 4, "b5", 6, "b7"];
|
|
824
|
+
break;
|
|
825
|
+
default:
|
|
826
|
+
this.scaleDegrees = [1, 2, 3, 4, 5, 6, 7];
|
|
827
|
+
break;
|
|
828
|
+
}
|
|
829
|
+
this.scaleNotes = this.scaleDegrees.map((d) => this.getNoteByDegree(d));
|
|
830
|
+
this.chromaticClassDegree = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11].map((chromaticClass) => {
|
|
831
|
+
let id = this.scaleNotes.findIndex((scaleNote) => scaleNote.chromaticClass === chromaticClass);
|
|
832
|
+
return id >= 0 ? this.scaleDegrees[id] : void 0;
|
|
833
|
+
});
|
|
834
|
+
}
|
|
835
|
+
static equals(a, b) {
|
|
836
|
+
if (a == null && b == null) {
|
|
837
|
+
return true;
|
|
838
|
+
} else if (a == null || b == null) {
|
|
839
|
+
return false;
|
|
840
|
+
} else {
|
|
841
|
+
return a === b || a.getScaleName() === b.getScaleName();
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
getScaleName(symbolSet) {
|
|
845
|
+
switch (symbolSet) {
|
|
846
|
+
case 1 /* Unicode */:
|
|
847
|
+
return Note.getScientificNoteName(this.tonic, symbolSet) + " " + this.scaleType;
|
|
848
|
+
default:
|
|
849
|
+
return this.tonic + " " + this.scaleType;
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
getScaleNotes(bottomNote, numOctaves) {
|
|
853
|
+
if (!import_ts_utils_lib5.Utils.Is.isIntegerGte(numOctaves, 1)) {
|
|
854
|
+
throw new import_core5.MusicError(import_core5.MusicErrorType.Scale, `Invalid numOctaves: ${numOctaves}`);
|
|
855
|
+
}
|
|
856
|
+
let scaleNoteList = [];
|
|
857
|
+
for (let o = 1; o <= numOctaves; o++) {
|
|
858
|
+
scaleNoteList = [...scaleNoteList, ...this.scaleNotes];
|
|
859
|
+
}
|
|
860
|
+
scaleNoteList.push(this.scaleNotes[0]);
|
|
861
|
+
let diatonicId = Note.getNote(bottomNote).diatonicId;
|
|
862
|
+
return scaleNoteList.map((note) => {
|
|
863
|
+
diatonicId = Note.findNextDiatonicIdAbove(note.diatonicId, diatonicId, false);
|
|
864
|
+
return new Note(diatonicId, note.accidental);
|
|
865
|
+
});
|
|
866
|
+
}
|
|
867
|
+
getScaleOverview() {
|
|
868
|
+
return this.getScaleNotes("C4", 1).map((note) => note.formatOmitOctave(1 /* Unicode */)).join(" - ");
|
|
869
|
+
}
|
|
870
|
+
getScaleSteps() {
|
|
871
|
+
let chromaticIds = this.getScaleNotes("C4", 1).map((note) => note.chromaticId);
|
|
872
|
+
let steps = [];
|
|
873
|
+
for (let i = 0; i < chromaticIds.length - 1; i++) {
|
|
874
|
+
steps.push(import_ts_utils_lib5.Utils.Math.mod(chromaticIds[i + 1] - chromaticIds[i], 12));
|
|
875
|
+
}
|
|
876
|
+
return steps;
|
|
877
|
+
}
|
|
878
|
+
getScaleStringSteps() {
|
|
879
|
+
return this.getScaleSteps().map((step) => step === 1 ? "H" : step === 2 ? "W" : step.toString() + "H");
|
|
880
|
+
}
|
|
881
|
+
isScaleNote(note) {
|
|
882
|
+
return this.chromaticClassDegree[note.chromaticClass] !== void 0;
|
|
883
|
+
}
|
|
884
|
+
isScaleRootNote(note) {
|
|
885
|
+
return String(this.chromaticClassDegree[note.chromaticClass]) === "1";
|
|
886
|
+
}
|
|
887
|
+
getIntervalFromRootNote(note) {
|
|
888
|
+
let rootNote = this.getScaleNotes("C0", 1)[0];
|
|
889
|
+
while (note.chromaticId >= rootNote.chromaticId + 12) {
|
|
890
|
+
note = new Note(note.diatonicClass, note.accidental, note.octave - 1);
|
|
891
|
+
}
|
|
892
|
+
if (note.chromaticId < rootNote.chromaticId) {
|
|
893
|
+
throw new import_core5.MusicError(import_core5.MusicErrorType.Scale, `Note is below rootNote.`);
|
|
894
|
+
}
|
|
895
|
+
let interval = Interval.get(rootNote, note);
|
|
896
|
+
if (interval === void 0) {
|
|
897
|
+
throw new import_core5.MusicError(import_core5.MusicErrorType.Scale, `Interval is undefined.`);
|
|
898
|
+
} else {
|
|
899
|
+
return interval;
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
getPreferredChromaticNote(chromaticId) {
|
|
903
|
+
Note.validateChromaticId(chromaticId);
|
|
904
|
+
let note = this.preferredChromaticNoteCache.get(chromaticId);
|
|
905
|
+
if (note) {
|
|
906
|
+
return note;
|
|
907
|
+
}
|
|
908
|
+
let octave = Note.getOctaveFromChromaticId(chromaticId);
|
|
909
|
+
let scaleNotes = this.scaleNotes.map((accNote) => {
|
|
910
|
+
if (accNote.noteLetter === "C" && accNote.accidental < 0) {
|
|
911
|
+
return new Note(accNote.diatonicClass, accNote.accidental, octave + 1);
|
|
912
|
+
} else if (accNote.noteLetter === "B" && accNote.accidental > 0) {
|
|
913
|
+
return new Note(accNote.diatonicClass, accNote.accidental, octave - 1);
|
|
914
|
+
} else {
|
|
915
|
+
return new Note(accNote.diatonicClass, accNote.accidental, octave);
|
|
916
|
+
}
|
|
917
|
+
});
|
|
918
|
+
note = scaleNotes.find((note2) => Note.getChromaticClass(chromaticId) === note2.chromaticClass);
|
|
919
|
+
if (note) {
|
|
920
|
+
this.preferredChromaticNoteCache.set(chromaticId, note);
|
|
921
|
+
return note;
|
|
922
|
+
}
|
|
923
|
+
let diatonicIdMid = getNaturalDiatonicId(chromaticId);
|
|
924
|
+
let diatonicIdStart = diatonicIdMid - 2;
|
|
925
|
+
let diatonicIdEnd = diatonicIdMid + 2;
|
|
926
|
+
let preferFlat = this.getAccidentalType() === 1 /* Flats */;
|
|
927
|
+
let preferredAccs = preferFlat ? [0, -1, 1, -2, 2] : [0, 1, -1, 2, -2];
|
|
928
|
+
for (let ai = 0; ai < preferredAccs.length; ai++) {
|
|
929
|
+
let acc = preferredAccs[ai];
|
|
930
|
+
for (let diatonicId = Math.max(0, diatonicIdStart); diatonicId <= diatonicIdEnd; diatonicId++) {
|
|
931
|
+
note = new Note(diatonicId, acc);
|
|
932
|
+
if (chromaticId === note.chromaticId) {
|
|
933
|
+
this.preferredChromaticNoteCache.set(chromaticId, note);
|
|
934
|
+
return note;
|
|
935
|
+
}
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
note = Note.getChromaticNote(chromaticId);
|
|
939
|
+
this.preferredChromaticNoteCache.set(chromaticId, note);
|
|
940
|
+
return note;
|
|
941
|
+
}
|
|
942
|
+
};
|
|
943
|
+
var ScaleFactory = class {
|
|
944
|
+
constructor(type) {
|
|
945
|
+
this.type = type;
|
|
946
|
+
__publicField(this, "tonicList", []);
|
|
947
|
+
__publicField(this, "scaleMap", /* @__PURE__ */ new Map());
|
|
948
|
+
let naturalScales = [];
|
|
949
|
+
let sharpScales = [];
|
|
950
|
+
let flatScales = [];
|
|
951
|
+
FullTonicList.forEach((tonic) => {
|
|
952
|
+
try {
|
|
953
|
+
let scale = new Scale(tonic, this.type);
|
|
954
|
+
switch (scale.getAccidentalType()) {
|
|
955
|
+
case 0 /* Natural */:
|
|
956
|
+
naturalScales.push(scale);
|
|
957
|
+
break;
|
|
958
|
+
case 2 /* Sharps */:
|
|
959
|
+
if (tonic.endsWith("b")) {
|
|
960
|
+
return;
|
|
961
|
+
} else {
|
|
962
|
+
sharpScales.push(scale);
|
|
963
|
+
break;
|
|
964
|
+
}
|
|
965
|
+
case 1 /* Flats */:
|
|
966
|
+
if (tonic.endsWith("#")) {
|
|
967
|
+
return;
|
|
968
|
+
} else {
|
|
969
|
+
flatScales.push(scale);
|
|
970
|
+
break;
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
this.scaleMap.set(tonic, scale);
|
|
974
|
+
} catch (err) {
|
|
975
|
+
}
|
|
976
|
+
});
|
|
977
|
+
if (naturalScales.length === 0) {
|
|
978
|
+
throw new import_core5.MusicError(import_core5.MusicErrorType.Scale, `Expected natural scale.`);
|
|
979
|
+
}
|
|
980
|
+
const SortByAccidentalCountFunc = (a, b) => a.getNumAccidentals() - b.getNumAccidentals();
|
|
981
|
+
this.tonicList = [
|
|
982
|
+
...naturalScales.sort(SortByAccidentalCountFunc).map((scale) => scale.tonic),
|
|
983
|
+
"- Sharps -",
|
|
984
|
+
...sharpScales.sort(SortByAccidentalCountFunc).map((scale) => scale.tonic),
|
|
985
|
+
"- Flats -",
|
|
986
|
+
...flatScales.sort(SortByAccidentalCountFunc).map((scale) => scale.tonic)
|
|
987
|
+
];
|
|
988
|
+
}
|
|
989
|
+
getTonicList() {
|
|
990
|
+
return this.tonicList;
|
|
991
|
+
}
|
|
992
|
+
getDefaultTonic() {
|
|
993
|
+
return this.tonicList[0];
|
|
994
|
+
}
|
|
995
|
+
getType() {
|
|
996
|
+
return this.type;
|
|
997
|
+
}
|
|
998
|
+
getScale(tonic) {
|
|
999
|
+
let scale = this.scaleMap.get(tonic);
|
|
1000
|
+
if (!scale) {
|
|
1001
|
+
throw new import_core5.MusicError(import_core5.MusicErrorType.Scale, `Invalid scale: ${tonic} ${this.type}`);
|
|
1002
|
+
} else {
|
|
1003
|
+
return scale;
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
1006
|
+
hasScale(tonic) {
|
|
1007
|
+
return this.scaleMap.get(tonic) !== void 0;
|
|
1008
|
+
}
|
|
1009
|
+
};
|
|
1010
|
+
var ScaleFactoryList = [
|
|
1011
|
+
new ScaleFactory("Major" /* Major */),
|
|
1012
|
+
new ScaleFactory("Natural Minor" /* NaturalMinor */),
|
|
1013
|
+
new ScaleFactory("Harmonic Minor" /* HarmonicMinor */),
|
|
1014
|
+
"- Modes -",
|
|
1015
|
+
new ScaleFactory("Ionian" /* Ionian */),
|
|
1016
|
+
new ScaleFactory("Dorian" /* Dorian */),
|
|
1017
|
+
new ScaleFactory("Phrygian" /* Phrygian */),
|
|
1018
|
+
new ScaleFactory("Lydian" /* Lydian */),
|
|
1019
|
+
new ScaleFactory("Mixolydian" /* Mixolydian */),
|
|
1020
|
+
new ScaleFactory("Aeolian" /* Aeolian */),
|
|
1021
|
+
new ScaleFactory("Locrian" /* Locrian */),
|
|
1022
|
+
"- Pentatonic -",
|
|
1023
|
+
new ScaleFactory("Major Pentatonic" /* MajorPentatonic */),
|
|
1024
|
+
new ScaleFactory("Minor Pentatonic" /* MinorPentatonic */),
|
|
1025
|
+
"- Blues -",
|
|
1026
|
+
new ScaleFactory("Major Hexatonic Blues" /* MajorHexatonicBlues */),
|
|
1027
|
+
new ScaleFactory("Minor Hexatonic Blues" /* MinorHexatonicBlues */),
|
|
1028
|
+
new ScaleFactory("Heptatonic Blues" /* HeptatonicBlues */)
|
|
1029
|
+
];
|
|
1030
|
+
function getScaleFactoryList() {
|
|
1031
|
+
return ScaleFactoryList;
|
|
1032
|
+
}
|
|
1033
|
+
var ScaleFactoryMap = /* @__PURE__ */ new Map();
|
|
1034
|
+
ScaleFactoryList.forEach((factory) => {
|
|
1035
|
+
if (factory instanceof ScaleFactory) {
|
|
1036
|
+
ScaleFactoryMap.set(factory.getType(), factory);
|
|
1037
|
+
}
|
|
1038
|
+
});
|
|
1039
|
+
function getScaleFactory(scaleType) {
|
|
1040
|
+
let f = ScaleFactoryMap.get(scaleType);
|
|
1041
|
+
if (!f) {
|
|
1042
|
+
throw new import_core5.MusicError(import_core5.MusicErrorType.Scale, `Invalid scaleType: ${scaleType}`);
|
|
1043
|
+
} else {
|
|
1044
|
+
return f;
|
|
1045
|
+
}
|
|
1046
|
+
}
|
|
1047
|
+
function validateScaleType(scaleType) {
|
|
1048
|
+
if (import_ts_utils_lib5.Utils.Is.isEnumValue(scaleType, ScaleType)) {
|
|
1049
|
+
return scaleType;
|
|
1050
|
+
} else {
|
|
1051
|
+
throw new import_core5.MusicError(import_core5.MusicErrorType.Scale, `Invalid scaleType: ${scaleType}`);
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
function getScale(tonic, scaleType) {
|
|
1055
|
+
return getScaleFactory(scaleType).getScale(tonic);
|
|
1056
|
+
}
|
|
1057
|
+
var DefaultScale = getScale("C", "Major" /* Major */);
|
|
1058
|
+
function getDefaultScale() {
|
|
1059
|
+
return DefaultScale;
|
|
1060
|
+
}
|
|
1061
|
+
|
|
1062
|
+
// src/theory/chord.ts
|
|
1063
|
+
var import_core6 = require("@tspro/web-music-score/core");
|
|
1064
|
+
var isEqualNote = (n1, n2) => n1.chromaticClass === n2.chromaticClass;
|
|
1065
|
+
var OkayRootNoteList = [
|
|
1066
|
+
"C",
|
|
1067
|
+
"C#",
|
|
1068
|
+
"Db",
|
|
1069
|
+
// Same id, first one always gets found
|
|
1070
|
+
"D",
|
|
1071
|
+
"Eb",
|
|
1072
|
+
"E",
|
|
1073
|
+
"F",
|
|
1074
|
+
"F#",
|
|
1075
|
+
"Gb",
|
|
1076
|
+
"G",
|
|
1077
|
+
"Ab",
|
|
1078
|
+
"A",
|
|
1079
|
+
"Bb",
|
|
1080
|
+
"B",
|
|
1081
|
+
"Cb"
|
|
1082
|
+
].map((noteName) => Note.getNote(noteName + "0"));
|
|
1083
|
+
var okayRootNoteCache = /* @__PURE__ */ new Map();
|
|
1084
|
+
function getOkayRootNote(wantedRootNote) {
|
|
1085
|
+
let cacheKey = wantedRootNote.chromaticClass;
|
|
1086
|
+
let rootNote = okayRootNoteCache.get(cacheKey);
|
|
1087
|
+
if (!rootNote) {
|
|
1088
|
+
rootNote = OkayRootNoteList.find((note) => isEqualNote(note, wantedRootNote));
|
|
1089
|
+
if (!rootNote) {
|
|
1090
|
+
throw new import_core6.MusicError(import_core6.MusicErrorType.InvalidArg, `Invalid chord root note: ${wantedRootNote.formatOmitOctave(1 /* Unicode */)}`);
|
|
1091
|
+
}
|
|
1092
|
+
okayRootNoteCache.set(cacheKey, rootNote);
|
|
1093
|
+
}
|
|
1094
|
+
return rootNote;
|
|
1095
|
+
}
|
|
1096
|
+
function getChordNoteByDegree(chordRootNote, degree) {
|
|
1097
|
+
let chordRootNoteStr = chordRootNote.formatOmitOctave(0 /* Ascii */);
|
|
1098
|
+
let ks = getScale(chordRootNoteStr, "Major" /* Major */);
|
|
1099
|
+
return ks.getNoteByDegree(degree);
|
|
1100
|
+
}
|
|
1101
|
+
function removeNoteDuplicates(notes) {
|
|
1102
|
+
return import_ts_utils_lib6.Utils.Arr.removeDuplicatesCmp(notes, isEqualNote);
|
|
1103
|
+
}
|
|
1104
|
+
var ChordInfoList = [
|
|
1105
|
+
// Power chord
|
|
1106
|
+
{ name: "5", degrees: [1, 5] },
|
|
1107
|
+
// Triads
|
|
1108
|
+
{ name: "", degrees: [1, 3, 5] },
|
|
1109
|
+
{ name: "m", degrees: [1, "b3", 5] },
|
|
1110
|
+
{ name: "dim", degrees: [1, "b3", "b5"] },
|
|
1111
|
+
{ name: "aug", degrees: [1, 3, "#5"] },
|
|
1112
|
+
{ name: "sus2", degrees: [1, 2, 5] },
|
|
1113
|
+
{ name: "sus4", degrees: [1, 4, 5] },
|
|
1114
|
+
// Four-part chords
|
|
1115
|
+
{ name: "6", degrees: [1, 3, 5, 6] },
|
|
1116
|
+
{ name: "m6", degrees: [1, "b3", 5, 6] },
|
|
1117
|
+
{ name: "m(maj7)", degrees: [1, "b3", 5, 7] },
|
|
1118
|
+
{ name: "7", degrees: [1, 3, 5, "b7"] },
|
|
1119
|
+
{ name: "7\u266D5", degrees: [1, 3, "b5", "b7"] },
|
|
1120
|
+
{ name: "7\u266F5", degrees: [1, 3, "#5", "b7"] },
|
|
1121
|
+
{ name: "7sus2", degrees: [1, 2, 5, "b7"] },
|
|
1122
|
+
{ name: "7sus4", degrees: [1, 4, 5, "b7"] },
|
|
1123
|
+
{ name: "dim7", degrees: [1, "b3", "b5", "bb7"] },
|
|
1124
|
+
{ name: "maj7", degrees: [1, 3, 5, 7] },
|
|
1125
|
+
{ name: "maj7\u266D5", degrees: [1, 3, "b5", 7] },
|
|
1126
|
+
{ name: "maj7\u266F5", degrees: [1, 3, "#5", 7] },
|
|
1127
|
+
{ name: "m7", degrees: [1, "b3", 5, "b7"] },
|
|
1128
|
+
{ name: "m7\u266D5", degrees: [1, "b3", "b5", "b7"] },
|
|
1129
|
+
{ name: "m7\u266F5", degrees: [1, "b3", "#5", "b7"] },
|
|
1130
|
+
// Five-part chords
|
|
1131
|
+
{ name: "9", degrees: [1, 3, 5, "b7", 9] },
|
|
1132
|
+
{ name: "m9", degrees: [1, "b3", 5, "b7", 9] },
|
|
1133
|
+
{ name: "7\u266F9", degrees: [1, 3, 5, "b7", "#9"] },
|
|
1134
|
+
{ name: "7\u266D9", degrees: [1, 3, 5, "b7", "b9"] },
|
|
1135
|
+
// Six-part chords
|
|
1136
|
+
{ name: "11", degrees: [1, 3, 5, "b7", 9, 11] },
|
|
1137
|
+
{ name: "m11", degrees: [1, "b3", 5, "b7", 9, 11] },
|
|
1138
|
+
// Seven-part chords
|
|
1139
|
+
{ name: "13", degrees: [1, 3, 5, "b7", 9, 11, 13] },
|
|
1140
|
+
{ name: "m13", degrees: [1, "b3", 5, "b7", 9, 11, 13] }
|
|
1141
|
+
];
|
|
1142
|
+
function canOmitDegree(chordInfo, degree) {
|
|
1143
|
+
if (chordInfo.degrees.every((c) => c !== degree)) {
|
|
1144
|
+
return true;
|
|
1145
|
+
}
|
|
1146
|
+
return chordInfo.degrees.length >= 4 && degree === 5 || // Four (and higher) part chord can exclude 5th degree
|
|
1147
|
+
chordInfo.degrees.length >= 6 && degree === 9 || // Six (and higher) part chord can exclude 9th degree
|
|
1148
|
+
chordInfo.degrees.length >= 7 && degree === 11;
|
|
1149
|
+
}
|
|
1150
|
+
var InvalidChordException = class extends Error {
|
|
1151
|
+
constructor(msg) {
|
|
1152
|
+
super(msg);
|
|
1153
|
+
this.msg = msg;
|
|
1154
|
+
this.name = "InvalidChordException";
|
|
1155
|
+
}
|
|
1156
|
+
};
|
|
1157
|
+
var Chord = class _Chord {
|
|
1158
|
+
constructor(chordInfo, chordNotes, rootNote, bassNote) {
|
|
1159
|
+
this.chordInfo = chordInfo;
|
|
1160
|
+
this.rootNote = rootNote;
|
|
1161
|
+
__publicField(this, "name");
|
|
1162
|
+
__publicField(this, "notes");
|
|
1163
|
+
__publicField(this, "omitNotes");
|
|
1164
|
+
__publicField(this, "slashBassNote");
|
|
1165
|
+
this.name = chordInfo.name;
|
|
1166
|
+
let notesLeft = chordNotes.slice();
|
|
1167
|
+
let outOfChordBass = !notesLeft.some((note) => isEqualNote(note, bassNote));
|
|
1168
|
+
if (outOfChordBass) {
|
|
1169
|
+
notesLeft.push(bassNote);
|
|
1170
|
+
}
|
|
1171
|
+
this.notes = new Array(this.chordInfo.degrees.length);
|
|
1172
|
+
this.omitNotes = new Array(this.chordInfo.degrees.length);
|
|
1173
|
+
for (let i = 0; i < chordInfo.degrees.length; i++) {
|
|
1174
|
+
let degree = chordInfo.degrees[i];
|
|
1175
|
+
let degreeNote = this.notes[i] = getChordNoteByDegree(this.rootNote, degree);
|
|
1176
|
+
let noteIndex = notesLeft.findIndex((note) => isEqualNote(note, degreeNote));
|
|
1177
|
+
if (noteIndex >= 0) {
|
|
1178
|
+
this.omitNotes[i] = false;
|
|
1179
|
+
notesLeft.splice(noteIndex, 1);
|
|
1180
|
+
} else if (canOmitDegree(chordInfo, degree)) {
|
|
1181
|
+
this.omitNotes[i] = true;
|
|
1182
|
+
} else {
|
|
1183
|
+
throw new InvalidChordException("Missing chord note!");
|
|
1184
|
+
}
|
|
1185
|
+
if (isEqualNote(bassNote, degreeNote)) {
|
|
1186
|
+
bassNote = degreeNote;
|
|
1187
|
+
}
|
|
1188
|
+
}
|
|
1189
|
+
if (notesLeft.length > 0) {
|
|
1190
|
+
if (notesLeft.every((note) => isEqualNote(note, bassNote))) {
|
|
1191
|
+
this.slashBassNote = bassNote;
|
|
1192
|
+
} else {
|
|
1193
|
+
throw new InvalidChordException("Got some extra notes that are not bass note!");
|
|
1194
|
+
}
|
|
1195
|
+
} else {
|
|
1196
|
+
this.slashBassNote = isEqualNote(bassNote, this.rootNote) ? void 0 : bassNote;
|
|
1197
|
+
}
|
|
1198
|
+
if (chordInfo.name === "5" && this.slashBassNote) {
|
|
1199
|
+
throw new InvalidChordException("Power chord no bass note allowed!");
|
|
1200
|
+
}
|
|
1201
|
+
}
|
|
1202
|
+
static getChords(notes) {
|
|
1203
|
+
let chords = [];
|
|
1204
|
+
let chordNotes = Note.sort(notes);
|
|
1205
|
+
let bassNote = chordNotes[0];
|
|
1206
|
+
let uniqueNotes = removeNoteDuplicates(chordNotes);
|
|
1207
|
+
for (let inversion = 0; inversion < uniqueNotes.length; inversion++) {
|
|
1208
|
+
let rootNote = getOkayRootNote(uniqueNotes[inversion]);
|
|
1209
|
+
ChordInfoList.forEach((chordInfo) => {
|
|
1210
|
+
try {
|
|
1211
|
+
let newChord = new _Chord(chordInfo, uniqueNotes, rootNote, bassNote);
|
|
1212
|
+
let replaceIndex = chords.findIndex((chord) => chord.replaceWith(newChord));
|
|
1213
|
+
if (replaceIndex >= 0) {
|
|
1214
|
+
chords[replaceIndex] = newChord;
|
|
1215
|
+
} else {
|
|
1216
|
+
chords.push(newChord);
|
|
1217
|
+
}
|
|
1218
|
+
} catch (err) {
|
|
1219
|
+
if (!(err instanceof InvalidChordException)) {
|
|
1220
|
+
throw err;
|
|
1221
|
+
}
|
|
1222
|
+
}
|
|
1223
|
+
});
|
|
1224
|
+
}
|
|
1225
|
+
return chords;
|
|
1226
|
+
}
|
|
1227
|
+
replaceWith(arg) {
|
|
1228
|
+
if (arg.notes.length < this.notes.length) {
|
|
1229
|
+
return false;
|
|
1230
|
+
} else if (arg.slashBassNote && this.slashBassNote && !isEqualNote(arg.slashBassNote, this.slashBassNote) || arg.slashBassNote && !this.slashBassNote || !arg.slashBassNote && this.slashBassNote) {
|
|
1231
|
+
return false;
|
|
1232
|
+
}
|
|
1233
|
+
for (let i = 0; i < this.notes.length; i++) {
|
|
1234
|
+
if (!isEqualNote(arg.notes[i], this.notes[i]) || arg.omitNotes[i] !== this.omitNotes[i]) {
|
|
1235
|
+
return false;
|
|
1236
|
+
}
|
|
1237
|
+
}
|
|
1238
|
+
return true;
|
|
1239
|
+
}
|
|
1240
|
+
/**
|
|
1241
|
+
* @returns Chord name e.g. "C/B"
|
|
1242
|
+
*/
|
|
1243
|
+
toString() {
|
|
1244
|
+
let symbolSet = 1 /* Unicode */;
|
|
1245
|
+
let rootNoteStr = this.rootNote.formatOmitOctave(symbolSet);
|
|
1246
|
+
let slashBassStr = this.slashBassNote ? "/" + this.slashBassNote.formatOmitOctave(symbolSet) : "";
|
|
1247
|
+
return rootNoteStr + this.name + slashBassStr;
|
|
1248
|
+
}
|
|
1249
|
+
/**
|
|
1250
|
+
* @returns Degree notation string, e.g. "E - 1(C) - 3(E) - 5(G)"
|
|
1251
|
+
*/
|
|
1252
|
+
getDegreeNotationString() {
|
|
1253
|
+
let symbolSet = 1 /* Unicode */;
|
|
1254
|
+
let bassNoteStr = this.slashBassNote ? this.slashBassNote.formatOmitOctave(symbolSet) + " - " : "";
|
|
1255
|
+
let degreeNoteStr = this.omitNotes.map((omitNote, i) => {
|
|
1256
|
+
return this.getDegreeStr(i) + "(" + (omitNote ? "-" : this.getNoteStr(i)) + ")";
|
|
1257
|
+
}).join(" - ");
|
|
1258
|
+
return bassNoteStr + degreeNoteStr;
|
|
1259
|
+
}
|
|
1260
|
+
/**
|
|
1261
|
+
* @returns Omitted degrees string e.g. "Omits 5(G), 9(D)"
|
|
1262
|
+
*/
|
|
1263
|
+
getOmittedDegreesString() {
|
|
1264
|
+
let omittedStrList = this.omitNotes.map((omit, i) => {
|
|
1265
|
+
return omit ? this.getDegreeStr(i) + "(" + this.getNoteStr(i) + ")" : void 0;
|
|
1266
|
+
}).filter((str) => str !== void 0);
|
|
1267
|
+
return omittedStrList.length > 0 ? "Omits " + omittedStrList.join(", ") : "";
|
|
1268
|
+
}
|
|
1269
|
+
/**
|
|
1270
|
+
* @param i - Degree index
|
|
1271
|
+
* @returns Degree string for given degree index, e.g. "3"
|
|
1272
|
+
*/
|
|
1273
|
+
getDegreeStr(i) {
|
|
1274
|
+
return Note.replaceAccidentalSymbols("" + this.chordInfo.degrees[i], 1 /* Unicode */);
|
|
1275
|
+
}
|
|
1276
|
+
/**
|
|
1277
|
+
* @param i - Degree index
|
|
1278
|
+
* @returns Note string for given degree index, e.g. "E"
|
|
1279
|
+
*/
|
|
1280
|
+
getNoteStr(i) {
|
|
1281
|
+
return this.notes[i].formatOmitOctave(1 /* Unicode */);
|
|
1282
|
+
}
|
|
1283
|
+
};
|
|
1284
|
+
|
|
1285
|
+
// src/theory/guitar.ts
|
|
1286
|
+
var import_ts_utils_lib7 = require("@tspro/ts-utils-lib");
|
|
1287
|
+
|
|
1288
|
+
// src/theory/assets/tunings.json
|
|
1289
|
+
var tunings_default = {
|
|
1290
|
+
list: [
|
|
1291
|
+
{
|
|
1292
|
+
name: "Standard",
|
|
1293
|
+
strings: [
|
|
1294
|
+
"E2",
|
|
1295
|
+
"A2",
|
|
1296
|
+
"D3",
|
|
1297
|
+
"G3",
|
|
1298
|
+
"B3",
|
|
1299
|
+
"E4"
|
|
1300
|
+
]
|
|
1301
|
+
},
|
|
1302
|
+
{
|
|
1303
|
+
name: "B Standard",
|
|
1304
|
+
strings: [
|
|
1305
|
+
"B1",
|
|
1306
|
+
"E2",
|
|
1307
|
+
"A2",
|
|
1308
|
+
"D3",
|
|
1309
|
+
"F#3",
|
|
1310
|
+
"B3"
|
|
1311
|
+
]
|
|
1312
|
+
},
|
|
1313
|
+
{
|
|
1314
|
+
name: "C Standard",
|
|
1315
|
+
strings: [
|
|
1316
|
+
"C2",
|
|
1317
|
+
"F2",
|
|
1318
|
+
"A#2",
|
|
1319
|
+
"D#3",
|
|
1320
|
+
"G3",
|
|
1321
|
+
"C4"
|
|
1322
|
+
]
|
|
1323
|
+
},
|
|
1324
|
+
{
|
|
1325
|
+
name: "D Modal",
|
|
1326
|
+
strings: [
|
|
1327
|
+
"D2",
|
|
1328
|
+
"A2",
|
|
1329
|
+
"D3",
|
|
1330
|
+
"G3",
|
|
1331
|
+
"A3",
|
|
1332
|
+
"D4"
|
|
1333
|
+
]
|
|
1334
|
+
},
|
|
1335
|
+
{
|
|
1336
|
+
name: "D Standard",
|
|
1337
|
+
strings: [
|
|
1338
|
+
"D2",
|
|
1339
|
+
"G2",
|
|
1340
|
+
"C3",
|
|
1341
|
+
"F3",
|
|
1342
|
+
"A3",
|
|
1343
|
+
"D4"
|
|
1344
|
+
]
|
|
1345
|
+
},
|
|
1346
|
+
{
|
|
1347
|
+
name: "D# Standard",
|
|
1348
|
+
strings: [
|
|
1349
|
+
"D#2",
|
|
1350
|
+
"G#2",
|
|
1351
|
+
"C#3",
|
|
1352
|
+
"F#3",
|
|
1353
|
+
"A#3",
|
|
1354
|
+
"D#4"
|
|
1355
|
+
]
|
|
1356
|
+
},
|
|
1357
|
+
{
|
|
1358
|
+
name: "Double Drop D",
|
|
1359
|
+
strings: [
|
|
1360
|
+
"D2",
|
|
1361
|
+
"A2",
|
|
1362
|
+
"D3",
|
|
1363
|
+
"G3",
|
|
1364
|
+
"B3",
|
|
1365
|
+
"D4"
|
|
1366
|
+
]
|
|
1367
|
+
},
|
|
1368
|
+
{
|
|
1369
|
+
name: "Drop B",
|
|
1370
|
+
strings: [
|
|
1371
|
+
"B1",
|
|
1372
|
+
"F#2",
|
|
1373
|
+
"B2",
|
|
1374
|
+
"E3",
|
|
1375
|
+
"G#3",
|
|
1376
|
+
"C#4"
|
|
1377
|
+
]
|
|
1378
|
+
},
|
|
1379
|
+
{
|
|
1380
|
+
name: "Drop C",
|
|
1381
|
+
strings: [
|
|
1382
|
+
"C2",
|
|
1383
|
+
"G2",
|
|
1384
|
+
"C3",
|
|
1385
|
+
"F3",
|
|
1386
|
+
"A3",
|
|
1387
|
+
"D4"
|
|
1388
|
+
]
|
|
1389
|
+
},
|
|
1390
|
+
{
|
|
1391
|
+
name: "Drop D",
|
|
1392
|
+
strings: [
|
|
1393
|
+
"D2",
|
|
1394
|
+
"A2",
|
|
1395
|
+
"D3",
|
|
1396
|
+
"G3",
|
|
1397
|
+
"B3",
|
|
1398
|
+
"E4"
|
|
1399
|
+
]
|
|
1400
|
+
},
|
|
1401
|
+
{
|
|
1402
|
+
name: "Low C",
|
|
1403
|
+
strings: [
|
|
1404
|
+
"C2",
|
|
1405
|
+
"G2",
|
|
1406
|
+
"D3",
|
|
1407
|
+
"G3",
|
|
1408
|
+
"A3",
|
|
1409
|
+
"D4"
|
|
1410
|
+
]
|
|
1411
|
+
},
|
|
1412
|
+
{
|
|
1413
|
+
name: "New Standard",
|
|
1414
|
+
strings: [
|
|
1415
|
+
"C2",
|
|
1416
|
+
"G2",
|
|
1417
|
+
"D3",
|
|
1418
|
+
"A3",
|
|
1419
|
+
"E4",
|
|
1420
|
+
"G4"
|
|
1421
|
+
]
|
|
1422
|
+
},
|
|
1423
|
+
{
|
|
1424
|
+
name: "Open A",
|
|
1425
|
+
strings: [
|
|
1426
|
+
"E2",
|
|
1427
|
+
"A2",
|
|
1428
|
+
"C#3",
|
|
1429
|
+
"E3",
|
|
1430
|
+
"A3",
|
|
1431
|
+
"E4"
|
|
1432
|
+
]
|
|
1433
|
+
},
|
|
1434
|
+
{
|
|
1435
|
+
name: "Open A Minor",
|
|
1436
|
+
strings: [
|
|
1437
|
+
"E2",
|
|
1438
|
+
"A2",
|
|
1439
|
+
"E3",
|
|
1440
|
+
"A3",
|
|
1441
|
+
"C4",
|
|
1442
|
+
"E4"
|
|
1443
|
+
]
|
|
1444
|
+
},
|
|
1445
|
+
{
|
|
1446
|
+
name: "Open C",
|
|
1447
|
+
strings: [
|
|
1448
|
+
"C2",
|
|
1449
|
+
"G2",
|
|
1450
|
+
"C3",
|
|
1451
|
+
"G3",
|
|
1452
|
+
"C4",
|
|
1453
|
+
"E4"
|
|
1454
|
+
]
|
|
1455
|
+
},
|
|
1456
|
+
{
|
|
1457
|
+
name: "Open C Minor",
|
|
1458
|
+
strings: [
|
|
1459
|
+
"C2",
|
|
1460
|
+
"G2",
|
|
1461
|
+
"C3",
|
|
1462
|
+
"G3",
|
|
1463
|
+
"C4",
|
|
1464
|
+
"D#4"
|
|
1465
|
+
]
|
|
1466
|
+
},
|
|
1467
|
+
{
|
|
1468
|
+
name: "Open D",
|
|
1469
|
+
strings: [
|
|
1470
|
+
"D2",
|
|
1471
|
+
"A2",
|
|
1472
|
+
"D3",
|
|
1473
|
+
"F#3",
|
|
1474
|
+
"A3",
|
|
1475
|
+
"D4"
|
|
1476
|
+
]
|
|
1477
|
+
},
|
|
1478
|
+
{
|
|
1479
|
+
name: "Open D Minor",
|
|
1480
|
+
strings: [
|
|
1481
|
+
"D2",
|
|
1482
|
+
"A2",
|
|
1483
|
+
"D3",
|
|
1484
|
+
"F3",
|
|
1485
|
+
"A3",
|
|
1486
|
+
"D4"
|
|
1487
|
+
]
|
|
1488
|
+
},
|
|
1489
|
+
{
|
|
1490
|
+
name: "Open E",
|
|
1491
|
+
strings: [
|
|
1492
|
+
"E2",
|
|
1493
|
+
"B2",
|
|
1494
|
+
"E3",
|
|
1495
|
+
"G#3",
|
|
1496
|
+
"B3",
|
|
1497
|
+
"E4"
|
|
1498
|
+
]
|
|
1499
|
+
},
|
|
1500
|
+
{
|
|
1501
|
+
name: "Open E Minor",
|
|
1502
|
+
strings: [
|
|
1503
|
+
"E2",
|
|
1504
|
+
"B2",
|
|
1505
|
+
"E3",
|
|
1506
|
+
"G3",
|
|
1507
|
+
"B3",
|
|
1508
|
+
"E4"
|
|
1509
|
+
]
|
|
1510
|
+
},
|
|
1511
|
+
{
|
|
1512
|
+
name: "Open G",
|
|
1513
|
+
strings: [
|
|
1514
|
+
"D2",
|
|
1515
|
+
"G2",
|
|
1516
|
+
"D3",
|
|
1517
|
+
"G3",
|
|
1518
|
+
"B3",
|
|
1519
|
+
"D4"
|
|
1520
|
+
]
|
|
1521
|
+
},
|
|
1522
|
+
{
|
|
1523
|
+
name: "Open G Minor",
|
|
1524
|
+
strings: [
|
|
1525
|
+
"D2",
|
|
1526
|
+
"G2",
|
|
1527
|
+
"D3",
|
|
1528
|
+
"G3",
|
|
1529
|
+
"A#3",
|
|
1530
|
+
"D4"
|
|
1531
|
+
]
|
|
1532
|
+
}
|
|
1533
|
+
]
|
|
1534
|
+
};
|
|
1535
|
+
|
|
1536
|
+
// src/theory/guitar.ts
|
|
1537
|
+
var import_core7 = require("@tspro/web-music-score/core");
|
|
1538
|
+
var Handedness = /* @__PURE__ */ ((Handedness2) => {
|
|
1539
|
+
Handedness2[Handedness2["RightHanded"] = 0] = "RightHanded";
|
|
1540
|
+
Handedness2[Handedness2["LeftHanded"] = 1] = "LeftHanded";
|
|
1541
|
+
return Handedness2;
|
|
1542
|
+
})(Handedness || {});
|
|
1543
|
+
var DefaultHandedness = 0 /* RightHanded */;
|
|
1544
|
+
function validateHandedness(h) {
|
|
1545
|
+
if (!import_ts_utils_lib7.Utils.Is.isEnumValue(h, Handedness)) {
|
|
1546
|
+
throw new import_core7.MusicError(import_core7.MusicErrorType.InvalidArg, `Invalid handedness: ${h}`);
|
|
1547
|
+
} else {
|
|
1548
|
+
return h;
|
|
1549
|
+
}
|
|
1550
|
+
}
|
|
1551
|
+
var TuningNameList = tunings_default.list.map((data) => data.name);
|
|
1552
|
+
var DefaultTuningName = TuningNameList[0];
|
|
1553
|
+
function validateTuningName(tuningName) {
|
|
1554
|
+
if (TuningNameList.indexOf(tuningName) < 0) {
|
|
1555
|
+
throw new import_core7.MusicError(import_core7.MusicErrorType.InvalidArg, `Invalid tuning name: ${tuningName}`);
|
|
1556
|
+
} else {
|
|
1557
|
+
return tuningName;
|
|
1558
|
+
}
|
|
1559
|
+
}
|
|
1560
|
+
var TuningStringsCache = new import_ts_utils_lib7.LRUCache(100);
|
|
1561
|
+
function getTuningStrings(tuningName) {
|
|
1562
|
+
let tuningStrings = TuningStringsCache.get(tuningName);
|
|
1563
|
+
if (!tuningStrings) {
|
|
1564
|
+
let tuningData = tunings_default.list.find((data) => data.name === tuningName);
|
|
1565
|
+
if (!tuningData) {
|
|
1566
|
+
throw new import_core7.MusicError(import_core7.MusicErrorType.InvalidArg, `Invalid tuningName: ${tuningName}`);
|
|
1567
|
+
}
|
|
1568
|
+
tuningStrings = tuningData.strings.slice().reverse().map((noteName) => Note.getNote(noteName));
|
|
1569
|
+
if (!import_ts_utils_lib7.Utils.Is.isIntegerEq(tuningStrings.length, 6)) {
|
|
1570
|
+
throw new import_core7.MusicError(import_core7.MusicErrorType.Unknown, `Tuning has ${tuningStrings.length} strings.`);
|
|
1571
|
+
}
|
|
1572
|
+
TuningStringsCache.set(tuningName, tuningStrings);
|
|
1573
|
+
}
|
|
1574
|
+
return tuningStrings;
|
|
1575
|
+
}
|
|
1576
|
+
|
|
1577
|
+
// src/theory/time-signature.ts
|
|
1578
|
+
var import_ts_utils_lib9 = require("@tspro/ts-utils-lib");
|
|
1579
|
+
|
|
1580
|
+
// src/theory/rhythm.ts
|
|
1581
|
+
var import_ts_utils_lib8 = require("@tspro/ts-utils-lib");
|
|
1582
|
+
var import_core8 = require("@tspro/web-music-score/core");
|
|
1583
|
+
var NoteLength = /* @__PURE__ */ ((NoteLength3) => {
|
|
1584
|
+
NoteLength3[NoteLength3["Whole"] = 192] = "Whole";
|
|
1585
|
+
NoteLength3[NoteLength3["Half"] = 96] = "Half";
|
|
1586
|
+
NoteLength3[NoteLength3["Quarter"] = 48] = "Quarter";
|
|
1587
|
+
NoteLength3[NoteLength3["Eighth"] = 24] = "Eighth";
|
|
1588
|
+
NoteLength3[NoteLength3["Sixteenth"] = 12] = "Sixteenth";
|
|
1589
|
+
NoteLength3[NoteLength3["ThirtySecond"] = 6] = "ThirtySecond";
|
|
1590
|
+
NoteLength3[NoteLength3["SixtyFourth"] = 3] = "SixtyFourth";
|
|
1591
|
+
return NoteLength3;
|
|
1592
|
+
})(NoteLength || {});
|
|
1593
|
+
var MaxNoteLength = 192 /* Whole */;
|
|
1594
|
+
var MinNoteLength = 3 /* SixtyFourth */;
|
|
1595
|
+
var FlagCountMap = /* @__PURE__ */ new Map([
|
|
1596
|
+
[192 /* Whole */, 0],
|
|
1597
|
+
[96 /* Half */, 0],
|
|
1598
|
+
[48 /* Quarter */, 0],
|
|
1599
|
+
[24 /* Eighth */, 1],
|
|
1600
|
+
[12 /* Sixteenth */, 2],
|
|
1601
|
+
[6 /* ThirtySecond */, 3],
|
|
1602
|
+
[3 /* SixtyFourth */, 4]
|
|
1603
|
+
]);
|
|
1604
|
+
var NoteSymbolMap = /* @__PURE__ */ new Map([
|
|
1605
|
+
[192 /* Whole */, "\u{1D15D}"],
|
|
1606
|
+
[96 /* Half */, "\u{1D15E}"],
|
|
1607
|
+
[48 /* Quarter */, "\u{1D15F}"],
|
|
1608
|
+
[24 /* Eighth */, "\u{1D160}"],
|
|
1609
|
+
[12 /* Sixteenth */, "\u{1D161}"],
|
|
1610
|
+
[6 /* ThirtySecond */, "\u{1D162}"],
|
|
1611
|
+
[3 /* SixtyFourth */, "\u{1D163}"]
|
|
1612
|
+
]);
|
|
1613
|
+
function validateNoteLength(noteLength) {
|
|
1614
|
+
if (!import_ts_utils_lib8.Utils.Is.isEnumValue(noteLength, NoteLength)) {
|
|
1615
|
+
throw new import_core8.MusicError(import_core8.MusicErrorType.InvalidArg, `Invalid noteLength: ${noteLength}`);
|
|
1616
|
+
} else {
|
|
1617
|
+
return noteLength;
|
|
1618
|
+
}
|
|
1619
|
+
}
|
|
1620
|
+
var RhythmProps = class _RhythmProps {
|
|
1621
|
+
constructor(noteLength, dotted, triplet) {
|
|
1622
|
+
__publicField(this, "noteLength");
|
|
1623
|
+
__publicField(this, "dotted");
|
|
1624
|
+
__publicField(this, "triplet");
|
|
1625
|
+
__publicField(this, "ticks");
|
|
1626
|
+
__publicField(this, "flagCount");
|
|
1627
|
+
var _a;
|
|
1628
|
+
this.noteLength = validateNoteLength(noteLength);
|
|
1629
|
+
this.dotted = dotted === true;
|
|
1630
|
+
this.triplet = triplet === true;
|
|
1631
|
+
this.ticks = this.noteLength;
|
|
1632
|
+
this.flagCount = (_a = FlagCountMap.get(this.noteLength)) != null ? _a : 0;
|
|
1633
|
+
if (this.dotted && this.triplet) {
|
|
1634
|
+
throw new import_core8.MusicError(import_core8.MusicErrorType.Note, "Note cannot be both dotted and triplet!");
|
|
1635
|
+
} else if (this.dotted && this.noteLength === MinNoteLength) {
|
|
1636
|
+
throw new import_core8.MusicError(import_core8.MusicErrorType.Note, "Shortest note cannot be dotted!");
|
|
1637
|
+
}
|
|
1638
|
+
if (this.dotted) {
|
|
1639
|
+
this.ticks += this.noteLength / 2;
|
|
1640
|
+
}
|
|
1641
|
+
if (this.triplet) {
|
|
1642
|
+
this.ticks = this.ticks * 2 / 3;
|
|
1643
|
+
}
|
|
1644
|
+
}
|
|
1645
|
+
static createFromNoteSize(noteSize) {
|
|
1646
|
+
return new _RhythmProps(MaxNoteLength / noteSize);
|
|
1647
|
+
}
|
|
1648
|
+
canDot() {
|
|
1649
|
+
return !this.dotted && this.noteLength !== MinNoteLength;
|
|
1650
|
+
}
|
|
1651
|
+
hasStem() {
|
|
1652
|
+
return this.noteLength < 192 /* Whole */;
|
|
1653
|
+
}
|
|
1654
|
+
toString() {
|
|
1655
|
+
return NoteSymbolMap.get(this.noteLength) + (this.dotted ? "." : "");
|
|
1656
|
+
}
|
|
1657
|
+
};
|
|
1658
|
+
|
|
1659
|
+
// src/theory/time-signature.ts
|
|
1660
|
+
var import_core9 = require("@tspro/web-music-score/core");
|
|
1661
|
+
var TimeSignature = class {
|
|
1662
|
+
constructor(...args) {
|
|
1663
|
+
__publicField(this, "beatCount");
|
|
1664
|
+
__publicField(this, "beatSize");
|
|
1665
|
+
/** Lengths in ticks */
|
|
1666
|
+
__publicField(this, "beatLength");
|
|
1667
|
+
__publicField(this, "measureTicks");
|
|
1668
|
+
__publicField(this, "beamGroupCount");
|
|
1669
|
+
__publicField(this, "beamGroupLength");
|
|
1670
|
+
if (args.length === 1 && typeof args[0] === "string") {
|
|
1671
|
+
let parts = args[0].split("/");
|
|
1672
|
+
this.beatCount = +parts[0];
|
|
1673
|
+
this.beatSize = +parts[1];
|
|
1674
|
+
} else if (args.length === 2 && typeof args[0] === "number" && typeof args[1] === "number") {
|
|
1675
|
+
this.beatCount = args[0];
|
|
1676
|
+
this.beatSize = args[1];
|
|
1677
|
+
} else {
|
|
1678
|
+
throw new import_core9.MusicError(import_core9.MusicErrorType.Timesignature, `Invalid args: ${args}`);
|
|
1679
|
+
}
|
|
1680
|
+
if (!import_ts_utils_lib9.Utils.Is.isIntegerGte(this.beatCount, 1)) {
|
|
1681
|
+
throw new import_core9.MusicError(import_core9.MusicErrorType.Timesignature, `Invalid beatCount: ${this.beatCount}`);
|
|
1682
|
+
} else if (!import_ts_utils_lib9.Utils.Is.isIntegerGte(this.beatSize, 1)) {
|
|
1683
|
+
throw new import_core9.MusicError(import_core9.MusicErrorType.Timesignature, `Invalid beatSize: ${this.beatSize}`);
|
|
1684
|
+
}
|
|
1685
|
+
let beatLengthValue = RhythmProps.createFromNoteSize(this.beatSize);
|
|
1686
|
+
this.beatLength = beatLengthValue.noteLength;
|
|
1687
|
+
this.measureTicks = this.beatCount * beatLengthValue.ticks;
|
|
1688
|
+
if (this.is(2, 4) || this.is(3, 4) || this.is(4, 4)) {
|
|
1689
|
+
this.beamGroupCount = this.beatCount;
|
|
1690
|
+
} else if (this.is(6, 8) || this.is(9, 8)) {
|
|
1691
|
+
this.beamGroupCount = this.beatCount / 3;
|
|
1692
|
+
} else {
|
|
1693
|
+
console.warn("Not necessarily an error, but unsupported time signature: " + this.toString());
|
|
1694
|
+
this.beamGroupCount = 1;
|
|
1695
|
+
}
|
|
1696
|
+
this.beamGroupLength = this.measureTicks / this.beamGroupCount;
|
|
1697
|
+
if (!import_ts_utils_lib9.Utils.Is.isIntegerGte(this.beamGroupLength, 1)) {
|
|
1698
|
+
throw new import_core9.MusicError(import_core9.MusicErrorType.Timesignature, `Invalid beamGroupLength: ${this.beamGroupLength}`);
|
|
1699
|
+
}
|
|
1700
|
+
}
|
|
1701
|
+
is(beatCount, beatSize) {
|
|
1702
|
+
return this.beatCount === beatCount && this.beatSize === beatSize;
|
|
1703
|
+
}
|
|
1704
|
+
toString() {
|
|
1705
|
+
return this.beatCount + "/" + this.beatSize;
|
|
1706
|
+
}
|
|
1707
|
+
};
|
|
1708
|
+
var defaultTimeSignature;
|
|
1709
|
+
function getDefaultTimeSignature() {
|
|
1710
|
+
if (!defaultTimeSignature) {
|
|
1711
|
+
defaultTimeSignature = new TimeSignature(4, 4);
|
|
1712
|
+
}
|
|
1713
|
+
return defaultTimeSignature;
|
|
1714
|
+
}
|
|
1715
|
+
|
|
1716
|
+
// src/theory/tempo.ts
|
|
1717
|
+
var defaultTempo;
|
|
1718
|
+
function getDefaultTempo() {
|
|
1719
|
+
if (!defaultTempo) {
|
|
1720
|
+
defaultTempo = { beatsPerMinute: 120, options: { beatLength: 48 /* Quarter */, dotted: false } };
|
|
1721
|
+
}
|
|
1722
|
+
return defaultTempo;
|
|
1723
|
+
}
|
|
1724
|
+
function getTempoString(tempo) {
|
|
1725
|
+
return new RhythmProps(tempo.options.beatLength, tempo.options.dotted).toString() + "=" + tempo.beatsPerMinute;
|
|
1726
|
+
}
|
|
1727
|
+
function alterTempoSpeed(tempo, speed) {
|
|
1728
|
+
return {
|
|
1729
|
+
beatsPerMinute: tempo.beatsPerMinute * speed,
|
|
1730
|
+
options: { beatLength: tempo.options.beatLength, dotted: tempo.options.dotted }
|
|
1731
|
+
};
|
|
1732
|
+
}
|
|
1733
|
+
|
|
1734
|
+
// src/theory/index.ts
|
|
1735
|
+
var import_core10 = require("@tspro/web-music-score/core");
|
|
1736
|
+
(0, import_core10.init)();
|
|
1737
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
1738
|
+
0 && (module.exports = {
|
|
1739
|
+
AccidentalType,
|
|
1740
|
+
Chord,
|
|
1741
|
+
DefaultGuitarNoteLabel,
|
|
1742
|
+
DefaultHandedness,
|
|
1743
|
+
DefaultPitchNotation,
|
|
1744
|
+
DefaultTuningName,
|
|
1745
|
+
GuitarNoteLabel,
|
|
1746
|
+
GuitarNoteLabelList,
|
|
1747
|
+
Handedness,
|
|
1748
|
+
Interval,
|
|
1749
|
+
KeySignature,
|
|
1750
|
+
MaxNoteLength,
|
|
1751
|
+
MinNoteLength,
|
|
1752
|
+
Mode,
|
|
1753
|
+
Note,
|
|
1754
|
+
NoteLength,
|
|
1755
|
+
PitchNotation,
|
|
1756
|
+
PitchNotationList,
|
|
1757
|
+
RhythmProps,
|
|
1758
|
+
Scale,
|
|
1759
|
+
ScaleFactory,
|
|
1760
|
+
ScaleType,
|
|
1761
|
+
SymbolSet,
|
|
1762
|
+
TimeSignature,
|
|
1763
|
+
TuningNameList,
|
|
1764
|
+
alterTempoSpeed,
|
|
1765
|
+
getDefaultKeySignature,
|
|
1766
|
+
getDefaultScale,
|
|
1767
|
+
getDefaultTempo,
|
|
1768
|
+
getDefaultTimeSignature,
|
|
1769
|
+
getPitchNotationName,
|
|
1770
|
+
getScale,
|
|
1771
|
+
getScaleFactory,
|
|
1772
|
+
getScaleFactoryList,
|
|
1773
|
+
getTempoString,
|
|
1774
|
+
getTuningStrings,
|
|
1775
|
+
validateGuitarNoteLabel,
|
|
1776
|
+
validateHandedness,
|
|
1777
|
+
validateIntervalQuality,
|
|
1778
|
+
validateNoteLength,
|
|
1779
|
+
validatePitchNotation,
|
|
1780
|
+
validateScaleType,
|
|
1781
|
+
validateTuningName
|
|
1782
|
+
});
|
|
1783
|
+
//# sourceMappingURL=index.js.map
|