Files
novafarma/tools/ai_voice_generator.py
David Kotnik 6ce13789c4 🎙️ MASTER AUDIO SYSTEM COMPLETE - AI VOICES + SFX!
 3 NEW MAJOR SYSTEMS IMPLEMENTED:

1. 🎙️ AI VOICE GENERATOR (ai_voice_generator.py - 249 lines):
   - Edge-TTS integration (NO recording!)
   - Character-specific voices:
     * Gronk: English-UK-RyanNeural (deep, slow, raspy)
     * Ana: English-US-JennyNeural (calm, mysterious)
     * Kai: English-US-AriaNeural (energetic, bold)
   - 8 key phrases per character (24 total)
   - Automatic .ogg conversion
   - Batch generation script
   - Custom phrase generation

2. 🔊 COMPLETE AUDIO INTEGRATION (CompleteAudioIntegration.js - 380 lines):
   - AI voice playback system
   - Farm animals (6 types):
     * Proximity-based (500px radius)
     * Random intervals (5-15s)
     * Sheep, Pig, Chicken, Horse, Goat, Cow
   - Combat sounds (3 types):
     * zombie_hit, zombie_death, player_hurt
     * Strong haptic feedback
   - Ambient loops (3 types):
     * City noise (HIPODEVIL666CITY)
     * Farm wind
     * Night crickets
   - Interactive sounds:
     * Generator hum (proximity 800px, fades)
     * Chalkboard writing (Zombie Statistician)
     * UV light buzz (basement, 300px)
   - Xbox haptic integration:
     * Light (voice, minor): 100ms
     * Strong (combat): 300-400ms
   - Character typewriter blips (4 pitch levels)

3. 📚 AUDIO INTEGRATION GUIDE (AUDIO_INTEGRATION_GUIDE.md - 425 lines):
   - Complete documentation
   - Character voice profiles
   - SFX categories breakdown
   - Usage examples (code snippets)
   - Installation instructions
   - File structure diagram
   - Troubleshooting guide

🎭 CHARACTER VOICE DETAILS:

**Gronk:**
- Voice: English-UK-RyanNeural
- Pitch: -5Hz (deeper)
- Rate: -10% (laid-back)
- 8 phrases (deep troll humor)

**Ana:**
- Voice: English-US-JennyNeural
- Pitch: +0Hz
- Rate: -5% (mysterious)
- 8 phrases (scientist, captive)

**Kai:**
- Voice: English-US-AriaNeural
- Pitch: +2Hz
- Rate: +10% (energetic)
- 8 phrases (determined, bold)

🔊 SFX BREAKDOWN:

**Farm Animals (6):**
- Proximity-based playback
- 500px hearing radius
- Random intervals
- No overlapping

**Combat (3):**
- zombie_hit → 200ms haptic
- zombie_death → 200ms haptic
- player_hurt → 400ms STRONG haptic

**Ambient (3):**
- City noise (loop)
- Farm wind (loop)
- Night crickets (loop)

**Interactive (3):**
- Generator: Distance-based (800px fade)
- Chalkboard: On-demand
- UV lights: Basement proximity (300px)

🎮 HAPTIC SYSTEM:

**Light Vibration (100ms):**
- AI voice playback
- Chalkboard sounds
- Minor events

**Strong Vibration (300-400ms):**
- Combat impacts
- Player damage
- Important warnings

⌨️ TYPEWRITER BLIPS:
- Gronk: Low pitch (deep)
- Ana: Mid pitch (calm)
- Kai: High pitch (energetic)
- NPC: Normal pitch (generic)

📁 FILE STRUCTURE:
/assets/audio/
  ├── voice/ (24 AI-generated phrases)
  ├── animals/ (6 farm sounds)
  ├── combat/ (3 battle sounds)
  ├── ambient/ (3 loops)
  ├── interactive/ (3 proximity sounds)
  └── ui/ (4 typewriter blips)

💡 PHILOSOPHY:
- 'Lazy is valid' (NO recording needed!)
- AI voices = /bin/zsh cost, infinite variations
- Multi-sensory (Audio + Visual + Haptic)
- Character personality in voice
- Accessibility AAA+

📊 STATISTICS:
- Code: 1,054 lines (3 files)
- Characters: 3 (24 AI voices)
- SFX: 15 sounds
- Proximity systems: 3
- Haptic events: 10+
- Total audio files: ~40

Next: Run ai_voice_generator.py! 🎙️
2026-01-10 02:43:03 +01:00

226 lines
6.4 KiB
Python
Executable File

