ノート読み上げを含むPowerPoint

音声での説明があった方が良いPowerPointのスライドを作る必要がある。

原稿はつくるとして自分で読み上げると、録音のための環境が整っていないので、周囲からの音が問題になった場合には、録音を繰り返さなければならない。面倒で時間がかかる。

自分の声である必要は必ずしもないので、音声合成を利用してノートの原稿を読み上げ、それをスライドに埋め込むことにした。音声の必要がなければノートを読めばよいし、ノートを読むのが面倒であれば音声を再生して聞けばよい。

Windowsで、VBAとText-to-Speech(TTS)エンジンを使って読み上げをするプログラムはあったが、複数のスライドを一括して処理するものが見つけられなかったので作成してみた。

環境

  • Windows 10 Home 1909
  • PowerPoint  for Microsoft 365 バージョン 2008 (ビルド 13127.20409) 64bit

音声合成で利用できる音声は次の通り。下記のVBAプログラムでは日本語の男性の声としてMicrosoft Ichiro が使われた。

プログラムを含むPowerPointファイル

スライドのノートを音声合成エンジンで読み上げたものをスライドに埋め込むことをすべてのスライドで行うVBAを利用したプログラムの例を示す。

VBAを利用しているのでマクロ実行を有効にしないと動作しない。

スライドショーを実行して最初のスライドにある「音声ファイルの作成・挿入」ボタンを押すと、読み上げた音声ファイルが埋め込まれる。

音声ファイルを一括して削除したい場合には、スライドショーを実行して、最初のスライドにある「音声ファイルの削除」ボタンを押す。

作成したPowerPointファイルをスライドショーにして、クリックなどでスライドを変えた場合に自動的に音声ファイルの再生を行うようにすると速く読み進めるのの邪魔になるので、例では、スライドの左上の再生ボタンを押さないと音声は出ないようにした。

VBAプログラム

「音声ファイルの作成・挿入」ボタンは、オブジェクト名 AddAudioFilesButton とした。スライドショーなどでボタンをクリックすると AddAudioFilesButton_Click() が呼び出される。そこから AddAudioFiles() が呼び出されて処理が進む。

「音声ファイルの削除」ボタンは、オブジェクト名 RemoveAudioFilesButton とした。スライドショーなどでボタンをクリックすると RemoveAudioFilesButton_Click() が呼び出される。そこから、RemoveAudioFiles() が呼び出されて処理が進む。

Private Sub AddAudioFilesButton_Click()
    Call AddAudioFiles
End Sub

Private Sub RemoveAudioFilesButton_Click()
    Call RemoveAudioFiles
End Sub

音声ファイルの作成・挿入

GetTtsEngine()で、指定された言語と性別の音声を合成できるText-To-Speech エンジンを取得する。

スライドを順番にみていき、ノート部分をMakeSpeechText() で必要に応じて編集して、MakeFileName()で音声ファイル名を生成し、Speak()で発生して、音声ファイルに保存する。

InsertAudio()で作成した音声ファイルをスライドに追加する。

Private Sub AddAudioFiles()
    ' 音声合成エンジンを取得する
    Dim ttsEngine As Object
    Set ttsEngine = GetTtsEngine("Japanese", "Male")

    ' 適切な音声エンジンが見つからなかった場合
    If ttsEngine Is Nothing Then
        ' 発見に失敗した旨をメッセージボックスで通知
        MsgBox "適切な日本語の音声が見つかりませんでした。"
        Exit Sub
    End If

    ' スライドのノートのテキストを取得して音声ファイルに変換する
    Dim aSlide As Slide
    Dim aShape As Shape
    Dim slideNo As Integer
    
    For Each aSlide In ActivePresentation.Slides
        slideNo = aSlide.slideNumber
        For Each aShape In aSlide.NotesPage.Shapes
            If aShape.PlaceholderFormat.Type = ppPlaceholderBody Then
                If aShape.HasTextFrame Then
                    If aShape.TextFrame.HasText Then
                        ' 発話テキスト
                        Dim speechText As String
                        strNotesText = aShape.TextFrame.TextRange.text
                        speechText = MakeSpeechText(strNotesText, slideNo)
                        ' ファイル名
                        Dim fileName As String
                        fileName = MakeFileName(slideNo)
                        ' 発声させてファイルを作成
                        Call Speak(ttsEngine, speechText, fileName)
                        ' ファイルをスライドに追加
                        Call InsertAudio(fileName, aSlide)
                    End If
                End If
            End If
        Next aShape
    Next aSlide
    
    ' 音声合成エンジンを解放する
    Set ttsEngine = Nothing
