Commit ·
5b4a1b3
1
Parent(s): e46266f
Add inference mode selector: Full / MDX Only / RVC Only
Browse files- Added 'inference_mode' parameter to song_cover_pipeline and process_song
with three options:
'full' - MDX separation + RVC voice conversion (default, existing behavior)
'mdx' - MDX separation only, skip RVC (outputs separated vocals)
'rvc' - RVC voice conversion only, skip MDX (uses input as vocals)
- Added Radio dropdown in webui.py for inference mode selection
- Voice model dropdown hides when MDX Only mode is selected
- Added --mode CLI argument with choices: full, mdx, rvc
- --rvc-dirname is no longer required for mdx mode
- MDX-only outputs: separated vocals without effects/mixing
- RVC-only outputs: converted vocals with effects, no instrumental mixing
- Full mode: unchanged (MDX + RVC + effects + mixing)
- src/main.py +103 -20
- src/webui.py +22 -3
src/main.py
CHANGED
|
@@ -313,29 +313,64 @@ def combine_audio(audio_paths, output_path, main_gain, backup_gain, inst_gain, o
|
|
| 313 |
def process_song(
|
| 314 |
song_dir, song_input, mdx_model_params, song_id, is_webui, input_type, progress,
|
| 315 |
keep_files, pitch_change, pitch_change_all, voice_model, index_rate, filter_radius,
|
| 316 |
-
volume_envelope, protect, f0_method, hop_length, output_format, keep_orig, orig_song_path
|
|
|
|
| 317 |
):
|
|
|
|
|
|
|
| 318 |
|
| 319 |
-
|
| 320 |
-
|
| 321 |
-
|
| 322 |
-
|
| 323 |
-
|
| 324 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 325 |
|
| 326 |
-
|
| 327 |
-
|
|
|
|
|
|
|
|
|
|
| 328 |
orig_song_path, vocals_path, instrumentals_path, main_vocals_path, backup_vocals_path, main_vocals_dereverb_path = preprocess_song(song_input, mdx_model_params, song_id, is_webui, input_type, progress, keep_orig, orig_song_path)
|
| 329 |
else:
|
| 330 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 331 |
|
| 332 |
pitch_change = pitch_change * 12 + pitch_change_all
|
| 333 |
ai_vocals_path = os.path.join(song_dir, f'{os.path.splitext(os.path.basename(orig_song_path))[0]}_{voice_model}_p{pitch_change}_i{index_rate}_fr{filter_radius}_ve{volume_envelope}_pro{protect}_{f0_method}{"" if "crepe" not in f0_method else f"_{hop_length}"}.wav')
|
| 334 |
ai_cover_path = os.path.join(song_dir, f'{os.path.splitext(os.path.basename(orig_song_path))[0]} ({voice_model} Ver).{output_format}')
|
| 335 |
|
| 336 |
-
|
| 337 |
-
|
| 338 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 339 |
|
| 340 |
return ai_vocals_path, ai_cover_path, instrumentals_path, backup_vocals_path, vocals_path, main_vocals_path
|
| 341 |
|
|
@@ -384,7 +419,7 @@ def song_cover_pipeline(song_input, voice_model, pitch_change, keep_files,
|
|
| 384 |
is_webui=0, main_gain=0, backup_gain=0, inst_gain=0, index_rate=0.5, filter_radius=3,
|
| 385 |
volume_envelope=0.25, f0_method='rmvpe', hop_length=128, protect=0.33, pitch_change_all=0,
|
| 386 |
reverb_rm_size=0.15, reverb_wet=0.2, reverb_dry=0.8, reverb_damping=0.7, output_format='mp3',
|
| 387 |
-
extra_denoise=False,
|
| 388 |
progress=gr.Progress()):
|
| 389 |
if not keep_files or IS_ZERO_GPU:
|
| 390 |
clean_old_folders("./song_output", 14400)
|
|
@@ -393,8 +428,10 @@ def song_cover_pipeline(song_input, voice_model, pitch_change, keep_files,
|
|
| 393 |
clean_old_folders("./rvc_models", 10800)
|
| 394 |
|
| 395 |
try:
|
| 396 |
-
if not song_input
|
| 397 |
-
raise_exception('Ensure that the song input field
|
|
|
|
|
|
|
| 398 |
|
| 399 |
display_progress('[~] Starting AI Cover Generation Pipeline...', 0, is_webui, progress)
|
| 400 |
|
|
@@ -455,6 +492,7 @@ def song_cover_pipeline(song_input, voice_model, pitch_change, keep_files,
|
|
| 455 |
output_format,
|
| 456 |
keep_orig,
|
| 457 |
orig_song_path,
|
|
|
|
| 458 |
)
|
| 459 |
|
| 460 |
end = time.time()
|
|
@@ -467,6 +505,27 @@ def song_cover_pipeline(song_input, voice_model, pitch_change, keep_files,
|
|
| 467 |
print(f"Warning: Could not read audio duration from {ai_vocals_path}: {sf_err}")
|
| 468 |
print("The RVC inference may have produced an invalid output file. Continuing with effects processing...")
|
| 469 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 470 |
display_progress('[~] Applying audio effects to Vocals...', 0.8, is_webui, progress)
|
| 471 |
|
| 472 |
nr_path = ai_vocals_path # get_audio_with_suffix(song_dir, "_nr.wav")
|
|
@@ -475,6 +534,23 @@ def song_cover_pipeline(song_input, voice_model, pitch_change, keep_files,
|
|
| 475 |
|
| 476 |
ai_vocals_mixed_path = add_audio_effects(ai_vocals_path, reverb_rm_size, reverb_wet, reverb_dry, reverb_damping)
|
| 477 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 478 |
ins_path = get_audio_with_suffix(song_dir, "_Voiceless.wav")
|
| 479 |
if not ins_path:
|
| 480 |
instrumentals_path, _ = run_mdx(
|
|
@@ -518,7 +594,7 @@ def song_cover_pipeline(song_input, voice_model, pitch_change, keep_files,
|
|
| 518 |
if __name__ == '__main__':
|
| 519 |
parser = argparse.ArgumentParser(description='Generate a AI cover song in the song_output/id directory.', add_help=True)
|
| 520 |
parser.add_argument('-i', '--song-input', type=str, required=True, help='Link to a YouTube video or the filepath to a local mp3/wav file to create an AI cover of')
|
| 521 |
-
parser.add_argument('-dir', '--rvc-dirname', type=str,
|
| 522 |
parser.add_argument('-p', '--pitch-change', type=int, required=True, help='Change the pitch of AI Vocals only. Generally, use 1 for male to female and -1 for vice-versa. (Octaves)')
|
| 523 |
parser.add_argument('-k', '--keep-files', action=argparse.BooleanOptionalAction, help='Whether to keep all intermediate audio files generated in the song_output/id directory, e.g. Isolated Vocals/Instrumentals')
|
| 524 |
parser.add_argument('-ir', '--index-rate', type=float, default=0.5, help='A decimal number e.g. 0.5, used to reduce/resolve the timbre leakage problem. If set to 1, more biased towards the timbre quality of the training dataset')
|
|
@@ -536,11 +612,18 @@ if __name__ == '__main__':
|
|
| 536 |
parser.add_argument('-rdry', '--reverb-dryness', type=float, default=0.8, help='Reverb dry level between 0 and 1')
|
| 537 |
parser.add_argument('-rdamp', '--reverb-damping', type=float, default=0.7, help='Reverb damping between 0 and 1')
|
| 538 |
parser.add_argument('-oformat', '--output-format', type=str, default='mp3', help='Output format of audio file. mp3 for smaller file size, wav for best quality')
|
|
|
|
|
|
|
|
|
|
|
|
|
| 539 |
args = parser.parse_args()
|
| 540 |
|
| 541 |
rvc_dirname = args.rvc_dirname
|
| 542 |
-
if
|
| 543 |
-
|
|
|
|
|
|
|
|
|
|
| 544 |
|
| 545 |
cover_path = song_cover_pipeline(args.song_input, rvc_dirname, args.pitch_change, args.keep_files,
|
| 546 |
main_gain=args.main_vol, backup_gain=args.backup_vol, inst_gain=args.inst_vol,
|
|
@@ -550,5 +633,5 @@ if __name__ == '__main__':
|
|
| 550 |
pitch_change_all=args.pitch_change_all,
|
| 551 |
reverb_rm_size=args.reverb_size, reverb_wet=args.reverb_wetness,
|
| 552 |
reverb_dry=args.reverb_dryness, reverb_damping=args.reverb_damping,
|
| 553 |
-
output_format=args.output_format)
|
| 554 |
print(f'[+] Cover generated at {cover_path}')
|
|
|
|
| 313 |
def process_song(
|
| 314 |
song_dir, song_input, mdx_model_params, song_id, is_webui, input_type, progress,
|
| 315 |
keep_files, pitch_change, pitch_change_all, voice_model, index_rate, filter_radius,
|
| 316 |
+
volume_envelope, protect, f0_method, hop_length, output_format, keep_orig, orig_song_path,
|
| 317 |
+
inference_mode='full'
|
| 318 |
):
|
| 319 |
+
"""
|
| 320 |
+
Process a song through the AI cover pipeline.
|
| 321 |
|
| 322 |
+
inference_mode controls which stages are executed:
|
| 323 |
+
'full' - MDX separation + RVC voice conversion (default)
|
| 324 |
+
'mdx' - MDX separation only, skip RVC (outputs separated vocals)
|
| 325 |
+
'rvc' - RVC voice conversion only, use input audio directly as vocals
|
| 326 |
+
"""
|
| 327 |
+
instrumentals_path = None
|
| 328 |
+
backup_vocals_path = None
|
| 329 |
+
vocals_path = None
|
| 330 |
+
main_vocals_path = None
|
| 331 |
+
main_vocals_dereverb_path = None
|
| 332 |
|
| 333 |
+
# --- MDX Separation Stage ---
|
| 334 |
+
# Run MDX for 'full' and 'mdx' modes; skip for 'rvc' mode
|
| 335 |
+
if inference_mode in ('full', 'mdx'):
|
| 336 |
+
if not os.path.exists(song_dir):
|
| 337 |
+
os.makedirs(song_dir)
|
| 338 |
orig_song_path, vocals_path, instrumentals_path, main_vocals_path, backup_vocals_path, main_vocals_dereverb_path = preprocess_song(song_input, mdx_model_params, song_id, is_webui, input_type, progress, keep_orig, orig_song_path)
|
| 339 |
else:
|
| 340 |
+
vocals_path, main_vocals_path = None, None
|
| 341 |
+
paths = get_audio_paths(song_dir)
|
| 342 |
+
|
| 343 |
+
# if any of the audio files aren't available or keep intermediate files, rerun preprocess
|
| 344 |
+
if any(path is None for path in paths):
|
| 345 |
+
orig_song_path, vocals_path, instrumentals_path, main_vocals_path, backup_vocals_path, main_vocals_dereverb_path = preprocess_song(song_input, mdx_model_params, song_id, is_webui, input_type, progress, keep_orig, orig_song_path)
|
| 346 |
+
else:
|
| 347 |
+
orig_song_path, instrumentals_path, main_vocals_dereverb_path, backup_vocals_path = paths
|
| 348 |
+
else:
|
| 349 |
+
# RVC-only mode: use the original audio as vocals directly
|
| 350 |
+
# No MDX separation — the input audio IS the vocals
|
| 351 |
+
main_vocals_dereverb_path = orig_song_path
|
| 352 |
+
# We still need placeholder paths for the downstream pipeline
|
| 353 |
+
vocals_path = orig_song_path
|
| 354 |
+
main_vocals_path = orig_song_path
|
| 355 |
+
# Create a simple instrumental by treating the original as instrumental too
|
| 356 |
+
# (will be ignored in RVC-only output mixing)
|
| 357 |
+
instrumentals_path = orig_song_path
|
| 358 |
+
backup_vocals_path = orig_song_path
|
| 359 |
|
| 360 |
pitch_change = pitch_change * 12 + pitch_change_all
|
| 361 |
ai_vocals_path = os.path.join(song_dir, f'{os.path.splitext(os.path.basename(orig_song_path))[0]}_{voice_model}_p{pitch_change}_i{index_rate}_fr{filter_radius}_ve{volume_envelope}_pro{protect}_{f0_method}{"" if "crepe" not in f0_method else f"_{hop_length}"}.wav')
|
| 362 |
ai_cover_path = os.path.join(song_dir, f'{os.path.splitext(os.path.basename(orig_song_path))[0]} ({voice_model} Ver).{output_format}')
|
| 363 |
|
| 364 |
+
# --- RVC Voice Conversion Stage ---
|
| 365 |
+
# Run RVC for 'full' and 'rvc' modes; skip for 'mdx' mode
|
| 366 |
+
if inference_mode in ('full', 'rvc'):
|
| 367 |
+
if not os.path.exists(ai_vocals_path):
|
| 368 |
+
display_progress('[~] Converting voice using RVC...', 0.5, is_webui, progress)
|
| 369 |
+
voice_change(voice_model, main_vocals_dereverb_path, ai_vocals_path, pitch_change, f0_method, index_rate, filter_radius, volume_envelope, protect, hop_length, is_webui)
|
| 370 |
+
elif inference_mode == 'mdx':
|
| 371 |
+
# MDX-only mode: the "AI vocals" are just the dereverbed main vocals (no RVC)
|
| 372 |
+
ai_vocals_path = main_vocals_dereverb_path
|
| 373 |
+
display_progress('[~] MDX separation complete (RVC skipped).', 0.6, is_webui, progress)
|
| 374 |
|
| 375 |
return ai_vocals_path, ai_cover_path, instrumentals_path, backup_vocals_path, vocals_path, main_vocals_path
|
| 376 |
|
|
|
|
| 419 |
is_webui=0, main_gain=0, backup_gain=0, inst_gain=0, index_rate=0.5, filter_radius=3,
|
| 420 |
volume_envelope=0.25, f0_method='rmvpe', hop_length=128, protect=0.33, pitch_change_all=0,
|
| 421 |
reverb_rm_size=0.15, reverb_wet=0.2, reverb_dry=0.8, reverb_damping=0.7, output_format='mp3',
|
| 422 |
+
extra_denoise=False, inference_mode='full',
|
| 423 |
progress=gr.Progress()):
|
| 424 |
if not keep_files or IS_ZERO_GPU:
|
| 425 |
clean_old_folders("./song_output", 14400)
|
|
|
|
| 428 |
clean_old_folders("./rvc_models", 10800)
|
| 429 |
|
| 430 |
try:
|
| 431 |
+
if not song_input:
|
| 432 |
+
raise_exception('Ensure that the song input field is filled.', is_webui)
|
| 433 |
+
if inference_mode in ('full', 'rvc') and not voice_model:
|
| 434 |
+
raise_exception('A voice model is required for Full Inference and RVC Only modes.', is_webui)
|
| 435 |
|
| 436 |
display_progress('[~] Starting AI Cover Generation Pipeline...', 0, is_webui, progress)
|
| 437 |
|
|
|
|
| 492 |
output_format,
|
| 493 |
keep_orig,
|
| 494 |
orig_song_path,
|
| 495 |
+
inference_mode,
|
| 496 |
)
|
| 497 |
|
| 498 |
end = time.time()
|
|
|
|
| 505 |
print(f"Warning: Could not read audio duration from {ai_vocals_path}: {sf_err}")
|
| 506 |
print("The RVC inference may have produced an invalid output file. Continuing with effects processing...")
|
| 507 |
|
| 508 |
+
# --- Post-processing: Effects, mixing, and output ---
|
| 509 |
+
# The post-processing differs based on inference_mode
|
| 510 |
+
if inference_mode == 'mdx':
|
| 511 |
+
# MDX-only: output the separated vocals without effects or mixing
|
| 512 |
+
# Just export the dereverbed main vocals as the final output
|
| 513 |
+
display_progress('[~] Exporting separated vocals (MDX Only mode)...', 0.8, is_webui, progress)
|
| 514 |
+
ai_cover_path = os.path.join(song_dir, f'{os.path.splitext(os.path.basename(orig_song_path))[0]} (MDX Separated).{output_format}')
|
| 515 |
+
# Export the separated vocals as the cover
|
| 516 |
+
main_vocal_audio = AudioSegment.from_wav(ai_vocals_path)
|
| 517 |
+
main_vocal_audio.export(ai_cover_path, format=output_format)
|
| 518 |
+
|
| 519 |
+
if not keep_files:
|
| 520 |
+
display_progress('[~] Removing intermediate audio files...', 0.95, is_webui, progress)
|
| 521 |
+
intermediate_files = [vocals_path, main_vocals_path]
|
| 522 |
+
for file in intermediate_files:
|
| 523 |
+
if file and os.path.exists(file):
|
| 524 |
+
os.remove(file)
|
| 525 |
+
|
| 526 |
+
return ai_cover_path
|
| 527 |
+
|
| 528 |
+
# For 'full' and 'rvc' modes: apply effects, mix, and output
|
| 529 |
display_progress('[~] Applying audio effects to Vocals...', 0.8, is_webui, progress)
|
| 530 |
|
| 531 |
nr_path = ai_vocals_path # get_audio_with_suffix(song_dir, "_nr.wav")
|
|
|
|
| 534 |
|
| 535 |
ai_vocals_mixed_path = add_audio_effects(ai_vocals_path, reverb_rm_size, reverb_wet, reverb_dry, reverb_damping)
|
| 536 |
|
| 537 |
+
if inference_mode == 'rvc':
|
| 538 |
+
# RVC-only: output just the converted vocals with effects, no mixing
|
| 539 |
+
display_progress('[~] Exporting RVC vocals (RVC Only mode)...', 0.9, is_webui, progress)
|
| 540 |
+
ai_cover_path = os.path.join(song_dir, f'{os.path.splitext(os.path.basename(orig_song_path))[0]} (RVC Only).{output_format}')
|
| 541 |
+
main_vocal_audio = AudioSegment.from_wav(ai_vocals_mixed_path)
|
| 542 |
+
main_vocal_audio.export(ai_cover_path, format=output_format)
|
| 543 |
+
|
| 544 |
+
if not keep_files:
|
| 545 |
+
display_progress('[~] Removing intermediate audio files...', 0.95, is_webui, progress)
|
| 546 |
+
intermediate_files = [ai_vocals_mixed_path, nr_path]
|
| 547 |
+
for file in intermediate_files:
|
| 548 |
+
if file and os.path.exists(file):
|
| 549 |
+
os.remove(file)
|
| 550 |
+
|
| 551 |
+
return ai_cover_path
|
| 552 |
+
|
| 553 |
+
# Full mode: mix AI vocals with instrumentals and backup vocals
|
| 554 |
ins_path = get_audio_with_suffix(song_dir, "_Voiceless.wav")
|
| 555 |
if not ins_path:
|
| 556 |
instrumentals_path, _ = run_mdx(
|
|
|
|
| 594 |
if __name__ == '__main__':
|
| 595 |
parser = argparse.ArgumentParser(description='Generate a AI cover song in the song_output/id directory.', add_help=True)
|
| 596 |
parser.add_argument('-i', '--song-input', type=str, required=True, help='Link to a YouTube video or the filepath to a local mp3/wav file to create an AI cover of')
|
| 597 |
+
parser.add_argument('-dir', '--rvc-dirname', type=str, default='', help='Name of the folder in the rvc_models directory containing the RVC model file and optional index file to use. Required for "full" and "rvc" modes.')
|
| 598 |
parser.add_argument('-p', '--pitch-change', type=int, required=True, help='Change the pitch of AI Vocals only. Generally, use 1 for male to female and -1 for vice-versa. (Octaves)')
|
| 599 |
parser.add_argument('-k', '--keep-files', action=argparse.BooleanOptionalAction, help='Whether to keep all intermediate audio files generated in the song_output/id directory, e.g. Isolated Vocals/Instrumentals')
|
| 600 |
parser.add_argument('-ir', '--index-rate', type=float, default=0.5, help='A decimal number e.g. 0.5, used to reduce/resolve the timbre leakage problem. If set to 1, more biased towards the timbre quality of the training dataset')
|
|
|
|
| 612 |
parser.add_argument('-rdry', '--reverb-dryness', type=float, default=0.8, help='Reverb dry level between 0 and 1')
|
| 613 |
parser.add_argument('-rdamp', '--reverb-damping', type=float, default=0.7, help='Reverb damping between 0 and 1')
|
| 614 |
parser.add_argument('-oformat', '--output-format', type=str, default='mp3', help='Output format of audio file. mp3 for smaller file size, wav for best quality')
|
| 615 |
+
parser.add_argument('-m', '--mode', type=str, default='full', choices=['full', 'mdx', 'rvc'],
|
| 616 |
+
help='Inference mode: "full" = MDX separation + RVC voice conversion (default), '
|
| 617 |
+
'"mdx" = MDX separation only (skip RVC), '
|
| 618 |
+
'"rvc" = RVC voice conversion only (skip MDX, use input as vocals)')
|
| 619 |
args = parser.parse_args()
|
| 620 |
|
| 621 |
rvc_dirname = args.rvc_dirname
|
| 622 |
+
if args.mode in ('full', 'rvc'):
|
| 623 |
+
if not rvc_dirname:
|
| 624 |
+
raise Exception('A voice model directory (-dir) is required for "full" and "rvc" modes.')
|
| 625 |
+
if not os.path.exists(os.path.join(rvc_models_dir, rvc_dirname)):
|
| 626 |
+
raise Exception(f'The folder {os.path.join(rvc_models_dir, rvc_dirname)} does not exist.')
|
| 627 |
|
| 628 |
cover_path = song_cover_pipeline(args.song_input, rvc_dirname, args.pitch_change, args.keep_files,
|
| 629 |
main_gain=args.main_vol, backup_gain=args.backup_vol, inst_gain=args.inst_vol,
|
|
|
|
| 633 |
pitch_change_all=args.pitch_change_all,
|
| 634 |
reverb_rm_size=args.reverb_size, reverb_wet=args.reverb_wetness,
|
| 635 |
reverb_dry=args.reverb_dryness, reverb_damping=args.reverb_damping,
|
| 636 |
+
output_format=args.output_format, inference_mode=args.mode)
|
| 637 |
print(f'[+] Cover generated at {cover_path}')
|
src/webui.py
CHANGED
|
@@ -110,6 +110,14 @@ def show_hop_slider(pitch_detection_algo):
|
|
| 110 |
else:
|
| 111 |
return gr.update(visible=False)
|
| 112 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 113 |
def update_input_visibility(selected_method):
|
| 114 |
if selected_method == "File Upload":
|
| 115 |
return gr.update(visible=True), gr.update(visible=False), gr.update(visible=False)
|
|
@@ -151,6 +159,16 @@ if __name__ == '__main__':
|
|
| 151 |
rvc_model = gr.Dropdown(voice_models, label='Voice Models', info='Models folder "AICoverGen --> rvc_models". After new models are added into this folder, click the refresh button')
|
| 152 |
ref_btn = gr.Button('Refresh Models 🔁', variant='primary')
|
| 153 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 154 |
|
| 155 |
# Input Method Selection
|
| 156 |
with gr.Row(equal_height=True):
|
|
@@ -245,19 +263,20 @@ if __name__ == '__main__':
|
|
| 245 |
ai_cover = gr.Audio(label='AI Cover')
|
| 246 |
|
| 247 |
ref_btn.click(update_models_list, None, outputs=rvc_model)
|
|
|
|
| 248 |
is_webui = gr.Number(value=1, visible=False)
|
| 249 |
|
| 250 |
generate_btn.click(song_cover_pipeline,
|
| 251 |
inputs=[local_file, rvc_model, pitch, keep_files, is_webui, main_gain, backup_gain,
|
| 252 |
inst_gain, index_rate, filter_radius, volume_envelope, f0_method, hop_length,
|
| 253 |
protect, pitch_all, reverb_rm_size, reverb_wet, reverb_dry, reverb_damping,
|
| 254 |
-
output_format, extra_denoise],
|
| 255 |
outputs=[ai_cover])
|
| 256 |
|
| 257 |
-
clear_btn.click(lambda: [0, 0, 0, 0, 0.5, 3, 0.25, 0.33, 'rmvpe', 128, 0, 0.15, 0.2, 0.8, 0.7, 'mp3', None, True],
|
| 258 |
outputs=[pitch, main_gain, backup_gain, inst_gain, index_rate, filter_radius, volume_envelope,
|
| 259 |
protect, f0_method, hop_length, pitch_all, reverb_rm_size, reverb_wet,
|
| 260 |
-
reverb_dry, reverb_damping, output_format, ai_cover, extra_denoise])
|
| 261 |
|
| 262 |
# Download tab
|
| 263 |
with gr.Tab('Download model'):
|
|
|
|
| 110 |
else:
|
| 111 |
return gr.update(visible=False)
|
| 112 |
|
| 113 |
+
def update_voice_model_visibility(mode):
|
| 114 |
+
"""Show/hide the voice model dropdown based on inference mode.
|
| 115 |
+
Voice model is required for 'full' and 'rvc' modes, not for 'mdx' mode."""
|
| 116 |
+
if mode == 'mdx':
|
| 117 |
+
return gr.update(visible=False)
|
| 118 |
+
else:
|
| 119 |
+
return gr.update(visible=True)
|
| 120 |
+
|
| 121 |
def update_input_visibility(selected_method):
|
| 122 |
if selected_method == "File Upload":
|
| 123 |
return gr.update(visible=True), gr.update(visible=False), gr.update(visible=False)
|
|
|
|
| 159 |
rvc_model = gr.Dropdown(voice_models, label='Voice Models', info='Models folder "AICoverGen --> rvc_models". After new models are added into this folder, click the refresh button')
|
| 160 |
ref_btn = gr.Button('Refresh Models 🔁', variant='primary')
|
| 161 |
|
| 162 |
+
# Inference Mode Selection
|
| 163 |
+
with gr.Row(equal_height=True):
|
| 164 |
+
inference_mode = gr.Radio(
|
| 165 |
+
choices=['full', 'mdx', 'rvc'],
|
| 166 |
+
value='full',
|
| 167 |
+
label='Inference Mode',
|
| 168 |
+
info='Full: MDX separation + RVC voice conversion | MDX Only: Separate vocals only (no RVC) | RVC Only: Convert voice only (no separation)',
|
| 169 |
+
interactive=True
|
| 170 |
+
)
|
| 171 |
+
|
| 172 |
|
| 173 |
# Input Method Selection
|
| 174 |
with gr.Row(equal_height=True):
|
|
|
|
| 263 |
ai_cover = gr.Audio(label='AI Cover')
|
| 264 |
|
| 265 |
ref_btn.click(update_models_list, None, outputs=rvc_model)
|
| 266 |
+
inference_mode.change(update_voice_model_visibility, inputs=inference_mode, outputs=rvc_model)
|
| 267 |
is_webui = gr.Number(value=1, visible=False)
|
| 268 |
|
| 269 |
generate_btn.click(song_cover_pipeline,
|
| 270 |
inputs=[local_file, rvc_model, pitch, keep_files, is_webui, main_gain, backup_gain,
|
| 271 |
inst_gain, index_rate, filter_radius, volume_envelope, f0_method, hop_length,
|
| 272 |
protect, pitch_all, reverb_rm_size, reverb_wet, reverb_dry, reverb_damping,
|
| 273 |
+
output_format, extra_denoise, inference_mode],
|
| 274 |
outputs=[ai_cover])
|
| 275 |
|
| 276 |
+
clear_btn.click(lambda: [0, 0, 0, 0, 0.5, 3, 0.25, 0.33, 'rmvpe', 128, 0, 0.15, 0.2, 0.8, 0.7, 'mp3', None, True, 'full'],
|
| 277 |
outputs=[pitch, main_gain, backup_gain, inst_gain, index_rate, filter_radius, volume_envelope,
|
| 278 |
protect, f0_method, hop_length, pitch_all, reverb_rm_size, reverb_wet,
|
| 279 |
+
reverb_dry, reverb_damping, output_format, ai_cover, extra_denoise, inference_mode])
|
| 280 |
|
| 281 |
# Download tab
|
| 282 |
with gr.Tab('Download model'):
|