Windows環境で音声合成(音声読み上げ)


はじめに

WindowsAPIを使って、音声合成(音声読み上げ)処理を実装しました。

環境

ソースコード

音声合成には、SpeechSynthesizer クラスを使用しています。
.NET APIを利用するためにC++/CLIを経由しています。
英語はMicrosoft Zira Desktop、日本語はMicrosoft Haruka Desktopとそれぞれに適した音声で再生します。
ソースコードではコメントアウトしていますが、waveファイルへの出力も可能です。

speak.d
import std.stdio;
import std.utf;

extern (C++) {
    void speak(const(wchar)* phrase, const(wchar)* speaker, const(wchar)* filename = cast(wchar*)0);
}

void main()
{
    wstring phrase = "D is a general-purpose programming language with static typing, systems-level access, and C-like syntax.";
    writefln("input : %s", phrase);
    phrase.toUTF16z.speak("Microsoft Zira Desktop");
    phrase = "D言語は、静的かたづけ、システムレベルのアクセス、およびCのような構文を備えた汎用プログラミング言語です。";
    writefln("input : %s", phrase);
    phrase.toUTF16z.speak("Microsoft Haruka Desktop");
//  waveファイルに出力することも可能
//  phrase.toUTF16z.speak("Microsoft Haruka Desktop", "output.wav");
}
speechsynthesizer.cpp
#using <C:\Windows\Microsoft.NET\assembly\GAC_MSIL\System.Speech\v4.0_4.0.0.0__31bf3856ad364e35\System.Speech.dll>

using namespace System;
using namespace System::Speech::Synthesis;

void outputToWaveFile(char16_t const *phrase, char16_t const *speaker, char16_t const *filename)
{
    SpeechSynthesizer^ synth = gcnew SpeechSynthesizer();
    if ( filename != 0 ){
        synth->SetOutputToWaveFile(gcnew String(reinterpret_cast<wchar_t const*>(filename)));
    }
    synth->SelectVoice(gcnew String(reinterpret_cast<wchar_t const*>(speaker)));
    String^ p = gcnew String(reinterpret_cast<wchar_t const*>(phrase));
    synth->Speak(p);
}

void speak(char16_t const *phrase, char16_t const *speaker, char16_t const *filename = 0)
{
    outputToWaveFile(phrase, speaker, filename);
}

コンパイル、実行

x64 Native Tools Command Prompt for VS 2019を起動して、以下の順に実行します。
音声合成の技術は、思っていたより向上していて、いい感じに読み上げてくれました。
こんなに簡単に実装できたのにも驚きです。

コマンドプロンプト
**********************************************************************
** Visual Studio 2019 Developer Command Prompt v16.4.2
** Copyright (c) 2019 Microsoft Corporation
**********************************************************************
[vcvarsall.bat] Environment initialized for: 'x64'

d:\Dev> cl /clr /c speechsynthesizer.cpp
Microsoft(R) C/C++ Optimizing Compiler Version 19.24.28314
Microsoft (R) .NET Framework の場合 バージョン 4.08.4300.0
Copyright (C) Microsoft Corporation.  All rights reserved.

speechsynthesizer.cpp

d:\Dev> dmd -m64 -release -L=/NODEFAULTLIB:libcmt.lib speak.d speechsynthesizer.obj "C:\Program Files (x86)\Windows Kits\NETFXSDK\4.8\Lib\um\x64\mscoree.lib"

d:\Dev> chcp 65001
Active code page: 65001

d:\Dev> speak
input : D is a general-purpose programming language with static typing, systems-level access, and C-like syntax.
input : D言語は、静的かたづけ、システムレベルのアクセス、およびCのような構文を備えた汎用プログラミング言語です。

実験:隠れキャラ(?)の呼び出し

この実験ではレジストリの書き換えを行っています。推奨しているわけではありません。

.NET Framework 4.8環境のSpeechSynthesizer クラスで日本語読み上げに適した音声はMicrosoft Haruka Desktopしか用意されていません。
しかし、音声認識の音声選択ではMicrosoft AyumiMicrosoft Ichiroなる音声が存在します。

レジストリを探したところ、HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Speech_OneCore\Voices\Tokens以下に何か定義があります。さらに、そこにはMicrosoft Sayakaという隠れキャラ(?)まで存在しました。
これらの定義をHKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Speech\Voices\Tokens以下でも追加すれば、音声合成に使えるのではないかと思い、試しました。
結論として、これでうまく音声合成ができました。

以下、追加したレジストリ定義です。

ayumi.reg
Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Speech\Voices\Tokens\TTS_MS_JA-JP_AYUMI_11.0]
@="Microsoft Ayumi - Japanese (Japan)"
"411"="Microsoft Ayumi - Japanese (Japan)"
"CLSID"="{179F3D56-1B0B-42B2-A962-59B7EF59FE1B}"
"LangDataPath"=hex(2):25,00,77,00,69,00,6e,00,64,00,69,00,72,00,25,00,5c,00,53,\
  00,70,00,65,00,65,00,63,00,68,00,5f,00,4f,00,6e,00,65,00,43,00,6f,00,72,00,\
  65,00,5c,00,45,00,6e,00,67,00,69,00,6e,00,65,00,73,00,5c,00,54,00,54,00,53,\
  00,5c,00,6a,00,61,00,2d,00,4a,00,50,00,5c,00,4d,00,53,00,54,00,54,00,53,00,\
  4c,00,6f,00,63,00,6a,00,61,00,4a,00,50,00,2e,00,64,00,61,00,74,00,00,00
