+
23
-

回答

有,使用demucs进行人声伴奏提取,然后对提取的Basic Pitch 伴奏转录为 MIDI 音符,如果精度不够,demucs可可指定提取单个乐器的伴奏,Demucs 的 htdemucs_6s 模型可以分离出 6 种音轨:鼓、贝斯、其他、人声、钢琴、吉他。

cmd = [
sys.executable, "-m", "demucs",
"--two-stems", "other", # 只分离出“其他乐器(伴奏主体)”
"-n", "htdemucs_6s", # 指定使用 6 分轨模型
"-o", output_dir,
input_audio_path
]

如果你只把分离出来的 piano.wav 或 guitar.wav 喂给 Basic Pitch,精度会呈指数级上升

示例代码如下:

import os
import sys
import subprocess
from basic_pitch import ICASSP_2022_MODEL_PATH
from basic_pitch.inference import predict_and_save

# ==============================================================================
# Step 1: 使用 Demucs 进行人声伴奏分离
# ==============================================================================
def separate_vocals(input_audio_path, output_dir):
    print("\n[Step 1] 正在使用 Demucs 进行人声与伴奏分离...")
    
    # --two-stems=vocals 参数会将音频分离为人声 (vocals.wav) 和伴奏 (no_vocals.wav)
    cmd = [
        sys.executable, "-m", "demucs",
        "--two-stems", "vocals",
        "-o", output_dir,
        input_audio_path
    ]
    
    # 运行 Demucs 分离任务
    subprocess.run(cmd, check=True)
    
    # 查找分离出的伴奏文件
    track_name = os.path.splitext(os.path.basename(input_audio_path))[0]
    # Demucs 默认模型通常输出在 output_dir/htademucs/{track_name}/no_vocals.wav
    accompaniment_path = os.path.join(output_dir, "htademucs", track_name, "no_vocals.wav")
    
    # 备用检索:若因版本结构变化导致路径不同,则在输出目录下全局搜索伴奏文件
    if not os.path.exists(accompaniment_path):
        for root, dirs, files in os.walk(output_dir):
            if "no_vocals.wav" in files:
                accompaniment_path = os.path.join(root, "no_vocals.wav")
                break
                
    if not os.path.exists(accompaniment_path):
        raise FileNotFoundError("未能找到分离后的伴奏文件 no_vocals.wav,请检查分离过程。")
        
    print(f"-> 伴奏分离成功!文件保存在: {accompaniment_path}")
    return accompaniment_path


# ==============================================================================
# Step 2: 使用 Basic Pitch 将提取的伴奏转录为 MIDI 音符
# ==============================================================================

def extract_melody_to_midi(accompaniment_path, output_dir):
    print("\n[Step 2] 正在使用 Spotify Basic Pitch 转录伴奏旋律为 MIDI...")

    predict_and_save(
        audio_path_list=[accompaniment_path],
        output_directory=output_dir,
        save_midi=True,
        sonify_midi=False,                        # 新增:是否合成MIDI音频
        save_model_outputs=False,
        save_notes=False,
        model_or_model_path=ICASSP_2022_MODEL_PATH,  # 新增:指定模型
    onset_threshold=0.5,  # 音头阈值 (0~1)。调高(如0.6)可减少幽灵音符;调低(如0.3)可捕捉更多微弱发音
    frame_threshold=0.3,  # 帧阈值 (0~1)。控制音符持续时的稳定性,调高可减少断断续续的碎音

    )

    track_name = os.path.splitext(os.path.basename(accompaniment_path))[0]
    midi_path = os.path.join(output_dir, f"{track_name}_basic_pitch.mid")

    if not os.path.exists(midi_path):
        raise FileNotFoundError(f"未能成功生成 MIDI 文件: {midi_path}")

    print(f"-> MIDI 转录成功!文件保存在: {midi_path}")
    return midi_path

网友回复

我知道答案,我要回答