t-hom’s diary

主にVBAネタを扱っているブログ…とも言えなくなってきたこの頃。

Excel VBAで音声読み上げ

今回は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となっているものを選択する。
f:id:t-hom:20180103153150p:plain

もう片方は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

ヘルシープログラマ ―プログラミングを楽しく続けるための健康Hack

  • 作者:Joe Kutner
  • 発売日: 2015/07/23
  • メディア: 単行本(ソフトカバー)

その中に次の一節がある。

アメリカ労働安全衛生局によると、コンピュータを使う作業者が5分間の「ミニ休憩」を一日のうちに5回増やせば、痛みと眼精疲労が大きく減るのです。

なるほど。では1時間ごとに5分の休憩を取ろうと思ってこれを考えた。

ちなみにヘルシープログラマはわざわざエンジニアのために書かれた健康本である。「健康へのイテレーティブなアプローチ」などと、一般の方にはちょっと何言ってるか分からない用語が頻出し、ほとんど文字情報なので活字耐性のない非プログラマーは退屈するかもしれない。でも論理的に書かれていて、エンジニアには良い本だと思う。

2021/1/30 追記

以下のように音声を追加してみたところ、前述の方法では追加した音声が使用できないことが分かった。
f:id:t-hom:20210130182227p:plain

調べたところ、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

以上

当ブログは、amazon.co.jpを宣伝しリンクすることによってサイトが紹介料を獲得できる手段を提供することを目的に設定されたアフィリエイト宣伝プログラムである、 Amazonアソシエイト・プログラムの参加者です。