Windows の SAPI・Speech Synthesizer で say コマンドもどきを作る

MacOS には say コマンドというモノが標準搭載されている。OpenJTalk や espeak コマンドと同じようなモノだ。

# どちらでも動く
$ say こんにちは Neo です
$ say 'こんにちは Neo です'

こんな風に引数に与えた文字列を全て連結して読み上げてくれる。利用できるボイスは $ say -v ? で確認できるが、日本語が話せるのは Kyoko の1種類のみ。

そして、以前 PowerShell でも似たようなことができる、という記事も書いたことがある。

この時はよく分からないまま触っていたのだが、COM オブジェクトである SAPI (Windows Speech API)、もしくは .NET の Speech Synthesizer を使うことで、Windows でも MacOS の say コマンドのように、任意のテキストを発話させられるワケだ。

今回はこの SAPI が VBScript・JScript からも呼べることを確認しつつ、最終的に PowerShell で say もどきのコマンドを作ってみる。

目次

WSH で SAPI を呼び出す

まずは WSH、つまり VBScript や JScript で SAPI を呼び出すコードを書いてみる。

Option Explicit

Dim sapi : Set sapi = WScript.CreateObject("SAPI.SpVoice")
sapi.Speak "どうも Neo です。お疲れ様です。VBScript です。"
var sapi = WScript.CreateObject('SAPI.SpVoice');
sapi.Speak('どうも Neo です。お疲れ様です。JScript です。');

こんな感じでとっても簡単。

PowerShell では SAPI と Speech Synthesizer 両方使える

SAPI は COM オブジェクトとして提供されているので、WScript.CreateObject() で WSH から簡単に利用できたが、PowerShell では .NET に含まれる Speech Synthesizer というモノも呼び出せる。検証した限り、どちらでも出来ることやボイスの種類などは同じだったので、好きに使えば良さそう。

(ちなみに WSH から .NET の API を呼び出すことも可能ではあるようなので、VBScript から Speech Synthesizer を呼び出すようなコードを書くこともできそうではある)

$sapi = New-Object -ComObject SAPI.SpVoice;
$sapi.Speak("どうも Neo です。お疲れ様です。PowerShell です。");
Add-Type -AssemblyName System.speech;
$speech = New-Object System.Speech.Synthesis.SpeechSynthesizer;
$speech.Speak("どうも Neo です。お疲れ様です。Speech Synthesizer です。");

こんな感じ。

PowerShell で say コマンドもどきを作る

というワケで、扱い方は分かったので、say コマンドもどきを作ってみよう。以下のスクリプトを say.ps1 という名前で保存し、環境変数 PATH が通っているフォルダに配置する。そうすれば PowerShell を開いて PS> say ほげふが と実行できるようになる。

# ================================================================================
# Windows 版・簡易 `say` コマンド
# ================================================================================

# 引数を文字列に連結する
$paramArray = $args[0..($args.Length - 1)];
$paramString = $paramArray -join ' ';

# 引数での文字列指定がなければ中断する
if([string]::IsNullOrEmpty($paramString)) {
  Write-Host 'Please Input Text';
  exit;
}

# 発話する
$sapi = New-Object -ComObject SAPI.SpVoice;
$sapi.Speak($paramString) | Out-Null;

引数を文字列に連結して SAPI に与えているだけ。細かいところで参考にした文献は以下のとおり。

簡単にできて良き良き!