greenmix commited on
Commit
53843ac
·
verified ·
1 Parent(s): 0815b3d

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +91 -257
app.py CHANGED
@@ -1,276 +1,110 @@
1
  import gradio as gr
2
- import os
3
- import shutil
4
- import subprocess
5
- from datetime import datetime
6
- from pydub import AudioSegment, silence
7
- from pydub.effects import normalize
8
  import noisereduce as nr
9
  import numpy as np
10
- import random
11
- from scipy.io import wavfile
12
- import librosa
13
- import yt_dlp
14
-
15
-
16
- # Part 1: Audio Processor
17
- # Global variable to store processed audio path from Step 1
18
- processed_audio_path_step1 = None
19
-
20
- SILENCE_THRESHOLD_MS = 500 # Example: 500ms
21
-
22
- def generate_unique_filename(base_path, duration, suffix=""):
23
- timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
24
- duration_str = f"{duration:.2f}"
25
- base_name = os.path.basename(base_path)
26
- name, ext = os.path.splitext(base_name)
27
- unique_filename = f"Mirchi_{duration_str}_{timestamp}{suffix}{ext}"
28
- return unique_filename
29
-
30
- sarcastic_messages = [
31
- "Oh wow, that went well... Not.",
32
- "You really outdid yourself this time.",
33
- "Congratulations, you've hit an error. Again.",
34
- "Well, that didn't work. Shocker.",
35
- "Surprise, surprise, another error.",
36
- "Great job! Another error for your collection."
37
- ]
38
 
39
- def remove_unwanted_sounds(audio_path, silence_threshold_ms):
40
- y, sr = librosa.load(audio_path, sr=None)
 
 
 
41
 
42
- non_silent_intervals = librosa.effects.split(y, top_db=35) # Fine-tuned silence detection
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43
 
44
- if not non_silent_intervals.any():
45
- raise ValueError("No non-silent segments detected.")
 
 
 
46
 
47
- processed_audio = []
48
- last_end = 0
 
 
 
 
49
 
50
- for start, end in non_silent_intervals:
51
- silence_duration = start - last_end
52
-
53
- if silence_duration <= silence_threshold_ms * sr / 1000:
54
- processed_audio.append(y[last_end:start])
55
-
56
- processed_audio.append(y[start:end])
57
- last_end = end
58
 
59
- remaining_silence_duration = len(y) - last_end
60
- if remaining_silence_duration <= silence_threshold_ms * sr / 1000:
61
- processed_audio.append(y[last_end:])
62
 
63
- processed_audio = np.concatenate(processed_audio)
 
64
 
65
- return processed_audio, sr
66
-
67
- def apply_noise_removal(y, sr):
68
- reduced_noise = nr.reduce_noise(y=y, sr=sr, prop_decrease=0.6, n_fft=1024, win_length=512, hop_length=256)
69
- return reduced_noise
70
 
71
- def numpy_to_audiosegment(y, sr):
72
- y = (y * np.iinfo(np.int16).max).astype(np.int16)
73
- audio_segment = AudioSegment(
74
- y.tobytes(),
75
- frame_rate=sr,
76
- sample_width=2,
77
- channels=1
78
- )
79
- return audio_segment
80
-
81
- def process_audio_step1(audio_path, crossfade, normalize_audio, noise_removal):
82
- global processed_audio_path_step1
83
- try:
84
- if not audio_path:
85
- return None, random.choice(sarcastic_messages), None
86
-
87
- y, sr = remove_unwanted_sounds(audio_path, SILENCE_THRESHOLD_MS)
88
 
89
- if noise_removal:
90
- y = apply_noise_removal(y, sr)
 
 
 
 
 
 
 
 
 
 
91
 
92
- final_audio = numpy_to_audiosegment(y, sr)
 
 
 
 
93
 
94
- if normalize_audio:
95
- final_audio = normalize(final_audio)
96
 
97
- if crossfade:
98
- crossfade_duration = 1000 # 1 second crossfade
99
- processed_audio = final_audio[:crossfade_duration]
100
- for i in range(crossfade_duration, len(final_audio), crossfade_duration):
101
- chunk = final_audio[i:i + crossfade_duration]
102
- processed_audio = processed_audio.append(chunk, crossfade=crossfade_duration)
103
- else:
104
- processed_audio = final_audio
105
 
