Update app.py
Browse files
app.py
CHANGED
@@ -2,112 +2,78 @@ import streamlit as st
|
|
2 |
import librosa
|
3 |
import soundfile as sf
|
4 |
import numpy as np
|
5 |
-
from
|
6 |
import tempfile
|
7 |
-
import os
|
8 |
|
9 |
-
def
|
10 |
# Load the audio file
|
11 |
-
y, sr = librosa.load(
|
12 |
|
13 |
-
#
|
14 |
-
|
15 |
-
y=y,
|
16 |
-
sr=sr,
|
17 |
-
n_steps=settings['pitch_steps']
|
18 |
-
)
|
19 |
|
20 |
-
#
|
21 |
-
|
22 |
-
|
23 |
|
24 |
-
#
|
25 |
-
|
26 |
-
noise_filtered = signal.filtfilt([1], [1, -0.99], noise)
|
27 |
-
y_breathy = y_formant + settings['breathiness'] * noise_filtered
|
28 |
-
|
29 |
-
# Final normalization
|
30 |
-
y_normalized = librosa.util.normalize(y_breathy)
|
31 |
|
32 |
return y_normalized, sr
|
33 |
|
34 |
-
|
35 |
-
|
|
|
|
|
|
|
|
|
|
|
36 |
|
37 |
-
# File
|
38 |
-
|
39 |
|
40 |
-
if
|
41 |
# Save uploaded file temporarily
|
42 |
-
with tempfile.NamedTemporaryFile(delete=False, suffix=
|
43 |
-
tmp_file.write(
|
44 |
-
|
45 |
-
|
46 |
-
#
|
47 |
-
|
48 |
-
"Select voice type",
|
49 |
-
["Young Female", "Mature Female", "Custom"]
|
50 |
-
)
|
51 |
-
|
52 |
-
# Settings based on voice type
|
53 |
-
if voice_type == "Young Female":
|
54 |
-
settings = {
|
55 |
-
'pitch_steps': 4.0,
|
56 |
-
'breathiness': 0.1
|
57 |
-
}
|
58 |
-
elif voice_type == "Mature Female":
|
59 |
-
settings = {
|
60 |
-
'pitch_steps': 3.0,
|
61 |
-
'breathiness': 0.08
|
62 |
-
}
|
63 |
-
else: # Custom
|
64 |
-
settings = {
|
65 |
-
'pitch_steps': st.slider("Pitch (Higher = More Female)", 0.0, 6.0, 4.0, 0.5),
|
66 |
-
'breathiness': st.slider("Breathiness", 0.0, 0.2, 0.1, 0.01)
|
67 |
-
}
|
68 |
|
69 |
-
# Convert button
|
70 |
if st.button("Convert to Female Voice"):
|
|
|
71 |
try:
|
72 |
-
|
73 |
-
st.write("Converting... Please wait...")
|
74 |
-
converted_audio, sr = convert_to_female_voice(temp_path, settings)
|
75 |
-
|
76 |
-
# Save the processed audio
|
77 |
-
output_path = "temp_output.wav"
|
78 |
-
sf.write(output_path, converted_audio, sr)
|
79 |
|
80 |
-
#
|
81 |
-
|
82 |
|
83 |
-
#
|
84 |
-
|
85 |
-
st.download_button(
|
86 |
-
label="Download converted audio",
|
87 |
-
data=audio_file,
|
88 |
-
file_name="female_voice.wav",
|
89 |
-
mime="audio/wav"
|
90 |
-
)
|
91 |
|
92 |
-
#
|
93 |
-
|
94 |
-
|
|
|
|
|
|
|
|
|
95 |
|
96 |
except Exception as e:
|
97 |
-
st.error(f"
|
98 |
|
|
|
99 |
st.markdown("""
|
100 |
-
###
|
101 |
-
1. Upload
|
102 |
-
2.
|
103 |
3. Click 'Convert to Female Voice'
|
104 |
-
4.
|
105 |
-
5. Download
|
106 |
|
107 |
-
###
|
108 |
-
-
|
109 |
-
-
|
110 |
-
-
|
111 |
-
- Young female voice works best with pitch 4-5
|
112 |
-
- Mature female voice works best with pitch 3-4
|
113 |
""")
|
|
|
2 |
import librosa
|
3 |
import soundfile as sf
|
4 |
import numpy as np
|
5 |
+
from io import BytesIO
|
6 |
import tempfile
|
|
|
7 |
|
8 |
+
def process_audio(audio_file, pitch_factor=8):
|
9 |
# Load the audio file
|
10 |
+
y, sr = librosa.load(audio_file)
|
11 |
|
12 |
+
# Pitch shift using librosa (female voice typically higher pitch)
|
13 |
+
y_shifted = librosa.effects.pitch_shift(y, sr=sr, n_steps=pitch_factor)
|
|
|
|
|
|
|
|
|
14 |
|
15 |
+
# Apply some feminine characteristics
|
16 |
+
# Smooth the audio slightly
|
17 |
+
y_smooth = librosa.effects.preemphasis(y_shifted)
|
18 |
|
19 |
+
# Normalize audio
|
20 |
+
y_normalized = librosa.util.normalize(y_smooth)
|
|
|
|
|
|
|
|
|
|
|
21 |
|
22 |
return y_normalized, sr
|
23 |
|
24 |
+
def save_audio(audio_data, sr):
|
25 |
+
# Save processed audio to BytesIO object
|
26 |
+
buffer = BytesIO()
|
27 |
+
sf.write(buffer, audio_data, sr, format='WAV')
|
28 |
+
return buffer
|
29 |
+
|
30 |
+
st.title("Voice Changer - Female Voice Conversion")
|
31 |
|
32 |
+
# File uploader
|
33 |
+
uploaded_file = st.file_uploader("Upload an audio file", type=['wav', 'mp3'])
|
34 |
|
35 |
+
if uploaded_file is not None:
|
36 |
# Save uploaded file temporarily
|
37 |
+
with tempfile.NamedTemporaryFile(delete=False, suffix='.wav') as tmp_file:
|
38 |
+
tmp_file.write(uploaded_file.getvalue())
|
39 |
+
tmp_path = tmp_file.name
|
40 |
+
|
41 |
+
# Pitch adjustment slider
|
42 |
+
pitch_factor = st.slider("Pitch Adjustment", 0.0, 12.0, 8.0, 0.5)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
43 |
|
|
|
44 |
if st.button("Convert to Female Voice"):
|
45 |
+
# Process the audio
|
46 |
try:
|
47 |
+
processed_audio, sr = process_audio(tmp_path, pitch_factor)
|
|
|
|
|
|
|
|
|
|
|
|
|
48 |
|
49 |
+
# Save processed audio
|
50 |
+
audio_buffer = save_audio(processed_audio, sr)
|
51 |
|
52 |
+
# Create download button
|
53 |
+
st.audio(audio_buffer, format='audio/wav')
|
|
|
|
|
|
|
|
|
|
|
|
|
54 |
|
55 |
+
# Add download button
|
56 |
+
st.download_button(
|
57 |
+
label="Download Converted Audio",
|
58 |
+
data=audio_buffer,
|
59 |
+
file_name="female_voice.wav",
|
60 |
+
mime="audio/wav"
|
61 |
+
)
|
62 |
|
63 |
except Exception as e:
|
64 |
+
st.error(f"Error processing audio: {str(e)}")
|
65 |
|
66 |
+
# Add instructions
|
67 |
st.markdown("""
|
68 |
+
### Instructions:
|
69 |
+
1. Upload a WAV or MP3 audio file
|
70 |
+
2. Adjust the pitch slider (higher values = more feminine voice)
|
71 |
3. Click 'Convert to Female Voice'
|
72 |
+
4. Play the converted audio
|
73 |
+
5. Download the result if satisfied
|
74 |
|
75 |
+
### Notes:
|
76 |
+
- Best results with clear audio input
|
77 |
+
- Recommended pitch adjustment: 6-8 for natural-sounding results
|
78 |
+
- Larger files may take longer to process
|
|
|
|
|
79 |
""")
|