plainscore 0.1.0 → 0.1.1

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 CHANGED
@@ -1,18 +1,25 @@
1
1
  # plainscore
2
2
 
3
- A plain-text score format that a musician can read without docs and an AI can edit line by line. One file holds the music; plainscore turns it into timed note events, MIDI and ABC notation.
3
+ > A plain-text music score. One `.score` file reads like a composer's sketch, edits line by line, and compiles to ABC notation, MIDI and timed note events. TypeScript, no runtime dependencies.
4
+
5
+ ![Manuscript paper and a fountain pen](docs/images/hero.jpg)
6
+
7
+ ![song.score on the left; the sheet plainscore engraves from it on the right](docs/images/score-to-sheet.png)
8
+
9
+ <details>
10
+ <summary><code>song.score</code> as text</summary>
4
11
 
5
12
  ```
6
13
  score 0.1
7
14
 
8
- title Small Waltz in 4
15
+ title Evening Song
9
16
  by You
10
17
 
11
18
  instruments
12
19
  piano piano
13
20
  cello cello
14
21
 
15
- piece waltz Small Waltz
22
+ piece song Evening Song
16
23
  tempo q = 72
17
24
  key G major
18
25
 
@@ -41,71 +48,38 @@ piece waltz Small Waltz
41
48
  tune, comp p, pad 80%, pedal
42
49
  ```
43
50
 
44
- ## What it can say
45
-
46
- - **Pitches as written**, durations `w h q e s` with dots and ties, bars separated by `|`.
47
- - **Chord-relative patterns**: write a figure once with `bass`, `t1`–`t4`, `top`, `upper`, and it follows the chords.
48
- - **Form as an orchestration table**: each section row names the parts that play and how loud (`85%`, `92%-75%`, `bars 3-4`, `on 1 and 3`, `8va`, `in E`).
49
- - **Loop**: `form loop`, or `form loop from A1` for an intro that plays once.
50
- - **Variants**: versions of one piece that share a timeline (`drop P`, `Q for P`, `P <options>`).
51
- - **Doubles**: `part strings violins doubles tune 8vb` plays another part's notes on its own instrument.
52
- - **Pedal, rolls, staggered entries, ad lib.** (seeded random notes), and a **mix** block for playback balance that notation and MIDI ignore.
51
+ </details>
53
52
 
54
- The full reference is [docs/grammar.md](docs/grammar.md). Every score can carry the standard legend (`plainscore legend`) so a reader never needs this README.
53
+ ![The form of examples/bgm.score: each section row names the parts that play, and how loud](docs/images/form.png)
55
54
 
56
- ## Use
55
+ ![One file, four outputs: check, events, ABC, MIDI](docs/images/outputs.png)
57
56
 
58
- ```bash
59
- pnpm add -D plainscore
60
- ```
61
-
62
- ```bash
63
- plainscore check song.score
64
- plainscore abc song.score --piece waltz > song.abc
65
- plainscore midi song.score --piece waltz -o song.mid
66
- plainscore events song.score --variant quiet --seed 7 --passes 2
67
- plainscore legend
68
- ```
57
+ - Install: `pnpm add -D plainscore` (Node 20+).
58
+ - CLI: `plainscore check|abc|midi|events|legend <file> [--piece id] [--variant v] [--seed n] [--passes n] [-o out.mid]`.
59
+ - API: `render(parseScore(text, file), piece, { variant, seed })`, then `toAbc(r)` or `toMidi(r)`.
60
+ - Staves follow `instruments`. The family (`piano harp violins violas cello bass flute oboe clarinet bassoon horn trumpet voice synth`) sets clef, MIDI program and pedal. A piano `lead` gets a Melody staff; `pizz.` gets its own staff.
61
+ - Not in 0.1: meters other than 4/4, tuplets, ties across barlines, tempo changes, hairpins, repeats with endings, imports, percussion.
69
62
 
