@scorelabs/core 1.0.7 → 1.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/importers/MusicXMLParser.d.ts +2 -2
- package/dist/importers/MusicXMLParser.js +75 -17
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/models/Instrument.d.ts +8 -19
- package/dist/models/Instrument.js +77 -23
- package/dist/models/Measure.d.ts +2 -0
- package/dist/models/Measure.js +6 -0
- package/dist/models/NoteSet.d.ts +40 -38
- package/dist/models/NoteSet.js +5 -2
- package/dist/models/Pitch.js +4 -0
- package/dist/models/PreMeasure.d.ts +24 -0
- package/dist/models/PreMeasure.js +30 -0
- package/dist/models/Score.d.ts +16 -1
- package/dist/models/Score.js +190 -5
- package/dist/models/index.d.ts +1 -0
- package/dist/models/index.js +1 -0
- package/dist/models/types.d.ts +2 -213
- package/dist/models/types.js +2 -213
- package/dist/types/Accidental.d.ts +7 -0
- package/dist/types/Accidental.js +8 -0
- package/dist/types/Arpeggio.d.ts +5 -0
- package/dist/types/Arpeggio.js +6 -0
- package/dist/types/Articulation.d.ts +10 -0
- package/dist/types/Articulation.js +11 -0
- package/dist/types/BarlineStyle.d.ts +9 -0
- package/dist/types/BarlineStyle.js +10 -0
- package/dist/types/Bowing.d.ts +4 -0
- package/dist/types/Bowing.js +5 -0
- package/dist/types/Clef.d.ts +10 -0
- package/dist/types/Clef.js +11 -0
- package/dist/types/Duration.d.ts +20 -0
- package/dist/types/Duration.js +60 -0
- package/dist/types/Dynamic.d.ts +12 -0
- package/dist/types/Dynamic.js +13 -0
- package/dist/types/Fretboard.d.ts +19 -0
- package/dist/types/Fretboard.js +1 -0
- package/dist/types/Genre.d.ts +27 -0
- package/dist/types/Genre.js +28 -0
- package/dist/types/Glissando.d.ts +8 -0
- package/dist/types/Glissando.js +5 -0
- package/dist/types/Hairpin.d.ts +10 -0
- package/dist/types/Hairpin.js +11 -0
- package/dist/types/InstrumentPreset.d.ts +11 -0
- package/dist/types/InstrumentPreset.js +12 -0
- package/dist/types/InstrumentType.d.ts +8 -0
- package/dist/types/InstrumentType.js +9 -0
- package/dist/types/KeySignature.d.ts +3 -0
- package/dist/types/KeySignature.js +1 -0
- package/dist/types/Lyric.d.ts +11 -0
- package/dist/types/Lyric.js +7 -0
- package/dist/types/NoteheadShape.d.ts +8 -0
- package/dist/types/NoteheadShape.js +9 -0
- package/dist/types/Ornament.d.ts +8 -0
- package/dist/types/Ornament.js +9 -0
- package/dist/types/Ottava.d.ts +10 -0
- package/dist/types/Ottava.js +7 -0
- package/dist/types/Pedal.d.ts +4 -0
- package/dist/types/Pedal.js +1 -0
- package/dist/types/Repeat.d.ts +8 -0
- package/dist/types/Repeat.js +1 -0
- package/dist/types/Slur.d.ts +4 -0
- package/dist/types/Slur.js +1 -0
- package/dist/types/StemDirection.d.ts +4 -0
- package/dist/types/StemDirection.js +5 -0
- package/dist/types/Tempo.d.ts +8 -0
- package/dist/types/Tempo.js +1 -0
- package/dist/types/TimeSignature.d.ts +6 -0
- package/dist/types/TimeSignature.js +3 -0
- package/dist/types/Tuplet.d.ts +5 -0
- package/dist/types/Tuplet.js +1 -0
- package/dist/types/index.d.ts +26 -0
- package/dist/types/index.js +26 -0
- package/package.json +1 -1
package/dist/models/Score.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Measure } from './Measure';
|
|
1
2
|
import { Part } from './Part';
|
|
2
3
|
import { Duration, Genre, decomposeDuration } from './types';
|
|
3
4
|
/**
|
|
@@ -120,6 +121,170 @@ export class Score {
|
|
|
120
121
|
const updatedMeasure = measure.replaceNoteSet(noteIndex, newNote, voiceIndex);
|
|
121
122
|
return this.replaceMeasure(partIndex, staffIndex, measureIndex, updatedMeasure, true);
|
|
122
123
|
}
|
|
124
|
+
withKeySignature(keySig) {
|
|
125
|
+
return new Score(this.title, this.composer, this.timeSignature, keySig, this.parts, this.bpm, this.tempoDuration, this.tempoIsDotted, this.copyright, this.lyricist, this.swing, this.subtitle, this.genre, this.tempoText);
|
|
126
|
+
}
|
|
127
|
+
withTimeSignature(timeSig) {
|
|
128
|
+
return new Score(this.title, this.composer, timeSig, this.keySignature, this.parts, this.bpm, this.tempoDuration, this.tempoIsDotted, this.copyright, this.lyricist, this.swing, this.subtitle, this.genre, this.tempoText);
|
|
129
|
+
}
|
|
130
|
+
updateMeasureSignatures(measureIndex, signatures, autoBeam = true) {
|
|
131
|
+
let score = this;
|
|
132
|
+
for (let pIdx = 0; pIdx < this.parts.length; pIdx++) {
|
|
133
|
+
for (let sIdx = 0; sIdx < this.parts[pIdx].staves.length; sIdx++) {
|
|
134
|
+
const currentMsr = score.parts[pIdx].staves[sIdx].measures[measureIndex];
|
|
135
|
+
if (currentMsr) {
|
|
136
|
+
let updatedMsr = currentMsr;
|
|
137
|
+
if (signatures.keySignature !== undefined) {
|
|
138
|
+
updatedMsr = updatedMsr.withKeySignature(signatures.keySignature);
|
|
139
|
+
}
|
|
140
|
+
if (signatures.timeSignature !== undefined) {
|
|
141
|
+
updatedMsr = updatedMsr.withTimeSignature(signatures.timeSignature);
|
|
142
|
+
}
|
|
143
|
+
if (signatures.clef !== undefined) {
|
|
144
|
+
updatedMsr = updatedMsr.withClef(signatures.clef);
|
|
145
|
+
}
|
|
146
|
+
score = score.replaceMeasure(pIdx, sIdx, measureIndex, updatedMsr, autoBeam);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
if (signatures.timeSignature !== undefined) {
|
|
151
|
+
score = score.reflow(measureIndex, autoBeam);
|
|
152
|
+
}
|
|
153
|
+
return score;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Reflows the notes starting from a specific measure index.
|
|
157
|
+
* This is useful when time signatures change and notes need to be redistributed.
|
|
158
|
+
*/
|
|
159
|
+
reflow(fromMeasureIndex, autoBeam = true) {
|
|
160
|
+
let currentScore = this;
|
|
161
|
+
const allStaves = this.getAllStaves();
|
|
162
|
+
for (const { partIndex, staffIndex } of allStaves) {
|
|
163
|
+
currentScore = currentScore.reflowStaff(partIndex, staffIndex, fromMeasureIndex, autoBeam);
|
|
164
|
+
}
|
|
165
|
+
// Harmonize measure count across all staves
|
|
166
|
+
const maxMeasures = Math.max(...currentScore.parts.flatMap((p) => p.staves.map((s) => s.measures.length)));
|
|
167
|
+
const minMeasures = Math.min(...currentScore.parts.flatMap((p) => p.staves.map((s) => s.measures.length)));
|
|
168
|
+
if (maxMeasures !== minMeasures) {
|
|
169
|
+
for (let pIdx = 0; pIdx < currentScore.parts.length; pIdx++) {
|
|
170
|
+
for (let sIdx = 0; sIdx < currentScore.parts[pIdx].staves.length; sIdx++) {
|
|
171
|
+
const staff = currentScore.parts[pIdx].staves[sIdx];
|
|
172
|
+
if (staff.measures.length < maxMeasures) {
|
|
173
|
+
let updatedMsrs = [...staff.measures];
|
|
174
|
+
for (let i = staff.measures.length; i < maxMeasures; i++) {
|
|
175
|
+
const ts = currentScore.getTimeSignatureAt(i);
|
|
176
|
+
const targetDur = ts.beats * (4 / ts.beatType);
|
|
177
|
+
updatedMsrs.push(new Measure([[]]).fillVoiceWithRests(0, targetDur));
|
|
178
|
+
}
|
|
179
|
+
currentScore = currentScore.replaceStaff(pIdx, sIdx, staff.withMeasures(updatedMsrs));
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return currentScore;
|
|
185
|
+
}
|
|
186
|
+
isTied(ns) {
|
|
187
|
+
return !!ns.notes[0].tie;
|
|
188
|
+
}
|
|
189
|
+
areSamePitch(ns1, ns2) {
|
|
190
|
+
if (ns1.isRest !== ns2.isRest)
|
|
191
|
+
return false;
|
|
192
|
+
if (ns1.isRest)
|
|
193
|
+
return true;
|
|
194
|
+
if (ns1.notes.length !== ns2.notes.length)
|
|
195
|
+
return false;
|
|
196
|
+
const p1 = ns1.notes.map((n) => n.pitch?.midiNumber || -1).sort((a, b) => a - b);
|
|
197
|
+
const p2 = ns2.notes.map((n) => n.pitch?.midiNumber || -1).sort((a, b) => a - b);
|
|
198
|
+
return p1.every((v, i) => v === p2[i]);
|
|
199
|
+
}
|
|
200
|
+
reflowStaff(pIdx, sIdx, fromMeasureIndex, autoBeam) {
|
|
201
|
+
const staff = this.parts[pIdx].staves[sIdx];
|
|
202
|
+
const measures = staff.measures;
|
|
203
|
+
const maxVoices = Math.max(...measures.map((m) => m.voices.length), 1);
|
|
204
|
+
let updatedMeasures = [...measures];
|
|
205
|
+
for (let vIdx = 0; vIdx < maxVoices; vIdx++) {
|
|
206
|
+
// 1. Collect notes and merge tied notes into logical streams
|
|
207
|
+
let stream = [];
|
|
208
|
+
for (let mIdx = fromMeasureIndex; mIdx < measures.length; mIdx++) {
|
|
209
|
+
const msr = measures[mIdx];
|
|
210
|
+
const voice = msr.voices[vIdx] || [];
|
|
211
|
+
for (const ns of voice) {
|
|
212
|
+
const d = ns.getDurationValue();
|
|
213
|
+
if (stream.length > 0 &&
|
|
214
|
+
this.isTied(stream[stream.length - 1].ns) &&
|
|
215
|
+
this.areSamePitch(stream[stream.length - 1].ns, ns)) {
|
|
216
|
+
stream[stream.length - 1].duration += d;
|
|
217
|
+
}
|
|
218
|
+
else {
|
|
219
|
+
stream.push({ ns, duration: d });
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
// 2. Redistribute logical notes into measures according to time signatures
|
|
224
|
+
let currentMIdx = fromMeasureIndex;
|
|
225
|
+
let streamIdx = 0;
|
|
226
|
+
while (streamIdx < stream.length) {
|
|
227
|
+
if (currentMIdx >= updatedMeasures.length) {
|
|
228
|
+
updatedMeasures.push(new Measure([[]]));
|
|
229
|
+
}
|
|
230
|
+
let msr = updatedMeasures[currentMIdx];
|
|
231
|
+
const ts = this.getTimeSignatureAt(currentMIdx);
|
|
232
|
+
const targetDur = ts.beats * (4 / ts.beatType);
|
|
233
|
+
const newVoices = [...msr.voices];
|
|
234
|
+
while (newVoices.length <= vIdx)
|
|
235
|
+
newVoices.push([]);
|
|
236
|
+
newVoices[vIdx] = [];
|
|
237
|
+
msr = msr.withVoices(newVoices);
|
|
238
|
+
let currentDur = 0;
|
|
239
|
+
while (streamIdx < stream.length &&
|
|
240
|
+
(currentDur < targetDur - 0.001 || stream[streamIdx].duration === 0)) {
|
|
241
|
+
const logicalNote = stream[streamIdx];
|
|
242
|
+
if (logicalNote.duration === 0) {
|
|
243
|
+
// Grace note or zero-duration element
|
|
244
|
+
msr = msr.withVoices(msr.voices.map((v, i) => (i === vIdx ? [...v, logicalNote.ns] : v)));
|
|
245
|
+
streamIdx++;
|
|
246
|
+
continue;
|
|
247
|
+
}
|
|
248
|
+
const remainingRoom = targetDur - currentDur;
|
|
249
|
+
const toTake = Math.min(logicalNote.duration, remainingRoom);
|
|
250
|
+
const parts = decomposeDuration(toTake);
|
|
251
|
+
const newNoteSets = parts.map((p, idx) => {
|
|
252
|
+
const isLastOfLogical = Math.abs(toTake - logicalNote.duration) < 0.001 && idx === parts.length - 1;
|
|
253
|
+
return logicalNote.ns
|
|
254
|
+
.withDuration(p.duration, p.isDotted)
|
|
255
|
+
.withTie(isLastOfLogical ? !!logicalNote.ns.notes[0].tie : true);
|
|
256
|
+
});
|
|
257
|
+
msr = msr.withVoices(msr.voices.map((v, i) => (i === vIdx ? [...v, ...newNoteSets] : v)));
|
|
258
|
+
logicalNote.duration -= toTake;
|
|
259
|
+
currentDur += toTake;
|
|
260
|
+
if (logicalNote.duration < 0.001) {
|
|
261
|
+
streamIdx++;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
// Fill with rests if score is not full
|
|
265
|
+
if (currentDur < targetDur - 0.001) {
|
|
266
|
+
msr = msr.fillVoiceWithRests(vIdx, targetDur);
|
|
267
|
+
}
|
|
268
|
+
if (autoBeam) {
|
|
269
|
+
msr = msr.autoBeam(ts);
|
|
270
|
+
}
|
|
271
|
+
updatedMeasures[currentMIdx] = msr;
|
|
272
|
+
currentMIdx++;
|
|
273
|
+
}
|
|
274
|
+
// Ensure any remaining measures in this staff are also cleared/filled with rests for this voice
|
|
275
|
+
for (let mIdx = currentMIdx; mIdx < updatedMeasures.length; mIdx++) {
|
|
276
|
+
const ts = this.getTimeSignatureAt(mIdx);
|
|
277
|
+
const targetDur = ts.beats * (4 / ts.beatType);
|
|
278
|
+
updatedMeasures[mIdx] = updatedMeasures[mIdx]
|
|
279
|
+
.withVoices(updatedMeasures[mIdx].voices.map((v, i) => (i === vIdx ? [] : v)))
|
|
280
|
+
.fillVoiceWithRests(vIdx, targetDur);
|
|
281
|
+
if (autoBeam) {
|
|
282
|
+
updatedMeasures[mIdx] = updatedMeasures[mIdx].autoBeam(ts);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
return this.replaceStaff(pIdx, sIdx, staff.withMeasures(updatedMeasures));
|
|
287
|
+
}
|
|
123
288
|
replaceMeasure(partIndex, staffIndex, measureIndex, newMeasure, autoBeam = true) {
|
|
124
289
|
if (partIndex < 0 || partIndex >= this.parts.length)
|
|
125
290
|
return this;
|
|
@@ -273,17 +438,27 @@ export class Score {
|
|
|
273
438
|
const measures = this.parts[0]?.staves[0]?.measures || [];
|
|
274
439
|
const sequence = [];
|
|
275
440
|
let i = 0;
|
|
276
|
-
|
|
441
|
+
const startRepeatStack = [0]; // Implicit start at 0
|
|
442
|
+
let justJumpedTo = -1;
|
|
277
443
|
const repeatCount = new Map();
|
|
278
444
|
let safetyCounter = 0;
|
|
279
445
|
const MAX_SEQUENCE = 10000;
|
|
280
446
|
while (i < measures.length && safetyCounter < MAX_SEQUENCE) {
|
|
281
447
|
safetyCounter++;
|
|
282
448
|
const m = measures[i];
|
|
283
|
-
|
|
284
|
-
|
|
449
|
+
// Handle Start Repeats
|
|
450
|
+
if (m.repeats.some((r) => r.type === 'start')) {
|
|
451
|
+
// Only push if we didn't just jump here (avoid re-pushing on loop reentry)
|
|
452
|
+
if (i !== justJumpedTo) {
|
|
453
|
+
startRepeatStack.push(i);
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
// Reset jump flag after processing start repeats check
|
|
457
|
+
if (i !== justJumpedTo)
|
|
458
|
+
justJumpedTo = -1;
|
|
285
459
|
const endRepeat = m.repeats.find((r) => r.type === 'end');
|
|
286
460
|
let iteration = 1;
|
|
461
|
+
// Calculate current iteration for Volta logic
|
|
287
462
|
if (endRepeat)
|
|
288
463
|
iteration = (repeatCount.get(i) || 0) + 1;
|
|
289
464
|
else {
|
|
@@ -307,11 +482,21 @@ export class Score {
|
|
|
307
482
|
const currentCount = repeatCount.get(i) || 0;
|
|
308
483
|
if (currentCount + 1 < maxTimes) {
|
|
309
484
|
repeatCount.set(i, currentCount + 1);
|
|
310
|
-
|
|
485
|
+
// Jump to the nearest start repeat
|
|
486
|
+
const target = startRepeatStack[startRepeatStack.length - 1];
|
|
487
|
+
i = target;
|
|
488
|
+
justJumpedTo = target;
|
|
311
489
|
continue;
|
|
312
490
|
}
|
|
313
|
-
else
|
|
491
|
+
else {
|
|
492
|
+
// Finished loop
|
|
314
493
|
repeatCount.set(i, 0);
|
|
494
|
+
// Pop the start repeat if we have one (keeping the implicit 0)
|
|
495
|
+
if (startRepeatStack.length > 1) {
|
|
496
|
+
startRepeatStack.pop();
|
|
497
|
+
}
|
|
498
|
+
// Do not pop 0, so unmatched repeats will default to 0
|
|
499
|
+
}
|
|
315
500
|
}
|
|
316
501
|
i++;
|
|
317
502
|
}
|
package/dist/models/index.d.ts
CHANGED
package/dist/models/index.js
CHANGED
package/dist/models/types.d.ts
CHANGED
|
@@ -1,216 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Shared types and enums for ScoreLabs
|
|
3
|
+
* All types have been moved to ../types/ for better organization.
|
|
3
4
|
*/
|
|
4
|
-
export
|
|
5
|
-
Up = "up",
|
|
6
|
-
Down = "down"
|
|
7
|
-
}
|
|
8
|
-
export declare enum Clef {
|
|
9
|
-
Treble = "treble",
|
|
10
|
-
Bass = "bass",
|
|
11
|
-
Alto = "alto",
|
|
12
|
-
Tenor = "tenor",
|
|
13
|
-
Percussion = "percussion",
|
|
14
|
-
Tab = "tab"
|
|
15
|
-
}
|
|
16
|
-
export declare enum Duration {
|
|
17
|
-
Whole = "whole",
|
|
18
|
-
Half = "half",
|
|
19
|
-
Quarter = "quarter",
|
|
20
|
-
Eighth = "eighth",
|
|
21
|
-
Sixteenth = "sixteenth",
|
|
22
|
-
ThirtySecond = "thirty-second",
|
|
23
|
-
SixtyFourth = "sixty-fourth",
|
|
24
|
-
OneHundredTwentyEighth = "one-hundred-twenty-eighth",
|
|
25
|
-
TwoHundredFiftySixth = "two-hundred-fifty-sixth"
|
|
26
|
-
}
|
|
27
|
-
export declare enum Accidental {
|
|
28
|
-
Sharp = "sharp",
|
|
29
|
-
Flat = "flat",
|
|
30
|
-
Natural = "natural",
|
|
31
|
-
DoubleSharp = "double-sharp",
|
|
32
|
-
DoubleFlat = "double-flat"
|
|
33
|
-
}
|
|
34
|
-
export declare enum Articulation {
|
|
35
|
-
Staccato = "staccato",
|
|
36
|
-
Accent = "accent",
|
|
37
|
-
Tenuto = "tenuto",
|
|
38
|
-
Marcato = "marcato",
|
|
39
|
-
Fermata = "fermata",
|
|
40
|
-
Staccatissimo = "staccatissimo",
|
|
41
|
-
Caesura = "caesura",
|
|
42
|
-
BreathMark = "breath-mark"
|
|
43
|
-
}
|
|
44
|
-
export declare enum Bowing {
|
|
45
|
-
DownBow = "down-bow",
|
|
46
|
-
UpBow = "up-bow"
|
|
47
|
-
}
|
|
48
|
-
export declare enum Syllabic {
|
|
49
|
-
Single = "single",
|
|
50
|
-
Begin = "begin",
|
|
51
|
-
Middle = "middle",
|
|
52
|
-
End = "end"
|
|
53
|
-
}
|
|
54
|
-
export interface Lyric {
|
|
55
|
-
text: string;
|
|
56
|
-
syllabic?: Syllabic;
|
|
57
|
-
isExtension?: boolean;
|
|
58
|
-
}
|
|
59
|
-
export declare enum NoteheadShape {
|
|
60
|
-
Normal = "normal",
|
|
61
|
-
Cross = "cross",// X shape (percussion, spoken)
|
|
62
|
-
Diamond = "diamond",// Harmonics
|
|
63
|
-
Slash = "slash",// Rhythmic notation
|
|
64
|
-
Triangle = "triangle",// Percussion
|
|
65
|
-
Square = "square"
|
|
66
|
-
}
|
|
67
|
-
export declare enum Dynamic {
|
|
68
|
-
PPP = "ppp",
|
|
69
|
-
PP = "pp",
|
|
70
|
-
P = "p",
|
|
71
|
-
MP = "mp",
|
|
72
|
-
MF = "mf",
|
|
73
|
-
F = "f",
|
|
74
|
-
FF = "ff",
|
|
75
|
-
FFF = "fff",
|
|
76
|
-
SFZ = "sfz",
|
|
77
|
-
FP = "fp"
|
|
78
|
-
}
|
|
79
|
-
export declare enum Genre {
|
|
80
|
-
Blues = "Blues",
|
|
81
|
-
Children = "Children",
|
|
82
|
-
Christian = "Christian",
|
|
83
|
-
Christmas = "Christmas",
|
|
84
|
-
Classical = "Classical",
|
|
85
|
-
ContestFestival = "Contest/Festival",
|
|
86
|
-
Country = "Country",
|
|
87
|
-
Educational = "Educational",
|
|
88
|
-
FilmTV = "Film/TV",
|
|
89
|
-
Folk = "Folk",
|
|
90
|
-
Games = "Games",
|
|
91
|
-
Gospel = "Gospel",
|
|
92
|
-
Holiday = "Holiday",
|
|
93
|
-
Jazz = "Jazz",
|
|
94
|
-
Latin = "Latin",
|
|
95
|
-
Musicals = "Musicals",
|
|
96
|
-
Pop = "Pop",
|
|
97
|
-
RBHipHop = "R&B/Hip-Hop",
|
|
98
|
-
Rock = "Rock",
|
|
99
|
-
Standards = "Standards",
|
|
100
|
-
Traditional = "Traditional",
|
|
101
|
-
Wedding = "Wedding",
|
|
102
|
-
World = "World",
|
|
103
|
-
Worship = "Worship",
|
|
104
|
-
Unknown = "unknown"
|
|
105
|
-
}
|
|
106
|
-
export interface TimeSignature {
|
|
107
|
-
beats: number;
|
|
108
|
-
beatType: number;
|
|
109
|
-
symbol?: 'common' | 'cut' | 'normal';
|
|
110
|
-
}
|
|
111
|
-
export interface KeySignature {
|
|
112
|
-
fifths: number;
|
|
113
|
-
}
|
|
114
|
-
export interface Tempo {
|
|
115
|
-
bpm: number;
|
|
116
|
-
duration: Duration;
|
|
117
|
-
isDotted: boolean;
|
|
118
|
-
text?: string;
|
|
119
|
-
}
|
|
120
|
-
export interface Slur {
|
|
121
|
-
placement: 'start' | 'stop';
|
|
122
|
-
direction?: 'up' | 'down';
|
|
123
|
-
}
|
|
124
|
-
export interface Tuplet {
|
|
125
|
-
actual: number;
|
|
126
|
-
normal: number;
|
|
127
|
-
type: 'start' | 'stop' | 'middle';
|
|
128
|
-
}
|
|
129
|
-
export declare enum HairpinType {
|
|
130
|
-
Crescendo = "crescendo",
|
|
131
|
-
Decrescendo = "decrescendo"
|
|
132
|
-
}
|
|
133
|
-
export interface Hairpin {
|
|
134
|
-
type: HairpinType;
|
|
135
|
-
placement: 'start' | 'stop';
|
|
136
|
-
}
|
|
137
|
-
export interface Repeat {
|
|
138
|
-
type: 'start' | 'end';
|
|
139
|
-
times?: number;
|
|
140
|
-
}
|
|
141
|
-
export interface Volta {
|
|
142
|
-
type: 'start' | 'stop' | 'both';
|
|
143
|
-
numbers: number[];
|
|
144
|
-
}
|
|
145
|
-
export declare enum BarlineStyle {
|
|
146
|
-
Regular = "regular",
|
|
147
|
-
Double = "light-light",// Double barline (often used for key changes)
|
|
148
|
-
Final = "light-heavy",
|
|
149
|
-
Dotted = "dotted",
|
|
150
|
-
Dashed = "dashed",
|
|
151
|
-
Heavy = "heavy",
|
|
152
|
-
None = "none"
|
|
153
|
-
}
|
|
154
|
-
export declare enum GlissandoType {
|
|
155
|
-
Wavy = "wavy",
|
|
156
|
-
Straight = "straight"
|
|
157
|
-
}
|
|
158
|
-
export interface Glissando {
|
|
159
|
-
type: GlissandoType;
|
|
160
|
-
placement: 'start' | 'stop';
|
|
161
|
-
}
|
|
162
|
-
export declare enum Arpeggio {
|
|
163
|
-
Normal = "normal",
|
|
164
|
-
Up = "up",
|
|
165
|
-
Down = "down"
|
|
166
|
-
}
|
|
167
|
-
export declare enum OttavaType {
|
|
168
|
-
OttavaAlta = "8va",
|
|
169
|
-
OttavaBassa = "8vb",
|
|
170
|
-
QuindicesimaAlta = "15ma",
|
|
171
|
-
QuindicesimaBassa = "15mb"
|
|
172
|
-
}
|
|
173
|
-
export interface Ottava {
|
|
174
|
-
type: OttavaType;
|
|
175
|
-
placement: 'start' | 'stop';
|
|
176
|
-
}
|
|
177
|
-
export interface Pedal {
|
|
178
|
-
type: 'sustain' | 'una-corda';
|
|
179
|
-
placement: 'start' | 'stop';
|
|
180
|
-
}
|
|
181
|
-
export declare enum Ornament {
|
|
182
|
-
Trill = "trill",
|
|
183
|
-
Mordent = "mordent",
|
|
184
|
-
InvertedMordent = "inverted-mordent",
|
|
185
|
-
Turn = "turn",
|
|
186
|
-
InvertedTurn = "inverted-turn",
|
|
187
|
-
Tremolo = "tremolo"
|
|
188
|
-
}
|
|
189
|
-
export declare const DURATION_VALUES: Record<Duration, number>;
|
|
190
|
-
/**
|
|
191
|
-
* Decomposes a duration value (quarter = 1) into a list of duration/dot pairs.
|
|
192
|
-
*/
|
|
193
|
-
export declare function decomposeDuration(value: number): {
|
|
194
|
-
duration: Duration;
|
|
195
|
-
isDotted: boolean;
|
|
196
|
-
val: number;
|
|
197
|
-
}[];
|
|
198
|
-
export interface FretboardDot {
|
|
199
|
-
string: number;
|
|
200
|
-
fret: number;
|
|
201
|
-
label?: string;
|
|
202
|
-
}
|
|
203
|
-
export interface FretboardBarre {
|
|
204
|
-
fret: number;
|
|
205
|
-
startString: number;
|
|
206
|
-
endString: number;
|
|
207
|
-
}
|
|
208
|
-
export interface FretboardDiagram {
|
|
209
|
-
strings: number;
|
|
210
|
-
frets: number;
|
|
211
|
-
startingFret?: number;
|
|
212
|
-
dots: FretboardDot[];
|
|
213
|
-
barres?: FretboardBarre[];
|
|
214
|
-
openStrings?: number[];
|
|
215
|
-
mutedStrings?: number[];
|
|
216
|
-
}
|
|
5
|
+
export * from '../types/index.js';
|
package/dist/models/types.js
CHANGED
|
@@ -1,216 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Shared types and enums for ScoreLabs
|
|
3
|
+
* All types have been moved to ../types/ for better organization.
|
|
3
4
|
*/
|
|
4
|
-
|
|
5
|
-
export var StemDirection;
|
|
6
|
-
(function (StemDirection) {
|
|
7
|
-
StemDirection["Up"] = "up";
|
|
8
|
-
StemDirection["Down"] = "down";
|
|
9
|
-
})(StemDirection || (StemDirection = {}));
|
|
10
|
-
// Clef types supported
|
|
11
|
-
export var Clef;
|
|
12
|
-
(function (Clef) {
|
|
13
|
-
Clef["Treble"] = "treble";
|
|
14
|
-
Clef["Bass"] = "bass";
|
|
15
|
-
Clef["Alto"] = "alto";
|
|
16
|
-
Clef["Tenor"] = "tenor";
|
|
17
|
-
Clef["Percussion"] = "percussion";
|
|
18
|
-
Clef["Tab"] = "tab";
|
|
19
|
-
})(Clef || (Clef = {}));
|
|
20
|
-
// Note duration types
|
|
21
|
-
export var Duration;
|
|
22
|
-
(function (Duration) {
|
|
23
|
-
Duration["Whole"] = "whole";
|
|
24
|
-
Duration["Half"] = "half";
|
|
25
|
-
Duration["Quarter"] = "quarter";
|
|
26
|
-
Duration["Eighth"] = "eighth";
|
|
27
|
-
Duration["Sixteenth"] = "sixteenth";
|
|
28
|
-
Duration["ThirtySecond"] = "thirty-second";
|
|
29
|
-
Duration["SixtyFourth"] = "sixty-fourth";
|
|
30
|
-
Duration["OneHundredTwentyEighth"] = "one-hundred-twenty-eighth";
|
|
31
|
-
Duration["TwoHundredFiftySixth"] = "two-hundred-fifty-sixth";
|
|
32
|
-
})(Duration || (Duration = {}));
|
|
33
|
-
// Accidental types
|
|
34
|
-
export var Accidental;
|
|
35
|
-
(function (Accidental) {
|
|
36
|
-
Accidental["Sharp"] = "sharp";
|
|
37
|
-
Accidental["Flat"] = "flat";
|
|
38
|
-
Accidental["Natural"] = "natural";
|
|
39
|
-
Accidental["DoubleSharp"] = "double-sharp";
|
|
40
|
-
Accidental["DoubleFlat"] = "double-flat";
|
|
41
|
-
})(Accidental || (Accidental = {}));
|
|
42
|
-
// Articulation types
|
|
43
|
-
export var Articulation;
|
|
44
|
-
(function (Articulation) {
|
|
45
|
-
Articulation["Staccato"] = "staccato";
|
|
46
|
-
Articulation["Accent"] = "accent";
|
|
47
|
-
Articulation["Tenuto"] = "tenuto";
|
|
48
|
-
Articulation["Marcato"] = "marcato";
|
|
49
|
-
Articulation["Fermata"] = "fermata";
|
|
50
|
-
Articulation["Staccatissimo"] = "staccatissimo";
|
|
51
|
-
Articulation["Caesura"] = "caesura";
|
|
52
|
-
Articulation["BreathMark"] = "breath-mark";
|
|
53
|
-
})(Articulation || (Articulation = {}));
|
|
54
|
-
// Bowing markings
|
|
55
|
-
export var Bowing;
|
|
56
|
-
(function (Bowing) {
|
|
57
|
-
Bowing["DownBow"] = "down-bow";
|
|
58
|
-
Bowing["UpBow"] = "up-bow";
|
|
59
|
-
})(Bowing || (Bowing = {}));
|
|
60
|
-
// Lyrics Syllabic types
|
|
61
|
-
export var Syllabic;
|
|
62
|
-
(function (Syllabic) {
|
|
63
|
-
Syllabic["Single"] = "single";
|
|
64
|
-
Syllabic["Begin"] = "begin";
|
|
65
|
-
Syllabic["Middle"] = "middle";
|
|
66
|
-
Syllabic["End"] = "end";
|
|
67
|
-
})(Syllabic || (Syllabic = {}));
|
|
68
|
-
// Notehead shapes
|
|
69
|
-
export var NoteheadShape;
|
|
70
|
-
(function (NoteheadShape) {
|
|
71
|
-
NoteheadShape["Normal"] = "normal";
|
|
72
|
-
NoteheadShape["Cross"] = "cross";
|
|
73
|
-
NoteheadShape["Diamond"] = "diamond";
|
|
74
|
-
NoteheadShape["Slash"] = "slash";
|
|
75
|
-
NoteheadShape["Triangle"] = "triangle";
|
|
76
|
-
NoteheadShape["Square"] = "square";
|
|
77
|
-
})(NoteheadShape || (NoteheadShape = {}));
|
|
78
|
-
// Dynamic markings
|
|
79
|
-
export var Dynamic;
|
|
80
|
-
(function (Dynamic) {
|
|
81
|
-
Dynamic["PPP"] = "ppp";
|
|
82
|
-
Dynamic["PP"] = "pp";
|
|
83
|
-
Dynamic["P"] = "p";
|
|
84
|
-
Dynamic["MP"] = "mp";
|
|
85
|
-
Dynamic["MF"] = "mf";
|
|
86
|
-
Dynamic["F"] = "f";
|
|
87
|
-
Dynamic["FF"] = "ff";
|
|
88
|
-
Dynamic["FFF"] = "fff";
|
|
89
|
-
Dynamic["SFZ"] = "sfz";
|
|
90
|
-
Dynamic["FP"] = "fp";
|
|
91
|
-
})(Dynamic || (Dynamic = {}));
|
|
92
|
-
// Genre types
|
|
93
|
-
export var Genre;
|
|
94
|
-
(function (Genre) {
|
|
95
|
-
Genre["Blues"] = "Blues";
|
|
96
|
-
Genre["Children"] = "Children";
|
|
97
|
-
Genre["Christian"] = "Christian";
|
|
98
|
-
Genre["Christmas"] = "Christmas";
|
|
99
|
-
Genre["Classical"] = "Classical";
|
|
100
|
-
Genre["ContestFestival"] = "Contest/Festival";
|
|
101
|
-
Genre["Country"] = "Country";
|
|
102
|
-
Genre["Educational"] = "Educational";
|
|
103
|
-
Genre["FilmTV"] = "Film/TV";
|
|
104
|
-
Genre["Folk"] = "Folk";
|
|
105
|
-
Genre["Games"] = "Games";
|
|
106
|
-
Genre["Gospel"] = "Gospel";
|
|
107
|
-
Genre["Holiday"] = "Holiday";
|
|
108
|
-
Genre["Jazz"] = "Jazz";
|
|
109
|
-
Genre["Latin"] = "Latin";
|
|
110
|
-
Genre["Musicals"] = "Musicals";
|
|
111
|
-
Genre["Pop"] = "Pop";
|
|
112
|
-
Genre["RBHipHop"] = "R&B/Hip-Hop";
|
|
113
|
-
Genre["Rock"] = "Rock";
|
|
114
|
-
Genre["Standards"] = "Standards";
|
|
115
|
-
Genre["Traditional"] = "Traditional";
|
|
116
|
-
Genre["Wedding"] = "Wedding";
|
|
117
|
-
Genre["World"] = "World";
|
|
118
|
-
Genre["Worship"] = "Worship";
|
|
119
|
-
Genre["Unknown"] = "unknown";
|
|
120
|
-
})(Genre || (Genre = {}));
|
|
121
|
-
// Hairpin (Crescendo/Decrescendo)
|
|
122
|
-
export var HairpinType;
|
|
123
|
-
(function (HairpinType) {
|
|
124
|
-
HairpinType["Crescendo"] = "crescendo";
|
|
125
|
-
HairpinType["Decrescendo"] = "decrescendo";
|
|
126
|
-
})(HairpinType || (HairpinType = {}));
|
|
127
|
-
// Barline styles
|
|
128
|
-
export var BarlineStyle;
|
|
129
|
-
(function (BarlineStyle) {
|
|
130
|
-
BarlineStyle["Regular"] = "regular";
|
|
131
|
-
BarlineStyle["Double"] = "light-light";
|
|
132
|
-
BarlineStyle["Final"] = "light-heavy";
|
|
133
|
-
BarlineStyle["Dotted"] = "dotted";
|
|
134
|
-
BarlineStyle["Dashed"] = "dashed";
|
|
135
|
-
BarlineStyle["Heavy"] = "heavy";
|
|
136
|
-
BarlineStyle["None"] = "none";
|
|
137
|
-
})(BarlineStyle || (BarlineStyle = {}));
|
|
138
|
-
// Glissando
|
|
139
|
-
export var GlissandoType;
|
|
140
|
-
(function (GlissandoType) {
|
|
141
|
-
GlissandoType["Wavy"] = "wavy";
|
|
142
|
-
GlissandoType["Straight"] = "straight";
|
|
143
|
-
})(GlissandoType || (GlissandoType = {}));
|
|
144
|
-
// Arpeggio (rolled chords)
|
|
145
|
-
export var Arpeggio;
|
|
146
|
-
(function (Arpeggio) {
|
|
147
|
-
Arpeggio["Normal"] = "normal";
|
|
148
|
-
Arpeggio["Up"] = "up";
|
|
149
|
-
Arpeggio["Down"] = "down";
|
|
150
|
-
})(Arpeggio || (Arpeggio = {}));
|
|
151
|
-
// Ottava (8va, 8vb, etc.)
|
|
152
|
-
export var OttavaType;
|
|
153
|
-
(function (OttavaType) {
|
|
154
|
-
OttavaType["OttavaAlta"] = "8va";
|
|
155
|
-
OttavaType["OttavaBassa"] = "8vb";
|
|
156
|
-
OttavaType["QuindicesimaAlta"] = "15ma";
|
|
157
|
-
OttavaType["QuindicesimaBassa"] = "15mb";
|
|
158
|
-
})(OttavaType || (OttavaType = {}));
|
|
159
|
-
// Ornaments
|
|
160
|
-
export var Ornament;
|
|
161
|
-
(function (Ornament) {
|
|
162
|
-
Ornament["Trill"] = "trill";
|
|
163
|
-
Ornament["Mordent"] = "mordent";
|
|
164
|
-
Ornament["InvertedMordent"] = "inverted-mordent";
|
|
165
|
-
Ornament["Turn"] = "turn";
|
|
166
|
-
Ornament["InvertedTurn"] = "inverted-turn";
|
|
167
|
-
Ornament["Tremolo"] = "tremolo";
|
|
168
|
-
})(Ornament || (Ornament = {}));
|
|
169
|
-
// Duration values in terms of quarter note = 1
|
|
170
|
-
export const DURATION_VALUES = {
|
|
171
|
-
[Duration.Whole]: 4,
|
|
172
|
-
[Duration.Half]: 2,
|
|
173
|
-
[Duration.Quarter]: 1,
|
|
174
|
-
[Duration.Eighth]: 0.5,
|
|
175
|
-
[Duration.Sixteenth]: 0.25,
|
|
176
|
-
[Duration.ThirtySecond]: 0.125,
|
|
177
|
-
[Duration.SixtyFourth]: 0.0625,
|
|
178
|
-
[Duration.OneHundredTwentyEighth]: 0.03125,
|
|
179
|
-
[Duration.TwoHundredFiftySixth]: 0.015625,
|
|
180
|
-
};
|
|
181
|
-
/**
|
|
182
|
-
* Decomposes a duration value (quarter = 1) into a list of duration/dot pairs.
|
|
183
|
-
*/
|
|
184
|
-
export function decomposeDuration(value) {
|
|
185
|
-
const result = [];
|
|
186
|
-
let remaining = value;
|
|
187
|
-
const options = [
|
|
188
|
-
{ val: 4, dur: Duration.Whole, dot: false },
|
|
189
|
-
{ val: 3, dur: Duration.Half, dot: true },
|
|
190
|
-
{ val: 2, dur: Duration.Half, dot: false },
|
|
191
|
-
{ val: 1.5, dur: Duration.Quarter, dot: true },
|
|
192
|
-
{ val: 1, dur: Duration.Quarter, dot: false },
|
|
193
|
-
{ val: 0.75, dur: Duration.Eighth, dot: true },
|
|
194
|
-
{ val: 0.5, dur: Duration.Eighth, dot: false },
|
|
195
|
-
{ val: 0.375, dur: Duration.Sixteenth, dot: true },
|
|
196
|
-
{ val: 0.25, dur: Duration.Sixteenth, dot: false },
|
|
197
|
-
{ val: 0.1875, dur: Duration.ThirtySecond, dot: true },
|
|
198
|
-
{ val: 0.125, dur: Duration.ThirtySecond, dot: false },
|
|
199
|
-
{ val: 0.09375, dur: Duration.SixtyFourth, dot: true },
|
|
200
|
-
{ val: 0.0625, dur: Duration.SixtyFourth, dot: false },
|
|
201
|
-
];
|
|
202
|
-
// Protect against infinite loop with max iterations
|
|
203
|
-
let loops = 0;
|
|
204
|
-
while (remaining > 0.001 && loops < 100) {
|
|
205
|
-
const match = options.find((o) => o.val <= remaining + 0.001);
|
|
206
|
-
if (match) {
|
|
207
|
-
result.push({ duration: match.dur, isDotted: match.dot, val: match.val });
|
|
208
|
-
remaining -= match.val;
|
|
209
|
-
}
|
|
210
|
-
else {
|
|
211
|
-
break;
|
|
212
|
-
}
|
|
213
|
-
loops++;
|
|
214
|
-
}
|
|
215
|
-
return result;
|
|
216
|
-
}
|
|
5
|
+
export * from '../types/index.js';
|