tee342 commited on
Commit
d9349e6
·
verified ·
1 Parent(s): bdcd719

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +215 -253
app.py CHANGED
@@ -1,269 +1,231 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  with gr.Blocks() as demo:
2
  gr.HTML('<h3 style="text-align:center;">Where Your Audio Meets Intelligence</h3>')
3
  gr.Markdown('### Upload, edit, export — powered by AI!')
4
 
5
- # 1. Single File Studio
6
  with gr.Tab("🎵 Single File Studio"):
7
  with gr.Row():
8
  with gr.Column():
9
  input_audio = gr.Audio(label="Upload Audio", type="filepath")
10
- effect_checkbox = gr.CheckboxGroup(
11
- choices=list({e for effects in preset_choices.values() for e in effects}),
12
- label="Apply Effects in Order"
13
- )
14
- preset_dropdown = gr.Dropdown(choices=preset_names, label="Select Preset", value=preset_names[0])
15
  export_format = gr.Dropdown(choices=["WAV", "MP3"], label="Export Format", value="WAV")
16
  isolate_vocals = gr.Checkbox(label="Isolate Vocals After Effects")
17
  process_btn = gr.Button("Process Audio")
 
18
  with gr.Column():
19
- output_audio = gr.Audio(label="Processed Audio", type="numpy")
20
- waveform_img = gr.Image(label="Waveform Preview")
21
- session_log_out = gr.Textbox(label="Session Log", lines=6)
22
- genre_out = gr.Textbox(label="Detected Genre")
23
- status_box = gr.Textbox(label="Status", lines=1, value="Ready")
24
-
25
- def update_effects_for_preset(preset_name):
26
- return preset_choices.get(preset_name, [])
27
-
28
- preset_dropdown.change(update_effects_for_preset, inputs=preset_dropdown, outputs=effect_checkbox)
29
-
30
- def process_wrapper(audio_path, effects, isolate, preset, fmt):
31
  effs = preset_choices.get(preset, []) if preset in preset_choices else effects
