musicxml-io 0.2.5 → 0.2.8

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/index.d.ts CHANGED
@@ -1,9 +1,8 @@
1
- import { S as Score, P as Pitch, M as Measure } from './types-D3LhKCDK.js';
2
- export { A as Accidental, i as AccidentalInfo, O as AdjacentNotes, a4 as AssembledLyrics, B as BackupEntry, p as Barline, a5 as BarlineWithContext, a0 as BeamGroup, j as BeamInfo, s as Chord, C as Clef, aa as ClefChangeInfo, w as Credit, v as Defaults, D as DirectionEntry, Q as DirectionKind, l as DirectionType, z as DirectionWithContext, R as DynamicWithContext, m as DynamicsValue, a7 as EndingInfo, E as EntryWithContext, F as ForwardEntry, a2 as HarmonyWithContext, a8 as KeyChangeInfo, K as KeySignature, L as Lyric, a3 as LyricWithContext, f as MeasureAttributes, g as MeasureEntry, k as Notation, a1 as NotationType, N as NoteEntry, t as NoteIteratorItem, h as NoteType, y as NoteWithContext, r as NoteWithPosition, Y as OctaveShiftWithContext, e as Part, c as PartGroup, b as PartInfo, d as PartListEntry, W as PedalWithContext, H as PositionQueryOptions, u as Print, a6 as RepeatInfo, a as ScoreMetadata, _ as SlurSpan, q as StaffGroup, G as StaffRange, ab as StructuralChanges, U as TempoWithContext, T as TieInfo, Z as TiedNoteGroup, a9 as TimeChangeInfo, n as TimeSignature, o as Transpose, $ as TupletGroup, I as VerticalSlice, V as VoiceGroup, J as VoiceLine, x as VoiceToStaffMap, X as WedgeWithContext } from './types-D3LhKCDK.js';
3
- import { V as ValidateOptions, a as ValidationResult } from './index-CJUkJI2P.js';
4
- export { L as LocalValidateOptions, M as MeasureValidationContext, G as ValidationError, I as ValidationErrorCode, C as ValidationException, J as ValidationLevel, H as ValidationLocation, g as addChordNote, b as addNote, F as assertMeasureValid, k as assertValid, c as changeKey, e as changeTime, f as deleteMeasure, d as deleteNote, B as formatLocation, E as getMeasureContext, i as insertMeasure, j as isValid, h as modifyNoteDuration, m as modifyNotePitch, t as transpose, v as validate, o as validateBackupForward, q as validateBeams, l as validateDivisions, n as validateMeasureDuration, D as validateMeasureLocal, u as validatePartReferences, w as validatePartStructure, r as validateSlurs, A as validateSlursAcrossMeasures, x as validateStaffStructure, p as validateTies, z as validateTiesAcrossMeasures, s as validateTuplets, y as validateVoiceStaff } from './index-CJUkJI2P.js';
5
- export { NormalizedPositionOptions, VoiceFilter, buildVoiceToStaffMap, buildVoiceToStaffMapForPart, findBarlines, findDirectionsByType, findNotesWithNotation, getAbsolutePosition, getAdjacentNotes, getAllNotes, getBeamGroups, getChordProgression, getChords, getClefChanges, getClefForStaff, getDirections, getDirectionsAtPosition, getDynamics, getEffectiveStaff, getEndings, getEntriesAtPosition, getEntriesForStaff, getEntriesInRange, getHarmonies, getHarmonyAtPosition, getKeyChanges, getLyricText, getLyrics, getNextNote, getNormalizedDuration, getNormalizedPosition, getNotesAtPosition, getNotesForStaff, getNotesForVoice, getNotesInRange, getOctaveShifts, getPartByIndex, getPartCount, getPartIds, getPedalMarkings, getPrevNote, getRepeatStructure, getSlurSpans, getStaffRange, getStaves, getStructuralChanges, getTempoMarkings, getTiedNoteGroups, getTimeChanges, getTupletGroups, getVerseCount, getVerticalSlice, getVoiceLine, getVoiceLineInRange, getVoices, getVoicesForStaff, getWedges, groupByStaff, groupByVoice, hasNotes, inferStaff, isRestMeasure, iterateEntries, iterateNotes, withAbsolutePositions } from './accessors/index.js';
6
- export { FindNotesFilter, PitchRange, RoundtripMetrics, countNotes, findNotes, getAttributesAtMeasure, getDivisions, getDuration, getMeasure, getMeasureByIndex, getMeasureCount, getPartById, getPartIndex, getStaveCount, hasMultipleStaves, measureRoundtrip, scoresEqual } from './query/index.js';
1
+ import { S as Score, P as Pitch, M as Measure, D as DirectionType, a as DirectionEntry, N as NoteEntry, b as PartListEntry, c as PartInfo } from './types-Bpq2o5JS.js';
2
+ export { A as Accidental, j as AccidentalInfo, O as AdjacentNotes, a4 as AssembledLyrics, B as BackupEntry, p as Barline, a5 as BarlineWithContext, a0 as BeamGroup, k as BeamInfo, s as Chord, C as Clef, aa as ClefChangeInfo, w as Credit, v as Defaults, Q as DirectionKind, z as DirectionWithContext, R as DynamicWithContext, m as DynamicsValue, a7 as EndingInfo, E as EntryWithContext, F as ForwardEntry, a2 as HarmonyWithContext, a8 as KeyChangeInfo, K as KeySignature, L as Lyric, a3 as LyricWithContext, g as MeasureAttributes, h as MeasureEntry, l as Notation, a1 as NotationType, t as NoteIteratorItem, i as NoteType, y as NoteWithContext, r as NoteWithPosition, Y as OctaveShiftWithContext, f as Part, e as PartGroup, W as PedalWithContext, H as PositionQueryOptions, u as Print, a6 as RepeatInfo, d as ScoreMetadata, _ as SlurSpan, q as StaffGroup, G as StaffRange, ab as StructuralChanges, U as TempoWithContext, T as TieInfo, Z as TiedNoteGroup, a9 as TimeChangeInfo, n as TimeSignature, o as Transpose, $ as TupletGroup, I as VerticalSlice, V as VoiceGroup, J as VoiceLine, x as VoiceToStaffMap, X as WedgeWithContext } from './types-Bpq2o5JS.js';
3
+ import { V as ValidateOptions, a as ValidationResult } from './index-B-GcfEfL.js';
4
+ export { L as LocalValidateOptions, M as MeasureValidationContext, G as ValidationError, I as ValidationErrorCode, C as ValidationException, J as ValidationLevel, H as ValidationLocation, g as addChordNote, b as addNote, F as assertMeasureValid, k as assertValid, c as changeKey, e as changeTime, f as deleteMeasure, d as deleteNote, B as formatLocation, E as getMeasureContext, i as insertMeasure, j as isValid, h as modifyNoteDuration, m as modifyNotePitch, t as transpose, v as validate, o as validateBackupForward, q as validateBeams, l as validateDivisions, n as validateMeasureDuration, D as validateMeasureLocal, u as validatePartReferences, w as validatePartStructure, r as validateSlurs, A as validateSlursAcrossMeasures, x as validateStaffStructure, p as validateTies, z as validateTiesAcrossMeasures, s as validateTuplets, y as validateVoiceStaff } from './index-B-GcfEfL.js';
5
+ export { FindNotesFilter, NormalizedPositionOptions, PitchRange, RoundtripMetrics, VoiceFilter, buildVoiceToStaffMap, buildVoiceToStaffMapForPart, countNotes, findBarlines, findDirectionsByType, findNotes, findNotesWithNotation, getAbsolutePosition, getAdjacentNotes, getAllNotes, getAttributesAtMeasure, getBeamGroups, getChordProgression, getChords, getClefChanges, getClefForStaff, getDirections, getDirectionsAtPosition, getDivisions, getDuration, getDynamics, getEffectiveStaff, getEndings, getEntriesAtPosition, getEntriesForStaff, getEntriesInRange, getHarmonies, getHarmonyAtPosition, getKeyChanges, getLyricText, getLyrics, getMeasure, getMeasureByIndex, getMeasureCount, getNextNote, getNormalizedDuration, getNormalizedPosition, getNotesAtPosition, getNotesForStaff, getNotesForVoice, getNotesInRange, getOctaveShifts, getPartById, getPartByIndex, getPartCount, getPartIds, getPartIndex, getPedalMarkings, getPrevNote, getRepeatStructure, getSlurSpans, getStaffRange, getStaveCount, getStaves, getStructuralChanges, getTempoMarkings, getTiedNoteGroups, getTimeChanges, getTupletGroups, getVerseCount, getVerticalSlice, getVoiceLine, getVoiceLineInRange, getVoices, getVoicesForStaff, getWedges, groupByStaff, groupByVoice, hasMultipleStaves, hasNotes, inferStaff, isRestMeasure, iterateEntries, iterateNotes, measureRoundtrip, scoresEqual, withAbsolutePositions } from './query/index.js';
7
6
 