106
- unique_filename = generate_unique_filename(audio_path, len(processed_audio) / 1000, "_step1")
107
- output_path = os.path.join("audios_output_step1", unique_filename)
108
- os.makedirs("audios_output_step1", exist_ok=True)
109
- processed_audio.export(output_path, format="wav")
110
- processed_audio_path_step1 = output_path
111
- return output_path, "Success! Your audio is now processed.", output_path
112
- except Exception as e:
113
- return None, f"{random.choice(sarcastic_messages)} Error: {str(e)}", None
114
-
115
- def process_audio_step2(audio_path, target_duration):
116
- try:
117
- if not audio_path:
118
- return None, random.choice(sarcastic_messages), None
119
-
120
- audio = AudioSegment.from_file(audio_path)
121
- original_duration = len(audio) / 1000
122
- stretch_ratio = original_duration / target_duration
123
- unique_filename = generate_unique_filename(audio_path, original_duration, "_step2")
124
- output_path = os.path.join("audios_output_step2", unique_filename)
125
- os.makedirs("audios_output_step2", exist_ok=True)
126
- command = [
127
- 'ffmpeg',
128
- '-i', audio_path,
129
- '-filter:a', f'atempo={stretch_ratio}',
130
- output_path
131
- ]
132
- subprocess.run(command, check=True)
133
- return output_path, "Done! Your audio is stretched.", None
134
- except subprocess.CalledProcessError:
135
- return None, f"{random.choice(sarcastic_messages)} FFmpeg error occurred.", None
136
- except Exception as e:
137
- return None, f"{random.choice(sarcastic_messages)} Error: {str(e)}", None
138
-
139
- def clear_output_folders():
140
- folders = ["audios_output_step1", "audios_output_step2"]
141
- for folder in folders:
142
- if os.path.exists(folder):
143
- shutil.rmtree(folder)
144
- return "All output folders are cleared."
145
-
146
- def open_output_folder(folder_name):
147
- try:
148
- if os.name == 'nt': # Windows
149
- os.startfile(folder_name)
150
- elif os.name == 'posix': # macOS or Linux
151
- if os.uname().sysname == 'Darwin': # macOS
152
- subprocess.run(['open', folder_name])
153
- else: # Linux
154
- subprocess.run(['xdg-open', folder_name])
155
- return "Opening folder."
156
- except Exception as e:
157
- return f"{random.choice(sarcastic_messages)} Failed to open folder: {str(e)}"
158
-
159
- # Part 2: YouTube Downloader
160
- def download_youtube_video(url, save_path='.', file_format='mp4'):
161
- try:
162
- if file_format == 'mp4':
163
- ydl_opts = {
164
- 'format': 'bestvideo+bestaudio/best',
165
- 'outtmpl': os.path.join(save_path, '%(title)s.%(ext)s'),
166
- 'merge_output_format': 'mp4',
167
- 'postprocessors': [{
168
- 'key': 'FFmpegVideoConvertor',
169
- 'preferedformat': 'mp4',
170
- }],
171
- }
172
- elif file_format == 'mp3':
173
- ydl_opts = {
174
- 'format': 'bestaudio/best',
175
- 'outtmpl': os.path.join(save_path, '%(title)s.%(ext)s'),
176
- 'postprocessors': [{
177
- 'key': 'FFmpegExtractAudio',
178
- 'preferredcodec': 'mp3',
179
- 'preferredquality': '192',
180
- }],
181
- }
182
-
183
- with yt_dlp.YoutubeDL(ydl_opts) as ydl:
184
- info = ydl.extract_info(url, download=True)
185
- filename = ydl.prepare_filename(info)
186
- file_ext = '.mp4' if file_format == 'mp4' else '.mp3'
187
- final_filename = filename.rsplit('.', 1)[0] + file_ext
188
-
189
- if os.path.exists(final_filename):
190
- return final_filename, f"Downloaded successfully as {file_format.upper()}!"
191
- else:
192
- return None, f"Download failed, file not found."
193
-
194
- except Exception as e:
195
- return None, f"An error occurred: {str(e)}"
196
-
197
- def download_video_from_ui(url, save_location, file_format):
198
- if not url.strip():
199
- return None, "Please enter a valid URL."
200
 