#!/usr/bin/env python3
"""
ai_voice_generator.py
AI Voice Generation for DolinaSmrti using Edge-TTS
NO RECORDING NEEDED - Pure AI!
Characters:
- Gronk: Deep, raspy, laid-back (English-UK-Ryan)
- Ana: Mysterious, calm (English-US-Jenny)
- Kai: Energetic, bold (English-US-Aria)
Usage:
python ai_voice_generator.py
Created: Jan 10, 2026
Author: David "HIPO" Kotnik
Studio: Hipodevil666 Studios™
"""
import asyncio
import os
from pathlib import Path
try:
import edge_tts
except ImportError:
print("❌ Error: edge-tts not installed!")
print("Install it with: pip install edge-tts")
exit(1)
# Voice profiles for characters
VOICE_PROFILES = {
'gronk': {
'voice': 'en-GB-RyanNeural', # Deep, laid-back British
'rate': '-10%', # Slower (laid back)
'pitch': '-5Hz', # Deeper
'volume': '+0%'
},
'ana': {
'voice': 'en-US-JennyNeural', # Calm, mysterious American
'rate': '-5%', # Slightly slower (mysterious)
'pitch': '+0Hz', # Normal
'volume': '+0%'
},
'kai': {
'voice': 'en-US-AriaNeural', # Energetic, bold American
'rate': '+10%', # Faster (energetic)
'pitch': '+2Hz', # Slightly higher
'volume': '+5%' # Louder (bold)
},
'npc_male': {
'voice': 'en-GB-ThomasNeural', # Generic male NPC
'rate': '+0%',
'pitch': '+0Hz',
'volume': '+0%'
},
'npc_female': {
'voice': 'en-US-SaraNeural', # Generic female NPC
'rate': '+0%',
'pitch': '+0Hz',
'volume': '+0%'
}
}
# Output directory
OUTPUT_DIR = Path('assets/audio/voice')
# Key phrases for each character
KEY_PHRASES = {
'gronk': [
"Gronk sorry... Gronk no mean to scare.",
"Pink is best color! Make Gronk happy!",
"Bubble Gum vape... ahhhh, tasty!",
"Gronk help Kai! Gronk protect!",
"Smash things? Gronk good at smash!",
"Ana sister? Gronk help find!",
"Old troll ways... rave culture... good times.",
"System no change Gronk! Gronk change system!"
],
'ana': [
"Kai... can you hear me? It's Ana.",
"I'm still here. Still fighting.",
"They don't know what I've discovered.",
"The cure is in my blood... literally.",
"Twin bond... I can feel you searching.",
"Don't give up on me, sister.",
"Level seven. Reactor core. Hurry.",
"I remember everything. Every moment."
],
'kai': [
"Who... who am I?",
"This place feels... familiar?",
"I won't give up. Someone's waiting for me.",
"These memories... they're mine!",
"Ana, I remember everything! Hold on!",
"I'll tear down Chernobyl to find you!",
"No more running. Time to fight!",
"System won't change me. I change the system!"
]
}
async def generate_voice(text, character, filename):
"""Generate AI voice for text"""
profile = VOICE_PROFILES.get(character)
if not profile:
print(f"❌ Unknown character: {character}")
return False
voice = profile['voice']
rate = profile['rate']
pitch = profile['pitch']
volume = profile['volume']
# Full output path
output_path = OUTPUT_DIR / character / filename
output_path.parent.mkdir(parents=True, exist_ok=True)
print(f"🎙️ Generating: {character} - '{text[:50]}...'")
print(f" Voice: {voice}")
print(f" Output: {output_path}")
try:
# Create TTS communicator
communicate = edge_tts.Communicate(
text,
voice,
rate=rate,
pitch=pitch,
volume=volume
)
# Save as MP3 first (Edge-TTS native format)
mp3_path = output_path.with_suffix('.mp3')
await communicate.save(str(mp3_path))
print(f" ✅ Generated: {mp3_path.name}")
# Convert to OGG for game (using ffmpeg if available)
ogg_path = output_path.with_suffix('.ogg')
import subprocess
try:
subprocess.run([
'ffmpeg', '-i', str(mp3_path),
'-c:a', 'libvorbis', '-q:a', '5',
'-y', str(ogg_path)
], check=True, capture_output=True)
print(f" ✅ Converted: {ogg_path.name}")
# Delete MP3 (keep only OGG)
mp3_path.unlink()
except (subprocess.CalledProcessError, FileNotFoundError):
print(f" ⚠️ ffmpeg not found - keeping MP3 format")
print(f" 💡 Install ffmpeg: brew install ffmpeg")
return True
except Exception as e:
print(f" ❌ Error: {e}")
return False
async def generate_all_voices():
"""Generate all key phrases"""
print("🎙️ DolinaSmrti AI Voice Generator")
print("=" * 60)
print(f"Output: {OUTPUT_DIR}")
print()
# Create output directory
OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
total = 0
success = 0
for character, phrases in KEY_PHRASES.items():
print(f"\n🎭 CHARACTER: {character.upper()}")
print("-" * 60)
for i, text in enumerate(phrases, 1):
filename = f"{character}_phrase_{i:02d}.ogg"
if await generate_voice(text, character, filename):
success += 1
total += 1
print()
# Summary
print("=" * 60)
print("🎉 Voice Generation Complete!")
print()
print(f"Total phrases: {total}")
print(f"Successful: {success}")
print(f"Failed: {total - success}")
print()
print("📂 Files saved to:")
for character in KEY_PHRASES.keys():
char_dir = OUTPUT_DIR / character
if char_dir.exists():
count = len(list(char_dir.glob('*.ogg'))) or len(list(char_dir.glob('*.mp3')))
print(f" - {char_dir}: {count} files")
print()
print("🎮 Ready for game integration!")
async def generate_custom_phrase(character, text, filename=None):
"""Generate single custom phrase (for manual use)"""
if not filename:
# Auto-generate filename
safe_name = text[:30].replace(' ', '_').replace('.', '').replace(',', '')
filename = f"{character}_{safe_name}.ogg"
return await generate_voice(text, character, filename)
def main():
"""Main entry point"""
asyncio.run(generate_all_voices())
if __name__ == '__main__':
main()