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