201
- if not save_location.strip():
202
- save_location = '.' # Use current directory if save path is empty
203
-
204
- file_path, message = download_youtube_video(url, save_location, file_format)
205
- return file_path, message
206
-
207
-
208
- # Gradio interface with tabs
209
- with gr.Blocks(theme="soft") as demo:
210
- with gr.Tabs():
211
- with gr.Tab("Audio Processor"):
212
- with gr.Column():
213
- gr.Markdown("### Step 1: Cleanup")
214
- audio_input_step1 = gr.Audio(label="Upload Audio for Cleanup", type="filepath")
215
- with gr.Row():
216
- crossfade_option = gr.Checkbox(label="Apply Crossfade")
217
- normalize_option = gr.Checkbox(label="Normalize Audio")
218
- noise_removal_option = gr.Checkbox(label="Noise Removal")
219
- step1_error = gr.Textbox(lines=2, interactive=False)
220
- step1_output = gr.Audio(label="Processed Audio", interactive=False)
221
- step1_button = gr.Button("Process Step 1")
222
-
223
- gr.Markdown("### Step 2: Time Stretch")
224
- step2_audio_input = gr.Audio(label="Upload Audio for Time Stretch", type="filepath")
225
- with gr.Row():
226
- target_duration_input = gr.Number(label="Target Duration (seconds)", value=60.0)
227
- process_step2_button = gr.Button("Process Step 2")
228
- step2_error = gr.Textbox(lines=2, interactive=False)
229
- step2_output = gr.Audio(label="Processed Audio", interactive=False)
230
-
231
- gr.Markdown("### Manage Outputs")
232
- with gr.Row():
233
- open_output_button_step1 = gr.Button("Open Cleanup Output Folder")
234
- open_output_button_step2 = gr.Button("Open Stretch Output Folder")
235
- with gr.Row():
236
- clear_button = gr.Button("Clear Output Folders")
237
- step1_button.click(fn=process_audio_step1,
238
- inputs=[audio_input_step1, crossfade_option, normalize_option, noise_removal_option],
239
- outputs=[step1_output, step1_error, step1_output])
240
- process_step2_button.click(fn=process_audio_step2,
241
- inputs=[step2_audio_input, target_duration_input],
242
- outputs=[step2_output, step2_error, step2_output])
243
- clear_button.click(fn=clear_output_folders, inputs=None, outputs=None)
244
- open_output_button_step1.click(fn=lambda: open_output_folder("audios_output_step1"), inputs=None, outputs=None)
245
- open_output_button_step2.click(fn=lambda: open_output_folder("audios_output_step2"), inputs=None, outputs=None)
246
-
247
- with gr.Tab("YouTube Downloader"):
248
- gr.Markdown("""
249
- <div style="text-align: center;">
250
- <h1>YouTube Video Downloader</h1>
251
- <p>This application allows you to download YouTube videos or audio tracks.
252
- You can choose the format (MP4 for video or MP3 for audio) and specify a save location for the downloaded file.</p>
253
- </div>
254
- """)
255
- with gr.Row():
256
- url_input = gr.Textbox(label="YouTube Video URL", placeholder="Enter YouTube video URL here...")
257
- format_input = gr.Radio(label="Select Format", choices=['mp4', 'mp3'], value='mp4')
258
- save_path_input = gr.Textbox(label="Save Path", placeholder="Enter path to save the video (or leave blank for current directory)")
259
-
260
- download_button = gr.Button("Download Video/Audio")
261
- output_text = gr.Textbox(label="Status", interactive=False)
262
- file_output = gr.File(label="Download Link")
263
- def enable_button(url):
264
- if url.strip():
265
- return gr.update(interactive=True)
266
- else:
267
- return gr.update(interactive=False)
268
-
269
- def execute_download(url, save_path, file_format):
270
- file_path, result = download_video_from_ui(url, save_path, file_format)
271
- return result, file_path
272
-
273
- url_input.change(enable_button, inputs=url_input, outputs=download_button)
274
- download_button.click(execute_download, inputs=[url_input, save_path_input, format_input], outputs=[output_text, file_output])
275
 
276
- demo.launch()
 
 
 
 
1
  import gradio as gr
2
+ from pydub import AudioSegment
3
+ import librosa
 
 
 
 
4
  import noisereduce as nr
5
  import numpy as np
6
+ from io import BytesIO
7
+ import tempfile
8
+ import os
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
 
10
+ # Function to load audio
11
+ def load_audio(audio_file_path):
12
+ # Open the file and read its bytes
13
+ with open(audio_file_path, "rb") as f:
14
+ audio_bytes = f.read()
15
 
