abcnotes 0.1.0__py3-none-any.whl

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.
@@ -0,0 +1,282 @@
1
+ Metadata-Version: 2.4
2
+ Name: abcnotes
3
+ Version: 0.1.0
4
+ Summary: Parse, validate and expand tunes in ABC music notation
5
+ Author: Luke Campagnola
6
+ Author-email: John McBride <jmmcbride@protonmail.com>
7
+ Maintainer-email: John McBride <jmmcbride@protonmail.com>
8
+ License-Expression: MIT
9
+ Project-URL: Homepage, https://github.com/jomimc/abcnotes
10
+ Project-URL: Issues, https://github.com/jomimc/abcnotes/issues
11
+ Keywords: abc,music,notation,folk,parser
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Science/Research
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3 :: Only
16
+ Classifier: Topic :: Multimedia :: Sound/Audio
17
+ Classifier: Topic :: Text Processing :: Markup
18
+ Requires-Python: >=3.9
19
+ Description-Content-Type: text/markdown
20
+ License-File: LICENSE.txt
21
+ Provides-Extra: test
22
+ Requires-Dist: pytest; extra == "test"
23
+ Dynamic: license-file
24
+
25
+ abcnotes
26
+ ========
27
+
28
+ A parser for tunes written in [ABC music notation](https://abcnotation.com/),
29
+ for analysing the music rather than typesetting it. It reads a tune into
30
+ tokens, gives each note a pitch and a duration, writes out repeats and
31
+ variant endings in playback order, and reports problems in a tune's ABC.
32
+
33
+ It is a single module, `abcnotes.py`, with no dependencies. Python 3.9 or
34
+ later. MIT licence.
35
+
36
+
37
+ Installation
38
+ ------------
39
+
40
+ ```bash
41
+ pip install abcnotes
42
+ ```
43
+
44
+ or, from a clone of this repository:
45
+
46
+ ```bash
47
+ pip install .
48
+ ```
49
+
50
+
51
+ Quick start
52
+ -----------
53
+
54
+ ### Parse a tune
55
+
56
+ ```python
57
+ from abcnotes import Tune
58
+
59
+ abc = """X: 1
60
+ T: The Road To Lisdoonvarna
61
+ R: slide
62
+ M: 12/8
63
+ L: 1/8
64
+ K: Edor
65
+ E2B B2A B2c d2A|F2A ABA D2E FED|E2B B2A B2c d3|cdc B2A B2E E3:|
66
+ |:e2f gfe d2B Bcd|c2A ABc d2B B3|e2f gfe d2B Bcd|cdc B2A B2E E3:||
67
+ """
68
+
69
+ tune = Tune(abc=abc)
70
+ print(tune.header['tune title'])
71
+ print(tune.header['key'], tune.header['meter'], tune.header['unit note length'])
72
+ print(len(tune.notes), len(tune.bars))
73
+ ```
74
+
75
+ ```
76
+ The Road To Lisdoonvarna
77
+ Edor 12/8 1/8
78
+ 69 10
79
+ ```
80
+
81
+ `tune.header` is keyed by the full field names from the ABC standard
82
+ (`'key'`, `'meter'`, `'unit note length'`, `'reference number'`, ...), with
83
+ the values as written. `tune.fields` keeps every field in order, including
84
+ repeated ones.
85
+
86
+ ### Notes, pitches and durations
87
+
88
+ ```python
89
+ for note in tune.notes[:6]:
90
+ print(note.pitch.name, note.pitch.abs_value, note.duration, note.abs_duration)
91
+ ```
92
+
93
+ ```
94
+ E 4 2.0 0.25
95
+ B 11 1.0 0.125
96
+ B 11 2.0 0.25
97
+ A 9 1.0 0.125
98
+ B 11 2.0 0.25
99
+ C# 13 1.0 0.125
100
+ ```
101
+
102
+ `note.pitch.abs_value` is the pitch in semitones relative to middle C, with
103
+ the key signature applied (the `c` in E dorian is a C sharp). `note.duration`
104
+ is in units of the `L:` field and `note.abs_duration` is a fraction of a
105
+ whole note. Broken rhythms (`A>B`), chords (`[DF]3`) and tuplets (`(3abc`)
106
+ are resolved in these values.
107
+
108
+ ### Expand repeats
109
+
110
+ `tune.expand_repeats()` returns the bars in playback order. Each bar is a
111
+ list of tokens, so the notes of the tune as played are:
112
+
113
+ ```python
114
+ from abcnotes import Note, Tune
115
+
116
+ abc = """X: 2
117
+ T: Endings
118
+ M: 4/4
119
+ L: 1/4
120
+ K: G
121
+ |: G A B c |1 d2 d2 :|2 g2 g2 |]
122
+ """
123
+
124
+ tune = Tune(abc=abc)
125
+ for bar in tune.expand_repeats():
126
+ names = [token.pitch.name for token in bar if isinstance(token, Note)]
127
+ if names:
128
+ print(' '.join(names))
129
+ ```
130
+
131
+ ```
132
+ G A B C
133
+ D D
134
+ G A B C
135
+ G G
136
+ ```
137
+
138
+ If the repeat structure is ambiguous (an ending number that is missing or
139
+ repeated, a `|:` that is never closed, endings with no repeat sign, ...) a
140
+ `RepeatError` is raised. Pass `strict=False` to get the most likely reading
141
+ instead; `check_repeats(tune.bars)` lists the problems without raising.
142
+
143
+ ### Validate a file
144
+
145
+ ```python
146
+ import abcnotes
147
+
148
+ text = """X: 1
149
+ T: First
150
+ M: 4/4
151
+ L: 1/8
152
+ K: D
153
+ D2 FA d2 fd | A2 F2 e2 | d2-f2 a2 f2 | d4 z4 |]
154
+
155
+ X: 2
156
+ T: Second
157
+ K: G
158
+ GBd g |]
159
+ """
160
+
161
+ for abc in abcnotes.split_tunes(text):
162
+ for issue in abcnotes.validate(abc):
163
+ print(issue)
164
+ ```
165
+
166
+ ```
167
+ Issue(line=6, char=26, message='tie from d2 to a different note f2 (a slur was probably meant)')
168
+ Issue(line=6, char=15, message='bar 2 has length 3/4, expected 1')
169
+ ```
170
+
171
+ `split_tunes` cuts the text of an ABC file into one string per tune, with
172
+ any file-header fields prepended to each. `validate` returns a list of
173
+ `Issue(line, char, message)` namedtuples with 1-based positions in the
174
+ tune's text (`None` when the issue has no single position). It checks:
175
+
176
+ * required fields (`X:`, `T:`, `K:`) and header lines that are not fields;
177
+ * characters the tokenizer cannot read;
178
+ * unbalanced chord brackets, grace-note braces and slurs;
179
+ * ties between different notes;
180
+ * repeat structure (the same problems that make `expand_repeats` raise);
181
+ * `P:` parts in the header that are not in the body, and vice versa;
182
+ * bar lengths against the meter, tolerating pickups.
183
+
184
+
185
+ API overview
186
+ ------------
187
+
188
+ Everything is in the `abcnotes` module.
189
+
190
+ | Name | What it is |
191
+ | --- | --- |
192
+ | `Tune(abc=text)` | Parse one tune from its ABC text. |
193
+ | `Tune(json=record)` | Parse a record from the [TheSession](https://thesession.org) data dump or API: a dict with keys `tune_id`, `setting_id`, `name`, `type`, `meter`, `mode` and `abc`. |
194
+ | `Tune(abc, strict=False)` | Unreadable characters become `Unknown` tokens instead of raising. |
195
+ | `tune.header` | Dict of header fields keyed by full name (`'key'`, `'meter'`, `'unit note length'`, ...). |
196
+ | `tune.fields` | All header fields in order, as `(name, value)` pairs. |
197
+ | `tune.tokens` | The body as a flat list of tokens. |
198
+ | `tune.notes` | The `Note` tokens only. |
199
+ | `tune.bars` | The tokens grouped by bar. Each bar starts with the `BarLine` that opens it, except for a pickup before the first bar line. |
200
+ | `tune.parts` | `(part name, bars)` pairs, split where a `P:` field appears in the body. |
201
+ | `tune.expand_repeats(strict=True)` | Bars in playback order, following the `P:` header field if there is one. |
202
+ | `tune.validate()` | Problems with the tune, as a list of `Issue`. |
203
+ | `Note` | `.pitch` (a `Pitch`, with `.name` and `.abs_value` in semitones from middle C), `.duration` (in units of `L:`), `.abs_duration` (fraction of a whole note), `.length` (as a `(numerator, denominator)` pair), `.tie`, `.grace`, `.accidental`, `.bar_accidental`, `.key`, `.time_sig`. |
204
+ | `Rest` | `.duration`, `.abs_duration` and `.length` as for `Note`; `.symbol` is one of `z Z x X`. |
205
+ | `BarLine` | `.repeat_start`, `.repeat_end`, `.endings` (list of pass numbers, or `None`) and `.double`. |
206
+ | `Key` | `Key('Edor')`: `.root`, `.mode`, `.key_signature`, `.accidentals` (including explicit ones such as `K:D ^g`), `.relative_ionian`. |
207
+ | `TimeSignature` | Meter, unit note length and tempo in force at a note (`note.time_sig`). |
208
+ | `expand_repeats(bars, strict=True)` | The module-level function behind `tune.expand_repeats`. |
209
+ | `check_repeats(bars)` | Repeat-structure problems as `(bar index, message)` pairs. |
210
+ | `RepeatError` | Raised by `expand_repeats` when the structure is ambiguous. |
211
+ | `validate(abc)` | Parse with `strict=False` and return `tune.validate()`. |
212
+ | `Issue` | `namedtuple('Issue', 'line char message')`. |
213
+ | `split_tunes(text)` | Cut the text of an ABC file into one string per tune. |
214
+ | `parse_parts(spec)` | Expand a `P:` field: `'(AB)2.C'` becomes `['A', 'B', 'A', 'B', 'C']`. |
215
+
216
+ Other token classes are `Space`, `Newline`, `Continuation`, `Slur`, `Tie`,
217
+ `Tuplet`, `ChordBracket`, `ChordSymbol`, `Annotation`, `Decoration`,
218
+ `GracenoteBrace`, `VoiceOverlay`, `BodyField`, `InlineField`, `Ignored` and
219
+ `Unknown`.
220
+
221
+ Some points of behaviour:
222
+
223
+ * An accidental lasts until the end of the bar, for the same note letter in
224
+ every octave, as the standard says; `I:propagate-accidentals` is honoured.
225
+ * Explicit accidentals in the `K:` field (`K:D ^g`, `K:C exp ^f`) are
226
+ applied.
227
+ * `K:`, `M:`, `L:` and `Q:` fields in the body, and inline fields such as
228
+ `[K:G]`, take effect from where they appear.
229
+ * Repeat expansion follows sections 4.8 to 4.10 of the ABC 2.1 standard:
230
+ `|1`, `[1,3` and `[1-3` endings, `::`, `|::` (three passes) and `P:`
231
+ parts. A `:|` with no matching `|:` restarts from the latest of the start
232
+ of the tune, a double bar and the previous `:|`.
233
+
234
+
235
+ Limitations
236
+ -----------
237
+
238
+ * Multi-voice tunes (`V:`) are parsed as a single line of music. Bar lengths
239
+ are not checked for them and `expand_repeats` refuses them unless
240
+ `strict=False`.
241
+ * `D.C.`, `D.S.`, coda and fine jumps are not followed.
242
+ * Lyrics (`w:`) are not aligned to notes.
243
+
244
+
245
+ Status
246
+ ------
247
+
248
+ Alpha. The parser has been checked against the whole TheSession corpus and
249
+ the Norbeck, Cobbs, Nottingham and Chambers collections, and repeat
250
+ expansion has been cross-checked against music21. The API may still change.
251
+
252
+
253
+ Development
254
+ -----------
255
+
256
+ Run the tests from the root of the repository:
257
+
258
+ ```bash
259
+ python -m pytest
260
+ ```
261
+
262
+ `pyproject.toml` puts the repository root on the path for pytest, so no
263
+ install is needed.
264
+
265
+
266
+ History and credits
267
+ -------------------
268
+
269
+ abcnotes started as [pyabc](https://github.com/campagnola/pyabc), written by
270
+ Luke Campagnola in 2014 and released under the MIT licence as a pre-alpha.
271
+ John McBride forked it to read the TheSession data set and fixed and
272
+ extended it. In September 2026, in
273
+ [issue #31](https://github.com/campagnola/pyabc/issues/31) of the original
274
+ repository, Luke Campagnola agreed that the fork becomes the maintained
275
+ version under a new name, published to PyPI, and that the original
276
+ repository will point here.
277
+
278
+
279
+ Licence
280
+ -------
281
+
282
+ MIT. See `LICENSE.txt`.
@@ -0,0 +1,6 @@
1
+ abcnotes.py,sha256=WW8araiK7-IMf6niX_dPREnNghi7wpQDSk8Zu9N91kw,60816
2
+ abcnotes-0.1.0.dist-info/licenses/LICENSE.txt,sha256=hPhvKiUCRagmalAQG6Rg43U1BTl9juX7gsFx_Pi6Keg,1072
3
+ abcnotes-0.1.0.dist-info/METADATA,sha256=HMCs_jy3zoOcR4J7kTeJfw0iX6_tuEyAQN2K2DWJsck,9371
4
+ abcnotes-0.1.0.dist-info/WHEEL,sha256=mOdXR9C3wMVov7cSY8PY-XCzo3SmmWCHvGQr5csJoao,91
5
+ abcnotes-0.1.0.dist-info/top_level.txt,sha256=uaGmRhjA_I0LKR0CCleKThNZXVMOGyxE975EDBFovPI,9
6
+ abcnotes-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (84.2.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,9 @@
1
+ Copyright 2018 Luke Campagnola
2
+
3
+ The MIT License
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5
+
6
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7
+
8
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
9
+
@@ -0,0 +1 @@
1
+ abcnotes