@scorelabs/core 1.0.5 → 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.
Files changed (82) hide show
  1. package/README.md +1 -1
  2. package/dist/importers/MusicXMLParser.d.ts +2 -1
  3. package/dist/importers/MusicXMLParser.js +102 -29
  4. package/dist/index.d.ts +2 -2
  5. package/dist/index.js +2 -2
  6. package/dist/models/Instrument.d.ts +8 -19
  7. package/dist/models/Instrument.js +77 -23
  8. package/dist/models/Measure.d.ts +3 -1
  9. package/dist/models/Measure.js +7 -1
  10. package/dist/models/Note.d.ts +1 -1
  11. package/dist/models/Note.js +1 -1
  12. package/dist/models/NoteSet.d.ts +40 -38
  13. package/dist/models/NoteSet.js +5 -2
  14. package/dist/models/Part.d.ts +2 -2
  15. package/dist/models/Part.js +1 -1
  16. package/dist/models/Pitch.js +4 -0
  17. package/dist/models/PreMeasure.d.ts +24 -0
  18. package/dist/models/PreMeasure.js +30 -0
  19. package/dist/models/Score.d.ts +18 -3
  20. package/dist/models/Score.js +196 -8
  21. package/dist/models/Staff.d.ts +2 -2
  22. package/dist/models/index.d.ts +1 -0
  23. package/dist/models/index.js +1 -0
  24. package/dist/models/types.d.ts +2 -213
  25. package/dist/models/types.js +2 -213
  26. package/dist/types/Accidental.d.ts +7 -0
  27. package/dist/types/Accidental.js +8 -0
  28. package/dist/types/Arpeggio.d.ts +5 -0
  29. package/dist/types/Arpeggio.js +6 -0
  30. package/dist/types/Articulation.d.ts +10 -0
  31. package/dist/types/Articulation.js +11 -0
  32. package/dist/types/BarlineStyle.d.ts +9 -0
  33. package/dist/types/BarlineStyle.js +10 -0
  34. package/dist/types/Bowing.d.ts +4 -0
  35. package/dist/types/Bowing.js +5 -0
  36. package/dist/types/Clef.d.ts +10 -0
  37. package/dist/types/Clef.js +11 -0
  38. package/dist/types/Duration.d.ts +20 -0
  39. package/dist/types/Duration.js +60 -0
  40. package/dist/types/Dynamic.d.ts +12 -0
  41. package/dist/types/Dynamic.js +13 -0
  42. package/dist/types/Fretboard.d.ts +19 -0
  43. package/dist/types/Fretboard.js +1 -0
  44. package/dist/types/Genre.d.ts +27 -0
  45. package/dist/types/Genre.js +28 -0
  46. package/dist/types/Glissando.d.ts +8 -0
  47. package/dist/types/Glissando.js +5 -0
  48. package/dist/types/Hairpin.d.ts +10 -0
  49. package/dist/types/Hairpin.js +11 -0
  50. package/dist/types/InstrumentPreset.d.ts +11 -0
  51. package/dist/types/InstrumentPreset.js +12 -0
  52. package/dist/types/InstrumentType.d.ts +8 -0
  53. package/dist/types/InstrumentType.js +9 -0
  54. package/dist/types/KeySignature.d.ts +3 -0
  55. package/dist/types/KeySignature.js +1 -0
  56. package/dist/types/Lyric.d.ts +11 -0
  57. package/dist/types/Lyric.js +7 -0
  58. package/dist/types/NoteheadShape.d.ts +8 -0
  59. package/dist/types/NoteheadShape.js +9 -0
  60. package/dist/types/Ornament.d.ts +8 -0
  61. package/dist/types/Ornament.js +9 -0
  62. package/dist/types/Ottava.d.ts +10 -0
  63. package/dist/types/Ottava.js +7 -0
  64. package/dist/types/Pedal.d.ts +4 -0
  65. package/dist/types/Pedal.js +1 -0
  66. package/dist/types/Repeat.d.ts +8 -0
  67. package/dist/types/Repeat.js +1 -0
  68. package/dist/types/Slur.d.ts +4 -0
  69. package/dist/types/Slur.js +1 -0
  70. package/dist/types/StemDirection.d.ts +4 -0
  71. package/dist/types/StemDirection.js +5 -0
  72. package/dist/types/Tempo.d.ts +8 -0
  73. package/dist/types/Tempo.js +1 -0
  74. package/dist/types/TimeSignature.d.ts +6 -0
  75. package/dist/types/TimeSignature.js +3 -0
  76. package/dist/types/Tuplet.d.ts +5 -0
  77. package/dist/types/Tuplet.js +1 -0
  78. package/dist/types/index.d.ts +26 -0
  79. package/dist/types/index.js +26 -0
  80. package/package.json +5 -4
  81. package/dist/utils/tier.d.ts +0 -36
  82. package/dist/utils/tier.js +0 -112
