はじめに
Teams会議のマイクに生成した音声を入力し、喋らなくていいようにします。
開発環境
- MacBook Air M1, 2020
- Python 3.12
- BlackHole 0.6.1
フォルダ構成
my-virtual-mic/
├── README.md
└── standalone/
├── check.py
├── requirements.txt
├── speak.py
└── speech.wav
導入
BlackHoleをインストールします。

standaloneフォルダに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"
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)に設定します。

自分が喋る時に、Pythonコードを実行しましょう!
Teams会議で生成した音声をマイク入力することに成功、これで会議で喋らなくて良くなったw pic.twitter.com/sex3efuEGO
— がちもとさん (@sotongshi) December 16, 2025
お疲れ様でした。