-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathnote_address.py
More file actions
140 lines (94 loc) · 4.68 KB
/
note_address.py
File metadata and controls
140 lines (94 loc) · 4.68 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# ## Classes for note-addresses
from utils import pmts
class NoteAddress(object):
"""(Global) address of a Note, the path of that note in a with respect to some global root score."""
def __init__(self, address=()):
pmts(address, tuple)
for part in address:
pmts(part, NoteAddressPart)
self.address = address
def __eq__(self, other):
return isinstance(other, NoteAddress) and \
self.address == other.address
def __hash__(self):
return hash(self.address)
def _repr_parts(self):
return self.address
def __repr__(self):
return "(" + ", ".join(repr(p) for p in self._repr_parts()) + ")"
def plus(self, part):
return NoteAddress(self.address + (part,))
def is_prefix_of(self, other):
return self.address == other.address[:len(self.address)]
class NoteAddressPart(object):
"""The global paths are defined as tuples of NoteAddressPart."""
pass
class TheChild(NoteAddressPart):
"""For notes which take a single child: this part of the path denotes descending into that child."""
def __repr__(self):
return '>'
def __eq__(self, other):
return isinstance(other, TheChild)
def __hash__(self):
return hash(repr(self))
class InScore(NoteAddressPart):
"""For Scores, the path is denoted by indicating which child in the score we're talking abuot. (by index)"""
def __init__(self, index):
self.index = index
def __repr__(self):
return '@%s' % self.index
def __eq__(self, other):
return isinstance(other, InScore) and self.index == other.index
def __hash__(self):
return hash(self.index)
class SExprELS18NoteAddress(object):
"""Notes may be represented as S-Expressions, as we do in the paper that was presented at ELS18. How an individual
so formed s-expression relates to the global address of the represented note, and which part (i.e. field) of the
represented note it represents, can be expressed using an `SExprELS18NoteAddress`"""
def __init__(self, note_address, note_field=None):
self.note_address = note_address
# the note_field may be None, when a given s-expression represents the whole Note.
self.note_field = note_field
def __eq__(self, other):
return isinstance(other, SExprELS18NoteAddress) and \
self.note_address == other.note_address and \
self.note_field == other.note_field
def __hash__(self):
return hash((self.note_address, self.note_field))
def _repr_parts(self):
return self.note_address._repr_parts() + (() if not self.note_field else (self.note_field,))
def __repr__(self):
return "(" + ", ".join(repr(p) for p in self._repr_parts()) + ")"
def with_render(self, part=None):
return ELS18RenderingAddress(self, part)
def is_prefix_of(self, other):
if self.note_field is None:
return self.note_address.is_prefix_of(other.note_address)
if self.note_field == 'list':
# This branch is here to deal with descending into chords' list field. The hackyness of it arises
# from the fact that the fact that the 'list' note_field only shows up in the list-expr that is used to
# represent that score, but not in its children. In short: (@3, 'list') is a prefix of (@3, @2)
#
# We also check if the other_note has a longer note_address to ensure there actually is a next part of the
# global address to consider (i.e. guard against index out of bounds)
#
return (len(self.note_address.address) < len(other.note_address.address) and
isinstance(other.note_address.address[len(self.note_address.address) - 1 + 1], InScore))
return self.note_address.is_prefix_of(other.note_address)
return self.note_address == other.note_address and self.note_field == other.note_field
els18_root_address = SExprELS18NoteAddress(NoteAddress(()), None)
class ELS18RenderingAddress(object):
"""For list-expressions: open-paren or close-paren; for atoms: no further information"""
def __init__(self, node_address, part):
self.node_address = node_address
self.part = part
def __eq__(self, other):
return isinstance(other, ELS18RenderingAddress) and \
self.node_address == other.node_address and \
self.part == other.part
def __hash__(self):
return hash((self.node_address, self.part))
def _repr_parts(self):
return self.node_address._repr_parts() + ([] if not self.part else [self.part])
def __repr__(self):
return "(" + ", ".join(self._repr_parts()) + ")"