今回はExcel VBAでSAPIを使った音声読み上げを紹介する。
SAPIとはSpeech Application Programming Interfaceの略で、Windowsアプリケーションで音声認識や音声合成を使うためにマイクロソフトが開発したAPIである。
Windows 8.1 以降のOSには標準で音声合成エンジンが同梱されている。
※Windows 7の場合、SAPIの仕組み自体はありますが音声合成エンジンが別途調達しないといけないので今回のマクロはそのままでは動作しないと思われます。
作成したコードはこちら。
Sub Greeting() With CreateObject("SAPI.SpVoice") Set .Voice = .GetVoices.Item(0) .Speak "こんにちは" End With End Sub
このマクロを実行すると、日本語で「こんにちは」と読み上げられる。
※読み上げ中は他の操作ができなくなるので注意。
ただWindowsにインストールされている音声合成エンジンに依存するため、環境によってうまくいかないこともあるかもしれない。
利用できる音声合成エンジンを調べる方法
利用できる音声合成エンジンを調べるには次のマクロを実行する。
Sub ShowVoiceList() With CreateObject("SAPI.SpVoice") For i = 0 To .GetVoices.Count - 1 Debug.Print i & ":" & .GetVoices.Item(i).GetDescription Next End With End Sub
私の環境(Win10Home 64bit)の場合、イミディエイトウインドウに次のように表示された。
0:Microsoft Haruka Desktop - Japanese 1:Microsoft Zira Desktop - English (United States) 2:Microsoft David Desktop - English (United States)
冒頭で紹介したGreetingマクロにSet .Voice = .GetVoices().Item(0)という一文があるが、このItemプロパティの0を1に変えると私の環境ではZiraという英語ボイスになる。ただ英語なので日本語には対応していない。
外国人ボイスで日本語を読み上げる方法
日本語ボイスがインストールされてない場合、ローマ字で「kon nichiwa」と入力すればカタコトで、「コンニチハ」と読み上げてくれる。「Konnichiwa」だと「ケネティワ」に聞こえたのでスペースを空けた。
Sub GreetingKatakoto() With CreateObject("SAPI.SpVoice") Set .Voice = .GetVoices.Item(1) .Speak "Kon nichiwa" End With End Sub
参照設定で利用する場合
参照設定を利用する場合は、Microsoft Speech Object Libraryを参照する。
ただし、環境によっては下図のように同名の参照が2つ存在するので、実体の場所を確認し、sapi.dllとなっているものを選択する。
もう片方はsapi_onecore.dllとなっていたが、こちらはVBAから使えなかった。
参照設定させると、冒頭のGreetingは次のようになる。
Sub GreetingOnReference() With New SpVoice Set .Voice = .GetVoices().Item(0) .Speak "こんにちは" End With End Sub
あるいは変数を宣言しても良い。
以下は、型が分かるように逐一変数に入れた例。
Sub GreetingWithVariables() Dim greeter As SpVoice Set greeter = New SpVoice Dim speechVoice As ISpeechObjectToken Set speechVoice = greeter.GetVoices.Item(1) Set greeter.Voice = speechVoice greeter.Speak "Kon nichiwa" End Sub
何がしたかったのか
パソコンの連続使用はとても目に悪い。仕事では会議に行ったり上司に呼ばれたりして適宜モニターの前を離れることもあるけど、自宅で作業に没頭してしまうとついつい何時間もモニターを見つめ続けることになる。
そこで、一定時間ごとに音声で知らせてくれるような仕組みを作ろうと思ったのがきっかけ。
とりあえず最初はExcelで作ったのでそのまま記事にしたけれど、オブジェクトの使い方さえ分かればVBSへの移植は簡単。あとはタスクスケジューラに登録して一時間ごとに音声で休憩を促す。この辺りは次回の記事で書こうと思う。
きっかけは最近購入した以下の書籍。

ヘルシープログラマ ―プログラミングを楽しく続けるための健康Hack
- 作者:Joe Kutner
- 発売日: 2015/07/23
- メディア: 単行本(ソフトカバー)
その中に次の一節がある。
アメリカ労働安全衛生局によると、コンピュータを使う作業者が5分間の「ミニ休憩」を一日のうちに5回増やせば、痛みと眼精疲労が大きく減るのです。
なるほど。では1時間ごとに5分の休憩を取ろうと思ってこれを考えた。
ちなみにヘルシープログラマはわざわざエンジニアのために書かれた健康本である。「健康へのイテレーティブなアプローチ」などと、一般の方にはちょっと何言ってるか分からない用語が頻出し、ほとんど文字情報なので活字耐性のない非プログラマーは退屈するかもしれない。でも論理的に書かれていて、エンジニアには良い本だと思う。
2021/1/30 追記
以下のように音声を追加してみたところ、前述の方法では追加した音声が使用できないことが分かった。
調べたところ、OneCoreという別の場所に分類されてるらしく、コードを変更することで対応できるようだ。
以下、参考サイト
qiita.com
以下、サイトを参考に作ってみたコード。JamesとZiraとHarukaがそれぞれ文を読み分ける。
Sub JamesZiraHarukaSpeaksByExcelVBA() Dim sapi As Object, tokenCategory As Object Set sapi = CreateObject("SAPI.SpVoice") Set tokenCategory = CreateObject("SAPI.SpObjectTokenCategory") tokenCategory.SetID "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Speech_OneCore\Voices", False Dim James As Object Dim Zira As Object Dim Haruka As Object Dim token As Object For Each token In tokenCategory.EnumerateTokens If token.GetAttribute("Name") = "Microsoft James" Then Set James = token End If If token.GetAttribute("Name") = "Microsoft Zira" Then Set Zira = token End If If token.GetAttribute("Name") = "Microsoft Haruka" Then Set Haruka = token End If If Not (James Is Nothing Or Zira Is Nothing Or Haruka Is Nothing) Then Exit For Next Set sapi.Voice = James sapi.Speak "From Wikipedia Poisson's Ratio" sapi.Speak "In materials science and solid mechanics, " _ & "Poisson's ratio is a measure of the Poisson effect, " _ & "the deformation of a material in directions perpendicular to the direction of loading. " Set sapi.Voice = Zira sapi.Speak "The value of Poisson's ratio is the negative of the ratio of transverse strain to axial strain." sapi.Speak "For small values of these changes, " _ & "is the amount of transversal elongation divided by the amount of axial compression." Set sapi.Voice = Haruka sapi.Speak "以上で解説を終わります。ありがとうございました。" End Sub
以上