16
+ # Load the audio using pydub from the file bytes
17
+ audio_segment = AudioSegment.from_file(BytesIO(audio_bytes))
18
+ audio_array = np.array(audio_segment.get_array_of_samples(), dtype=np.float32)
19
+ sample_rate = audio_segment.frame_rate
20
+ return audio_array, sample_rate
21
+
22
+ # Function for noise reduction
23
+ def reduce_noise(audio, sample_rate):
24
+ reduced_noise_audio = nr.reduce_noise(y=audio, sr=sample_rate)
25
+ return reduced_noise_audio
26
+
27
+ # Function for pitch shifting
28
+ def pitch_shift(audio, sample_rate, n_steps):
29
+ shifted_audio = librosa.effects.pitch_shift(audio, sr=sample_rate, n_steps=n_steps)
30
+ return shifted_audio
31
+
32
+ # Function for time-stretching
33
+ def time_stretch(audio, rate):
34
+ stretched_audio = librosa.effects.time_stretch(audio, rate)
35
+ return stretched_audio
36
+
37
+ # Function to save audio to a temporary file and return the path
38
+ def save_audio(audio, sample_rate):
39
+ # Create a temporary file to save the audio
40
+ temp_file = tempfile.NamedTemporaryFile(delete=False, suffix=".wav")
41
+ temp_file_name = temp_file.name
42
 
43
+ # Use pydub to save the audio to the temp file
44
+ audio_segment = AudioSegment(
45
+ np.int16(audio).tobytes(), frame_rate=sample_rate, sample_width=2, channels=1
46
+ )
47
+ audio_segment.export(temp_file_name, format="wav")
48
 
49
+ temp_file.close()
50
+ return temp_file_name
51
+
52
+ # Main function to apply audio effects
53
+ def apply_effects(audio_file, noise_reduction, pitch_shift_steps, time_stretch_rate):
54
+ audio, sr = load_audio(audio_file)
55
 
56
+ if noise_reduction:
57
+ audio = reduce_noise(audio, sr)
 
 
 
 
 
 
58
 
59
+ if pitch_shift_steps != 0:
60
+ audio = pitch_shift(audio, sr, pitch_shift_steps)
 
61
 
62
+ if time_stretch_rate != 1.0:
63
+ audio = time_stretch(audio, time_stretch_rate)
64
 
65
+ return save_audio(audio, sr)
 
 
 
 
66
 
67
+ # Gradio UI
68
+ def build_ui():
69
+ with gr.Blocks() as demo:
70
+ # Custom Title
71
+ gr.Markdown("# Shyam's AI Audio Studio")
 
 
 
 
 
 
 
 
 
 
 
 
72
 
73
+ # Description for the tool
74
+ gr.Markdown(
75
+ """
76
+ Welcome to **Shyam's AI Audio Studio**!
77
+ This tool allows you to upload audio files and apply various effects like:
78
+ - Noise Reduction
79
+ - Pitch Shifting (up or down by semitones)
80
+ - Time Stretching (speed up or slow down)
81
+
82
+ Experiment with the sliders to fine-tune the effects and get your desired sound!
83
+ """
84
+ )
85
 
86
+ # Input components
87
+ audio_input = gr.Audio(type="filepath", label="Upload Audio File")
88
+ noise_reduction = gr.Checkbox(label="Apply Noise Reduction", value=True)
89
+ pitch_shift_steps = gr.Slider(label="Pitch Shift (in semitones)", minimum=-12, maximum=12, value=0, step=1)
90
+ time_stretch_rate = gr.Slider(label="Time Stretch Rate", minimum=0.5, maximum=2.0, value=1.0, step=0.1)
91
 
92
+ # Output component
93
+ audio_output = gr.File(label="Download Edited Audio")
94
 
95
+ # Button to trigger the process
96
+ edit_button = gr.Button("Apply Effects")
 
 
 
 
 
 
97
 
98
+ # Link the button to the effect function
99
+ edit_button.click(
100
+ apply_effects,
101
+ inputs=[audio_input, noise_reduction, pitch_shift_steps, time_stretch_rate],
102
+ outputs=audio_output
103
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
104
 
105
+ return demo
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
106
 
107
+ # Launch the Gradio app
108
+ if __name__ == "__main__":
109
+ ui = build_ui()
110
+ ui.launch()