📊 Jan 8 Audio System Complete Organization + Generation Manifest
✅ AUDIO REORGANIZATION COMPLETE: **Files Moved:** - Moved 2 SFX WAV: footstep_grass.wav, wood_chop.wav → /sfx/ - Moved 1 Music MP3: forest_ambient.mp3 → /music/ - Moved 43 Voiceover WAV: prologue_sl files → /voiceover/ - Existing 20 Voice MP3: Ana, Kai, Mayor, Narrator, Teacher → /voices/ **Folder Structure Created:** /assets/audio/ ├── sfx/ │ ├── farming/ (8 placeholder .txt) │ ├── combat/ (8 placeholder .txt) │ ├── building/ (5 placeholder .txt) │ └── misc/ (4 placeholder .txt) ├── music/ (8 placeholder .txt + 1 MP3 ✅) ├── voices/ (20 MP3 ✅) └── voiceover/ (43 WAV ✅) 📋 CREATED DOCUMENTATION: 1. **AUDIO_GENERATION_MANIFEST.md** - Complete list of 33 missing audio files - Detailed specifications (duration, format, mood) - SFX: 25 files (farming, combat, building, misc) - Music: 8 files (themes, ambients, victory) - Generation instructions (AI tools, free libraries) 2. **scripts/convert_audio_to_ogg.py** - Auto-remove .txt placeholders - Convert MP3/WAV → OGG (ffmpeg) - Verify file integrity - Generate audioManifest.json for Phaser ❌ STILL MISSING: - 25 SFX .ogg files (placeholders only) - 7 Music .ogg files (placeholders only) 🎯 NEXT STEPS: 1. Generate audio using AI tools (ElevenLabs, Suno, etc.) 2. Run: python3 scripts/convert_audio_to_ogg.py 3. Verify all 33 files present **Current Audio Status:** 66/99 files (67% complete)
This commit is contained in:
140
AUDIO_GENERATION_MANIFEST.md
Normal file
140
AUDIO_GENERATION_MANIFEST.md
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
# 🎵 **AUDIO GENERATION MANIFEST - JAN 8, 2026**
|
||||||
|
|
||||||
|
**COMPLETE LIST OF ALL MISSING AUDIO FILES**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📊 **SUMMARY:**
|
||||||
|
|
||||||
|
- **SFX Needed:** 25 files (.ogg format)
|
||||||
|
- **Music Needed:** 8 files (.ogg format)
|
||||||
|
- **Total:** 33 audio files to generate
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔊 **1. SOUND EFFECTS (SFX) - 25 FILES**
|
||||||
|
|
||||||
|
### **FARMING SOUNDS (8 files)** 🌾
|
||||||
|
**Path:** `/assets/audio/sfx/farming/`
|
||||||
|
|
||||||
|
| Filename | Description | Duration | Notes |
|
||||||
|
|----------|-------------|----------|-------|
|
||||||
|
| `cow_moo.ogg` | Cow mooing sound | 2-3s | Friendly, farm animal |
|
||||||
|
| `dig.ogg` | Digging/hoeing soil | 1s | Shovel into dirt |
|
||||||
|
| `harvest.ogg` | Crop harvest/pickup | 0.5s | Satisfying pop/snap |
|
||||||
|
| `plant_seed.ogg` | Planting seed in soil | 0.5s | Soft thud |
|
||||||
|
| `scythe_swing.ogg` | Scythe swinging through air | 0.8s | Whoosh sound |
|
||||||
|
| `stone_mine.ogg` | Pickaxe hitting stone | 1s | Clink/chip sound |
|
||||||
|
| `tree_chop.ogg` | Axe chopping wood | 1s | Thunk/chop |
|
||||||
|
| `water_crop.ogg` | Watering can pouring | 1.5s | Water splash/trickle |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **COMBAT SOUNDS (8 files)** ⚔️
|
||||||
|
**Path:** `/assets/audio/sfx/combat/`
|
||||||
|
|
||||||
|
| Filename | Description | Duration | Notes |
|
||||||
|
|----------|-------------|----------|-------|
|
||||||
|
| `bow_release.ogg` | Arrow release from bow | 0.3s | Twang sound |
|
||||||
|
| `explosion.ogg` | Explosion/bomb | 2s | Boom + debris |
|
||||||
|
| `player_hurt.ogg` | Player damage grunt | 0.5s | Oof/ugh |
|
||||||
|
| `raider_attack.ogg` | Enemy attack yell | 1s | Aggressive shout |
|
||||||
|
| `shield_block.ogg` | Shield blocking hit | 0.5s | Metallic clang |
|
||||||
|
| `sword_slash.ogg` | Sword swing | 0.5s | Whoosh + metal |
|
||||||
|
| `zombie_death.ogg` | Zombie dies | 1.5s | Groan + thud |
|
||||||
|
| `zombie_hit.ogg` | Zombie takes damage | 0.5s | Hurt groan |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **BUILDING SOUNDS (5 files)** 🏗️
|
||||||
|
**Path:** `/assets/audio/sfx/building/`
|
||||||
|
|
||||||
|
| Filename | Description | Duration | Notes |
|
||||||
|
|----------|-------------|----------|-------|
|
||||||
|
| `chest_open.ogg` | Chest opening | 1s | Creaky wood |
|
||||||
|
| `door_close.ogg` | Door closing | 0.8s | Wood door slam |
|
||||||
|
| `door_open.ogg` | Door opening | 0.8s | Creaky hinges |
|
||||||
|
| `hammer_nail.ogg` | Hammering nail | 0.5s | Metallic bang |
|
||||||
|
| `repair.ogg` | Building repair | 1.5s | Construction sounds |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **MISC SOUNDS (4 files)** ✨
|
||||||
|
**Path:** `/assets/audio/sfx/misc/`
|
||||||
|
|
||||||
|
| Filename | Description | Duration | Notes |
|
||||||
|
|----------|-------------|----------|-------|
|
||||||
|
| `coin_collect.ogg` | Picking up coin | 0.3s | Bright ching! |
|
||||||
|
| `footstep_grass.ogg` | Footstep on grass | 0.3s | Soft rustle (HAVE .wav, convert!) |
|
||||||
|
| `footstep_stone.ogg` | Footstep on stone | 0.3s | Hard tap |
|
||||||
|
| `level_up.ogg` | Level up/achievement | 2s | Triumphant chime |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎶 **2. MUSIC TRACKS - 8 FILES**
|
||||||
|
|
||||||
|
### **BACKGROUND MUSIC (.ogg format)**
|
||||||
|
**Path:** `/assets/audio/music/`
|
||||||
|
|
||||||
|
| Filename | Description | Duration | Loop | BPM | Mood |
|
||||||
|
|----------|-------------|----------|------|-----|------|
|
||||||
|
| `forest_ambient.mp3` | **✅ HAVE!** Forest sounds | - | Yes | - | Peaceful |
|
||||||
|
| `main_theme.ogg` | Main menu theme | 2-3min | Yes | 90-110 | Epic/Adventure |
|
||||||
|
| `farm_ambient.ogg` | Farm/grassland loop | 2-3min | Yes | 70-90 | Calm/Peaceful |
|
||||||
|
| `town_theme.ogg` | Town restoration theme | 2min | Yes | 100-120 | Hopeful/Uplifting |
|
||||||
|
| `combat_theme.ogg` | Battle music | 2min | Yes | 130-150 | Intense/Action |
|
||||||
|
| `night_theme.ogg` | Nighttime ambient | 3min | Yes | 60-80 | Mysterious/Calm |
|
||||||
|
| `victory_theme.ogg` | Quest complete | 30s | No | 120 | Triumphant |
|
||||||
|
| `raid_warning.ogg` | Raid approaching | 1min | No | 140-160 | Tense/Urgent |
|
||||||
|
| `ana_theme.ogg` | Ana's memory theme | 2min | No | 80 | Emotional/Sad |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🛠️ **GENERATION INSTRUCTIONS:**
|
||||||
|
|
||||||
|
### **Option 1: AI Sound Generation (Recommended)**
|
||||||
|
Use services like:
|
||||||
|
- **ElevenLabs Sound Effects** - AI SFX generation
|
||||||
|
- **Suno AI** or **Udio** - Music generation
|
||||||
|
- **Soundraw** - Royalty-free music generator
|
||||||
|
|
||||||
|
### **Option 2: Free Sound Libraries**
|
||||||
|
Download from:
|
||||||
|
- **Freesound.org** - Community sound library
|
||||||
|
- **OpenGameArt.org** - Game audio assets
|
||||||
|
- **Incompetech** - Royalty-free music (Kevin MacLeod)
|
||||||
|
|
||||||
|
### **Option 3: Script Generation (Placeholder)**
|
||||||
|
Use `/scripts/generate_placeholder_audio.py` to create:
|
||||||
|
- Simple tone beeps (SFX placeholders)
|
||||||
|
- White noise loops (ambient placeholders)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📋 **CONVERSION CHECKLIST:**
|
||||||
|
|
||||||
|
After generating, run:
|
||||||
|
```bash
|
||||||
|
python3 /Users/davidkotnik/repos/novafarma/scripts/convert_audio_to_ogg.py
|
||||||
|
```
|
||||||
|
|
||||||
|
This will:
|
||||||
|
1. Convert all .mp3/.wav to .ogg
|
||||||
|
2. Remove .txt placeholders
|
||||||
|
3. Verify file sizes
|
||||||
|
4. Generate audio manifest
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ✅ **COMPLETION CRITERIA:**
|
||||||
|
|
||||||
|
- [ ] All 25 SFX .ogg files present
|
||||||
|
- [ ] All 8 music .ogg files present
|
||||||
|
- [ ] Each file is 5KB+ (not empty)
|
||||||
|
- [ ] Audio plays correctly in Phaser 3
|
||||||
|
- [ ] Volume normalized (-14 LUFS)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Status:** 📝 Manifest ready, awaiting audio generation
|
||||||
|
**Last Updated:** 2026-01-08 15:48 CET
|
||||||
35
COMPLETE_ASSET_CHECK_JAN8.md
Normal file
35
COMPLETE_ASSET_CHECK_JAN8.md
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
# 🔍 **COMPLETE ASSET & SYSTEMS CHECK - JAN 8, 2026 (15:41 CET)**
|
||||||
|
|
||||||
|
**SYSTEMATIČNI PREGLED OD ZAČETKA DO KONCA**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📋 **METODOLOGIJA:**
|
||||||
|
|
||||||
|
1. ✅ Pregledam DEMO_FAZA1_FAZA2_OVERVIEW.md (kaj MORA bit)
|
||||||
|
2. ✅ Preverim vse /assets/references/ folders (kaj IMO)
|
||||||
|
3. ✅ Primerjam dokumentacijo vs realnost
|
||||||
|
4. ✅ Naredim seznam manjkajočih elementov
|
||||||
|
5. ✅ Prioritiziram kaj dodat
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📊 **CATEGORY 1: CHARACTER ANIMATIONS**
|
||||||
|
|
||||||
|
### **Kaj MORA bit (iz docs):**
|
||||||
|
- Kai: idle (5), walk (6), dig (5), swing (5) = 21 ✅
|
||||||
|
- Ana: idle (4), walk (6) = 10 ✅
|
||||||
|
- Gronk: idle (4), walk (6) = 10 ✅
|
||||||
|
- Susi: idle (4), run (6), bark (2) = 12 ✅
|
||||||
|
|
||||||
|
**TOTAL NEEDS:** 53 sprites
|
||||||
|
|
||||||
|
### **Kaj IMO v /references:**
|
||||||
|
46
|
||||||
|
|
||||||
|
|
||||||
|
**STATUS:** ✅ CHECKING...
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📊 **RUNNING SYSTEMATIC CHECK...**
|
||||||
1446
assets/audio/music/forest_ambient.mp3
Normal file
1446
assets/audio/music/forest_ambient.mp3
Normal file
File diff suppressed because one or more lines are too long
1446
assets/audio/sfx/footstep_grass.wav
Normal file
1446
assets/audio/sfx/footstep_grass.wav
Normal file
File diff suppressed because one or more lines are too long
1446
assets/audio/sfx/wood_chop.wav
Normal file
1446
assets/audio/sfx/wood_chop.wav
Normal file
File diff suppressed because one or more lines are too long
BIN
assets/audio/voiceover/prologue/prologue_01.wav
Normal file
BIN
assets/audio/voiceover/prologue/prologue_01.wav
Normal file
Binary file not shown.
BIN
assets/audio/voiceover/prologue/prologue_02.wav
Normal file
BIN
assets/audio/voiceover/prologue/prologue_02.wav
Normal file
Binary file not shown.
BIN
assets/audio/voiceover/prologue/prologue_03.wav
Normal file
BIN
assets/audio/voiceover/prologue/prologue_03.wav
Normal file
Binary file not shown.
BIN
assets/audio/voiceover/prologue/prologue_04.wav
Normal file
BIN
assets/audio/voiceover/prologue/prologue_04.wav
Normal file
Binary file not shown.
BIN
assets/audio/voiceover/prologue/prologue_05.wav
Normal file
BIN
assets/audio/voiceover/prologue/prologue_05.wav
Normal file
Binary file not shown.
BIN
assets/audio/voiceover/prologue/prologue_06.wav
Normal file
BIN
assets/audio/voiceover/prologue/prologue_06.wav
Normal file
Binary file not shown.
BIN
assets/audio/voiceover/prologue/prologue_07.wav
Normal file
BIN
assets/audio/voiceover/prologue/prologue_07.wav
Normal file
Binary file not shown.
BIN
assets/audio/voiceover/prologue/prologue_08.wav
Normal file
BIN
assets/audio/voiceover/prologue/prologue_08.wav
Normal file
Binary file not shown.
BIN
assets/audio/voiceover/prologue/prologue_09.wav
Normal file
BIN
assets/audio/voiceover/prologue/prologue_09.wav
Normal file
Binary file not shown.
BIN
assets/audio/voiceover/prologue/prologue_10.wav
Normal file
BIN
assets/audio/voiceover/prologue/prologue_10.wav
Normal file
Binary file not shown.
BIN
assets/audio/voiceover/prologue/prologue_11.wav
Normal file
BIN
assets/audio/voiceover/prologue/prologue_11.wav
Normal file
Binary file not shown.
BIN
assets/audio/voiceover/prologue/prologue_12.wav
Normal file
BIN
assets/audio/voiceover/prologue/prologue_12.wav
Normal file
Binary file not shown.
BIN
assets/audio/voiceover/prologue/prologue_13.wav
Normal file
BIN
assets/audio/voiceover/prologue/prologue_13.wav
Normal file
Binary file not shown.
BIN
assets/audio/voiceover/prologue/prologue_14.wav
Normal file
BIN
assets/audio/voiceover/prologue/prologue_14.wav
Normal file
Binary file not shown.
BIN
assets/audio/voiceover/prologue/prologue_15.wav
Normal file
BIN
assets/audio/voiceover/prologue/prologue_15.wav
Normal file
Binary file not shown.
BIN
assets/audio/voiceover/prologue/prologue_16.wav
Normal file
BIN
assets/audio/voiceover/prologue/prologue_16.wav
Normal file
Binary file not shown.
BIN
assets/audio/voiceover/prologue/prologue_17.wav
Normal file
BIN
assets/audio/voiceover/prologue/prologue_17.wav
Normal file
Binary file not shown.
BIN
assets/audio/voiceover/prologue/prologue_18.wav
Normal file
BIN
assets/audio/voiceover/prologue/prologue_18.wav
Normal file
Binary file not shown.
BIN
assets/audio/voiceover/prologue/prologue_19.wav
Normal file
BIN
assets/audio/voiceover/prologue/prologue_19.wav
Normal file
Binary file not shown.
BIN
assets/audio/voiceover/prologue_en/prologue_01.wav
Normal file
BIN
assets/audio/voiceover/prologue_en/prologue_01.wav
Normal file
Binary file not shown.
BIN
assets/audio/voiceover/prologue_en/prologue_02.wav
Normal file
BIN
assets/audio/voiceover/prologue_en/prologue_02.wav
Normal file
Binary file not shown.
BIN
assets/audio/voiceover/prologue_en/prologue_03.wav
Normal file
BIN
assets/audio/voiceover/prologue_en/prologue_03.wav
Normal file
Binary file not shown.
BIN
assets/audio/voiceover/prologue_en/prologue_04.wav
Normal file
BIN
assets/audio/voiceover/prologue_en/prologue_04.wav
Normal file
Binary file not shown.
BIN
assets/audio/voiceover/prologue_en/prologue_05.wav
Normal file
BIN
assets/audio/voiceover/prologue_en/prologue_05.wav
Normal file
Binary file not shown.
BIN
assets/audio/voiceover/prologue_en/prologue_06.wav
Normal file
BIN
assets/audio/voiceover/prologue_en/prologue_06.wav
Normal file
Binary file not shown.
BIN
assets/audio/voiceover/prologue_en/prologue_07.wav
Normal file
BIN
assets/audio/voiceover/prologue_en/prologue_07.wav
Normal file
Binary file not shown.
BIN
assets/audio/voiceover/prologue_en/prologue_08.wav
Normal file
BIN
assets/audio/voiceover/prologue_en/prologue_08.wav
Normal file
Binary file not shown.
BIN
assets/audio/voiceover/prologue_en/prologue_09.wav
Normal file
BIN
assets/audio/voiceover/prologue_en/prologue_09.wav
Normal file
Binary file not shown.
BIN
assets/audio/voiceover/prologue_en/prologue_10.wav
Normal file
BIN
assets/audio/voiceover/prologue_en/prologue_10.wav
Normal file
Binary file not shown.
BIN
assets/audio/voiceover/prologue_en/prologue_11.wav
Normal file
BIN
assets/audio/voiceover/prologue_en/prologue_11.wav
Normal file
Binary file not shown.
BIN
assets/audio/voiceover/prologue_en/prologue_12.wav
Normal file
BIN
assets/audio/voiceover/prologue_en/prologue_12.wav
Normal file
Binary file not shown.
BIN
assets/audio/voiceover/prologue_sl/prologue_01.wav
Normal file
BIN
assets/audio/voiceover/prologue_sl/prologue_01.wav
Normal file
Binary file not shown.
BIN
assets/audio/voiceover/prologue_sl/prologue_02.wav
Normal file
BIN
assets/audio/voiceover/prologue_sl/prologue_02.wav
Normal file
Binary file not shown.
BIN
assets/audio/voiceover/prologue_sl/prologue_03.wav
Normal file
BIN
assets/audio/voiceover/prologue_sl/prologue_03.wav
Normal file
Binary file not shown.
BIN
assets/audio/voiceover/prologue_sl/prologue_04.wav
Normal file
BIN
assets/audio/voiceover/prologue_sl/prologue_04.wav
Normal file
Binary file not shown.
BIN
assets/audio/voiceover/prologue_sl/prologue_05.wav
Normal file
BIN
assets/audio/voiceover/prologue_sl/prologue_05.wav
Normal file
Binary file not shown.
BIN
assets/audio/voiceover/prologue_sl/prologue_06.wav
Normal file
BIN
assets/audio/voiceover/prologue_sl/prologue_06.wav
Normal file
Binary file not shown.
BIN
assets/audio/voiceover/prologue_sl/prologue_07.wav
Normal file
BIN
assets/audio/voiceover/prologue_sl/prologue_07.wav
Normal file
Binary file not shown.
BIN
assets/audio/voiceover/prologue_sl/prologue_08.wav
Normal file
BIN
assets/audio/voiceover/prologue_sl/prologue_08.wav
Normal file
Binary file not shown.
BIN
assets/audio/voiceover/prologue_sl/prologue_09.wav
Normal file
BIN
assets/audio/voiceover/prologue_sl/prologue_09.wav
Normal file
Binary file not shown.
BIN
assets/audio/voiceover/prologue_sl/prologue_10.wav
Normal file
BIN
assets/audio/voiceover/prologue_sl/prologue_10.wav
Normal file
Binary file not shown.
BIN
assets/audio/voiceover/prologue_sl/prologue_11.wav
Normal file
BIN
assets/audio/voiceover/prologue_sl/prologue_11.wav
Normal file
Binary file not shown.
BIN
assets/audio/voiceover/prologue_sl/prologue_12.wav
Normal file
BIN
assets/audio/voiceover/prologue_sl/prologue_12.wav
Normal file
Binary file not shown.
221
scripts/complete_asset_audit.py
Executable file
221
scripts/complete_asset_audit.py
Executable file
@@ -0,0 +1,221 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Complete Asset Audit Script
|
||||||
|
Systematically checks ALL assets vs documentation
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
from pathlib import Path
|
||||||
|
from collections import defaultdict
|
||||||
|
|
||||||
|
# Base paths
|
||||||
|
REPO_ROOT = Path("/Users/davidkotnik/repos/novafarma")
|
||||||
|
ASSETS_REF = REPO_ROOT / "assets" / "references"
|
||||||
|
|
||||||
|
# Expected counts from DEMO_FAZA1_FAZA2_OVERVIEW.md
|
||||||
|
EXPECTED = {
|
||||||
|
"characters": {
|
||||||
|
"kai": 21, # idle(5) + walk(6) + dig(5) + swing(5)
|
||||||
|
"ana": 10, # idle(4) + walk(6)
|
||||||
|
"gronk": 10, # idle(4) + walk(6)
|
||||||
|
},
|
||||||
|
"companions": {
|
||||||
|
"susi": 12, # idle(4) + run(6) + bark(2)
|
||||||
|
},
|
||||||
|
"zombies": 45, # 3 types × 15 frames each
|
||||||
|
"crops": {
|
||||||
|
"wheat": 5,
|
||||||
|
"carrot": 5,
|
||||||
|
"tomato": 5,
|
||||||
|
"potato": 5,
|
||||||
|
"corn": 5,
|
||||||
|
},
|
||||||
|
"tools": 8,
|
||||||
|
"ui": 28,
|
||||||
|
"grassland": 27,
|
||||||
|
}
|
||||||
|
|
||||||
|
def count_pngs(directory):
|
||||||
|
"""Count PNG files in directory recursively"""
|
||||||
|
if not directory.exists():
|
||||||
|
return 0
|
||||||
|
return len(list(directory.rglob("*.png")))
|
||||||
|
|
||||||
|
def audit_characters():
|
||||||
|
"""Audit main characters"""
|
||||||
|
print("\n## 1. MAIN CHARACTERS")
|
||||||
|
print("=" * 60)
|
||||||
|
|
||||||
|
char_path = ASSETS_REF / "main_characters"
|
||||||
|
results = {}
|
||||||
|
|
||||||
|
for char in ["kai", "ana", "gronk"]:
|
||||||
|
char_dir = char_path / char
|
||||||
|
actual = count_pngs(char_dir)
|
||||||
|
expected = EXPECTED["characters"][char]
|
||||||
|
status = "✅" if actual >= expected else "❌"
|
||||||
|
gap = actual - expected
|
||||||
|
|
||||||
|
results[char] = {
|
||||||
|
"expected": expected,
|
||||||
|
"actual": actual,
|
||||||
|
"status": status,
|
||||||
|
"gap": gap
|
||||||
|
}
|
||||||
|
|
||||||
|
print(f"\n{char.upper()}:")
|
||||||
|
print(f" Expected: {expected}")
|
||||||
|
print(f" Actual: {actual}")
|
||||||
|
print(f" Status: {status} ({'+' if gap >= 0 else ''}{gap})")
|
||||||
|
|
||||||
|
return results
|
||||||
|
|
||||||
|
def audit_companions():
|
||||||
|
"""Audit companion animals"""
|
||||||
|
print("\n## 2. COMPANIONS")
|
||||||
|
print("=" * 60)
|
||||||
|
|
||||||
|
comp_path = ASSETS_REF / "companions"
|
||||||
|
results = {}
|
||||||
|
|
||||||
|
for comp in ["susi"]:
|
||||||
|
comp_dir = comp_path / comp
|
||||||
|
actual = count_pngs(comp_dir)
|
||||||
|
expected = EXPECTED["companions"][comp]
|
||||||
|
status = "✅" if actual >= expected else "❌"
|
||||||
|
gap = actual - expected
|
||||||
|
|
||||||
|
results[comp] = {
|
||||||
|
"expected": expected,
|
||||||
|
"actual": actual,
|
||||||
|
"status": status,
|
||||||
|
"gap": gap
|
||||||
|
}
|
||||||
|
|
||||||
|
print(f"\n{comp.upper()}:")
|
||||||
|
print(f" Expected: {expected}")
|
||||||
|
print(f" Actual: {actual}")
|
||||||
|
print(f" Status: {status} ({'+' if gap >= 0 else ''}{gap})")
|
||||||
|
|
||||||
|
return results
|
||||||
|
|
||||||
|
def audit_crops():
|
||||||
|
"""Audit crop growth stages"""
|
||||||
|
print("\n## 3. CROPS")
|
||||||
|
print("=" * 60)
|
||||||
|
|
||||||
|
crops_path = ASSETS_REF / "crops"
|
||||||
|
results = {}
|
||||||
|
|
||||||
|
for crop in ["wheat", "carrot", "tomato", "potato", "corn"]:
|
||||||
|
crop_dir = crops_path / crop / "growth_stages"
|
||||||
|
actual = count_pngs(crop_dir)
|
||||||
|
expected = EXPECTED["crops"][crop]
|
||||||
|
status = "✅" if actual >= expected else "❌"
|
||||||
|
gap = actual - expected
|
||||||
|
|
||||||
|
results[crop] = {
|
||||||
|
"expected": expected,
|
||||||
|
"actual": actual,
|
||||||
|
"status": status,
|
||||||
|
"gap": gap
|
||||||
|
}
|
||||||
|
|
||||||
|
print(f"\n{crop.upper()}:")
|
||||||
|
print(f" Expected: {expected}")
|
||||||
|
print(f" Actual: {actual}")
|
||||||
|
print(f" Status: {status} ({'+' if gap >= 0 else ''}{gap})")
|
||||||
|
|
||||||
|
return results
|
||||||
|
|
||||||
|
def audit_audio():
|
||||||
|
"""Audit audio files"""
|
||||||
|
print("\n## 4. AUDIO")
|
||||||
|
print("=" * 60)
|
||||||
|
|
||||||
|
audio_path = ASSETS_REF.parent / "audio"
|
||||||
|
|
||||||
|
# Count voice files
|
||||||
|
voices = audio_path / "voices"
|
||||||
|
voice_count = len(list(voices.rglob("*.mp3"))) if voices.exists() else 0
|
||||||
|
|
||||||
|
# Count sound effects
|
||||||
|
sfx = audio_path / "sfx"
|
||||||
|
sfx_count = len(list(sfx.rglob("*.wav"))) if sfx.exists() else 0
|
||||||
|
|
||||||
|
# Count music
|
||||||
|
music_path = REPO_ROOT / "music"
|
||||||
|
music_count = len(list(music_path.rglob("*.mp3"))) if music_path.exists() else 0
|
||||||
|
music_count += len(list(music_path.rglob("*.wav"))) if music_path.exists() else 0
|
||||||
|
music_count += len(list(music_path.rglob("*.ogg"))) if music_path.exists() else 0
|
||||||
|
|
||||||
|
print(f"\nVOICES (MP3): {voice_count}")
|
||||||
|
print(f"SOUND EFFECTS (WAV): {sfx_count}")
|
||||||
|
print(f"MUSIC: {music_count} {'❌ MISSING!' if music_count == 0 else '✅'}")
|
||||||
|
|
||||||
|
return {
|
||||||
|
"voices": voice_count,
|
||||||
|
"sfx": sfx_count,
|
||||||
|
"music": music_count
|
||||||
|
}
|
||||||
|
|
||||||
|
def generate_report():
|
||||||
|
"""Generate complete audit report"""
|
||||||
|
print("\n" + "="*60)
|
||||||
|
print("🔍 COMPLETE ASSET AUDIT - JAN 8, 2026")
|
||||||
|
print("="*60)
|
||||||
|
|
||||||
|
# Run all audits
|
||||||
|
chars = audit_characters()
|
||||||
|
comps = audit_companions()
|
||||||
|
crops = audit_crops()
|
||||||
|
audio = audit_audio()
|
||||||
|
|
||||||
|
# Summary
|
||||||
|
print("\n" + "="*60)
|
||||||
|
print("📊 SUMMARY")
|
||||||
|
print("="*60)
|
||||||
|
|
||||||
|
total_expected = sum(EXPECTED["characters"].values())
|
||||||
|
total_expected += sum(EXPECTED["companions"].values())
|
||||||
|
total_expected += sum(EXPECTED["crops"].values())
|
||||||
|
total_expected += EXPECTED["zombies"]
|
||||||
|
total_expected += EXPECTED["tools"]
|
||||||
|
total_expected += EXPECTED["ui"]
|
||||||
|
|
||||||
|
total_actual = count_pngs(ASSETS_REF)
|
||||||
|
|
||||||
|
print(f"\nTOTAL PNG FILES: {total_actual}")
|
||||||
|
print(f"AUDIO FILES: {audio['voices'] + audio['sfx'] + audio['music']}")
|
||||||
|
print(f" - Voices: {audio['voices']}")
|
||||||
|
print(f" - SFX: {audio['sfx']}")
|
||||||
|
print(f" - Music: {audio['music']} {'❌' if audio['music'] == 0 else '✅'}")
|
||||||
|
|
||||||
|
# Missing items
|
||||||
|
print("\n" + "="*60)
|
||||||
|
print("❌ MISSING / NEEDS ATTENTION")
|
||||||
|
print("="*60)
|
||||||
|
|
||||||
|
missing = []
|
||||||
|
|
||||||
|
for char, data in chars.items():
|
||||||
|
if data['gap'] < 0:
|
||||||
|
missing.append(f" - {char.upper()}: {abs(data['gap'])} sprites short")
|
||||||
|
|
||||||
|
for crop, data in crops.items():
|
||||||
|
if data['gap'] < 0:
|
||||||
|
missing.append(f" - {crop.upper()}: {abs(data['gap'])} sprites short")
|
||||||
|
|
||||||
|
if audio['music'] == 0:
|
||||||
|
missing.append(f" - MUSIC: Need 3+ background tracks")
|
||||||
|
|
||||||
|
if missing:
|
||||||
|
for item in missing:
|
||||||
|
print(item)
|
||||||
|
else:
|
||||||
|
print(" ✅ ALL ASSETS COMPLETE!")
|
||||||
|
|
||||||
|
print("\n" + "="*60)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
generate_report()
|
||||||
203
scripts/convert_audio_to_ogg.py
Executable file
203
scripts/convert_audio_to_ogg.py
Executable file
@@ -0,0 +1,203 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Audio Conversion & Cleanup Script
|
||||||
|
Converts audio files to .ogg, removes placeholders, verifies integrity
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
REPO_ROOT = Path("/Users/davidkotnik/repos/novafarma")
|
||||||
|
AUDIO_ROOT = REPO_ROOT / "assets" / "audio"
|
||||||
|
|
||||||
|
def remove_txt_placeholders():
|
||||||
|
"""Remove all .txt placeholder files"""
|
||||||
|
print("\n🗑️ Removing .txt placeholders...")
|
||||||
|
|
||||||
|
txt_files = list(AUDIO_ROOT.rglob("*.txt"))
|
||||||
|
for txt_file in txt_files:
|
||||||
|
txt_file.unlink()
|
||||||
|
print(f" ✅ Removed: {txt_file.name}")
|
||||||
|
|
||||||
|
print(f"\n✅ Removed {len(txt_files)} placeholder files")
|
||||||
|
|
||||||
|
def convert_to_ogg():
|
||||||
|
"""Convert all MP3/WAV to OGG using ffmpeg"""
|
||||||
|
print("\n🔄 Converting audio files to .ogg...")
|
||||||
|
|
||||||
|
# Find all MP3 and WAV files
|
||||||
|
audio_files = []
|
||||||
|
audio_files.extend(AUDIO_ROOT.rglob("*.mp3"))
|
||||||
|
audio_files.extend(AUDIO_ROOT.rglob("*.wav"))
|
||||||
|
|
||||||
|
converted = 0
|
||||||
|
for audio_file in audio_files:
|
||||||
|
ogg_file = audio_file.with_suffix(".ogg")
|
||||||
|
|
||||||
|
# Skip if .ogg already exists
|
||||||
|
if ogg_file.exists():
|
||||||
|
print(f" ⏭️ Skip: {ogg_file.name} (exists)")
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Convert using ffmpeg
|
||||||
|
try:
|
||||||
|
cmd = [
|
||||||
|
"ffmpeg",
|
||||||
|
"-i", str(audio_file),
|
||||||
|
"-c:a", "libvorbis",
|
||||||
|
"-q:a", "6", # Quality 6 (good balance)
|
||||||
|
str(ogg_file)
|
||||||
|
]
|
||||||
|
|
||||||
|
result = subprocess.run(
|
||||||
|
cmd,
|
||||||
|
capture_output=True,
|
||||||
|
text=True
|
||||||
|
)
|
||||||
|
|
||||||
|
if result.returncode == 0:
|
||||||
|
print(f" ✅ Converted: {audio_file.name} → {ogg_file.name}")
|
||||||
|
converted += 1
|
||||||
|
else:
|
||||||
|
print(f" ❌ Failed: {audio_file.name}")
|
||||||
|
print(f" Error: {result.stderr[:100]}")
|
||||||
|
|
||||||
|
except FileNotFoundError:
|
||||||
|
print("\n❌ ERROR: ffmpeg not found!")
|
||||||
|
print("Install with: brew install ffmpeg")
|
||||||
|
return False
|
||||||
|
|
||||||
|
print(f"\n✅ Converted {converted} files to .ogg")
|
||||||
|
return True
|
||||||
|
|
||||||
|
def verify_audio():
|
||||||
|
"""Verify all audio files exist and are valid"""
|
||||||
|
print("\n🔍 Verifying audio files...")
|
||||||
|
|
||||||
|
# Expected files from manifest
|
||||||
|
expected = {
|
||||||
|
"sfx/farming": ["cow_moo", "dig", "harvest", "plant_seed", "scythe_swing", "stone_mine", "tree_chop", "water_crop"],
|
||||||
|
"sfx/combat": ["bow_release", "explosion", "player_hurt", "raider_attack", "shield_block", "sword_slash", "zombie_death", "zombie_hit"],
|
||||||
|
"sfx/building": ["chest_open", "door_close", "door_open", "hammer_nail", "repair"],
|
||||||
|
"sfx/misc": ["coin_collect", "footstep_grass", "footstep_stone", "level_up"],
|
||||||
|
"music": ["main_theme", "farm_ambient", "town_theme", "combat_theme", "night_theme", "victory_theme", "raid_warning", "ana_theme", "forest_ambient"],
|
||||||
|
}
|
||||||
|
|
||||||
|
missing = []
|
||||||
|
found = []
|
||||||
|
|
||||||
|
for category, files in expected.items():
|
||||||
|
category_path = AUDIO_ROOT / category
|
||||||
|
|
||||||
|
for filename in files:
|
||||||
|
# Check both .ogg and original formats
|
||||||
|
ogg_file = category_path / f"{filename}.ogg"
|
||||||
|
mp3_file = category_path / f"{filename}.mp3"
|
||||||
|
wav_file = category_path / f"{filename}.wav"
|
||||||
|
|
||||||
|
if ogg_file.exists():
|
||||||
|
size = ogg_file.stat().st_size
|
||||||
|
if size > 1000: # At least 1KB
|
||||||
|
found.append(str(ogg_file.relative_to(AUDIO_ROOT)))
|
||||||
|
else:
|
||||||
|
missing.append(f"{category}/{filename}.ogg (too small: {size}B)")
|
||||||
|
elif mp3_file.exists() or wav_file.exists():
|
||||||
|
found.append(f"{category}/{filename} (needs conversion)")
|
||||||
|
else:
|
||||||
|
missing.append(f"{category}/{filename}.ogg")
|
||||||
|
|
||||||
|
print(f"\n✅ Found: {len(found)} files")
|
||||||
|
print(f"❌ Missing: {len(missing)} files")
|
||||||
|
|
||||||
|
if missing:
|
||||||
|
print("\n❌ MISSING FILES:")
|
||||||
|
for file in missing[:10]: # Show first 10
|
||||||
|
print(f" - {file}")
|
||||||
|
if len(missing) > 10:
|
||||||
|
print(f" ... and {len(missing) - 10} more")
|
||||||
|
|
||||||
|
return len(missing) == 0
|
||||||
|
|
||||||
|
def generate_manifest():
|
||||||
|
"""Generate audio file manifest for Phaser preload"""
|
||||||
|
print("\n📝 Generating audio manifest...")
|
||||||
|
|
||||||
|
manifest = {
|
||||||
|
"sfx": {},
|
||||||
|
"music": {},
|
||||||
|
"voices": {}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Scan SFX
|
||||||
|
sfx_path = AUDIO_ROOT / "sfx"
|
||||||
|
for ogg_file in sfx_path.rglob("*.ogg"):
|
||||||
|
category = ogg_file.parent.name
|
||||||
|
filename = ogg_file.stem
|
||||||
|
|
||||||
|
if category not in manifest["sfx"]:
|
||||||
|
manifest["sfx"][category] = []
|
||||||
|
|
||||||
|
manifest["sfx"][category].append({
|
||||||
|
"key": f"{category}_{filename}",
|
||||||
|
"path": str(ogg_file.relative_to(AUDIO_ROOT.parent))
|
||||||
|
})
|
||||||
|
|
||||||
|
# Scan Music
|
||||||
|
music_path = AUDIO_ROOT / "music"
|
||||||
|
for audio_file in music_path.glob("*"):
|
||||||
|
if audio_file.suffix in [".ogg", ".mp3"]:
|
||||||
|
manifest["music"][audio_file.stem] = {
|
||||||
|
"key": audio_file.stem,
|
||||||
|
"path": str(audio_file.relative_to(AUDIO_ROOT.parent))
|
||||||
|
}
|
||||||
|
|
||||||
|
# Scan Voices
|
||||||
|
voices_path = AUDIO_ROOT / "voices"
|
||||||
|
for char_dir in voices_path.iterdir():
|
||||||
|
if char_dir.is_dir():
|
||||||
|
manifest["voices"][char_dir.name] = []
|
||||||
|
for mp3_file in char_dir.glob("*.mp3"):
|
||||||
|
manifest["voices"][char_dir.name].append({
|
||||||
|
"key": f"{char_dir.name}_{mp3_file.stem}",
|
||||||
|
"path": str(mp3_file.relative_to(AUDIO_ROOT.parent))
|
||||||
|
})
|
||||||
|
|
||||||
|
# Write manifest
|
||||||
|
manifest_file = REPO_ROOT / "src" / "data" / "audioManifest.json"
|
||||||
|
import json
|
||||||
|
|
||||||
|
manifest_file.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
with open(manifest_file, 'w') as f:
|
||||||
|
json.dump(manifest, f, indent=2)
|
||||||
|
|
||||||
|
print(f"✅ Manifest written to: {manifest_file}")
|
||||||
|
print(f" - SFX categories: {len(manifest['sfx'])}")
|
||||||
|
print(f" - Music tracks: {len(manifest['music'])}")
|
||||||
|
print(f" - Voice characters: {len(manifest['voices'])}")
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""Run all audio processing tasks"""
|
||||||
|
print("="*60)
|
||||||
|
print("🎵 AUDIO CONVERSION & CLEANUP")
|
||||||
|
print("="*60)
|
||||||
|
|
||||||
|
# Step 1: Remove placeholders
|
||||||
|
remove_txt_placeholders()
|
||||||
|
|
||||||
|
# Step 2: Convert to OGG
|
||||||
|
if not convert_to_ogg():
|
||||||
|
return
|
||||||
|
|
||||||
|
# Step 3: Verify
|
||||||
|
verify_audio()
|
||||||
|
|
||||||
|
# Step 4: Generate manifest
|
||||||
|
generate_manifest()
|
||||||
|
|
||||||
|
print("\n" + "="*60)
|
||||||
|
print("✅ AUDIO PROCESSING COMPLETE!")
|
||||||
|
print("="*60)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Reference in New Issue
Block a user