+31
-26
@@ -17,9 +17,12 @@ import generator.engraving.pipeline
|
||||
import generator.engraving.types
|
||||
import generator.parts
|
||||
import generator.pico_artwork
|
||||
import generator.playback
|
||||
import generator.performance
|
||||
import generator.score
|
||||
import generator.summary
|
||||
import generator.solo.export
|
||||
import platform
|
||||
import os
|
||||
|
||||
RUNTIME_FONT_FILES = ("PetalumaScript.otf", "OFL.txt")
|
||||
|
||||
@@ -42,8 +45,8 @@ def parse_args() -> argparse.Namespace:
|
||||
parser.add_argument("--composition-jobs", type=int, default=2, choices=range(1, 17), metavar="1-16")
|
||||
parser.add_argument("--composition-cache", type=pathlib.Path)
|
||||
parser.add_argument("--export-solo-xml", action="store_true", help="Export completed solo roles as comparison MusicXML, without recomposing.")
|
||||
parser.add_argument("--trace-level",choices=("summary","full"),default="summary",help="Diagnostic detail only; does not seed composition.")
|
||||
parser.add_argument("--profile-output",type=pathlib.Path,help="Write build and per-role elapsed timings (not a search timeout).")
|
||||
parser.add_argument("--trace-level", choices=("summary", "full"), default="summary", help="Diagnostic detail only; does not seed composition.")
|
||||
parser.add_argument("--profile-output", type=pathlib.Path, help="Write build and per-role elapsed timings (not a search timeout).")
|
||||
parser.add_argument("--progress", action="store_true")
|
||||
args = parser.parse_args()
|
||||
if not args.renderer_fingerprint and (args.data_dir is None or args.output_dir is None):
|
||||
@@ -58,19 +61,22 @@ def generate_assets(args: argparse.Namespace) -> None:
|
||||
cache_dir = cache_dir.resolve() if cache_dir else 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')
|
||||
composition_cache = getattr(args,'composition_cache',None)
|
||||
composition_cache = getattr(args, 'composition_cache', None)
|
||||
if composition_cache:
|
||||
composition_cache=composition_cache.resolve()
|
||||
composition_cache = composition_cache.resolve()
|
||||
if composition_cache.is_relative_to(output_dir) or output_dir.is_relative_to(composition_cache):
|
||||
raise ValueError('composition cache and generated assets must not overlap')
|
||||
progress = getattr(args, 'progress', False)
|
||||
started = time.monotonic()
|
||||
timings=[];stages=[];last_stage=started
|
||||
timings = []
|
||||
stages = []
|
||||
last_stage = started
|
||||
|
||||
def report(message):
|
||||
nonlocal last_stage
|
||||
now=time.monotonic()
|
||||
stages.append({'completed_before':message,'seconds':now-last_stage});last_stage=now
|
||||
now = time.monotonic()
|
||||
stages.append({'completed_before': message, 'seconds': now - last_stage})
|
||||
last_stage = now
|
||||
if progress:
|
||||
print(f'Assets [{time.monotonic() - started:.0f}s]: {message}', flush=True)
|
||||
|
||||
@@ -82,23 +88,23 @@ def generate_assets(args: argparse.Namespace) -> None:
|
||||
staged.mkdir(parents=True, exist_ok=True)
|
||||
copy_runtime_fonts(static_assets_dir, staged)
|
||||
report('generating performance parts')
|
||||
performance_count = generator.arrange.generate.generate_performance_scores(data_dir / 'songs', staged / 'songs',
|
||||
composition_jobs=getattr(args,'composition_jobs',2), cache_dir=getattr(args,'composition_cache',None), progress=progress,timings=timings)
|
||||
if getattr(args,'trace_level','summary')=='summary':
|
||||
for path in (staged/'analysis').glob('*.roles'):
|
||||
roles=json.loads(path.read_text())
|
||||
performance_count = generator.arrange.generate.generate_performance_scores(data_dir / 'songs', staged / 'songs', composition_jobs=getattr(args, 'composition_jobs', 2), cache_dir=getattr(args, 'composition_cache', None), progress=progress, timings=timings)
|
||||
if getattr(args, 'trace_level', 'summary') == 'summary':
|
||||
for path in (staged / 'analysis').glob('*.roles'):
|
||||
roles = json.loads(path.read_text())
|
||||
for role in roles.values():
|
||||
trace=role.get('details',{}).get('selection_trace',{})
|
||||
trace.pop('decisions',None)
|
||||
path.write_text(json.dumps(roles,sort_keys=True,indent=2))
|
||||
trace = role.get('details', {}).get('selection_trace', {})
|
||||
trace.pop('decisions', None)
|
||||
path.write_text(json.dumps(roles, sort_keys=True, indent=2))
|
||||
if getattr(args, 'export_solo_xml', False):
|
||||
from generator.solo.export import export_tree
|
||||
export_tree(staged)
|
||||
generator.solo.export.export_tree(staged)
|
||||
generator.score.validate_generated_tree(staged)
|
||||
if args.check:
|
||||
generator.summary.validate_expected_performance_summary(pathlib.Path(__file__).resolve().parents[1] / 'tests' / 'fixtures' / 'performance_summary.json', staged / 'songs')
|
||||
report('compiling playback')
|
||||
generator.playback.compile_tree(staged)
|
||||
report('copying supplied recordings')
|
||||
song_ids = {generator.score.slugify(path.stem) for path in (data_dir / 'songs').glob('*.xml')}
|
||||
audio_assets = generator.performance.copy_audio(static_assets_dir, staged, song_ids)
|
||||
generator.performance.validate_recording_lengths(staged, audio_assets)
|
||||
report('engraving pages')
|
||||
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')
|
||||
@@ -106,16 +112,15 @@ def generate_assets(args: argparse.Namespace) -> None:
|
||||
report('validating score, page, and audio assets')
|
||||
generator.score.validate_generated_tree(staged, validated_pages)
|
||||
report('building catalog database')
|
||||
generator.catalog.build_catalog(staged)
|
||||
generator.catalog.build_catalog(staged, audio_assets=audio_assets)
|
||||
with modulus.filesystem.publish_directories([(staged, output_dir)]):
|
||||
pass
|
||||
report('publishing complete')
|
||||
profile_path=getattr(args,'profile_output',None)
|
||||
profile_path = getattr(args, 'profile_output', None)
|
||||
if profile_path:
|
||||
import platform,os
|
||||
profile_path.parent.mkdir(parents=True,exist_ok=True)
|
||||
profile_path.write_text(json.dumps({'total_seconds':time.monotonic()-started,'stages':stages,'roles':timings,
|
||||
'platform':platform.platform(),'cpus':os.cpu_count(),'workers':getattr(args,'composition_jobs',2)},indent=2))
|
||||
profile_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
profile_path.write_text(json.dumps({'total_seconds': time.monotonic() - started, 'stages': stages, 'roles': timings,
|
||||
'platform': platform.platform(), 'cpus': os.cpu_count(), 'workers': getattr(args, 'composition_jobs', 2)}, indent=2))
|
||||
print(f'Generated Product Vamp assets: {performance_count} performance scores.')
|
||||
if args.check:
|
||||
print('Generator check passed.')
|
||||
|
||||
Reference in New Issue
Block a user