Vgjkmhf commited on
Commit
4b76478
·
verified ·
1 Parent(s): 92f6db2

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +215 -92
app.py CHANGED
@@ -1,146 +1,269 @@
1
  import os
2
  import sys
3
  import time
4
- import inspect
5
  import traceback
 
 
 
 
6
  import numpy as np
7
  import soundfile as sf
8
  import librosa
9
  import gradio as gr
10
- from scipy.signal import iirpeak, lfilter
 
 
 
 
 
 
11
 
12
- # 1. Setup
13
  try:
14
  import imageio_ffmpeg
15
  import static_ffmpeg
16
  from rvc_python.infer import RVCInference
17
- static_ffmpeg.add_paths()
18
- ffmpeg_path = imageio_ffmpeg.get_ffmpeg_exe()
19
- os.environ["PATH"] += os.pathsep + os.path.dirname(ffmpeg_path)
20
- print("✅ System Ready")
21
  except ImportError as e:
22
- print(f"❌ Import Error: {e}")
 
23
  sys.exit(1)
24
 
25
- TEMP_DIR = "/tmp/rvc_studio"
 
 
 
 
 
 
 
 
 
26
  os.makedirs(TEMP_DIR, exist_ok=True)
27
  os.environ["TEMP"] = TEMP_DIR
 
28
 
29
- # 2. DSP Functions
30
- def anti_muffle_filter(y, sr):
31
- try:
32
- b, a = iirpeak(600, Q=1.5, fs=sr, ftype='notch')
33
- return lfilter(b, a, y)
34
- except: return y
 
35
 
36
- def clarity_boost(y, sr):
 
 
 
 
 
 
37
  try:
38
- b, a = iirpeak(8000, Q=0.7, fs=sr, ftype='peak')
39
- boosted = lfilter(b, a, y)
40
- return (y * 0.7) + (boosted * 0.3)
41
- except: return y
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
42
 
43
  def preprocess_audio(input_path):
44
  try:
45
- y, sr = librosa.load(input_path, sr=None, mono=True)
46
- y = librosa.util.normalize(y) * 0.90
47
- y = anti_muffle_filter(y, sr)
 
 
 
 
48
  processed_path = os.path.join(TEMP_DIR, "preprocessed.wav")
49
  sf.write(processed_path, y, sr)
50
- return processed_path, f"✅ Preprocess Done (SR: {sr}Hz)"
51
  except Exception as e:
52
- return input_path, f"⚠️ Preprocess Warning: {e}"
53
 
54
- def postprocess_audio(input_path):
 
55
  try:
56
- y, sr = librosa.load(input_path, sr=None, mono=True)
57
- y = clarity_boost(y, sr)
 
 
 
 
58
  y = librosa.util.normalize(y) * 0.95
59
- post_path = os.path.join(TEMP_DIR, "postprocessed.wav")
60
- sf.write(post_path, y, sr)
61
- return post_path, "✅ Postprocess Done"
62
- except Exception as e:
63
- return input_path, f"⚠️ Postprocess Warning: {e}"
 
 
 
 
 
 
 
 
 
 
 
 
 
64
 
65
- # 3. Pipeline
66
  def rvc_process_pipeline(
67
- audio_path, model_file, index_file, pitch_change, f0_method,
68
- index_rate, protect_val, filter_radius, resample_sr, envelope_mix, hop_length
 
 
 
69
  ):
70
- if not audio_path or not model_file:
71
- return None, "❌ Input missing"
72
 
 
 
 
73
  try:
74
- clean_audio, log1 = preprocess_audio(audio_path)
 
 
75
 
76
- rvc = RVCInference(device="cpu")
77
- rvc.load_model(model_file.name)
78
- rvc_out_path = os.path.join(TEMP_DIR, "rvc_output.wav")
79
- if os.path.exists(rvc_out_path): os.remove(rvc_out_path)
80
 
81
- sig = inspect.signature(rvc.infer_file)
82
- params = sig.parameters
83
- kwargs = {"input_path": clean_audio, "output_path": rvc_out_path}
 
 
 
84
 
