1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Teams会議のマイクに生成した音声を入力すーる(macOS、Python3.12)

Last updated at Posted at 2025-12-16

はじめに

Teams会議のマイクに生成した音声を入力し、喋らなくていいようにします。

開発環境

フォルダ構成

my-virtual-mic/
├── README.md
└── standalone/
    ├── check.py
    ├── requirements.txt
    ├── speak.py
    └── speech.wav

導入

BlackHoleをインストールします。
20251216-060755-7f2e0d43.png

standaloneフォルダにcheck.pyを作成します。

check.py
import sounddevice as sd

print(sd.query_devices())

こちらのコードを実行して、マイクとスピーカーの名前一覧を取得しましょう。

% python check.py
  0 ‎Gのマイク, Core Audio (1 in, 0 out)
< 1 USB PnP Sound Device, Core Audio (0 in, 2 out)
  2 USB PnP Sound Device, Core Audio (1 in, 0 out)
  3 BlackHole 2ch, Core Audio (2 in, 2 out)
> 4 MacBook Airのマイク, Core Audio (1 in, 0 out)
  5 MacBook Airのスピーカー, Core Audio (0 in, 2 out)
  6 Microsoft Teams Audio, Core Audio (1 in, 1 out)

音声ファイル(standalone/speech.wav)をElevenLabs等で用意します。

用意した音声ファイル(standalone/speech.wav)を再生して 仮想マイク(BlackHole)に流し込むための speak.py を作成します。

仮想マイクをBlackHole 2ch、モニター用のスピーカーを任意に設定します。
モニター用のスピーカーは None だとデフォルトのスピーカーが選ばれます。

VIRTUAL_DEVICE = "BlackHole 2ch"
MONITOR_DEVICE = "USB PnP Sound Device"

speak.py
try:
    import sounddevice as sd
    import soundfile as sf
except ModuleNotFoundError as e:
    missing = getattr(e, "name", "required package")
    raise SystemExit(
        f"必要なパッケージ '{missing}' が見つかりません。\n"
        "以下を実行してから再度お試しください:\n"
        "  pip install sounddevice soundfile\n"
        "(conda 環境の場合は、対象の環境を有効化してから実行)"
    ) from e
from pathlib import Path

# `speech.wav` はこのスクリプトと同じフォルダに置く想定(カレントディレクトリに依存しない)
wav_path = Path(__file__).with_name("speech.wav")
data, fs = sf.read(wav_path, dtype="float32")

# デバイス一覧の確認:
# python -c "import sounddevice as sd; print(sd.query_devices())"
#
# 仮想マイクへ流す出力先(BlackHole)
VIRTUAL_DEVICE = "BlackHole 2ch"

# モニター(手元で聴く)出力先:
# - None: macOS のデフォルト出力(「選んだスピーカー」)に出す
# - 文字列: 例 "MacBook Airのスピーカー" のように query_devices() に出てくる名前を指定
MONITOR_DEVICE = "USB PnP Sound Device"


def _resolve_output_device_id(device_name_or_none: str | None):
    """device= に渡せる値(int or None)へ解決する。文字列は部分一致で探す。"""
    if device_name_or_none is None:
        return None  # sounddevice のデフォルト出力
    devices = sd.query_devices()
    for idx, d in enumerate(devices):
        if device_name_or_none in d.get("name", "") and d.get("max_output_channels", 0) > 0:
            return idx
    raise RuntimeError(
        f"出力デバイス '{device_name_or_none}' が見つかりません。"
        " `python -c \"import sounddevice as sd; print(sd.query_devices())\"` で確認して、"
        " 実在する出力デバイス名(部分一致可)に合わせてください。"
    )


def play_to_outputs(audio, samplerate: int, output_devices: list[int | None], blocksize: int = 2048):
    """同じ音声を複数の出力デバイスへ同時に流す(例: BlackHole + スピーカー)。"""
    if audio.ndim == 1:
        audio = audio.reshape(-1, 1)
    channels = int(audio.shape[1])
    # soundfile が返す ndarray 互換の想定。dtypeだけ合わせておく
    if getattr(audio, "dtype", None) != "float32":
        audio = audio.astype("float32", copy=False)

    streams = [
        sd.OutputStream(
            device=dev,
            samplerate=samplerate,
            channels=channels,
            dtype="float32",
            blocksize=blocksize,
        )
        for dev in output_devices
    ]
    try:
        for s in streams:
            s.start()
        for i in range(0, len(audio), blocksize):
            chunk = audio[i : i + blocksize]
            for s in streams:
                s.write(chunk)
    finally:
        for s in streams:
            try:
                s.stop()
            except Exception:
                pass
            s.close()


virtual_id = _resolve_output_device_id(VIRTUAL_DEVICE)
monitor_id = _resolve_output_device_id(MONITOR_DEVICE)

# 同じデバイスを二重に指定しない
outs = [virtual_id]
if monitor_id not in outs:
    outs.append(monitor_id)

play_to_outputs(data, fs, outs)

Teams会議を立ち上げて、マイクの入力を BlackHole 2ch(Virtual)に設定します。
20251216-040956-3c518482.png

自分が喋る時に、Pythonコードを実行しましょう!

お疲れ様でした。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?