@k-l-lambda/lilylet 0.1.35 → 0.1.37
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 +30 -25
- package/lib/grammar.jison.js +16 -5
- package/lib/index.d.ts +2 -1
- package/lib/index.js +2 -1
- package/lib/lilypondEncoder.d.ts +29 -0
- package/lib/lilypondEncoder.js +669 -0
- package/lib/meiEncoder.js +152 -29
- package/lib/musicXmlDecoder.js +4 -4
- package/lib/serializer.js +86 -20
- package/package.json +1 -1
- package/source/lilylet/grammar.jison.js +16 -5
- package/source/lilylet/index.ts +2 -0
- package/source/lilylet/lilylet.jison +16 -5
- package/source/lilylet/lilypondEncoder.ts +832 -0
- package/source/lilylet/meiEncoder.ts +171 -29
- package/source/lilylet/musicXmlDecoder.ts +4 -4
- package/source/lilylet/serializer.ts +111 -21
package/README.md
CHANGED
|
@@ -1,7 +1,37 @@
|
|
|
1
1
|
# Lilylet
|
|
2
2
|
|
|
3
|
+

|
|
4
|
+
|
|
3
5
|
Lilylet is a LilyPond-like music notation language designed for Markdown rendering and symbolic music representation in AIGC applications.
|
|
4
6
|
|
|
7
|
+
## Hello World
|
|
8
|
+
|
|
9
|
+
```lyl
|
|
10
|
+
\key c \major \time 4/4 \clef "treble" c1 \bar "|."
|
|
11
|
+
```
|
|
12
|
+

|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
## A Comprehensive Example
|
|
16
|
+
|
|
17
|
+
```lyl
|
|
18
|
+
[title "Jesu, meine Freude"]
|
|
19
|
+
[subtitle "BWV 610"]
|
|
20
|
+
[composer "J.S. Bach"]
|
|
21
|
+
|
|
22
|
+
\staff "1" \key c \minor \time 4/4 \clef "treble" \stemUp g'4 g f ef \\
|
|
23
|
+
\staff "1" \stemDown ef16[ d ef8]~ ef16[ f ef d] c8[ d]~ d[ c] \\
|
|
24
|
+
\staff "2" \clef "bass" c16[ b c8]~ c16[ b c g] a8[ g]~ g16[ g af ef] \\
|
|
25
|
+
\staff "3" \clef "bass" r8 c,16[ d] ef[ d ef8]~ ef16[ a, b g] c[ b c8] | % 1
|
|
26
|
+
|
|
27
|
+
\staff "1" \stemUp d2 c\fermata \\
|
|
28
|
+
\staff "1" \stemDown c8[ c4 b8] c8.[ \staff "2" \stemUp g16] \staff "1" c[ b c d] \\
|
|
29
|
+
\staff "2" f,16[ ef f d] g[ af g f] ef[ d ef8]~ ef16[ f ef d] \\
|
|
30
|
+
\staff "3" r16 g,[ af f] g[ f g8] c,2 | % 2
|
|
31
|
+
```
|
|
32
|
+

