@k-l-lambda/lilylet 0.1.34 → 0.1.35
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/grammar.jison.js +179 -150
- package/lib/meiEncoder.js +21 -3
- package/lib/serializer.js +7 -1
- package/lib/types.d.ts +4 -1
- package/package.json +1 -1
- package/source/lilylet/grammar.jison.js +179 -150
- package/source/lilylet/lilylet.jison +30 -2
- package/source/lilylet/meiEncoder.ts +22 -3
- package/source/lilylet/serializer.ts +8 -2
- package/source/lilylet/types.ts +7 -1
- package/lib/lilypondDecoder.d.ts +0 -28
- package/lib/lilypondDecoder.js +0 -645
package/lib/meiEncoder.js
CHANGED
|
@@ -1237,9 +1237,11 @@ const analyzePartStructure = (doc) => {
|
|
|
1237
1237
|
return partInfos;
|
|
1238
1238
|
};
|
|
1239
1239
|
// Encode scoreDef with part groups
|
|
1240
|
-
const encodeScoreDef = (keySig, timeNum, timeDen, partInfos, indent) => {
|
|
1240
|
+
const encodeScoreDef = (keySig, timeNum, timeDen, partInfos, indent, meterSymbol) => {
|
|
1241
1241
|
const scoreDefId = generateId("scoredef");
|
|
1242
|
-
|
|
1242
|
+
// Build meter attributes
|
|
1243
|
+
const meterSymAttr = meterSymbol ? ` meter.sym="${meterSymbol}"` : '';
|
|
1244
|
+
let xml = `${indent}<scoreDef xml:id="${scoreDefId}" key.sig="${keySig}"${meterSymAttr} meter.count="${timeNum}" meter.unit="${timeDen}">\n`;
|
|
1243
1245
|
xml += `${indent} <staffGrp xml:id="${generateId("staffgrp")}">\n`;
|
|
1244
1246
|
for (let pi = 0; pi < partInfos.length; pi++) {
|
|
1245
1247
|
const info = partInfos[pi];
|
|
@@ -1281,6 +1283,7 @@ const encode = (doc, options = {}) => {
|
|
|
1281
1283
|
let currentKey = 0;
|
|
1282
1284
|
let currentTimeNum = 4;
|
|
1283
1285
|
let currentTimeDen = 4;
|
|
1286
|
+
let currentMeterSymbol = undefined;
|
|
1284
1287
|
const firstMeasure = doc.measures[0];
|
|
1285
1288
|
if (firstMeasure.key) {
|
|
1286
1289
|
currentKey = keyToFifths(firstMeasure.key);
|
|
@@ -1288,6 +1291,7 @@ const encode = (doc, options = {}) => {
|
|
|
1288
1291
|
if (firstMeasure.timeSig) {
|
|
1289
1292
|
currentTimeNum = firstMeasure.timeSig.numerator;
|
|
1290
1293
|
currentTimeDen = firstMeasure.timeSig.denominator;
|
|
1294
|
+
currentMeterSymbol = firstMeasure.timeSig.symbol;
|
|
1291
1295
|
}
|
|
1292
1296
|
const keySig = KEY_SIGS[currentKey] || "0";
|
|
1293
1297
|
// Build MEI document
|
|
@@ -1332,7 +1336,7 @@ const encode = (doc, options = {}) => {
|
|
|
1332
1336
|
mei += `${indent}${indent}<body>\n`;
|
|
1333
1337
|
mei += `${indent}${indent}${indent}<mdiv xml:id="${generateId("mdiv")}">\n`;
|
|
1334
1338
|
mei += `${indent}${indent}${indent}${indent}<score xml:id="${generateId("score")}">\n`;
|
|
1335
|
-
mei += encodeScoreDef(keySig, currentTimeNum, currentTimeDen, partInfos, `${indent}${indent}${indent}${indent}${indent}
|
|
1339
|
+
mei += encodeScoreDef(keySig, currentTimeNum, currentTimeDen, partInfos, `${indent}${indent}${indent}${indent}${indent}`, currentMeterSymbol);
|
|
1336
1340
|
mei += `${indent}${indent}${indent}${indent}${indent}<section xml:id="${generateId("section")}">\n`;
|
|
1337
1341
|
// Track tie state across measures for cross-measure ties
|
|
1338
1342
|
const tieState = {};
|
|
@@ -1381,6 +1385,20 @@ const encode = (doc, options = {}) => {
|
|
|
1381
1385
|
mei += `${indent}${indent}${indent}${indent}${indent}${indent}<scoreDef xml:id="${generateId('scoredef')}" key.sig="${newKeySig}" />\n`;
|
|
1382
1386
|
}
|
|
1383
1387
|
}
|
|
1388
|
+
// Check for time signature change and output scoreDef if needed
|
|
1389
|
+
if (measure.timeSig && mi > 0) {
|
|
1390
|
+
const newTimeNum = measure.timeSig.numerator;
|
|
1391
|
+
const newTimeDen = measure.timeSig.denominator;
|
|
1392
|
+
const newMeterSymbol = measure.timeSig.symbol;
|
|
1393
|
+
if (newTimeNum !== currentTimeNum || newTimeDen !== currentTimeDen || newMeterSymbol !== currentMeterSymbol) {
|
|
1394
|
+
currentTimeNum = newTimeNum;
|
|
1395
|
+
currentTimeDen = newTimeDen;
|
|
1396
|
+
currentMeterSymbol = newMeterSymbol;
|
|
1397
|
+
// Output a scoreDef with the new time signature
|
|
1398
|
+
const meterSymAttr = currentMeterSymbol ? ` meter.sym="${currentMeterSymbol}"` : '';
|
|
1399
|
+
mei += `${indent}${indent}${indent}${indent}${indent}${indent}<scoreDef xml:id="${generateId('scoredef')}"${meterSymAttr} meter.count="${currentTimeNum}" meter.unit="${currentTimeDen}" />\n`;
|
|
1400
|
+
}
|
|
1401
|
+
}
|
|
1384
1402
|
mei += encodeMeasure(measure, mi + 1, `${indent}${indent}${indent}${indent}${indent}${indent}`, totalStaves, tieState, slurState, hairpinState, currentKey, partInfos, clefState);
|
|
1385
1403
|
});
|
|
1386
1404
|
mei += `${indent}${indent}${indent}${indent}${indent}</section>\n`;
|
package/lib/serializer.js
CHANGED
|
@@ -448,7 +448,13 @@ const serializeVoice = (voice, currentStaff, isGrandStaff = false, measureContex
|
|
|
448
448
|
parts.push('\\key ' + keyStr);
|
|
449
449
|
}
|
|
450
450
|
if (measureContext.time) {
|
|
451
|
-
|
|
451
|
+
const { numerator, denominator, symbol } = measureContext.time;
|
|
452
|
+
// Output \numericTimeSignature before 4/4 or 2/2 if no symbol is set
|
|
453
|
+
// (meaning numeric display was explicitly requested)
|
|
454
|
+
if (!symbol && ((numerator === 4 && denominator === 4) || (numerator === 2 && denominator === 2))) {
|
|
455
|
+
parts.push('\\numericTimeSignature');
|
|
456
|
+
}
|
|
457
|
+
parts.push('\\time ' + numerator + '/' + denominator);
|
|
452
458
|
}
|
|
453
459
|
}
|
|
454
460
|
for (const event of voice.events) {
|
package/lib/types.d.ts
CHANGED
|
@@ -83,6 +83,9 @@ export interface Fraction {
|
|
|
83
83
|
numerator: number;
|
|
84
84
|
denominator: number;
|
|
85
85
|
}
|
|
86
|
+
export interface TimeSig extends Fraction {
|
|
87
|
+
symbol?: 'common' | 'cut';
|
|
88
|
+
}
|
|
86
89
|
export interface Pitch {
|
|
87
90
|
phonet: Phonet;
|
|
88
91
|
accidental?: Accidental;
|
|
@@ -231,7 +234,7 @@ export interface Part {
|
|
|
231
234
|
}
|
|
232
235
|
export interface Measure {
|
|
233
236
|
key?: KeySignature;
|
|
234
|
-
timeSig?:
|
|
237
|
+
timeSig?: TimeSig;
|
|
235
238
|
parts: Part[];
|
|
236
239
|
partial?: boolean;
|
|
237
240
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@k-l-lambda/lilylet",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.35",
|
|
4
4
|
"description": "Lilylet is a lilyopnd-like sheet music language designed for Markdown rendering and symbolic music representation in AIGC applications.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|