#!/usr/bin/env python3 """ AUDIO PRODUCTION AUTOMATION SCRIPT Generates placeholder audio files and TTS voices for DolinaSmrti Uses edge-tts for voice synthesis (FREE Microsoft Azure TTS) """ import os import json import asyncio from pathlib import Path # Check if edge-tts is installed try: import edge_tts EDGE_TTS_AVAILABLE = True except ImportError: EDGE_TTS_AVAILABLE = False print("⚠️ edge-tts not installed. Install with: pip install edge-tts") # Audio output directory AUDIO_DIR = Path(__file__).parent.parent / "assets" / "audio" # Audio manifest AUDIO_MANIFEST = { "music": [ "main_theme.ogg", "farm_ambient.ogg", "combat_theme.ogg", "raid_warning.ogg", "town_theme.ogg", "night_theme.ogg", "victory_theme.ogg", "ana_theme.ogg" ], "ambience": [ "wind_soft.ogg", "wind_strong.ogg", "rain_light.ogg", "rain_heavy.ogg", "crickets.ogg", "birds_chirping.ogg", "fire_crackling.ogg", "water_stream.ogg", "zombie_moans_distant.ogg", "town_bustle.ogg", "workshop_ambient.ogg", "forest_ambient.ogg" ], "sfx": { "farming": [ "dig.ogg", "plant_seed.ogg", "harvest.ogg", "water_crop.ogg", "tree_chop.ogg", "stone_mine.ogg", "scythe_swing.ogg", "cow_moo.ogg" ], "combat": [ "sword_slash.ogg", "zombie_hit.ogg", "zombie_death.ogg", "player_hurt.ogg", "raider_attack.ogg", "shield_block.ogg", "bow_release.ogg", "explosion.ogg" ], "building": [ "hammer_nail.ogg", "door_open.ogg", "door_close.ogg", "chest_open.ogg", "repair.ogg" ], "misc": [ "footstep_grass.ogg", "footstep_stone.ogg", "coin_collect.ogg", "level_up.ogg" ] }, "ui": [ "button_click.ogg", "button_hover.ogg", "notification.ogg", "quest_complete.ogg", "error.ogg" ] } # NPC voice lines NPC_VOICES = { "kai": { "voice": "sl-SI-PetraNeural", # Slovenian female (can use for young male) "lines": [ "Živjo! Sem Kai.", "Moramo najti Ano.", "Zombiji prihajajo!", "Hvala za pomoč.", "To je nevarno..." ] }, "ana": { "voice": "sl-SI-RokNeural", # Slovenian male (soft) "lines": [ "Kai... kje si?", "Spomin mi uhaja...", "Pomagaj mi, prosim.", "Hvala ti." ] }, "teacher": { "voice": "sl-SI-PetraNeural", "lines": [ "Dobrodošel v šoli!", "Želiš se kaj naučiti?", "Odlično delo!", "Še ena lekcija?" ] }, "mayor": { "voice": "sl-SI-RokNeural", "lines": [ "Dobrodošel, meščan!", "Mesto potrebuje tvojo pomoč.", "Odlično! Mesto cveti.", "Hvala za vašo službo!" ] } } async def generate_voice_line(text, voice, output_path): """Generate a single voice line using edge-tts""" if not EDGE_TTS_AVAILABLE: print(f"⚠️ Skipping {output_path.name} - edge-tts not available") return False try: communicate = edge_tts.Communicate(text, voice) await communicate.save(str(output_path)) print(f"✅ Generated: {output_path.name}") return True except Exception as e: print(f"❌ Error generating {output_path.name}: {e}") return False async def generate_all_npc_voices(): """Generate all NPC voice lines""" voices_dir = AUDIO_DIR / "voices" voices_dir.mkdir(parents=True, exist_ok=True) total = 0 successful = 0 for npc_name, npc_data in NPC_VOICES.items(): npc_dir = voices_dir / npc_name npc_dir.mkdir(exist_ok=True) for i, line in enumerate(npc_data["lines"], 1): output_file = npc_dir / f"{npc_name}_{i:02d}.mp3" total += 1 if await generate_voice_line(line, npc_data["voice"], output_file): successful += 1 print(f"\n🎤 Voice Generation: {successful}/{total} successful") def create_placeholder_files(): """Create placeholder text files for all audio""" print("\n📝 Creating placeholder files...\n") # Music music_dir = AUDIO_DIR / "music" music_dir.mkdir(parents=True, exist_ok=True) for track in AUDIO_MANIFEST["music"]: placeholder = music_dir / f"{track}.txt" placeholder.write_text(f"PLACEHOLDER: {track}\nDuration: 2-3 minutes\nStyle: Dark folk/post-apocalyptic\nLoop: Yes") print(f"📄 {track}.txt") # Ambience ambience_dir = AUDIO_DIR / "ambience" ambience_dir.mkdir(parents=True, exist_ok=True) for amb in AUDIO_MANIFEST["ambience"]: placeholder = ambience_dir / f"{amb}.txt" placeholder.write_text(f"PLACEHOLDER: {amb}\nDuration: 30-60 seconds\nLoop: Seamless\nSource: Freesound.org") print(f"📄 {amb}.txt") # SFX for category, sounds in AUDIO_MANIFEST["sfx"].items(): sfx_dir = AUDIO_DIR / "sfx" / category sfx_dir.mkdir(parents=True, exist_ok=True) for sfx in sounds: placeholder = sfx_dir / f"{sfx}.txt" placeholder.write_text(f"PLACEHOLDER: {sfx}\nCategory: {category}\nDuration: 0.1-2 seconds\nFormat: OGG Vorbis") print(f"📄 {sfx}.txt") # UI ui_dir = AUDIO_DIR / "ui" ui_dir.mkdir(parents=True, exist_ok=True) for ui_sound in AUDIO_MANIFEST["ui"]: placeholder = ui_dir / f"{ui_sound}.txt" placeholder.write_text(f"PLACEHOLDER: {ui_sound}\nDuration: 0.1-0.5 seconds\nFormat: OGG Vorbis\nCrisp, clean sound") print(f"📄 {ui_sound}.txt") print(f"\n✅ Created {61} placeholder files!") def generate_audio_manifest_json(): """Generate audio_manifest.json for loading""" manifest_path = AUDIO_DIR / "audio_manifest.json" manifest_data = { "version": "1.0", "total_files": 61, "categories": { "music": len(AUDIO_MANIFEST["music"]), "ambience": len(AUDIO_MANIFEST["ambience"]), "sfx": sum(len(sounds) for sounds in AUDIO_MANIFEST["sfx"].values()), "ui": len(AUDIO_MANIFEST["ui"]), "voices": sum(len(npc["lines"]) for npc in NPC_VOICES.values()) }, "files": AUDIO_MANIFEST } manifest_path.write_text(json.dumps(manifest_data, indent=2)) print(f"\n✅ Generated audio_manifest.json") async def main(): """Main execution""" print("🎵 DolinaSmrti - Audio Production Automation") print("=" * 50) # Create directories AUDIO_DIR.mkdir(parents=True, exist_ok=True) # Step 1: Create placeholder files create_placeholder_files() # Step 2: Generate manifest generate_audio_manifest_json() # Step 3: Generate NPC voices (if edge-tts available) if EDGE_TTS_AVAILABLE: print("\n🎤 Generating NPC voice lines...") await generate_all_npc_voices() else: print("\n⚠️ Install edge-tts to generate NPC voices:") print(" pip install edge-tts") print("\n" + "=" * 50) print("✅ AUDIO PRODUCTION SETUP COMPLETE!") print("\nNext steps:") print("1. Install edge-tts: pip install edge-tts") print("2. Run this script again to generate voices") print("3. Source music/SFX from Freesound.org or AI music generators") print("4. Convert all files to OGG Vorbis format") if __name__ == "__main__": asyncio.run(main())