32
- return process_audio(audio_path, effs, isolate, preset, fmt)
33
-
34
- process_btn.click(process_wrapper,
35
- inputs=[input_audio, effect_checkbox, isolate_vocals, preset_dropdown, export_format],
36
- outputs=[output_audio, waveform_img, session_log_out, genre_out, status_box])
37
-
38
- # 2. Remix Mode
39
- with gr.Tab("🎛 Remix Mode"):
40
- with gr.Row():
41
- with gr.Column():
42
- remix_input = gr.Audio(label="Upload Music Track", type="filepath")
43
- split_button = gr.Button("Split Into Drums, Bass, Vocals, etc.")
44
- with gr.Column():
45
- vocals_file = gr.File(label="Vocals")
46
- drums_file = gr.File(label="Drums")
47
- bass_file = gr.File(label="Bass")
48
- other_file = gr.File(label="Other")
49
- split_button.click(stem_split, inputs=remix_input, outputs=[vocals_file, drums_file, bass_file, other_file])
50
-
51
- # 3. AI Remastering
52
- with gr.Tab("🔮 AI Remastering"):
53
- remaster_input = gr.Audio(label="Upload Low-Quality Recording", type="filepath")
54
- remaster_output = gr.Audio(label="Studio-Grade Output", type="numpy")
55
- remaster_status = gr.Textbox(label="Status", value="Ready", interactive=False)
56
- remaster_btn = gr.Button("Remaster")
57
- remaster_btn.click(ai_remaster, inputs=remaster_input, outputs=remaster_output)
58
- remaster_btn.click(lambda _: "Done!", remaster_btn, remaster_status)
59
-
60
- # 4. Harmonic Saturation
61
- with gr.Tab("🧬 Harmonic Saturation"):
62
- saturation_in = gr.Audio(label="Upload Track", type="filepath")
63
- saturation_type = gr.Dropdown(choices=["Tube", "Tape", "Console", "Mix Bus"], label="Saturation Type", value="Tube")
64
- saturation_intensity = gr.Slider(minimum=0.1, maximum=1.0, value=0.2, label="Intensity")
65
- saturation_out = gr.Audio(label="Warm Output", type="numpy")
66
- sat_btn = gr.Button("Apply Saturation")
67
- sat_btn.click(harmonic_saturation,
68
- inputs=[saturation_in, saturation_type, saturation_intensity],
69
- outputs=saturation_out)
70
-
71
- # 5. Vocal Doubler / Harmonizer
72
- with gr.Tab("🎧 Vocal Doubler / Harmonizer"):
73
- vocal_in = gr.Audio(label="Upload Vocal Clip", type="filepath")
74
- vocal_out = gr.Audio(label="Doubled Output", type="numpy")
75
- vocal_status = gr.Textbox(label="Status", interactive=False)
76
- vocal_btn = gr.Button("Add Vocal Doubling / Harmony")
77
- vocal_btn.click(run_harmony, inputs=vocal_in, outputs=[vocal_out, vocal_status])
78
-
79
- # 6. Batch Processing
80
- with gr.Tab("🔊 Batch Processing"):
81
- batch_files = gr.File(label="Upload Multiple Files", file_count="multiple")
82
- batch_effects = gr.CheckboxGroup(choices=list({e for effs in preset_choices.values() for e in effs}), label="Apply Effects in Order")
83
- batch_isolate = gr.Checkbox(label="Isolate Vocals After Effects")
84
- batch_preset = gr.Dropdown(choices=preset_names, label="Select Preset", value=preset_names[0])
85
- batch_export = gr.Dropdown(choices=["MP3", "WAV"], label="Export Format", value="MP3")
86
- batch_btn = gr.Button("Process All Files")
87
- batch_zip = gr.File(label="Download All Processed Files (ZIP)")
88
- batch_status = gr.Textbox(label="Status", interactive=False)
89
- batch_btn.click(batch_process_audio,
90
- inputs=[batch_files, batch_effects, batch_isolate, batch_preset, batch_export],
91
- outputs=[batch_zip, batch_status])
92
-
93
- # 7. AI Auto-Tune
94
- with gr.Tab("🎤 AI Auto-Tune"):
95
- autotune_file = gr.File(label="Source Voice Clip")
96
- autotune_key = gr.Textbox(label="Target Key", value="C", lines=1)
97
- autotune_out = gr.Audio(label="Pitch-Corrected Output", type="numpy")
98
- autotune_btn = gr.Button("Apply Auto-Tune")
99
- autotune_btn.click(auto_tune_vocal, inputs=[autotune_file, autotune_key], outputs=autotune_out)
100
-
101
- # 8. Frequency Spectrum
102
- with gr.Tab("📊 Frequency Spectrum"):
103
- spectrum_in = gr.Audio(label="Upload Track", type="filepath")
104
- spectrum_out = gr.Image(label="Frequency Spectrum")
105
- spectrum_btn = gr.Button("Visualize Spectrum")
106
- spectrum_btn.click(visualize_spectrum, inputs=spectrum_in, outputs=spectrum_out)
107
-
108
- # 9. Loudness Graph
109
- with gr.Tab("📈 Loudness Graph"):
110
- loudness_in = gr.Audio(label="Upload Track", type="filepath")
111
- loudness_target = gr.Slider(minimum=-24, maximum=-6, value=-14, label="Target LUFS")
112
- loudness_out = gr.Audio(label="Normalized Output", type="numpy")
113
- loudness_btn = gr.Button("Match Loudness")
114
- loudness_btn.click(match_loudness, inputs=[loudness_in, loudness_target], outputs=loudness_out)
115
-
116
- # 10. Save/Load Project
117
- with gr.Tab("📁 Save/Load Project"):
118
- with gr.Row():
119
- with gr.Column():
120
- project_audio = gr.File(label="Original Audio")
121
- project_preset = gr.Dropdown(choices=preset_names, label="Used Preset", value=preset_names[0])
122
- project_effects = gr.CheckboxGroup(choices=list({e for effs in preset_choices.values() for e in effs}), label="Applied Effects")
123
- save_proj_btn = gr.Button("Save Project")
124
- project_file = gr.File(label="Project File (.aiproj)")
125
- with gr.Column():
126
- load_proj_file = gr.File(label="Load .aiproj File")
127
- loaded_preset = gr.Dropdown(choices=preset_names, label="Loaded Preset")
128
- loaded_effects = gr.CheckboxGroup(choices=list({e for effs in preset_choices.values() for e in effs}), label="Loaded Effects")
129
- load_proj_btn = gr.Button("Load Project")
130
- save_proj_btn.click(save_project, inputs=[project_audio, project_preset, project_effects], outputs=project_file)
131
- load_proj_btn.click(load_project, inputs=load_proj_file, outputs=[loaded_preset, loaded_effects])
132
-
133
- # 11. Prompt-Based Editing
134
- with gr.Tab("🧠 Prompt-Based Editing"):
135
- prompt_audio = gr.File(label="Upload Audio", file_types=[".wav", ".mp3"])
136
- prompt_text = gr.Textbox(label="Describe What You Want", lines=5)
137
- prompt_out = gr.Audio(label="Edited Output", type="numpy")
138
- prompt_btn = gr.Button("Process Prompt")
139
- prompt_btn.click(process_prompt, inputs=[prompt_audio, prompt_text], outputs=prompt_out)
140
-
141
- # 12. Custom EQ Editor
142
- with gr.Tab("🎛 Custom EQ Editor"):
143
- eq_audio = gr.Audio(label="Upload Track", type="filepath")
144
- eq_genre = gr.Dropdown(choices=list(eq_map.keys()), value="Pop", label="Genre")
145
- eq_output = gr.Audio(label="EQ-Enhanced Output", type="numpy")
146
- eq_btn = gr.Button("Apply EQ")
147
- eq_btn.click(auto_eq, inputs=[eq_audio, eq_genre], outputs=eq_output)
148
-
149
- # 13. A/B Compare
150
- with gr.Tab("🎯 A/B Compare"):
151
- ab_track1 = gr.Audio(label="Version A", type="filepath")
152
- ab_track2 = gr.Audio(label="Version B", type="filepath")
153
- ab_out1 = gr.Audio(label="Version A", type="filepath")
154
- ab_out2 = gr.Audio(label="Version B", type="filepath")
155
- ab_btn = gr.Button("Compare")
156
- ab_btn.click(compare_ab, inputs=[ab_track1, ab_track2], outputs=[ab_out1, ab_out2])
157
-
158
- # 14. Loop Playback
159
- with gr.Tab("🔁 Loop Playback"):
160
- loop_audio = gr.Audio(label="Upload Track", type="filepath")
161
- loop_start = gr.Slider(minimum=0, maximum=30000, step=100, value=5000, label="Start MS")
162
- loop_end = gr.Slider(minimum=100, maximum=30000, step=100, value=10000, label="End MS")
163
- loop_repeat = gr.Slider(minimum=1, maximum=10, value=2, label="Repeat Loops")
164
- loop_out = gr.Audio(label="Looped Output", type="numpy")
165
- loop_btn = gr.Button("Loop Section")
166
- loop_btn.click(loop_section, inputs=[loop_audio, loop_start, loop_end, loop_repeat], outputs=loop_out)
167
-
168
- # 15. Share Effect Chain Tab
169
- with gr.Tab("🔗 Share Effect Chain"):
170
- share_effects = gr.CheckboxGroup(choices=list({e for effs in preset_choices.values() for e in effs}), label="Select Effects")
171
- share_code = gr.Textbox(label="Share Code", lines=2)
172
- share_btn = gr.Button("Generate Share Code")
173
- share_btn.click(lambda x: json.dumps(sorted(x)), inputs=share_effects, outputs=share_code)
174
-
175
- # 16. Load Shared Chain Tab
176
- with gr.Tab("📥 Load Shared Chain"):
177
- load_code = gr.Textbox(label="Paste Shared Code", lines=2)
178
- loaded_effects = gr.CheckboxGroup(choices=list({e for effs in preset_choices.values() for e in effs}), label="Loaded Effects")
179
- load_code_btn = gr.Button("Load Effects")
180
- load_code_btn.click(lambda code: json.loads(code) if code else [], inputs=load_code, outputs=loaded_effects)
181
-
182
- # 17. Keyboard Shortcuts Tab
183
- with gr.Tab("⌨ Keyboard Shortcuts"):
184
- gr.Markdown("""
185
- ### Keyboard Controls
186
- - `Ctrl + Z`: Undo last effect
187
- - `Ctrl + Y`: Redo
188
- - `Spacebar`: Play/Stop playback
189
- - `Ctrl + S`: Save current session
190
- - `Ctrl + O`: Open session
191
- - `Ctrl + C`: Copy effect chain
192
- - `Ctrl + V`: Paste effect chain
193
- """)
194
-
195
- # 18. Vocal Formant Correction Tab
196
- with gr.Tab("🧑‍🎤 Vocal Formant Correction"):
197
- formant_audio = gr.Audio(label="Upload Vocal Track", type="filepath")
198
- formant_shift = gr.Slider(minimum=-2, maximum=2, value=1.0, step=0.1, label="Formant Shift")
199
- formant_output = gr.Audio(label="Natural-Sounding Vocal", type="numpy")
200
- formant_btn = gr.Button("Apply Correction")
201
- formant_btn.click(
202
- lambda audio, shift: array_to_audiosegment(
203
- librosa.effects.pitch_shift(
204
- np.array(AudioSegment.from_file(audio).get_array_of_samples()),
205
- sr=AudioSegment.from_file(audio).frame_rate,
206
- n_steps=shift
207
- ).astype(np.int16),
208
- AudioSegment.from_file(audio).frame_rate,
209
- channels=AudioSegment.from_file(audio).channels
210
- ),
211
- inputs=[formant_audio, formant_shift],
212
- outputs=formant_output
213
- )
214
 
