musicxml-io 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +167 -0
- package/dist/accessors/index.d.mts +82 -0
- package/dist/accessors/index.d.ts +82 -0
- package/dist/accessors/index.js +239 -0
- package/dist/accessors/index.js.map +1 -0
- package/dist/accessors/index.mjs +198 -0
- package/dist/accessors/index.mjs.map +1 -0
- package/dist/index.d.mts +285 -0
- package/dist/index.d.ts +285 -0
- package/dist/index.js +6033 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +5932 -0
- package/dist/index.mjs.map +1 -0
- package/dist/operations/index.d.mts +92 -0
- package/dist/operations/index.d.ts +92 -0
- package/dist/operations/index.js +352 -0
- package/dist/operations/index.js.map +1 -0
- package/dist/operations/index.mjs +315 -0
- package/dist/operations/index.mjs.map +1 -0
- package/dist/query/index.d.mts +103 -0
- package/dist/query/index.d.ts +103 -0
- package/dist/query/index.js +272 -0
- package/dist/query/index.js.map +1 -0
- package/dist/query/index.mjs +232 -0
- package/dist/query/index.mjs.map +1 -0
- package/dist/types-DC_TnJu_.d.mts +797 -0
- package/dist/types-DC_TnJu_.d.ts +797 -0
- package/package.json +80 -0
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
// src/utils/index.ts
|
|
2
|
+
function createPositionState() {
|
|
3
|
+
return { position: 0, lastNonChordPosition: 0 };
|
|
4
|
+
}
|
|
5
|
+
function updatePositionForEntry(state, entry) {
|
|
6
|
+
const pos = state.position;
|
|
7
|
+
switch (entry.type) {
|
|
8
|
+
case "note": {
|
|
9
|
+
const note = entry;
|
|
10
|
+
if (!note.chord) {
|
|
11
|
+
state.lastNonChordPosition = state.position;
|
|
12
|
+
state.position += note.duration;
|
|
13
|
+
}
|
|
14
|
+
return note.chord ? state.lastNonChordPosition : pos;
|
|
15
|
+
}
|
|
16
|
+
case "backup":
|
|
17
|
+
state.position -= entry.duration;
|
|
18
|
+
state.lastNonChordPosition = state.position;
|
|
19
|
+
return pos;
|
|
20
|
+
case "forward":
|
|
21
|
+
state.position += entry.duration;
|
|
22
|
+
state.lastNonChordPosition = state.position;
|
|
23
|
+
return pos;
|
|
24
|
+
default:
|
|
25
|
+
return pos;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function getAbsolutePositionForNote(note, measure) {
|
|
29
|
+
const state = createPositionState();
|
|
30
|
+
for (const entry of measure.entries) {
|
|
31
|
+
if (entry === note) return entry.chord ? state.lastNonChordPosition : state.position;
|
|
32
|
+
updatePositionForEntry(state, entry);
|
|
33
|
+
}
|
|
34
|
+
return state.position;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// src/accessors/index.ts
|
|
38
|
+
function getNotesForVoice(measure, filter) {
|
|
39
|
+
return measure.entries.filter((entry) => {
|
|
40
|
+
if (entry.type !== "note") return false;
|
|
41
|
+
if (filter.voice !== void 0 && entry.voice !== filter.voice) return false;
|
|
42
|
+
if (filter.staff !== void 0 && (entry.staff ?? 1) !== filter.staff) return false;
|
|
43
|
+
return true;
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
function getNotesForStaff(measure, filter) {
|
|
47
|
+
return measure.entries.filter((entry) => {
|
|
48
|
+
if (entry.type !== "note") return false;
|
|
49
|
+
return (entry.staff ?? 1) === filter.staff;
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
function groupByVoice(measure) {
|
|
53
|
+
const groups = /* @__PURE__ */ new Map();
|
|
54
|
+
for (const entry of measure.entries) {
|
|
55
|
+
if (entry.type !== "note") continue;
|
|
56
|
+
const staff = entry.staff ?? 1;
|
|
57
|
+
const voice = entry.voice;
|
|
58
|
+
const key = `${staff}-${voice}`;
|
|
59
|
+
if (!groups.has(key)) {
|
|
60
|
+
groups.set(key, { staff, voice, notes: [] });
|
|
61
|
+
}
|
|
62
|
+
groups.get(key).notes.push(entry);
|
|
63
|
+
}
|
|
64
|
+
return Array.from(groups.values()).sort((a, b) => {
|
|
65
|
+
if (a.staff !== b.staff) return a.staff - b.staff;
|
|
66
|
+
return a.voice - b.voice;
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
function groupByStaff(measure) {
|
|
70
|
+
const groups = /* @__PURE__ */ new Map();
|
|
71
|
+
for (const entry of measure.entries) {
|
|
72
|
+
if (entry.type !== "note") continue;
|
|
73
|
+
const staff = entry.staff ?? 1;
|
|
74
|
+
if (!groups.has(staff)) {
|
|
75
|
+
groups.set(staff, { staff, notes: [] });
|
|
76
|
+
}
|
|
77
|
+
groups.get(staff).notes.push(entry);
|
|
78
|
+
}
|
|
79
|
+
return Array.from(groups.values()).sort((a, b) => a.staff - b.staff);
|
|
80
|
+
}
|
|
81
|
+
function getAbsolutePosition(note, measure) {
|
|
82
|
+
return getAbsolutePositionForNote(note, measure);
|
|
83
|
+
}
|
|
84
|
+
function withAbsolutePositions(measure) {
|
|
85
|
+
const result = [];
|
|
86
|
+
const state = createPositionState();
|
|
87
|
+
for (const entry of measure.entries) {
|
|
88
|
+
if (entry.type === "note") {
|
|
89
|
+
const notePosition = entry.chord ? state.lastNonChordPosition : state.position;
|
|
90
|
+
result.push({
|
|
91
|
+
...entry,
|
|
92
|
+
absolutePosition: notePosition
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
updatePositionForEntry(state, entry);
|
|
96
|
+
}
|
|
97
|
+
return result;
|
|
98
|
+
}
|
|
99
|
+
function getChords(measure, filter) {
|
|
100
|
+
const notesWithPos = withAbsolutePositions(measure);
|
|
101
|
+
const filteredNotes = filter ? notesWithPos.filter((note) => {
|
|
102
|
+
if (filter.voice !== void 0 && note.voice !== filter.voice) return false;
|
|
103
|
+
if (filter.staff !== void 0 && (note.staff ?? 1) !== filter.staff) return false;
|
|
104
|
+
return true;
|
|
105
|
+
}) : notesWithPos;
|
|
106
|
+
const chordMap = /* @__PURE__ */ new Map();
|
|
107
|
+
for (const note of filteredNotes) {
|
|
108
|
+
const pos = note.absolutePosition;
|
|
109
|
+
if (!chordMap.has(pos)) {
|
|
110
|
+
chordMap.set(pos, []);
|
|
111
|
+
}
|
|
112
|
+
chordMap.get(pos).push(note);
|
|
113
|
+
}
|
|
114
|
+
const chords = [];
|
|
115
|
+
for (const [position, notes] of chordMap.entries()) {
|
|
116
|
+
const duration = notes[0].duration;
|
|
117
|
+
chords.push({
|
|
118
|
+
position,
|
|
119
|
+
duration,
|
|
120
|
+
notes: notes.map(({ absolutePosition, ...note }) => note)
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
return chords.sort((a, b) => a.position - b.position);
|
|
124
|
+
}
|
|
125
|
+
function* iterateNotes(score) {
|
|
126
|
+
for (const part of score.parts) {
|
|
127
|
+
for (const measure of part.measures) {
|
|
128
|
+
const state = createPositionState();
|
|
129
|
+
for (const entry of measure.entries) {
|
|
130
|
+
if (entry.type === "note") {
|
|
131
|
+
const notePosition = entry.chord ? state.lastNonChordPosition : state.position;
|
|
132
|
+
yield {
|
|
133
|
+
part,
|
|
134
|
+
measure,
|
|
135
|
+
note: entry,
|
|
136
|
+
position: notePosition
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
updatePositionForEntry(state, entry);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
function getAllNotes(score) {
|
|
145
|
+
return Array.from(iterateNotes(score));
|
|
146
|
+
}
|
|
147
|
+
function getVoices(measure) {
|
|
148
|
+
const voices = /* @__PURE__ */ new Set();
|
|
149
|
+
for (const entry of measure.entries) {
|
|
150
|
+
if (entry.type === "note") {
|
|
151
|
+
voices.add(entry.voice);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return Array.from(voices).sort((a, b) => a - b);
|
|
155
|
+
}
|
|
156
|
+
function getStaves(measure) {
|
|
157
|
+
const staves = /* @__PURE__ */ new Set();
|
|
158
|
+
for (const entry of measure.entries) {
|
|
159
|
+
if (entry.type === "note") {
|
|
160
|
+
staves.add(entry.staff ?? 1);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
return Array.from(staves).sort((a, b) => a - b);
|
|
164
|
+
}
|
|
165
|
+
function hasNotes(measure) {
|
|
166
|
+
return measure.entries.some((entry) => entry.type === "note");
|
|
167
|
+
}
|
|
168
|
+
function isRestMeasure(measure) {
|
|
169
|
+
const notes = measure.entries.filter((entry) => entry.type === "note");
|
|
170
|
+
return notes.length === 0 || notes.every((note) => !note.pitch);
|
|
171
|
+
}
|
|
172
|
+
function getNormalizedPosition(note, measure, options) {
|
|
173
|
+
const absolutePosition = getAbsolutePosition(note, measure);
|
|
174
|
+
const currentDivisions = options.currentDivisions ?? measure.attributes?.divisions ?? 1;
|
|
175
|
+
return absolutePosition * options.baseDivisions / currentDivisions;
|
|
176
|
+
}
|
|
177
|
+
function getNormalizedDuration(note, options) {
|
|
178
|
+
const currentDivisions = options.currentDivisions ?? 1;
|
|
179
|
+
return note.duration * options.baseDivisions / currentDivisions;
|
|
180
|
+
}
|
|
181
|
+
export {
|
|
182
|
+
getAbsolutePosition,
|
|
183
|
+
getAllNotes,
|
|
184
|
+
getChords,
|
|
185
|
+
getNormalizedDuration,
|
|
186
|
+
getNormalizedPosition,
|
|
187
|
+
getNotesForStaff,
|
|
188
|
+
getNotesForVoice,
|
|
189
|
+
getStaves,
|
|
190
|
+
getVoices,
|
|
191
|
+
groupByStaff,
|
|
192
|
+
groupByVoice,
|
|
193
|
+
hasNotes,
|
|
194
|
+
isRestMeasure,
|
|
195
|
+
iterateNotes,
|
|
196
|
+
withAbsolutePositions
|
|
197
|
+
};
|
|
198
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/utils/index.ts","../../src/accessors/index.ts"],"sourcesContent":["import type { Pitch, Measure, MeasureEntry, NoteEntry } from '../types';\n\n// Pitch constants\nexport const STEPS: Pitch['step'][] = ['C', 'D', 'E', 'F', 'G', 'A', 'B'];\nexport const STEP_SEMITONES: Record<Pitch['step'], number> = {\n 'C': 0, 'D': 2, 'E': 4, 'F': 5, 'G': 7, 'A': 9, 'B': 11,\n};\n\n/** Convert pitch to semitone value (MIDI-like) */\nexport function pitchToSemitone(pitch: Pitch): number {\n return pitch.octave * 12 + STEP_SEMITONES[pitch.step] + (pitch.alter ?? 0);\n}\n\n// Position tracking for measure iteration\nexport interface PositionState {\n position: number;\n lastNonChordPosition: number;\n}\n\nexport function createPositionState(): PositionState {\n return { position: 0, lastNonChordPosition: 0 };\n}\n\n/** Update position state for entry, returns position before update */\nexport function updatePositionForEntry(state: PositionState, entry: MeasureEntry): number {\n const pos = state.position;\n switch (entry.type) {\n case 'note': {\n const note = entry as NoteEntry;\n if (!note.chord) {\n state.lastNonChordPosition = state.position;\n state.position += note.duration;\n }\n return note.chord ? state.lastNonChordPosition : pos;\n }\n case 'backup':\n state.position -= entry.duration;\n state.lastNonChordPosition = state.position;\n return pos;\n case 'forward':\n state.position += entry.duration;\n state.lastNonChordPosition = state.position;\n return pos;\n default:\n return pos;\n }\n}\n\n/** Get absolute position of a note within a measure */\nexport function getAbsolutePositionForNote(note: NoteEntry, measure: Measure): number {\n const state = createPositionState();\n for (const entry of measure.entries) {\n if (entry === note) return entry.chord ? state.lastNonChordPosition : state.position;\n updatePositionForEntry(state, entry);\n }\n return state.position;\n}\n\n/** Get position at end of measure */\nexport function getMeasureEndPosition(measure: Measure): number {\n const state = createPositionState();\n for (const entry of measure.entries) updatePositionForEntry(state, entry);\n return state.position;\n}\n","import type {\n Score,\n Measure,\n NoteEntry,\n VoiceGroup,\n StaffGroup,\n NoteWithPosition,\n Chord,\n NoteIteratorItem,\n} from '../types';\nimport { getAbsolutePositionForNote, createPositionState, updatePositionForEntry } from '../utils';\n\n/**\n * Filter options for voice/staff selection\n */\nexport interface VoiceFilter {\n voice?: number;\n staff?: number;\n}\n\n/**\n * Get all notes for a specific voice (and optionally staff)\n */\nexport function getNotesForVoice(measure: Measure, filter: VoiceFilter): NoteEntry[] {\n return measure.entries.filter((entry): entry is NoteEntry => {\n if (entry.type !== 'note') return false;\n if (filter.voice !== undefined && entry.voice !== filter.voice) return false;\n if (filter.staff !== undefined && (entry.staff ?? 1) !== filter.staff) return false;\n return true;\n });\n}\n\n/**\n * Get all notes for a specific staff (regardless of voice)\n */\nexport function getNotesForStaff(measure: Measure, filter: { staff: number }): NoteEntry[] {\n return measure.entries.filter((entry): entry is NoteEntry => {\n if (entry.type !== 'note') return false;\n return (entry.staff ?? 1) === filter.staff;\n });\n}\n\n/**\n * Group notes by voice (and staff)\n */\nexport function groupByVoice(measure: Measure): VoiceGroup[] {\n const groups = new Map<string, VoiceGroup>();\n\n for (const entry of measure.entries) {\n if (entry.type !== 'note') continue;\n\n const staff = entry.staff ?? 1;\n const voice = entry.voice;\n const key = `${staff}-${voice}`;\n\n if (!groups.has(key)) {\n groups.set(key, { staff, voice, notes: [] });\n }\n\n groups.get(key)!.notes.push(entry);\n }\n\n // Sort by staff, then by voice\n return Array.from(groups.values()).sort((a, b) => {\n if (a.staff !== b.staff) return a.staff - b.staff;\n return a.voice - b.voice;\n });\n}\n\n/**\n * Group notes by staff\n */\nexport function groupByStaff(measure: Measure): StaffGroup[] {\n const groups = new Map<number, StaffGroup>();\n\n for (const entry of measure.entries) {\n if (entry.type !== 'note') continue;\n\n const staff = entry.staff ?? 1;\n\n if (!groups.has(staff)) {\n groups.set(staff, { staff, notes: [] });\n }\n\n groups.get(staff)!.notes.push(entry);\n }\n\n return Array.from(groups.values()).sort((a, b) => a.staff - b.staff);\n}\n\n/**\n * Calculate absolute position of a note within a measure\n * Position is in divisions from the start of the measure\n */\nexport function getAbsolutePosition(note: NoteEntry, measure: Measure): number {\n return getAbsolutePositionForNote(note, measure);\n}\n\n/**\n * Add absolute position to all notes in a measure\n */\nexport function withAbsolutePositions(measure: Measure): NoteWithPosition[] {\n const result: NoteWithPosition[] = [];\n const state = createPositionState();\n\n for (const entry of measure.entries) {\n if (entry.type === 'note') {\n const notePosition = entry.chord ? state.lastNonChordPosition : state.position;\n result.push({\n ...entry,\n absolutePosition: notePosition,\n });\n }\n updatePositionForEntry(state, entry);\n }\n\n return result;\n}\n\n/**\n * Get chords (groups of simultaneously sounding notes)\n */\nexport function getChords(measure: Measure, filter?: VoiceFilter): Chord[] {\n const notesWithPos = withAbsolutePositions(measure);\n\n // Filter by voice/staff if specified\n const filteredNotes = filter\n ? notesWithPos.filter((note) => {\n if (filter.voice !== undefined && note.voice !== filter.voice) return false;\n if (filter.staff !== undefined && (note.staff ?? 1) !== filter.staff) return false;\n return true;\n })\n : notesWithPos;\n\n // Group by position\n const chordMap = new Map<number, NoteWithPosition[]>();\n\n for (const note of filteredNotes) {\n const pos = note.absolutePosition;\n if (!chordMap.has(pos)) {\n chordMap.set(pos, []);\n }\n chordMap.get(pos)!.push(note);\n }\n\n // Convert to Chord array\n const chords: Chord[] = [];\n\n for (const [position, notes] of chordMap.entries()) {\n // All notes in a chord should have the same duration (using first note's duration)\n const duration = notes[0].duration;\n\n chords.push({\n position,\n duration,\n notes: notes.map(({ absolutePosition, ...note }) => note),\n });\n }\n\n // Sort by position\n return chords.sort((a, b) => a.position - b.position);\n}\n\n/**\n * Iterate over all notes in a score\n */\nexport function* iterateNotes(score: Score): Generator<NoteIteratorItem> {\n for (const part of score.parts) {\n for (const measure of part.measures) {\n const state = createPositionState();\n\n for (const entry of measure.entries) {\n if (entry.type === 'note') {\n const notePosition = entry.chord ? state.lastNonChordPosition : state.position;\n yield {\n part,\n measure,\n note: entry,\n position: notePosition,\n };\n }\n updatePositionForEntry(state, entry);\n }\n }\n }\n}\n\n/**\n * Get all notes from a score as an array\n */\nexport function getAllNotes(score: Score): NoteIteratorItem[] {\n return Array.from(iterateNotes(score));\n}\n\n/**\n * Get unique voices used in a measure\n */\nexport function getVoices(measure: Measure): number[] {\n const voices = new Set<number>();\n\n for (const entry of measure.entries) {\n if (entry.type === 'note') {\n voices.add(entry.voice);\n }\n }\n\n return Array.from(voices).sort((a, b) => a - b);\n}\n\n/**\n * Get unique staves used in a measure\n */\nexport function getStaves(measure: Measure): number[] {\n const staves = new Set<number>();\n\n for (const entry of measure.entries) {\n if (entry.type === 'note') {\n staves.add(entry.staff ?? 1);\n }\n }\n\n return Array.from(staves).sort((a, b) => a - b);\n}\n\n/**\n * Check if a measure contains any notes\n */\nexport function hasNotes(measure: Measure): boolean {\n return measure.entries.some((entry) => entry.type === 'note');\n}\n\n/**\n * Check if a measure is a rest (no pitched notes)\n */\nexport function isRestMeasure(measure: Measure): boolean {\n const notes = measure.entries.filter((entry): entry is NoteEntry => entry.type === 'note');\n return notes.length === 0 || notes.every((note) => !note.pitch);\n}\n\n/**\n * Options for normalized position calculation\n */\nexport interface NormalizedPositionOptions {\n baseDivisions: number;\n currentDivisions?: number;\n}\n\n/**\n * Get a normalized position of a note using a common base divisions\n * This is useful when comparing positions across measures with different divisions\n */\nexport function getNormalizedPosition(\n note: NoteEntry,\n measure: Measure,\n options: NormalizedPositionOptions\n): number {\n const absolutePosition = getAbsolutePosition(note, measure);\n const currentDivisions = options.currentDivisions ?? measure.attributes?.divisions ?? 1;\n\n // Convert from current divisions to base divisions\n return (absolutePosition * options.baseDivisions) / currentDivisions;\n}\n\n/**\n * Get normalized duration of a note using a common base divisions\n */\nexport function getNormalizedDuration(\n note: NoteEntry,\n options: NormalizedPositionOptions\n): number {\n const currentDivisions = options.currentDivisions ?? 1;\n return (note.duration * options.baseDivisions) / currentDivisions;\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
import { S as Score, M as Measure, T as TimeSignature, P as Part, a as Pitch } from './types-DC_TnJu_.mjs';
|
|
2
|
+
export { A as Accidental, i as AccidentalInfo, B as BackupEntry, p as Barline, k as BeamInfo, s as Chord, C as Clef, w as Credit, v as Defaults, D as DirectionEntry, m as DirectionType, n as DynamicsValue, F as ForwardEntry, K as KeySignature, L as Lyric, f as MeasureAttributes, g as MeasureEntry, l as Notation, N as NoteEntry, t as NoteIteratorItem, h as NoteType, r as NoteWithPosition, d as PartGroup, c as PartInfo, e as PartListEntry, u as Print, b as ScoreMetadata, q as StaffGroup, j as TieInfo, o as Transpose, V as VoiceGroup } from './types-DC_TnJu_.mjs';
|
|
3
|
+
export { NormalizedPositionOptions, VoiceFilter, getAbsolutePosition, getAllNotes, getChords, getNormalizedDuration, getNormalizedPosition, getNotesForStaff, getNotesForVoice, getStaves, getVoices, groupByStaff, groupByVoice, hasNotes, isRestMeasure, iterateNotes, withAbsolutePositions } from './accessors/index.mjs';
|
|
4
|
+
export { FindNotesFilter, PitchRange, RoundtripMetrics, countNotes, findNotes, getAttributesAtMeasure, getDivisions, getDuration, getMeasure, getMeasureByIndex, getMeasureCount, getPartById, getPartIndex, getStaveCount, hasMultipleStaves, measureRoundtrip, scoresEqual } from './query/index.mjs';
|
|
5
|
+
export { AddNoteOptions, addChordNote, addNote, changeKey, changeTime, deleteMeasure, deleteNote, insertMeasure, modifyNoteDuration, modifyNotePitch, setDivisions, transpose } from './operations/index.mjs';
|
|
6
|
+
|
|
7
|
+
declare function parse(xmlString: string): Score;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Parse a compressed MusicXML (.mxl) file
|
|
11
|
+
* @param data - The compressed file data as Uint8Array or Buffer
|
|
12
|
+
* @returns The parsed Score
|
|
13
|
+
*/
|
|
14
|
+
declare function parseCompressed(data: Uint8Array): Score;
|
|
15
|
+
/**
|
|
16
|
+
* Check if data is a compressed MusicXML file
|
|
17
|
+
* @param data - The file data
|
|
18
|
+
* @returns true if the data appears to be a ZIP file
|
|
19
|
+
*/
|
|
20
|
+
declare function isCompressed(data: Uint8Array): boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Parse either compressed (.mxl) or uncompressed (.xml/.musicxml) MusicXML
|
|
23
|
+
* Automatically detects the format
|
|
24
|
+
* @param data - The file data as Uint8Array or string
|
|
25
|
+
* @returns The parsed Score
|
|
26
|
+
*/
|
|
27
|
+
declare function parseAuto(data: Uint8Array | string): Score;
|
|
28
|
+
|
|
29
|
+
type ValidationErrorCode = 'MISSING_DIVISIONS' | 'INVALID_DIVISIONS' | 'MEASURE_DURATION_MISMATCH' | 'MEASURE_DURATION_OVERFLOW' | 'MEASURE_DURATION_UNDERFLOW' | 'NEGATIVE_POSITION' | 'BACKUP_EXCEEDS_POSITION' | 'TIE_START_WITHOUT_STOP' | 'TIE_STOP_WITHOUT_START' | 'TIE_PITCH_MISMATCH' | 'BEAM_BEGIN_WITHOUT_END' | 'BEAM_END_WITHOUT_BEGIN' | 'SLUR_START_WITHOUT_STOP' | 'SLUR_STOP_WITHOUT_START' | 'TUPLET_START_WITHOUT_STOP' | 'TUPLET_STOP_WITHOUT_START' | 'PART_ID_NOT_IN_PART_LIST' | 'PART_LIST_ID_NOT_IN_PARTS' | 'PART_MEASURE_COUNT_MISMATCH' | 'PART_MEASURE_NUMBER_MISMATCH' | 'PART_GROUP_START_WITHOUT_STOP' | 'PART_GROUP_STOP_WITHOUT_START' | 'DUPLICATE_PART_ID' | 'INVALID_VOICE_NUMBER' | 'INVALID_STAFF_NUMBER' | 'STAFF_EXCEEDS_STAVES' | 'MISSING_STAVES_DECLARATION' | 'STAVES_DECLARATION_MISMATCH' | 'MISSING_CLEF_FOR_STAFF' | 'CLEF_STAFF_EXCEEDS_STAVES' | 'INVALID_DURATION' | 'EMPTY_MEASURE';
|
|
30
|
+
type ValidationLevel = 'error' | 'warning' | 'info';
|
|
31
|
+
interface ValidationLocation {
|
|
32
|
+
partIndex?: number;
|
|
33
|
+
partId?: string;
|
|
34
|
+
measureIndex?: number;
|
|
35
|
+
measureNumber?: string;
|
|
36
|
+
entryIndex?: number;
|
|
37
|
+
voice?: number;
|
|
38
|
+
staff?: number;
|
|
39
|
+
}
|
|
40
|
+
interface ValidationError {
|
|
41
|
+
code: ValidationErrorCode;
|
|
42
|
+
level: ValidationLevel;
|
|
43
|
+
message: string;
|
|
44
|
+
location: ValidationLocation;
|
|
45
|
+
details?: Record<string, unknown>;
|
|
46
|
+
}
|
|
47
|
+
interface ValidationResult {
|
|
48
|
+
valid: boolean;
|
|
49
|
+
errors: ValidationError[];
|
|
50
|
+
warnings: ValidationError[];
|
|
51
|
+
infos: ValidationError[];
|
|
52
|
+
}
|
|
53
|
+
interface ValidateOptions {
|
|
54
|
+
/** Check divisions consistency (default: true) */
|
|
55
|
+
checkDivisions?: boolean;
|
|
56
|
+
/** Check measure durations match time signature (default: true) */
|
|
57
|
+
checkMeasureDuration?: boolean;
|
|
58
|
+
/** Check backup/forward position consistency (default: true) */
|
|
59
|
+
checkPosition?: boolean;
|
|
60
|
+
/** Check tie start/stop pairing (default: true) */
|
|
61
|
+
checkTies?: boolean;
|
|
62
|
+
/** Check beam begin/end pairing (default: true) */
|
|
63
|
+
checkBeams?: boolean;
|
|
64
|
+
/** Check slur start/stop pairing (default: true) */
|
|
65
|
+
checkSlurs?: boolean;
|
|
66
|
+
/** Check tuplet start/stop pairing (default: true) */
|
|
67
|
+
checkTuplets?: boolean;
|
|
68
|
+
/** Check part ID references (default: true) */
|
|
69
|
+
checkPartReferences?: boolean;
|
|
70
|
+
/** Check part structure (measure count, numbers) (default: true) */
|
|
71
|
+
checkPartStructure?: boolean;
|
|
72
|
+
/** Check voice/staff numbers (default: true) */
|
|
73
|
+
checkVoiceStaff?: boolean;
|
|
74
|
+
/** Check staff structure (staves declaration, clefs) (default: true) */
|
|
75
|
+
checkStaffStructure?: boolean;
|
|
76
|
+
/** Tolerance for measure duration (in divisions, default: 0) */
|
|
77
|
+
durationTolerance?: number;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Validate a Score for internal consistency
|
|
81
|
+
*/
|
|
82
|
+
declare function validate(score: Score, options?: ValidateOptions): ValidationResult;
|
|
83
|
+
/**
|
|
84
|
+
* Validate that divisions are defined and consistent
|
|
85
|
+
*/
|
|
86
|
+
declare function validateDivisions(score: Score): ValidationError[];
|
|
87
|
+
/**
|
|
88
|
+
* Validate measure duration matches time signature
|
|
89
|
+
*/
|
|
90
|
+
declare function validateMeasureDuration(measure: Measure, divisions: number, time: TimeSignature, location: ValidationLocation, tolerance?: number): ValidationError[];
|
|
91
|
+
/**
|
|
92
|
+
* Validate backup/forward position consistency
|
|
93
|
+
*/
|
|
94
|
+
declare function validateBackupForward(measure: Measure, location: ValidationLocation): ValidationError[];
|
|
95
|
+
/**
|
|
96
|
+
* Validate tie start/stop pairing
|
|
97
|
+
*/
|
|
98
|
+
declare function validateTies(measure: Measure, location: ValidationLocation): ValidationError[];
|
|
99
|
+
/**
|
|
100
|
+
* Validate beam begin/end pairing
|
|
101
|
+
*/
|
|
102
|
+
declare function validateBeams(measure: Measure, location: ValidationLocation): ValidationError[];
|
|
103
|
+
/**
|
|
104
|
+
* Validate slur start/stop pairing
|
|
105
|
+
*/
|
|
106
|
+
declare function validateSlurs(measure: Measure, _location: ValidationLocation): ValidationError[];
|
|
107
|
+
/**
|
|
108
|
+
* Validate tuplet start/stop pairing
|
|
109
|
+
*/
|
|
110
|
+
declare function validateTuplets(measure: Measure, location: ValidationLocation): ValidationError[];
|
|
111
|
+
/**
|
|
112
|
+
* Validate part ID references between partList and parts
|
|
113
|
+
*/
|
|
114
|
+
declare function validatePartReferences(score: Score): ValidationError[];
|
|
115
|
+
/**
|
|
116
|
+
* Validate voice and staff numbers
|
|
117
|
+
*/
|
|
118
|
+
declare function validateVoiceStaff(measure: Measure, staves: number, location: ValidationLocation): ValidationError[];
|
|
119
|
+
/**
|
|
120
|
+
* Validate part structure (measure counts and numbers match across parts)
|
|
121
|
+
*/
|
|
122
|
+
declare function validatePartStructure(score: Score): ValidationError[];
|
|
123
|
+
/**
|
|
124
|
+
* Validate staff structure within a part
|
|
125
|
+
*/
|
|
126
|
+
declare function validateStaffStructure(part: Part, partIndex: number): ValidationError[];
|
|
127
|
+
/**
|
|
128
|
+
* Context needed to validate a single measure
|
|
129
|
+
*/
|
|
130
|
+
interface MeasureValidationContext {
|
|
131
|
+
/** Current divisions value (from previous attributes) */
|
|
132
|
+
divisions: number;
|
|
133
|
+
/** Current time signature */
|
|
134
|
+
time?: TimeSignature;
|
|
135
|
+
/** Current staves count */
|
|
136
|
+
staves: number;
|
|
137
|
+
/** Part index (for error location) */
|
|
138
|
+
partIndex: number;
|
|
139
|
+
/** Part ID (for error location) */
|
|
140
|
+
partId: string;
|
|
141
|
+
/** Measure index (for error location) */
|
|
142
|
+
measureIndex: number;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Options for local measure validation
|
|
146
|
+
*/
|
|
147
|
+
interface LocalValidateOptions {
|
|
148
|
+
checkMeasureDuration?: boolean;
|
|
149
|
+
checkPosition?: boolean;
|
|
150
|
+
checkBeams?: boolean;
|
|
151
|
+
checkTuplets?: boolean;
|
|
152
|
+
checkVoiceStaff?: boolean;
|
|
153
|
+
durationTolerance?: number;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Validate a single measure with provided context.
|
|
157
|
+
* This is useful for validating after local operations like addNote, deleteNote.
|
|
158
|
+
*
|
|
159
|
+
* @example
|
|
160
|
+
* ```typescript
|
|
161
|
+
* const context = getMeasureContext(score, partIndex, measureIndex);
|
|
162
|
+
* const errors = validateMeasureLocal(measure, context);
|
|
163
|
+
* if (errors.length > 0) {
|
|
164
|
+
* throw new Error('Operation created invalid state');
|
|
165
|
+
* }
|
|
166
|
+
* ```
|
|
167
|
+
*/
|
|
168
|
+
declare function validateMeasureLocal(measure: Measure, context: MeasureValidationContext, options?: LocalValidateOptions): ValidationError[];
|
|
169
|
+
/**
|
|
170
|
+
* Get the validation context for a measure by traversing previous attributes.
|
|
171
|
+
* This collects divisions, time, and staves from measure 0 to the target measure.
|
|
172
|
+
*/
|
|
173
|
+
declare function getMeasureContext(score: Score, partIndex: number, measureIndex: number): MeasureValidationContext;
|
|
174
|
+
/**
|
|
175
|
+
* Validate a measure after an operation, throwing if invalid.
|
|
176
|
+
* Convenience wrapper around validateMeasureLocal.
|
|
177
|
+
*/
|
|
178
|
+
declare function assertMeasureValid(score: Score, partIndex: number, measureIndex: number, options?: LocalValidateOptions): void;
|
|
179
|
+
/**
|
|
180
|
+
* Check if a score is valid (no errors)
|
|
181
|
+
*/
|
|
182
|
+
declare function isValid(score: Score, options?: ValidateOptions): boolean;
|
|
183
|
+
/**
|
|
184
|
+
* Validate and throw if invalid
|
|
185
|
+
*/
|
|
186
|
+
declare function assertValid(score: Score, options?: ValidateOptions): void;
|
|
187
|
+
/**
|
|
188
|
+
* Format a validation location for display
|
|
189
|
+
*/
|
|
190
|
+
declare function formatLocation(location: ValidationLocation): string;
|
|
191
|
+
/**
|
|
192
|
+
* Validation exception with structured error information
|
|
193
|
+
*/
|
|
194
|
+
declare class ValidationException extends Error {
|
|
195
|
+
readonly errors: ValidationError[];
|
|
196
|
+
constructor(errors: ValidationError[], message: string);
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Validate ties across measures
|
|
200
|
+
* This is more complex as ties can span multiple measures
|
|
201
|
+
*/
|
|
202
|
+
declare function validateTiesAcrossMeasures(part: Part): ValidationError[];
|
|
203
|
+
/**
|
|
204
|
+
* Validate slurs across measures
|
|
205
|
+
*/
|
|
206
|
+
declare function validateSlursAcrossMeasures(part: Part): ValidationError[];
|
|
207
|
+
|
|
208
|
+
interface SerializeOptions {
|
|
209
|
+
version?: '3.1' | '4.0';
|
|
210
|
+
indent?: string;
|
|
211
|
+
/** Validate score before serializing (default: false) */
|
|
212
|
+
validate?: boolean;
|
|
213
|
+
/** Options for validation (if validate is true) */
|
|
214
|
+
validateOptions?: ValidateOptions;
|
|
215
|
+
/** Throw error if validation fails (default: false, will only warn) */
|
|
216
|
+
throwOnValidationError?: boolean;
|
|
217
|
+
/** Callback to receive validation result */
|
|
218
|
+
onValidation?: (result: ValidationResult) => void;
|
|
219
|
+
}
|
|
220
|
+
declare function serialize(score: Score, options?: SerializeOptions): string;
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Serialize a Score to compressed MusicXML (.mxl) format
|
|
224
|
+
* @param score - The Score to serialize
|
|
225
|
+
* @param options - Serialization options
|
|
226
|
+
* @returns The compressed file data as Uint8Array
|
|
227
|
+
*/
|
|
228
|
+
declare function serializeCompressed(score: Score, options?: SerializeOptions): Uint8Array;
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* MIDI export options
|
|
232
|
+
*/
|
|
233
|
+
interface MidiExportOptions {
|
|
234
|
+
/** Ticks per quarter note (default: 480) */
|
|
235
|
+
ticksPerQuarterNote?: number;
|
|
236
|
+
/** Default tempo in BPM (default: 120) */
|
|
237
|
+
defaultTempo?: number;
|
|
238
|
+
/** Default velocity for notes (default: 80) */
|
|
239
|
+
defaultVelocity?: number;
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Export a Score to Standard MIDI File format (SMF Type 1)
|
|
243
|
+
* @param score - The Score to export
|
|
244
|
+
* @param options - Export options
|
|
245
|
+
* @returns The MIDI file data as Uint8Array
|
|
246
|
+
*/
|
|
247
|
+
declare function exportMidi(score: Score, options?: MidiExportOptions): Uint8Array;
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Parse a MusicXML file from disk
|
|
251
|
+
* Automatically handles both .xml/.musicxml and .mxl formats
|
|
252
|
+
* @param filePath - Path to the file
|
|
253
|
+
* @returns The parsed Score
|
|
254
|
+
*/
|
|
255
|
+
declare function parseFile(filePath: string): Promise<Score>;
|
|
256
|
+
/**
|
|
257
|
+
* Detect encoding from BOM and decode buffer to string
|
|
258
|
+
* Supports UTF-8, UTF-16BE, UTF-16LE
|
|
259
|
+
*/
|
|
260
|
+
declare function decodeBuffer(buffer: Buffer): string;
|
|
261
|
+
/**
|
|
262
|
+
* Export options combining all format options
|
|
263
|
+
*/
|
|
264
|
+
interface ExportOptions extends SerializeOptions, MidiExportOptions {
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Serialize a Score to a file
|
|
268
|
+
* Format is determined by file extension:
|
|
269
|
+
* - .mxl: Compressed MusicXML
|
|
270
|
+
* - .xml/.musicxml: Uncompressed MusicXML
|
|
271
|
+
* - .mid/.midi: Standard MIDI File
|
|
272
|
+
* @param score - The Score to serialize
|
|
273
|
+
* @param filePath - Path to write the file
|
|
274
|
+
* @param options - Serialization options
|
|
275
|
+
*/
|
|
276
|
+
declare function serializeToFile(score: Score, filePath: string, options?: ExportOptions): Promise<void>;
|
|
277
|
+
|
|
278
|
+
declare const STEPS: Pitch['step'][];
|
|
279
|
+
declare const STEP_SEMITONES: Record<Pitch['step'], number>;
|
|
280
|
+
/** Convert pitch to semitone value (MIDI-like) */
|
|
281
|
+
declare function pitchToSemitone(pitch: Pitch): number;
|
|
282
|
+
/** Get position at end of measure */
|
|
283
|
+
declare function getMeasureEndPosition(measure: Measure): number;
|
|
284
|
+
|
|
285
|
+
export { type LocalValidateOptions, Measure, type MeasureValidationContext, type MidiExportOptions, Part, Pitch, STEPS, STEP_SEMITONES, Score, type SerializeOptions, TimeSignature, type ValidateOptions, type ValidationError, type ValidationErrorCode, ValidationException, type ValidationLevel, type ValidationLocation, type ValidationResult, assertMeasureValid, assertValid, decodeBuffer, exportMidi, formatLocation, getMeasureContext, getMeasureEndPosition, isCompressed, isValid, parse, parseAuto, parseCompressed, parseFile, pitchToSemitone, serialize, serializeCompressed, serializeToFile, validate, validateBackupForward, validateBeams, validateDivisions, validateMeasureDuration, validateMeasureLocal, validatePartReferences, validatePartStructure, validateSlurs, validateSlursAcrossMeasures, validateStaffStructure, validateTies, validateTiesAcrossMeasures, validateTuplets, validateVoiceStaff };
|