Artificial-superintelligence commited on
Commit
6a86f73
·
verified ·
1 Parent(s): 982ba4e

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +83 -142
app.py CHANGED
@@ -2,171 +2,112 @@ import streamlit as st
2
  import librosa
3
  import soundfile as sf
4
  import numpy as np
5
- import scipy.signal as signal
6
- from io import BytesIO
7
  import tempfile
 
8
 
9
- def pitch_shift_with_formant_preservation(y, sr, n_steps):
10
- # Use a smaller frame size for better quality
11
- frame_length = 1024
12
- hop_length = 256
13
 
14
- # Apply pitch shifting with smaller frame size
15
- y_shifted = librosa.effects.pitch_shift(
16
  y=y,
17
  sr=sr,
18
- n_steps=n_steps,
19
- bins_per_octave=12,
20
- res_type='kaiser_fast'
21
  )
22
 
23
- return y_shifted
24
-
25
- def enhance_female_characteristics(y, sr, settings):
26
- # Extract harmonics more gently
27
- y_harmonic, y_percussive = librosa.effects.hpss(
28
- y,
29
- margin=3.0,
30
- kernel_size=31
31
- )
32
 
33
- # Enhance harmonics subtly
34
- y_enhanced = y_harmonic * settings['harmonic_boost'] + y * (1 - settings['harmonic_boost'])
 
 
35
 
36
- # Apply subtle EQ to enhance female characteristics
37
- y_filtered = apply_female_eq(y_enhanced, sr)
38
 
39
- return y_filtered
40
 
41
- def apply_female_eq(y, sr):
42
- # Design filters for female voice enhancement
43
- # Boost frequencies around 1kHz-2kHz for feminine resonance
44
- b1, a1 = signal.butter(2, [1000/(sr/2), 2000/(sr/2)], btype='band')
45
- y_filtered = signal.filtfilt(b1, a1, y)
46
-
47
- # Slight boost in high frequencies (3kHz-5kHz)
48
- b2, a2 = signal.butter(2, [3000/(sr/2), 5000/(sr/2)], btype='band')
49
- y_filtered += 0.3 * signal.filtfilt(b2, a2, y)
50
-
51
- return librosa.util.normalize(y_filtered)
52
 
53
- def add_breathiness(y, sr, amount):
54
- # Generate more natural breath noise
55
- noise = np.random.normal(0, 0.005, len(y))
56
-
57
- # Filter the noise to sound more like breath
58
- b, a = signal.butter(2, 2000/(sr/2), btype='lowpass')
59
- breath_noise = signal.filtfilt(b, a, noise)
60
-
61
- # Add filtered noise
62
- y_breathy = y * (1 - amount) + breath_noise * amount
63
- return librosa.util.normalize(y_breathy)
64
 
65
- def process_audio_advanced(audio_file, settings):
66
- # Load audio with a higher sample rate
67
- y, sr = librosa.load(audio_file, sr=24000)
68
-
69
- # Remove DC offset
70
- y = librosa.util.normalize(y - np.mean(y))
71
-
72
- # Apply pitch shifting
73
- y_shifted = pitch_shift_with_formant_preservation(
74
- y,
75
- sr,
76
- settings['pitch_shift']
77
  )
78
 
79
- # Enhance female characteristics
80
- y_enhanced = enhance_female_characteristics(y_shifted, sr, settings)
81
-
82
- # Add breathiness
83
- if settings['breathiness'] > 0:
84
- y_enhanced = add_breathiness(y_enhanced, sr, settings['breathiness'])
85
-
86
- # Final normalization and cleaning
87
- y_final = librosa.util.normalize(y_enhanced)
88
-
89
- # Apply final smoothing
90
- y_final = signal.savgol_filter(y_final, 1001, 2)
91
-
92
- return y_final, sr
93
-
94
- def create_voice_preset(preset_name):
95
- presets = {
96
- 'Young Female': {
97
- 'pitch_shift': 4.0,
98
- 'harmonic_boost': 0.3,
99
- 'breathiness': 0.15
100
- },
101
- 'Mature Female': {
102
- 'pitch_shift': 3.0,
103
- 'harmonic_boost': 0.2,
104
  'breathiness': 0.1
105
- },
106
- 'Soft Female': {
107
- 'pitch_shift': 3.5,
108
- 'harmonic_boost': 0.25,
109
- 'breathiness': 0.2
110
  }
111
- }
112
- return presets.get(preset_name)
113
-
114
- st.title("Improved Female Voice Converter")
115
-
116
- uploaded_file = st.file_uploader("Upload an audio file", type=['wav', 'mp3'])
117
-
118
- if uploaded_file is not None:
119
- with tempfile.NamedTemporaryFile(delete=False, suffix='.wav') as tmp_file:
120
- tmp_file.write(uploaded_file.getvalue())
121
- tmp_path = tmp_file.name
122
-
123
- preset_name = st.selectbox(
124
- "Select Voice Preset",
125
- ['Young Female', 'Mature Female', 'Soft Female', 'Custom']
126
- )
127
-
128
- if preset_name == 'Custom':
129
  settings = {
130
- 'pitch_shift': st.slider("Pitch Shift", 0.0, 6.0, 4.0, 0.5),
131
- 'harmonic_boost': st.slider("Harmonic Enhancement", 0.0, 0.5, 0.3, 0.05),
132
- 'breathiness': st.slider("Breathiness", 0.0, 0.3, 0.15, 0.05)
133
  }
