13
9

More than 3 years have passed since last update.

Rust/WinRTで音声合成

Last updated at Posted at 2020-06-22

Rust/WinRT の存在を知ったので、音声合成を試します。

この記事のコードは以下のリポジトリに掲載しています。

他の言語での利用については以下の記事を参照してください。

Rust/WinRT

Microsoft が GitHub で公開しています。

こちらの記事で Rust/WinRT の存在を知りました。

紹介記事です。

Microsoft が C++ の代替として使えるように Rust を整備しているという印象を受けました。

Windows の音声合成

Windows 10 でサポートされる音声の一覧です。

日本語以外の言語を使用する場合は追加します。

今回はすべての言語を追加した状態でテストします。

音声一覧

どこか適当なディレクトリでパッケージを作成します。

cargo new voices --bin

以下のファイルが生成されます。

  • voices/Cargo.toml
  • voices/src/main.rs

Cargo.toml の [dependencies] の後に依存パッケージを追記します。

winrt = "0.7"

コードを記述します。

src/main.rs
winrt::import!(
    dependencies
        os
    types
        windows::media::speech_synthesis::*
);

use windows::media::speech_synthesis::*;

fn main() -> winrt::Result<()> {
    for voice in SpeechSynthesizer::all_voices()? {
        println!("{}: {}", voice.language()?, voice.description()?);
    }
    Ok(())
}

cargo run でビルドして実行します。

実行結果
fr-FR: Microsoft Hortense - French (France)
en-GB: Microsoft George - English (United Kingdom)
en-US: Microsoft David - English (United States)
es-ES: Microsoft Pablo - Spanish (Spain)
de-DE: Microsoft Stefan - German (Germany)
it-IT: Microsoft Cosimo - Italian (Italy)
en-AU: Microsoft Catherine - English (Australia)
en-CA: Microsoft Linda - English (Canada)
ca-ES: Microsoft Herena - Catalan (Catalan)
en-GB: Microsoft Hazel - English (United Kingdom)
en-GB: Microsoft Susan - English (United Kingdom)
en-IN: Microsoft Heera - English (India)
da-DK: Microsoft Helle - Danish (Denmark)
en-US: Microsoft Zira - English (United States)
es-ES: Microsoft Helena - Spanish (Spain)
es-ES: Microsoft Laura - Spanish (Spain)
de-DE: Microsoft Hedda - German (Germany)
es-MX: Microsoft Sabina - Spanish (Mexico)
fi-FI: Microsoft Heidi - Finnish (Finland)
fr-CA: Microsoft Caroline - French (Canada)
de-DE: Microsoft Katja - German (Germany)
fr-FR: Microsoft Julie - French (France)
hi-IN: Microsoft Kalpana - Hindi (India)
ja-JP: Microsoft Ayumi - Japanese (Japan)
it-IT: Microsoft Elsa - Italian (Italy)
ar-EG: Microsoft Hoda - Arabic (Egypt)
ja-JP: Microsoft Haruka - Japanese (Japan)
ko-KR: Microsoft Heami - Korean (Korean)
pl-PL: Microsoft Paulina - Polish (Poland)
pt-BR: Microsoft Maria - Portuguese (Brazil)
pt-PT: Microsoft Helia - Portuguese (Portugal)
ru-RU: Microsoft Irina - Russian (Russia)
zh-CN: Microsoft Huihui - Chinese (Simplified, PRC)
zh-CN: Microsoft Yaoyao - Chinese (Simplified, PRC)
zh-HK: Microsoft Tracy - Chinese (Traditional, Hong Kong S.A.R.)
zh-TW: Microsoft Hanhan - Chinese (Traditional, Taiwan)
zh-TW: Microsoft Yating - Chinese (Traditional, Taiwan)
he-IL: Microsoft Asaf - Hebrew (Israel)
hi-IN: Microsoft Hemant - Hindi (India)
de-AT: Microsoft Michael - German (Austria)
hr-HR: Microsoft Matej - Croatian (Croatia)
hu-HU: Microsoft Szabolcs - Hungarian (Hungary)
id-ID: Microsoft Andika - Indonesian (Indonesia)
en-US: Microsoft Mark - English (United States)
en-AU: Microsoft James - English (Australia)
de-CH: Microsoft Karsten - German (Switzerland)
en-CA: Microsoft Richard - English (Canada)
ja-JP: Microsoft Ichiro - Japanese (Japan)
ar-SA: Microsoft Naayf - Arabic (Saudi)
ms-MY: Microsoft Rizwan - Malay (Malaysia)
nb-NO: Microsoft Jon - Norwegian (Bokmål)
nl-BE: Microsoft Bart - Dutch (Belgium)
nl-NL: Microsoft Frank - Dutch (Netherlands)
pl-PL: Microsoft Adam - Polish (Poland)
es-MX: Microsoft Raul - Spanish (Mexico)
pt-BR: Microsoft Daniel - Portuguese (Brazil)
cs-CZ: Microsoft Jakub - Czech (Czech Republic)
bg-BG: Microsoft Ivan - Bulgarian (Bulgaria)
ro-RO: Microsoft Andrei - Romanian (Romania)
en-IE: Microsoft Sean - English (Ireland)
ru-RU: Microsoft Pavel - Russian (Russia)
sk-SK: Microsoft Filip - Slovak (Slovakia)
sl-SI: Microsoft Lado - Slovenian (Slovenia)
sv-SE: Microsoft Bengt - Swedish
ta-IN: Microsoft Valluvar - Tamil (India)
th-TH: Microsoft Pattara - Thai (Thailand)
tr-TR: Microsoft Tolga - Turkish (Turkey)
vi-VN: Microsoft An - Vietnamese (Vietnam)
fr-CA: Microsoft Claude - French (Canada)
zh-CN: Microsoft Kangkang - Chinese (Simplified, PRC)
fr-CH: Microsoft Guillaume - French (Switzerland)
zh-HK: Microsoft Danny - Chinese (Traditional, Hong Kong S.A.R.)
el-GR: Microsoft Stefanos - Greek (Greece)
en-IN: Microsoft Ravi - English (India)
fr-FR: Microsoft Paul - French (France)
zh-TW: Microsoft Zhiwei - Chinese (Traditional, Taiwan)