End Sub

音声ファイルの作成で利用されるプログラム

MakeSpeechTextは、テキストとスライド番号から発話用のテキストをつくる。スライド番号を使用している箇所はコメントアウトされていて使われていない。音声ファイルが正しくスライド番号と対応しているかをスライド番号を最初に読み上げることで確認する際に使用した。

Private Function MakeSpeechText(ByVal text As String, ByVal slideNumber As Integer)
    Dim speechText As String
    Dim prefixText As String
    
    '' ページ番号を最初に読み上げる?
    ''prefixText = Str(slideNumber) & "ページ。" & text
    prefixText = ""
        

    If text = "" Then
        ' 発話内容が空の場合には prefixTextも読まない
        speechText = ""
    Else
        ' 発話テキストを作成
        speechText = prefixText & text
    End If
    MakeSpeechText = speechText
End Function

Private Function MakeFileName(ByVal slideNumber As Integer)
    'ファイル名を作成
    fileName = "slide" & CStr(slideNumber) & ".wav"
    MakeFileName = fileName
End Function

Private Sub Speak(ByRef ttsEngine, ByVal speechText As String, ByVal fileName As String)
    Const SAFT8kHz8BitMono = 4
    Const SAFT48kHz16BitMono = 38
    Const SAFTGSM610_8kHzMono = 64
    Const SSFMCreateForWrite = 3 ' Creates file even if file exists and so destroys or overwrites the existing file

    Dim aFileStream
    
    Set aFileStream = CreateObject("SAPI.SpFileStream")
    ' 48kHz 16bit Mono PCM
    'aFileStream.Format.Type = SAFT48kHz16BitMono
    ' 8kHz GSM6.10 Mono (圧縮形式)
    'aFileStream.Format.Type = SAFTGSM610_8kHzMono
    ' 8kHz 8bit Mono PCM
    aFileStream.Format.Type = SAFT8kHz8BitMono
    
    ' ファイルの作成(存在したら上書き SSFMCreateForWrite)
    Call aFileStream.Open(fileName, SSFMCreateForWrite)
    'oFileStream.Open fileName, SSFMCreateForWrite
    ' オーディオストリームの出力をファイルに設定
    Set ttsEngine.AudioOutputStream = aFileStream
    
    ' 音声合成実行
    ttsEngine.Speak speechText
    
    ' ファイルを閉じる
    aFileStream.Close
End Sub

Private Function GetTtsEngine(language As String, gender As String) As Object
    ' 音声合成エンジンを取得する
    Dim ttsEngine As Object
    Set ttsEngine = CreateObject("SAPI.SpVoice")
    
    
    ' gender と language に合致する音声を探す (OneCoreを含めないでGetVoicesだけでは Ichiro が使えない)
    Set voice = Nothing
    Set Category = CreateObject("SAPI.SpObjectTokenCategory")
    Category.SetID "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Speech_OneCore\Voices", False
    For Each token In Category.EnumerateTokens
        If InStr(token.GetDescription, language) Then   '言語
            If token.GetAttribute("Gender") = gender Then   '性別
                Set voice = token
                Set ttsEngine.voice = voice
                Exit For
            End If
        End If
    Next

    If voice Is Nothing Then
        ' 目的の音声が見つからなかった場合
        Set ttsEngine = Nothing
    End If
    Set GetTtsEngine = ttsEngine
