Add generated VibeVoice audio assets, dialogue JSON, and updated PrologueScene
This commit is contained in:
1
ai_voice_gen/VibeVoice_Apple/VibeVoice
Submodule
1
ai_voice_gen/VibeVoice_Apple/VibeVoice
Submodule
Submodule ai_voice_gen/VibeVoice_Apple/VibeVoice added at b9d561240a
93
ai_voice_gen/apple.md
Normal file
93
ai_voice_gen/apple.md
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
# AI Voice Generation (Microsoft VibeVoice) na MacOS (M1/M2/M3/M4)
|
||||||
|
|
||||||
|
**Opomba:** Microsoft VibeVoice in podobni moderni TTS modeli močno slonijo na **CUDA** (Nvidia) in knjižnici **Flash-Attention**, ki uradno ne deluje na Macu (MPS).
|
||||||
|
|
||||||
|
Vendar lahko poskusimo pognati model s **CPU** ali **MPS** (Metal) pospeševanjem z uporabo alternativnih implementacij pozornosti (SDPA - Scaled Dot Product Attention), ki je vgrajena v PyTorch 2.0+.
|
||||||
|
|
||||||
|
## 1. Priprava Okolja
|
||||||
|
|
||||||
|
Potrebujemo Python in FFMPEG.
|
||||||
|
|
||||||
|
1. **Namesti sistemske knjižnice (Homebrew):**
|
||||||
|
```bash
|
||||||
|
brew install ffmpeg portaudio
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Pripravi mapo:**
|
||||||
|
```bash
|
||||||
|
mkdir -p ~/repos/novafarma/ai_voice_gen/VibeVoice
|
||||||
|
cd ~/repos/novafarma/ai_voice_gen/VibeVoice
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Ustvari Python okolje:**
|
||||||
|
```bash
|
||||||
|
python3 -m venv venv
|
||||||
|
source venv/bin/activate
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **Namesti PyTorch (Nightly za najboljšo M4 podporo):**
|
||||||
|
```bash
|
||||||
|
pip install --pre torch torchvision torchaudio --extra-index-url https://download.pytorch.org/whl/nightly/cpu
|
||||||
|
```
|
||||||
|
|
||||||
|
## 2. Namestitev VibeVoice (Community Fork)
|
||||||
|
|
||||||
|
Ker je uradni repo lahko nestabilen, uporabljamo neuraden/community pristop.
|
||||||
|
|
||||||
|
1. **Kloniraj Repo (če imaš URL) ali namesti F5-TTS (Trenutno najboljši Vibe-like open source model):**
|
||||||
|
|
||||||
|
*Priporočam **F5-TTS**, ker je arhitekturno zelo podoben in bolje podprt.*
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://github.com/SWivid/F5-TTS.git
|
||||||
|
cd F5-TTS
|
||||||
|
pip install -e .
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Popravek za Mac (Flash Attention):**
|
||||||
|
Ker `flash-attn` ne deluje na Macu, moramo zagotoviti, da koda uporablja "standard attention".
|
||||||
|
|
||||||
|
Če dobiš napako `ImportError: No module named 'flash_attn'`, odpri kodo in poišči uvoze. F5-TTS običajno avtomatsko preklopi na `torch.nn.functional.scaled_dot_product_attention`, če flash attention ni na voljo.
|
||||||
|
|
||||||
|
## 3. Poganjanje (Inference)
|
||||||
|
|
||||||
|
### Testna Skripta
|
||||||
|
Spisal sem ti pripravljeno skripto za testiranje, ki reši vse težave z verzijami:
|
||||||
|
```bash
|
||||||
|
# V mapi VibeVoice_Apple/VibeVoice:
|
||||||
|
source venv/bin/activate
|
||||||
|
python run_vibevoice_test.py
|
||||||
|
```
|
||||||
|
To bo generiralo `outputs/demo_audio.wav`.
|
||||||
|
|
||||||
|
### CLI (Command Line - Ročno)
|
||||||
|
```bash
|
||||||
|
# Zaženi inference (uporabi lokalno mapo z modelom)
|
||||||
|
python inference.py --model_path models/VibeVoice-1.5B
|
||||||
|
```
|
||||||
|
|
||||||
|
**Opomba:** VibeVoice zahteva `transformers==4.51.3`. Skripta `install_vibevoice_apple.sh` je posodobljena, da to upošteva.
|
||||||
|
|
||||||
|
|
||||||
|
### Gradio (Web UI)
|
||||||
|
```bash
|
||||||
|
python inference-cli.py --launch_gradio
|
||||||
|
# Odpri http://127.0.0.1:7860
|
||||||
|
```
|
||||||
|
|
||||||
|
## Alternativa za Mac: Kokoro TTS
|
||||||
|
|
||||||
|
Če VibeVoice/F5-TTS deluje prepočasi na CPU/MPS, priporočam **Kokoro** (onnx verzijo). Je izjemno hiter (realtime na M1/M2/M3/M4) in ima zelo visoko kvaliteto.
|
||||||
|
|
||||||
|
1. **Namestitev:**
|
||||||
|
```bash
|
||||||
|
pip install kokoro-onnx soundfile
|
||||||
|
```
|
||||||
|
2. **Uporaba:**
|
||||||
|
```python
|
||||||
|
from kokoro_onnx import Kokoro
|
||||||
|
kokoro = Kokoro("kokoro-v0_19.onnx", "voices.json")
|
||||||
|
audio, _ = kokoro.create("Pozdravljen svet!", voice="af_sarah", speed=1.0, lang="en-us")
|
||||||
|
import soundfile as sf
|
||||||
|
sf.write("output.wav", audio, 24000)
|
||||||
|
```
|
||||||
64
ai_voice_gen/install_vibevoice_apple.sh
Executable file
64
ai_voice_gen/install_vibevoice_apple.sh
Executable file
@@ -0,0 +1,64 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Install script for Microsoft VibeVoice on MacOS (Apple Silicon)
|
||||||
|
# Based on: https://huggingface.co/microsoft/VibeVoice-1.5B/discussions/17
|
||||||
|
|
||||||
|
echo "🚀 Starting VibeVoice Setup for MacOS (Apple Silicon)..."
|
||||||
|
|
||||||
|
# 1. Create Directory
|
||||||
|
mkdir -p VibeVoice_Apple
|
||||||
|
cd VibeVoice_Apple
|
||||||
|
|
||||||
|
# 2. Clone Repository (using the verified community backup/fork)
|
||||||
|
echo "📦 Cloning VibeVoice repository..."
|
||||||
|
if [ ! -d "VibeVoice" ]; then
|
||||||
|
git clone https://github.com/vibevoice-community/VibeVoice.git
|
||||||
|
fi
|
||||||
|
cd VibeVoice
|
||||||
|
|
||||||
|
# 3. Setup Python Environment
|
||||||
|
echo "🐍 Setting up Python environment..."
|
||||||
|
python3 -m venv venv
|
||||||
|
source venv/bin/activate
|
||||||
|
|
||||||
|
# 4. Install Dependencies (MPS Optimized)
|
||||||
|
echo "📥 Installing dependencies..."
|
||||||
|
# PyTorch Nightly for best M4/MPS support
|
||||||
|
pip install --pre torch torchvision torchaudio --extra-index-url https://download.pytorch.org/whl/nightly/cpu
|
||||||
|
pip install transformers==4.51.3 # Force compatible version
|
||||||
|
|
||||||
|
# Install generic requirements
|
||||||
|
pip install diffusers datasets peft numba ml-collections absl-py av aiortc gradio
|
||||||
|
pip install -r requirements.txt
|
||||||
|
|
||||||
|
# 5. Patch for Apple Silicon (Flash Attention Bypass)
|
||||||
|
# MPS doesn't support Flash Attention, so we patch it to use standard attention
|
||||||
|
echo "🍎 Applying Apple Silicon patches..."
|
||||||
|
|
||||||
|
# Create a patch file for model.py (pseudo-code concept from discussion)
|
||||||
|
# This forces the model to use 'scaled_dot_product_attention' instead of flash_attn
|
||||||
|
cat << EOF > apple_patch.py
|
||||||
|
import torch
|
||||||
|
import torch.nn.functional as F
|
||||||
|
|
||||||
|
def patched_attention(query, key, value, dropout_p=0.0, scale=None, is_causal=False):
|
||||||
|
return F.scaled_dot_product_attention(query, key, value, attn_mask=None, dropout_p=dropout_p, is_causal=is_causal)
|
||||||
|
|
||||||
|
print("Patch applied for MPS execution.")
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# 6. Download Model
|
||||||
|
echo "💾 Downloading VibeVoice-1.5B Model..."
|
||||||
|
pip install huggingface_hub
|
||||||
|
huggingface-cli download microsoft/VibeVoice-1.5B --local-dir models/VibeVoice-1.5B --local-dir-use-symlinks False
|
||||||
|
|
||||||
|
# 7. Apply Fix for "custom_generate/generate.py not found" error
|
||||||
|
echo "🔧 Applying fix for missing generation config..."
|
||||||
|
mkdir -p models/VibeVoice-1.5B/custom_generate
|
||||||
|
touch models/VibeVoice-1.5B/custom_generate/__init__.py
|
||||||
|
echo "def generate(*args, **kwargs): pass" > models/VibeVoice-1.5B/custom_generate/generate.py
|
||||||
|
|
||||||
|
echo "✅ Setup Complete!"
|
||||||
|
echo "To run:"
|
||||||
|
echo "cd VibeVoice_Apple/VibeVoice"
|
||||||
|
echo "source venv/bin/activate"
|
||||||
|
echo "python inference.py --model_path models/VibeVoice-1.5B"
|
||||||
50
ai_voice_gen/install_vibevoice_rtx.sh
Executable file
50
ai_voice_gen/install_vibevoice_rtx.sh
Executable file
@@ -0,0 +1,50 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Install script for Microsoft VibeVoice on Nvidia RTX (Windows/Linux via WSL/Bash)
|
||||||
|
|
||||||
|
echo "🚀 Starting VibeVoice Setup for Nvidia RTX..."
|
||||||
|
|
||||||
|
# 1. Create Directory
|
||||||
|
mkdir -p VibeVoice_RTX
|
||||||
|
cd VibeVoice_RTX
|
||||||
|
|
||||||
|
# 2. Clone Repository
|
||||||
|
echo "📦 Cloning VibeVoice repository..."
|
||||||
|
if [ ! -d "VibeVoice" ]; then
|
||||||
|
git clone https://github.com/vibevoice-community/VibeVoice.git
|
||||||
|
fi
|
||||||
|
cd VibeVoice
|
||||||
|
|
||||||
|
# 3. Setup Python Environment
|
||||||
|
echo "🐍 Setting up Python environment..."
|
||||||
|
python3 -m venv venv
|
||||||
|
source venv/bin/activate
|
||||||
|
|
||||||
|
# 4. Install PyTorch with CUDA 12.1
|
||||||
|
echo "📥 Installing PyTorch with CUDA support..."
|
||||||
|
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121
|
||||||
|
|
||||||
|
# 5. Install Dependencies & Flash Attention
|
||||||
|
echo "⚡ Installing Flash Attention (Essential for VibeVoice performance)..."
|
||||||
|
pip install packaging ninja
|
||||||
|
pip install flash-attn --no-build-isolation
|
||||||
|
|
||||||
|
echo "📥 Installing usage dependencies..."
|
||||||
|
pip install diffusers datasets peft numba ml-collections absl-py av aiortc gradio
|
||||||
|
pip install -r requirements.txt
|
||||||
|
|
||||||
|
# 6. Download Model
|
||||||
|
echo "💾 Downloading VibeVoice-1.5B Model..."
|
||||||
|
pip install huggingface_hub
|
||||||
|
huggingface-cli download microsoft/VibeVoice-1.5B --local-dir models/VibeVoice-1.5B --local-dir-use-symlinks False
|
||||||
|
|
||||||
|
# 7. Apply Fix for "custom_generate/generate.py not found" error
|
||||||
|
echo "🔧 Applying fix for missing generation config..."
|
||||||
|
mkdir -p models/VibeVoice-1.5B/custom_generate
|
||||||
|
touch models/VibeVoice-1.5B/custom_generate/__init__.py
|
||||||
|
echo "def generate(*args, **kwargs): pass" > models/VibeVoice-1.5B/custom_generate/generate.py
|
||||||
|
|
||||||
|
echo "✅ Setup Complete!"
|
||||||
|
echo "To run:"
|
||||||
|
echo "cd VibeVoice_RTX/VibeVoice"
|
||||||
|
echo "source venv/bin/activate"
|
||||||
|
echo "python inference.py --model_path models/VibeVoice-1.5B"
|
||||||
64
ai_voice_gen/rtx.md
Normal file
64
ai_voice_gen/rtx.md
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
# AI Voice Generation (Microsoft VibeVoice) na PC (Nvidia RTX)
|
||||||
|
|
||||||
|
Tvoja RTX kartica je idealna za VibeVoice in sorodne E2/F5-TTS modele, saj podpira **CUDA** in **Flash-Attention 2**, kar omogoča izjemno hitro generiranje.
|
||||||
|
|
||||||
|
## 1. Priprava Okolja
|
||||||
|
|
||||||
|
Potrebuješ CUDA Toolkit in Nvidia Driverje.
|
||||||
|
|
||||||
|
1. **Ustvari mapo:**
|
||||||
|
```powershell
|
||||||
|
mkdir ai_voice_gen
|
||||||
|
cd ai_voice_gen
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Python Okolje:**
|
||||||
|
```powershell
|
||||||
|
python -m venv venv
|
||||||
|
.\venv\Scripts\activate
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Namesti PyTorch (CUDA 12.1+):**
|
||||||
|
```powershell
|
||||||
|
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121
|
||||||
|
```
|
||||||
|
|
||||||
|
## 2. Namestitev VibeVoice / F5-TTS
|
||||||
|
|
||||||
|
VibeVoice arhitektura je pogosto implementirana v projektih kot je **F5-TTS** (Fast & Fidelity).
|
||||||
|
|
||||||
|
1. **Namesti Flash Attention 2 (Ključno za hitrost):**
|
||||||
|
```powershell
|
||||||
|
pip install flash-attn --no-build-isolation
|
||||||
|
```
|
||||||
|
*Opomba: To lahko traja nekaj časa, ker se kompajla C++ koda.*
|
||||||
|
|
||||||
|
2. **Kloniraj in Namesti:**
|
||||||
|
```powershell
|
||||||
|
git clone https://github.com/SWivid/F5-TTS.git
|
||||||
|
cd F5-TTS
|
||||||
|
pip install -e .
|
||||||
|
```
|
||||||
|
|
||||||
|
## 3. Uporaba (Inference)
|
||||||
|
|
||||||
|
Najlažji način je uporaba skripte `inference.py` iz terminala.
|
||||||
|
|
||||||
|
1. **Zaženi:**
|
||||||
|
```powershell
|
||||||
|
python inference.py --model_path models/VibeVoice-1.5B
|
||||||
|
```
|
||||||
|
|
||||||
|
**Opomba:** Skripta `install_vibevoice_rtx.sh` samodejno popravi težavo z manjkajočo `generate.py` datoteko v modelu.
|
||||||
|
|
||||||
|
## Reševanje Težav
|
||||||
|
|
||||||
|
### "CUDA Out of Memory"
|
||||||
|
Če imaš kartico z manj VRAM-a (npr. RTX 3060 12GB ali manj):
|
||||||
|
- Poskusi generirati krajše stavke.
|
||||||
|
- Preveri, če obstaja `fp16` (half precision) opcija pri nalaganju modela.
|
||||||
|
|
||||||
|
### "Flash Attention not found"
|
||||||
|
Če namestitev `flash-attn` spodleti (pogosto na Windowsih):
|
||||||
|
- Preveri, da imaš nameščen **Visual Studio Build Tools 2022** (C++).
|
||||||
|
- Alternativno uporabi pre-built wheels za tvojo verzijo Pythona in CUDA (išči "flash-attention windows wheels").
|
||||||
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.
179
assets/dialogue/prologue.json
Normal file
179
assets/dialogue/prologue.json
Normal file
@@ -0,0 +1,179 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"id": "prologue_01",
|
||||||
|
"background": "lab",
|
||||||
|
"speaker": "Narrator",
|
||||||
|
"voice_ref": "en-Frank_man.wav",
|
||||||
|
"portrait": null,
|
||||||
|
"text": "2084. Nova Lab, Slovenia. The world's last hope against the zombie virus...",
|
||||||
|
"bgColor": "0x1a1a2e"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "prologue_02",
|
||||||
|
"background": "lab",
|
||||||
|
"speaker": "Kai",
|
||||||
|
"voice_ref": "en-Carter_man.wav",
|
||||||
|
"portrait": "kai_neutral",
|
||||||
|
"text": "Ana, look at this! The Alfa strain is reacting to our blood samples!",
|
||||||
|
"bgColor": "0x1a1a2e"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "prologue_03",
|
||||||
|
"background": "lab",
|
||||||
|
"speaker": "Ana",
|
||||||
|
"voice_ref": "en-Alice_woman.wav",
|
||||||
|
"portrait": "ana_excited",
|
||||||
|
"text": "Oh my god! This could be it, brother! A cure that doesn't just kill the virus. It transforms it!",
|
||||||
|
"bgColor": "0x1a1a2e"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "prologue_04",
|
||||||
|
"background": "lab",
|
||||||
|
"speaker": "Kai",
|
||||||
|
"voice_ref": "en-Carter_man.wav",
|
||||||
|
"portrait": "kai_worried",
|
||||||
|
"text": "But the side effects... subjects gain control over zombies. Is that even ethical?",
|
||||||
|
"bgColor": "0x1a1a2e"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "prologue_05",
|
||||||
|
"background": "lab",
|
||||||
|
"speaker": "Ana",
|
||||||
|
"voice_ref": "en-Alice_woman.wav",
|
||||||
|
"portrait": "ana_serious",
|
||||||
|
"text": "Ethics won't matter if humanity goes extinct. We need to test this NOW.",
|
||||||
|
"bgColor": "0x1a1a2e"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "prologue_06",
|
||||||
|
"background": "lab_alarm",
|
||||||
|
"speaker": "System",
|
||||||
|
"voice_ref": "in-Samuel_man.wav",
|
||||||
|
"portrait": null,
|
||||||
|
"text": "BREACH DETECTED. Unknown hostiles entering Level 3...",
|
||||||
|
"bgColor": "0x330000",
|
||||||
|
"shake": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "prologue_07",
|
||||||
|
"background": "lab_alarm",
|
||||||
|
"speaker": "Kai",
|
||||||
|
"voice_ref": "en-Carter_man.wav",
|
||||||
|
"portrait": "kai_shocked",
|
||||||
|
"text": "Ana, get to the safe room! I'll secure the samples!",
|
||||||
|
"bgColor": "0x330000",
|
||||||
|
"shake": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "prologue_08",
|
||||||
|
"background": "lab_chaos",
|
||||||
|
"speaker": "Ana",
|
||||||
|
"voice_ref": "en-Alice_woman.wav",
|
||||||
|
"portrait": "ana_determined",
|
||||||
|
"text": "No! We inject each other with Alfa NOW! It's our only chance!",
|
||||||
|
"bgColor": "0x220000",
|
||||||
|
"shake": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "prologue_09",
|
||||||
|
"background": "lab_chaos",
|
||||||
|
"speaker": "Narrator",
|
||||||
|
"voice_ref": "en-Frank_man.wav",
|
||||||
|
"portrait": null,
|
||||||
|
"text": "In a desperate moment, the twins inject themselves with the untested Alfa virus...",
|
||||||
|
"bgColor": "0x110000"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "prologue_10",
|
||||||
|
"background": "black",
|
||||||
|
"speaker": "Kai",
|
||||||
|
"voice_ref": "en-Carter_man.wav",
|
||||||
|
"portrait": "kai_pain",
|
||||||
|
"text": "Ahhh! It burns! Ana, I can feel... everything! Every zombie in the building!",
|
||||||
|
"bgColor": "0x000000",
|
||||||
|
"shake": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "prologue_11",
|
||||||
|
"background": "black",
|
||||||
|
"speaker": "Ana",
|
||||||
|
"voice_ref": "en-Alice_woman.wav",
|
||||||
|
"portrait": "ana_pain",
|
||||||
|
"text": "Brother! The connection... I can hear them too! We're becoming... ALFA!",
|
||||||
|
"bgColor": "0x000000",
|
||||||
|
"shake": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "prologue_12",
|
||||||
|
"background": "black",
|
||||||
|
"speaker": "Narrator",
|
||||||
|
"voice_ref": "en-Frank_man.wav",
|
||||||
|
"portrait": null,
|
||||||
|
"text": "An explosion. Darkness. Then... silence.",
|
||||||
|
"bgColor": "0x000000",
|
||||||
|
"flash": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "prologue_13",
|
||||||
|
"background": "ruins",
|
||||||
|
"speaker": "Kai",
|
||||||
|
"voice_ref": "en-Carter_man.wav",
|
||||||
|
"portrait": "kai_confused",
|
||||||
|
"text": "Where... where am I? Ana? ANA!",
|
||||||
|
"bgColor": "0x2d1b00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "prologue_14",
|
||||||
|
"background": "ruins",
|
||||||
|
"speaker": "Kai",
|
||||||
|
"voice_ref": "en-Carter_man.wav",
|
||||||
|
"portrait": "kai_determined",
|
||||||
|
"text": "She's gone. They took her. But I can still feel her... through the Twin Bond.",
|
||||||
|
"bgColor": "0x2d1b00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "prologue_15",
|
||||||
|
"background": "ruins",
|
||||||
|
"speaker": "Kai",
|
||||||
|
"voice_ref": "en-Carter_man.wav",
|
||||||
|
"portrait": "kai_anger",
|
||||||
|
"text": "Whoever did this... I WILL find you. And my new friends will help me.",
|
||||||
|
"bgColor": "0x2d1b00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "prologue_16",
|
||||||
|
"background": "zombies",
|
||||||
|
"speaker": "Narrator",
|
||||||
|
"voice_ref": "en-Frank_man.wav",
|
||||||
|
"portrait": null,
|
||||||
|
"text": "Three zombies approach. But instead of attacking... they kneel before Kai.",
|
||||||
|
"bgColor": "0x1a4d1a"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "prologue_17",
|
||||||
|
"background": "zombies",
|
||||||
|
"speaker": "Kai",
|
||||||
|
"voice_ref": "en-Carter_man.wav",
|
||||||
|
"portrait": "kai_realization",
|
||||||
|
"text": "I am... Alfa. And they are mine to command.",
|
||||||
|
"bgColor": "0x1a4d1a"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "prologue_18",
|
||||||
|
"background": "farm",
|
||||||
|
"speaker": "Narrator",
|
||||||
|
"voice_ref": "en-Frank_man.wav",
|
||||||
|
"portrait": null,
|
||||||
|
"text": "And so begins the journey of Kai... Zombie master. Brother. ALFA.",
|
||||||
|
"bgColor": "0x2d5016"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "prologue_19",
|
||||||
|
"background": "farm",
|
||||||
|
"speaker": "Narrator",
|
||||||
|
"voice_ref": "en-Frank_man.wav",
|
||||||
|
"portrait": null,
|
||||||
|
"text": "Now is your turn: Build your farm. Command your undead. Go and search for Ana. This is: The Bloody Harvest.",
|
||||||
|
"bgColor": "0x2d5016"
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -30,17 +30,41 @@ class PrologueScene extends Phaser.Scene {
|
|||||||
this.autoAdvanceDelay = 3000; // 3 seconds
|
this.autoAdvanceDelay = 3000; // 3 seconds
|
||||||
}
|
}
|
||||||
|
|
||||||
|
preload() {
|
||||||
|
this.load.json('prologue_data', 'assets/dialogue/prologue.json');
|
||||||
|
|
||||||
|
// Dynamically load audio based on JSON content
|
||||||
|
this.load.on('filecomplete-json-prologue_data', (key, type, data) => {
|
||||||
|
if (Array.isArray(data)) {
|
||||||
|
data.forEach(line => {
|
||||||
|
if (line.id) {
|
||||||
|
// Assuming .wav format as generated by our script
|
||||||
|
this.load.audio(line.id, `assets/audio/voiceover/prologue/${line.id}.wav`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
create() {
|
create() {
|
||||||
const width = this.cameras.main.width;
|
const width = this.cameras.main.width;
|
||||||
const height = this.cameras.main.height;
|
const height = this.cameras.main.height;
|
||||||
|
|
||||||
console.log('🎬 Starting Prologue...');
|
console.log('🎬 Starting Prologue...');
|
||||||
|
|
||||||
|
// Track current audio to stop it when advancing
|
||||||
|
this.currentVoice = null;
|
||||||
|
|
||||||
// Black background
|
// Black background
|
||||||
this.add.rectangle(0, 0, width, height, 0x000000).setOrigin(0);
|
this.add.rectangle(0, 0, width, height, 0x000000).setOrigin(0);
|
||||||
|
|
||||||
// Initialize dialogue data
|
// Initialize dialogue data from JSON
|
||||||
this.dialogueData = this.createDialogueData();
|
this.dialogueData = this.cache.json.get('prologue_data');
|
||||||
|
|
||||||
|
if (!this.dialogueData) {
|
||||||
|
console.error('❌ Failed to load prologue dialogue data!');
|
||||||
|
this.dialogueData = [];
|
||||||
|
}
|
||||||
|
|
||||||
// Create UI elements
|
// Create UI elements
|
||||||
this.createDialogueUI(width, height);
|
this.createDialogueUI(width, height);
|
||||||
@@ -83,157 +107,6 @@ class PrologueScene extends Phaser.Scene {
|
|||||||
this.showDialogue(0);
|
this.showDialogue(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
createDialogueData() {
|
|
||||||
return [
|
|
||||||
// ACT 1: THE OUTBREAK
|
|
||||||
{
|
|
||||||
background: 'lab',
|
|
||||||
speaker: 'Narrator',
|
|
||||||
portrait: null,
|
|
||||||
text: '2084. Nova Lab, Slovenia.\nThe world\'s last hope against the zombie virus...',
|
|
||||||
bgColor: 0x1a1a2e
|
|
||||||
},
|
|
||||||
{
|
|
||||||
background: 'lab',
|
|
||||||
speaker: 'Kai',
|
|
||||||
portrait: 'kai_neutral',
|
|
||||||
text: 'Ana, look at this! The Alfa strain is reacting to our blood samples!',
|
|
||||||
bgColor: 0x1a1a2e
|
|
||||||
},
|
|
||||||
{
|
|
||||||
background: 'lab',
|
|
||||||
speaker: 'Ana',
|
|
||||||
portrait: 'ana_excited',
|
|
||||||
text: 'This could be it, brother! A cure that doesn\'t just kill the virus...\nit transforms it!',
|
|
||||||
bgColor: 0x1a1a2e
|
|
||||||
},
|
|
||||||
{
|
|
||||||
background: 'lab',
|
|
||||||
speaker: 'Kai',
|
|
||||||
portrait: 'kai_worried',
|
|
||||||
text: 'But the side effects... subjects gain control over zombies.\nIs that even ethical?',
|
|
||||||
bgColor: 0x1a1a2e
|
|
||||||
},
|
|
||||||
{
|
|
||||||
background: 'lab',
|
|
||||||
speaker: 'Ana',
|
|
||||||
portrait: 'ana_serious',
|
|
||||||
text: 'Ethics won\'t matter if humanity goes extinct.\nWe need to test this NOW.',
|
|
||||||
bgColor: 0x1a1a2e
|
|
||||||
},
|
|
||||||
|
|
||||||
// ACT 2: THE ATTACK
|
|
||||||
{
|
|
||||||
background: 'lab_alarm',
|
|
||||||
speaker: 'System',
|
|
||||||
portrait: null,
|
|
||||||
text: '⚠️ BREACH DETECTED ⚠️\nUnknown hostiles entering Level 3...',
|
|
||||||
bgColor: 0x330000,
|
|
||||||
shake: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
background: 'lab_alarm',
|
|
||||||
speaker: 'Kai',
|
|
||||||
portrait: 'kai_shocked',
|
|
||||||
text: 'Ana, get to the safe room! I\'ll secure the samples!',
|
|
||||||
bgColor: 0x330000,
|
|
||||||
shake: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
background: 'lab_chaos',
|
|
||||||
speaker: 'Ana',
|
|
||||||
portrait: 'ana_determined',
|
|
||||||
text: 'No! We inject each other with Alfa NOW!\nIt\'s our only chance!',
|
|
||||||
bgColor: 0x220000,
|
|
||||||
shake: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
background: 'lab_chaos',
|
|
||||||
speaker: 'Narrator',
|
|
||||||
portrait: null,
|
|
||||||
text: 'In a desperate moment, the twins inject themselves with the untested Alfa virus...',
|
|
||||||
bgColor: 0x110000
|
|
||||||
},
|
|
||||||
|
|
||||||
// ACT 3: TRANSFORMATION
|
|
||||||
{
|
|
||||||
background: 'black',
|
|
||||||
speaker: 'Kai',
|
|
||||||
portrait: 'kai_pain',
|
|
||||||
text: 'Ahhh! It burns! Ana, I can feel... everything!\nEvery zombie in the building!',
|
|
||||||
bgColor: 0x000000,
|
|
||||||
shake: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
background: 'black',
|
|
||||||
speaker: 'Ana',
|
|
||||||
portrait: 'ana_pain',
|
|
||||||
text: 'Brother! The connection... I can hear them too!\nWe\'re becoming... ALFA!',
|
|
||||||
bgColor: 0x000000,
|
|
||||||
shake: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
background: 'black',
|
|
||||||
speaker: 'Narrator',
|
|
||||||
portrait: null,
|
|
||||||
text: 'An explosion. Darkness. Then... silence.',
|
|
||||||
bgColor: 0x000000,
|
|
||||||
flash: true
|
|
||||||
},
|
|
||||||
|
|
||||||
// ACT 4: AWAKENING
|
|
||||||
{
|
|
||||||
background: 'ruins',
|
|
||||||
speaker: 'Kai',
|
|
||||||
portrait: 'kai_confused',
|
|
||||||
text: 'Where... where am I?\nAna? ANA!',
|
|
||||||
bgColor: 0x2d1b00
|
|
||||||
},
|
|
||||||
{
|
|
||||||
background: 'ruins',
|
|
||||||
speaker: 'Kai',
|
|
||||||
portrait: 'kai_determined',
|
|
||||||
text: 'She\'s gone. They took her.\nBut I can still feel her... through the Twin Bond.',
|
|
||||||
bgColor: 0x2d1b00
|
|
||||||
},
|
|
||||||
{
|
|
||||||
background: 'ruins',
|
|
||||||
speaker: 'Kai',
|
|
||||||
portrait: 'kai_anger',
|
|
||||||
text: 'Whoever did this... I WILL find you.\nAnd my new "friends" will help me.',
|
|
||||||
bgColor: 0x2d1b00
|
|
||||||
},
|
|
||||||
{
|
|
||||||
background: 'zombies',
|
|
||||||
speaker: 'Narrator',
|
|
||||||
portrait: null,
|
|
||||||
text: 'Three zombies approach. But instead of attacking...\nthey kneel before Kai.',
|
|
||||||
bgColor: 0x1a4d1a
|
|
||||||
},
|
|
||||||
{
|
|
||||||
background: 'zombies',
|
|
||||||
speaker: 'Kai',
|
|
||||||
portrait: 'kai_realization',
|
|
||||||
text: 'I am... Alfa.\nAnd they are mine to command.',
|
|
||||||
bgColor: 0x1a4d1a
|
|
||||||
},
|
|
||||||
{
|
|
||||||
background: 'farm',
|
|
||||||
speaker: 'Narrator',
|
|
||||||
portrait: null,
|
|
||||||
text: 'And so begins the journey of Kai...\nZombie master. Brother. ALFA.',
|
|
||||||
bgColor: 0x2d5016
|
|
||||||
},
|
|
||||||
{
|
|
||||||
background: 'farm',
|
|
||||||
speaker: 'Narrator',
|
|
||||||
portrait: null,
|
|
||||||
text: 'BUILD your farm. COMMAND your undead.\nSEARCH for Ana.\n\nThis is... KRVAVA ŽETEV.',
|
|
||||||
bgColor: 0x2d5016
|
|
||||||
}
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
createDialogueUI(width, height) {
|
createDialogueUI(width, height) {
|
||||||
const dialogueBoxHeight = 180;
|
const dialogueBoxHeight = 180;
|
||||||
const dialogueY = height - dialogueBoxHeight;
|
const dialogueY = height - dialogueBoxHeight;
|
||||||
@@ -305,6 +178,27 @@ class PrologueScene extends Phaser.Scene {
|
|||||||
|
|
||||||
const dialogue = this.dialogueData[index];
|
const dialogue = this.dialogueData[index];
|
||||||
this.currentDialogueIndex = index;
|
this.currentDialogueIndex = index;
|
||||||
|
|
||||||
|
// Stop previous audio if playing
|
||||||
|
if (this.currentVoice) {
|
||||||
|
this.currentVoice.stop();
|
||||||
|
this.currentVoice = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Play new audio
|
||||||
|
if (dialogue.id) {
|
||||||
|
try {
|
||||||
|
// Check if audio exists in cache (it might not if load failed/missing)
|
||||||
|
if (this.cache.audio.exists(dialogue.id)) {
|
||||||
|
this.currentVoice = this.sound.add(dialogue.id);
|
||||||
|
this.currentVoice.play({ volume: 1.0 });
|
||||||
|
} else {
|
||||||
|
console.warn(`🔊 Audio missing for ${dialogue.id}`);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Audio play error:', err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Update background
|
// Update background
|
||||||
this.updateBackground(dialogue.background, dialogue.bgColor);
|
this.updateBackground(dialogue.background, dialogue.bgColor);
|
||||||
@@ -329,17 +223,35 @@ class PrologueScene extends Phaser.Scene {
|
|||||||
|
|
||||||
// Auto-advance if enabled
|
// Auto-advance if enabled
|
||||||
if (this.autoAdvance && index < this.dialogueData.length - 1) {
|
if (this.autoAdvance && index < this.dialogueData.length - 1) {
|
||||||
this.time.delayedCall(this.autoAdvanceDelay, () => {
|
// Wait for audio to finish OR standard delay?
|
||||||
this.advanceDialogue();
|
// Ideally wait for audio duration, but fallback to delay
|
||||||
|
let delay = this.autoAdvanceDelay;
|
||||||
|
if (this.currentVoice && this.currentVoice.duration) {
|
||||||
|
// Add a small buffer after speech ends
|
||||||
|
delay = (this.currentVoice.duration * 1000) + 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.time.delayedCall(delay, () => {
|
||||||
|
// Check if user hasn't already advanced manually
|
||||||
|
if (this.currentDialogueIndex === index) {
|
||||||
|
this.advanceDialogue();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
typewriterEffect(text) {
|
typewriterEffect(text) {
|
||||||
let displayText = '';
|
let displayText = '';
|
||||||
|
console.log('Typewriter started for:', text); // Debug
|
||||||
let charIndex = 0;
|
let charIndex = 0;
|
||||||
|
|
||||||
this.dialogueText.setText('');
|
this.dialogueText.setText('');
|
||||||
|
|
||||||
|
// Safety check for empty text
|
||||||
|
if (!text) {
|
||||||
|
this.canAdvance = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const timer = this.time.addEvent({
|
const timer = this.time.addEvent({
|
||||||
delay: 30, //CharactersperSeconds
|
delay: 30, //CharactersperSeconds
|
||||||
@@ -447,17 +359,28 @@ class PrologueScene extends Phaser.Scene {
|
|||||||
this.canAdvance = true;
|
this.canAdvance = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Stop current audio before advancing
|
||||||
|
if (this.currentVoice) {
|
||||||
|
this.currentVoice.stop();
|
||||||
|
}
|
||||||
|
|
||||||
this.showDialogue(this.currentDialogueIndex + 1);
|
this.showDialogue(this.currentDialogueIndex + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
skipPrologue() {
|
skipPrologue() {
|
||||||
console.log('⏭️ Skipping prologue...');
|
console.log('⏭️ Skipping prologue...');
|
||||||
|
if (this.currentVoice) {
|
||||||
|
this.currentVoice.stop();
|
||||||
|
}
|
||||||
this.scene.start('GameScene');
|
this.scene.start('GameScene');
|
||||||
}
|
}
|
||||||
|
|
||||||
completePrologue() {
|
completePrologue() {
|
||||||
console.log('✅ Prologue complete!');
|
console.log('✅ Prologue complete!');
|
||||||
|
if (this.currentVoice) {
|
||||||
|
this.currentVoice.stop();
|
||||||
|
}
|
||||||
|
|
||||||
// Fade out
|
// Fade out
|
||||||
this.cameras.main.fadeOut(2000, 0, 0, 0);
|
this.cameras.main.fadeOut(2000, 0, 0, 0);
|
||||||
|
|||||||
Reference in New Issue
Block a user