musicxml-io 0.12.0 → 0.12.2
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/README.md +96 -8
- package/dist/abc-HXITSXCS.js +9 -0
- package/dist/abc-IAD53SFI.mjs +11 -0
- package/dist/abc-MTGVOYKS.js +11 -0
- package/dist/abc-R7DIJSHG.mjs +9 -0
- package/dist/abc.d.mts +67 -0
- package/dist/abc.d.ts +67 -0
- package/dist/abc.js +17 -0
- package/dist/abc.mjs +17 -0
- package/dist/accessors/index.d.mts +1 -1
- package/dist/accessors/index.d.ts +1 -1
- package/dist/browser.d.mts +11 -187
- package/dist/browser.d.ts +11 -187
- package/dist/browser.js +30 -6
- package/dist/browser.mjs +96 -72
- package/dist/chunk-2EH2MGBY.js +1799 -0
- package/dist/chunk-33IQXDOH.js +1 -0
- package/dist/chunk-5EK7K5X3.js +29 -0
- package/dist/chunk-5VF442RA.mjs +29 -0
- package/dist/chunk-626TXMVP.js +706 -0
- package/dist/chunk-63UT3IEY.mjs +2788 -0
- package/dist/chunk-6EKVRPFF.js +407 -0
- package/dist/chunk-776XPK66.js +45 -0
- package/dist/chunk-7D4MLQKO.js +69 -0
- package/dist/chunk-A2CGW2UF.js +25 -0
- package/dist/chunk-AOSK4RGV.mjs +45 -0
- package/dist/{chunk-FQ3NEYIV.js → chunk-ASPCIBWD.js} +127 -1249
- package/dist/chunk-BDHPMB7Q.mjs +61 -0
- package/dist/chunk-BHHOS2E6.mjs +407 -0
- package/dist/chunk-F2UCOAO6.mjs +155 -0
- package/dist/chunk-HP4DAUGT.js +2788 -0
- package/dist/chunk-JF5TM534.js +1065 -0
- package/dist/chunk-K6DSQPVF.mjs +706 -0
- package/dist/chunk-KJK2IGNN.mjs +0 -0
- package/dist/chunk-KYGLANYG.mjs +2354 -0
- package/dist/chunk-LFQXT7PV.mjs +69 -0
- package/dist/chunk-LS5SHP75.js +155 -0
- package/dist/chunk-MMIZQMIO.mjs +25 -0
- package/dist/chunk-NIUEAHPN.js +2354 -0
- package/dist/{chunk-EWLB5X64.js → chunk-PMPROVJW.js} +66 -770
- package/dist/chunk-QFYOH4DY.mjs +0 -0
- package/dist/chunk-QKUNJEVW.mjs +1401 -0
- package/dist/chunk-SBT2RMUW.mjs +1065 -0
- package/dist/chunk-TCXDBRRT.mjs +1799 -0
- package/dist/chunk-WNQIUYWY.js +61 -0
- package/dist/{chunk-I4X4GRMP.mjs → chunk-WS5LSW3S.mjs} +13 -1135
- package/dist/chunk-YKMNCYOD.js +1 -0
- package/dist/{chunk-UMEH3ENQ.mjs → chunk-ZRKJKEP7.mjs} +0 -704
- package/dist/chunk-ZSEJQPBO.js +1401 -0
- package/dist/core.d.mts +33 -0
- package/dist/core.d.ts +33 -0
- package/dist/core.js +524 -0
- package/dist/core.mjs +524 -0
- package/dist/file.d.mts +37 -0
- package/dist/file.d.ts +37 -0
- package/dist/file.js +14 -0
- package/dist/file.mjs +14 -0
- package/dist/index-C9lLZwol.d.mts +185 -0
- package/dist/index-DNA970t1.d.ts +185 -0
- package/dist/index.d.mts +12 -38
- package/dist/index.d.ts +12 -38
- package/dist/index.js +34 -49
- package/dist/index.mjs +101 -116
- package/dist/midi.d.mts +54 -0
- package/dist/midi.d.ts +54 -0
- package/dist/midi.js +10 -0
- package/dist/midi.mjs +10 -0
- package/dist/musicxml-DWPClEqa.d.ts +25 -0
- package/dist/musicxml-DzuFr2c3.d.mts +25 -0
- package/dist/musicxml-compressed-7NUEGLSF.mjs +8 -0
- package/dist/musicxml-compressed-7RL6QRF7.js +12 -0
- package/dist/musicxml-compressed-WPEIBOZ3.js +8 -0
- package/dist/musicxml-compressed-ZHZYFJ7H.mjs +12 -0
- package/dist/musicxml-compressed.d.mts +33 -0
- package/dist/musicxml-compressed.d.ts +33 -0
- package/dist/musicxml-compressed.js +18 -0
- package/dist/musicxml-compressed.mjs +18 -0
- package/dist/musicxml.d.mts +8 -0
- package/dist/musicxml.d.ts +8 -0
- package/dist/musicxml.js +14 -0
- package/dist/musicxml.mjs +14 -0
- package/dist/operations/index.d.mts +1234 -2
- package/dist/operations/index.d.ts +1234 -2
- package/dist/operations/index.js +7 -3
- package/dist/operations/index.mjs +6 -2
- package/dist/playback-timeline-CVRHsikj.d.mts +129 -0
- package/dist/playback-timeline-CmWA8YDy.d.ts +129 -0
- package/dist/query/index.d.mts +3 -128
- package/dist/query/index.d.ts +3 -128
- package/dist/query/index.js +4 -2
- package/dist/query/index.mjs +7 -5
- package/dist/{types-Cy0veafI.d.mts → types-B-RGHY0c.d.mts} +1 -1
- package/dist/{types-Cy0veafI.d.ts → types-B-RGHY0c.d.ts} +1 -1
- package/package.json +36 -2
- package/dist/chunk-T2USSS5E.mjs +0 -8939
- package/dist/chunk-UT7LQW6V.js +0 -8939
- package/dist/index-CbUtBHLD.d.ts +0 -1415
- package/dist/index-CuMPBK7U.d.mts +0 -1415
|
@@ -0,0 +1,407 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
var _chunkOEX7NVZNjs = require('./chunk-OEX7NVZN.js');
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
var _chunk626TXMVPjs = require('./chunk-626TXMVP.js');
|
|
12
|
+
|
|
13
|
+
// src/exporters/midi.ts
|
|
14
|
+
var DYNAMICS_VELOCITY = {
|
|
15
|
+
pppppp: 12,
|
|
16
|
+
ppppp: 20,
|
|
17
|
+
pppp: 25,
|
|
18
|
+
ppp: 30,
|
|
19
|
+
pp: 40,
|
|
20
|
+
p: 50,
|
|
21
|
+
mp: 60,
|
|
22
|
+
mf: 75,
|
|
23
|
+
f: 90,
|
|
24
|
+
ff: 105,
|
|
25
|
+
fff: 115,
|
|
26
|
+
ffff: 120,
|
|
27
|
+
fffff: 125,
|
|
28
|
+
ffffff: 127,
|
|
29
|
+
fp: 90,
|
|
30
|
+
// forte-piano: forte attack
|
|
31
|
+
n: 25,
|
|
32
|
+
// niente
|
|
33
|
+
pf: 70
|
|
34
|
+
};
|
|
35
|
+
var SF_ACCENT_MULTIPLIER = {
|
|
36
|
+
sf: 1.3,
|
|
37
|
+
sfz: 1.35,
|
|
38
|
+
sffz: 1.45,
|
|
39
|
+
fz: 1.3,
|
|
40
|
+
rf: 1.2,
|
|
41
|
+
rfz: 1.3,
|
|
42
|
+
sfp: 1.3,
|
|
43
|
+
sfpp: 1.3
|
|
44
|
+
};
|
|
45
|
+
var ARTICULATION_VELOCITY = {
|
|
46
|
+
"accent": 1.25,
|
|
47
|
+
"strong-accent": 1.35,
|
|
48
|
+
"marcato": 1.35,
|
|
49
|
+
"tenuto": 1.05,
|
|
50
|
+
"stress": 1.15,
|
|
51
|
+
"unstress": 0.85,
|
|
52
|
+
"soft-accent": 0.8
|
|
53
|
+
};
|
|
54
|
+
var GRACE_VELOCITY_MULTIPLIER = 0.85;
|
|
55
|
+
function clampVelocity(v) {
|
|
56
|
+
return Math.round(Math.min(127, Math.max(1, v)));
|
|
57
|
+
}
|
|
58
|
+
function articulationVelocityMultiplier(note) {
|
|
59
|
+
if (!note.notations) return 1;
|
|
60
|
+
let mult = 1;
|
|
61
|
+
for (const n of note.notations) {
|
|
62
|
+
if (n.type === "articulation") {
|
|
63
|
+
const m = ARTICULATION_VELOCITY[n.articulation];
|
|
64
|
+
if (m) mult *= m;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return mult;
|
|
68
|
+
}
|
|
69
|
+
function scheduleGraceNotes(graceNotes, targetTick, baseVelocity, chromaticTranspose, ticksPerQuarterNote, noteEvents) {
|
|
70
|
+
if (graceNotes.length === 0) return;
|
|
71
|
+
const graceUnit = Math.max(1, Math.round(ticksPerQuarterNote / 8));
|
|
72
|
+
const slots = [];
|
|
73
|
+
let slot = -1;
|
|
74
|
+
for (const g of graceNotes) {
|
|
75
|
+
if (!g.chord || slot < 0) slot++;
|
|
76
|
+
slots.push(slot);
|
|
77
|
+
}
|
|
78
|
+
const numSlots = slot + 1;
|
|
79
|
+
const velocity = clampVelocity(baseVelocity * GRACE_VELOCITY_MULTIPLIER);
|
|
80
|
+
for (let i = 0; i < graceNotes.length; i++) {
|
|
81
|
+
const g = graceNotes[i];
|
|
82
|
+
if (!g.pitch) continue;
|
|
83
|
+
const s = slots[i];
|
|
84
|
+
const onset = Math.max(0, targetTick - (numSlots - s) * graceUnit);
|
|
85
|
+
const off = Math.max(onset + 1, targetTick - (numSlots - s - 1) * graceUnit);
|
|
86
|
+
const midiNote = pitchToMidiNote(g.pitch, chromaticTranspose);
|
|
87
|
+
noteEvents.push({ tick: onset, type: "on", note: midiNote, velocity });
|
|
88
|
+
noteEvents.push({ tick: off, type: "off", note: midiNote, velocity: 0 });
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
function exportMidi(score, options = {}) {
|
|
92
|
+
const { tracks, ticksPerQuarterNote } = buildMidiTracks(score, options);
|
|
93
|
+
return buildMidiFile(tracks, ticksPerQuarterNote);
|
|
94
|
+
}
|
|
95
|
+
function exportMidiWithTimingMap(score, options = {}) {
|
|
96
|
+
const { tracks, ticksPerQuarterNote, defaultTempo, grid } = buildMidiTracks(score, options);
|
|
97
|
+
return {
|
|
98
|
+
midi: buildMidiFile(tracks, ticksPerQuarterNote),
|
|
99
|
+
sidecar: _chunk626TXMVPjs.buildTimingSidecar.call(void 0, grid, defaultTempo, ticksPerQuarterNote)
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
function buildMidiTracks(score, options) {
|
|
103
|
+
const ticksPerQuarterNote = _nullishCoalesce(options.ticksPerQuarterNote, () => ( 480));
|
|
104
|
+
const defaultTempo = _nullishCoalesce(options.defaultTempo, () => ( 120));
|
|
105
|
+
const defaultVelocity = _nullishCoalesce(options.defaultVelocity, () => ( 80));
|
|
106
|
+
const tracks = [];
|
|
107
|
+
const sequence = _chunk626TXMVPjs.generatePlaybackSequence.call(void 0, score);
|
|
108
|
+
const measureOrder = sequence.map((m) => m.measureIndex);
|
|
109
|
+
const grid = _chunk626TXMVPjs.buildGridTimeline.call(void 0, score, ticksPerQuarterNote, sequence, {
|
|
110
|
+
defaultTempo,
|
|
111
|
+
fermataHoldMultiplier: options.fermataHoldMultiplier,
|
|
112
|
+
caesuraSeconds: options.caesuraSeconds,
|
|
113
|
+
breathSeconds: options.breathSeconds,
|
|
114
|
+
tempoRampSteps: options.tempoRampSteps
|
|
115
|
+
});
|
|
116
|
+
tracks.push(createConductorTrack(score, defaultTempo, grid));
|
|
117
|
+
const scoreParts = score.partList.filter((entry) => entry.type === "score-part");
|
|
118
|
+
for (let partIndex = 0; partIndex < score.parts.length; partIndex++) {
|
|
119
|
+
const part = score.parts[partIndex];
|
|
120
|
+
const partEntry = scoreParts[partIndex];
|
|
121
|
+
let channel = partIndex % 16;
|
|
122
|
+
let program = 1;
|
|
123
|
+
if (partEntry && _optionalChain([partEntry, 'access', _ => _.midiInstruments, 'optionalAccess', _2 => _2[0]])) {
|
|
124
|
+
const midiInst = partEntry.midiInstruments[0];
|
|
125
|
+
if (midiInst.channel !== void 0) {
|
|
126
|
+
channel = Math.min(16, Math.max(1, midiInst.channel)) - 1;
|
|
127
|
+
}
|
|
128
|
+
program = Math.min(128, Math.max(1, _nullishCoalesce(midiInst.program, () => ( program))));
|
|
129
|
+
}
|
|
130
|
+
const trackData = createPartTrack(
|
|
131
|
+
part,
|
|
132
|
+
score,
|
|
133
|
+
channel,
|
|
134
|
+
program,
|
|
135
|
+
ticksPerQuarterNote,
|
|
136
|
+
defaultVelocity,
|
|
137
|
+
measureOrder
|
|
138
|
+
);
|
|
139
|
+
tracks.push(trackData);
|
|
140
|
+
}
|
|
141
|
+
return { tracks, ticksPerQuarterNote, defaultTempo, grid };
|
|
142
|
+
}
|
|
143
|
+
function pitchToMidiNote(pitch, chromaticTranspose = 0) {
|
|
144
|
+
const stepValues = {
|
|
145
|
+
"C": 0,
|
|
146
|
+
"D": 2,
|
|
147
|
+
"E": 4,
|
|
148
|
+
"F": 5,
|
|
149
|
+
"G": 7,
|
|
150
|
+
"A": 9,
|
|
151
|
+
"B": 11
|
|
152
|
+
};
|
|
153
|
+
const baseMidi = (pitch.octave + 1) * 12 + stepValues[pitch.step] + (_nullishCoalesce(pitch.alter, () => ( 0)));
|
|
154
|
+
return baseMidi + chromaticTranspose;
|
|
155
|
+
}
|
|
156
|
+
function createConductorTrack(score, defaultTempo, grid) {
|
|
157
|
+
const metaEvents = [];
|
|
158
|
+
const tempoBytes = (bpm) => {
|
|
159
|
+
const us = _chunk626TXMVPjs.bpmToUsPerQuarter.call(void 0, bpm);
|
|
160
|
+
return [255, 81, 3, us >> 16 & 255, us >> 8 & 255, us & 255];
|
|
161
|
+
};
|
|
162
|
+
const tempoEvents = [...grid.tempoEvents].sort((a, b) => a.tick - b.tick);
|
|
163
|
+
const startBpm = tempoEvents.length > 0 && tempoEvents[0].tick === 0 ? tempoEvents[0].bpm : defaultTempo;
|
|
164
|
+
metaEvents.push({ tick: 0, order: 0, bytes: tempoBytes(startBpm) });
|
|
165
|
+
let lastBpm = startBpm;
|
|
166
|
+
for (const ev of tempoEvents) {
|
|
167
|
+
if (ev.tick === 0) continue;
|
|
168
|
+
if (ev.bpm === lastBpm) continue;
|
|
169
|
+
metaEvents.push({ tick: ev.tick, order: 0, bytes: tempoBytes(ev.bpm) });
|
|
170
|
+
lastBpm = ev.bpm;
|
|
171
|
+
}
|
|
172
|
+
const part = score.parts.length > 0 ? score.parts[0] : void 0;
|
|
173
|
+
if (part) {
|
|
174
|
+
let lastSig = null;
|
|
175
|
+
for (const m of grid.measures) {
|
|
176
|
+
const time = _optionalChain([part, 'access', _3 => _3.measures, 'access', _4 => _4[m.measureIndex], 'optionalAccess', _5 => _5.attributes, 'optionalAccess', _6 => _6.time]);
|
|
177
|
+
if (!time) continue;
|
|
178
|
+
const numerator = parseInt(time.beats, 10) || 4;
|
|
179
|
+
const denominator = Math.log2(time.beatType);
|
|
180
|
+
const sig = `${numerator}/${denominator}`;
|
|
181
|
+
if (sig === lastSig) continue;
|
|
182
|
+
lastSig = sig;
|
|
183
|
+
metaEvents.push({
|
|
184
|
+
tick: m.startTick,
|
|
185
|
+
order: 1,
|
|
186
|
+
bytes: [255, 88, 4, numerator, denominator, 24, 8]
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
metaEvents.sort((a, b) => a.tick - b.tick || a.order - b.order);
|
|
191
|
+
const events = [];
|
|
192
|
+
let lastTick = 0;
|
|
193
|
+
for (const ev of metaEvents) {
|
|
194
|
+
events.push(...writeVariableLength(ev.tick - lastTick), ...ev.bytes);
|
|
195
|
+
lastTick = ev.tick;
|
|
196
|
+
}
|
|
197
|
+
events.push(
|
|
198
|
+
...writeVariableLength(Math.max(0, grid.totalTicks - lastTick)),
|
|
199
|
+
255,
|
|
200
|
+
47,
|
|
201
|
+
0
|
|
202
|
+
);
|
|
203
|
+
return new Uint8Array(events);
|
|
204
|
+
}
|
|
205
|
+
function createPartTrack(part, _score, channel, program, ticksPerQuarterNote, defaultVelocity, measureOrder) {
|
|
206
|
+
const events = [];
|
|
207
|
+
events.push(
|
|
208
|
+
...writeVariableLength(0),
|
|
209
|
+
192 | channel & 15,
|
|
210
|
+
program - 1 & 127
|
|
211
|
+
// MIDI programs are 0-indexed
|
|
212
|
+
);
|
|
213
|
+
const noteEvents = [];
|
|
214
|
+
let currentTick = 0;
|
|
215
|
+
let divisions = 1;
|
|
216
|
+
let chromaticTranspose = 0;
|
|
217
|
+
let currentVelocity = defaultVelocity;
|
|
218
|
+
let pendingAccent = 1;
|
|
219
|
+
let accentBound = false;
|
|
220
|
+
let pendingGrace = [];
|
|
221
|
+
for (const measureIndex of measureOrder) {
|
|
222
|
+
const measure = part.measures[measureIndex];
|
|
223
|
+
if (!measure) continue;
|
|
224
|
+
if (_optionalChain([measure, 'access', _7 => _7.attributes, 'optionalAccess', _8 => _8.divisions])) {
|
|
225
|
+
divisions = measure.attributes.divisions;
|
|
226
|
+
}
|
|
227
|
+
if (_optionalChain([measure, 'access', _9 => _9.attributes, 'optionalAccess', _10 => _10.transpose])) {
|
|
228
|
+
chromaticTranspose = measure.attributes.transpose.chromatic;
|
|
229
|
+
}
|
|
230
|
+
const measureStartTick = currentTick;
|
|
231
|
+
let position = 0;
|
|
232
|
+
let chordBasePosition = 0;
|
|
233
|
+
let maxPosition = 0;
|
|
234
|
+
for (const entry of measure.entries) {
|
|
235
|
+
if (entry.type === "note") {
|
|
236
|
+
const note = entry;
|
|
237
|
+
if (note.grace) {
|
|
238
|
+
if (note.pitch) pendingGrace.push(note);
|
|
239
|
+
continue;
|
|
240
|
+
}
|
|
241
|
+
if (!note.chord) {
|
|
242
|
+
if (accentBound) {
|
|
243
|
+
pendingAccent = 1;
|
|
244
|
+
accentBound = false;
|
|
245
|
+
}
|
|
246
|
+
if (pendingAccent !== 1) accentBound = true;
|
|
247
|
+
}
|
|
248
|
+
if (note.pitch) {
|
|
249
|
+
const midiNote = pitchToMidiNote(note.pitch, chromaticTranspose);
|
|
250
|
+
const notePosition = note.chord ? chordBasePosition : position;
|
|
251
|
+
const startTick = measureStartTick + Math.round(notePosition * ticksPerQuarterNote / divisions);
|
|
252
|
+
const durationTicks = Math.round(note.duration * ticksPerQuarterNote / divisions);
|
|
253
|
+
if (!note.chord && pendingGrace.length > 0) {
|
|
254
|
+
scheduleGraceNotes(pendingGrace, startTick, currentVelocity, chromaticTranspose, ticksPerQuarterNote, noteEvents);
|
|
255
|
+
pendingGrace = [];
|
|
256
|
+
}
|
|
257
|
+
const velocity = clampVelocity(currentVelocity * pendingAccent * articulationVelocityMultiplier(note));
|
|
258
|
+
const isTieStop = _chunkOEX7NVZNjs.hasTieStop.call(void 0, note);
|
|
259
|
+
const isTieStart = _chunkOEX7NVZNjs.hasTieStart.call(void 0, note);
|
|
260
|
+
if (!isTieStop) {
|
|
261
|
+
noteEvents.push({ tick: startTick, type: "on", note: midiNote, velocity });
|
|
262
|
+
}
|
|
263
|
+
if (!isTieStart) {
|
|
264
|
+
noteEvents.push({ tick: startTick + durationTicks, type: "off", note: midiNote, velocity: 0 });
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
if (!note.chord) {
|
|
268
|
+
chordBasePosition = position;
|
|
269
|
+
position += note.duration;
|
|
270
|
+
if (position > maxPosition) {
|
|
271
|
+
maxPosition = position;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
} else if (entry.type === "direction") {
|
|
275
|
+
for (const dt of entry.directionTypes) {
|
|
276
|
+
if (dt.kind === "dynamics" && dt.value) {
|
|
277
|
+
const abs = DYNAMICS_VELOCITY[dt.value];
|
|
278
|
+
if (abs !== void 0) {
|
|
279
|
+
currentVelocity = abs;
|
|
280
|
+
} else {
|
|
281
|
+
const accent = SF_ACCENT_MULTIPLIER[dt.value];
|
|
282
|
+
if (accent !== void 0) {
|
|
283
|
+
pendingAccent = accent;
|
|
284
|
+
accentBound = false;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
} else if (entry.type === "backup") {
|
|
290
|
+
position -= entry.duration;
|
|
291
|
+
} else if (entry.type === "forward") {
|
|
292
|
+
position += entry.duration;
|
|
293
|
+
if (position > maxPosition) {
|
|
294
|
+
maxPosition = position;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
currentTick = _chunk626TXMVPjs.measureEndTick.call(void 0,
|
|
299
|
+
measure,
|
|
300
|
+
part,
|
|
301
|
+
divisions,
|
|
302
|
+
measureStartTick,
|
|
303
|
+
maxPosition,
|
|
304
|
+
ticksPerQuarterNote
|
|
305
|
+
);
|
|
306
|
+
}
|
|
307
|
+
if (pendingGrace.length > 0) {
|
|
308
|
+
scheduleGraceNotes(pendingGrace, currentTick, currentVelocity, chromaticTranspose, ticksPerQuarterNote, noteEvents);
|
|
309
|
+
pendingGrace = [];
|
|
310
|
+
}
|
|
311
|
+
const onCounts = /* @__PURE__ */ new Map();
|
|
312
|
+
const offCounts = /* @__PURE__ */ new Map();
|
|
313
|
+
for (const e of noteEvents) {
|
|
314
|
+
const map = e.type === "on" ? onCounts : offCounts;
|
|
315
|
+
map.set(e.note, (_nullishCoalesce(map.get(e.note), () => ( 0))) + 1);
|
|
316
|
+
}
|
|
317
|
+
for (const [note, onCount] of onCounts) {
|
|
318
|
+
const offCount = _nullishCoalesce(offCounts.get(note), () => ( 0));
|
|
319
|
+
for (let i = 0; i < onCount - offCount; i++) {
|
|
320
|
+
noteEvents.push({ tick: currentTick, type: "off", note, velocity: 0 });
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
noteEvents.sort((a, b) => {
|
|
324
|
+
if (a.tick !== b.tick) return a.tick - b.tick;
|
|
325
|
+
if (a.type !== b.type) return a.type === "off" ? -1 : 1;
|
|
326
|
+
return a.note - b.note;
|
|
327
|
+
});
|
|
328
|
+
let lastTick = 0;
|
|
329
|
+
for (const event of noteEvents) {
|
|
330
|
+
const deltaTick = event.tick - lastTick;
|
|
331
|
+
lastTick = event.tick;
|
|
332
|
+
if (event.type === "on") {
|
|
333
|
+
events.push(
|
|
334
|
+
...writeVariableLength(deltaTick),
|
|
335
|
+
144 | channel & 15,
|
|
336
|
+
event.note & 127,
|
|
337
|
+
event.velocity & 127
|
|
338
|
+
);
|
|
339
|
+
} else {
|
|
340
|
+
events.push(
|
|
341
|
+
...writeVariableLength(deltaTick),
|
|
342
|
+
128 | channel & 15,
|
|
343
|
+
event.note & 127,
|
|
344
|
+
0
|
|
345
|
+
);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
events.push(...writeVariableLength(0), 255, 47, 0);
|
|
349
|
+
return new Uint8Array(events);
|
|
350
|
+
}
|
|
351
|
+
function writeVariableLength(value) {
|
|
352
|
+
if (value < 0) value = 0;
|
|
353
|
+
const bytes = [];
|
|
354
|
+
bytes.unshift(value & 127);
|
|
355
|
+
value >>= 7;
|
|
356
|
+
while (value > 0) {
|
|
357
|
+
bytes.unshift(value & 127 | 128);
|
|
358
|
+
value >>= 7;
|
|
359
|
+
}
|
|
360
|
+
return bytes;
|
|
361
|
+
}
|
|
362
|
+
function writeUint32BE(value) {
|
|
363
|
+
return [
|
|
364
|
+
value >> 24 & 255,
|
|
365
|
+
value >> 16 & 255,
|
|
366
|
+
value >> 8 & 255,
|
|
367
|
+
value & 255
|
|
368
|
+
];
|
|
369
|
+
}
|
|
370
|
+
function writeUint16BE(value) {
|
|
371
|
+
return [
|
|
372
|
+
value >> 8 & 255,
|
|
373
|
+
value & 255
|
|
374
|
+
];
|
|
375
|
+
}
|
|
376
|
+
function buildMidiFile(tracks, ticksPerQuarterNote) {
|
|
377
|
+
const header = Uint8Array.from([
|
|
378
|
+
77,
|
|
379
|
+
84,
|
|
380
|
+
104,
|
|
381
|
+
100,
|
|
382
|
+
...writeUint32BE(6),
|
|
383
|
+
...writeUint16BE(1),
|
|
384
|
+
...writeUint16BE(tracks.length),
|
|
385
|
+
...writeUint16BE(ticksPerQuarterNote)
|
|
386
|
+
]);
|
|
387
|
+
let total = header.length;
|
|
388
|
+
for (const track of tracks) total += 8 + track.length;
|
|
389
|
+
const out = new Uint8Array(total);
|
|
390
|
+
let offset = 0;
|
|
391
|
+
out.set(header, offset);
|
|
392
|
+
offset += header.length;
|
|
393
|
+
for (const track of tracks) {
|
|
394
|
+
out.set([77, 84, 114, 107], offset);
|
|
395
|
+
offset += 4;
|
|
396
|
+
out.set(writeUint32BE(track.length), offset);
|
|
397
|
+
offset += 4;
|
|
398
|
+
out.set(track, offset);
|
|
399
|
+
offset += track.length;
|
|
400
|
+
}
|
|
401
|
+
return out;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
|
|
405
|
+
|
|
406
|
+
|
|
407
|
+
exports.exportMidi = exportMidi; exports.exportMidiWithTimingMap = exportMidiWithTimingMap;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } }// src/beams.ts
|
|
2
|
+
var BEAM_LEVELS = {
|
|
3
|
+
eighth: 1,
|
|
4
|
+
"16th": 2,
|
|
5
|
+
"32nd": 3,
|
|
6
|
+
"64th": 4,
|
|
7
|
+
"128th": 5,
|
|
8
|
+
"256th": 6,
|
|
9
|
+
"512th": 7,
|
|
10
|
+
"1024th": 8
|
|
11
|
+
};
|
|
12
|
+
function beamLevel(note) {
|
|
13
|
+
return note.rest || !note.noteType ? 0 : _nullishCoalesce(BEAM_LEVELS[note.noteType], () => ( 0));
|
|
14
|
+
}
|
|
15
|
+
function applyBeamGroup(group) {
|
|
16
|
+
const levels = group.map(beamLevel);
|
|
17
|
+
const beams = group.map(() => []);
|
|
18
|
+
const maxLevel = Math.max(...levels);
|
|
19
|
+
for (let lv = 1; lv <= maxLevel; lv++) {
|
|
20
|
+
for (let i = 0; i < group.length; ) {
|
|
21
|
+
if (levels[i] < lv) {
|
|
22
|
+
i++;
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
let j = i;
|
|
26
|
+
while (j + 1 < group.length && levels[j + 1] >= lv) j++;
|
|
27
|
+
if (i === j) {
|
|
28
|
+
beams[i].push({ number: lv, type: i === group.length - 1 ? "backward hook" : "forward hook" });
|
|
29
|
+
} else {
|
|
30
|
+
for (let k = i; k <= j; k++) {
|
|
31
|
+
beams[k].push({ number: lv, type: k === i ? "begin" : k === j ? "end" : "continue" });
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
i = j + 1;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
group.forEach((n, i) => {
|
|
38
|
+
n.beam = beams[i];
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
exports.beamLevel = beamLevel; exports.applyBeamGroup = applyBeamGroup;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true});
|
|
2
|
+
|
|
3
|
+
var _chunkHP4DAUGTjs = require('./chunk-HP4DAUGT.js');
|
|
4
|
+
|
|
5
|
+
// src/importers/musicxml-compressed.ts
|
|
6
|
+
var _fflate = require('fflate');
|
|
7
|
+
function parseCompressed(data) {
|
|
8
|
+
const containerPath = "META-INF/container.xml";
|
|
9
|
+
const xmlFiles = [];
|
|
10
|
+
const files = _fflate.unzipSync.call(void 0, data, {
|
|
11
|
+
filter: ({ name }) => {
|
|
12
|
+
if (name.endsWith(".xml") && !name.startsWith("META-INF")) {
|
|
13
|
+
xmlFiles.push(name);
|
|
14
|
+
}
|
|
15
|
+
return name === containerPath;
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
const containerData = files[containerPath];
|
|
19
|
+
let rootFilePath;
|
|
20
|
+
if (containerData) {
|
|
21
|
+
const containerXml = _fflate.strFromU8.call(void 0, containerData);
|
|
22
|
+
const rootfileMatch = containerXml.match(/full-path="([^"]+)"/);
|
|
23
|
+
if (rootfileMatch) {
|
|
24
|
+
rootFilePath = rootfileMatch[1];
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
if (!rootFilePath) {
|
|
28
|
+
if (xmlFiles.length === 1) {
|
|
29
|
+
rootFilePath = xmlFiles[0];
|
|
30
|
+
} else {
|
|
31
|
+
const commonNames = ["score.xml", "musicxml.xml"];
|
|
32
|
+
for (const name of commonNames) {
|
|
33
|
+
if (xmlFiles.includes(name)) {
|
|
34
|
+
rootFilePath = name;
|
|
35
|
+
break;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
if (!rootFilePath) {
|
|
41
|
+
throw new Error("Could not find MusicXML file in compressed archive");
|
|
42
|
+
}
|
|
43
|
+
const xmlData = _fflate.unzipSync.call(void 0, data, {
|
|
44
|
+
filter: ({ name }) => name === rootFilePath
|
|
45
|
+
})[rootFilePath];
|
|
46
|
+
if (!xmlData) {
|
|
47
|
+
throw new Error("Could not find MusicXML file in compressed archive");
|
|
48
|
+
}
|
|
49
|
+
const xmlString = _fflate.strFromU8.call(void 0, xmlData);
|
|
50
|
+
return _chunkHP4DAUGTjs.parse.call(void 0, xmlString);
|
|
51
|
+
}
|
|
52
|
+
function isCompressed(data) {
|
|
53
|
+
return data.length >= 2 && data[0] === 80 && data[1] === 75;
|
|
54
|
+
}
|
|
55
|
+
function parseAuto(data) {
|
|
56
|
+
if (typeof data === "string") {
|
|
57
|
+
return _chunkHP4DAUGTjs.parse.call(void 0, data);
|
|
58
|
+
}
|
|
59
|
+
if (isCompressed(data)) {
|
|
60
|
+
return parseCompressed(data);
|
|
61
|
+
}
|
|
62
|
+
return _chunkHP4DAUGTjs.parse.call(void 0, data);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
exports.parseCompressed = parseCompressed; exports.isCompressed = isCompressed; exports.parseAuto = parseAuto;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true});
|
|
2
|
+
|
|
3
|
+
var _chunk2EH2MGBYjs = require('./chunk-2EH2MGBY.js');
|
|
4
|
+
|
|
5
|
+
// src/exporters/musicxml-compressed.ts
|
|
6
|
+
var _fflate = require('fflate');
|
|
7
|
+
function serializeCompressed(score, options = {}) {
|
|
8
|
+
const xmlString = _chunk2EH2MGBYjs.serialize.call(void 0, score, options);
|
|
9
|
+
const rootFileName = "score.xml";
|
|
10
|
+
const containerXml = `<?xml version="1.0" encoding="UTF-8"?>
|
|
11
|
+
<container>
|
|
12
|
+
<rootfiles>
|
|
13
|
+
<rootfile full-path="${rootFileName}"/>
|
|
14
|
+
</rootfiles>
|
|
15
|
+
</container>`;
|
|
16
|
+
const files = {
|
|
17
|
+
"META-INF/container.xml": _fflate.strToU8.call(void 0, containerXml),
|
|
18
|
+
[rootFileName]: _fflate.strToU8.call(void 0, xmlString)
|
|
19
|
+
};
|
|
20
|
+
return _fflate.zipSync.call(void 0, files, { level: 6 });
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
exports.serializeCompressed = serializeCompressed;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// src/beams.ts
|
|
2
|
+
var BEAM_LEVELS = {
|
|
3
|
+
eighth: 1,
|
|
4
|
+
"16th": 2,
|
|
5
|
+
"32nd": 3,
|
|
6
|
+
"64th": 4,
|
|
7
|
+
"128th": 5,
|
|
8
|
+
"256th": 6,
|
|
9
|
+
"512th": 7,
|
|
10
|
+
"1024th": 8
|
|
11
|
+
};
|
|
12
|
+
function beamLevel(note) {
|
|
13
|
+
return note.rest || !note.noteType ? 0 : BEAM_LEVELS[note.noteType] ?? 0;
|
|
14
|
+
}
|
|
15
|
+
function applyBeamGroup(group) {
|
|
16
|
+
const levels = group.map(beamLevel);
|
|
17
|
+
const beams = group.map(() => []);
|
|
18
|
+
const maxLevel = Math.max(...levels);
|
|
19
|
+
for (let lv = 1; lv <= maxLevel; lv++) {
|
|
20
|
+
for (let i = 0; i < group.length; ) {
|
|
21
|
+
if (levels[i] < lv) {
|
|
22
|
+
i++;
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
let j = i;
|
|
26
|
+
while (j + 1 < group.length && levels[j + 1] >= lv) j++;
|
|
27
|
+
if (i === j) {
|
|
28
|
+
beams[i].push({ number: lv, type: i === group.length - 1 ? "backward hook" : "forward hook" });
|
|
29
|
+
} else {
|
|
30
|
+
for (let k = i; k <= j; k++) {
|
|
31
|
+
beams[k].push({ number: lv, type: k === i ? "begin" : k === j ? "end" : "continue" });
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
i = j + 1;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
group.forEach((n, i) => {
|
|
38
|
+
n.beam = beams[i];
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export {
|
|
43
|
+
beamLevel,
|
|
44
|
+
applyBeamGroup
|
|
45
|
+
};
|