以下の2つの音声が取得できませんが、これは C# でも同じなので Rust 特有の問題ではありません。

取得できなかった音声
fr-CA: Microsoft Nathalie - French (Canada)
ja-JP: Microsoft Sayaka - Japanese (Japan)

これらは音声の設定にも現れませんが、Chromium 版 Edge では使えます。隠れキャラなのでしょうか。

音声合成

音声を指定してしゃべらせます。

winrt::import!(
    dependencies
        os
    types
        windows::media::core::*
        windows::media::playback::*
        windows::media::speech_synthesis::*
);

use windows::media::core::*;
use windows::media::playback::*;
use windows::media::speech_synthesis::*;

fn set_voice(synthesizer: &SpeechSynthesizer, v: &str) -> winrt::Result<()> {
    for voice in SpeechSynthesizer::all_voices()? {
        if voice.display_name()? == v {
            synthesizer.set_voice(voice)?;
            break;
        }
    }
    Ok(())
}

fn main() -> winrt::Result<()> {
    let voice = "Microsoft Ichiro";
    let text  = "こんにちは、世界";
    let synthesizer = SpeechSynthesizer::new()?;
    set_voice(&synthesizer, &voice)?;
    let stream = synthesizer.synthesize_text_to_stream_async(text)?.get()?;
    let player = MediaPlayer::new()?;
    let content_type = stream.content_type()?;
    player.set_source(MediaSource::create_from_stream(stream, content_type)?)?;
    player.play()?;
    loop {
        std::thread::sleep(std::time::Duration::from_millis(200));
        if player.playback_session()?.playback_state()? != MediaPlaybackState::Playing {
            break;
        }
    };
    Ok(())
}

※ 再生の終了を待つループがやっつけです。

感想

コンパイル時に WinRT の型を Rust で使えるように投影(変換)するようですが、かなり時間が掛かります。ソースを修正して再度ビルドするのがかなりストレスです。まだプレビュー版とのことなので、今後の開発に期待したいです。

F# では WinRT がうまく使えませんが、先に Rust で使えるようになったのは意外でした。WinRT は COM ベースのため .NET に限定されないことを実感しました。

※ 開発中の C#/WinRT によって F# も改善する見込みです。

Go ではもっと直接 COM を触るようです。従来の COM との違いにも言及されていて興味深いです。

Excel等のCOMオブジェクトにはIDispatchが実装してあるため、メソッド名を文字列で渡すことで呼び出すことができます。これはgo-oleでもサポートされており便利な機能なのですが、WinRTにはこのIDispatchが実装されていません。メタデータを使用するのがWinRTの方針のようです。

IDispatch が実装されていないため、残念ながら以下の記事の手法でインターフェース名を取得することはできませんでした。

13
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
9