134
- else:
135
- settings = create_voice_preset(preset_name)
136
-
137
- if st.button("Convert Voice"):
138
- with st.spinner("Processing audio..."):
139
- try:
140
- processed_audio, sr = process_audio_advanced(tmp_path, settings)
141
-
142
- # Save to buffer
143
- buffer = BytesIO()
144
- sf.write(buffer, processed_audio, sr, format='WAV')
145
-
146
- # Display audio player
147
- st.audio(buffer, format='audio/wav')
148
-
149
- # Download button
 
 
 
 
 
 
150
  st.download_button(
151
- label="Download Converted Audio",
152
- data=buffer,
153
- file_name="female_voice_converted.wav",
154
  mime="audio/wav"
155
  )
156
-
157
- except Exception as e:
158
- st.error(f"Error processing audio: {str(e)}")
 
 
 
 
159
 
160
  st.markdown("""
161
- ### Tips for Best Results:
162
- 1. Use high-quality input audio with clear speech
163
- 2. Start with presets and adjust if needed
164
- 3. Keep pitch shift between 3-5 for most natural results
165
- 4. Use minimal breathiness (0.1-0.2) for realistic sound
166
- 5. Record in a quiet environment with minimal background noise
167
 
168
- ### Recommended Settings:
169
- - For younger female voice: pitch shift 4.0, harmonic boost 0.3
170
- - For mature female voice: pitch shift 3.0, harmonic boost 0.2
171
- - For soft female voice: pitch shift 3.5, harmonic boost 0.25
 
 
172
  """)
 
2
  import librosa
3
  import soundfile as sf
4
  import numpy as np
5
+ from scipy import signal
 
6
  import tempfile
7
+ import os
8
 
9
+ def convert_to_female_voice(audio_path, settings):
10
+ # Load the audio file
11
+ y, sr = librosa.load(audio_path, sr=None)
 
12
 
13
+ # Step 1: Pitch shifting (female voice is typically higher)
14
+ y_pitched = librosa.effects.pitch_shift(
15
  y=y,
16
  sr=sr,
17
+ n_steps=settings['pitch_steps']
 
 
18
  )
19
 
20
+ # Step 2: Simple formant shifting using resampling
21
+ alpha = 1.2 # Formant scaling factor
22
+ y_formant = librosa.effects.time_stretch(y_pitched, rate=alpha)
 
 
 
 
 
 
23
 
24
+ # Step 3: Add slight breathiness
25
+ noise = np.random.normal(0, 0.005, len(y_formant))
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
+ # Streamlit interface
35
+ st.title("Simple Female Voice Converter")
 
 
 
 
 
 
 
 
 
36
 
37
+ # File upload
38
+ audio_file = st.file_uploader("Upload your audio file (WAV or MP3)", type=['wav', 'mp3'])
 
 
 
 
 
 
 
 
 
39
 
40
+ if audio_file is not None:
41
+ # Save uploaded file temporarily
42
+ with tempfile.NamedTemporaryFile(delete=False, suffix=os.path.splitext(audio_file.name)[1]) as tmp_file:
43
+ tmp_file.write(audio_file.getvalue())
44
+ temp_path = tmp_file.name
45
+
46
+ # Voice type selection
47
+ voice_type = st.selectbox(
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
+ # Process the audio
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
+ # Play the audio
81
+ st.audio(output_path)
82
+
83
+ # Provide download button
84
+ with open(output_path, 'rb') as audio_file:
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
+ # Clean up
93
+ os.remove(temp_path)
94
+ os.remove(output_path)
95
+
96
+ except Exception as e:
97
+ st.error(f"An error occurred: {str(e)}")
98
 
99
  st.markdown("""
100
+ ### How to use:
101
+ 1. Upload an audio file (WAV or MP3)
102
+ 2. Choose a preset or custom settings
103
+ 3. Click 'Convert to Female Voice'
104
+ 4. Listen to the result
105
+ 5. Download if you like it
106
 
107
+ ### Tips for best results:
108
+ - Use clear audio with minimal background noise
109
+ - Speak in a neutral tone
110
+ - Try different settings to find the best match
111
+ - Young female voice works best with pitch 4-5
112
+ - Mature female voice works best with pitch 3-4
113
  """)