@@ -173,6 +173,16 @@ def normalize_beams(events: list[dict]) -> None:
|
||||
if not event.get('beams'):
|
||||
event.pop('beams', None)
|
||||
|
||||
def written_durations(length: fractions.Fraction):
|
||||
while length:
|
||||
written = generator.model.written_for(length)
|
||||
duration = length
|
||||
if 'ratio' in written and length.denominator & (length.denominator - 1) == 0:
|
||||
duration = next((size for size in generator.model.TYPE_LENGTHS.values() if size < length), length)
|
||||
written = generator.model.written_for(duration)
|
||||
yield duration, written
|
||||
length -= duration
|
||||
|
||||
def realize(measure: dict, bar: generator.rhythm.Bar, previous: dict | None, *, lane: str = '') -> list[dict]:
|
||||
item = context(measure, previous)
|
||||
length = generator.model.fraction(measure['duration'])
|
||||
@@ -186,23 +196,27 @@ def realize(measure: dict, bar: generator.rhythm.Bar, previous: dict | None, *,
|
||||
if continuation:
|
||||
chord = None
|
||||
sounding_end = end
|
||||
if chord and lane == 'electric':
|
||||
sounding_end = min(end, start + 1)
|
||||
for change in measure['harmonies']:
|
||||
time = generator.model.fraction(change['onset'])
|
||||
if chord and start < time < sounding_end and not same_chord(chord, active_chord(measure, time, previous)):
|
||||
sounding_end = time
|
||||
written = {'type': source.written_type, 'dots': source.dots} if end - start == source.duration and sounding_end == end else None
|
||||
event = generator.model.make_event(f'{measure["id"]}-rhythm-{lane}-{len(events)}', start, sounding_end - start, 'note' if chord else 'rest', written=written)
|
||||
unchanged = end - start == source.duration and sounding_end == end
|
||||
duration = sounding_end - start
|
||||
written = {'type': source.written_type, 'dots': source.dots} if unchanged else generator.model.written_for(duration)
|
||||
if not unchanged and (lane == 'electric' or not chord):
|
||||
duration, written = next(written_durations(duration))
|
||||
event = generator.model.make_event(f'{measure["id"]}-rhythm-{lane}-{len(events)}', start, duration, 'note' if chord else 'rest', written=written)
|
||||
if chord:
|
||||
event['_harmony'] = chord
|
||||
if lane:
|
||||
event.update(_guitar_profile='electric' if lane == 'electric' else 'acoustic', _guitar_lane=lane)
|
||||
if source.beams and written and chord:
|
||||
if source.beams and unchanged and chord:
|
||||
event['beams'] = [{'level': level, 'type': kind} for level, kind in source.beams]
|
||||
events.append(event)
|
||||
if sounding_end < end:
|
||||
events.append(generator.model.make_event(f'{measure["id"]}-rhythm-{lane}-{len(events)}', sounding_end, end - sounding_end, 'rest'))
|
||||
cursor = start + duration
|
||||
for duration, written in written_durations(end - cursor):
|
||||
events.append(generator.model.make_event(f'{measure["id"]}-rhythm-{lane}-{len(events)}', cursor, duration, 'rest', written=written))
|
||||
cursor += duration
|
||||
normalize_beams(events)
|
||||
return events
|
||||
|
||||
|
||||
+2
-12
@@ -35,16 +35,6 @@ def harmony_spans(document: dict) -> list[HarmonySpan]:
|
||||
span.notes.append(item)
|
||||
return spans
|
||||
|
||||
def written_durations(length: fractions.Fraction):
|
||||
while length:
|
||||
written = generator.model.written_for(length)
|
||||
duration = length
|
||||
if 'ratio' in written and length.denominator & (length.denominator - 1) == 0:
|
||||
duration = next((size for size in generator.model.TYPE_LENGTHS.values() if size < length), length)
|
||||
written = generator.model.written_for(duration)
|
||||
yield duration, written
|
||||
length -= duration
|
||||
|
||||
def measures(document: dict):
|
||||
staff = document['staves'][0]
|
||||
if staff.get('arrangement_part_type') == 'acoustic':
|
||||
@@ -60,7 +50,7 @@ def prepare(document: dict) -> None:
|
||||
end = min(start + generator.model.fraction(n['duration']) for n in notes)
|
||||
end = min(end, groups[index + 1][0] if index + 1 < len(groups) else length)
|
||||
# A duration needing ties becomes one shorter attack followed by silence.
|
||||
duration, written = next(written_durations(end - start))
|
||||
duration, written = next(generator.accompaniment.written_durations(end - start))
|
||||
for note in notes:
|
||||
if generator.model.fraction(note['duration']) != duration:
|
||||
note.update(duration=generator.model.rational(duration), written=written)
|
||||
@@ -89,7 +79,7 @@ def combine(document: dict) -> None:
|
||||
|
||||
def rest(end):
|
||||
nonlocal cursor
|
||||
for duration, written in written_durations(end - cursor):
|
||||
for duration, written in generator.accompaniment.written_durations(end - cursor):
|
||||
notes.append(generator.model.make_event(f'{measure["id"]}-acoustic-{len(notes) + 1}', cursor, duration, 'rest', written=written) | {'voice': 'voice-arranged'})
|
||||
cursor += duration
|
||||
|
||||
|
||||
+1
-1
@@ -84,7 +84,7 @@ def load_library(root: pathlib.Path) -> Library:
|
||||
snippets = []
|
||||
for path in sorted(root.rglob('*.xml')):
|
||||
relative = path.relative_to(root)
|
||||
if len(relative.parts) != 3 or relative.parts[0] not in ('2-4', '3-4', '4-4', '5-4') or relative.parts[1] not in ('1', '2'):
|
||||
if len(relative.parts) != 3 or relative.parts[0] not in ('2-4', '3-4', '4-4', '5-4') or relative.parts[1] not in ('1', '2', '3'):
|
||||
raise ValueError(f'{path}: rhythm sources belong under meter/series')
|
||||
snippet = read_snippet(path, relative.as_posix())
|
||||
if snippet.meter != relative.parts[0].replace('-', '/'):
|
||||
|
||||
Reference in New Issue
Block a user