@@ -1,5 +1,5 @@
1
1
  import { Note } from './Note';
2
- import { Duration } from './types';
2
+ import { Duration, } from './types';
3
3
  export class NoteSet {
4
4
  notes;
5
5
  constructor(notes) {
@@ -178,6 +178,9 @@ export class NoteSet {
178
178
  get slur() {
179
179
  return this.notes[0].slur;
180
180
  }
181
+ get articulations() {
182
+ return this.notes[0].articulations;
183
+ }
181
184
  get articulation() {
182
185
  return this.notes[0].articulation;
183
186
  }
@@ -264,7 +267,7 @@ export class NoteSet {
264
267
  return new NoteSet([new Note(Duration.Quarter, undefined, true)]);
265
268
  }
266
269
  let notesArray;
267
- if (data.notes && Array.isArray(data.notes)) {
270
+ if ('notes' in data && Array.isArray(data.notes)) {
268
271
  notesArray = data.notes;
269
272
  }
270
273
  else if (Array.isArray(data)) {
@@ -1,7 +1,7 @@
1
- import { Staff, StaffJSON } from './Staff';
2
1
  import { Instrument } from './Instrument';
3
- import { Note } from './Note';
4
2
  import { Measure } from './Measure';
3
+ import { Note } from './Note';
4
+ import { Staff, StaffJSON } from './Staff';
5
5
  import { Duration } from './types';
6
6
  /**
7
7
  * Represents a musical part (instrument/voice) which can have multiple staves.
@@ -1,5 +1,5 @@
1
- import { Staff } from './Staff';
2
1
  import { PRESET_INSTRUMENTS } from './Instrument';
2
+ import { Staff } from './Staff';
3
3
  /**
4
4
  * Represents a musical part (instrument/voice) which can have multiple staves.
5
5
  */
@@ -33,7 +33,9 @@ export class Pitch {
33
33
  getStaffPosition(clef) {
34
34
  const middleLineAbsStep = {
35
35
  [Clef.Treble]: 4 * 7 + 6, // B4
36
+ [Clef.Treble8vaBassa]: 3 * 7 + 6, // B3
36
37
  [Clef.Bass]: 3 * 7 + 1, // D3
38
+ [Clef.Bass8vaBassa]: 2 * 7 + 1, // D2
37
39
  [Clef.Alto]: 4 * 7 + 0, // C4
38
40
  [Clef.Tenor]: 3 * 7 + 5, // A3
39
41
  [Clef.Percussion]: 4 * 7 + 6, // B4
@@ -100,7 +102,9 @@ export class Pitch {
100
102
  static fromStaffPosition(clef, staffPosition) {
101
103
  const middleLineAbsStep = {
102
104
  [Clef.Treble]: 4 * 7 + 6, // B4
105
+ [Clef.Treble8vaBassa]: 3 * 7 + 6, // B3
103
106
  [Clef.Bass]: 3 * 7 + 1, // D3
107
+ [Clef.Bass8vaBassa]: 2 * 7 + 1, // D2
104
108
  [Clef.Alto]: 4 * 7 + 0, // C4
105
109
  [Clef.Tenor]: 3 * 7 + 5, // A3
106
110
  [Clef.Percussion]: 4 * 7 + 0,
@@ -0,0 +1,24 @@
1
+ import { Clef, KeySignature, TimeSignature } from './types';
2
+ export interface PreMeasureJSON {
3
+ clef?: string;
4
+ keySignature?: KeySignature;
5
+ timeSignature?: TimeSignature;
6
+ }
7
+ /**
8
+ * Represents the musical context before the first measure of a system.
9
+ * This includes the clef, key signature, and time signature.
10
+ */
11
+ export declare class PreMeasure {
12
+ readonly clef?: Clef | undefined;
13
+ readonly keySignature?: KeySignature | undefined;
14
+ readonly timeSignature?: TimeSignature | undefined;
15
+ constructor(clef?: Clef | undefined, keySignature?: KeySignature | undefined, timeSignature?: TimeSignature | undefined);
16
+ /**
17
+ * Creates a PreMeasure from JSON data.
18
+ */
19
+ static fromJSON(data: Partial<PreMeasureJSON>): PreMeasure;
20
+ /**
21
+ * Converts the PreMeasure to a JSON-serializable object.
22
+ */
23
+ toJSON(): PreMeasureJSON;
24
+ }
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Represents the musical context before the first measure of a system.
3
+ * This includes the clef, key signature, and time signature.
4
+ */
5
+ export class PreMeasure {
6
+ clef;
7
+ keySignature;
8
+ timeSignature;
9
+ constructor(clef, keySignature, timeSignature) {
10
+ this.clef = clef;
11
+ this.keySignature = keySignature;
12
+ this.timeSignature = timeSignature;
13
+ }
14
+ /**
15
+ * Creates a PreMeasure from JSON data.
16
+ */
17
+ static fromJSON(data) {
18
+ return new PreMeasure(data.clef, data.keySignature, data.timeSignature);
19
+ }
20
+ /**
21
+ * Converts the PreMeasure to a JSON-serializable object.
22
+ */
23
+ toJSON() {
24
+ return {
25
+ clef: this.clef,
26
+ keySignature: this.keySignature,
27
+ timeSignature: this.timeSignature,
28
+ };
29
+ }
30
+ }
@@ -1,8 +1,8 @@
1
- import { TimeSignature, KeySignature, Duration, Genre } from './types';
1
+ import { Measure } from './Measure';
2
+ import { NoteSet } from './NoteSet';
2
3
  import { Part, PartJSON } from './Part';
3
4
  import { Staff } from './Staff';
4
- import { NoteSet } from './NoteSet';
5
- import { Measure } from './Measure';
5
+ import { Clef, Duration, Genre, KeySignature, TimeSignature } from './types';
6
6
  /**
7
7
  * Represents a complete musical score.
8
8
  */
@@ -38,6 +38,21 @@ export declare class Score {
38
38
  static fromJSON(data: ScoreJSON): Score;
39
39
  transpose(semitones: number): Score;
40
40
  replaceNote(partIndex: number, staffIndex: number, measureIndex: number, noteIndex: number, newNote: NoteSet, voiceIndex?: number): Score;
41
+ withKeySignature(keySig: KeySignature): Score;
42
+ withTimeSignature(timeSig: TimeSignature): Score;
43
+ updateMeasureSignatures(measureIndex: number, signatures: {
44
+ keySignature?: KeySignature;
45
+ timeSignature?: TimeSignature;
46
+ clef?: Clef;
47
+ }, autoBeam?: boolean): Score;
48
+ /**
49
+ * Reflows the notes starting from a specific measure index.
50
+ * This is useful when time signatures change and notes need to be redistributed.
51
+ */
52
+ reflow(fromMeasureIndex: number, autoBeam?: boolean): Score;
53
+ private isTied;
54
+ private areSamePitch;
55
+ private reflowStaff;
41
56
  replaceMeasure(partIndex: number, staffIndex: number, measureIndex: number, newMeasure: Measure, autoBeam?: boolean): Score;
42
57
  deleteNote(partIndex: number, staffIndex: number, measureIndex: number, noteIndex: number, voiceIndex?: number): Score;
43
58
  changeNoteDuration(partIndex: number, staffIndex: number, measureIndex: number, noteIndex: number, newDuration: Duration, isDotted?: boolean, voiceIndex?: number): Score;
@@ -1,5 +1,6 @@
1
- import { Duration, decomposeDuration, Genre } from './types';
1
+ import { Measure } from './Measure';
2
2
  import { Part } from './Part';
3
+ import { Duration, Genre, decomposeDuration } from './types';
3
4
  /**
4
5
  * Represents a complete musical score.
5
6
  */
@@ -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,14 +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
- let blockStart = 0;
441
+ const startRepeatStack = [0]; // Implicit start at 0
442
+ let justJumpedTo = -1;
277
443
  const repeatCount = new Map();
278
- while (i < measures.length) {
444
+ let safetyCounter = 0;
445
+ const MAX_SEQUENCE = 10000;
446
+ while (i < measures.length && safetyCounter < MAX_SEQUENCE) {
447
+ safetyCounter++;
279
448
  const m = measures[i];
280
- if (m.repeats.some((r) => r.type === 'start'))
281
- blockStart = i;
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;
282
459
  const endRepeat = m.repeats.find((r) => r.type === 'end');
283
460
  let iteration = 1;
461
+ // Calculate current iteration for Volta logic
284
462
  if (endRepeat)
285
463
  iteration = (repeatCount.get(i) || 0) + 1;
286
464
  else {
@@ -294,7 +472,7 @@ export class Score {
294
472
  if (nextEndIdx !== -1)
295
473
  iteration = (repeatCount.get(nextEndIdx) || 0) + 1;
296
474
  }
297
- if (m.volta && m.volta.number !== iteration) {
475
+ if (m.volta && !m.volta.numbers.includes(iteration)) {
298
476
  i++;
299
477
  continue;
300
478
  }
@@ -304,11 +482,21 @@ export class Score {
304
482
  const currentCount = repeatCount.get(i) || 0;
305
483
  if (currentCount + 1 < maxTimes) {
306
484
  repeatCount.set(i, currentCount + 1);
307
- i = blockStart;
485
+ // Jump to the nearest start repeat
486
+ const target = startRepeatStack[startRepeatStack.length - 1];
487
+ i = target;
488
+ justJumpedTo = target;
308
489
  continue;
309
490
  }
310
- else
491
+ else {
492
+ // Finished loop
311
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
+ }
312
500
  }
313
501
  i++;
314
502
  }
@@ -1,7 +1,7 @@
1
- import { Clef, Duration } from './types';
2
1
  import { Measure, MeasureJSON } from './Measure';
3
- import { Pitch } from './Pitch';
4
2
  import { Note } from './Note';
3
+ import { Pitch } from './Pitch';
4
+ import { Clef, Duration } from './types';
5
5
  /**
6
6
  * Represents a single staff (one set of 5 lines with a clef).
7
7
  */
@@ -7,3 +7,4 @@ export * from './Staff';
7
7
  export * from './Part';
8
8
  export * from './Score';
9
9
  export * from './Instrument';
10
+ export * from './PreMeasure';
@@ -7,3 +7,4 @@ export * from './Staff';
7
7
  export * from './Part';
8
8
  export * from './Score';
9
9
  export * from './Instrument';
10
+ export * from './PreMeasure';
@@ -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 declare enum StemDirection {
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
- number: 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';