@k-l-lambda/lilylet 0.1.48 → 0.1.50

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.
Files changed (71) hide show
  1. package/lib/abc/abc.d.ts +102 -0
  2. package/lib/abc/abc.js +25 -0
  3. package/lib/abc/grammar.jison.js +1203 -0
  4. package/lib/abc/parser.d.ts +3 -0
  5. package/lib/abc/parser.js +6 -0
  6. package/lib/abcDecoder.d.ts +1 -0
  7. package/lib/abcDecoder.js +1 -0
  8. package/lib/grammar.jison.js +1 -1303
  9. package/lib/index.d.ts +1 -8
  10. package/lib/index.js +1 -10
  11. package/lib/lilylet/abcDecoder.d.ts +25 -0
  12. package/lib/lilylet/abcDecoder.js +1007 -0
  13. package/lib/lilylet/grammar.jison.js +1308 -0
  14. package/lib/lilylet/index.d.ts +10 -0
  15. package/lib/lilylet/index.js +10 -0
  16. package/lib/lilylet/lilypondDecoder.d.ts +29 -0
  17. package/lib/lilylet/lilypondDecoder.js +1053 -0
  18. package/lib/lilylet/lilypondEncoder.d.ts +34 -0
  19. package/lib/lilylet/lilypondEncoder.js +759 -0
  20. package/lib/lilylet/meiEncoder.d.ts +8 -0
  21. package/lib/lilylet/meiEncoder.js +1808 -0
  22. package/lib/lilylet/musicXmlDecoder.d.ts +20 -0
  23. package/lib/lilylet/musicXmlDecoder.js +1195 -0
  24. package/lib/lilylet/musicXmlEncoder.d.ts +15 -0
  25. package/lib/lilylet/musicXmlEncoder.js +701 -0
  26. package/lib/lilylet/musicXmlTypes.d.ts +199 -0
  27. package/lib/lilylet/musicXmlTypes.js +7 -0
  28. package/lib/lilylet/musicXmlUtils.d.ts +92 -0
  29. package/lib/lilylet/musicXmlUtils.js +469 -0
  30. package/lib/lilylet/parser.d.ts +3 -0
  31. package/lib/lilylet/parser.js +151 -0
  32. package/lib/lilylet/serializer.d.ts +11 -0
  33. package/lib/lilylet/serializer.js +653 -0
  34. package/lib/lilylet/types.d.ts +245 -0
  35. package/lib/lilylet/types.js +99 -0
  36. package/lib/lilypondDecoder.d.ts +1 -29
  37. package/lib/lilypondDecoder.js +1 -1006
  38. package/lib/lilypondEncoder.d.ts +1 -34
  39. package/lib/lilypondEncoder.js +1 -759
  40. package/lib/meiEncoder.d.ts +1 -8
  41. package/lib/meiEncoder.js +1 -1545
  42. package/lib/musicXmlDecoder.d.ts +1 -20
  43. package/lib/musicXmlDecoder.js +1 -1151
  44. package/lib/musicXmlEncoder.d.ts +1 -15
  45. package/lib/musicXmlEncoder.js +1 -666
  46. package/lib/musicXmlTypes.d.ts +1 -199
  47. package/lib/musicXmlTypes.js +1 -7
  48. package/lib/musicXmlUtils.d.ts +1 -81
  49. package/lib/musicXmlUtils.js +1 -435
  50. package/lib/parser.d.ts +1 -3
  51. package/lib/parser.js +1 -151
  52. package/lib/serializer.d.ts +1 -11
  53. package/lib/serializer.js +1 -650
  54. package/lib/types.d.ts +1 -244
  55. package/lib/types.js +1 -99
  56. package/package.json +2 -1
  57. package/source/abc/abc.jison +692 -0
  58. package/source/abc/abc.ts +176 -0
  59. package/source/abc/grammar.jison.js +1203 -0
  60. package/source/abc/parser.ts +12 -0
  61. package/source/lilylet/abcDecoder.ts +1121 -0
  62. package/source/lilylet/grammar.jison.js +170 -165
  63. package/source/lilylet/index.ts +4 -3
  64. package/source/lilylet/lilylet.jison +2 -0
  65. package/source/lilylet/lilypondDecoder.ts +92 -42
  66. package/source/lilylet/meiEncoder.ts +280 -0
  67. package/source/lilylet/musicXmlDecoder.ts +74 -27
  68. package/source/lilylet/musicXmlEncoder.ts +201 -146
  69. package/source/lilylet/musicXmlUtils.ts +46 -4
  70. package/source/lilylet/serializer.ts +3 -0
  71. package/source/lilylet/types.ts +1 -0
