@@ -2,7 +2,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import copy
|
||||
from fractions import Fraction as F
|
||||
import fractions
|
||||
|
||||
import generator.accompaniment
|
||||
import generator.acoustic
|
||||
@@ -13,39 +13,41 @@ import generator.fretboard
|
||||
import generator.model
|
||||
import generator.parts
|
||||
import generator.score
|
||||
from generator.arrange import form
|
||||
import generator.arrange.form
|
||||
import generator.arrange.pickup
|
||||
|
||||
|
||||
def harmonic_key(measure, previous):
|
||||
|
||||
def key(chord):
|
||||
return repr({k: chord.get(k) for k in ('root', 'kind', 'degrees', 'bass', 'inversion')}) if chord else ''
|
||||
active = generator.accompaniment.active_chord(measure, F(), previous)
|
||||
|
||||
active = generator.accompaniment.active_chord(measure, fractions.Fraction(), previous)
|
||||
return (key(active), tuple((generator.model.fraction(h['onset']), key(h)) for h in measure['harmonies']
|
||||
if generator.model.fraction(h['onset']) > 0), measure['duration'], measure['time_signature'])
|
||||
|
||||
|
||||
def audit(source, documents):
|
||||
"""Compare music, not generated IDs, at every reused form position."""
|
||||
authored = generator.score.source_staff(source)['measures']
|
||||
result = {}
|
||||
for part, document in documents.items():
|
||||
if part == 'vocal': continue
|
||||
sections = form.full_arrangement_sections(authored, part)
|
||||
if part == 'vocal':
|
||||
continue
|
||||
sections = generator.arrange.form.full_arrangement_sections(authored, part)
|
||||
measures = document['staves'][0]['measures']
|
||||
carried = generator.accompaniment.carried_chords(measures)
|
||||
seen, exceptions, offset, reused = {}, [], 0, 0
|
||||
for si, section in enumerate(sections):
|
||||
following = sections[si + 1] if si + 1 < len(sections) else None
|
||||
for j in range(section.measure_count):
|
||||
if section.role != 'accompaniment': continue
|
||||
m = measures[offset+j]
|
||||
if j == section.measure_count-1 and following and following.role == 'melody' and generator.arrange.pickup.enters(following, authored):
|
||||
if section.role != 'accompaniment':
|
||||
continue
|
||||
m = measures[offset + j]
|
||||
if j == section.measure_count - 1 and following and following.role == 'melody' and generator.arrange.pickup.enters(following, authored):
|
||||
exceptions.append({'measure': m['number'], 'reason': 'protected melody pickup'})
|
||||
continue
|
||||
key = (section.source_measure_index+j, repr(harmonic_key(m, carried[offset+j])))
|
||||
key = (section.source_measure_index + j, repr(harmonic_key(m, carried[offset + j])))
|
||||
signature = tuple((generator.model.fraction(n['onset']), generator.model.fraction(n['duration']),
|
||||
tuple((generator.model.pitch_number(p),p['tablature']['string'],p['tablature']['fret']) for p in n['pitches']))
|
||||
tuple((generator.model.pitch_number(p), p['tablature']['string'], p['tablature']['fret']) for p in n['pitches']))
|
||||
for n in generator.score.measure_notes(m))
|
||||
if key in seen:
|
||||
if signature != seen[key]:
|
||||
|
||||
@@ -28,10 +28,10 @@ def section_role(part_type: str, section_index: int) -> typing.Literal["accompan
|
||||
return "slash"
|
||||
if section_index == 2:
|
||||
return "melody"
|
||||
if section_index in {1, 3, 5, 6}:
|
||||
if section_index in {1, 3, 5}:
|
||||
return "accompaniment"
|
||||
return "rest"
|
||||
return "vocal" if section_index in {1, 5, 6} else "rest"
|
||||
return "vocal" if section_index in {1, 5} else "rest"
|
||||
|
||||
def full_arrangement_sections(measures: list[dict], part_type: str) -> list[ArrangementSection]:
|
||||
if not measures:
|
||||
@@ -49,7 +49,6 @@ def full_arrangement_sections(measures: list[dict], part_type: str) -> list[Arra
|
||||
("Acoustic Solo", body_start, body_measure_count, 3),
|
||||
("Electric Solo", body_start, body_measure_count, 4),
|
||||
("Vocal Melody", body_start, body_measure_count, 5),
|
||||
("Ending", edge_source_measure, edge_measure_count, 6),
|
||||
)
|
||||
return [
|
||||
ArrangementSection(label=label, source_measure_index=start, measure_count=count, section_index=index, role=section_role(part_type, index))
|
||||
|
||||
@@ -19,16 +19,18 @@ import generator.musicxml
|
||||
import generator.parts
|
||||
import generator.score
|
||||
import generator.solo.arrangement
|
||||
import generator.comping
|
||||
import generator.vocabulary
|
||||
import generator.production
|
||||
|
||||
FINAL_SECTION_INDEX = 6
|
||||
FINAL_SECTION_INDEX = 5
|
||||
|
||||
def arrange_document(document: dict, part_type: str) -> dict:
|
||||
"""Canonical source-only template; solos are inserted by production roles."""
|
||||
from generator import comping, vocabulary
|
||||
document=generator.parts.prepare_document(document)
|
||||
with vocabulary.using(vocabulary.load(),part_type+'_accompaniment'):
|
||||
backing=comping.Canonical(document,part_type,'canonical') if part_type!='vocal' else None
|
||||
return _arrange_document(document,part_type,accompaniment=backing)
|
||||
document = generator.parts.prepare_document(document)
|
||||
with generator.vocabulary.using(generator.vocabulary.load(), part_type + '_accompaniment'):
|
||||
backing = generator.comping.Canonical(document, part_type, 'canonical') if part_type != 'vocal' else None
|
||||
return _arrange_document(document, part_type, accompaniment=backing)
|
||||
|
||||
def section_source(source: list[dict], section, next_section=None) -> list[dict]:
|
||||
result = copy.deepcopy(source)
|
||||
@@ -115,5 +117,4 @@ def _arrange_document(document: dict, part_type: str, plans=None, *, owned=None,
|
||||
return result
|
||||
|
||||
def generate_performance_scores(source_dir: pathlib.Path, output_dir: pathlib.Path, *, composition_jobs=2, cache_dir=None, progress=False, timings=None) -> int:
|
||||
from generator.production import generate_tree
|
||||
return generate_tree(source_dir, output_dir, jobs=composition_jobs, cache_dir=cache_dir, progress=progress,timings=timings)
|
||||
return generator.production.generate_tree(source_dir, output_dir, jobs=composition_jobs, cache_dir=cache_dir, progress=progress, timings=timings)
|
||||
|
||||
Reference in New Issue
Block a user