85
- if "pitch" in params: kwargs["pitch"] = int(pitch_change)
86
- elif "f0_up_key" in params: kwargs["f0_up_key"] = int(pitch_change)
87
- if "method" in params: kwargs["method"] = f0_method
88
- elif "f0_method" in params: kwargs["f0_method"] = f0_method
89
- if "index_path" in params and index_file: kwargs["index_path"] = index_file.name
90
- if "index_rate" in params: kwargs["index_rate"] = float(index_rate)
91
- if "protect" in params: kwargs["protect"] = float(protect_val)
92
- if "filter_radius" in params: kwargs["filter_radius"] = int(filter_radius)
93
- if "resample_sr" in params: kwargs["resample_sr"] = int(resample_sr)
94
- if "rms_mix_rate" in params: kwargs["rms_mix_rate"] = float(envelope_mix)
95
- if "hop_length" in params: kwargs["hop_length"] = int(hop_length)
 
 
 
96
 
97
- print(f"Running: {kwargs}")
98
- rvc.infer_file(**kwargs)
99
- log2 = "✅ RVC Done"
 
100
 
101
- final_output, log3 = postprocess_audio(rvc_out_path)
 
 
 
 
 
 
102
 
103
- # --- اصلاح خط مشکل‌دار ---
104
- full_log = "
105
- ".join([str(log1), str(log2), str(log3)])
106
 
107
- return final_output, full_log
 
 
 
 
108
 
 
 
 
 
 
 
109
  except Exception as e:
110
- err = f"❌ Error: {traceback.format_exc()}"
111
- print(err)
112
- return None, err
 
 
 
 
 
 
 
113
 
114
- # 4. UI
115
- with gr.Blocks(title="RVC Studio Pro", theme=gr.themes.Soft()) as demo:
116
- gr.Markdown("# 🎙️ RVC Studio Pro")
117
 
118
  with gr.Row():
119
- with gr.Column(scale=1):
120
- audio_in = gr.Audio(label="Input", type="filepath")
121
  with gr.Row():
122
- model_in = gr.File(label="Model", file_types=[".pth"])
123
- index_in = gr.File(label="Index", file_types=[".index"])
124
 
125
- pitch = gr.Slider(-24, 24, value=0, step=1, label="Pitch")
126
- method = gr.Dropdown(["rmvpe", "harvest", "crepe", "pm"], value="harvest", label="Algo")
127
- btn = gr.Button(" Start", variant="primary")
 
 
 
 
128
 
129
- with gr.Column(scale=1):
130
- audio_out = gr.Audio(label="Output")
131
- status = gr.Textbox(label="Logs", lines=5)
132
 
133
- with gr.Accordion("Settings", open=True):
134
- with gr.Tab("Quality"):
135
- index_rate = gr.Slider(0, 1, value=0.3, label="Index Rate")
136
- protect = gr.Slider(0, 0.5, value=0.45, label="Protect")
137
- filter_radius = gr.Slider(0, 7, value=3, label="Filter Radius")
138
- with gr.Tab("Clarity"):
139
- envelope_mix = gr.Slider(0, 1, value=0.25, label="Vol Mix")
140
- hop_length = gr.Slider(32, 256, value=64, step=32, label="Hop Length")
141
- resample_sr = gr.Slider(0, 48000, value=40000, step=8000, label="Resample SR")
142
-
143
- btn.click(rvc_process_pipeline, inputs=[audio_in, model_in, index_in, pitch, method, index_rate, protect, filter_radius, resample_sr, envelope_mix, hop_length], outputs=[audio_out, status])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
144
 
145
  if __name__ == "__main__":
146
  demo.queue().launch(server_name="0.0.0.0", server_port=7860)
 
1
  import os
2
  import sys
3
  import time
 
4
  import traceback
5
+ import inspect
6
+ import logging
7
+ import shutil
8
+ import subprocess
9
  import numpy as np
10
  import soundfile as sf
11
  import librosa
12
  import gradio as gr
13
+ import scipy.signal as signal # اضافه شده برای پردازش سیگنال حرفه‌ای
14
+ from datetime import datetime
15
+
16
+ # ==========================================
17
+ # 1. تنظیمات اولیه و کتابخانه‌ها
18
+ # ==========================================
19
+ print(">>> در حال راه‌اندازی سیستم RVC Pro Max...")
20
 
 
21
  try:
22
  import imageio_ffmpeg
23
  import static_ffmpeg
24
  from rvc_python.infer import RVCInference
25
+ print("✅ کتابخانه‌های RVC با موفقیت بارگذاری شدند.")
 
 
 
