@@ -0,0 +1,122 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from fractions import Fraction
|
||||
|
||||
from generator.model import LETTERS, TYPE_LENGTHS, alteration, fraction
|
||||
from generator.engraving.fonts import Fonts
|
||||
from generator.engraving.notation import ScoreIndex, accidental
|
||||
from generator.engraving.types import Primitive, bounds, line
|
||||
|
||||
def staff_attributes(index: ScoreIndex, state: dict, time: Fraction, fonts: Fonts, space: float, source: str, fields: tuple[str, ...]) -> list[Primitive]:
|
||||
result = []
|
||||
x = 0
|
||||
references = (source,)
|
||||
clef = state['clef']
|
||||
lines = state['staff_details']['lines']
|
||||
if 'clef' in fields and clef['sign'] != 'none':
|
||||
sign = clef['sign']
|
||||
name = {'G': 'gClef', 'F': 'fClef', 'C': 'cClef', 'percussion': 'unpitchedPercussionClef1', 'TAB': '6stringTabClef' if lines != 4 else '4stringTabClef'}[sign]
|
||||
y = -space * (clef.get('line', 2) - 1) if sign in ('G', 'F', 'C') else -space * (lines - 1) / 2
|
||||
glyph = fonts.glyph(name, x, y, space, 'clef', references)
|
||||
result.append(glyph)
|
||||
if octave := clef.get('octave_change', 0):
|
||||
label = str(abs(octave) * 7 + 1)
|
||||
result.append(fonts.text(label, (glyph.box.left + glyph.box.right) / 2, glyph.box.top - 2 if octave > 0 else glyph.box.bottom + 14, 14, 'clef-octave', references, True))
|
||||
x = bounds(result).right + space
|
||||
if 'key' in fields and clef['sign'] not in ('percussion', 'TAB'):
|
||||
key = state['key']
|
||||
steps = key.get('steps')
|
||||
if steps is None:
|
||||
order = 'fcgdaeb' if key.get('fifths', 0) >= 0 else 'beadgcf'
|
||||
steps = [{'letter': c, 'alter': key['alterations'][LETTERS.index(c)]} for c in order if alteration(key['alterations'][LETTERS.index(c)])]
|
||||
cancellation = key.get('cancel', 0)
|
||||
if cancellation:
|
||||
order = 'fcgdaeb' if cancellation > 0 else 'beadgcf'
|
||||
steps = [{'letter': c, 'alter': 0} for c in order[:min(7, abs(cancellation))]] + steps
|
||||
for step in steps:
|
||||
pitch = {'letter': step['letter'], 'octave': step.get('octave', 5), 'id': source}
|
||||
position = index.pitch_position(pitch, time)
|
||||
if 'octave' not in step:
|
||||
while position > 9:
|
||||
position -= 7
|
||||
while position < 2:
|
||||
position += 7
|
||||
items = accidental(fonts, alteration(step['alter']), {'name': step.get('accidental', '')}, space, references)
|
||||
result.extend(p.moved(x, -position * space / 2) for p in items)
|
||||
x += bounds(items).right - bounds(items).left + 4
|
||||
if steps:
|
||||
x += space / 2
|
||||
if 'meter' in fields:
|
||||
meter = state['meter']
|
||||
if meter.get('unmetered'):
|
||||
result.append(fonts.text('senza misura', x, -space * 2, 16, 'meter', references))
|
||||
elif meter.get('symbol') in ('common', 'cut'):
|
||||
result.append(fonts.glyph('timeSigCommon' if meter['symbol'] == 'common' else 'timeSigCutCommon', x, -space * 2, space, 'meter', references))
|
||||
else:
|
||||
for gi, group in enumerate(meter['groups']):
|
||||
if gi:
|
||||
plus = fonts.glyph('timeSigPlus', x, -space * 2, space, 'meter', references)
|
||||
result.append(plus)
|
||||
x = plus.box.right + 7
|
||||
numerator = '+'.join(map(str, group['beats']))
|
||||
denominator = str(group['unit'])
|
||||
rows = [(numerator, -space * 2)] if meter.get('symbol') == 'single-number' else [(numerator, -space * 3), (denominator, -space)]
|
||||
groups = []
|
||||
for value, y in rows:
|
||||
items = []
|
||||
cursor = 0
|
||||
if y == -space and meter.get('symbol') in ('note', 'dotted-note'):
|
||||
unit = Fraction(4, group['unit'])
|
||||
kind = next((name for name, length in TYPE_LENGTHS.items() if length == unit), None)
|
||||
glyph_name = {'whole': 'noteWhole', 'half': 'noteHalfUp', 'quarter': 'noteQuarterUp', 'eighth': 'note8thUp'}.get(kind, 'note' + str(kind) + 'Up')
|
||||
if kind and glyph_name in fonts.names:
|
||||
glyph = fonts.glyph(glyph_name, 0, y + space, space * 0.55, 'meter', references)
|
||||
items.append(glyph)
|
||||
if meter['symbol'] == 'dotted-note':
|
||||
items.append(fonts.glyph('augmentationDot', glyph.box.right + 3, y + space / 2, space * 0.55, 'meter', references))
|
||||
groups.append(items)
|
||||
continue
|
||||
for char in value:
|
||||
glyph = fonts.glyph('timeSigPlus' if char == '+' else 'timeSig' + char, cursor, y, space, 'meter', references)
|
||||
items.append(glyph)
|
||||
cursor = glyph.box.right + 1
|
||||
groups.append(items)
|
||||
width = max(bounds(items).right for items in groups)
|
||||
for items in groups:
|
||||
result.extend(p.moved(x + (width - bounds(items).right) / 2, 0) for p in items)
|
||||
x += width + 6
|
||||
if 'staff_details' in fields and state['staff_details'].get('capo'):
|
||||
result.append(fonts.text(f'Capo {state["staff_details"]["capo"]}', x, -space * (lines + 1), 16, 'staff-details', references))
|
||||
return result
|
||||
|
||||
def barline(style: str, x: float, top: float, source: str) -> list[Primitive]:
|
||||
if style == 'none':
|
||||
return []
|
||||
references = (source,)
|
||||
if style in ('dashed', 'dotted'):
|
||||
dash, gap = (5, 4) if style == 'dashed' else (1, 4)
|
||||
return [line('barline', references, ((x, y), (x, min(y + dash, 0)))) for y in range(round(top), 0, dash + gap)]
|
||||
if style in ('tick', 'short'):
|
||||
return [line('barline', references, ((x, top - 4 if style == 'tick' else top * 0.75), (x, top + 5 if style == 'tick' else top * 0.25)))]
|
||||
weights = {'regular': [1.4], 'heavy': [4], 'light-light': [1.4, 1.4], 'light-heavy': [1.4, 4], 'heavy-light': [4, 1.4], 'heavy-heavy': [4, 4]}[style]
|
||||
return [line('barline', references, ((x - (len(weights) - 1 - i) * 5, top), (x - (len(weights) - 1 - i) * 5, 0)), width) for i, width in enumerate(weights)]
|
||||
|
||||
def tempo(value: dict, fonts: Fonts, x: float, y: float, space: float, source: str) -> list[Primitive]:
|
||||
from generator.engraving.notation import flags, head_glyph
|
||||
written = value['written']
|
||||
references = (source,)
|
||||
glyph = fonts.glyph(head_glyph(written, None), x, y, space * 0.7, 'tempo', references)
|
||||
items = [glyph]
|
||||
stem_x = glyph.box.right - 0.5
|
||||
if written['type'] not in ('whole', 'breve', 'long', 'maxima'):
|
||||
items.append(line('tempo', references, ((stem_x, y), (stem_x, y - 23)), 1))
|
||||
if flags(written):
|
||||
name = 'flag' + ('8th' if written['type'] == 'eighth' else written['type']) + 'Up'
|
||||
items.append(fonts.glyph(name, stem_x, y - 23, space * 0.7, 'tempo', references))
|
||||
cursor = max(p.box.right for p in items) + 3
|
||||
for _ in range(written.get('dots', 0)):
|
||||
dot = fonts.glyph('augmentationDot', cursor, y - 3, space * 0.7, 'tempo', references)
|
||||
items.append(dot)
|
||||
cursor = dot.box.right + 3
|
||||
items.append(fonts.text(' = ' + str(fraction(value['bpm'])), cursor, y + 3, 16, 'tempo', references))
|
||||
return items
|
||||
Reference in New Issue
Block a user