8
7
  declare function parse(xmlString: string): Score;
9
8
 
@@ -104,4 +103,199 @@ declare function pitchToSemitone(pitch: Pitch): number;
104
103
  /** Get position at end of measure */
105
104
  declare function getMeasureEndPosition(measure: Measure): number;
106
105
 
107
- export { Measure, type MidiExportOptions, Pitch, STEPS, STEP_SEMITONES, Score, type SerializeOptions, ValidateOptions, ValidationResult, decodeBuffer, exportMidi, getMeasureEndPosition, isCompressed, parse, parseAuto, parseCompressed, parseFile, pitchToSemitone, serialize, serializeCompressed, serializeToFile };
106
+ /**
107
+ * Entry-level accessors for DirectionEntry, NoteEntry, and PartInfo
108
+ *
109
+ * These are simple helper functions for working with individual entries,
110
+ * complementing the score-level query functions in ./query.
111
+ */
112
+
113
+ /**
114
+ * Extracts a specific DirectionType union member by its kind
115
+ */
116
+ type DirectionTypeOfKind<K extends DirectionType['kind']> = Extract<DirectionType, {
117
+ kind: K;
118
+ }>;
119
+ /**
120
+ * Get the first direction type of a specific kind from a DirectionEntry
121
+ *
122
+ * @example
123
+ * const dynamics = getDirectionOfKind(entry, 'dynamics');
124
+ * if (dynamics) {
125
+ * console.log(dynamics.value); // 'ff', 'pp', etc.
126
+ * }
127
+ */
128
+ declare function getDirectionOfKind<K extends DirectionType['kind']>(entry: DirectionEntry, kind: K): DirectionTypeOfKind<K> | undefined;
129
+ /**
130
+ * Get all direction types of a specific kind from a DirectionEntry
131
+ *
132
+ * @example
133
+ * const allWords = getDirectionsOfKind(entry, 'words');
134
+ * allWords.forEach(w => console.log(w.text));
135
+ */
136
+ declare function getDirectionsOfKind<K extends DirectionType['kind']>(entry: DirectionEntry, kind: K): DirectionTypeOfKind<K>[];
137
+ /**
138
+ * Check if a DirectionEntry contains a specific direction type
139
+ *
140
+ * @example
141
+ * if (hasDirectionOfKind(entry, 'metronome')) {
142
+ * // Handle tempo marking
143
+ * }
144
+ */
145
+ declare function hasDirectionOfKind(entry: DirectionEntry, kind: DirectionType['kind']): boolean;
146
+ /**
147
+ * Get tempo from DirectionEntry.sound
148
+ *
149
+ * @example
150
+ * const tempo = getSoundTempo(entry); // 120
151
+ */
152
+ declare function getSoundTempo(entry: DirectionEntry): number | undefined;
153
+ /**
154
+ * Get dynamics value from DirectionEntry.sound (MIDI velocity 0-127)
155
+ *
156
+ * @example
157
+ * const dynamics = getSoundDynamics(entry); // 80
158
+ */
159
+ declare function getSoundDynamics(entry: DirectionEntry): number | undefined;
160
+ /**
161
+ * Get damper pedal state from DirectionEntry.sound
162
+ */
163
+ declare function getSoundDamperPedal(entry: DirectionEntry): 'yes' | 'no' | undefined;
164
+ /**
165
+ * Get soft pedal state from DirectionEntry.sound
166
+ */
167
+ declare function getSoundSoftPedal(entry: DirectionEntry): 'yes' | 'no' | undefined;
168
+ /**
169
+ * Get sostenuto pedal state from DirectionEntry.sound
170
+ */
171
+ declare function getSoundSostenutoPedal(entry: DirectionEntry): 'yes' | 'no' | undefined;
172
+ /**
173
+ * Check if a NoteEntry is a rest
174
+ *
175
+ * @example
176
+ * if (isRest(note)) {
177
+ * console.log('This is a rest');
178
+ * }
179
+ */
180
+ declare function isRest(entry: NoteEntry): boolean;
181
+ /**
182
+ * Check if a NoteEntry is a pitched note (has pitch information)
183
+ *
184
+ * @example
185
+ * if (isPitchedNote(note)) {
186
+ * console.log(`Note: ${note.pitch!.step}${note.pitch!.octave}`);
187
+ * }
188
+ */
189
+ declare function isPitchedNote(entry: NoteEntry): boolean;
190
+ /**
191
+ * Check if a NoteEntry is an unpitched note (percussion)
192
+ */
193
+ declare function isUnpitchedNote(entry: NoteEntry): boolean;
194
+ /**
195
+ * Check if a NoteEntry is part of a chord (shares onset with previous note)
196
+ *
197
+ * @example
198
+ * const chordNotes = notes.filter(isChordNote);
199
+ */
200
+ declare function isChordNote(entry: NoteEntry): boolean;
201
+ /**
202
+ * Check if a NoteEntry is a grace note
203
+ *
204
+ * @example
205
+ * if (isGraceNote(note)) {
206
+ * console.log('Grace note with slash:', note.grace?.slash);
207
+ * }
208
+ */
209
+ declare function isGraceNote(entry: NoteEntry): boolean;
210
+ /**
211
+ * Check if a NoteEntry has any tie (start, stop, or continue)
212
+ *
213
+ * @example
214
+ * if (hasTie(note)) {
215
+ * // Note is tied to another note
216
+ * }
217
+ */
218
+ declare function hasTie(entry: NoteEntry): boolean;
219
+ /**
220
+ * Check if a NoteEntry has a tie start
221
+ */
222
+ declare function hasTieStart(entry: NoteEntry): boolean;
223
+ /**
224
+ * Check if a NoteEntry has a tie stop
225
+ */
226
+ declare function hasTieStop(entry: NoteEntry): boolean;
227
+ /**
228
+ * Check if a NoteEntry is a cue note
229
+ */
230
+ declare function isCueNote(entry: NoteEntry): boolean;
231
+ /**
232
+ * Check if a NoteEntry has any beams
233
+ */
234
+ declare function hasBeam(entry: NoteEntry): boolean;
235
+ /**
236
+ * Check if a NoteEntry has any lyrics
237
+ */
238
+ declare function hasLyrics(entry: NoteEntry): boolean;
239
+ /**
240
+ * Check if a NoteEntry has any notations (articulations, slurs, ornaments, etc.)
241
+ */
242
+ declare function hasNotations(entry: NoteEntry): boolean;
243
+ /**
244
+ * Check if a NoteEntry is part of a tuplet
245
+ */
246
+ declare function hasTuplet(entry: NoteEntry): boolean;
247
+ /**
248
+ * Check if a PartListEntry is a PartInfo (score-part)
249
+ */
250
+ declare function isPartInfo(entry: PartListEntry): entry is PartInfo;
251
+ /**
252
+ * Get PartInfo by part ID
253
+ *
254
+ * @example
255
+ * const partInfo = getPartInfo(score, 'P1');
256
+ * if (partInfo) {
257
+ * console.log(partInfo.name); // 'Piano'
258
+ * }
259
+ */
260
+ declare function getPartInfo(score: Score, partId: string): PartInfo | undefined;
261
+ /**
262
+ * Get part name by part ID
263
+ *
264
+ * @example
265
+ * const name = getPartName(score, 'P1'); // 'Piano'
266
+ */
267
+ declare function getPartName(score: Score, partId: string): string | undefined;
268
+ /**
269
+ * Get part abbreviation by part ID
270
+ *
271
+ * @example
272
+ * const abbr = getPartAbbreviation(score, 'P1'); // 'Pno.'
273
+ */
274
+ declare function getPartAbbreviation(score: Score, partId: string): string | undefined;
275
+ /**
276
+ * Get all PartInfo entries from a score
277
+ */
278
+ declare function getAllPartInfos(score: Score): PartInfo[];
279
+ /**
280
+ * Get a map of part ID to part name
281
+ *
282
+ * @example
283
+ * const names = getPartNameMap(score);
284
+ * // { 'P1': 'Piano', 'P2': 'Violin' }
285
+ */
286
+ declare function getPartNameMap(score: Score): Record<string, string | undefined>;
287
+
288
+ /**
289
+ * Generates a unique ID for elements in the Score structure.
290
+ *
291
+ * The ID format is "i" + nanoid(10), where:
292
+ * - "i" prefix ensures XML ID compatibility (XML IDs must start with a letter or underscore)
293
+ * - nanoid(10) generates a 10-character URL-safe unique identifier
294
+ *
295
+ * Example: "iV1StGXR8_"
296
+ *
297
+ * @returns A unique 11-character ID string
298
+ */
299
+ declare function generateId(): string;
300
+
301
+ export { DirectionEntry, DirectionType, type DirectionTypeOfKind, Measure, type MidiExportOptions, NoteEntry, PartInfo, PartListEntry, Pitch, STEPS, STEP_SEMITONES, Score, type SerializeOptions, ValidateOptions, ValidationResult, decodeBuffer, exportMidi, generateId, getAllPartInfos, getDirectionOfKind, getDirectionsOfKind, getMeasureEndPosition, getPartAbbreviation, getPartInfo, getPartName, getPartNameMap, getSoundDamperPedal, getSoundDynamics, getSoundSoftPedal, getSoundSostenutoPedal, getSoundTempo, hasBeam, hasDirectionOfKind, hasLyrics, hasNotations, hasTie, hasTieStart, hasTieStop, hasTuplet, isChordNote, isCompressed, isCueNote, isGraceNote, isPartInfo, isPitchedNote, isRest, isUnpitchedNote, parse, parseAuto, parseCompressed, parseFile, pitchToSemitone, serialize, serializeCompressed, serializeToFile };
package/dist/index.js CHANGED
@@ -41,17 +41,21 @@ __export(src_exports, {
41
41
  findNotes: () => findNotes,
42
42
  findNotesWithNotation: () => findNotesWithNotation,
43
43
  formatLocation: () => formatLocation,
44
+ generateId: () => generateId,
44
45
  getAbsolutePosition: () => getAbsolutePosition,
45
46
  getAdjacentNotes: () => getAdjacentNotes,
46
47
  getAllNotes: () => getAllNotes,
48
+ getAllPartInfos: () => getAllPartInfos,
47
49
  getAttributesAtMeasure: () => getAttributesAtMeasure,
48
50
  getBeamGroups: () => getBeamGroups,
49
51
  getChordProgression: () => getChordProgression,
50
52
  getChords: () => getChords,
51
53
  getClefChanges: () => getClefChanges,
52
54
  getClefForStaff: () => getClefForStaff,
55
+ getDirectionOfKind: () => getDirectionOfKind,
53
56
  getDirections: () => getDirections,
54
57
  getDirectionsAtPosition: () => getDirectionsAtPosition,
58
+ getDirectionsOfKind: () => getDirectionsOfKind,
55
59
  getDivisions: () => getDivisions,
56
60
  getDuration: () => getDuration,
57
61
  getDynamics: () => getDynamics,
@@ -78,15 +82,24 @@ __export(src_exports, {
78
82
  getNotesForVoice: () => getNotesForVoice,
79
83
  getNotesInRange: () => getNotesInRange,
80
84
  getOctaveShifts: () => getOctaveShifts,
85
+ getPartAbbreviation: () => getPartAbbreviation,
81
86
  getPartById: () => getPartById,
82
87
  getPartByIndex: () => getPartByIndex,
83
88
  getPartCount: () => getPartCount,
84
89
  getPartIds: () => getPartIds,
85
90
  getPartIndex: () => getPartIndex,
91
+ getPartInfo: () => getPartInfo,
92
+ getPartName: () => getPartName,
93
+ getPartNameMap: () => getPartNameMap,
86
94
  getPedalMarkings: () => getPedalMarkings,
87
95
  getPrevNote: () => getPrevNote,
88
96
  getRepeatStructure: () => getRepeatStructure,
89
97
  getSlurSpans: () => getSlurSpans,
98
+ getSoundDamperPedal: () => getSoundDamperPedal,
99
+ getSoundDynamics: () => getSoundDynamics,
100
+ getSoundSoftPedal: () => getSoundSoftPedal,
101
+ getSoundSostenutoPedal: () => getSoundSostenutoPedal,
102
+ getSoundTempo: () => getSoundTempo,
90
103
  getStaffRange: () => getStaffRange,
91
104
  getStaveCount: () => getStaveCount,
92
105
  getStaves: () => getStaves,
@@ -104,12 +117,27 @@ __export(src_exports, {
104
117
  getWedges: () => getWedges,
105
118
  groupByStaff: () => groupByStaff,
106
119
  groupByVoice: () => groupByVoice,
120
+ hasBeam: () => hasBeam,
121
+ hasDirectionOfKind: () => hasDirectionOfKind,
122
+ hasLyrics: () => hasLyrics,
107
123
  hasMultipleStaves: () => hasMultipleStaves,
124
+ hasNotations: () => hasNotations,
108
125
  hasNotes: () => hasNotes,
126
+ hasTie: () => hasTie,
127
+ hasTieStart: () => hasTieStart,
128
+ hasTieStop: () => hasTieStop,
129
+ hasTuplet: () => hasTuplet,
109
130
  inferStaff: () => inferStaff,
110
131
  insertMeasure: () => insertMeasure,
132
+ isChordNote: () => isChordNote,
111
133
  isCompressed: () => isCompressed,
134
+ isCueNote: () => isCueNote,
135
+ isGraceNote: () => isGraceNote,
136
+ isPartInfo: () => isPartInfo,
137
+ isPitchedNote: () => isPitchedNote,
138
+ isRest: () => isRest,
112
139
  isRestMeasure: () => isRestMeasure,
140
+ isUnpitchedNote: () => isUnpitchedNote,
113
141
  isValid: () => isValid,
114
142
  iterateEntries: () => iterateEntries,
115
143
  iterateNotes: () => iterateNotes,
@@ -147,6 +175,14 @@ module.exports = __toCommonJS(src_exports);
147
175
 
148
176
  // src/importers/musicxml.ts
149
177
  var import_fast_xml_parser = require("fast-xml-parser");
178
+
179
+ // src/id.ts
180
+ var import_nanoid = require("nanoid");
181
+ function generateId() {
182
+ return "i" + (0, import_nanoid.nanoid)(10);
183
+ }
184
+
185
+ // src/importers/musicxml.ts
150
186
  var xmlParser = new import_fast_xml_parser.XMLParser({
151
187
  ignoreAttributes: false,
152
188
  attributeNamePrefix: "@_",
@@ -233,6 +269,7 @@ function parseScorePartwise(elements) {
233
269
  const defaults = parseDefaults(elements);
234
270
  const credits = parseCredits(elements);
235
271
  return {
272
+ _id: generateId(),
236
273
  metadata,
237
274
  partList,
238
275
  parts,
@@ -434,7 +471,7 @@ function parseSystemLayout(elements) {
434
471
  }
435
472
  function parseCredits(elements) {
436
473
  const credits = collectElements(elements, "credit", (content, attrs) => {
437
- const credit = {};
474
+ const credit = { _id: generateId() };
438
475
  if (attrs["page"]) credit.page = parseInt(attrs["page"], 10);
439
476
  const types = collectElements(content, "credit-type", (c) => extractText(c));
440
477
  const words = collectElements(content, "credit-words", (c, a) => {
@@ -476,6 +513,7 @@ function parsePartList(elements) {
476
513
  const attrs = getAttributes(el);
477
514
  const content = el["score-part"];
478
515
  const partInfo = {
516
+ _id: generateId(),
479
517
  type: "score-part",
480
518
  id: attrs["id"] || ""
481
519
  };
@@ -568,6 +606,7 @@ function parsePartList(elements) {
568
606
  const attrs = getAttributes(el);
569
607
  const content = el["part-group"];
570
608
  const group = {
609
+ _id: generateId(),
571
610
  type: "part-group",
572
611
  groupType: attrs["type"] === "stop" ? "stop" : "start"
573
612
  };
@@ -603,6 +642,7 @@ function parseParts(elements) {
603
642
  const attrs = getAttributes(el);
604
643
  const content = el["part"];
605
644
  const part = {
645
+ _id: generateId(),
606
646
  id: attrs["id"] || "",
607
647
  measures: []
608
648
  };
@@ -620,6 +660,7 @@ function parseParts(elements) {
620
660
  }
621
661
  function parseMeasure(elements, attrs) {
622
662
  const measure = {
663
+ _id: generateId(),
623
664
  number: attrs["number"] || "0",
624
665
  // Keep as string per MusicXML spec (token type)
625
666
  entries: []
@@ -636,6 +677,7 @@ function parseMeasure(elements, attrs) {
636
677
  isFirstAttributes = false;
637
678
  } else {
638
679
  const attrEntry = {
680
+ _id: generateId(),
639
681
  type: "attributes",
640
682
  attributes: parsedAttrs
641
683
  };
@@ -861,6 +903,7 @@ function parseTranspose(elements) {
861
903
  }
862
904
  function parseNote(elements, attrs) {
863
905
  const note = {
906
+ _id: generateId(),
864
907
  type: "note",
865
908
  duration: getElementTextAsInt(elements, "duration", 0),
866
909
  voice: getElementTextAsInt(elements, "voice", 1)
@@ -1515,12 +1558,14 @@ function parseLyric(elements, attrs) {
1515
1558
  }
1516
1559
  function parseBackup(elements) {
1517
1560
  return {
1561
+ _id: generateId(),
1518
1562
  type: "backup",
1519
1563
  duration: parseInt(getElementText(elements, "duration") || "0", 10)
1520
1564
  };
1521
1565
  }
1522
1566
  function parseForward(elements) {
1523
1567
  const forward = {
1568
+ _id: generateId(),
1524
1569
  type: "forward",
1525
1570
  duration: parseInt(getElementText(elements, "duration") || "0", 10)
1526
1571
  };
@@ -1532,6 +1577,7 @@ function parseForward(elements) {
1532
1577
  }
1533
1578
  function parseDirection(elements, attrs) {
1534
1579
  const direction = {
1580
+ _id: generateId(),
1535
1581
  type: "direction",
1536
1582
  directionTypes: []
1537
1583
  };
@@ -1907,7 +1953,7 @@ function parseDirectionType(elements) {
1907
1953
  }
1908
1954
  function parseBarline(elements, attrs) {
1909
1955
  const location = attrs["location"] || "right";
1910
- const barline = { location };
1956
+ const barline = { _id: generateId(), location };
1911
1957
  const barStyle = getElementText(elements, "bar-style");
1912
1958
  if (barStyle && isValidBarStyle(barStyle)) {
1913
1959
  barline.barStyle = barStyle;
@@ -2123,6 +2169,7 @@ function parseMeasureStyle(elements, attrs) {
2123
2169
  }
2124
2170
  function parseHarmony(elements, attrs) {
2125
2171
  const harmony = {
2172
+ _id: generateId(),
2126
2173
  type: "harmony",
2127
2174
  root: { rootStep: "C" },
2128
2175
  kind: "major"
@@ -2246,6 +2293,7 @@ function parseHarmony(elements, attrs) {
2246
2293
  }
2247
2294
  function parseFiguredBass(elements, attrs) {
2248
2295
  const fb = {
2296
+ _id: generateId(),
2249
2297
  type: "figured-bass",
2250
2298
  figures: []
2251
2299
  };
@@ -2292,6 +2340,7 @@ function parseFiguredBass(elements, attrs) {
2292
2340
  }
2293
2341
  function parseSound(elements, attrs) {
2294
2342
  const sound = {
2343
+ _id: generateId(),
2295
2344
  type: "sound"
2296
2345
  };
2297
2346
  if (attrs["tempo"]) sound.tempo = parseFloat(attrs["tempo"]);
@@ -5509,7 +5558,7 @@ function getMeasureEndPosition(measure) {
5509
5558
  return state.position;
5510
5559
  }
5511
5560
 
5512
- // src/accessors/index.ts
5561
+ // src/query/index.ts
5513
5562
  function getNotesForVoice(measure, filter) {
5514
5563
  return measure.entries.filter((entry) => {
5515
5564
  if (entry.type !== "note") return false;
@@ -6250,17 +6299,17 @@ function getTiedNoteGroups(score, options) {
6250
6299
  measureIndex,
6251
6300
  position
6252
6301
  };
6253
- const hasTieStart = entry.tie?.type === "start" || entry.ties?.some((t) => t.type === "start") || entry.notations?.some((n) => n.type === "tied" && n.tiedType === "start");
6254
- const hasTieStop = entry.tie?.type === "stop" || entry.ties?.some((t) => t.type === "stop") || entry.notations?.some((n) => n.type === "tied" && n.tiedType === "stop");
6255
- if (hasTieStop && pendingTies.has(pitchKey)) {
6302
+ const hasTieStart2 = entry.tie?.type === "start" || entry.ties?.some((t) => t.type === "start") || entry.notations?.some((n) => n.type === "tied" && n.tiedType === "start");
6303
+ const hasTieStop2 = entry.tie?.type === "stop" || entry.ties?.some((t) => t.type === "stop") || entry.notations?.some((n) => n.type === "tied" && n.tiedType === "stop");
6304
+ if (hasTieStop2 && pendingTies.has(pitchKey)) {
6256
6305
  const group = pendingTies.get(pitchKey);
6257
6306
  group.push(context);
6258
- if (!hasTieStart) {
6307
+ if (!hasTieStart2) {
6259
6308
  const totalDuration = group.reduce((sum, nc) => sum + nc.note.duration, 0);
6260
6309
  results.push({ notes: group, totalDuration });
6261
6310
  pendingTies.delete(pitchKey);
6262
6311
  }
6263
- } else if (hasTieStart) {
6312
+ } else if (hasTieStart2) {
6264
6313
  pendingTies.set(pitchKey, [context]);
6265
6314
  }
6266
6315
  }
@@ -6856,8 +6905,6 @@ function getPartCount(score) {
6856
6905
  function getPartIds(score) {
6857
6906
  return score.parts.map((part) => part.id);
6858
6907
  }
6859
-
6860
- // src/query/index.ts
6861
6908
  function getMeasure(score, options) {
6862
6909
  const part = score.parts[options.part];
6863
6910
  if (!part) return void 0;
@@ -6935,8 +6982,8 @@ function findNotes(score, filter) {
6935
6982
  if (filter.staff !== void 0 && (entry.staff ?? 1) !== filter.staff) continue;
6936
6983
  if (filter.noteType !== void 0 && entry.noteType !== filter.noteType) continue;
6937
6984
  if (filter.hasTie !== void 0) {
6938
- const hasTie = entry.tie !== void 0;
6939
- if (filter.hasTie !== hasTie) continue;
6985
+ const hasTie2 = entry.tie !== void 0;
6986
+ if (filter.hasTie !== hasTie2) continue;
6940
6987
  }
6941
6988
  results.push(entry);
6942
6989
  }
@@ -7140,6 +7187,7 @@ function hasNotesInRange(voiceEntries, startPos, endPos) {
7140
7187
  }
7141
7188
  function createRest(duration, voice, staff) {
7142
7189
  return {
7190
+ _id: generateId(),
7143
7191
  type: "note",
7144
7192
  rest: { displayStep: void 0, displayOctave: void 0 },
7145
7193
  duration,
@@ -7201,10 +7249,11 @@ function rebuildMeasureWithVoice(measure, voice, newEntries, measureDuration, st
7201
7249
  for (const { position: targetPos, entry } of allEntries) {
7202
7250
  const diff = targetPos - currentPosition;
7203
7251
  if (diff < 0) {
7204
- result.push({ type: "backup", duration: -diff });
7252
+ result.push({ _id: generateId(), type: "backup", duration: -diff });
7205
7253
  currentPosition = targetPos;
7206
7254
  } else if (diff > 0) {
7207
7255
  result.push({
7256
+ _id: generateId(),
7208
7257
  type: "forward",
7209
7258
  duration: diff,
7210
7259
  voice: entry.type === "note" ? entry.voice : 1,
@@ -7259,6 +7308,7 @@ function insertNote(score, options) {
7259
7308
  )]);
7260
7309
  }
7261
7310
  const newNote = {
7311
+ _id: generateId(),
7262
7312
  type: "note",
7263
7313
  pitch: options.pitch,
7264
7314
  duration: options.duration,
@@ -7365,6 +7415,7 @@ function addChord(score, options) {
7365
7415
  return failure([operationError("NOTE_NOT_FOUND", `Note index ${options.noteIndex} not found`, { partIndex: options.partIndex, measureIndex: options.measureIndex })]);
7366
7416
  }
7367
7417
  const chordNote = {
7418
+ _id: generateId(),
7368
7419
  type: "note",
7369
7420
  pitch: options.pitch,
7370
7421
  duration: targetEntry.duration,
@@ -7588,7 +7639,7 @@ function insertMeasure(score, options) {
7588
7639
  if (insertIndex === -1) continue;
7589
7640
  const numericPart = parseInt(targetMeasure, 10);
7590
7641
  const newMeasureNumber = String(isNaN(numericPart) ? insertIndex + 2 : numericPart + 1);
7591
- const newMeasure = { number: newMeasureNumber, entries: [] };
7642
+ const newMeasure = { _id: generateId(), number: newMeasureNumber, entries: [] };
7592
7643
  if (options.copyAttributes && part.measures[insertIndex].attributes) {
7593
7644
  newMeasure.attributes = { ...part.measures[insertIndex].attributes };
7594
7645
  }
@@ -7684,6 +7735,97 @@ async function serializeToFile(score, filePath, options = {}) {
7684
7735
  await (0, import_promises.writeFile)(filePath, xmlString, "utf-8");
7685
7736
  }
7686
7737
  }
7738
+
7739
+ // src/entry-accessors.ts
7740
+ function getDirectionOfKind(entry, kind) {
7741
+ return entry.directionTypes.find((d) => d.kind === kind);
7742
+ }
7743
+ function getDirectionsOfKind(entry, kind) {
7744
+ return entry.directionTypes.filter((d) => d.kind === kind);
7745
+ }
7746
+ function hasDirectionOfKind(entry, kind) {
7747
+ return entry.directionTypes.some((d) => d.kind === kind);
7748
+ }
7749
+ function getSoundTempo(entry) {
7750
+ return entry.sound?.tempo;
7751
+ }
7752
+ function getSoundDynamics(entry) {
7753
+ return entry.sound?.dynamics;
7754
+ }
7755
+ function getSoundDamperPedal(entry) {
7756
+ return entry.sound?.damperPedal;
7757
+ }
7758
+ function getSoundSoftPedal(entry) {
7759
+ return entry.sound?.softPedal;
7760
+ }
7761
+ function getSoundSostenutoPedal(entry) {
7762
+ return entry.sound?.sostenutoPedal;
7763
+ }
7764
+ function isRest(entry) {
7765
+ return entry.rest !== void 0 || !entry.pitch && !entry.unpitched;
7766
+ }
7767
+ function isPitchedNote(entry) {
7768
+ return entry.pitch !== void 0;
7769
+ }
7770
+ function isUnpitchedNote(entry) {
7771
+ return entry.unpitched !== void 0;
7772
+ }
7773
+ function isChordNote(entry) {
7774
+ return entry.chord === true;
7775
+ }
7776
+ function isGraceNote(entry) {
7777
+ return entry.grace !== void 0;
7778
+ }
7779
+ function hasTie(entry) {
7780
+ return entry.tie !== void 0 || entry.ties !== void 0 && entry.ties.length > 0;
7781
+ }
7782
+ function hasTieStart(entry) {
7783
+ if (entry.tie?.type === "start") return true;
7784
+ return entry.ties?.some((t) => t.type === "start") ?? false;
7785
+ }
7786
+ function hasTieStop(entry) {
7787
+ if (entry.tie?.type === "stop") return true;
7788
+ return entry.ties?.some((t) => t.type === "stop") ?? false;
7789
+ }
7790
+ function isCueNote(entry) {
7791
+ return entry.cue === true;
7792
+ }
7793
+ function hasBeam(entry) {
7794
+ return entry.beam !== void 0 && entry.beam.length > 0;
7795
+ }
7796
+ function hasLyrics(entry) {
7797
+ return entry.lyrics !== void 0 && entry.lyrics.length > 0;
7798
+ }
7799
+ function hasNotations(entry) {
7800
+ return entry.notations !== void 0 && entry.notations.length > 0;
7801
+ }
7802
+ function hasTuplet(entry) {
7803
+ return entry.timeModification !== void 0;
7804
+ }
7805
+ function isPartInfo(entry) {
7806
+ return entry.type === "score-part";
7807
+ }
7808
+ function getPartInfo(score, partId) {
7809
+ return score.partList.find((entry) => {
7810
+ return entry.type === "score-part" && entry.id === partId;
7811
+ });
7812
+ }
7813
+ function getPartName(score, partId) {
7814
+ return getPartInfo(score, partId)?.name;
7815
+ }
7816
+ function getPartAbbreviation(score, partId) {
7817
+ return getPartInfo(score, partId)?.abbreviation;
7818
+ }
7819
+ function getAllPartInfos(score) {
7820
+ return score.partList.filter(isPartInfo);
7821
+ }
7822
+ function getPartNameMap(score) {
7823
+ const map = {};
7824
+ for (const part of getAllPartInfos(score)) {
7825
+ map[part.id] = part.name;
7826
+ }
7827
+ return map;
7828
+ }
7687
7829
  // Annotate the CommonJS export names for ESM import in node:
7688
7830
  0 && (module.exports = {
7689
7831
  STEPS,
@@ -7707,17 +7849,21 @@ async function serializeToFile(score, filePath, options = {}) {
7707
7849
  findNotes,
7708
7850
  findNotesWithNotation,
7709
7851
  formatLocation,
7852
+ generateId,
7710
7853
  getAbsolutePosition,
7711
7854
  getAdjacentNotes,
7712
7855
  getAllNotes,
7856
+ getAllPartInfos,
7713
7857
  getAttributesAtMeasure,
7714
7858
  getBeamGroups,
7715
7859
  getChordProgression,
7716
7860
  getChords,
7717
7861
  getClefChanges,
7718
7862
  getClefForStaff,
7863
+ getDirectionOfKind,
7719
7864
  getDirections,
7720
7865
  getDirectionsAtPosition,
7866
+ getDirectionsOfKind,
7721
7867
  getDivisions,
7722
7868
  getDuration,
7723
7869
  getDynamics,
@@ -7744,15 +7890,24 @@ async function serializeToFile(score, filePath, options = {}) {
7744
7890
  getNotesForVoice,
7745
7891
  getNotesInRange,
7746
7892
  getOctaveShifts,
7893
+ getPartAbbreviation,
7747
7894
  getPartById,
7748
7895
  getPartByIndex,
7749
7896
  getPartCount,
7750
7897
  getPartIds,
7751
7898
  getPartIndex,
7899
+ getPartInfo,
7900
+ getPartName,
7901
+ getPartNameMap,
7752
7902
  getPedalMarkings,
7753
7903
  getPrevNote,
7754
7904
  getRepeatStructure,
7755
7905
  getSlurSpans,
7906
+ getSoundDamperPedal,
7907
+ getSoundDynamics,
7908
+ getSoundSoftPedal,
7909
+ getSoundSostenutoPedal,
7910
+ getSoundTempo,
7756
7911
  getStaffRange,
7757
7912
  getStaveCount,
7758
7913
  getStaves,
@@ -7770,12 +7925,27 @@ async function serializeToFile(score, filePath, options = {}) {
7770
7925
  getWedges,
7771
7926
  groupByStaff,
7772
7927
  groupByVoice,
7928
+ hasBeam,
7929
+ hasDirectionOfKind,
7930
+ hasLyrics,
7773
7931
  hasMultipleStaves,
7932
+ hasNotations,
7774
7933
  hasNotes,
7934
+ hasTie,
7935
+ hasTieStart,
7936
+ hasTieStop,
7937
+ hasTuplet,
7775
7938
  inferStaff,
7776
7939
  insertMeasure,
7940
+ isChordNote,
7777
7941
  isCompressed,
7942
+ isCueNote,
7943
+ isGraceNote,
7944
+ isPartInfo,
7945
+ isPitchedNote,
7946
+ isRest,
7778
7947
  isRestMeasure,
7948
+ isUnpitchedNote,
7779
7949
  isValid,
7780
7950
  iterateEntries,
7781
7951
  iterateNotes,