26
  except ImportError as e:
27
+ print(f"❌ خطای بحرانی در ایمپورت: {e}")
28
+ print("لطفاً requirements.txt را بررسی کنید.")
29
  sys.exit(1)
30
 
31
+ # تنظیم مسیر FFmpeg
32
+ try:
33
+ static_ffmpeg.add_paths()
34
+ ffmpeg_exe = imageio_ffmpeg.get_ffmpeg_exe()
35
+ os.environ["PATH"] += os.pathsep + os.path.dirname(ffmpeg_exe)
36
+ print(f"✅ FFmpeg یافت شد: {ffmpeg_exe}")
37
+ except Exception as e:
38
+ print(f"⚠️ هشدار FFmpeg: {e}")
39
+
40
+ TEMP_DIR = "/tmp/rvc_temp"
41
  os.makedirs(TEMP_DIR, exist_ok=True)
42
  os.environ["TEMP"] = TEMP_DIR
43
+ os.environ["TMPDIR"] = TEMP_DIR
44
 
45
+ # ==========================================
46
+ # 2. توابع پردازش صدا (Audio DSP)
47
+ # ==========================================
48
+
49
+ def log_message(message):
50
+ timestamp = datetime.now().strftime("%H:%M:%S")
51
+ return f"[{timestamp}] {message}"
52
 
53
+ def apply_clarity_eq(y, sr):
54
+ """
55
+ اعمال EQ برای رفع تودماغی و شفاف‌سازی صدا
56
+ 1. Low-Cut: حذف هام (Hum) زیر 60Hz
57
+ 2. Mid-Cut: کاهش فرکانس‌های تودماغی (800Hz - 1.2kHz)
58
+ 3. High-Boost: افزایش فرکانس‌های شفاف (Air) بالای 6kHz
59
+ """
60
  try:
61
+ # 1. High-pass filter (حذف نویز خیلی بم)
62
+ sos_hp = signal.butter(4, 60, 'hp', fs=sr, output='sos')
63
+ y = signal.sosfilt(sos_hp, y)
64
+
65
+ # 2. Notch/Bell filter برای کاهش تودماغی (حدود 1000Hz)
66
+ # استفاده از فیلتر Peaking EQ معکوس
67
+ b, a = signal.iirpeak(1000, 1.0, fs=sr)
68
+ # اعمال معکوس (کاهش دامنه در این فرکانس) - پیاده‌سازی ساده‌تر با فیلتر باترورث بند-استاپ نرم
69
+ # اما اینجا یک ترفند ساده‌تر می‌زنیم: کاهش ملایم میدرنج
70
+ # یک فیلتر ساده برای کاهش ناحیه 1k
71
+ sos_mid = signal.butter(2, [800, 1200], 'bandstop', fs=sr, output='sos')
72
+ # میکس کردن سیگنال فیلتر شده با اصلی (Dry/Wet) برای اینکه صدا توخالی نشود
73
+ y_filtered = signal.sosfilt(sos_mid, y)
74
+ y = (y * 0.7) + (y_filtered * 0.3) # تاثیر ملایم
75
+
76
+ # 3. High Shelf Boost (شفافیت)
77
+ # بوست کردن فرکانس‌های بالای 5000 هرتز
78
+ sos_high = signal.butter(2, 5000, 'hp', fs=sr, output='sos')
79
+ y_high = signal.sosfilt(sos_high, y)
80
+ y = y + (y_high * 0.15) # افزودن 15% فرکانس بالا به سیگنال اصلی
81
+
82
+ return y
83
+ except Exception as e:
84
+ print(f"EQ Error: {e}")
85
+ return y
86
 
87
  def preprocess_audio(input_path):
88
  try:
89
+ y, sr = librosa.load(input_path, sr=None)
90
+ if y.ndim > 1:
91
+ y = librosa.to_mono(y)
92
+
93
+ # نرمال‌سازی استاندارد
94
+ y = librosa.util.normalize(y)
95
+
96
  processed_path = os.path.join(TEMP_DIR, "preprocessed.wav")
97
  sf.write(processed_path, y, sr)
98
+ return processed_path, f"✅ صدا پیش‌پردازش شد (SR: {sr}Hz)"
99
  except Exception as e:
100
+ return input_path, f"⚠️ پیش‌پردازش ناموفق: {e}"
101
 
