@k-l-lambda/lilylet 0.1.63 → 0.1.64
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/lib/lilylet/meiEncoder.js +58 -40
- package/lib/source/abc/abc.d.ts +102 -0
- package/lib/source/abc/abc.js +25 -0
- package/lib/source/abc/parser.d.ts +3 -0
- package/lib/source/abc/parser.js +6 -0
- package/lib/source/lilylet/abcDecoder.d.ts +25 -0
- package/lib/source/lilylet/abcDecoder.js +1035 -0
- package/lib/source/lilylet/index.d.ts +10 -0
- package/lib/source/lilylet/index.js +10 -0
- package/lib/source/lilylet/lilypondDecoder.d.ts +29 -0
- package/lib/source/lilylet/lilypondDecoder.js +1223 -0
- package/lib/source/lilylet/lilypondEncoder.d.ts +34 -0
- package/lib/source/lilylet/lilypondEncoder.js +893 -0
- package/lib/source/lilylet/meiEncoder.d.ts +8 -0
- package/lib/source/lilylet/meiEncoder.js +1985 -0
- package/lib/source/lilylet/musicXmlDecoder.d.ts +20 -0
- package/lib/source/lilylet/musicXmlDecoder.js +1195 -0
- package/lib/source/lilylet/musicXmlEncoder.d.ts +15 -0
- package/lib/source/lilylet/musicXmlEncoder.js +701 -0
- package/lib/source/lilylet/musicXmlTypes.d.ts +199 -0
- package/lib/source/lilylet/musicXmlTypes.js +7 -0
- package/lib/source/lilylet/musicXmlUtils.d.ts +92 -0
- package/lib/source/lilylet/musicXmlUtils.js +469 -0
- package/lib/source/lilylet/parser.d.ts +14 -0
- package/lib/source/lilylet/parser.js +161 -0
- package/lib/source/lilylet/serializer.d.ts +11 -0
- package/lib/source/lilylet/serializer.js +791 -0
- package/lib/source/lilylet/types.d.ts +253 -0
- package/lib/source/lilylet/types.js +100 -0
- package/lib/tests/abc-abcjs-parse.d.ts +8 -0
- package/lib/tests/abc-abcjs-parse.js +90 -0
- package/lib/tests/abc-abcjs-svg.d.ts +1 -0
- package/lib/tests/abc-abcjs-svg.js +143 -0
- package/lib/tests/abc-decoder.d.ts +1 -0
- package/lib/tests/abc-decoder.js +67 -0
- package/lib/tests/abc-mei-compare.d.ts +1 -0
- package/lib/tests/abc-mei-compare.js +525 -0
- package/lib/tests/auto-beam.d.ts +9 -0
- package/lib/tests/auto-beam.js +151 -0
- package/lib/tests/computeMeiHashes.d.ts +1 -0
- package/lib/tests/computeMeiHashes.js +87 -0
- package/lib/tests/encoder-mutation.d.ts +9 -0
- package/lib/tests/encoder-mutation.js +110 -0
- package/lib/tests/gpt-review-issues.d.ts +5 -0
- package/lib/tests/gpt-review-issues.js +255 -0
- package/lib/tests/json-to-lyl.d.ts +1 -0
- package/lib/tests/json-to-lyl.js +18 -0
- package/lib/tests/lilypond-roundtrip.d.ts +7 -0
- package/lib/tests/lilypond-roundtrip.js +558 -0
- package/lib/tests/lilypondDecoder.d.ts +6 -0
- package/lib/tests/lilypondDecoder.js +95 -0
- package/lib/tests/ly-to-lyl.d.ts +1 -0
- package/lib/tests/ly-to-lyl.js +12 -0
- package/lib/tests/mei.d.ts +1 -0
- package/lib/tests/mei.js +278 -0
- package/lib/tests/musicxml-decoder.d.ts +4 -0
- package/lib/tests/musicxml-decoder.js +61 -0
- package/lib/tests/musicxml-detail.d.ts +4 -0
- package/lib/tests/musicxml-detail.js +85 -0
- package/lib/tests/musicxml-fprod.d.ts +9 -0
- package/lib/tests/musicxml-fprod.js +153 -0
- package/lib/tests/musicxml-roundtrip.d.ts +7 -0
- package/lib/tests/musicxml-roundtrip.js +296 -0
- package/lib/tests/musicxml-to-mei.d.ts +6 -0
- package/lib/tests/musicxml-to-mei.js +115 -0
- package/lib/tests/parser.d.ts +1 -0
- package/lib/tests/parser.js +17 -0
- package/lib/tests/render-k283.d.ts +1 -0
- package/lib/tests/render-k283.js +33 -0
- package/lib/tests/render-lyl.d.ts +1 -0
- package/lib/tests/render-lyl.js +35 -0
- package/lib/tests/unit/afterGraceInsideTuplet.test.d.ts +23 -0
- package/lib/tests/unit/afterGraceInsideTuplet.test.js +186 -0
- package/lib/tests/unit/changeStaffBeforeTuplet.test.d.ts +21 -0
- package/lib/tests/unit/changeStaffBeforeTuplet.test.js +356 -0
- package/lib/tests/unit/crossStaffDecoder.test.d.ts +15 -0
- package/lib/tests/unit/crossStaffDecoder.test.js +147 -0
- package/lib/tests/unit/crossStaffEdgeCases.test.d.ts +1 -0
- package/lib/tests/unit/crossStaffEdgeCases.test.js +209 -0
- package/lib/tests/unit/crossStaffMultiMeasure.test.d.ts +15 -0
- package/lib/tests/unit/crossStaffMultiMeasure.test.js +231 -0
- package/lib/tests/unit/fullMeasureRestDecoder.test.d.ts +11 -0
- package/lib/tests/unit/fullMeasureRestDecoder.test.js +154 -0
- package/lib/tests/unit/gptReviewIssues.test.d.ts +8 -0
- package/lib/tests/unit/gptReviewIssues.test.js +240 -0
- package/lib/tests/unit/parallelMusicDecoder.test.d.ts +13 -0
- package/lib/tests/unit/parallelMusicDecoder.test.js +261 -0
- package/lib/tests/unit/partialWarning.test.d.ts +4 -0
- package/lib/tests/unit/partialWarning.test.js +65 -0
- package/lib/tests/unit/serializerRoundTrip.test.d.ts +8 -0
- package/lib/tests/unit/serializerRoundTrip.test.js +263 -0
- package/lib/tests/unit/staffInsideTuplet.test.d.ts +25 -0
- package/lib/tests/unit/staffInsideTuplet.test.js +133 -0
- package/lib/tests/unit/timesFirstNoteEscape.test.d.ts +16 -0
- package/lib/tests/unit/timesFirstNoteEscape.test.js +152 -0
- package/lib/tests/unit/tupletWithBaseDuration.test.d.ts +17 -0
- package/lib/tests/unit/tupletWithBaseDuration.test.js +139 -0
- package/lib/tests/unit/voiceStaffParsing.test.d.ts +13 -0
- package/lib/tests/unit/voiceStaffParsing.test.js +118 -0
- package/package.json +1 -1
- package/source/lilylet/meiEncoder.ts +65 -40
|
@@ -741,7 +741,8 @@ const encodeLayer = (voice, layerN, indent, initialTiePitches = [], keyFifths =
|
|
|
741
741
|
const pedals = [];
|
|
742
742
|
// Track octave spans - initialize from previous measure if continuing
|
|
743
743
|
const octaves = [];
|
|
744
|
-
|
|
744
|
+
const octaveEndReplacements = {};
|
|
745
|
+
let currentOctave = initialOctave ? { dis: initialOctave.dis, disPlace: initialOctave.disPlace, startId: initialOctave.startId, continued: initialOctave.continued, emitted: initialOctave.emitted, endToken: initialOctave.endToken, endFallbackId: initialOctave.endFallbackId } : null;
|
|
745
746
|
let pendingOttava = null; // Track ottava to apply to next note
|
|
746
747
|
let currentOttavaShift = initialOctave?.shift || 0; // Track current ottava shift for pitch encoding
|
|
747
748
|
let lastNoteId = null; // Track last note id for ending ottava spans
|
|
@@ -833,6 +834,9 @@ const encodeLayer = (voice, layerN, indent, initialTiePitches = [], keyFifths =
|
|
|
833
834
|
const result = noteEventToMEI(effectiveNoteEvent, currentIndent, voice.staff, tieEnd, currentStemDirection, keyFifths, currentOttavaShift, measureAccidentals);
|
|
834
835
|
xml += result.xml;
|
|
835
836
|
lastNoteId = result.elementId;
|
|
837
|
+
if (currentOctave?.endToken) {
|
|
838
|
+
octaveEndReplacements[currentOctave.endToken] = result.elementId;
|
|
839
|
+
}
|
|
836
840
|
// Flush any pending markups onto this note
|
|
837
841
|
flushPendingMarkups(result.elementId);
|
|
838
842
|
// If there's a pending ottava, start the span on this note
|
|
@@ -841,9 +845,14 @@ const encodeLayer = (voice, layerN, indent, initialTiePitches = [], keyFifths =
|
|
|
841
845
|
const disPlace = pendingOttava > 0 ? 'above' : 'below';
|
|
842
846
|
// Close existing span first if it has a different value
|
|
843
847
|
if (currentOctave && (currentOctave.dis !== dis || currentOctave.disPlace !== disPlace)) {
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
848
|
+
if (lastNoteId) {
|
|
849
|
+
octaves.push({
|
|
850
|
+
dis: currentOctave.dis,
|
|
851
|
+
disPlace: currentOctave.disPlace,
|
|
852
|
+
startId: currentOctave.startId,
|
|
853
|
+
endId: lastNoteId,
|
|
854
|
+
});
|
|
855
|
+
}
|
|
847
856
|
currentOctave = null;
|
|
848
857
|
}
|
|
849
858
|
// Start new span if we don't already have one with the same value
|
|
@@ -852,6 +861,12 @@ const encodeLayer = (voice, layerN, indent, initialTiePitches = [], keyFifths =
|
|
|
852
861
|
}
|
|
853
862
|
pendingOttava = null;
|
|
854
863
|
}
|
|
864
|
+
else if (currentOctave?.continued) {
|
|
865
|
+
if (!currentOctave.endToken) {
|
|
866
|
+
currentOctave.startId = result.elementId;
|
|
867
|
+
}
|
|
868
|
+
currentOctave.continued = false;
|
|
869
|
+
}
|
|
855
870
|
// Update pending tie pitches
|
|
856
871
|
if (result.hasTieStart) {
|
|
857
872
|
pendingTiePitches = result.pitches;
|
|
@@ -997,12 +1012,14 @@ const encodeLayer = (voice, layerN, indent, initialTiePitches = [], keyFifths =
|
|
|
997
1012
|
if (ctx.ottava === 0) {
|
|
998
1013
|
// End current ottava span
|
|
999
1014
|
if (currentOctave && lastNoteId) {
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1015
|
+
if (!currentOctave.emitted) {
|
|
1016
|
+
octaves.push({
|
|
1017
|
+
dis: currentOctave.dis,
|
|
1018
|
+
disPlace: currentOctave.disPlace,
|
|
1019
|
+
startId: currentOctave.startId,
|
|
1020
|
+
endId: lastNoteId,
|
|
1021
|
+
});
|
|
1022
|
+
}
|
|
1006
1023
|
currentOctave = null;
|
|
1007
1024
|
ottavaExplicitlyClosed = true; // Mark that we explicitly closed the span
|
|
1008
1025
|
}
|
|
@@ -1015,7 +1032,7 @@ const encodeLayer = (voice, layerN, indent, initialTiePitches = [], keyFifths =
|
|
|
1015
1032
|
const dis = Math.abs(ctx.ottava) === 2 ? 15 : 8;
|
|
1016
1033
|
const disPlace = ctx.ottava > 0 ? 'above' : 'below';
|
|
1017
1034
|
if (currentOctave && currentOctave.dis === dis && currentOctave.disPlace === disPlace) {
|
|
1018
|
-
// Continuation - restore the shift
|
|
1035
|
+
// Continuation - restore the shift and let the existing 8va line reach this measure's first note
|
|
1019
1036
|
currentOttavaShift = ctx.ottava;
|
|
1020
1037
|
}
|
|
1021
1038
|
else {
|
|
@@ -1091,13 +1108,24 @@ const encodeLayer = (voice, layerN, indent, initialTiePitches = [], keyFifths =
|
|
|
1091
1108
|
if (beamElementOpen) {
|
|
1092
1109
|
xml += `${baseIndent}</beam>\n`;
|
|
1093
1110
|
}
|
|
1094
|
-
//
|
|
1095
|
-
|
|
1111
|
+
// Emit one visible octave span for a continuing ottava; a repeated same-value command can extend it to the next measure.
|
|
1112
|
+
if (currentOctave && lastNoteId && !currentOctave.emitted) {
|
|
1113
|
+
const endToken = `__OTTAVA_END_${generateId('octaveEnd')}__`;
|
|
1114
|
+
octaves.push({
|
|
1115
|
+
dis: currentOctave.dis,
|
|
1116
|
+
disPlace: currentOctave.disPlace,
|
|
1117
|
+
startId: currentOctave.startId,
|
|
1118
|
+
endId: endToken,
|
|
1119
|
+
});
|
|
1120
|
+
currentOctave.emitted = true;
|
|
1121
|
+
currentOctave.endToken = endToken;
|
|
1122
|
+
currentOctave.endFallbackId = lastNoteId;
|
|
1123
|
+
}
|
|
1096
1124
|
const pendingOctave = currentOctave
|
|
1097
|
-
? { dis: currentOctave.dis, disPlace: currentOctave.disPlace, startId: currentOctave.startId, shift: currentOttavaShift }
|
|
1125
|
+
? { dis: currentOctave.dis, disPlace: currentOctave.disPlace, startId: currentOctave.startId, shift: currentOttavaShift, continued: true, emitted: currentOctave.emitted, endToken: currentOctave.endToken, endFallbackId: currentOctave.endFallbackId }
|
|
1098
1126
|
: null;
|
|
1099
1127
|
xml += `${indent}</layer>\n`;
|
|
1100
|
-
return { xml, hairpins, pedals, octaves, slurs, arpeggios, fermatas, trills, mordents, turns, dynamics, fingerings, navigations, harmonies, barlines, markups, pendingTiePitches, pendingSlur: currentSlur?.startId || null, pendingHairpin: currentHairpin, pendingOctave, ottavaExplicitlyClosed, endingClef: currentClef, lastNoteId, currentOttavaShift };
|
|
1128
|
+
return { xml, hairpins, pedals, octaves, slurs, arpeggios, fermatas, trills, mordents, turns, dynamics, fingerings, navigations, harmonies, barlines, markups, pendingTiePitches, pendingSlur: currentSlur?.startId || null, pendingHairpin: currentHairpin, pendingOctave, ottavaExplicitlyClosed, endingClef: currentClef, lastNoteId, currentOttavaShift, octaveEndReplacements };
|
|
1101
1129
|
};
|
|
1102
1130
|
// Encode a staff
|
|
1103
1131
|
const encodeStaff = (voices, staffN, indent, tieState = {}, slurState = {}, hairpinState = {}, ottavaState = {}, keyFifths = 0, initialClef) => {
|
|
@@ -1124,6 +1152,7 @@ const encodeStaff = (voices, staffN, indent, tieState = {}, slurState = {}, hair
|
|
|
1124
1152
|
const pendingOctaves = {};
|
|
1125
1153
|
const ottavaExplicitlyClosed = {};
|
|
1126
1154
|
const lastNoteIds = {};
|
|
1155
|
+
const octaveEndReplacements = {};
|
|
1127
1156
|
let endingClef = initialClef;
|
|
1128
1157
|
if (voices.length === 0) {
|
|
1129
1158
|
xml += `${indent} <layer xml:id="${generateId('layer')}" n="1" />\n`;
|
|
@@ -1153,6 +1182,7 @@ const encodeStaff = (voices, staffN, indent, tieState = {}, slurState = {}, hair
|
|
|
1153
1182
|
allHarmonies.push(...result.harmonies);
|
|
1154
1183
|
allBarlines.push(...result.barlines);
|
|
1155
1184
|
allMarkups.push(...result.markups);
|
|
1185
|
+
Object.assign(octaveEndReplacements, result.octaveEndReplacements);
|
|
1156
1186
|
// Track pending ties for this layer
|
|
1157
1187
|
if (result.pendingTiePitches.length > 0) {
|
|
1158
1188
|
pendingTies[tieKey] = result.pendingTiePitches;
|
|
@@ -1205,6 +1235,7 @@ const encodeStaff = (voices, staffN, indent, tieState = {}, slurState = {}, hair
|
|
|
1205
1235
|
pendingOctaves,
|
|
1206
1236
|
ottavaExplicitlyClosed,
|
|
1207
1237
|
lastNoteIds,
|
|
1238
|
+
octaveEndReplacements,
|
|
1208
1239
|
endingClef,
|
|
1209
1240
|
};
|
|
1210
1241
|
};
|
|
@@ -1280,7 +1311,7 @@ const BARLINE_TO_MEI = {
|
|
|
1280
1311
|
};
|
|
1281
1312
|
// Encode a measure
|
|
1282
1313
|
// encodeMeasure accepts mutable tieState, slurState, hairpinState, ottavaState and clefState that persist across measures
|
|
1283
|
-
const encodeMeasure = (measure, measureN, indent, totalStaves, tieState, slurState, hairpinState, ottavaState, keyFifths = 0, partInfos = [], clefState = {}) => {
|
|
1314
|
+
const encodeMeasure = (measure, measureN, indent, totalStaves, tieState, slurState, hairpinState, ottavaState, keyFifths = 0, partInfos = [], clefState = {}, octaveEndReplacements = {}) => {
|
|
1284
1315
|
const measureId = generateId("measure");
|
|
1285
1316
|
let staffContent = ''; // Build staff content first, then add measure tag with barline
|
|
1286
1317
|
const allHairpins = [];
|
|
@@ -1353,39 +1384,22 @@ const encodeMeasure = (measure, measureN, indent, totalStaves, tieState, slurSta
|
|
|
1353
1384
|
allHarmonies.push(...result.harmonies);
|
|
1354
1385
|
allBarlines.push(...result.barlines);
|
|
1355
1386
|
allMarkups.push(...result.markups);
|
|
1387
|
+
Object.assign(octaveEndReplacements, result.octaveEndReplacements);
|
|
1356
1388
|
// Update tie state with pending ties from this staff
|
|
1357
1389
|
Object.assign(tieState, result.pendingTies);
|
|
1358
1390
|
// Update slur state with pending slurs from this staff
|
|
1359
1391
|
Object.assign(slurState, result.pendingSlurs);
|
|
1360
1392
|
// Update hairpin state with pending hairpins from this staff
|
|
1361
1393
|
Object.assign(hairpinState, result.pendingHairpins);
|
|
1362
|
-
// Update ottava state with pending octaves from this staff
|
|
1363
|
-
//
|
|
1394
|
+
// Update ottava state with pending octaves from this staff.
|
|
1395
|
+
// encodeLayer already emits measure-local octave spans, so keep the next measure's start independent.
|
|
1364
1396
|
const currentStaffPrefix = `${si}-`;
|
|
1365
1397
|
for (const [key, pending] of Object.entries(result.pendingOctaves)) {
|
|
1366
1398
|
if (pending) {
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
if (prevPending && prevPending.shift === pending.shift) {
|
|
1370
|
-
// Same ottava value continues - keep the original startId
|
|
1371
|
-
ottavaState[key] = { ...pending, startId: prevPending.startId };
|
|
1372
|
-
}
|
|
1373
|
-
else {
|
|
1374
|
-
// Different ottava value - close the old span first if exists
|
|
1375
|
-
if (prevPending) {
|
|
1376
|
-
const lastNoteId = result.lastNoteIds[key];
|
|
1377
|
-
if (lastNoteId) {
|
|
1378
|
-
allOctaves.push({
|
|
1379
|
-
dis: prevPending.dis,
|
|
1380
|
-
disPlace: prevPending.disPlace,
|
|
1381
|
-
startId: prevPending.startId,
|
|
1382
|
-
endId: lastNoteId,
|
|
1383
|
-
});
|
|
1384
|
-
}
|
|
1385
|
-
}
|
|
1386
|
-
// Start new span
|
|
1387
|
-
ottavaState[key] = pending;
|
|
1399
|
+
if (pending.endToken && pending.endFallbackId && !octaveEndReplacements[pending.endToken]) {
|
|
1400
|
+
octaveEndReplacements[pending.endToken] = pending.endFallbackId;
|
|
1388
1401
|
}
|
|
1402
|
+
ottavaState[key] = pending;
|
|
1389
1403
|
}
|
|
1390
1404
|
}
|
|
1391
1405
|
// For layers in this staff that had pending octaves but didn't in this measure, close the spans
|
|
@@ -1912,6 +1926,7 @@ const encode = (doc, options = {}) => {
|
|
|
1912
1926
|
const hairpinState = {};
|
|
1913
1927
|
// Track ottava state across measures for cross-measure ottava spans
|
|
1914
1928
|
const ottavaState = {};
|
|
1929
|
+
const octaveEndReplacements = {};
|
|
1915
1930
|
// Initialize clef state from partInfos (convert local staff to global staff)
|
|
1916
1931
|
const clefState = {};
|
|
1917
1932
|
for (let pi = 0; pi < partInfos.length; pi++) {
|
|
@@ -1967,7 +1982,7 @@ const encode = (doc, options = {}) => {
|
|
|
1967
1982
|
mei += `${indent}${indent}${indent}${indent}${indent}${indent}<scoreDef xml:id="${generateId('scoredef')}"${meterSymAttr} meter.count="${currentTimeNum}" meter.unit="${currentTimeDen}" />\n`;
|
|
1968
1983
|
}
|
|
1969
1984
|
}
|
|
1970
|
-
mei += encodeMeasure(measure, mi + 1, `${indent}${indent}${indent}${indent}${indent}${indent}`, totalStaves, tieState, slurState, hairpinState, ottavaState, currentKey, partInfos, clefState);
|
|
1985
|
+
mei += encodeMeasure(measure, mi + 1, `${indent}${indent}${indent}${indent}${indent}${indent}`, totalStaves, tieState, slurState, hairpinState, ottavaState, currentKey, partInfos, clefState, octaveEndReplacements);
|
|
1971
1986
|
});
|
|
1972
1987
|
mei += `${indent}${indent}${indent}${indent}${indent}</section>\n`;
|
|
1973
1988
|
mei += `${indent}${indent}${indent}${indent}</score>\n`;
|
|
@@ -1975,6 +1990,9 @@ const encode = (doc, options = {}) => {
|
|
|
1975
1990
|
mei += `${indent}${indent}</body>\n`;
|
|
1976
1991
|
mei += `${indent}</music>\n`;
|
|
1977
1992
|
mei += '</mei>\n';
|
|
1993
|
+
for (const [token, endId] of Object.entries(octaveEndReplacements)) {
|
|
1994
|
+
mei = mei.replaceAll(token, endId);
|
|
1995
|
+
}
|
|
1978
1996
|
return mei;
|
|
1979
1997
|
};
|
|
1980
1998
|
// Escape XML special characters
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
interface Fraction {
|
|
2
|
+
numerator: number;
|
|
3
|
+
denominator: number;
|
|
4
|
+
}
|
|
5
|
+
declare namespace ABC {
|
|
6
|
+
type Token = string;
|
|
7
|
+
interface KeyValue {
|
|
8
|
+
name: string;
|
|
9
|
+
value: any;
|
|
10
|
+
}
|
|
11
|
+
export interface ControlTerm {
|
|
12
|
+
control: KeyValue;
|
|
13
|
+
}
|
|
14
|
+
export interface Triplet {
|
|
15
|
+
triplet: number;
|
|
16
|
+
multiplier?: number;
|
|
17
|
+
n?: number;
|
|
18
|
+
}
|
|
19
|
+
export interface OctaveShift {
|
|
20
|
+
octaveShift: number;
|
|
21
|
+
}
|
|
22
|
+
export interface Fingering {
|
|
23
|
+
fingering: string;
|
|
24
|
+
}
|
|
25
|
+
export interface Tremolo {
|
|
26
|
+
tremolo: number;
|
|
27
|
+
}
|
|
28
|
+
interface Grace {
|
|
29
|
+
grace: boolean;
|
|
30
|
+
acciaccatura: Token;
|
|
31
|
+
events: GraceMusicTerm[];
|
|
32
|
+
}
|
|
33
|
+
interface Comment {
|
|
34
|
+
comment: string;
|
|
35
|
+
}
|
|
36
|
+
export interface Articulation {
|
|
37
|
+
articulation: Token;
|
|
38
|
+
scope?: '(' | ')';
|
|
39
|
+
}
|
|
40
|
+
export type Expressive = Articulation | {
|
|
41
|
+
express: Token;
|
|
42
|
+
};
|
|
43
|
+
export interface TextTerm {
|
|
44
|
+
text: string;
|
|
45
|
+
}
|
|
46
|
+
export interface Pitch {
|
|
47
|
+
acc: number | null;
|
|
48
|
+
phonet: Token;
|
|
49
|
+
quotes: number;
|
|
50
|
+
tie?: boolean;
|
|
51
|
+
}
|
|
52
|
+
export interface Chord {
|
|
53
|
+
pitches: Pitch[];
|
|
54
|
+
tie?: any;
|
|
55
|
+
}
|
|
56
|
+
export interface EventData {
|
|
57
|
+
chord: Chord;
|
|
58
|
+
duration?: Fraction;
|
|
59
|
+
}
|
|
60
|
+
export interface EventTerm {
|
|
61
|
+
event: EventData;
|
|
62
|
+
broken?: number;
|
|
63
|
+
}
|
|
64
|
+
export type MusicTerm = Expressive | TextTerm | EventTerm | Grace | ControlTerm | Triplet | OctaveShift | Fingering | Tremolo;
|
|
65
|
+
export type GraceMusicTerm = Expressive | EventTerm | Fingering;
|
|
66
|
+
type Header = KeyValue | Comment;
|
|
67
|
+
export interface BarPatch {
|
|
68
|
+
control: {
|
|
69
|
+
[k: string]: any;
|
|
70
|
+
};
|
|
71
|
+
terms: MusicTerm[];
|
|
72
|
+
bar: Token;
|
|
73
|
+
}
|
|
74
|
+
export interface StaffGroup {
|
|
75
|
+
items: (StaffGroup | string)[];
|
|
76
|
+
bound?: 'arc' | 'square' | 'curly';
|
|
77
|
+
}
|
|
78
|
+
export interface StaffLayout {
|
|
79
|
+
staffLayout: StaffGroup[];
|
|
80
|
+
}
|
|
81
|
+
export interface KeySignature {
|
|
82
|
+
root: string;
|
|
83
|
+
mode?: string;
|
|
84
|
+
}
|
|
85
|
+
export interface ClefValue {
|
|
86
|
+
clef: string;
|
|
87
|
+
}
|
|
88
|
+
interface Measure {
|
|
89
|
+
index: number;
|
|
90
|
+
voices: BarPatch[];
|
|
91
|
+
}
|
|
92
|
+
interface Body {
|
|
93
|
+
measures: Measure[];
|
|
94
|
+
}
|
|
95
|
+
export interface Tune {
|
|
96
|
+
header: Header[];
|
|
97
|
+
body: Body;
|
|
98
|
+
}
|
|
99
|
+
export type Document = Tune[];
|
|
100
|
+
export {};
|
|
101
|
+
}
|
|
102
|
+
export { ABC, };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ABC Notation Decoder for Lilylet
|
|
3
|
+
*
|
|
4
|
+
* Converts ABC notation files to Lilylet's internal LilyletDoc format.
|
|
5
|
+
*/
|
|
6
|
+
import { LilyletDoc } from "./types";
|
|
7
|
+
/**
|
|
8
|
+
* Decode ABC notation string to LilyletDoc.
|
|
9
|
+
* If the ABC contains multiple tunes, only the first is decoded.
|
|
10
|
+
*/
|
|
11
|
+
export declare const decode: (abcString: string) => LilyletDoc;
|
|
12
|
+
/**
|
|
13
|
+
* Decode ABC notation string to multiple LilyletDocs (one per tune).
|
|
14
|
+
*/
|
|
15
|
+
export declare const decodeAll: (abcString: string) => LilyletDoc[];
|
|
16
|
+
/**
|
|
17
|
+
* Decode an ABC file to LilyletDoc
|
|
18
|
+
*/
|
|
19
|
+
export declare const decodeFile: (filePath: string) => Promise<LilyletDoc>;
|
|
20
|
+
declare const _default: {
|
|
21
|
+
decode: (abcString: string) => LilyletDoc;
|
|
22
|
+
decodeAll: (abcString: string) => LilyletDoc[];
|
|
23
|
+
decodeFile: (filePath: string) => Promise<LilyletDoc>;
|
|
24
|
+
};
|
|
25
|
+
export default _default;
|