Initialize voicebox project with backend, frontend, and Tauri setup. Added configuration files, dependencies, and basic structure for components, hooks, and utilities. Included README and setup documentation for guidance.

This commit is contained in:
Jamie Pine
2026-01-25 02:19:06 -08:00
commit 01e3065692
166 changed files with 22764 additions and 0 deletions
+119
View File
@@ -0,0 +1,119 @@
"""
Audio processing utilities.
"""
import numpy as np
import soundfile as sf
import librosa
from typing import Tuple, Optional
def normalize_audio(
audio: np.ndarray,
target_db: float = -20.0,
peak_limit: float = 0.85,
) -> np.ndarray:
"""
Normalize audio to target loudness with peak limiting.
Args:
audio: Input audio array
target_db: Target RMS level in dB
peak_limit: Peak limit (0.0-1.0)
Returns:
Normalized audio array
"""
# Convert to float32
audio = audio.astype(np.float32)
# Calculate current RMS
rms = np.sqrt(np.mean(audio**2))
# Calculate target RMS
target_rms = 10**(target_db / 20)
# Apply gain
if rms > 0:
gain = target_rms / rms
audio = audio * gain
# Peak limiting
audio = np.clip(audio, -peak_limit, peak_limit)
return audio
def load_audio(
path: str,
sample_rate: int = 24000,
mono: bool = True,
) -> Tuple[np.ndarray, int]:
"""
Load audio file with normalization.
Args:
path: Path to audio file
sample_rate: Target sample rate
mono: Convert to mono
Returns:
Tuple of (audio_array, sample_rate)
"""
audio, sr = librosa.load(path, sr=sample_rate, mono=mono)
return audio, sr
def save_audio(
audio: np.ndarray,
path: str,
sample_rate: int = 24000,
) -> None:
"""
Save audio file.
Args:
audio: Audio array
path: Output path
sample_rate: Sample rate
"""
sf.write(path, audio, sample_rate)
def validate_reference_audio(
audio_path: str,
min_duration: float = 2.0,
max_duration: float = 30.0,
min_rms: float = 0.01,
) -> Tuple[bool, Optional[str]]:
"""
Validate reference audio for voice cloning.
Args:
audio_path: Path to audio file
min_duration: Minimum duration in seconds
max_duration: Maximum duration in seconds
min_rms: Minimum RMS level
Returns:
Tuple of (is_valid, error_message)
"""
try:
audio, sr = load_audio(audio_path)
duration = len(audio) / sr
if duration < min_duration:
return False, f"Audio too short (minimum {min_duration} seconds)"
if duration > max_duration:
return False, f"Audio too long (maximum {max_duration} seconds)"
rms = np.sqrt(np.mean(audio**2))
if rms < min_rms:
return False, "Audio is too quiet or silent"
if np.abs(audio).max() > 0.99:
return False, "Audio is clipping (reduce input gain)"
return True, None
except Exception as e:
return False, f"Error validating audio: {str(e)}"