Files
product-vamp/generator/practice/generate.py
T
khodowany 7bb1ed2b13
ci / checks (push) Failing after 3h12m18s
Data Labels
2026-09-20 02:07:26 -05:00

70 lines
2.8 KiB
Python

from __future__ import annotations
from pathlib import Path
from generator.score import copy_source_voices, make_arranged_document, make_measure, reidentify, slugify, source_staff, write_json
from generator.musicxml import load_musicxml
from generator.practice.guitar import transpose_guitar_practice
from generator.transposition import TARGET_KEYS
def practice_document(document: dict) -> dict:
staff = source_staff(document)
source_measures = staff.get("measures")
if not isinstance(source_measures, list):
raise ValueError("practice source must contain measures")
measures: list[dict] = []
for index, measure in enumerate(source_measure for source_measure in source_measures if isinstance(source_measure, dict)):
voices = copy_source_voices(measure, strip_lyrics=True)
output_measure = make_measure(
f"measure-{index + 1}",
measure,
[],
section_label=str(measure.get("section_label", "")),
)
output_measure['voices'] = voices
for chord in output_measure['harmonies']:
chord.pop('chord_optional', None)
measures.append(output_measure)
tuplets = reidentify(measures, staff.get('tuplets', []))
result = make_arranged_document(
document,
staff,
staff_id="staff-arranged-practice",
staff_name="Practice",
role="guitar",
arrangement_part_type="practice",
measures=measures,
tuplets=tuplets,
octave_shifts=staff.get('octave_shifts', []),
)
result['metadata'].setdefault('authored_key_signature', document['metadata']['key_signature'])
return result
def key_file_name(key: str) -> str:
return slugify(key.replace("#", "sharp")) + ".json"
def generate_key_variants(source_path: Path, output_dir: Path) -> int:
base_document = practice_document(load_musicxml(source_path))
count = 0
for key in TARGET_KEYS:
try:
variant = transpose_guitar_practice(base_document, key)
except ValueError as error:
raise ValueError(f'{source_path}, target key {key}: {error}') from error
write_json(output_dir / source_path.stem / key_file_name(key), variant)
count += 1
return count
def generate_practice_scores(source_dir: Path, output_dir: Path) -> int:
if not source_dir.is_dir():
raise ValueError(f'practice source directory not found: {source_dir}')
sources = sorted(source_dir.glob('*.xml'))
for path in source_dir.rglob('*.xml'):
parts = path.relative_to(source_dir).parts
if len(parts) != 1 and (len(parts) != 2 or parts[0] != 'songs'):
raise ValueError(f'{path}: practice sources belong directly under the data directory')
for path in sources:
if len(path.stem) != 3 or not path.stem.isascii() or not path.stem.isdecimal() or int(path.stem) == 0:
raise ValueError(f'{path}: practice sources require a three-digit positive filename such as 001.xml')
return sum(generate_key_variants(path, output_dir) for path in sources)