215
- # 19. Voice Swap / Cloning Tab
216
- with gr.Tab("🔁 Voice Swap / Cloning"):
217
- source_voice = gr.File(label="Source Voice Clip")
218
- reference_voice = gr.File(label="Reference Voice")
219
- clone_output = gr.Audio(label="Converted Output", type="numpy")
220
- clone_btn = gr.Button("Clone Voice")
221
-
222
- def clone_func(source, ref):
223
- s = AudioSegment.from_file(source.name)
224
- r = AudioSegment.from_file(ref.name)
225
- mixed = s.overlay(r - 10)
226
- tmp = save_audiosegment_to_temp(mixed, ".wav")
227
- return load_audiofile_to_numpy(tmp)
228
-
229
- clone_btn.click(clone_func, inputs=[source_voice, reference_voice], outputs=clone_output)
230
-
231
- # 20. DAW Template Export Tab
232
- with gr.Tab("🎛 DAW Template Export"):
233
- daw_stems = gr.File(label="Upload Stems", file_count="multiple")
234
- daw_output = gr.File(label="DAW Template (.json/.als/.flp)")
235
- daw_btn = gr.Button("Generate Template")
236
-
237
- def generate_template(stems):
238
- template = {
239
- "format": "Ableton Live",
240
- "stems": [os.path.basename(s.name) for s in stems],
241
- "effects": ["Reverb", "EQ", "Compression"],
242
- "tempo": 128,
243
- "title": "Studio Pulse Project"
244
- }
245
- out_path = os.path.join(tempfile.gettempdir(), "ableton_template.json")
246
- with open(out_path, "w") as f:
247
- json.dump(template, f, indent=2)
248
- return out_path
249
-
250
- daw_btn.click(generate_template, inputs=daw_stems, outputs=daw_output)
251
-
252
- # 21. Export Full Mix ZIP Tab
253
- with gr.Tab("📁 Export Full Mix ZIP"):
254
- stems_files = gr.File(label="Stems", file_count="multiple")
255
- final_mix_file = gr.File(label="Final Mix")
256
- full_zip_output = gr.File(label="Full Mix Archive (.zip)")
257
- export_zip_btn = gr.Button("Export ZIP")
258
-
259
- def export_zip(stems, final_mix):
260
- zip_path = os.path.join(tempfile.gettempdir(), "full_export.zip")
261
- with zipfile.ZipFile(zip_path, "w") as zipf:
262
- for i, stem in enumerate(stems):
263
- zipf.write(stem.name, f"stem_{i}.wav")
264
- zipf.write(final_mix.name, "final_mix.wav")
265
- return zip_path
266
-
267
- export_zip_btn.click(export_zip, inputs=[stems_files, final_mix_file], outputs=full_zip_output)
268
 