"VoicePath"=hex(2):25,00,77,00,69,00,6e,00,64,00,69,00,72,00,25,00,5c,00,53,00,\
  70,00,65,00,65,00,63,00,68,00,5f,00,4f,00,6e,00,65,00,43,00,6f,00,72,00,65,\
  00,5c,00,45,00,6e,00,67,00,69,00,6e,00,65,00,73,00,5c,00,54,00,54,00,53,00,\
  5c,00,6a,00,61,00,2d,00,4a,00,50,00,5c,00,4d,00,31,00,30,00,34,00,31,00,41,\
  00,79,00,75,00,6d,00,69,00,00,00

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Speech\Voices\Tokens\TTS_MS_JA-JP_AYUMI_11.0\Attributes]
"Age"="Adult"
"Gender"="Female"
"Language"="411"
"Name"="Microsoft Ayumi"
"SharedPronunciation"=""
"Vendor"="Microsoft"
"Version"="11.0"
ichiro.reg
Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Speech\Voices\Tokens\TTS_MS_JA-JP_ICHIRO_11.0]
@="Microsoft Ichiro - Japanese (Japan)"
"411"="Microsoft Ichiro - Japanese (Japan)"
"CLSID"="{179F3D56-1B0B-42B2-A962-59B7EF59FE1B}"
"LangDataPath"=hex(2):25,00,77,00,69,00,6e,00,64,00,69,00,72,00,25,00,5c,00,53,\
  00,70,00,65,00,65,00,63,00,68,00,5f,00,4f,00,6e,00,65,00,43,00,6f,00,72,00,\
  65,00,5c,00,45,00,6e,00,67,00,69,00,6e,00,65,00,73,00,5c,00,54,00,54,00,53,\
  00,5c,00,6a,00,61,00,2d,00,4a,00,50,00,5c,00,4d,00,53,00,54,00,54,00,53,00,\
  4c,00,6f,00,63,00,6a,00,61,00,4a,00,50,00,2e,00,64,00,61,00,74,00,00,00
"VoicePath"=hex(2):25,00,77,00,69,00,6e,00,64,00,69,00,72,00,25,00,5c,00,53,00,\
  70,00,65,00,65,00,63,00,68,00,5f,00,4f,00,6e,00,65,00,43,00,6f,00,72,00,65,\
  00,5c,00,45,00,6e,00,67,00,69,00,6e,00,65,00,73,00,5c,00,54,00,54,00,53,00,\
  5c,00,6a,00,61,00,2d,00,4a,00,50,00,5c,00,4d,00,31,00,30,00,34,00,31,00,49,\
  00,63,00,68,00,69,00,72,00,6f,00,00,00

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Speech\Voices\Tokens\TTS_MS_JA-JP_ICHIRO_11.0\Attributes]
"Age"="Adult"
"Gender"="Male"
"Language"="411"
"Name"="Microsoft Ichiro"
"SharedPronunciation"=""
"Vendor"="Microsoft"
"Version"="11.0"
sayaka.reg
Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Speech\Voices\Tokens\TTS_MS_JA-JP_SAYAKA_11.0]
@="Microsoft Sayaka - Japanese (Japan)"
"411"="Microsoft Sayaka - Japanese (Japan)"
"CLSID"="{179F3D56-1B0B-42B2-A962-59B7EF59FE1B}"
"LangDataPath"=hex(2):25,00,77,00,69,00,6e,00,64,00,69,00,72,00,25,00,5c,00,53,\
  00,70,00,65,00,65,00,63,00,68,00,5f,00,4f,00,6e,00,65,00,43,00,6f,00,72,00,\
  65,00,5c,00,45,00,6e,00,67,00,69,00,6e,00,65,00,73,00,5c,00,54,00,54,00,53,\
  00,5c,00,6a,00,61,00,2d,00,4a,00,50,00,5c,00,4d,00,53,00,54,00,54,00,53,00,\
  4c,00,6f,00,63,00,6a,00,61,00,4a,00,50,00,2e,00,64,00,61,00,74,00,00,00
"VoicePath"=hex(2):25,00,77,00,69,00,6e,00,64,00,69,00,72,00,25,00,5c,00,53,00,\
  70,00,65,00,65,00,63,00,68,00,5f,00,4f,00,6e,00,65,00,43,00,6f,00,72,00,65,\
  00,5c,00,45,00,6e,00,67,00,69,00,6e,00,65,00,73,00,5c,00,54,00,54,00,53,00,\
  5c,00,6a,00,61,00,2d,00,4a,00,50,00,5c,00,4d,00,31,00,30,00,34,00,31,00,53,\
  00,61,00,79,00,61,00,6b,00,61,00,00,00

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Speech\Voices\Tokens\TTS_MS_JA-JP_SAYAKA_11.0\Attributes]
"Age"="Adult"
"Gender"="Female"
"Language"="411"
"Name"="Microsoft Sayaka"
"SharedPronunciation"=""
"Vendor"="Microsoft"
"Version"="11.0"

レジストリ追加後の実装例

speak1.d
import std.stdio;
import std.utf;

extern (C++) {
    void speak(const(wchar)* phrase, const(wchar)* speaker, const(wchar)* filename = cast(wchar*)0);
}

void main()
{
    wstring phrase = "D言語は、静的かたづけ、システムレベルのアクセス、およびCのような構文を備えた汎用プログラミング言語です。";
    writefln("input : %s", phrase);
    phrase.toUTF16z.speak("Microsoft Haruka Desktop");
    phrase.toUTF16z.speak("Microsoft Ichiro");
    phrase.toUTF16z.speak("Microsoft Ayumi");
    phrase.toUTF16z.speak("Microsoft Sayaka");
}

参考情報

インストールされている .NET Framework バージョンを確認する
SpeechSynthesizer クラス