Pythonで話者分離して、片方の話者の発話を切り抜き

無料のブラウザツールだと、音楽などで、音声とインストラメントを分離することはできるようなのですが、二人が喋っていて、片方の音声に分離することができなかったので、Pythonで実行します。

前準備として、以下の手配が必要
1) ffmpeg, pyannote.audio のインストール
2) Hugging Faceでのaccess token発行(read)およびモデル利用のaccept
3) Hugging Faceでのaccess tokenをコードのHUGGINGFACE_TOKENに埋め込み
4) python3 speaker_separation.py の実行

import subprocess
from pyannote.audio import Pipeline
from pydub import AudioSegment
import os
from collections import defaultdict

# ===== 設定 =====
mp4_file = "video.mp4"
wav_file = "conversation.wav"
output_file = "main_speaker_only.wav"

HUGGINGFACE_TOKEN = "****"  # Hugging Face token

# ===== WAV変換 =====
if os.path.exists(wav_file):
    os.remove(wav_file)

subprocess.run([
    "ffmpeg", "-y", "-i", mp4_file,
    "-vn", "-acodec", "pcm_s16le", "-ar", "16000", "-ac", "1",
    wav_file
], check=True)

# ===== 話者分離 =====
pipeline = Pipeline.from_pretrained(
    "pyannote/speaker-diarization-3.1",
    use_auth_token=HUGGINGFACE_TOKEN
)

diarization = pipeline(wav_file)

# ===== 各話者の合計発話時間を計算 =====
speaker_durations = defaultdict(float)
for turn, _, speaker in diarization.itertracks(yield_label=True):
    speaker_durations[speaker] += turn.end - turn.start

# 発話時間が最も長い話者を自動選択
target_speaker = max(speaker_durations, key=speaker_durations.get)
print("選択された話者:", target_speaker)

# ===== その話者だけ抽出 =====
audio = AudioSegment.from_wav(wav_file)
speaker_segments = [
    audio[int(turn.start * 1000): int(turn.end * 1000)]
    for turn, _, speaker in diarization.itertracks(yield_label=True)
    if speaker == target_speaker
]

if speaker_segments:
    speaker_audio = sum(speaker_segments)
    speaker_audio.export(output_file, format="wav")
    print(f"✅ 保存しました: {output_file}")
else:
    print("⚠️ 対象話者の音声が見つかりませんでした")

Style-Bert-VITS2を試そう

$ mkdir tts
$ cd tts
$ git clone https://github.com/litagin02/Style-Bert-VITS2.git
$ cd Style-Bert-VITS2
$ python3 -m venv venv
$ ls
$ source venv/bin/activate
$ pip3 install “torch<2.4" "torchaudio<2.4" --index-url https://download.pytorch.org/whl/cu118 $ cat requirements.txt [code] # onnxruntime-gpu; sys_platform != 'darwin' [/code] $ pip3 install onnxruntime $ pip3 install -r requirements.txt $ pip3 initialize.py $ pip install style-bert-vits2 soundfile simpleaudio $ sudo apt install libasound2-dev $ pip3 install simpleaudio $ pip3 install style-bert-vits2 soundfile [code] from style_bert_vits2.tts_model import TTSModel from pathlib import Path import soundfile as sf # soundfile は requirements.txt に含まれています # モデルパス model_path = Path("model_assets/jvnv-F1-jp/jvnv-F1-jp_e160_s14000.safetensors") config_path = Path("model_assets/jvnv-F1-jp/config.json") style_vec_path = Path("model_assets/jvnv-F1-jp/style_vectors.npy") model = TTSModel( model_path=model_path, config_path=config_path, style_vec_path=style_vec_path, device="cpu" ) text = "こんにちは!仮想環境でも音声ファイルに保存できます。" # 音声生成 sr, audio = model.infer(text=text) # WAV に保存 sf.write("output.wav", audio, sr) print("output.wav に保存完了") [/code] [audio wav="http://hpscript.com/blog/wp-content/uploads/2025/09/output.wav"][/audio] jvnv-F1-jp/jvnv-F1-jp_e160_s14000.safetensors はStyle-Bert-VITS2 が使う日本語向け音声合成モデル本体 style_vectors.npy:複数の話者や声質の特徴ベクトル(スタイル変換用) スタイルベクトルで 複数話者・声質を切り替えられる pitchで微調整できる。 [code] sr, audio = model.infer( text="こんにちは", style=selected_style, length_scale=1.0, # 1.0が標準、<1で早口、>1でゆっくり noise_scale=0.5, # 音声の自然さ noise_scale_w=0.5, # ピッチ揺れの調整 ) [/code]

mcd(Mel Cepstral Distortion)による音声評価

$ pip3 install librosa

import librosa
import numpy as np

def calculate_mcd(ref_wav_path, syn_wav_path, sr=16000, n_mfcc=25):
    """
    Mel Cepstral Distortion (MCD) を計算する修正版関数
    正規化+フレームごとの距離平均を行います
    """
    # 音声読み込み
    ref, _ = librosa.load(ref_wav_path, sr=sr)
    syn, _ = librosa.load(syn_wav_path, sr=sr)

    # 正規化 (-1〜1 の範囲)
    ref = ref / np.max(np.abs(ref))
    syn = syn / np.max(np.abs(syn))

    # MFCC 抽出(c0 は除外)
    ref_mfcc = librosa.feature.mfcc(y=ref, sr=sr, n_mfcc=n_mfcc)[1:]
    syn_mfcc = librosa.feature.mfcc(y=syn, sr=sr, n_mfcc=n_mfcc)[1:]

    # フレーム数を揃える(短い方に合わせる)
    min_len = min(ref_mfcc.shape[1], syn_mfcc.shape[1])
    ref_mfcc = ref_mfcc[:, :min_len]
    syn_mfcc = syn_mfcc[:, :min_len]

    # フレームごとのユークリッド距離
    distances = np.sqrt(np.sum((ref_mfcc - syn_mfcc)**2, axis=0))

    # MCD 計算式(フレームごとの平均)
    mcd = (10.0 / np.log(10)) * np.sqrt(2.0) * np.mean(distances)

    return mcd

# 使用例
if __name__ == "__main__":
    ref_file = "original.wav"  # 参照音声
    syn_file = "tts.wav"       # 合成音声
    mcd_value = calculate_mcd(ref_file, syn_file)
    print(f"MCD: {mcd_value:.2f} dB")

$ python3 app.py
MCD: 568.47 dB

明らかに大きい