blechmusikの日記

いろいろなことを書いています。

一定時間毎に時刻を読み上げる AutoHotkey_L 用スクリプトを作成した

「テキスト音声合成ミドルウェア AquesTalk を使って時報」が興味深い - blechmusik2の日記で取り上げたsoftware / AutoHotkey スレッド part10のレス 12 の設定をもとに、一定時間毎に時刻を読み上げるスクリプトを作成した。元のスクリプトと同様に、AquesTalk2 - テキスト音声合成ミドルウェアを使用する AutoHotkey_L (Unicode ver.) 用スクリプトだ。まず、AQUEST Downloadの "AquesTalk2" にあるソフト"AquesTalk2 Win"(現時点のパッケージ名は "aqtk2_100121.zip" である)をダウンロードする。つぎに、ダウンロードしたパッケージを展開する。そして、展開したフォルダを AquesTalk2\bin と辿っていき、そこにある "AquesTalk2Da.dll" をコピーする。あとは、これを以下のスクリプトと同じフォルダに入れて、以下のスクリプトを実行するだけだ。このスクリプトを使用すれば、パソコンの時計を全く見なくとも、定期的に時刻を知ることができる。時間を気にしながらパソコンを触っているならば、それなりに役立つスクリプトだろう。
現在のところ、何分おきに時報を読み上げるかを指定できるようにしている。この設定は毎時0分になるとはじめから数え直すようにしている。どういうことか説明しよう。時間設定として 20 分毎とすれば、毎時0分、20分、40分に時報を読み上げる。 15 分毎とすれば、毎時0分、15分、30分、45分に時報を読み上げる。では、25 分毎とするならばいつ時報を読み上げるのだろう。このときには、毎時0分、25分、50分に読み上げる。このような振る舞いが適切かと問われると答えに窮してしまう。まあ、この仕様については将来の課題としよう。
問題は、時刻の読みあげに不自然さが残っている点だ。具体的には、読み上げ時にピッチを下げたり上げたりする動作に課題がある。AquesTalk2 - テキスト音声合成ミドルウェアをうまく使用することで、日本語をより自然に読み上げるよう設定できよう。ただ、具体的にどこをどう変更すればよいかを整理できていない。追って修正したい。

;;; 「ネタ: テキスト音声合成ミドルウェア AquesTalk を使って時報」
;;; software / AutoHotkey スレッド part10
;;; http://p2.chbox.jp/read.php?url=http%3A//pc12.2ch.net/test/read.cgi/software/1265518996/12

;;; 数字の読み方については、
;;; NHK 放送文化研究所編『NHK ことばのハンドブック第2版』「数字の発音」の「分〔フン〕」(p. 358)を参照。
;;; Amazon.co.jp: NHKことばのハンドブック: NHK放送文化研究所, 日本放送協会放送文化研究所=: 本
;;; http://www.amazon.co.jp/dp/4140112182

#SingleInstance

;; 待機時間を設定する
every_min := 20

if ( every_min = 0 )
    msgbox,Error!



Loop
{
    TalkTime( every_min )

    ;; 待機時間を設定する
    sleep_min := ( every_min = "1" ) ? 0
              :  ( Mod(A_Min, every_min) = 0 ) ? (every_min - 1)
              :                                  (every_min - 1) - ( Mod(A_Min, every_min) )
    sleep_sec := (60 - A_Sec) + (60 * sleep_min)

    Sleep, % sleep_sec * 1000
}
return