102
+ def post_process_audio(input_path, clarity_boost=True):
103
+ """پردازش نهایی برای کیفیت استودیویی"""
104
  try:
105
+ y, sr = librosa.load(input_path, sr=None)
106
+
107
+ if clarity_boost:
108
+ y = apply_clarity_eq(y, sr)
109
+
110
+ # نرمال‌سازی نهایی (جلوگیری از Clipping)
111
  y = librosa.util.normalize(y) * 0.95
112
+
113
+ output_path = input_path.replace(".wav", "_final.wav")
114
+ sf.write(output_path, y, sr)
115
+ return output_path
116
+ except Exception:
117
+ return input_path
118
+
119
+ def cleanup_temp():
120
+ try:
121
+ if os.path.exists(TEMP_DIR):
122
+ shutil.rmtree(TEMP_DIR)
123
+ os.makedirs(TEMP_DIR)
124
+ except Exception:
125
+ pass
126
+
127
+ # ==========================================
128
+ # 3. موتور تبدیل صدا (RVC Engine)
129
+ # ==========================================
130
 
 
131
  def rvc_process_pipeline(
132
+ audio_path, model_file, index_file,
133
+ pitch_change, f0_method, index_rate,
134
+ protect_val, filter_radius, resample_sr,
135
+ envelope_mix, hop_length,
136
+ enable_clarity
137
  ):
138
+ logs = []
139
+ logs.append(log_message("🚀 شروع عملیات تبدیل..."))
140
 
141
+ if not audio_path: return None, "❌ فایل صوتی انتخاب نشده است."
142
+ if not model_file: return None, "❌ فایل مدل انتخاب نشده است."
143
+
144
  try:
145
+ cleanup_temp()
146
+ model_path = model_file.name
147
+ index_path = index_file.name if index_file else None
148
 
149
+ # 1. پیش‌پردازش
150
+ clean_audio, msg = preprocess_audio(audio_path)
151
+ logs.append(log_message(msg))
 
152
 
153
+ # 2. لود مدل
154
+ logs.append(log_message(f"📂 مدل: {os.path.basename(model_path)}"))
155
+ rvc = RVCInference(device="cpu") # اگر GPU دارید "cuda" بگذارید
156
+ rvc.load_model(model_path)
157
+
158
+ output_temp = os.path.join(TEMP_DIR, f"rvc_out_{int(time.time())}.wav")
159
 
160
+ # 3. تنظیم پارامترها (بهینه‌سازی شده برای کیفیت)
161
+ kwargs = {
162
+ "input_path": clean_audio,
163
+ "output_path": output_temp,
164
+ "pitch": int(pitch_change),
165
+ "method": f0_method,
166
+ "index_path": index_path,
167
+ "index_rate": float(index_rate),
168
+ "protect": float(protect_val),
169
+ "filter_radius": int(filter_radius),
170
+ "resample_sr": int(resample_sr),
171
+ "rms_mix_rate": float(envelope_mix),
172
+ "hop_length": int(hop_length)
173
+ }
174
 
175
+ # بررسی پارامترهای معتبر تابع (برای جلوگیری از ارور نسخه‌های قدیمی)
176
+ sig = inspect.signature(rvc.infer_file)
177
+ valid_keys = sig.parameters.keys()
178
+ filtered_kwargs = {k: v for k, v in kwargs.items() if k in valid_keys or k == "pitch" or k == "method"}
179
 
180
+ # هندل کردن تغییر نام پارامترها در نسخه‌های مختلف
181
+ if "f0_up_key" in valid_keys and "pitch" in filtered_kwargs:
182
+ filtered_kwargs["f0_up_key"] = filtered_kwargs.pop("pitch")
183
+ if "f0_method" in valid_keys and "method" in filtered_kwargs:
184
+ filtered_kwargs["f0_method"] = filtered_kwargs.pop("method")
185
+
186
+ logs.append(log_message(f"⚙️ متد: {f0_method} | شفاف‌سازی: {'فعال' if enable_clarity else 'غیرفعال'}"))
187
 
188
+ # 4. اجرای تبدیل
189
+ start_time = time.time()
190
+ rvc.infer_file(**filtered_kwargs)
191
 
