+41
-33
@@ -1,24 +1,28 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import pathlib
|
||||
import shutil
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
from time import monotonic
|
||||
import time
|
||||
|
||||
from generator.arrange.generate import generate_performance_scores
|
||||
from generator.practice.generate import generate_practice_scores
|
||||
from generator.score import count_json_files, validate_generated_tree
|
||||
from generator.summary import validate_expected_performance_summary, validate_practice_parts
|
||||
from generator.parts import source_paths
|
||||
from generator.engraving import Fonts, Style, engrave_tree
|
||||
from generator.engraving.cache import renderer_fingerprint
|
||||
from generator.playback import compile_tree
|
||||
from generator.catalog import build_catalog
|
||||
import generator.arrange.generate
|
||||
import generator.catalog
|
||||
import generator.engraving.cache
|
||||
import generator.engraving.fonts
|
||||
import generator.engraving.pipeline
|
||||
import generator.engraving.types
|
||||
import generator.parts
|
||||
import generator.pico_artwork
|
||||
import generator.playback
|
||||
import generator.practice.generate
|
||||
import generator.rhythm
|
||||
import generator.score
|
||||
import generator.summary
|
||||
|
||||
RUNTIME_FONT_FILES = ("PetalumaScript.otf", "OFL.txt")
|
||||
|
||||
def copy_runtime_fonts(static_assets_dir: Path, output_dir: Path) -> None:
|
||||
def copy_runtime_fonts(static_assets_dir: pathlib.Path, output_dir: pathlib.Path) -> None:
|
||||
source = static_assets_dir / "fonts" / "petaluma"
|
||||
destination = output_dir / "fonts" / "petaluma"
|
||||
destination.mkdir(parents=True, exist_ok=True)
|
||||
@@ -27,12 +31,12 @@ def copy_runtime_fonts(static_assets_dir: Path, output_dir: Path) -> None:
|
||||
|
||||
def parse_args() -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser(description="Generate Product Vamp package score assets.")
|
||||
parser.add_argument("--data-dir", type=Path)
|
||||
parser.add_argument("--output-dir", type=Path)
|
||||
parser.add_argument("--data-dir", type=pathlib.Path)
|
||||
parser.add_argument("--output-dir", type=pathlib.Path)
|
||||
parser.add_argument("--renderer-fingerprint", action="store_true", help="Print the engraving cache identity without generating assets.")
|
||||
parser.add_argument("--static-assets-dir", type=Path, default=Path("package/assets"))
|
||||
parser.add_argument("--static-assets-dir", type=pathlib.Path, default=pathlib.Path("package/assets"))
|
||||
parser.add_argument("--check", action="store_true")
|
||||
parser.add_argument("--engraving-cache", type=Path)
|
||||
parser.add_argument("--engraving-cache", type=pathlib.Path)
|
||||
parser.add_argument("--jobs", type=int, default=1, choices=range(1, 17), metavar="1-16")
|
||||
parser.add_argument("--progress", action="store_true")
|
||||
args = parser.parse_args()
|
||||
@@ -49,11 +53,11 @@ def generate_assets(args: argparse.Namespace) -> None:
|
||||
if cache_dir and (cache_dir.is_relative_to(output_dir) or output_dir.is_relative_to(cache_dir)):
|
||||
raise ValueError('engraving cache and generated assets must not overlap')
|
||||
progress = getattr(args, 'progress', False)
|
||||
started = monotonic()
|
||||
started = time.monotonic()
|
||||
|
||||
def report(message):
|
||||
if progress:
|
||||
print(f'Assets [{monotonic() - started:.0f}s]: {message}', flush=True)
|
||||
print(f'Assets [{time.monotonic() - started:.0f}s]: {message}', flush=True)
|
||||
|
||||
report('checking source paths')
|
||||
for source in sorted(data_dir.rglob('*.xml')):
|
||||
@@ -61,29 +65,33 @@ def generate_assets(args: argparse.Namespace) -> None:
|
||||
continue
|
||||
if source.parent not in (data_dir / 'practice', data_dir / 'songs'):
|
||||
raise ValueError(f'{source}: MusicXML sources belong directly under data/practice or data/songs')
|
||||
source_paths(data_dir / 'songs')
|
||||
source_paths(data_dir / 'practice', practice=True)
|
||||
generator.parts.source_paths(data_dir / 'songs')
|
||||
generator.parts.source_paths(data_dir / 'practice', practice=True)
|
||||
report('loading rhythm snippets')
|
||||
rhythms = generator.rhythm.load_library(data_dir / 'rhythms')
|
||||
output_dir.parent.mkdir(parents=True, exist_ok=True)
|
||||
with tempfile.TemporaryDirectory(prefix='.vamp-assets-', dir=output_dir.parent) as temporary:
|
||||
staged = Path(temporary) / 'assets'
|
||||
staged = pathlib.Path(temporary) / 'assets'
|
||||
staged.mkdir(parents=True, exist_ok=True)
|
||||
copy_runtime_fonts(static_assets_dir, staged)
|
||||
report('generating performance and practice parts')
|
||||
performance_count = generate_performance_scores(data_dir / 'songs', staged / 'songs')
|
||||
practice_count = generate_practice_scores(data_dir / 'practice', staged / 'practice')
|
||||
validate_generated_tree(staged)
|
||||
performance_count = generator.arrange.generate.generate_performance_scores(data_dir / 'songs', staged / 'songs', rhythms=rhythms)
|
||||
practice_count = generator.practice.generate.generate_practice_scores(data_dir / 'practice', staged / 'practice', rhythms=rhythms)
|
||||
generator.score.validate_generated_tree(staged)
|
||||
if args.check:
|
||||
validate_expected_performance_summary(data_dir / 'expected' / 'performance_summary.json', staged / 'songs')
|
||||
validate_practice_parts(staged / 'practice')
|
||||
generator.summary.validate_expected_performance_summary(data_dir / 'expected' / 'performance_summary.json', staged / 'songs')
|
||||
generator.summary.validate_practice_parts(staged / 'practice')
|
||||
report('compiling playback')
|
||||
compile_tree(staged)
|
||||
generator.playback.compile_tree(staged)
|
||||
report('engraving pages')
|
||||
engrave_tree(staged, static_assets_dir / 'fonts' / 'petaluma', cache_dir=cache_dir, jobs=getattr(args, 'jobs', 1), progress=progress)
|
||||
validated_pages = generator.engraving.pipeline.engrave_tree(staged, static_assets_dir / 'fonts' / 'petaluma', cache_dir=cache_dir, jobs=getattr(args, 'jobs', 1), progress=progress)
|
||||
report('rendering Pico titles')
|
||||
generator.pico_artwork.generate_titles(staged, static_assets_dir / 'fonts' / 'petaluma')
|
||||
report('validating score, page, and audio assets')
|
||||
validate_generated_tree(staged)
|
||||
generator.score.validate_generated_tree(staged, validated_pages)
|
||||
report('building catalog database')
|
||||
build_catalog(staged)
|
||||
backup = Path(temporary) / 'previous'
|
||||
generator.catalog.build_catalog(staged)
|
||||
backup = pathlib.Path(temporary) / 'previous'
|
||||
if output_dir.exists():
|
||||
output_dir.rename(backup)
|
||||
try:
|
||||
@@ -94,14 +102,14 @@ def generate_assets(args: argparse.Namespace) -> None:
|
||||
raise
|
||||
report('publishing complete')
|
||||
print(f'Generated Product Vamp assets: {performance_count} performance scores, '
|
||||
f'{practice_count} practice parts, {count_json_files(output_dir)} total JSON files.')
|
||||
f'{practice_count} practice parts, {generator.score.count_json_files(output_dir)} total JSON files.')
|
||||
if args.check:
|
||||
print('Generator check passed.')
|
||||
|
||||
def main() -> int:
|
||||
args = parse_args()
|
||||
if args.renderer_fingerprint:
|
||||
print(renderer_fingerprint(Fonts(args.static_assets_dir / 'fonts' / 'petaluma'), Style()))
|
||||
print(generator.engraving.cache.renderer_fingerprint(generator.engraving.fonts.Fonts(args.static_assets_dir / 'fonts' / 'petaluma'), generator.engraving.types.Style()))
|
||||
else:
|
||||
generate_assets(args)
|
||||
return 0
|
||||
|
||||
Reference in New Issue
Block a user