End Function

音声ファイルの挿入で利用されるプログラム

InsertAudioで指定の音声ファイルをスライドに追加する。

スライドが切り替わった際に音声ファイルが自動的に再生されるようした場合も試してみたが、利用形態に合わないと思われるのでコメントアウトしている。音声の自動再生を有効にする場合には、再生ボタンがスライドショーの時に見えないようにしても良い。

Sub InsertAudio(fileName As String, aSlide As Slide)
    Dim aShape As Shape
    'Dim anEffect As Effect
    
    ' 音声ファイルをスライドに追加する
    '' False, True で音声ファイルをPowerPointに埋め込む
    '' 10,10 は再生ボタンの座標(x=10,y=10で左上に表示されるはず)
    Set aShape = aSlide.Shapes.AddMediaObject2(fileName, False, True, 10, 10)
    
    ' 音声ファイルが自動的に再生されるようにする
    'Set anEffect = aSlide.TimeLine.MainSequence.AddEffect(aShape, msoAnimEffectMediaPlay, , msoAnimTriggerWithPrevious)
    '' anEffect.MoveTo 1 '一番最初のエフェクトにする
    
    'スライド ショーの実行時は再生時にのみ出力される
    'anEffect.EffectInformation.PlaySettings.HideWhileNotPlaying = True
End Sub

音声ファイルの削除

スライドを順番にみていき、サウンドファイルがあったら削除する。

Private Sub RemoveAudioFiles()
    ' スライドからメディア(音声)ファイルを削除する
    Dim aSlide As Slide
    Dim aShape As Shape
    
    For Each aSlide In ActivePresentation.Slides
        For Each aShape In aSlide.Shapes
            If aShape.Type = msoMedia Then
                If aShape.MediaType = ppMediaTypeSound Then ' サウンドファイル
                    ' 音声ファイルを削除
                    aShape.Delete
                End If
            End If
        Next aShape
    Next aSlide
End Sub

コメント

  1. 古橋武 より:

    薫染庵様

    先ほどお送りしましたコメントは、改行コードが無視されているため、段落が連なった長文となってしまいました。改行コードの入れ方が分からないので、段落間に全角のスペースを入れた文を、以下に再送いたします。                          

    薫染庵様

      初めまして。

      貴サイトのプログラムを基に、図形のグループ化とアニメーション設定、ノート読み上げ、wavファイル埋め込みとアニメーション設定をワンクリックでできるマクロを作ることができました。これらの一連の操作に多くの時間を取られていたために(胃が少しおかしくなりかけていたために)、必要に迫られて貴プログラムを核にして、改変を進めてまいりました。お陰様で、講義資料のコンテンツ造りに専念できる環境を得ることができました。貴重なプログラムの公開をありがとうございました。

      つきましては、拙プログラムの公開サイトで貴サイトとのリンクを張らせていただきたくお願い申し上げます。また、貴プログラムをコピー・改変させていただいた箇所にはその旨と貴サイトのURLを記させていただいております。もし、差支えがありましたら、お手数をおかけして申し訳ございませんが、ご返信いただけましたら幸いです。

      拙プログラムの開発は、貴プログラムをはじめとしてネット上の様々なサイトのプログラムサンプルのお陰で進めることができました。オブジェクト指向のVBAもYouTubeで勉強しながらの心もとないレベルですが、多少は恩返しができるかなと思い、拙プログラムを公開する次第です。よろしく、ご高配のほどお願い申し上げます。

    • epi より:

      古橋武様
      このサイトのプログラムが多少なりとも参考になったとすればうれしく思います。
      リンクは自由に張っていただいて構いません。リンクは許諾不要と考えております。
      また、役に立つプログラムを公開いただきありがとうございます (http://www.mybook-pub-site.sakura.ne.jp/Macro_for_Note_Reading/)。Microsoftの日本語の音声合成の質はいま一つなので、他の音声合成エンジンが使えるとプレゼンテーションなどの質の向上につながると思います。