192
+ # 5. پس‌پردازش (شفاف‌سازی)
193
+ final_output = output_temp
194
+ if enable_clarity:
195
+ logs.append(log_message("✨ در حال اعمال فیلتر شفاف‌سازی و رفع تودماغی..."))
196
+ final_output = post_process_audio(output_temp, clarity_boost=True)
197
 
198
+ duration = time.time() - start_time
199
+ logs.append(log_message(f"✅ تمام شد! ({duration:.2f}s)"))
200
+
201
+ return final_output, "
202
+ ".join(logs)
203
+
204
  except Exception as e:
205
+ return None, f"❌ خطا: {traceback.format_exc()}"
206
+
207
+ # ==========================================
208
+ # 4. رابط کاربری (Gradio)
209
+ # ==========================================
210
+
211
+ custom_css = """
212
+ #run_btn {background: linear-gradient(90deg, #FF5722 0%, #FF8A65 100%); color: white; border: none;}
213
+ .gradio-container {font-family: 'Tahoma', sans-serif;}
214
+ """
215
 
216
+ with gr.Blocks(title="RVC Pro Persian", theme=gr.themes.Soft(), css=custom_css) as demo:
217
+ gr.Markdown("## 🎙️ RVC Pro: مبدل صدای حرفه‌ای (رفع گنگی و تودماغی)")
 
218
 
219
  with gr.Row():
220
+ with gr.Column():
221
+ audio_input = gr.Audio(label="ورودی صدا", type="filepath")
222
  with gr.Row():
223
+ model_input = gr.File(label="مدل (.pth)", file_types=[".pth"])
224
+ index_input = gr.File(label="ایندکس (.index)", file_types=[".index"])
225
 
226
+ # تمام الگوریتم‌ها
227
+ algo_dropdown = gr.Dropdown(
228
+ choices=["rmvpe", "fcpe", "crepe", "harvest", "pm"],
229
+ value="rmvpe",
230
+ label="الگوریتم (RMVPE پیشنهاد می‌شود)",
231
+ info="RMVPE: بهترین کیفیت | PM: سریع | Harvest: برای نت‌های پایین"
232
+ )
233
 
234
+ pitch_slider = gr.Slider(-24, 24, value=0, step=1, label="تغییر گام (Pitch)")
 
 
235
 
236
+ btn_run = gr.Button("🚀 تبدیل صدا", elem_id="run_btn", variant="primary")
237
+
238
+ with gr.Column():
239
+ with gr.Accordion("تنظیمات کیفیت (رفع نویز و خش)", open=True):
240
+ enable_clarity = gr.Checkbox(value=True, label=" فعال‌سازی شفاف‌کننده صدا (رفع تودماغی)")
241
+
242
+ with gr.Row():
243
+ index_rate = gr.Slider(0, 1, value=0.4, step=0.05, label="تاثیر ایندکس", info="بیشتر = شبیه‌تر به مدل (اما شاید نویزی)")
244
+ envelope_mix = gr.Slider(0, 1, value=0.25, step=0.05, label="میکس حجم (Volume Mix)", info="کمتر = شفاف‌تر (حجم مد��)")
245
+
246
+ with gr.Row():
247
+ protect_val = gr.Slider(0, 0.5, value=0.33, step=0.01, label="محافظت (Protect)", info="0.33 استاندارد است")
248
+ filter_radius = gr.Slider(0, 7, value=3, step=1, label="فیلتر نرم‌کننده", info="3 = متعادل")
249
+
250
+ with gr.Row():
251
+ resample_sr = gr.Slider(0, 48000, value=0, step=1000, label="ری‌سمپل", info="0 = بدون تغییر (پیشنهادی)")
252
+ hop_len = gr.Slider(1, 512, value=128, step=1, label="Hop Length", info="128 استاندارد")
253
+
254
+ output_audio = gr.Audio(label="خروجی نهایی", type="filepath")
255
+ logs = gr.Textbox(label="گزارش", lines=5)
256
+
257
+ btn_run.click(
258
+ rvc_process_pipeline,
259
+ inputs=[
260
+ audio_input, model_input, index_input,
261
+ pitch_slider, algo_dropdown, index_rate,
262
+ protect_val, filter_radius, resample_sr,
263
+ envelope_mix, hop_len, enable_clarity
264
+ ],
265
+ outputs=[output_audio, logs]
266
+ )
267
 
268
  if __name__ == "__main__":
269
  demo.queue().launch(server_name="0.0.0.0", server_port=7860)