✅ VOICE GENERATION SYSTEM COMPLETE: **Script Created:** scripts/generate_voices_edge_tts.py - Async voice generation using Microsoft Edge TTS - Multiple character voices configured - English + Slovenian support - Adjustable rate and pitch **Voice Configurations:** - Kai (EN): en-US-AvaNeural (young female) - Kai (SL): sl-SI-PetraNeural - Ana (EN): en-US-JennyNeural (warm, friendly) - Narrator (EN): en-US-GuyNeural (deep, storytelling) **Test Generation SUCCESS:** ✅ Generated: kai_test_01.mp3 (17,280 bytes) Text: 'My name is Kai, and I will find my sister.' Voice: en-US-AvaNeural Quality: High-quality AI voice synthesis **Features:** - Automatic MP3 generation - Organized output to /assets/audio/voices/[character]/ - Configurable speech rate (-50% to +100%) - Configurable pitch (-50Hz to +50Hz) - Batch generation functions ready **Usage:** python3 scripts/generate_voices_edge_tts.py **Next Steps:** 1. Uncomment generate_kai_voices() for full Kai dialogue 2. Generate Ana, Narrator voices 3. Add sound effects using similar approach (or freesound.org) 4. Generate background music (use AI music tools) 🎯 Audio Status: 67/99 files (68% complete + voice generator ready)
140 lines
4.4 KiB
Python
Executable File
140 lines
4.4 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""
|
|
Edge TTS Voice Generator
|
|
Generate voice-over audio using Microsoft Edge TTS
|
|
"""
|
|
|
|
import asyncio
|
|
import edge_tts
|
|
from pathlib import Path
|
|
|
|
# Output directory
|
|
OUTPUT_DIR = Path("/Users/davidkotnik/repos/novafarma/assets/audio/voices")
|
|
|
|
# Voice configurations
|
|
VOICES = {
|
|
"kai_en": "en-US-AvaNeural", # English - female, young
|
|
"kai_sl": "sl-SI-PetraNeural", # Slovenian
|
|
"ana_en": "en-US-JennyNeural", # English - warm, friendly
|
|
"ana_sl": "sl-SI-PetraNeural",
|
|
"narrator_en": "en-US-GuyNeural", # English - deep, storytelling
|
|
"narrator_sl": "sl-SI-RokNeural", # Slovenian male
|
|
}
|
|
|
|
async def generate_voice(text: str, voice: str, output_path: Path, rate: str = "+0%", pitch: str = "+0Hz"):
|
|
"""
|
|
Generate voice audio from text
|
|
|
|
Args:
|
|
text: Text to convert to speech
|
|
voice: Voice ID (e.g. "en-US-AvaNeural")
|
|
output_path: Where to save the MP3
|
|
rate: Speech rate (-50% to +100%)
|
|
pitch: Speech pitch (-50Hz to +50Hz)
|
|
"""
|
|
print(f"🎙️ Generating: {output_path.name}")
|
|
print(f" Voice: {voice}")
|
|
print(f" Text: {text[:50]}...")
|
|
|
|
# Create output directory
|
|
output_path.parent.mkdir(parents=True, exist_ok=True)
|
|
|
|
# Generate speech
|
|
communicate = edge_tts.Communicate(text, voice, rate=rate, pitch=pitch)
|
|
await communicate.save(str(output_path))
|
|
|
|
# Check file size
|
|
size = output_path.stat().st_size
|
|
print(f" ✅ Saved: {size:,} bytes\n")
|
|
|
|
async def generate_test():
|
|
"""Generate test voice for Kai"""
|
|
text = "My name is Kai, and I will find my sister."
|
|
output = OUTPUT_DIR / "kai" / "kai_test_01.mp3"
|
|
|
|
await generate_voice(
|
|
text=text,
|
|
voice=VOICES["kai_en"],
|
|
output_path=output
|
|
)
|
|
|
|
async def generate_kai_voices():
|
|
"""Generate Kai's voice lines"""
|
|
lines = [
|
|
"My name is Kai, and I will find my sister.",
|
|
"Ana, where are you? I won't give up.",
|
|
"This farm... it reminds me of home.",
|
|
"I need to keep farming. For Ana.",
|
|
"Another day, another harvest. But I won't forget."
|
|
]
|
|
|
|
for i, text in enumerate(lines, 1):
|
|
output = OUTPUT_DIR / "kai" / f"kai_{i:02d}.mp3"
|
|
await generate_voice(text, VOICES["kai_en"], output)
|
|
|
|
async def generate_ana_voices():
|
|
"""Generate Ana's voice lines (memories)"""
|
|
lines = [
|
|
"Kai... can you hear me?",
|
|
"Remember the farm... remember our home.",
|
|
"I'm still here, Kai. Don't forget me.",
|
|
"The valley holds secrets... find them."
|
|
]
|
|
|
|
for i, text in enumerate(lines, 1):
|
|
output = OUTPUT_DIR / "ana" / f"ana_{i:02d}.mp3"
|
|
await generate_voice(text, VOICES["ana_en"], output, rate="-10%", pitch="-5Hz")
|
|
|
|
async def generate_narrator_voices():
|
|
"""Generate narrator voice lines"""
|
|
lines = [
|
|
"In the Valley of Death, a young farmer searches for answers.",
|
|
"Long ago, this valley was green and full of life.",
|
|
"But the dead walk now, and the living must survive."
|
|
]
|
|
|
|
for i, text in enumerate(lines, 1):
|
|
output = OUTPUT_DIR / "narrator" / f"narrator_{i:02d}.mp3"
|
|
await generate_voice(text, VOICES["narrator_en"], output, rate="-5%")
|
|
|
|
async def list_available_voices():
|
|
"""List all available Edge TTS voices"""
|
|
print("\n📋 Available Edge TTS Voices:\n")
|
|
|
|
voices = await edge_tts.list_voices()
|
|
|
|
# Filter to relevant languages
|
|
relevant = [v for v in voices if v["Locale"].startswith(("en-", "sl-"))]
|
|
|
|
for voice in relevant[:20]: # Show first 20
|
|
print(f" {voice['ShortName']}")
|
|
print(f" Language: {voice['Locale']}")
|
|
print(f" Gender: {voice['Gender']}")
|
|
print()
|
|
|
|
async def main():
|
|
"""Main execution"""
|
|
print("="*60)
|
|
print("🎙️ EDGE TTS VOICE GENERATOR")
|
|
print("="*60)
|
|
|
|
# Generate test first
|
|
print("\n🧪 GENERATING TEST VOICE:\n")
|
|
await generate_test()
|
|
|
|
print("\n" + "="*60)
|
|
print("✅ TEST COMPLETE! Check: assets/audio/voices/kai/kai_test_01.mp3")
|
|
print("="*60)
|
|
|
|
# Ask if user wants to continue
|
|
print("\n📝 To generate all voices, uncomment the function calls below.")
|
|
|
|
if __name__ == "__main__":
|
|
# Run async main
|
|
asyncio.run(main())
|
|
|
|
# UNCOMMENT BELOW TO GENERATE ALL VOICES:
|
|
# asyncio.run(generate_kai_voices())
|
|
# asyncio.run(generate_ana_voices())
|
|
# asyncio.run(generate_narrator_voices())
|