in moonlight/structure/stems.py [0:0]
def apply(self, page):
"""Detects stems on the page.
Using `self.stem_candidates`, finds verticals that align with a notehead
glyph, and adds the stems.
Args:
page: The Page message.
Returns:
The same page, updated with stems.
"""
for system in page.system:
for staff, staff_ys in zip(system.staff,
self.staff_detector.staves_interpolated_y):
allowed_distance = np.multiply(
_STEM_NOTEHEAD_DISTANCE_STAFFLINE_DISTANCE,
staff.staffline_distance)
expected_horizontal_distance = np.multiply(
_STEM_NOTEHEAD_HORIZONTAL_STAFFLINE_DISTANCE,
staff.staffline_distance)
for glyph in staff.glyph:
if glyph_types.is_stemmed_notehead(glyph):
glyph_y = (
staff_ys[glyph.x] -
glyph.y_position * staff.staffline_distance / 2.0)
# Compute the ideal coordinates for the glyph to be assigned to each
# stem.
# Clip the glyph_y to the stem start and end y to get the ideal y.
ideal_y = np.clip(glyph_y, self.stem_candidates[:, 0, 1],
self.stem_candidates[:, 1, 1])
# If the glyph is left of the stem, subtract the expected distance
# from the stem x; otherwise, add it.
ideal_x = self.stem_candidates[:, 0, 0] + np.where(
glyph.x < self.stem_candidates[:, 0, 0],
-expected_horizontal_distance, expected_horizontal_distance)
stem_distance = np.linalg.norm(
np.c_[ideal_x - glyph.x, ideal_y - glyph_y], axis=1)
stem = np.argmin(stem_distance)
if stem_distance[stem] <= allowed_distance:
stem_coords = self.stem_candidates[stem]
glyph.stem.CopyFrom(
musicscore_pb2.LineSegment(
start=musicscore_pb2.Point(
x=stem_coords[0, 0], y=stem_coords[0, 1]),
end=musicscore_pb2.Point(
x=stem_coords[1, 0], y=stem_coords[1, 1])))
return page