@@ -1,13 +1,14 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from fractions import Fraction
|
||||
import dataclasses
|
||||
import fractions
|
||||
|
||||
from generator.model import alteration, fraction
|
||||
from generator.engraving.fonts import Fonts
|
||||
from generator.engraving.notation import Event, ScoreIndex, accidental, flags, fragment_written, head_glyph
|
||||
from generator.engraving.types import Anchor, Fragment, Primitive, Style, bounds, line
|
||||
import generator.engraving.fonts
|
||||
import generator.engraving.notation
|
||||
import generator.engraving.types
|
||||
import generator.model
|
||||
|
||||
def dots(fonts: Fonts, count: int, x: float, y: float, size: float, sources: tuple[str, ...]) -> list[Primitive]:
|
||||
def dots(fonts: generator.engraving.fonts.Fonts, count: int, x: float, y: float, size: float, sources: tuple[str, ...]) -> list[generator.engraving.types.Primitive]:
|
||||
result = []
|
||||
for i in range(count):
|
||||
result.append(fonts.glyph('augmentationDot', x + i * size * 0.6, y, size, 'dot', sources))
|
||||
@@ -16,13 +17,13 @@ def dots(fonts: Fonts, count: int, x: float, y: float, size: float, sources: tup
|
||||
def rest_glyph(kind: str) -> str:
|
||||
return {'maxima': 'restMaxima', 'long': 'restLonga', 'breve': 'restDoubleWhole', 'whole': 'restWhole', 'half': 'restHalf', 'quarter': 'restQuarter', 'eighth': 'rest8th'}.get(kind, 'rest' + kind)
|
||||
|
||||
def time_modification(written: dict, items: list[Primitive], fonts: Fonts, sources: tuple[str, ...]) -> None:
|
||||
ratio = fraction(written.get('ratio', {'numerator': 1, 'denominator': 1}))
|
||||
def time_modification(written: dict, items: list[generator.engraving.types.Primitive], fonts: generator.engraving.fonts.Fonts, sources: tuple[str, ...]) -> None:
|
||||
ratio = generator.model.fraction(written.get('ratio', {'numerator': 1, 'denominator': 1}))
|
||||
if ratio != 1 and items:
|
||||
box = bounds(items)
|
||||
box = generator.engraving.types.bounds(items)
|
||||
items.append(fonts.text(f'{ratio.denominator}:{ratio.numerator}', (box.left + box.right) / 2, box.top - 6, 13, 'time-modification', sources, True))
|
||||
|
||||
def draw_event(index: ScoreIndex, event: Event, start: Fraction, end: Fraction, fonts: Fonts, style: Style) -> tuple[list[Primitive], list[Anchor], list[Fragment]]:
|
||||
def draw_event(index: generator.engraving.notation.ScoreIndex, event: generator.engraving.notation.Event, start: fractions.Fraction, end: fractions.Fraction, fonts: generator.engraving.fonts.Fonts, style: generator.engraving.types.Style) -> tuple[list[generator.engraving.types.Primitive], list[generator.engraving.types.Anchor], list[generator.engraving.types.Fragment]]:
|
||||
note = event.value
|
||||
onset = max(start, event.start)
|
||||
finish = min(end, event.end)
|
||||
@@ -33,17 +34,17 @@ def draw_event(index: ScoreIndex, event: Event, start: Fraction, end: Fraction,
|
||||
state = index.state(onset)
|
||||
lines = state['staff_details']['lines']
|
||||
if not note['pitches']:
|
||||
written = fragment_written(note['written'], event.start, event.end, onset, finish)
|
||||
written = generator.engraving.notation.fragment_written(note['written'], event.start, event.end, onset, finish)
|
||||
y = -style.space * (lines - 1) / 2
|
||||
if position := note.get('rest_position'):
|
||||
y = -index.pitch_position(position, onset) * style.space / 2
|
||||
elif event.lanes > 1:
|
||||
y += (-1 if event.lane % 2 == 0 else 1) * (event.lane // 2 + 1) * style.space * 3
|
||||
kind = 'slash' if note.get('notehead') == 'slash' else 'rest'
|
||||
fragment = Fragment(note['id'], note['id'], onset, finish, written['type'], written.get('dots', 0), fraction(written.get('ratio', {'numerator': 1, 'denominator': 1})), visible, kind, None)
|
||||
fragment = generator.engraving.types.Fragment(note['id'], note['id'], onset, finish, written['type'], written.get('dots', 0), generator.model.fraction(written.get('ratio', {'numerator': 1, 'denominator': 1})), visible, kind, None)
|
||||
fragments.append(fragment)
|
||||
if visible:
|
||||
glyph = head_glyph(written, 'slash') if kind == 'slash' else rest_glyph('whole' if note.get('measure_rest') and onset == event.start and finish == event.end else written['type'])
|
||||
glyph = generator.engraving.notation.head_glyph(written, 'slash') if kind == 'slash' else rest_glyph('whole' if note.get('measure_rest') and onset == event.start and finish == event.end else written['type'])
|
||||
if written['type'] == 'whole' and not note.get('rest_position') and event.lanes == 1:
|
||||
y -= style.space
|
||||
items.append(fonts.glyph(glyph, 0, y, size, kind, references))
|
||||
@@ -51,20 +52,20 @@ def draw_event(index: ScoreIndex, event: Event, start: Fraction, end: Fraction,
|
||||
if kind == 'slash' and written['type'] not in ('whole', 'breve', 'long', 'maxima'):
|
||||
stem_x = items[0].box.right
|
||||
stem_y = y - 3 * size
|
||||
items.append(line('stem', references, ((stem_x, y), (stem_x, stem_y))))
|
||||
if flags(written):
|
||||
items.append(generator.engraving.types.line('stem', references, ((stem_x, y), (stem_x, stem_y))))
|
||||
if generator.engraving.notation.flags(written):
|
||||
flag = 'flag' + ('8th' if written['type'] == 'eighth' else written['type']) + 'Up'
|
||||
items.append(fonts.glyph(flag, stem_x, stem_y, size, 'flag', references))
|
||||
anchors.append(Anchor(note['id'], note['id'], event.voice, onset, finish, 0, y, 0, y - size * 3, -1, 0, fragment))
|
||||
anchors.append(generator.engraving.types.Anchor(note['id'], note['id'], event.voice, onset, finish, 0, y, 0, y - size * 3, -1, 0, fragment))
|
||||
if not note.get('tuplet_ids') or written != note['written']:
|
||||
time_modification(written, items, fonts, references)
|
||||
return items, anchors, fragments
|
||||
groups = {}
|
||||
for tone in note['pitches']:
|
||||
tone_end = event.start + fraction(tone['duration'])
|
||||
tone_end = event.start + generator.model.fraction(tone['duration'])
|
||||
if tone_end <= start and not note.get('grace'):
|
||||
continue
|
||||
written = fragment_written(tone['written'], event.start, tone_end, onset, min(end, tone_end))
|
||||
written = generator.engraving.notation.fragment_written(tone['written'], event.start, tone_end, onset, min(end, tone_end))
|
||||
stem = tone.get('stem', note.get('stem', 'auto'))
|
||||
identity = (written['type'], written.get('dots', 0), str(written.get('ratio')), stem)
|
||||
groups.setdefault(identity, []).append((tone, written, tone_end))
|
||||
@@ -82,7 +83,7 @@ def draw_event(index: ScoreIndex, event: Event, start: Fraction, end: Fraction,
|
||||
for position, tone, written, tone_end in positioned:
|
||||
sources = (note['id'], tone['id'])
|
||||
tone_size = size * (0.7 if tone.get('cue') and not note.get('cue') else 1)
|
||||
glyph = head_glyph(written, tone.get('notehead', note.get('notehead')))
|
||||
glyph = generator.engraving.notation.head_glyph(written, tone.get('notehead', note.get('notehead')))
|
||||
displayed = visible and tone.get('print', {}).get('print-object') != 'no' and bool(glyph)
|
||||
y = -position * style.space / 2
|
||||
if previous is not None and abs(position - previous) < 2:
|
||||
@@ -91,13 +92,13 @@ def draw_event(index: ScoreIndex, event: Event, start: Fraction, end: Fraction,
|
||||
displaced = False
|
||||
x = group_x + (tone_size * 1.2 * -direction if displaced else 0)
|
||||
previous = position
|
||||
fragment = Fragment(tone['id'], note['id'], onset, min(end, tone_end), written['type'], written.get('dots', 0), fraction(written.get('ratio', {'numerator': 1, 'denominator': 1})), displayed, 'tone', position)
|
||||
fragment = generator.engraving.types.Fragment(tone['id'], note['id'], onset, min(end, tone_end), written['type'], written.get('dots', 0), generator.model.fraction(written.get('ratio', {'numerator': 1, 'denominator': 1})), displayed, 'tone', position)
|
||||
fragments.append(fragment)
|
||||
if not displayed:
|
||||
continue
|
||||
if written['type'] in ('long', 'maxima') and tone.get('notehead', {}).get('name', 'normal') == 'normal':
|
||||
width = tone_size * (2.8 if written['type'] == 'maxima' else 1.4)
|
||||
head = line('head', sources, ((x, y - tone_size / 2), (x + width, y - tone_size / 2), (x + width, y + tone_size / 2), (x, y + tone_size / 2), (x, y - tone_size / 2)), 2)
|
||||
head = generator.engraving.types.line('head', sources, ((x, y - tone_size / 2), (x + width, y - tone_size / 2), (x + width, y + tone_size / 2), (x, y + tone_size / 2), (x, y - tone_size / 2)), 2)
|
||||
else:
|
||||
head = fonts.glyph(glyph, x, y, tone_size, 'head', sources)
|
||||
group_items.append(head)
|
||||
@@ -105,15 +106,15 @@ def draw_event(index: ScoreIndex, event: Event, start: Fraction, end: Fraction,
|
||||
group_items.extend((fonts.text('(', head.box.left - 6, y + 5, 18, 'head-parentheses', sources), fonts.text(')', head.box.right + 2, y + 5, 18, 'head-parentheses', sources)))
|
||||
ledger = -2
|
||||
while position <= ledger:
|
||||
group_items.append(line('ledger', sources, ((head.box.left - 5, -ledger * style.space / 2), (head.box.right + 5, -ledger * style.space / 2)), 1.8))
|
||||
group_items.append(generator.engraving.types.line('ledger', sources, ((head.box.left - 5, -ledger * style.space / 2), (head.box.right + 5, -ledger * style.space / 2)), 1.8))
|
||||
ledger -= 2
|
||||
ledger = lines * 2
|
||||
while position >= ledger:
|
||||
group_items.append(line('ledger', sources, ((head.box.left - 5, -ledger * style.space / 2), (head.box.right + 5, -ledger * style.space / 2)), 1.8))
|
||||
group_items.append(generator.engraving.types.line('ledger', sources, ((head.box.left - 5, -ledger * style.space / 2), (head.box.right + 5, -ledger * style.space / 2)), 1.8))
|
||||
ledger += 2
|
||||
if 'alter' in tone and index.accidentals[tone['id']] and onset == event.start:
|
||||
accidental_items = accidental(fonts, alteration(tone['alter']), tone.get('accidental_display', {}), tone_size, sources)
|
||||
box = bounds(accidental_items)
|
||||
accidental_items = generator.engraving.notation.accidental(fonts, generator.model.alteration(tone['alter']), tone.get('accidental_display', {}), tone_size, sources)
|
||||
box = generator.engraving.types.bounds(accidental_items)
|
||||
dx = min(group_x, head.box.left) - 5 - box.right
|
||||
candidate = box.moved(dx, y)
|
||||
while any(candidate.overlaps(other, 2) for other in accidental_boxes):
|
||||
@@ -128,32 +129,31 @@ def draw_event(index: ScoreIndex, event: Event, start: Fraction, end: Fraction,
|
||||
stem_x = x + fonts.anchor(glyph, 'stemUpSE' if direction == -1 else 'stemDownNW', tone_size)[0]
|
||||
else:
|
||||
stem_x = head.box.right - 0.6 if direction == -1 else head.box.left + 0.6
|
||||
stem_y = y + direction * max(3.5 * size, (flags(written) + 1) * size * 0.75)
|
||||
group_anchors.append(Anchor(tone['id'], note['id'], event.voice, onset, min(end, tone_end), x, y, stem_x, stem_y, direction, flags(written), fragment))
|
||||
stem_y = y + direction * max(3.5 * size, (generator.engraving.notation.flags(written) + 1) * size * 0.75)
|
||||
group_anchors.append(generator.engraving.types.Anchor(tone['id'], note['id'], event.voice, onset, min(end, tone_end), x, y, stem_x, stem_y, direction, generator.engraving.notation.flags(written), fragment))
|
||||
if group_anchors:
|
||||
stem_y = min(a.stem_y for a in group_anchors) if direction == -1 else max(a.stem_y for a in group_anchors)
|
||||
anchor = min(group_anchors, key=lambda a: a.y) if direction == 1 else max(group_anchors, key=lambda a: a.y)
|
||||
written = members[0][1]
|
||||
if stem != 'none' and written['type'] not in ('whole', 'breve'):
|
||||
group_items.append(line('stem', references, ((anchor.stem_x, anchor.y), (anchor.stem_x, stem_y)), size * 0.12))
|
||||
group_items.append(generator.engraving.types.line('stem', references, ((anchor.stem_x, anchor.y), (anchor.stem_x, stem_y)), size * 0.12))
|
||||
if stem == 'double':
|
||||
other_x = anchor.x if direction == -1 else anchor.x + size * 1.3
|
||||
other_y = anchor.y - direction * size * 3.5
|
||||
group_items.append(line('stem', references, ((other_x, anchor.y), (other_x, other_y)), size * 0.12))
|
||||
if flags(written):
|
||||
group_items.append(generator.engraving.types.line('stem', references, ((other_x, anchor.y), (other_x, other_y)), size * 0.12))
|
||||
if generator.engraving.notation.flags(written):
|
||||
flag = 'flag' + ('8th' if written['type'] == 'eighth' else written['type']) + ('Down' if direction == -1 else 'Up')
|
||||
group_items.append(fonts.glyph(flag, other_x, other_y, size, 'flag', references))
|
||||
if flags(written):
|
||||
if generator.engraving.notation.flags(written):
|
||||
flag = 'flag' + ('8th' if written['type'] == 'eighth' else written['type']) + ('Up' if direction == -1 else 'Down')
|
||||
group_items.append(fonts.glyph(flag, anchor.stem_x, stem_y, size, 'flag', references))
|
||||
if note.get('grace', {}).get('slash'):
|
||||
group_items.append(line('grace-slash', references, ((anchor.stem_x - 5, stem_y + 14), (anchor.stem_x + 9, stem_y + 4)), 1.5))
|
||||
group_items.append(generator.engraving.types.line('grace-slash', references, ((anchor.stem_x - 5, stem_y + 14), (anchor.stem_x + 9, stem_y + 4)), 1.5))
|
||||
if note.get('tremolo', {}).get('type') == 'single':
|
||||
for mark in range(note['tremolo']['marks']):
|
||||
ty = stem_y - direction * (10 + mark * 5)
|
||||
group_items.append(line('tremolo', references, ((anchor.stem_x - 6, ty + 2), (anchor.stem_x + 6, ty - 2)), 3))
|
||||
from dataclasses import replace
|
||||
anchors.extend(replace(a, stem_x=anchor.stem_x, stem_y=stem_y) for a in group_anchors)
|
||||
group_items.append(generator.engraving.types.line('tremolo', references, ((anchor.stem_x - 6, ty + 2), (anchor.stem_x + 6, ty - 2)), 3))
|
||||
anchors.extend(dataclasses.replace(a, stem_x=anchor.stem_x, stem_y=stem_y) for a in group_anchors)
|
||||
if not note.get('tuplet_ids') or members[0][1] != members[0][0]['written']:
|
||||
time_modification(members[0][1], group_items, fonts, references)
|
||||
items.extend(group_items)
|
||||
|
||||
Reference in New Issue
Block a user