Spaces:
Sleeping
Sleeping
Create app.py
Browse files
app.py
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import gradio as gr
|
| 2 |
+
import numpy as np
|
| 3 |
+
import librosa
|
| 4 |
+
import soundfile as sf
|
| 5 |
+
from scipy import signal
|
| 6 |
+
import io
|
| 7 |
+
|
| 8 |
+
def change_voice(audio, voice_preset, custom_pitch, custom_speed):
|
| 9 |
+
"""
|
| 10 |
+
Transform voice with selected preset or custom settings
|
| 11 |
+
"""
|
| 12 |
+
if audio is None:
|
| 13 |
+
return None, "Please record or upload audio first!"
|
| 14 |
+
|
| 15 |
+
presets = {
|
| 16 |
+
"Sophia (Soft)": {"pitch": 1.5, "speed": 1.0},
|
| 17 |
+
"Emma (Professional)": {"pitch": 1.4, "speed": 1.1},
|
| 18 |
+
"Olivia (Young)": {"pitch": 1.7, "speed": 1.15},
|
| 19 |
+
"Ava (Mature)": {"pitch": 1.3, "speed": 0.95},
|
| 20 |
+
"Isabella (Sweet)": {"pitch": 1.6, "speed": 1.05},
|
| 21 |
+
"Mia (Dramatic)": {"pitch": 1.55, "speed": 0.9},
|
| 22 |
+
"Custom": {"pitch": custom_pitch, "speed": custom_speed}
|
| 23 |
+
}
|
| 24 |
+
|
| 25 |
+
settings = presets[voice_preset]
|
| 26 |
+
pitch_factor = settings["pitch"]
|
| 27 |
+
speed_factor = settings["speed"]
|
| 28 |
+
|
| 29 |
+
try:
|
| 30 |
+
sr, y = audio
|
| 31 |
+
|
| 32 |
+
if y.dtype == np.int16:
|
| 33 |
+
y = y.astype(np.float32) / 32768.0
|
| 34 |
+
elif y.dtype == np.int32:
|
| 35 |
+
y = y.astype(np.float32) / 2147483648.0
|
| 36 |
+
|
| 37 |
+
if len(y.shape) > 1:
|
| 38 |
+
y = np.mean(y, axis=1)
|
| 39 |
+
|
| 40 |
+
y_shifted = librosa.effects.pitch_shift(y, sr=sr, n_steps=12 * np.log2(pitch_factor))
|
| 41 |
+
|
| 42 |
+
if speed_factor != 1.0:
|
| 43 |
+
y_shifted = librosa.effects.time_stretch(y_shifted, rate=speed_factor)
|
| 44 |
+
|
| 45 |
+
if pitch_factor > 1.2:
|
| 46 |
+
nyquist = sr / 2
|
| 47 |
+
formant_freqs = [800, 1150, 2900, 3900]
|
| 48 |
+
for freq in formant_freqs:
|
| 49 |
+
if freq < nyquist:
|
| 50 |
+
b, a = signal.butter(2, [max(freq-100, 20)/nyquist, min(freq+100, nyquist-1)/nyquist], btype='band')
|
| 51 |
+
filtered = signal.filtfilt(b, a, y_shifted)
|
| 52 |
+
y_shifted = y_shifted + filtered * 0.1
|
| 53 |
+
|
| 54 |
+
y_shifted = y_shifted / np.max(np.abs(y_shifted)) * 0.9
|
| 55 |
+
y_shifted = (y_shifted * 32768).astype(np.int16)
|
| 56 |
+
|
| 57 |
+
message = f"β
Voice transformed to {voice_preset}!\nPitch: {pitch_factor:.2f}x | Speed: {speed_factor:.2f}x"
|
| 58 |
+
return (sr, y_shifted), message
|
| 59 |
+
|
| 60 |
+
except Exception as e:
|
| 61 |
+
return None, f"β Error processing audio: {str(e)}"
|
| 62 |
+
|
| 63 |
+
with gr.Blocks(theme=gr.themes.Soft(primary_hue="pink")) as demo:
|
| 64 |
+
|
| 65 |
+
gr.Markdown("""
|
| 66 |
+
# π€ Professional Voice Changer
|
| 67 |
+
### Transform your voice with AI-powered female voice presets
|
| 68 |
+
""")
|
| 69 |
+
|
| 70 |
+
with gr.Row():
|
| 71 |
+
with gr.Column(scale=1):
|
| 72 |
+
gr.Markdown("### ποΈ Input Audio")
|
| 73 |
+
audio_input = gr.Audio(sources=["microphone", "upload"], type="numpy", label="Record or Upload Audio")
|
| 74 |
+
|
| 75 |
+
gr.Markdown("### π΅ Voice Settings")
|
| 76 |
+
voice_preset = gr.Radio(
|
| 77 |
+
choices=["Sophia (Soft)", "Emma (Professional)", "Olivia (Young)", "Ava (Mature)", "Isabella (Sweet)", "Mia (Dramatic)", "Custom"],
|
| 78 |
+
value="Sophia (Soft)",
|
| 79 |
+
label="Choose Voice Profile",
|
| 80 |
+
info="Select a preset or use Custom for manual control"
|
| 81 |
+
)
|
| 82 |
+
|
| 83 |
+
with gr.Accordion("ποΈ Custom Settings", open=False):
|
| 84 |
+
custom_pitch = gr.Slider(minimum=1.0, maximum=2.0, value=1.5, step=0.1, label="Pitch Multiplier", info="Higher = More feminine")
|
| 85 |
+
custom_speed = gr.Slider(minimum=0.5, maximum=1.5, value=1.0, step=0.05, label="Speed Multiplier", info="Adjust speaking speed")
|
| 86 |
+
|
| 87 |
+
transform_btn = gr.Button("β¨ Transform Voice", variant="primary", size="lg")
|
| 88 |
+
|
| 89 |
+
with gr.Column(scale=1):
|
| 90 |
+
gr.Markdown("### π Output Audio")
|
| 91 |
+
audio_output = gr.Audio(label="Transformed Voice", type="numpy")
|
| 92 |
+
status_output = gr.Textbox(label="Status", lines=3, interactive=False)
|
| 93 |
+
|
| 94 |
+
gr.Markdown("""
|
| 95 |
+
### π Voice Profile Details
|
| 96 |
+
- **Sophia (Soft)**: Gentle and warm tone
|
| 97 |
+
- **Emma (Professional)**: Clear and confident
|
| 98 |
+
- **Olivia (Young)**: Energetic and bright
|
| 99 |
+
- **Ava (Mature)**: Deep and authoritative
|
| 100 |
+
- **Isabella (Sweet)**: Friendly and cheerful
|
| 101 |
+
- **Mia (Dramatic)**: Expressive and bold
|
| 102 |
+
- **Custom**: Set your own pitch and speed
|
| 103 |
+
""")
|
| 104 |
+
|
| 105 |
+
transform_btn.click(fn=change_voice, inputs=[audio_input, voice_preset, custom_pitch, custom_speed], outputs=[audio_output, status_output])
|
| 106 |
+
|
| 107 |
+
gr.Markdown("""
|
| 108 |
+
---
|
| 109 |
+
### π‘ Tips:
|
| 110 |
+
- π€ **Recording**: Speak clearly and at normal volume
|
| 111 |
+
- π **Upload**: Supports WAV, MP3, and other audio formats
|
| 112 |
+
- ποΈ **Pitch**: Range 1.0-2.0 (higher = more feminine)
|
| 113 |
+
- β‘ **Speed**: Range 0.5-1.5 (adjust speaking pace)
|
| 114 |
+
- πΎ **Download**: Click the download button on the output audio player
|
| 115 |
+
""")
|
| 116 |
+
|
| 117 |
+
if __name__ == "__main__":
|
| 118 |
+
demo.launch()
|