Add generated VibeVoice audio assets, dialogue JSON, and updated PrologueScene

This commit is contained in:
2025-12-27 01:56:31 +01:00
parent bec3d8b59a
commit 6a01731de0
26 changed files with 529 additions and 155 deletions

Submodule ai_voice_gen/VibeVoice_Apple/VibeVoice added at b9d561240a

93
ai_voice_gen/apple.md Normal file
View 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)
```

View 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"

View 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
View 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").

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View 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"
}
]

View File

@@ -30,17 +30,41 @@ class PrologueScene extends Phaser.Scene {
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() {
const width = this.cameras.main.width;
const height = this.cameras.main.height;
console.log('🎬 Starting Prologue...');
// Track current audio to stop it when advancing
this.currentVoice = null;
// Black background
this.add.rectangle(0, 0, width, height, 0x000000).setOrigin(0);
// Initialize dialogue data
this.dialogueData = this.createDialogueData();
// Initialize dialogue data from JSON
this.dialogueData = this.cache.json.get('prologue_data');
if (!this.dialogueData) {
console.error('❌ Failed to load prologue dialogue data!');
this.dialogueData = [];
}
// Create UI elements
this.createDialogueUI(width, height);
@@ -83,157 +107,6 @@ class PrologueScene extends Phaser.Scene {
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) {
const dialogueBoxHeight = 180;
const dialogueY = height - dialogueBoxHeight;
@@ -305,6 +178,27 @@ class PrologueScene extends Phaser.Scene {
const dialogue = this.dialogueData[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
this.updateBackground(dialogue.background, dialogue.bgColor);
@@ -329,17 +223,35 @@ class PrologueScene extends Phaser.Scene {
// Auto-advance if enabled
if (this.autoAdvance && index < this.dialogueData.length - 1) {
this.time.delayedCall(this.autoAdvanceDelay, () => {
this.advanceDialogue();
// Wait for audio to finish OR standard delay?
// 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) {
let displayText = '';
console.log('Typewriter started for:', text); // Debug
let charIndex = 0;
this.dialogueText.setText('');
// Safety check for empty text
if (!text) {
this.canAdvance = true;
return;
}
const timer = this.time.addEvent({
delay: 30, //CharactersperSeconds
@@ -447,17 +359,28 @@ class PrologueScene extends Phaser.Scene {
this.canAdvance = true;
return;
}
// Stop current audio before advancing
if (this.currentVoice) {
this.currentVoice.stop();
}
this.showDialogue(this.currentDialogueIndex + 1);
}
skipPrologue() {
console.log('⏭️ Skipping prologue...');
if (this.currentVoice) {
this.currentVoice.stop();
}
this.scene.start('GameScene');
}
completePrologue() {
console.log('✅ Prologue complete!');
if (this.currentVoice) {
this.currentVoice.stop();
}
// Fade out
this.cameras.main.fadeOut(2000, 0, 0, 0);