70
- ```ts
71
- import { parseScore, render } from 'plainscore'
72
- import { toAbc } from 'plainscore/abc'
73
- import { toMidi } from 'plainscore/midi'
63
+ ## Docs
74
64
 
75
- const score = parseScore(text, 'song.score')
76
- const rendering = render(score, 'waltz', { variant: null, seed: 1 })
77
- const abc = toAbc(rendering)
78
- const midi = toMidi(rendering)
79
- ```
65
+ - [Grammar](docs/grammar.md): every keyword of score 0.1, with examples
66
+ - [Legend](src/legend.ts): the legend a score can carry so readers need no docs; `plainscore legend`
67
+ - [llms.txt](llms.txt): this index, for agents
80
68
 
81
- `render` returns plain data: metadata, sections, key changes, every note with its onset in eighths, offset, length, level and velocity, pedal changes, and the ad lib. rules. A player only needs that.
69
+ ## Examples
82
70
 
83
- ## Notation and MIDI
71
+ - [bgm.score](examples/bgm.score): two pieces with variants, loop, ad lib. and mix
72
+ - [road.score](examples/road.score): a full single for piano, harp and strings
84
73
 
85
- Staves come from the declared instruments, in declaration order:
86
-
87
- - each instrument gets a staff, and `pizz.` parts get their own staff right after it;
88
- - a `lead` part on a piano gets a Melody staff on top;
89
- - pianos get a grand staff with pedal marks, and an `inner` part becomes a voice of its own;
90
- - clefs, MIDI programs and pedal come from the instrument's family (`piano harp violins violas cello bass flute oboe clarinet bassoon horn trumpet voice synth`).
91
-
92
- The ABC targets [abcjs](https://www.abcjs.net/) 6.x. plainscore has no runtime dependencies and does not render; pass the ABC to abcjs, or to any ABC tool.
93
-
94
- ## Limits of 0.1
95
-
96
- 4/4 only; the smallest grid is the eighth (with `late s` for sixteenth offsets); no tuplets, ties across barlines, tempo changes, hairpins, articulations beyond `pizz.`/`arco`, repeats with endings, imports or percussion.
97
-
98
- ## Develop
99
-
100
- ```bash
101
- pnpm install
102
- pnpm test
103
- pnpm typecheck
104
- pnpm build
105
- ```
74
+ ## API
106
75
 
107
- `fixtures/` holds the expected ABC, MIDI and events for `examples/`. After an intended output change, run `pnpm test -u` and review the fixture diff.
76
+ - [plainscore](src/index.ts): `parseScore`, `render`, `checkScore`, `layout`, `seeded`
77
+ - [plainscore/abc](src/abc/index.ts): `toAbc(rendering)`, ABC for abcjs 6
78
+ - [plainscore/midi](src/midi.ts): `toMidi(rendering)`, SMF type 1, 480 PPQ, pedal as CC64
79
+ - [plainscore/legend](src/legend.ts): `LEGEND`
108
80
 
109
- ## License
81
+ ## Optional
110
82
 
111
- MIT
83
+ - [Fixtures](fixtures): expected ABC, MIDI and events for the examples; run `pnpm test -u` after an intended change
84
+ - [package.json](package.json): `pnpm test`, `pnpm typecheck`, `pnpm build`
85
+ - [License](LICENSE): MIT
@@ -0,0 +1,183 @@
1
+ # score 0.1 grammar
2
+
3
+ A score is a UTF-8 text file. Indentation carries structure: file-level lines start at column 0, a piece's blocks at 2 spaces, block rows at 4, and form entries deeper than 4. Lines starting with `#` are comments. Anything after ` — ` (an em dash between spaces) on a line is a note to the reader and is ignored.
4
+
5
+ ## File
6
+
7
+ ```
8
+ score 0.1 the first line, always
9
+
10
+ title Small Waltz optional, file-wide
11
+ by You optional; written as "Music by You"
12
+ after A song I love optional; written as "After A song I love"
13
+
14
+ instruments
15
+ piano piano <name> <family>
16
+ strings violins
17
+
18
+ piece waltz Small Waltz <id> <title>; a file can hold several pieces
19
+ …
20
+ ```
21
+
22
+ - Families: `piano harp violins violas cello bass flute oboe clarinet bassoon horn trumpet voice synth`. The family sets the clef, MIDI program, pedal and how notes are engraved. The instrument name is yours.
23
+ - Instrument names and part names must differ.
24
+
25
+ ## Piece header
26
+
27
+ ```
28
+ meter 4/4 only 4/4 in 0.1
29
+ tempo q = 80
30
+ key D major major minor dorian lydian mixolydian
31
+ ```
32
+
33
+ ## Pitches, durations, counts
34
+
35
+ - Pitches sound as written: `C4` is middle C, `F#5`, `Bb3`.
36
+ - Durations: `w h q e s` (whole to sixteenth), `.` dotted (`q.`), `+` ties (`w+s`, `h+q`).
37
+ - `r` is a rest in bar lines.
38
+ - Counts are beats and ands: `1 1& 2 2& 3 3& 4 4&`. `2.3&` means bar 2, the and of 3.
39
+
40
+ ## Chords
41
+
42
+ ```
43
+ chords theme — bass | voicing
44
+ D D2 | D4 F#4 A4
45
+ A/C# C#2 | C#4 E4 A4
46
+ D a symbol alone reuses its last voicing
47
+
48
+ chords stars two bars each one … four, or a number
49
+ Dmaj9(#11) D2 | D3 A3 F#4 C#5 E5 G#5
50
+ ```
51
+
52
+ A section is as long as the chord set it names.
53
+
54
+ ## Parts
55
+
56
+ Every part has a name and, unless each cue names one, an instrument. Header words, in any order:
57
+
58
+ | word | meaning |
59
+ |---|---|
60
+ | `piano`, `violins pizz.` | the instrument, optionally with `pizz.` or `arco` |
61
+ | `p`, `mf` … | the part's dynamic |
62
+ | `overlap e` | each note rings an eighth past its value |
63
+ | `ring w` | each note rings for a whole note |
64
+ | `once` | counts are within the section (`3.2&`), not repeated per chord |
65
+ | `lead` | the tune: breaths leave it ringing; on a piano it gets the Melody staff |
66
+ | `inner` | engraved as a voice of its own on its staff |
67
+ | `doubles P [8vb]` | plays part P's notes on this part's instrument |
68
+ | `ad lib.` | random notes from rules (below) |
69
+
70
+ ### Bars
71
+
72
+ ```
73
+ part tune piano mf overlap e lead
74
+ | F#5 h E5 q D5 q | E5 h. A4 q |
75
+ | mp D6 h B5 q D6 q | … | a dynamic before a note applies from there
76
+ ```
77
+
78
+ Each bar must add up to a whole note.
79
+
80
+ ### Cues
81
+
82
+ One line per entry: `<count> [instrument] <pitches> <duration> [options]`. A cue part repeats with every chord.
83
+
84
+ ```
85
+ part flow piano
86
+ 1 bass w >
87
+ 1& fifth q. soft
88
+ 2& t2 q. soft late s
89
+ 1 chord h soft roll 30ms
90
+ 1 cello bass+8va w+s f
91
+ ```
92
+
93
+ - Chord tones:
94
+ - `bass`; `t1`–`t4` / `v1`–`v6` are voicing tones from low to high; `top` is the highest.
95
+ - `chord` is all of them; `upper` is all but the lowest.
96
+ - `fifth` is the chord tone nearest a fifth above the bass.
97
+ - Shifts: `+5th` (a perfect fifth up, in the chord or not), `+8va`, `+15ma`, `+8vb`, `+15mb`.
98
+ - Options:
99
+ - A dynamic, or a rising roll such as `ppp-mf`.
100
+ - `>` accent, `soft`, `softer`.
101
+ - `roll X`: the notes enter X apart.
102
+ - `late X`: enters X after the count.
103
+ - X is a duration or a time in ms (`30ms`).
104
+ - Pedal: `1 Ped.` presses or changes the sustain pedal; `4& *` lifts it.
105
+
106
+ ### Ad lib.
107
+
108
+ ```
109
+ part sparkle harp ad lib.
110
+ chance 22%
111
+ notes D lydian, D6 to C#7, 8va 30% of the time
112
+ dynamic pppp-pp
113
+ length h.
114
+ timing anywhere within the eighth or sixteenth, quarter
115
+ avoid quote optional: skip eighths where this part plays
116
+ ```
117
+
118
+ ## Dynamics
119
+
120
+ `pppp .10 ppp .16 pp .22 p .32 mp .42 mf .50 f .55`. Accent adds .08, `soft` takes away .07 and `softer` takes away .14.
121
+
122
+ ## Form
123
+
124
+ ```
125
+ form loop from A1
126
+ Intro prelude — 序
127
+ wash mp, stream p 85%, drone pp 85% bars 1-2, pedal, breath
128
+ A1 theme
129
+ flow p 85%, theme 85%, pedal
130
+ A5 theme in E
131
+ flow mp, theme f 8va, pedal
132
+ ```
133
+
134
+ - Header:
135
+ - `form`: plays once.
136
+ - `form loop`: repeats from the top.
137
+ - `form loop from A1`: plays through, then repeats from A1.
138
+ - Each row is `<mark> <chord set> [in <key>]`, then the parts that play, comma-separated.
139
+ - A part not named in a row is silent there. Every part must play somewhere.
140
+ - Part options:
141
+ - A dynamic.
142
+ - `85%` shades the part; `92%-75%` shades it bar by bar.
143
+ - `bars 3-4`.
144
+ - `on 1 and 3`: only notes that start on those beats.
145
+ - A shift: `8va`, `8vb`.
146
+ - `breath`: every part but `lead` and `once` parts stops for the last eighth.
147
+ - `cut`: whatever still rings stops at the downbeat.
148
+ - Both also lift the pedal.
149
+
150
+ ## Variants
151
+
152
+ ```
153
+ variants
154
+ overview
155
+ browse drop stream
156
+ read drop stream, sparse for flow, melody on 1 and 3
157
+ ```
158
+
159
+ The first variant plays the form as written. The others edit every form row:
160
+
161
+ - `drop P`: P is silent everywhere.
162
+ - `Q for P`: Q plays wherever P was named, with P's options.
163
+ - `P <options>`: adds options to P wherever it plays.
164
+
165
+ All variants share one timeline.
166
+
167
+ ## Mix
168
+
169
+ ```
170
+ mix — playback only; notation and MIDI ignore it
171
+ violin-theme +13 dB attack 200ms
172
+ piano 75%
173
+ ```
174
+
175
+ Rows name a part or an instrument.
176
+
177
+ ## Errors
178
+
179
+ Every error names the file and line, and says what to write instead:
180
+
181
+ ```
182
+ song.score line 18: "+3" is mixing; put it in the piece's mix block
183
+ ```
package/llms.txt ADDED
@@ -0,0 +1,72 @@
1
+ # plainscore
2
+
3
+ > A plain-text music score. One `.score` file reads like a composer's sketch, edits line by line, and compiles to ABC notation, MIDI and timed note events. TypeScript, no runtime dependencies.
4
+
5
+ ```
6
+ score 0.1
7
+
8
+ title Evening Song
9
+ by You
10
+
11
+ instruments
12
+ piano piano
13
+ cello cello
14
+
15
+ piece song Evening Song
16
+ tempo q = 72
17
+ key G major
18
+
19
+ chords verse — bass | voicing
20
+ G G2 | B3 D4 G4
21
+ D/F# F#2 | A3 D4 F#4
22
+ Em E2 | B3 E4 G4
23
+ C C3 | C4 E4 G4
24
+
25
+ part tune piano mf overlap e lead
26
+ | B4 h A4 q G4 q | A4 w | G4 h B4 h | C5 w |
27
+
28
+ part comp piano
29
+ 1 bass w >
30
+ 2 upper q soft
31
+ 3& upper e softer
32
+
33
+ part pad cello mp
34
+ 1 bass+8va w
35
+
36
+ part pedal
37
+ 1 Ped.
38
+
39
+ form loop
40
+ A verse
41
+ tune, comp p, pad 80%, pedal
42
+ ```
43
+
44
+ - Install: `pnpm add -D plainscore` (Node 20+).
45
+ - CLI: `plainscore check|abc|midi|events|legend <file> [--piece id] [--variant v] [--seed n] [--passes n] [-o out.mid]`.
46
+ - API: `render(parseScore(text, file), piece, { variant, seed })`, then `toAbc(r)` or `toMidi(r)`.
47
+ - Staves follow `instruments`. The family (`piano harp violins violas cello bass flute oboe clarinet bassoon horn trumpet voice synth`) sets clef, MIDI program and pedal. A piano `lead` gets a Melody staff; `pizz.` gets its own staff.
48
+ - Not in 0.1: meters other than 4/4, tuplets, ties across barlines, tempo changes, hairpins, repeats with endings, imports, percussion.
49
+
50
+ ## Docs
51
+
52
+ - [Grammar](https://raw.githubusercontent.com/Innei/plainscore/main/docs/grammar.md): every keyword of score 0.1, with examples
53
+ - [Legend](https://raw.githubusercontent.com/Innei/plainscore/main/src/legend.ts): the legend a score can carry so readers need no docs; `plainscore legend`
54
+ - [README](https://github.com/Innei/plainscore#readme): the same index with pictures
55
+
56
+ ## Examples
57
+
58
+ - [bgm.score](https://raw.githubusercontent.com/Innei/plainscore/main/examples/bgm.score): two pieces with variants, loop, ad lib. and mix
59
+ - [road.score](https://raw.githubusercontent.com/Innei/plainscore/main/examples/road.score): a full single for piano, harp and strings
60
+
61
+ ## API
62
+
63
+ - [plainscore](https://raw.githubusercontent.com/Innei/plainscore/main/src/index.ts): `parseScore`, `render`, `checkScore`, `layout`, `seeded`
64
+ - [plainscore/abc](https://raw.githubusercontent.com/Innei/plainscore/main/src/abc/index.ts): `toAbc(rendering)`, ABC for abcjs 6
65
+ - [plainscore/midi](https://raw.githubusercontent.com/Innei/plainscore/main/src/midi.ts): `toMidi(rendering)`, SMF type 1, 480 PPQ, pedal as CC64
66
+ - [plainscore/legend](https://raw.githubusercontent.com/Innei/plainscore/main/src/legend.ts): `LEGEND`
67
+
68
+ ## Optional
69
+
70
+ - [Fixtures](https://github.com/Innei/plainscore/tree/main/fixtures): expected ABC, MIDI and events for the examples; run `pnpm test -u` after an intended change
71
+ - [package.json](https://raw.githubusercontent.com/Innei/plainscore/main/package.json): `pnpm test`, `pnpm typecheck`, `pnpm build`
72
+ - [License](https://raw.githubusercontent.com/Innei/plainscore/main/LICENSE): MIT
package/package.json CHANGED
@@ -1,8 +1,22 @@
1
1
  {
2
2
  "name": "plainscore",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "A plain-text score format a musician can read and an AI can edit, with MIDI and ABC export.",
5
5
  "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/Innei/plainscore.git"
9
+ },
10
+ "homepage": "https://github.com/Innei/plainscore#readme",
11
+ "keywords": [
12
+ "music",
13
+ "score",
14
+ "notation",
15
+ "abc",
16
+ "midi",
17
+ "dsl",
18
+ "composer"
19
+ ],
6
20
  "type": "module",
7
21
  "engines": {
8
22
  "node": ">=20"
@@ -17,7 +31,9 @@
17
31
  "./legend": "./dist/legend.js"
18
32
  },
19
33
  "files": [
20
- "dist"
34
+ "dist",
35
+ "docs/grammar.md",
36
+ "llms.txt"
21
37
  ],
22
38
  "devDependencies": {
23
39
  "@types/node": "^24.19.2",