|
|
33
|
+
|
|
34
|
+
|
|
5
35
|
## Try It Online
|
|
6
36
|
|
|
7
37
|
- [Live Editor](https://k-l-lambda.github.io/lilylet-live-editor/) - Interactive editor with real-time music notation rendering
|
|
@@ -33,28 +63,3 @@ LilyPond is powerful but overly flexible—the same music can be written in mult
|
|
|
33
63
|
- **Shorter context description**: Removes redundant information, allowing LLMs to process more music content within limited context windows
|
|
34
64
|
- **Formatted layout**: Fixed syntax structure facilitates model learning and generation
|
|
35
65
|
- **Markdown-embeddable**: Music snippets can be directly embedded in documents
|
|
36
|
-
|
|
37
|
-
### Basic Syntax
|
|
38
|
-
|
|
39
|
-
| Element | Syntax | Description |
|
|
40
|
-
|---------|--------|-------------|
|
|
41
|
-
| Staff | `\staff "1"` | Specifies which staff the current voice belongs to |
|
|
42
|
-
| Key | `\key c \major` | C major |
|
|
43
|
-
| Time | `\time 4/4` | 4/4 time signature |
|
|
44
|
-
| Clef | `\clef "treble"` | Treble clef |
|
|
45
|
-
| Notes | `c4 d8 e16` | C quarter note, D eighth note, E sixteenth note |
|
|
46
|
-
| Accidentals | `cs` `cf` `css` `cff` | C sharp, C flat, C double-sharp, C double-flat |
|
|
47
|
-
| Octave | `c'` `c,` | One octave higher, one octave lower |
|
|
48
|
-
| Chord | `<c e g>4` | C major triad, quarter note |
|
|
49
|
-
| Voice separator | `\\` | Separates multiple voices within the same staff |
|
|
50
|
-
| Part separator | `\\\` | Separates different instrument tracks (parts) in a score |
|
|
51
|
-
| Bar line | `\|` | Separates measures |
|
|
52
|
-
|
|
53
|
-
## Syntax Example
|
|
54
|
-
|
|
55
|
-
```lilylet
|
|
56
|
-
\staff "1" \key e \major \time 2/4 \clef "treble" \stemUp e8 [ ds16 e16 ] fs4 ~ \\
|
|
57
|
-
\staff "1" s4 \stemDown ds4 ~ \\
|
|
58
|
-
\staff "2" \key e \major \clef "bass" \stemUp e,,4 b4 \\
|
|
59
|
-
\staff "2" \stemDown e,,16 [ b'8 -> b16 ] b,16 [ b'8 -> b16 ] |
|
|
60
|
-
```
|
package/lib/grammar.jison.js
CHANGED
|
@@ -150,7 +150,7 @@ case 25:
|
|
|
150
150
|
this.$ = $$[$0-3].concat([part($$[$0])]);
|
|
151
151
|
break;
|
|
152
152
|
case 26:
|
|
153
|
-
currentStaff = 1;
|
|
153
|
+
currentStaff = 1; currentOttava = 0;
|
|
154
154
|
break;
|
|
155
155
|
case 27:
|
|
156
156
|
this.$ = [voice(currentStaff, $$[$0])];
|
|
@@ -174,7 +174,16 @@ case 43:
|
|
|
174
174
|
this.$ = markupEvent($$[$0].slice(1, -1));
|
|
175
175
|
break;
|
|
176
176
|
case 44:
|
|
177
|
-
|
|
177
|
+
|
|
178
|
+
// On newline, reset ottava to 0 if it's non-zero (like pitch base resets)
|
|
179
|
+
if (currentOttava !== 0) {
|
|
180
|
+
const ottavaReset = contextChange({ ottava: 0 });
|
|
181
|
+
currentOttava = 0;
|
|
182
|
+
this.$ = [ottavaReset, { type: 'pitchReset' }];
|
|
183
|
+
} else {
|
|
184
|
+
this.$ = { type: 'pitchReset' };
|
|
185
|
+
}
|
|
186
|
+
|
|
178
187
|
break;
|
|
179
188
|
case 45: case 46:
|
|
180
189
|
currentDuration = $$[$0-1]; this.$ = noteEvent($$[$0-2], $$[$0-1], $$[$0]);
|
|
@@ -299,13 +308,13 @@ case 85:
|
|
|
299
308
|
currentStaff = Number($$[$0].slice(1, -1)); this.$ = currentStaff;
|
|
300
309
|
break;
|
|
301
310
|
case 86:
|
|
302
|
-
|
|
311
|
+
currentOttava = Number($$[$0]); this.$ = currentOttava;
|
|
303
312
|
break;
|
|
304
313
|
case 87:
|
|
305
|
-
|
|
314
|
+
currentOttava = -Number($$[$0]); this.$ = currentOttava;
|
|
306
315
|
break;
|
|
307
316
|
case 88:
|
|
308
|
-
this.$ = 0;
|
|
317
|
+
currentOttava = 0; this.$ = 0;
|
|
309
318
|
break;
|
|
310
319
|
case 89:
|
|
311
320
|
this.$ = 'up';
|
|
@@ -737,6 +746,7 @@ parse: function parse(input) {
|
|
|
737
746
|
let currentTimeSig = null;
|
|
738
747
|
let currentDuration = { division: 4, dots: 0 }; // default quarter note
|
|
739
748
|
let numericTimeSignature = false; // When true, 4/4 and 2/2 use numeric display instead of C/C|
|
|
749
|
+
let currentOttava = 0; // Current ottava level, resets on newline
|
|
740
750
|
|
|
741
751
|
// Reset parser state - call before each parse
|
|
742
752
|
const resetParserState = () => {
|
|
@@ -745,6 +755,7 @@ parse: function parse(input) {
|
|
|
745
755
|
currentTimeSig = null;
|
|
746
756
|
currentDuration = { division: 4, dots: 0 };
|
|
747
757
|
numericTimeSignature = false;
|
|
758
|
+
currentOttava = 0;
|
|
748
759
|
};
|
|
749
760
|
|
|
750
761
|
// Export reset function
|
package/lib/index.d.ts
CHANGED
|
@@ -3,4 +3,5 @@ export * from "./parser";
|
|
|
3
3
|
export * from "./serializer";
|
|
4
4
|
import * as meiEncoder from "./meiEncoder";
|
|
5
5
|
import * as musicXmlDecoder from "./musicXmlDecoder";
|
|
6
|
-
|
|
6
|
+
import * as lilypondEncoder from "./lilypondEncoder";
|
|
7
|
+
export { meiEncoder, musicXmlDecoder, lilypondEncoder, };
|
package/lib/index.js
CHANGED
|
@@ -3,4 +3,5 @@ export * from "./parser.js";
|
|
|
3
3
|
export * from "./serializer.js";
|
|
4
4
|
import * as meiEncoder from "./meiEncoder.js";
|
|
5
5
|
import * as musicXmlDecoder from "./musicXmlDecoder.js";
|
|
6
|
-
|
|
6
|
+
import * as lilypondEncoder from "./lilypondEncoder.js";
|
|
7
|
+
export { meiEncoder, musicXmlDecoder, lilypondEncoder, };
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lilylet to LilyPond Encoder
|
|
3
|
+
*
|
|
4
|
+
* Converts LilyletDoc to LilyPond (.ly) format.
|
|
5
|
+
* Uses relative pitch mode matching LilyPond's default behavior.
|
|
6
|
+
*/
|
|
7
|
+
import { LilyletDoc } from "./types";
|
|
8
|
+
interface RenderOptions {
|
|
9
|
+
paper?: {
|
|
10
|
+
width?: number | string;
|
|
11
|
+
height?: number | string;
|
|
12
|
+
};
|
|
13
|
+
fontSize?: number;
|
|
14
|
+
withMIDI?: boolean;
|
|
15
|
+
autoBeaming?: boolean;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Encode a complete LilyletDoc to LilyPond format
|
|
19
|
+
*/
|
|
20
|
+
export declare const encode: (doc: LilyletDoc, options?: RenderOptions) => string;
|
|
21
|
+
/**
|
|
22
|
+
* Encode LilyletDoc to minimal LilyPond (music content only, no headers)
|
|
23
|
+
*/
|
|
24
|
+
export declare const encodeMinimal: (doc: LilyletDoc) => string;
|
|
25
|
+
declare const _default: {
|
|
26
|
+
encode: (doc: LilyletDoc, options?: RenderOptions) => string;
|
|
27
|
+
encodeMinimal: (doc: LilyletDoc) => string;
|
|
28
|
+
};
|
|
29
|
+
export default _default;
|