@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.
Files changed (74) hide show
  1. package/dist/importers/MusicXMLParser.d.ts +2 -2
  2. package/dist/importers/MusicXMLParser.js +75 -17
  3. package/dist/index.d.ts +2 -2
  4. package/dist/index.js +2 -2
  5. package/dist/models/Instrument.d.ts +8 -19
  6. package/dist/models/Instrument.js +77 -23
  7. package/dist/models/Measure.d.ts +2 -0
  8. package/dist/models/Measure.js +6 -0
  9. package/dist/models/NoteSet.d.ts +40 -38
  10. package/dist/models/NoteSet.js +5 -2
  11. package/dist/models/Pitch.js +4 -0
  12. package/dist/models/PreMeasure.d.ts +24 -0
  13. package/dist/models/PreMeasure.js +30 -0
  14. package/dist/models/Score.d.ts +16 -1
  15. package/dist/models/Score.js +190 -5
  16. package/dist/models/index.d.ts +1 -0
  17. package/dist/models/index.js +1 -0
  18. package/dist/models/types.d.ts +2 -213
  19. package/dist/models/types.js +2 -213
  20. package/dist/types/Accidental.d.ts +7 -0
  21. package/dist/types/Accidental.js +8 -0
  22. package/dist/types/Arpeggio.d.ts +5 -0
  23. package/dist/types/Arpeggio.js +6 -0
  24. package/dist/types/Articulation.d.ts +10 -0
  25. package/dist/types/Articulation.js +11 -0
  26. package/dist/types/BarlineStyle.d.ts +9 -0
  27. package/dist/types/BarlineStyle.js +10 -0
  28. package/dist/types/Bowing.d.ts +4 -0
  29. package/dist/types/Bowing.js +5 -0
  30. package/dist/types/Clef.d.ts +10 -0
  31. package/dist/types/Clef.js +11 -0
  32. package/dist/types/Duration.d.ts +20 -0
  33. package/dist/types/Duration.js +60 -0
  34. package/dist/types/Dynamic.d.ts +12 -0
  35. package/dist/types/Dynamic.js +13 -0
  36. package/dist/types/Fretboard.d.ts +19 -0
  37. package/dist/types/Fretboard.js +1 -0
  38. package/dist/types/Genre.d.ts +27 -0
  39. package/dist/types/Genre.js +28 -0
  40. package/dist/types/Glissando.d.ts +8 -0
  41. package/dist/types/Glissando.js +5 -0
  42. package/dist/types/Hairpin.d.ts +10 -0
  43. package/dist/types/Hairpin.js +11 -0
  44. package/dist/types/InstrumentPreset.d.ts +11 -0
  45. package/dist/types/InstrumentPreset.js +12 -0
  46. package/dist/types/InstrumentType.d.ts +8 -0
  47. package/dist/types/InstrumentType.js +9 -0
  48. package/dist/types/KeySignature.d.ts +3 -0
  49. package/dist/types/KeySignature.js +1 -0
  50. package/dist/types/Lyric.d.ts +11 -0
  51. package/dist/types/Lyric.js +7 -0
  52. package/dist/types/NoteheadShape.d.ts +8 -0
  53. package/dist/types/NoteheadShape.js +9 -0
  54. package/dist/types/Ornament.d.ts +8 -0
  55. package/dist/types/Ornament.js +9 -0
  56. package/dist/types/Ottava.d.ts +10 -0
  57. package/dist/types/Ottava.js +7 -0
  58. package/dist/types/Pedal.d.ts +4 -0
  59. package/dist/types/Pedal.js +1 -0
  60. package/dist/types/Repeat.d.ts +8 -0
  61. package/dist/types/Repeat.js +1 -0
  62. package/dist/types/Slur.d.ts +4 -0
  63. package/dist/types/Slur.js +1 -0
  64. package/dist/types/StemDirection.d.ts +4 -0
  65. package/dist/types/StemDirection.js +5 -0
  66. package/dist/types/Tempo.d.ts +8 -0
  67. package/dist/types/Tempo.js +1 -0
  68. package/dist/types/TimeSignature.d.ts +6 -0
  69. package/dist/types/TimeSignature.js +3 -0
  70. package/dist/types/Tuplet.d.ts +5 -0
  71. package/dist/types/Tuplet.js +1 -0
  72. package/dist/types/index.d.ts +26 -0
  73. package/dist/types/index.js +26 -0
  74. package/package.json +1 -1