@@ -158,10 +158,13 @@ export const convertPitch = (
158
158
  };
159
159
  };
160
160
 
161
- // ============ Duration Conversion ============
161
+ // ============ Duration Constants & Mappings ============
162
+
163
+ // Standard divisions per quarter note (shared by encoder/decoder)
164
+ export const DIVISIONS = 4;
162
165
 
163
166
  // MusicXML note type to division (1=whole, 2=half, 4=quarter, etc.)
164
- const TYPE_TO_DIVISION: Record<string, number> = {
167
+ export const TYPE_TO_DIVISION: Record<string, number> = {
165
168
  maxima: 0.125,
166
169
  long: 0.25,
167
170
  breve: 0.5,
@@ -178,6 +181,43 @@ const TYPE_TO_DIVISION: Record<string, number> = {
178
181
  '1024th': 1024,
179
182
  };
180
183
 
184
+ // Division to MusicXML note type (inverse of TYPE_TO_DIVISION)
185
+ export const DIVISION_TO_TYPE: Record<number, string> = Object.fromEntries(
186
+ Object.entries(TYPE_TO_DIVISION).map(([type, div]) => [div, type])
187
+ );
188
+
189
+ /**
190
+ * Calculate duration in MusicXML divisions.
191
+ * Shared by encoder (with DIVISIONS=4) and potentially decoder.
192
+ *
193
+ * Duration.tuplet is in Lilylet ratio semantics:
194
+ * \times 2/3 → {numerator:2, denominator:3} → multiply by 2/3
195
+ */
196
+ export const calculateDuration = (duration: Duration, divisions: number = DIVISIONS): number => {
197
+ // Base duration: divisions * (4 / division)
198
+ // e.g., quarter (4) = divisions * 1
199
+ // half (2) = divisions * 2
200
+ // eighth (8) = divisions * 0.5
201
+ let dur = divisions * (4 / duration.division);
202
+
203
+ // Apply dots
204
+ if (duration.dots) {
205
+ let dotValue = dur / 2;
206
+ for (let i = 0; i < duration.dots; i++) {
207
+ dur += dotValue;
208
+ dotValue /= 2;
209
+ }
210
+ }
211
+
212
+ // Apply tuplet ratio: Lilylet ratio num/den means multiply by num/den
213
+ // e.g., \times 2/3 means each note's actual duration = written * 2/3
214
+ if (duration.tuplet) {
215
+ dur = dur * duration.tuplet.numerator / duration.tuplet.denominator;
216
+ }
217
+
218
+ return Math.round(dur);
219
+ };
220
+
181
221
  /**
182
222
  * Convert MusicXML duration to Lilylet Duration
183
223
  *
@@ -218,9 +258,11 @@ export const convertDuration = (
218
258
  };
219
259
 
220
260
  if (timeModification) {
261
+ // Store as Lilylet ratio: normalNotes/actualNotes
262
+ // MusicXML actual=3, normal=2 (triplet) → Lilylet ratio {num:2, den:3}
221
263
  result.tuplet = {
222
- numerator: timeModification.actualNotes,
223
- denominator: timeModification.normalNotes,
264
+ numerator: timeModification.normalNotes,
265
+ denominator: timeModification.actualNotes,
224
266
  };
225
267
  }
226
268
 
@@ -771,6 +771,9 @@ const serializeMetadata = (metadata: any): string => {
771
771
  if (metadata.lyricist) {
772
772
  lines.push('[lyricist "' + escapeString(metadata.lyricist) + '"]');
773
773
  }
774
+ if (metadata.autoBeam) {
775
+ lines.push('[auto-beam "' + escapeString(metadata.autoBeam) + '"]');
776
+ }
774
777
 
775
778
  return lines.join('\n');
776
779
  };
@@ -286,6 +286,7 @@ export interface Metadata {
286
286
  opus?: string;
287
287
  instrument?: string;
288
288
  genre?: string;
289
+ autoBeam?: 'auto' | 'on' | 'off';
289
290
  }
290
291
 
291
292
  // Part within a measure: can be a single staff or grand staff (multiple staves)