#!/usr/bin/env python3 """Build confirmed-name aliases for native GodotSpikeBridge sound registrations.""" from __future__ import annotations import argparse import csv import os import re from pathlib import Path def slug(value: str) -> str: return re.sub(r"[^A-Za-z0-9_]+", "_", value).strip("_") or "sound" def main() -> int: parser = argparse.ArgumentParser(description=__doc__) parser.add_argument("--sound-manifest", type=Path, default=Path("analysis/radium-image/sound_export_manifest.tsv")) parser.add_argument("--native-map", type=Path, default=Path("analysis/radium-image/native_sound_id_map.tsv")) parser.add_argument("--alias-dir", type=Path, default=Path("analysis/radium-image/sounds-native-named")) parser.add_argument("--out", type=Path, default=Path("analysis/radium-image/native_named_sound_manifest.tsv")) args = parser.parse_args() manifest = list(csv.DictReader(args.sound_manifest.open(newline=""), delimiter="\t")) by_object = {int(row["primary_object_local_id"]): row for row in manifest if row["primary_object_local_id"]} native_rows = list(csv.DictReader(args.native_map.open(newline=""), delimiter="\t")) args.alias_dir.mkdir(parents=True, exist_ok=True) output_rows: list[dict[str, object]] = [] for native in native_rows: sound_id = int(native["native_sound_id"]) source = by_object.get(sound_id) if source is None: continue source_path = Path(source["wav_path"]) alias_name = ( f"{slug(native['name'])}" f"__obj{sound_id:04d}" f"_s{int(source['section8_index']):04d}" f"_{source['channels']}ch_{source['sample_rate']}hz.wav" ) alias_path = args.alias_dir / alias_name if not alias_path.exists(): try: os.link(source_path, alias_path) link_type = "hardlink" except OSError: alias_path.symlink_to(Path("..") / "sounds" / source_path.name) link_type = "symlink" else: link_type = "existing" output_rows.append( { "name": native["name"], "native_sound_id": sound_id, "alias_wav_path": alias_path.as_posix(), "source_wav_path": source_path.as_posix(), "section8_index": source["section8_index"], "duration_seconds": source["duration_seconds"], "channels": source["channels"], "sample_rate": source["sample_rate"], "command_ref_count": source["command_ref_count"], "register_call_ghidra": native["register_call_ghidra"], "string_ghidra": native["string_ghidra"], "link_type": link_type, } ) fields = [ "name", "native_sound_id", "alias_wav_path", "source_wav_path", "section8_index", "duration_seconds", "channels", "sample_rate", "command_ref_count", "register_call_ghidra", "string_ghidra", "link_type", ] with args.out.open("w", newline="") as f: writer = csv.DictWriter(f, fieldnames=fields, delimiter="\t") writer.writeheader() writer.writerows(output_rows) print(f"wrote {args.out} rows={len(output_rows)} alias_dir={args.alias_dir}") return 0 if len(output_rows) == len(native_rows) else 1 if __name__ == "__main__": raise SystemExit(main())