@k-l-lambda/lilylet 0.1.54 → 0.1.55

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.
@@ -941,9 +941,13 @@ const encodeLayer = (voice, layerN, indent, initialTiePitches = [], keyFifths =
941
941
  case 'context': {
942
942
  const ctx = event;
943
943
  // Check for clef changes - emit <clef> element only if different from current
944
+ // and only when on the home staff (don't emit cross-staff clefs into this layer)
944
945
  if (ctx.clef && ctx.clef !== currentClef) {
945
- const clefInfo = CLEF_SHAPES[ctx.clef] || CLEF_SHAPES.treble;
946
- xml += `${currentIndent}<clef xml:id="${generateId('clef')}" shape="${clefInfo.shape}" line="${clefInfo.line}" />\n`;
946
+ const layerStaff = voice.staff || 1;
947
+ if (currentStaff === layerStaff) {
948
+ const clefInfo = CLEF_SHAPES[ctx.clef] || CLEF_SHAPES.treble;
949
+ xml += `${currentIndent}<clef xml:id="${generateId('clef')}" shape="${clefInfo.shape}" line="${clefInfo.line}" />\n`;
950
+ }
947
951
  currentClef = ctx.clef;
948
952
  }
949
953
  // Check for ottava changes
@@ -1466,15 +1470,19 @@ const analyzePartStructure = (doc) => {
1466
1470
  for (let pi = 0; pi < measure.parts.length; pi++) {
1467
1471
  const part = measure.parts[pi];
1468
1472
  for (const voice of part.voices) {
1469
- const localStaff = voice.staff || 1;
1470
- partInfos[pi].maxStaff = Math.max(partInfos[pi].maxStaff, localStaff);
1471
- // Get FIRST clef from context changes (for initial staffDef)
1473
+ let currentStaff = voice.staff || 1;
1474
+ partInfos[pi].maxStaff = Math.max(partInfos[pi].maxStaff, currentStaff);
1475
+ // Scan context changes for staff switches and clefs
1472
1476
  for (const event of voice.events) {
1473
1477
  if (event.type === 'context') {
1474
1478
  const ctx = event;
1475
- if (ctx.clef && !partInfos[pi].clefs[localStaff]) {
1476
- // Only set if not already set - take the FIRST clef
1477
- partInfos[pi].clefs[localStaff] = ctx.clef;
1479
+ if (ctx.staff !== undefined) {
1480
+ currentStaff = ctx.staff;
1481
+ partInfos[pi].maxStaff = Math.max(partInfos[pi].maxStaff, currentStaff);
1482
+ }
1483
+ if (ctx.clef && !partInfos[pi].clefs[currentStaff]) {
1484
+ // Only set if not already set - take the FIRST clef per staff
1485
+ partInfos[pi].clefs[currentStaff] = ctx.clef;
1478
1486
  }
1479
1487
  }
1480
1488
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@k-l-lambda/lilylet",
3
- "version": "0.1.54",
3
+ "version": "0.1.55",
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",
@@ -1236,9 +1236,13 @@ const encodeLayer = (voice: Voice, layerN: number, indent: string, initialTiePit
1236
1236
  case 'context': {
1237
1237
  const ctx = event as ContextChange;
1238
1238
  // Check for clef changes - emit <clef> element only if different from current
1239
+ // and only when on the home staff (don't emit cross-staff clefs into this layer)
1239
1240
  if (ctx.clef && ctx.clef !== currentClef) {
1240
- const clefInfo = CLEF_SHAPES[ctx.clef] || CLEF_SHAPES.treble;
1241
- xml += `${currentIndent}<clef xml:id="${generateId('clef')}" shape="${clefInfo.shape}" line="${clefInfo.line}" />\n`;
1241
+ const layerStaff = voice.staff || 1;
1242
+ if (currentStaff === layerStaff) {
1243
+ const clefInfo = CLEF_SHAPES[ctx.clef] || CLEF_SHAPES.treble;
1244
+ xml += `${currentIndent}<clef xml:id="${generateId('clef')}" shape="${clefInfo.shape}" line="${clefInfo.line}" />\n`;
1245
+ }
1242
1246
  currentClef = ctx.clef;
1243
1247
  }
1244
1248
  // Check for ottava changes
@@ -1832,16 +1836,20 @@ const analyzePartStructure = (doc: LilyletDoc): PartInfo[] => {
1832
1836
  for (let pi = 0; pi < measure.parts.length; pi++) {
1833
1837
  const part = measure.parts[pi];
1834
1838
  for (const voice of part.voices) {
1835
- const localStaff = voice.staff || 1;
1836
- partInfos[pi].maxStaff = Math.max(partInfos[pi].maxStaff, localStaff);
1839
+ let currentStaff = voice.staff || 1;
1840
+ partInfos[pi].maxStaff = Math.max(partInfos[pi].maxStaff, currentStaff);
1837
1841
 
1838
- // Get FIRST clef from context changes (for initial staffDef)
1842
+ // Scan context changes for staff switches and clefs
1839
1843
  for (const event of voice.events) {
1840
1844
  if (event.type === 'context') {
1841
1845
  const ctx = event as ContextChange;
1842
- if (ctx.clef && !partInfos[pi].clefs[localStaff]) {
1843
- // Only set if not already set - take the FIRST clef
1844
- partInfos[pi].clefs[localStaff] = ctx.clef;
1846
+ if (ctx.staff !== undefined) {
1847
+ currentStaff = ctx.staff;
1848
+ partInfos[pi].maxStaff = Math.max(partInfos[pi].maxStaff, currentStaff);
1849
+ }
1850
+ if (ctx.clef && !partInfos[pi].clefs[currentStaff]) {
1851
+ // Only set if not already set - take the FIRST clef per staff
1852
+ partInfos[pi].clefs[currentStaff] = ctx.clef;
1845
1853
  }
1846
1854
  }
1847
1855
  }