269
  demo.launch()
 
1
+ import gradio as gr
2
+ from pydub import AudioSegment
3
+ import numpy as np
4
+ import tempfile
5
+ import os
6
+ import noisereduce as nr
7
+ import torch
8
+ from demucs import pretrained
9
+ from demucs.apply import apply_model
10
+ import torchaudio
11
+ from pathlib import Path
12
+ import matplotlib.pyplot as plt
13
+ from io import BytesIO
14
+ from PIL import Image
15
+ import zipfile
16
+ import datetime
17
+ import librosa
18
+ import warnings
19
+ import json
20
+ import pickle
21
+ import soundfile as sf
22
+
23
+ warnings.filterwarnings("ignore")
24
+
25
+ ### Helper Functions ###
26
+
27
+ def audiosegment_to_array(audio):
28
+ return np.array(audio.get_array_of_samples()), audio.frame_rate
29
+
30
+ def array_to_audiosegment(samples, frame_rate, channels=1):
31
+ return AudioSegment(
32
+ samples.tobytes(),
33
+ frame_rate=int(frame_rate),
34
+ sample_width=samples.dtype.itemsize,
35
+ channels=channels
36
+ )
37
+
38
+ def save_audiosegment_to_temp(audio: AudioSegment, suffix=".wav"):
39
+ with tempfile.NamedTemporaryFile(delete=False, suffix=suffix) as f:
40
+ audio.export(f.name, format=suffix.lstrip('.'))
41
+ return f.name
42
+
43
+ def load_audiofile_to_numpy(path):
44
+ samples, sr = sf.read(path, dtype="int16")
45
+ if samples.ndim > 1 and samples.shape[1] > 2:
46
+ samples = samples[:, :2]
47
+ return samples, sr
48
+
49
+ def show_waveform(audio_file):
50
+ try:
51
+ audio = AudioSegment.from_file(audio_file)
52
+ samples = np.array(audio.get_array_of_samples())
53
+ plt.figure(figsize=(10,2))
54
+ plt.plot(samples[:10000], color="skyblue")
55
+ plt.axis('off')
56
+ buf = BytesIO()
57
+ plt.savefig(buf, format='png', bbox_inches='tight')
58
+ plt.close()
59
+ buf.seek(0)
60
+ return Image.open(buf)
61
+ except Exception:
62
+ return None
63
+
64
+ ### Effects ###
65
+
66
+ def apply_normalize(audio): return audio.normalize()
67
+
68
+ def apply_noise_reduction(audio):
69
+ samples, sr = audiosegment_to_array(audio)
70
+ reduced = nr.reduce_noise(y=samples, sr=sr)
71
+ return array_to_audiosegment(reduced, sr, audio.channels)
72
+
73
+ def apply_compression(audio): return audio.compress_dynamic_range()
74
+
75
+ def apply_reverb(audio):
76
+ reverb = audio - 10
77
+ return audio.overlay(reverb, position=1000)
78
+
79
+ def apply_pitch_shift(audio, semitones=-2):
80
+ new_fr = int(audio.frame_rate * (2 ** (semitones / 12)))
81
+ return audio._spawn(audio.raw_data, overrides={"frame_rate": new_fr}).set_frame_rate(audio.frame_rate)
82
+
83
+ def apply_echo(audio, delay_ms=500, decay=0.5):
84
+ echo = audio - 10
85
+ return audio.overlay(echo, position=delay_ms)
86
+
87
+ def apply_stereo_widen(audio, pan_amount=0.3):
88
+ left = audio.pan(-pan_amount)
89
+ right = audio.pan(pan_amount)
90
+ return AudioSegment.from_mono_audiosegments(left, right)
91
+
92
+ def apply_bass_boost(audio, gain=10): return audio.low_pass_filter(100).apply_gain(gain)
93
+
94
+ def apply_treble_boost(audio, gain=10): return audio.high_pass_filter(4000).apply_gain(gain)
95
+
96
+ def apply_limiter(audio, limit_dB=-1):
97
+ limiter = audio._spawn(audio.raw_data, overrides={"frame_rate": audio.frame_rate})
98
+ return limiter.apply_gain(limit_dB)
99
+
100
+ def apply_auto_gain(audio, target_dB=-20):
101
+ change = target_dB - audio.dBFS
102
+ return audio.apply_gain(change)
103
+
104
+ def apply_vocal_distortion(audio, intensity=0.3):
105
+ samples = np.array(audio.get_array_of_samples()).astype(np.float32)
106
+ distorted = samples + intensity * np.sin(samples * 2 * np.pi / 32768)
107
+ return array_to_audiosegment(distorted.astype(np.int16), audio.frame_rate, audio.channels)
108
+
109
+ def apply_harmony(audio, shift_semitones=4):
110
+ shifted_up = apply_pitch_shift(audio, shift_semitones)
111
+ shifted_down = apply_pitch_shift(audio, -shift_semitones)
112
+ return audio.overlay(shifted_up).overlay(shifted_down)
113
+
114
+ def apply_stage_mode(audio):
115
+ processed = apply_reverb(audio)
116
+ processed = apply_bass_boost(processed, gain=6)
117
+ return apply_limiter(processed, limit_dB=-2)
118
+
119
+ def apply_bitcrush(audio, bit_depth=8):
120
+ samples = np.array(audio.get_array_of_samples())
121
+ max_value = 2 ** bit_depth - 1
122
+ downsampled = np.round(samples / (32768 / max_value)).astype(np.int16)
123
+ return array_to_audiosegment(downsampled, audio.frame_rate // 2, audio.channels)
124
+
125
+ ### Presets ###
126
+
127
+ preset_choices = {
128
+ "Default": [],
129
+ "Clean Podcast": ["Noise Reduction", "Normalize"],
130
+ "Podcast Mastered": ["Noise Reduction", "Normalize", "Compress Dynamic Range"],
131
+ "Radio Ready": ["Bass Boost", "Treble Boost", "Limiter"],
132
+ "Music Production": ["Reverb", "Stereo Widening", "Pitch Shift"],
133
+ "ASMR Creator": ["Noise Gate", "Auto Gain", "Low-Pass Filter"],
134
+ "Voiceover Pro": ["Vocal Isolation", "TTS", "EQ Match"],
135
+ "8-bit Retro": ["Bitcrusher", "Echo", "Mono Downmix"],
136
+ "🎙 Clean Vocal": ["Noise Reduction", "Normalize", "High Pass Filter (80Hz)"],
137
+ "🧪 Vocal Distortion": ["Vocal Distortion", "Reverb", "Compress Dynamic Range"],
138
+ "🎶 Singer's Harmony": ["Harmony", "Stereo Widening", "Pitch Shift"],
139
+ "🌫 ASMR Vocal": ["Auto Gain", "Low-Pass Filter (3000Hz)", "Noise Gate"],
140
+ "🎼 Stage Mode": ["Reverb", "Bass Boost", "Limiter"],
141
+ }
142
+
143
+ preset_names = list(preset_choices.keys())
144
+
145
+ ### Main processing ###
146
+
147
+ def process_audio(audio_file, selected_effects, isolate_vocals, preset_name, export_format):
148
+ try:
149
+ audio = AudioSegment.from_file(audio_file)
150
+ effect_map = {
151
+ "Noise Reduction": apply_noise_reduction,
152
+ "Compress Dynamic Range": apply_compression,
153
+ "Add Reverb": apply_reverb,
154
+ "Pitch Shift": apply_pitch_shift,
155
+ "Echo": apply_echo,
156
+ "Stereo Widening": apply_stereo_widen,
157
+ "Bass Boost": apply_bass_boost,
158
+ "Treble Boost": apply_treble_boost,
159
+ "Normalize": apply_normalize,
160
+ "Limiter": lambda x: apply_limiter(x, limit_dB=-1),
161
+ "Auto Gain": lambda x: apply_auto_gain(x, target_dB=-20),
162
+ "Vocal Distortion": apply_vocal_distortion,
163
+ "Stage Mode": apply_stage_mode,
164
+ "Harmony": apply_harmony,
165
+ "Bitcrusher": apply_bitcrush,
166
+ }
167
+ for effect in selected_effects:
168
+ if effect in effect_map:
169
+ audio = effect_map[effect](audio)
170
+ if isolate_vocals:
171
+ temp_path = save_audiosegment_to_temp(audio, suffix=".wav")
172
+ vocal_path = apply_vocal_isolation(temp_path)
173
+ audio = AudioSegment.from_file(vocal_path)
174
+ output_path = save_audiosegment_to_temp(audio, suffix='.' + export_format.lower())
175
+ samples, sr = load_audiofile_to_numpy(output_path)
176
+ waveform = show_waveform(output_path)
177
+ session_log = json.dumps({
178
+ "timestamp": str(datetime.datetime.now()),
179
+ "filename": os.path.basename(audio_file),
180
+ "effects_applied": selected_effects,
181
+ "isolate_vocals": isolate_vocals,
182
+ "export_format": export_format,
183
+ "detected_genre": "Unknown"
184
+ }, indent=2)
185
+ return (samples, sr), waveform, session_log, "Unknown", "🎉 Done!"
186
+ except Exception as e:
187
+ return None, None, f"Error: {e}", "", f"Error: {e}"
188
+
189
+ ### Other necessary functions (batch, AI remaster...) would follow similar patterns.
190
+
191
+ # ===================================================
192
+ # Now, the Gradio UI:
193
+ # Paste this after all function definitions above
194
+ # ===================================================
195
+
196
  with gr.Blocks() as demo:
197
  gr.HTML('<h3 style="text-align:center;">Where Your Audio Meets Intelligence</h3>')
198
  gr.Markdown('### Upload, edit, export — powered by AI!')
199
 
 
200
  with gr.Tab("🎵 Single File Studio"):
201
  with gr.Row():
202
  with gr.Column():
203
  input_audio = gr.Audio(label="Upload Audio", type="filepath")
204
+ effect_checkbox = gr.CheckboxGroup(choices=list({e for effects in preset_choices.values() for e in effects}), label="Apply Effects in Order")
205
+ preset_dropdown = gr.Dropdown(choices=preset_names, label="Select Preset")
 
 
 
206
  export_format = gr.Dropdown(choices=["WAV", "MP3"], label="Export Format", value="WAV")
207
  isolate_vocals = gr.Checkbox(label="Isolate Vocals After Effects")
208
  process_btn = gr.Button("Process Audio")
209
+
210
  with gr.Column():
211
+ processed_audio = gr.Audio(label="Processed Audio", type="numpy")
212
+ waveform_image = gr.Image(label="Waveform Preview")
213
+ session_log = gr.Textbox(label="Session Log", lines=6)
214
+ detected_genre = gr.Textbox(label="Detected Genre")
215
+ status = gr.Textbox(label="Status", lines=1, value="Ready")
216
+
217
+ def update_effects(preset):
218
+ return preset_choices.get(preset, [])
219
+
220
+ preset_dropdown.change(update_effects, inputs=preset_dropdown, outputs=effect_checkbox)
221
+
222
+ def run_processing(audio, effects, isolate, preset, fmt):
223
  effs = preset_choices.get(preset, []) if preset in preset_choices else effects
224
+ return process_audio(audio, effs, isolate, preset, fmt)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
225
 
226
+ process_btn.click(run_processing,
227
+ inputs=[input_audio, effect_checkbox, isolate_vocals, preset_dropdown, export_format],
228
+ outputs=[processed_audio, waveform_image, session_log, detected_genre, status]
229
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
230
 
231
  demo.launch()