TalkTime( every_min )
{
    hour := A_Hour
    min  := A_Min

    ;; 0 時のときには 0 を読み上げるよう設定する
    ;; そうしないと、0 時のときに時間を読み上げなくなってしまう
    hour := ( hour = "00" ) ? 0
         :                    LTrim(hour, "0")


    ;; 「ふん」か「ぷん」かを判断するために
    ;; 分の一桁目を取得
    min_one_digit := Mod(min, 10)
    ;; 分の二桁目を取得
    min_two_digits := min
    EnvDiv, min_two_digits, 10


    ;; 10 分以上のとき
    if ( min_two_digits )
    {
        if ( min_one_digit = 0 )
        {
            min := ( min_two_digits = 1) ? "じっ"
                :  ( min_two_digits = 2) ? "にじ'っ"
                :  ( min_two_digits = 3) ? "さんじ'っ"
                :  ( min_two_digits = 4) ? "よんじ'っ"
                :  ( min_two_digits = 5) ? "ごじ'っ"
                :                          0

            hun_pun := "ぷん"
        }
        else
        {
            min := ( min_two_digits = 1) ? "じゅー/"
                :  ( min_two_digits = 2) ? "に'じゅー/"
                :  ( min_two_digits = 3) ? "さ'んじゅー/"
                :  ( min_two_digits = 4) ? "よ'んじゅー/"
                :  ( min_two_digits = 5) ? "ご'じゅー/"
                :                          0

            min .= ( min_one_digit = 1 ) ? "い'っ"
                :  ( min_one_digit = 2 ) ? "に'"
                :  ( min_one_digit = 3 ) ? "さ'ん"
                :  ( min_one_digit = 4 ) ? "よ'ん"
                :  ( min_one_digit = 5 ) ? "ご'"
                :  ( min_one_digit = 6 ) ? "ろ'っ"
                :  ( min_one_digit = 7 ) ? "な'な"
                :  ( min_one_digit = 8 ) ? ";は'っ"
                :  ( min_one_digit = 9 ) ? "きゅ'ー"
                :                          0

            hun_pun := which_hun_pun( min_one_digit )
        }
    }
    else
    {
        min := ( min_one_digit = 1 ) ? "い'っ"
            :  ( min_one_digit = 2 ) ? "に'"
            :  ( min_one_digit = 3 ) ? "さ'ん"
            :  ( min_one_digit = 4 ) ? "よ'ん"
            :  ( min_one_digit = 5 ) ? "ご'"
            :  ( min_one_digit = 6 ) ? "ろ'っ"
            :  ( min_one_digit = 7 ) ? "な'な"
            :  ( min_one_digit = 8 ) ? ";は'っ"
            :  ( min_one_digit = 9 ) ? "きゅ'ー"
            :                          "れ'ー"

        hun_pun := which_hun_pun( min_one_digit )
    }


    hour := RegExReplace(hour, "っ", "、", "", -1)
    min  := RegExReplace(min,  "っ", "、", "", -1)
    hun_pun  := RegExReplace(hun_pun,  "ぷん", ";ぷ'ん", "", -1)


    Talk("<NUMK VAL=" hour ">じ、" min . hun_pun )

    return
}

which_hun_pun( min_one_digit )
{
    hun_pun := ( min_one_digit = 1 ) ? "ぷん"
            :  ( min_one_digit = 2 ) ? "ふん"
            :  ( min_one_digit = 3 ) ? "ぷん"
            :  ( min_one_digit = 4 ) ? "ふん"
            :  ( min_one_digit = 5 ) ? "ふん"
            :  ( min_one_digit = 6 ) ? "ぷん"
            :  ( min_one_digit = 7 ) ? "ふん"
            :  ( min_one_digit = 8 ) ? "ぷん"
            :  ( min_one_digit = 9 ) ? "ふん"
            :                          "ふん"

    return hun_pun
}

; phrase: 喋る内容(音声記号列という名の文字列)
; speed:速さ(遅50〜300速)
; sync:喋り終わるまで待つかどうか(真偽値)
Talk(phrase, speed=100, sync=true) {
    static hModule, hMe
    If (!hModule) {
        hModule := DllCall("LoadLibrary", "Str", "AquesTalk2Da.dll", "Ptr")
        hMe := DllCall("AquesTalk2Da\AquesTalk2Da_Create", "Ptr") ; 合成エンジン作成
    }
    If (sync) {
        Return DllCall("AquesTalk2Da\AquesTalk2Da_PlaySync", "AStr", phrase, "Int", speed, "UInt", 0, "Int")
    } Else {
        If DllCall("AquesTalk2Da\AquesTalk2Da_IsPlay", "Ptr", hMe, "Int") ; 喋り中なら
            DllCall("AquesTalk2Da\AquesTalk2Da_Stop", "Ptr", hMe) ; 止める
        Return DllCall("AquesTalk2Da\AquesTalk2Da_Play", "Ptr", hMe, "AStr", phrase, "Int", speed, "UInt", 0, "UInt", 0, "UInt", 0, "UInt", 0, "Int")
    }
}