diff --git a/example/infer_svc.sh b/example/infer_svc.sh index b40b1c5..8fbc484 100644 --- a/example/infer_svc.sh +++ b/example/infer_svc.sh @@ -6,7 +6,7 @@ root_dir=$(dirname "$script_dir") cd $root_dir || exit export PYTHONPATH=$root_dir:$PYTHONPATH -model_path=pretrained_models/SoulX-Singer-SVC/model.pt +model_path=pretrained_models/SoulX-Singer/model-svc.pt config=soulxsinger/config/soulxsinger.yaml prompt_wav_path=example/audio/zh_prompt.mp3 target_wav_path=example/audio/music.mp3 diff --git a/soulxsinger/models/soulxsinger_svc.py b/soulxsinger/models/soulxsinger_svc.py index 19a22c3..d04fbb9 100644 --- a/soulxsinger/models/soulxsinger_svc.py +++ b/soulxsinger/models/soulxsinger_svc.py @@ -212,6 +212,20 @@ class SoulXSingerSVC(nn.Module): else: pitch_shift = pitch_shift + # if target audio is less than 30 seconds, infer the whole audio + if gt_wav.shape[-1] < 30 * self.audio_cfg.sample_rate: + generated_audio = self.infer_segment( + pt_wav=pt_wav, + gt_wav=gt_wav, + pt_f0=pt_f0, + gt_f0=gt_f0, + pitch_shift=pitch_shift, + n_steps=n_steps, + cfg=cfg, + ) + return generated_audio, pitch_shift + + # if target audio is longer than 30 seconds, build vocal segments and infer each segment generated_audio = [] f0_rate = self.audio_cfg.sample_rate // self.audio_cfg.hop_size @@ -264,7 +278,8 @@ class SoulXSingerSVC(nn.Module): def infer_segment(self, pt_wav, gt_wav, pt_f0, gt_f0, pitch_shift=0, n_steps=32, cfg=3): pt_mel = self.mel(pt_wav) - len_prompt_mel = pt_f0.shape[1] + len_prompt_mel = pt_mel.shape[1] + pt_f0 = F.pad(pt_f0, (0, 0, 0, max(0, len_prompt_mel - pt_f0.shape[1])))[:, :len_prompt_mel] f0_course_pt = self.f0_to_coarse(pt_f0) f0_course_gt = self.f0_to_coarse(gt_f0, f0_shift=pitch_shift * 5) @@ -272,12 +287,13 @@ class SoulXSingerSVC(nn.Module): pt_content_feat = self.whisper_encoder.encode(pt_wav, sr=self.audio_cfg.sample_rate) gt_content_feat = self.whisper_encoder.encode(gt_wav, sr=self.audio_cfg.sample_rate) + t_pt, t_gt = f0_course_pt.shape[1], f0_course_gt.shape[1] + pt_content_feat = F.pad(pt_content_feat, (0, 0, 0, max(0, t_pt - pt_content_feat.shape[1])))[:, :t_pt, :] + gt_content_feat = F.pad(gt_content_feat, (0, 0, 0, max(0, t_gt - gt_content_feat.shape[1])))[:, :t_gt, :] + content_feat = torch.cat([pt_content_feat, gt_content_feat], 1) f0_feat = self.f0_encoder(f0_course) - min_len = min(content_feat.shape[1], f0_feat.shape[1]) - content_feat = content_feat[:, :min_len, :] - f0_feat = f0_feat[:, :min_len, :] features = content_feat + f0_feat gt_decoder_inp = features[:, len_prompt_mel:, :] diff --git a/webui_svc.py b/webui_svc.py index 41923db..8e7b696 100644 --- a/webui_svc.py +++ b/webui_svc.py @@ -60,7 +60,7 @@ _I18N = dict( zh="上传 Prompt 与 Target 音频,并配置相关参数", ), instruction_p2=dict( - en="Click the button to start singing voice conversion.", + en="Click「🎤Singing Voice Conversion」to start singing voice conversion.", zh="点击「🎤歌声转换」开始最终生成。", ), tips_title=dict(en="Tips", zh="提示"), @@ -145,7 +145,7 @@ class AppState: self.svc_config = load_config("soulxsinger/config/soulxsinger.yaml") self.svc_model = build_svc_model( - model_path="pretrained_models/SoulX-Singer-SVC/model.pt", + model_path="pretrained_models/SoulX-Singer/model-svc.pt", config=self.svc_config, device=self.device, ) @@ -194,8 +194,6 @@ class AppState: args = Args() args.device = self.device - args.model_path = "soulx-singer-svc.pt" - args.config = "soulxsinger/config/soulxsinger.yaml" args.prompt_wav_path = str(prompt_wav_path) args.target_wav_path = str(target_wav_path) args.prompt_f0_path = str(prompt_f0_path) @@ -305,7 +303,30 @@ def _start_svc(prompt_audio, target_audio, prompt_vocal_sep, target_vocal_sep, a def render_interface() -> gr.Blocks: - with gr.Blocks(title="SoulX-Singer SVC Demo", theme=gr.themes.Default()) as page: + with gr.Blocks(title="SoulX-Singer-SVC Demo", theme=gr.themes.Default()) as page: + gr.HTML( + '