@@ -12,9 +12,9 @@ export declare class MusicXMLParser {
12
12
  private currentSymbol;
13
13
  private instrumentPitchMap;
14
14
  private _domParser;
15
- constructor(domParserInstance?: DOMParser | any);
15
+ constructor(domParserInstance?: DOMParser | unknown);
16
16
  private parseFromString;
17
- static getXMLFromBinary(data: ArrayBuffer, domParser?: DOMParser | any): Promise<string>;
17
+ static getXMLFromBinary(data: ArrayBuffer, domParser?: DOMParser | unknown): Promise<string>;
18
18
  parseBinary(data: ArrayBuffer): Promise<ScoreJSON>;
19
19
  parse(xmlString: string): ScoreJSON;
20
20
  private parseSubtitle;
@@ -1,6 +1,6 @@
1
1
  import JSZip from 'jszip';
2
- import { getInstrumentByProgram } from '../models/Instrument';
3
- import { Accidental, Arpeggio, Articulation, BarlineStyle, Bowing, Clef, Duration, GlissandoType, HairpinType, NoteheadShape, Ornament, OttavaType, StemDirection, } from '../models/types';
2
+ import { getInstrumentByProgram, guessInstrumentByName } from '../models/Instrument';
3
+ import { Accidental, Arpeggio, Articulation, BarlineStyle, Bowing, Clef, DURATION_VALUES, Duration, GlissandoType, HairpinType, NoteheadShape, Ornament, OttavaType, StemDirection, decomposeDuration, } from '../models/types';
4
4
  /**
5
5
  * MusicXML Parser
6
6
  *
@@ -151,19 +151,28 @@ export class MusicXMLParser {
151
151
  for (const scorePart of Array.from(scoreParts)) {
152
152
  const id = scorePart.getAttribute('id');
153
153
  const name = this.getText(scorePart, 'part-name') || 'Part';
154
- let instrument = getInstrumentByProgram(0); // Default Piano
154
+ let instrument;
155
155
  // Find first midi-instrument to determine main instrument
156
156
  const firstMidiInst = scorePart.querySelector('midi-instrument');
157
157
  if (firstMidiInst) {
158
158
  const programStr = this.getText(firstMidiInst, 'midi-program');
159
159
  if (programStr) {
160
160
  const program = parseInt(programStr);
161
- // MusicXML uses 1-128, MIDI uses 0-127. Adjust if needed.
162
- // Often it's accurate to 1-based, so checking bounds.
163
- // Assuming input is 1-based as per standard
164
161
  instrument = getInstrumentByProgram(Math.max(0, program - 1));
165
162
  }
166
163
  }
164
+ // Fallback: guess by part name
165
+ if (!instrument || instrument.sound === 'piano') {
166
+ const guessed = guessInstrumentByName(name);
167
+ // Only override if the guess is more specific than default piano
168
+ if (guessed.sound !== 'piano') {
169
+ instrument = guessed;
170
+ }
171
+ }
172
+ // Final default
173
+ if (!instrument) {
174
+ instrument = getInstrumentByProgram(0);
175
+ }
167
176
  if (id) {
168
177
  partInfo.set(id, { name: name.trim(), instrument });
169
178
  }
@@ -242,7 +251,8 @@ export class MusicXMLParser {
242
251
  const sign = this.getText(clef, 'sign');
243
252
  if (sign && number <= numStaves) {
244
253
  const line = this.getNumber(clef, 'line') || 0;
245
- staffClefs[number - 1] = this.mapClef(sign, line);
254
+ const octaveChange = this.getNumber(clef, 'clef-octave-change') || 0;
255
+ staffClefs[number - 1] = this.mapClef(sign, line, octaveChange);
246
256
  }
247
257
  });
248
258
  const staffDetails = attributes.querySelectorAll('staff-details');
@@ -258,7 +268,10 @@ export class MusicXMLParser {
258
268
  let systemText = undefined;
259
269
  let contextDynamic = undefined;
260
270
  const { repeats, volta, barlineStyle } = this.parseBarlines(measureElement);
261
- const measureVoices = Array.from({ length: numStaves }, () => []);
271
+ // Map of staffIndex -> Map of voiceId -> NoteSetJSON[]
272
+ const staffVoices = new Map();
273
+ for (let i = 0; i < numStaves; i++)
274
+ staffVoices.set(i, new Map());
262
275
  const children = Array.from(measureElement.children);
263
276
  let pendingChord = undefined;
264
277
  let currentNoteSetMap = new Map();
@@ -375,6 +388,11 @@ export class MusicXMLParser {
375
388
  note.pedal = currentPedal;
376
389
  currentPedal = undefined;
377
390
  }
391
+ const voiceId = this.getText(child, 'voice') || '1';
392
+ const voiceMap = staffVoices.get(staffIdx);
393
+ if (!voiceMap.has(voiceId))
394
+ voiceMap.set(voiceId, []);
395
+ const voiceNoteSets = voiceMap.get(voiceId);
378
396
  if (isChord) {
379
397
  const existing = currentNoteSetMap.get(staffIdx);
380
398
  if (existing)
@@ -385,26 +403,42 @@ export class MusicXMLParser {
385
403
  else {
386
404
  const existing = currentNoteSetMap.get(staffIdx);
387
405
  if (existing)
388
- measureVoices[staffIdx].push({ notes: existing });
406
+ voiceNoteSets.push({ notes: existing });
389
407
  currentNoteSetMap.set(staffIdx, [note]);
390
408
  }
391
409
  }
392
410
  }
393
411
  else if (child.nodeName === 'backup' || child.nodeName === 'forward') {
394
412
  for (const [sIdx, notes] of currentNoteSetMap.entries()) {
395
- if (notes.length > 0)
396
- measureVoices[sIdx].push({ notes });
413
+ if (notes.length > 0) {
414
+ const voiceId = this.getText(child.previousElementSibling, 'voice') || '1';
415
+ const voiceMap = staffVoices.get(sIdx);
416
+ if (!voiceMap.has(voiceId))
417
+ voiceMap.set(voiceId, []);
418
+ voiceMap.get(voiceId).push({ notes });
419
+ }
397
420
  }
398
421
  currentNoteSetMap.clear();
399
422
  }
400
423
  });
401
424
  for (const [sIdx, notes] of currentNoteSetMap.entries()) {
402
- if (notes.length > 0)
403
- measureVoices[sIdx].push({ notes });
425
+ if (notes.length > 0) {
426
+ // Last note in measure
427
+ const voiceId = '1'; // Defaulting to 1 for final push if not tracked
428
+ const voiceMap = staffVoices.get(sIdx);
429
+ if (!voiceMap.has(voiceId))
430
+ voiceMap.set(voiceId, []);
431
+ voiceMap.get(voiceId).push({ notes });
432
+ }
404
433
  }
405
434
  for (let i = 0; i < numStaves; i++) {
435
+ const vMap = staffVoices.get(i);
436
+ let voicesIndices = Array.from(vMap.keys()).sort();
437
+ if (voicesIndices.length === 0)
438
+ voicesIndices = ['1'];
439
+ const voices = voicesIndices.map(id => vMap.get(id) || []);
406
440
  const measure = {
407
- voices: [measureVoices[i]],
441
+ voices: voices,
408
442
  timeSignature: measureTimeSignature,
409
443
  keySignature: measureKeySignature,
410
444
  isPickup: isPickup || undefined,
@@ -415,6 +449,30 @@ export class MusicXMLParser {
415
449
  systemText: i === 0 ? systemText : undefined,
416
450
  barlineStyle,
417
451
  };
452
+ // Padding with rests if not a pickup
453
+ if (!isPickup) {
454
+ const targetDur = (this.currentBeats * 4) / this.currentBeatType;
455
+ measure.voices = measure.voices.map((v) => {
456
+ const currentDur = v.reduce((sum, ns) => {
457
+ const base = DURATION_VALUES[ns.notes[0].duration];
458
+ return sum + (ns.notes[0].isDotted ? base * 1.5 : base);
459
+ }, 0);
460
+ if (currentDur < targetDur - 0.001) {
461
+ const gap = targetDur - currentDur;
462
+ const rests = decomposeDuration(gap).map((d) => ({
463
+ notes: [
464
+ {
465
+ duration: d.duration,
466
+ isRest: true,
467
+ isDotted: d.isDotted,
468
+ },
469
+ ],
470
+ }));
471
+ return [...v, ...rests];
472
+ }
473
+ return v;
474
+ });
475
+ }
418
476
  staves[i].measures.push(measure);
419
477
  staves[i].clef = staffClefs[i];
420
478
  }
@@ -891,12 +949,12 @@ export class MusicXMLParser {
891
949
  };
892
950
  return map[type] ?? Duration.Quarter;
893
951
  }
894
- mapClef(sign, line = 0) {
952
+ mapClef(sign, line = 0, octaveChange = 0) {
895
953
  switch (sign.toUpperCase()) {
896
954
  case 'G':
897
- return Clef.Treble;
955
+ return octaveChange === -1 ? Clef.Treble8vaBassa : Clef.Treble;
898
956
  case 'F':
899
- return Clef.Bass;
957
+ return octaveChange === -1 ? Clef.Bass8vaBassa : Clef.Bass;
900
958
  case 'C':
901
959
  return line === 4 ? Clef.Tenor : Clef.Alto;
902
960
  case 'PERCUSSION':
package/dist/index.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export * from './models';
2
- export * from './importers';
1
+ export * from './models/index.js';
2
+ export * from './importers/index.js';
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- export * from './models';
2
- export * from './importers';
1
+ export * from './models/index.js';
2
+ export * from './importers/index.js';
@@ -1,27 +1,16 @@
1
- export declare enum InstrumentType {
2
- String = "string",
3
- Brass = "brass",
4
- Woodwind = "woodwind",
5
- Percussion = "percussion",
6
- Keyboard = "keyboard",
7
- Synth = "synth"
8
- }
9
- export declare enum InstrumentPreset {
10
- Piano = "piano",
11
- Violin = "violin",
12
- Cello = "cello",
13
- Guitar = "guitar",
14
- ElectricGuitar = "electric-guitar",
15
- Bass = "bass",
16
- Flute = "flute",
17
- Trumpet = "trumpet",
18
- Drums = "drums"
19
- }
1
+ import { InstrumentPreset } from '../types/InstrumentPreset.js';
2
+ import { InstrumentType } from '../types/InstrumentType.js';
20
3
  export interface Instrument {
21
4
  name: string;
22
5
  midiProgram: number;
6
+ sound: InstrumentPreset;
23
7
  type?: InstrumentType;
24
8
  transposition?: number;
25
9
  }
26
10
  export declare const PRESET_INSTRUMENTS: Record<string, Instrument>;
11
+ export declare const TRANSLATED_INSTRUMENT_NAMES: Record<string, Record<InstrumentPreset, string>>;
27
12
  export declare function getInstrumentByProgram(program: number): Instrument;
13
+ /**
14
+ * Guesses the instrument based on a string (like part name).
15
+ */
16
+ export declare function guessInstrumentByName(name: string): Instrument;
@@ -1,67 +1,121 @@
1
- export var InstrumentType;
2
- (function (InstrumentType) {
3
- InstrumentType["String"] = "string";
4
- InstrumentType["Brass"] = "brass";
5
- InstrumentType["Woodwind"] = "woodwind";
6
- InstrumentType["Percussion"] = "percussion";
7
- InstrumentType["Keyboard"] = "keyboard";
8
- InstrumentType["Synth"] = "synth";
9
- })(InstrumentType || (InstrumentType = {}));
10
- export var InstrumentPreset;
11
- (function (InstrumentPreset) {
12
- InstrumentPreset["Piano"] = "piano";
13
- InstrumentPreset["Violin"] = "violin";
14
- InstrumentPreset["Cello"] = "cello";
15
- InstrumentPreset["Guitar"] = "guitar";
16
- InstrumentPreset["ElectricGuitar"] = "electric-guitar";
17
- InstrumentPreset["Bass"] = "bass";
18
- InstrumentPreset["Flute"] = "flute";
19
- InstrumentPreset["Trumpet"] = "trumpet";
20
- InstrumentPreset["Drums"] = "drums";
21
- })(InstrumentPreset || (InstrumentPreset = {}));
1
+ import { InstrumentPreset } from '../types/InstrumentPreset.js';
2
+ import { InstrumentType } from '../types/InstrumentType.js';
22
3
  export const PRESET_INSTRUMENTS = {
23
4
  [InstrumentPreset.Piano]: {
24
5
  name: 'Acoustic Grand Piano',
25
6
  midiProgram: 0,
7
+ sound: InstrumentPreset.Piano,
26
8
  type: InstrumentType.Keyboard,
27
9
  },
28
- [InstrumentPreset.Violin]: { name: 'Violin', midiProgram: 40, type: InstrumentType.String },
29
- [InstrumentPreset.Cello]: { name: 'Cello', midiProgram: 42, type: InstrumentType.String },
10
+ [InstrumentPreset.Violin]: {
11
+ name: 'Violin',
12
+ midiProgram: 40,
13
+ sound: InstrumentPreset.Violin,
14
+ type: InstrumentType.String,
15
+ },
16
+ [InstrumentPreset.Cello]: {
17
+ name: 'Cello',
18
+ midiProgram: 42,
19
+ sound: InstrumentPreset.Cello,
20
+ type: InstrumentType.String,
21
+ },
30
22
  [InstrumentPreset.Guitar]: {
31
23
  name: 'Acoustic Guitar (nylon)',
32
24
  midiProgram: 24,
25
+ sound: InstrumentPreset.Guitar,
33
26
  type: InstrumentType.String,
34
27
  },
35
28
  [InstrumentPreset.ElectricGuitar]: {
36
29
  name: 'Electric Guitar (clean)',
37
30
  midiProgram: 27,
31
+ sound: InstrumentPreset.ElectricGuitar,
38
32
  type: InstrumentType.String,
39
33
  },
40
34
  [InstrumentPreset.Bass]: {
41
35
  name: 'Acoustic Bass',
42
36
  midiProgram: 32,
37
+ sound: InstrumentPreset.Bass,
43
38
  type: InstrumentType.String,
44
39
  },
45
40
  [InstrumentPreset.Flute]: {
46
41
  name: 'Flute',
47
42
  midiProgram: 73,
43
+ sound: InstrumentPreset.Flute,
48
44
  type: InstrumentType.Woodwind,
49
45
  transposition: 0,
50
46
  },
51
47
  [InstrumentPreset.Trumpet]: {
52
48
  name: 'Trumpet',
53
49
  midiProgram: 56,
50
+ sound: InstrumentPreset.Trumpet,
54
51
  type: InstrumentType.Brass,
55
52
  transposition: -2,
56
53
  },
57
54
  [InstrumentPreset.Drums]: {
58
55
  name: 'Drum Kit',
59
56
  midiProgram: 118,
57
+ sound: InstrumentPreset.Drums,
60
58
  type: InstrumentType.Percussion,
61
59
  transposition: 0,
62
60
  },
63
61
  };
62
+ export const TRANSLATED_INSTRUMENT_NAMES = {
63
+ en: {
64
+ [InstrumentPreset.Piano]: 'Acoustic Grand Piano',
65
+ [InstrumentPreset.Violin]: 'Violin',
66
+ [InstrumentPreset.Cello]: 'Cello',
67
+ [InstrumentPreset.Guitar]: 'Acoustic Guitar',
68
+ [InstrumentPreset.ElectricGuitar]: 'Electric Guitar',
69
+ [InstrumentPreset.Bass]: 'Acoustic Bass',
70
+ [InstrumentPreset.Flute]: 'Flute',
71
+ [InstrumentPreset.Trumpet]: 'Trumpet',
72
+ [InstrumentPreset.Drums]: 'Drum Kit',
73
+ },
74
+ ca: {
75
+ [InstrumentPreset.Piano]: 'Piano',
76
+ [InstrumentPreset.Violin]: 'Violí',
77
+ [InstrumentPreset.Cello]: 'Violoncel',
78
+ [InstrumentPreset.Guitar]: 'Guitarra Acústica',
79
+ [InstrumentPreset.ElectricGuitar]: 'Guitarra Elèctrica',
80
+ [InstrumentPreset.Bass]: 'Baix',
81
+ [InstrumentPreset.Flute]: 'Flauta',
82
+ [InstrumentPreset.Trumpet]: 'Trompeta',
83
+ [InstrumentPreset.Drums]: 'Bateria',
84
+ },
85
+ };
64
86
  export function getInstrumentByProgram(program) {
65
87
  const match = Object.values(PRESET_INSTRUMENTS).find((i) => i.midiProgram === program);
66
88
  return match || PRESET_INSTRUMENTS[InstrumentPreset.Piano];
67
89
  }
90
+ /**
91
+ * Guesses the instrument based on a string (like part name).
92
+ */
93
+ export function guessInstrumentByName(name) {
94
+ const n = name.toLowerCase();
95
+ if (n.includes('piano'))
96
+ return PRESET_INSTRUMENTS[InstrumentPreset.Piano];
97
+ if (n.includes('violin'))
98
+ return PRESET_INSTRUMENTS[InstrumentPreset.Violin];
99
+ if (n.includes('cello') || n.includes('violoncel'))
100
+ return PRESET_INSTRUMENTS[InstrumentPreset.Cello];
101
+ if (n.includes('electric guitar'))
102
+ return PRESET_INSTRUMENTS[InstrumentPreset.ElectricGuitar];
103
+ if (n.includes('guitar'))
104
+ return PRESET_INSTRUMENTS[InstrumentPreset.Guitar];
105
+ if (n.includes('bass') || n.includes('baixo') || n.includes('baix'))
106
+ return PRESET_INSTRUMENTS[InstrumentPreset.Bass];
107
+ if (n.includes('flute') || n.includes('flauta'))
108
+ return PRESET_INSTRUMENTS[InstrumentPreset.Flute];
109
+ if (n.includes('trumpet') || n.includes('trompeta'))
110
+ return PRESET_INSTRUMENTS[InstrumentPreset.Trumpet];
111
+ if (n.includes('drum') || n.includes('perc') || n.includes('bateria'))
112
+ return PRESET_INSTRUMENTS[InstrumentPreset.Drums];
113
+ // Try partial matches for strings, brass, etc.
114
+ if (n.includes('string'))
115
+ return PRESET_INSTRUMENTS[InstrumentPreset.Violin];
116
+ if (n.includes('brass'))
117
+ return PRESET_INSTRUMENTS[InstrumentPreset.Trumpet];
118
+ if (n.includes('wind'))
119
+ return PRESET_INSTRUMENTS[InstrumentPreset.Flute];
120
+ return PRESET_INSTRUMENTS[InstrumentPreset.Piano];
121
+ }
@@ -20,6 +20,8 @@ export declare class Measure {
20
20
  readonly barlineStyle: BarlineStyle;
21
21
  constructor(voices: NoteSet[][], timeSignature?: TimeSignature | undefined, keySignature?: KeySignature | undefined, systemBreak?: boolean, pageBreak?: boolean, repeats?: Repeat[], volta?: Volta | undefined, isPickup?: boolean, clef?: Clef | undefined, tempo?: Tempo | undefined, rehearsalMark?: string | undefined, systemText?: string | undefined, barlineStyle?: BarlineStyle);
22
22
  get notes(): NoteSet[];
23
+ get hasStartRepeat(): boolean;
24
+ get hasEndRepeat(): boolean;
23
25
  changeNoteDuration(noteIndex: number, newDuration: Duration, isDotted?: boolean, voiceIndex?: number): Measure;
24
26
  getTotalDuration(voiceIndex?: number): number;
25
27
  static fromJSON(data: MeasureJSON): Measure;
@@ -39,6 +39,12 @@ export class Measure {
39
39
  get notes() {
40
40
  return this.voices[0] || [];
41
41
  }
42
+ get hasStartRepeat() {
43
+ return this.repeats.some((r) => r.type === "start");
44
+ }
45
+ get hasEndRepeat() {
46
+ return this.repeats.some((r) => r.type === "end");
47
+ }
42
48
  changeNoteDuration(noteIndex, newDuration, isDotted = false, voiceIndex = 0) {
43
49
  const voice = this.voices[voiceIndex];
44
50
  if (!voice || noteIndex < 0 || noteIndex >= voice.length)
@@ -1,5 +1,6 @@
1
1
  import { Note, NoteJSON } from './Note';
2
- import { Duration } from './types';
2
+ import { Pitch } from './Pitch';
3
+ import { Accidental, Arpeggio, Articulation, Bowing, Duration, Dynamic, FretboardDiagram, Glissando, Hairpin, Lyric, NoteheadShape, Ornament, Ottava, Pedal, Slur, StemDirection, Tuplet } from './types';
3
4
  export declare class NoteSet {
4
5
  readonly notes: Note[];
5
6
  constructor(notes: Note[]);
@@ -7,16 +8,16 @@ export declare class NoteSet {
7
8
  get isDotted(): boolean;
8
9
  get isRest(): boolean;
9
10
  get beamGroup(): number | undefined;
10
- get tuplet(): import("./types").Tuplet | undefined;
11
+ get tuplet(): Tuplet | undefined;
11
12
  getDurationValue(): number;
12
13
  isBeamable(): boolean;
13
14
  withDuration(duration: Duration, isDotted?: boolean): NoteSet;
14
15
  withBeamGroup(group?: number): NoteSet;
15
16
  withNotes(notes: Note[]): NoteSet;
16
- withLyrics(lyrics: (string | any)[]): NoteSet;
17
- withTuplet(tuplet?: any): NoteSet;
18
- withPitch(pitch: any): NoteSet;
19
- withAccidental(accidental: any): NoteSet;
17
+ withLyrics(lyrics: (string | Lyric)[]): NoteSet;
18
+ withTuplet(tuplet?: Tuplet): NoteSet;
19
+ withPitch(pitch: Pitch): NoteSet;
20
+ withAccidental(accidental?: Accidental): NoteSet;
20
21
  withRest(isRest: boolean): NoteSet;
21
22
  withGrace(isGrace: boolean): NoteSet;
22
23
  toggleEnharmonic(): NoteSet;
@@ -26,58 +27,59 @@ export declare class NoteSet {
26
27
  withChord(chord?: string): NoteSet;
27
28
  withTab(fret: number, string: number): NoteSet;
28
29
  withTie(tie: boolean): NoteSet;
29
- withSlur(slur?: any): NoteSet;
30
- withArticulation(articulation?: any): NoteSet;
31
- withOrnament(ornament?: any): NoteSet;
32
- withDynamic(dynamic?: any): NoteSet;
33
- withHairpin(hairpin?: any): NoteSet;
34
- withGlissando(glissando?: any): NoteSet;
35
- withArpeggio(arpeggio?: any): NoteSet;
36
- withOttava(ottava?: any): NoteSet;
37
- withPedal(pedal?: any): NoteSet;
30
+ withSlur(slur?: Slur): NoteSet;
31
+ withArticulation(articulation?: Articulation): NoteSet;
32
+ withOrnament(ornament?: Ornament): NoteSet;
33
+ withDynamic(dynamic?: Dynamic): NoteSet;
34
+ withHairpin(hairpin?: Hairpin): NoteSet;
35
+ withGlissando(glissando?: Glissando): NoteSet;
36
+ withArpeggio(arpeggio?: Arpeggio): NoteSet;
37
+ withOttava(ottava?: Ottava): NoteSet;
38
+ withPedal(pedal?: Pedal): NoteSet;
38
39
  withColor(color?: string): NoteSet;
39
- withNotehead(notehead: any): NoteSet;
40
- withBowing(bowing?: any): NoteSet;
40
+ withNotehead(notehead?: NoteheadShape): NoteSet;
41
+ withBowing(bowing?: Bowing): NoteSet;
41
42
  withFingering(fingering?: number): NoteSet;
42
43
  withHammerOn(type?: 'start' | 'stop'): NoteSet;
43
44
  withPullOff(type?: 'start' | 'stop'): NoteSet;
44
45
  withPalmMute(type?: 'start' | 'stop'): NoteSet;
45
46
  withStringCircled(isStringCircled?: boolean): NoteSet;
46
- withStemDirection(dir?: any): NoteSet;
47
- withLyric(lyric?: any): NoteSet;
47
+ withStemDirection(dir?: StemDirection): NoteSet;
48
+ withLyric(lyric?: string): NoteSet;
48
49
  withStaffText(text?: string): NoteSet;
49
- withFretboardDiagram(diagram?: any): NoteSet;
50
- get pitch(): import("./Pitch").Pitch | undefined;
51
- get accidental(): import("./types").Accidental | undefined;
50
+ withFretboardDiagram(diagram?: FretboardDiagram): NoteSet;
51
+ get pitch(): Pitch | undefined;
52
+ get accidental(): Accidental | undefined;
52
53
  get tie(): boolean | undefined;
53
- get slur(): import("./types").Slur | undefined;
54
- get articulation(): import("./types").Articulation | undefined;
55
- get ornament(): import("./types").Ornament | undefined;
56
- get dynamic(): import("./types").Dynamic | undefined;
57
- get hairpin(): import("./types").Hairpin | undefined;
58
- get glissando(): import("./types").Glissando | undefined;
59
- get arpeggio(): import("./types").Arpeggio | undefined;
60
- get ottava(): import("./types").Ottava | undefined;
61
- get pedal(): import("./types").Pedal | undefined;
62
- get notehead(): import("./types").NoteheadShape | undefined;
54
+ get slur(): Slur | undefined;
55
+ get articulations(): Articulation[];
56
+ get articulation(): Articulation | undefined;
57
+ get ornament(): Ornament | undefined;
58
+ get dynamic(): Dynamic | undefined;
59
+ get hairpin(): Hairpin | undefined;
60
+ get glissando(): Glissando | undefined;
61
+ get arpeggio(): Arpeggio | undefined;
62
+ get ottava(): Ottava | undefined;
63
+ get pedal(): Pedal | undefined;
64
+ get notehead(): NoteheadShape | undefined;
63
65
  get color(): string | undefined;
64
66
  get fret(): number | undefined;
65
67
  get string(): number | undefined;
66
- get bowing(): import("./types").Bowing | undefined;
68
+ get bowing(): Bowing | undefined;
67
69
  get fingering(): number | undefined;
68
- get allLyrics(): import("./types").Lyric[];
69
- get lyrics(): (string | import("./types").Lyric)[] | undefined;
70
+ get allLyrics(): Lyric[];
71
+ get lyrics(): (string | Lyric)[] | undefined;
70
72
  get lyric(): string | undefined;
71
73
  get chord(): string | undefined;
72
- get fretboardDiagram(): import("./types").FretboardDiagram | undefined;
74
+ get fretboardDiagram(): FretboardDiagram | undefined;
73
75
  get staffText(): string | undefined;
74
76
  get hammerOn(): "start" | "stop" | undefined;
75
77
  get pullOff(): "start" | "stop" | undefined;
76
78
  get palmMute(): "start" | "stop" | undefined;
77
79
  get isStringCircled(): boolean | undefined;
78
- get stemDirection(): import("./types").StemDirection | undefined;
80
+ get stemDirection(): StemDirection | undefined;
79
81
  toJSON(): NoteSetJSON;
80
- static fromJSON(data: any): NoteSet;
82
+ static fromJSON(data: Partial<NoteSetJSON> | NoteJSON | NoteJSON[]): NoteSet;
81
83
  }
82
84
  export interface NoteSetJSON {
83
85
  notes: NoteJSON[];
@@ -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)) {
@@ -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
+ }
@@ -2,7 +2,7 @@ import { Measure } from './Measure';
2
2
  import { NoteSet } from './NoteSet';
3
3
  import { Part, PartJSON } from './Part';
4
4
  import { Staff } from './Staff';
5
- import { Duration, Genre, KeySignature, TimeSignature } from './types';
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;