kernpy 0.0.2__py3-none-any.whl → 1.0.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.
- kernpy/__init__.py +215 -0
- kernpy/__main__.py +217 -0
- kernpy/core/__init__.py +119 -0
- kernpy/core/_io.py +48 -0
- kernpy/core/base_antlr_importer.py +61 -0
- kernpy/core/base_antlr_spine_parser_listener.py +196 -0
- kernpy/core/basic_spine_importer.py +43 -0
- kernpy/core/document.py +965 -0
- kernpy/core/dyn_importer.py +30 -0
- kernpy/core/dynam_spine_importer.py +42 -0
- kernpy/core/error_listener.py +51 -0
- kernpy/core/exporter.py +535 -0
- kernpy/core/fing_spine_importer.py +42 -0
- kernpy/core/generated/kernSpineLexer.interp +444 -0
- kernpy/core/generated/kernSpineLexer.py +535 -0
- kernpy/core/generated/kernSpineLexer.tokens +236 -0
- kernpy/core/generated/kernSpineParser.interp +425 -0
- kernpy/core/generated/kernSpineParser.py +9954 -0
- kernpy/core/generated/kernSpineParser.tokens +236 -0
- kernpy/core/generated/kernSpineParserListener.py +1200 -0
- kernpy/core/generated/kernSpineParserVisitor.py +673 -0
- kernpy/core/generic.py +426 -0
- kernpy/core/gkern.py +526 -0
- kernpy/core/graphviz_exporter.py +89 -0
- kernpy/core/harm_spine_importer.py +41 -0
- kernpy/core/import_humdrum_old.py +853 -0
- kernpy/core/importer.py +285 -0
- kernpy/core/importer_factory.py +43 -0
- kernpy/core/kern_spine_importer.py +73 -0
- kernpy/core/mens_spine_importer.py +23 -0
- kernpy/core/mhxm_spine_importer.py +44 -0
- kernpy/core/pitch_models.py +338 -0
- kernpy/core/root_spine_importer.py +58 -0
- kernpy/core/spine_importer.py +45 -0
- kernpy/core/text_spine_importer.py +43 -0
- kernpy/core/tokenizers.py +239 -0
- kernpy/core/tokens.py +2011 -0
- kernpy/core/transposer.py +300 -0
- kernpy/io/__init__.py +14 -0
- kernpy/io/public.py +355 -0
- kernpy/polish_scores/__init__.py +13 -0
- kernpy/polish_scores/download_polish_dataset.py +357 -0
- kernpy/polish_scores/iiif.py +47 -0
- kernpy/test_grammar.sh +22 -0
- kernpy/util/__init__.py +14 -0
- kernpy/util/helpers.py +55 -0
- kernpy/util/store_cache.py +35 -0
- kernpy/visualize_analysis.sh +23 -0
- kernpy-1.0.0.dist-info/METADATA +501 -0
- kernpy-1.0.0.dist-info/RECORD +51 -0
- {kernpy-0.0.2.dist-info → kernpy-1.0.0.dist-info}/WHEEL +1 -2
- kernpy/example.py +0 -1
- kernpy-0.0.2.dist-info/LICENSE +0 -19
- kernpy-0.0.2.dist-info/METADATA +0 -19
- kernpy-0.0.2.dist-info/RECORD +0 -7
- kernpy-0.0.2.dist-info/top_level.txt +0 -1
kernpy/core/importer.py
ADDED
@@ -0,0 +1,285 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
import csv
|
4
|
+
import io
|
5
|
+
from copy import copy
|
6
|
+
from pathlib import Path
|
7
|
+
from typing import List, Optional
|
8
|
+
|
9
|
+
from kernpy.core.tokens import TokenCategory, SignatureToken, MetacommentToken, HeaderToken, SpineOperationToken, \
|
10
|
+
FieldCommentToken, ErrorToken, \
|
11
|
+
BoundingBoxToken, SPINE_OPERATIONS, HEADERS, Token
|
12
|
+
from kernpy.core.document import Document, MultistageTree, BoundingBoxMeasures
|
13
|
+
from kernpy.core.importer_factory import createImporter
|
14
|
+
|
15
|
+
|
16
|
+
class Importer:
|
17
|
+
"""
|
18
|
+
Importer class.
|
19
|
+
|
20
|
+
Use this class to import the content from a file or a string to a `Document` object.
|
21
|
+
"""
|
22
|
+
def __init__(self):
|
23
|
+
"""
|
24
|
+
Create an instance of the importer.
|
25
|
+
|
26
|
+
Raises:
|
27
|
+
Exception: If the importer content is not a valid **kern file.
|
28
|
+
|
29
|
+
Examples:
|
30
|
+
# Create the importer
|
31
|
+
>>> importer = Importer()
|
32
|
+
|
33
|
+
# Import the content from a file
|
34
|
+
>>> document = importer.import_file('file.krn')
|
35
|
+
|
36
|
+
# Import the content from a string
|
37
|
+
>>> document = importer.import_string("**kern\n*clefF4\nc4\n4d\n4e\n4f\n*-")
|
38
|
+
"""
|
39
|
+
self.last_measure_number = None
|
40
|
+
self.last_bounding_box = None
|
41
|
+
self.errors = []
|
42
|
+
|
43
|
+
self._tree = MultistageTree()
|
44
|
+
self._document = Document(self._tree)
|
45
|
+
self._importers = {}
|
46
|
+
self._header_row_number = None
|
47
|
+
self._row_number = 1
|
48
|
+
self._tree_stage = 0
|
49
|
+
self._next_stage_parents = None
|
50
|
+
self._prev_stage_parents = None
|
51
|
+
self._last_node_previous_to_header = self._tree.root
|
52
|
+
|
53
|
+
@staticmethod
|
54
|
+
def get_last_spine_operator(parent):
|
55
|
+
if parent is None:
|
56
|
+
return None
|
57
|
+
elif isinstance(parent.token, SpineOperationToken):
|
58
|
+
return parent
|
59
|
+
else:
|
60
|
+
return parent.last_spine_operator_node
|
61
|
+
|
62
|
+
#TODO Documentar cómo propagamos los header_node y last_spine_operator_node...
|
63
|
+
def run(self, reader) -> Document:
|
64
|
+
for row in reader:
|
65
|
+
if len(row) <= 0:
|
66
|
+
# Found an empty row, usually the last one. Ignore it.
|
67
|
+
continue
|
68
|
+
|
69
|
+
self._tree_stage = self._tree_stage + 1
|
70
|
+
is_barline = False
|
71
|
+
if self._next_stage_parents:
|
72
|
+
self._prev_stage_parents = copy(self._next_stage_parents)
|
73
|
+
self._next_stage_parents = []
|
74
|
+
|
75
|
+
if row[0].startswith("!!"):
|
76
|
+
self._compute_metacomment_token(row[0].strip())
|
77
|
+
else:
|
78
|
+
for icolumn, column in enumerate(row):
|
79
|
+
if column.startswith("**"):
|
80
|
+
self._compute_header_token(icolumn, column)
|
81
|
+
# go to next row
|
82
|
+
continue
|
83
|
+
|
84
|
+
if column in SPINE_OPERATIONS:
|
85
|
+
self._compute_spine_operator_token(icolumn, column, row)
|
86
|
+
else: # column is not a spine operation
|
87
|
+
if column.startswith("!"):
|
88
|
+
token = FieldCommentToken(column)
|
89
|
+
else:
|
90
|
+
if self._prev_stage_parents is None:
|
91
|
+
raise ValueError(f'Any spine header found in the column #{icolumn}. '
|
92
|
+
f'Expected a previous line with valid content. '
|
93
|
+
f'The token in column #{icolumn} and row #{self._row_number - 1}'
|
94
|
+
f' was not created correctly. Error detected in '
|
95
|
+
f'column #{icolumn} in row #{self._row_number}. '
|
96
|
+
f'Found {column}. ')
|
97
|
+
if icolumn >= len(self._prev_stage_parents):
|
98
|
+
# TODO: Try to fix the kern in runtime. Add options to public API
|
99
|
+
# continue # ignore the column
|
100
|
+
raise ValueError(f'Wrong columns number in row {self._row_number}. '
|
101
|
+
f'The token in column #{icolumn} and row #{self._row_number}'
|
102
|
+
f' has more columns than expected in its row. '
|
103
|
+
f'Expected {len(self._prev_stage_parents)} columns '
|
104
|
+
f'but found {len(row)}.')
|
105
|
+
parent = self._prev_stage_parents[icolumn]
|
106
|
+
if not parent:
|
107
|
+
raise Exception(f'Cannot find a parent node for column #{icolumn} in row {self._row_number}')
|
108
|
+
if not parent.header_node:
|
109
|
+
raise Exception(f'Cannot find a header node for column #{icolumn} in row {self._row_number}')
|
110
|
+
importer = self._importers.get(parent.header_node.token.encoding)
|
111
|
+
if not importer:
|
112
|
+
raise Exception(f'Cannot find an importer for header {parent.header_node.token.encoding}')
|
113
|
+
try:
|
114
|
+
token = importer.import_token(column)
|
115
|
+
except Exception as error:
|
116
|
+
token = ErrorToken(column, self._row_number, str(error))
|
117
|
+
self.errors.append(token)
|
118
|
+
if not token:
|
119
|
+
raise Exception(
|
120
|
+
f'No token generated for input {column} in row number #{self._row_number} using importer {importer}')
|
121
|
+
|
122
|
+
parent = self._prev_stage_parents[icolumn]
|
123
|
+
node = self._tree.add_node(self._tree_stage, parent, token, self.get_last_spine_operator(parent), parent.last_signature_nodes, parent.header_node)
|
124
|
+
self._next_stage_parents.append(node)
|
125
|
+
|
126
|
+
if (token.category == TokenCategory.BARLINES
|
127
|
+
or TokenCategory.is_child(child=token.category, parent=TokenCategory.CORE)
|
128
|
+
and len(self._document.measure_start_tree_stages) == 0):
|
129
|
+
is_barline = True
|
130
|
+
elif isinstance(token, BoundingBoxToken):
|
131
|
+
self.handle_bounding_box(self._document, token)
|
132
|
+
elif isinstance(token, SignatureToken):
|
133
|
+
node.last_signature_nodes.update(node)
|
134
|
+
|
135
|
+
if is_barline:
|
136
|
+
self._document.measure_start_tree_stages.append(self._tree_stage)
|
137
|
+
self.last_measure_number = len(self._document.measure_start_tree_stages)
|
138
|
+
if self.last_bounding_box:
|
139
|
+
self.last_bounding_box.to_measure = self.last_measure_number
|
140
|
+
self._row_number = self._row_number + 1
|
141
|
+
return self._document
|
142
|
+
|
143
|
+
def handle_bounding_box(self, document: Document, token: BoundingBoxToken):
|
144
|
+
page_number = token.page_number
|
145
|
+
last_page_bb = document.page_bounding_boxes.get(page_number)
|
146
|
+
if last_page_bb is None:
|
147
|
+
if self.last_measure_number is None:
|
148
|
+
self.last_measure_number = 0
|
149
|
+
self.last_bounding_box = BoundingBoxMeasures(token.bounding_box, self.last_measure_number,
|
150
|
+
self.last_measure_number)
|
151
|
+
document.page_bounding_boxes[page_number] = self.last_bounding_box
|
152
|
+
else:
|
153
|
+
last_page_bb.bounding_box.extend(token.bounding_box)
|
154
|
+
last_page_bb.to_measure = self.last_measure_number
|
155
|
+
|
156
|
+
def import_file(self, file_path: Path) -> Document:
|
157
|
+
"""
|
158
|
+
Import the content from the importer to the file.
|
159
|
+
Args:
|
160
|
+
file_path: The path to the file.
|
161
|
+
|
162
|
+
Returns:
|
163
|
+
Document - The document with the imported content.
|
164
|
+
|
165
|
+
Examples:
|
166
|
+
# Create the importer and read the file
|
167
|
+
>>> importer = Importer()
|
168
|
+
>>> importer.import_file('file.krn')
|
169
|
+
"""
|
170
|
+
with open(file_path, 'r', newline='', encoding='utf-8', errors='ignore') as file:
|
171
|
+
reader = csv.reader(file, delimiter='\t')
|
172
|
+
return self.run(reader)
|
173
|
+
|
174
|
+
def import_string(self, text: str) -> Document:
|
175
|
+
"""
|
176
|
+
Import the content from the content of the score in string format.
|
177
|
+
|
178
|
+
Args:
|
179
|
+
text: The content of the score in string format.
|
180
|
+
|
181
|
+
Returns:
|
182
|
+
Document - The document with the imported content.
|
183
|
+
|
184
|
+
Examples:
|
185
|
+
# Create the importer and read the file
|
186
|
+
>>> importer = Importer()
|
187
|
+
>>> importer.import_string("**kern\n*clefF4\nc4\n4d\n4e\n4f\n*-")
|
188
|
+
# Read the content from a file
|
189
|
+
>>> with open('file.krn', 'r', newline='', encoding='utf-8', errors='ignore') as f: # We encourage you to use these open file options
|
190
|
+
>>> content = f.read()
|
191
|
+
>>> importer.import_string(content)
|
192
|
+
>>> document = importer.import_string(content)
|
193
|
+
"""
|
194
|
+
lines = text.splitlines()
|
195
|
+
reader = csv.reader(lines, delimiter='\t')
|
196
|
+
return self.run(reader)
|
197
|
+
|
198
|
+
def get_error_messages(self) -> str:
|
199
|
+
"""
|
200
|
+
Get the error messages of the importer.
|
201
|
+
|
202
|
+
Returns: str - The error messages split by a new line character.
|
203
|
+
|
204
|
+
Examples:
|
205
|
+
# Create the importer and read the file
|
206
|
+
>>> importer = Importer()
|
207
|
+
>>> importer.import_file(Path('file.krn'))
|
208
|
+
>>> print(importer.get_error_messages())
|
209
|
+
'Error: Invalid token in row 1'
|
210
|
+
"""
|
211
|
+
result = ''
|
212
|
+
for err in self.errors:
|
213
|
+
result += str(err)
|
214
|
+
result += '\n'
|
215
|
+
return result
|
216
|
+
|
217
|
+
def has_errors(self) -> bool:
|
218
|
+
"""
|
219
|
+
Check if the importer has any errors.
|
220
|
+
|
221
|
+
Returns: bool - True if the importer has errors, False otherwise.
|
222
|
+
|
223
|
+
Examples:
|
224
|
+
# Create the importer and read the file
|
225
|
+
>>> importer = Importer()
|
226
|
+
>>> importer.import_file(Path('file.krn')) # file.krn has an error
|
227
|
+
>>> print(importer.has_errors())
|
228
|
+
True
|
229
|
+
>>> importer.import_file(Path('file2.krn')) # file2.krn has no errors
|
230
|
+
>>> print(importer.has_errors())
|
231
|
+
False
|
232
|
+
"""
|
233
|
+
return len(self.errors) > 0
|
234
|
+
|
235
|
+
def _compute_metacomment_token(self, raw_token: str):
|
236
|
+
token = MetacommentToken(raw_token)
|
237
|
+
if self._header_row_number is None:
|
238
|
+
node = self._tree.add_node(self._tree_stage, self._last_node_previous_to_header, token, None, None, None)
|
239
|
+
self._last_node_previous_to_header = node
|
240
|
+
else:
|
241
|
+
for parent in self._prev_stage_parents:
|
242
|
+
node = self._tree.add_node(self._tree_stage, parent, token, self.get_last_spine_operator(parent), parent.last_signature_nodes, parent.header_node) # the same reference for all spines - TODO Recordar documentarlo
|
243
|
+
self._next_stage_parents.append(node)
|
244
|
+
|
245
|
+
def _compute_header_token(self, column_index: int, column_content: str):
|
246
|
+
if self._header_row_number is not None and self._header_row_number != self._row_number:
|
247
|
+
raise Exception(
|
248
|
+
f"Several header rows not supported, there is a header row in #{self._header_row_number} and another in #{self._row_number} ")
|
249
|
+
|
250
|
+
# it's a spine header
|
251
|
+
self._document.header_stage = self._tree_stage
|
252
|
+
importer = self._importers.get(column_content)
|
253
|
+
if not importer:
|
254
|
+
importer = createImporter(column_content)
|
255
|
+
self._importers[column_content] = importer
|
256
|
+
|
257
|
+
token = HeaderToken(column_content, spine_id=column_index)
|
258
|
+
node = self._tree.add_node(self._tree_stage, self._last_node_previous_to_header, token, None, None)
|
259
|
+
node.header_node = node # this value will be propagated
|
260
|
+
self._next_stage_parents.append(node)
|
261
|
+
|
262
|
+
def _compute_spine_operator_token(self, column_index: int, column_content: str, row: List[str]):
|
263
|
+
token = SpineOperationToken(column_content)
|
264
|
+
|
265
|
+
if column_index >= len(self._prev_stage_parents):
|
266
|
+
raise Exception(f'Expected at least {column_index+1} parents in row {self._row_number}, but found {len(self._prev_stage_parents)}: {row}')
|
267
|
+
|
268
|
+
parent = self._prev_stage_parents[column_index]
|
269
|
+
node = self._tree.add_node(self._tree_stage, parent, token, self.get_last_spine_operator(parent), parent.last_signature_nodes, parent.header_node)
|
270
|
+
|
271
|
+
if column_content == '*-':
|
272
|
+
if node.last_spine_operator_node is not None:
|
273
|
+
node.last_spine_operator_node.token.cancelled_at_stage = self._tree_stage
|
274
|
+
pass # it's terminated, no continuation
|
275
|
+
elif column_content == "*+" or column_content == "*^":
|
276
|
+
self._next_stage_parents.append(node)
|
277
|
+
self._next_stage_parents.append(node) # twice, the next stage two children will have this one as parent
|
278
|
+
elif column_content == "*v":
|
279
|
+
if node.last_spine_operator_node is not None:
|
280
|
+
node.last_spine_operator_node.token.cancelled_at_stage = self._tree_stage
|
281
|
+
|
282
|
+
if column_index == 0 or row[column_index-1] != '*v' or self._prev_stage_parents[column_index-1].header_node != self._prev_stage_parents[column_index].header_node: # don't collapse two different spines
|
283
|
+
self._next_stage_parents.append(node) # just one spine each two
|
284
|
+
else:
|
285
|
+
raise Exception(f'Unknown spine operation in column #{column_content} and row #{self._row_number}')
|
@@ -0,0 +1,43 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
import sys
|
3
|
+
|
4
|
+
from .dyn_importer import DynSpineImporter
|
5
|
+
from .dynam_spine_importer import DynamSpineImporter
|
6
|
+
from .fing_spine_importer import FingSpineImporter
|
7
|
+
from .harm_spine_importer import HarmSpineImporter
|
8
|
+
from .kern_spine_importer import KernSpineImporter
|
9
|
+
from .mens_spine_importer import MensSpineImporter
|
10
|
+
from .mhxm_spine_importer import MxhmSpineImporter
|
11
|
+
from .root_spine_importer import RootSpineImporter
|
12
|
+
from .spine_importer import SpineImporter
|
13
|
+
from .text_spine_importer import TextSpineImporter
|
14
|
+
from .basic_spine_importer import BasicSpineImporter
|
15
|
+
|
16
|
+
|
17
|
+
def createImporter(spine_type: str) -> SpineImporter:
|
18
|
+
if spine_type == '**mens':
|
19
|
+
return MensSpineImporter()
|
20
|
+
elif spine_type == '**kern':
|
21
|
+
return KernSpineImporter()
|
22
|
+
elif spine_type == '**text':
|
23
|
+
return TextSpineImporter()
|
24
|
+
elif spine_type == '**harm':
|
25
|
+
return HarmSpineImporter()
|
26
|
+
elif spine_type == '**mxhm':
|
27
|
+
return MxhmSpineImporter()
|
28
|
+
elif spine_type == '**root':
|
29
|
+
return RootSpineImporter()
|
30
|
+
elif spine_type == '**dyn':
|
31
|
+
return DynSpineImporter()
|
32
|
+
elif spine_type == '**dynam':
|
33
|
+
return DynamSpineImporter()
|
34
|
+
elif spine_type == '**fing':
|
35
|
+
return FingSpineImporter()
|
36
|
+
else:
|
37
|
+
#print(f'Invalid spine header type found: {spine_type} '
|
38
|
+
# f'using a basic spine importer instead',
|
39
|
+
# file=sys.stderr)
|
40
|
+
# TODO: Should we use a logger? Global variable for verbosity?
|
41
|
+
|
42
|
+
return BasicSpineImporter() # Only parse basic token categories
|
43
|
+
|
@@ -0,0 +1,73 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
from typing import List
|
4
|
+
|
5
|
+
from antlr4 import InputStream, CommonTokenStream, ParseTreeWalker, BailErrorStrategy, \
|
6
|
+
PredictionMode
|
7
|
+
from typing import Optional
|
8
|
+
|
9
|
+
from .base_antlr_importer import BaseANTLRListenerImporter
|
10
|
+
from .base_antlr_spine_parser_listener import BaseANTLRSpineParserListener
|
11
|
+
from .error_listener import ErrorListener
|
12
|
+
from .generated.kernSpineLexer import kernSpineLexer
|
13
|
+
from .generated.kernSpineParser import kernSpineParser
|
14
|
+
from .spine_importer import SpineImporter
|
15
|
+
from .tokens import SimpleToken, TokenCategory, Subtoken, ChordToken, BoundingBox, \
|
16
|
+
BoundingBoxToken, ClefToken, KeySignatureToken, TimeSignatureToken, MeterSymbolToken, BarToken, NoteRestToken, \
|
17
|
+
KeyToken, InstrumentToken
|
18
|
+
|
19
|
+
|
20
|
+
class KernSpineListener(BaseANTLRSpineParserListener):
|
21
|
+
|
22
|
+
def __init__(self):
|
23
|
+
super().__init__()
|
24
|
+
|
25
|
+
class KernListenerImporter(BaseANTLRListenerImporter):
|
26
|
+
|
27
|
+
def createListener(self):
|
28
|
+
return KernSpineListener()
|
29
|
+
|
30
|
+
def createLexer(self, charStream):
|
31
|
+
return kernSpineLexer(charStream)
|
32
|
+
|
33
|
+
def createParser(self, tokenStream):
|
34
|
+
return kernSpineParser(tokenStream)
|
35
|
+
|
36
|
+
def startRule(self):
|
37
|
+
return self.parser.start()
|
38
|
+
|
39
|
+
|
40
|
+
class KernSpineImporter(SpineImporter):
|
41
|
+
def __init__(self, verbose: Optional[bool] = False):
|
42
|
+
"""
|
43
|
+
KernSpineImporter constructor.
|
44
|
+
|
45
|
+
Args:
|
46
|
+
verbose (Optional[bool]): Level of verbosity for error messages.
|
47
|
+
"""
|
48
|
+
super().__init__(verbose=verbose)
|
49
|
+
|
50
|
+
def import_listener(self) -> BaseANTLRSpineParserListener:
|
51
|
+
return KernSpineListener()
|
52
|
+
|
53
|
+
def import_token(self, encoding: str):
|
54
|
+
self._raise_error_if_wrong_input(encoding)
|
55
|
+
|
56
|
+
# self.listenerImporter = KernListenerImporter(token) # TODO ¿Por qué no va esto?
|
57
|
+
# self.listenerImporter.start()
|
58
|
+
lexer = kernSpineLexer(InputStream(encoding))
|
59
|
+
lexer.removeErrorListeners()
|
60
|
+
lexer.addErrorListener(self.error_listener)
|
61
|
+
stream = CommonTokenStream(lexer)
|
62
|
+
parser = kernSpineParser(stream)
|
63
|
+
parser._interp.predictionMode = PredictionMode.SLL # it improves a lot the parsing
|
64
|
+
parser.removeErrorListeners()
|
65
|
+
parser.addErrorListener(self.error_listener)
|
66
|
+
parser.errHandler = BailErrorStrategy()
|
67
|
+
tree = parser.start()
|
68
|
+
walker = ParseTreeWalker()
|
69
|
+
listener = KernSpineListener()
|
70
|
+
walker.walk(listener, tree)
|
71
|
+
if self.error_listener.getNumberErrorsFound() > 0:
|
72
|
+
raise Exception(self.error_listener.errors)
|
73
|
+
return listener.token
|
@@ -0,0 +1,23 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
from typing import Optional
|
3
|
+
|
4
|
+
from .base_antlr_spine_parser_listener import BaseANTLRSpineParserListener
|
5
|
+
from .spine_importer import SpineImporter
|
6
|
+
from .tokens import Token
|
7
|
+
|
8
|
+
|
9
|
+
class MensSpineImporter(SpineImporter):
|
10
|
+
def __init__(self, verbose: Optional[bool] = False):
|
11
|
+
"""
|
12
|
+
MensSpineImporter constructor.
|
13
|
+
|
14
|
+
Args:
|
15
|
+
verbose (Optional[bool]): Level of verbosity for error messages.
|
16
|
+
"""
|
17
|
+
super().__init__(verbose=verbose)
|
18
|
+
|
19
|
+
def import_listener(self) -> BaseANTLRSpineParserListener:
|
20
|
+
raise NotImplementedError()
|
21
|
+
|
22
|
+
def import_token(self, encoding: str) -> Token:
|
23
|
+
raise NotImplementedError()
|
@@ -0,0 +1,44 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
from typing import Optional
|
3
|
+
|
4
|
+
from .kern_spine_importer import KernSpineListener, KernSpineImporter
|
5
|
+
from .base_antlr_spine_parser_listener import BaseANTLRSpineParserListener
|
6
|
+
from .spine_importer import SpineImporter
|
7
|
+
from .tokens import MHXMToken, Token, TokenCategory
|
8
|
+
|
9
|
+
|
10
|
+
class MxhmSpineImporter(SpineImporter):
|
11
|
+
def __init__(self, verbose: Optional[bool] = False):
|
12
|
+
"""
|
13
|
+
KernSpineImporter constructor.
|
14
|
+
|
15
|
+
Args:
|
16
|
+
verbose (Optional[bool]): Level of verbosity for error messages.
|
17
|
+
"""
|
18
|
+
super().__init__(verbose=verbose)
|
19
|
+
|
20
|
+
def import_listener(self) -> BaseANTLRSpineParserListener:
|
21
|
+
return KernSpineListener()
|
22
|
+
|
23
|
+
def import_token(self, encoding: str) -> Token:
|
24
|
+
self._raise_error_if_wrong_input(encoding)
|
25
|
+
|
26
|
+
kern_spine_importer = KernSpineImporter()
|
27
|
+
token = kern_spine_importer.import_token(encoding)
|
28
|
+
|
29
|
+
ACCEPTED_CATEGORIES = {
|
30
|
+
TokenCategory.STRUCTURAL,
|
31
|
+
TokenCategory.SIGNATURES,
|
32
|
+
TokenCategory.EMPTY,
|
33
|
+
TokenCategory.IMAGE_ANNOTATIONS,
|
34
|
+
TokenCategory.BARLINES,
|
35
|
+
TokenCategory.COMMENTS,
|
36
|
+
}
|
37
|
+
|
38
|
+
if any(TokenCategory.is_child(child=token.category, parent=cat) for cat in ACCEPTED_CATEGORIES):
|
39
|
+
return SimpleToken(encoding, TokenCategory.HARMONY)
|
40
|
+
|
41
|
+
return token
|
42
|
+
|
43
|
+
return MHXMToken(encoding)
|
44
|
+
|