質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

91.25%

  • Python

    4189questions

    Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

  • Python 3.x

    2745questions

    Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

  • Python 2.7

    974questions

    Python 2.7は2.xシリーズでは最後のメジャーバージョンです。Python3.1にある機能の多くが含まれています。

OpenJtalkを並列化したいので既存コードを書き直したが,動かない

解決済

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 43

WTH_0655

score 1

前提・実現したいこと

Raspberry PiでOpenJtalkを動かしたのですが,おそすぎるため,調べたところ,文を句読点ごとに区切り,それぞれ処理を並列化し
最終的に再生することで高速化を図るというものがありました
ただし,いちいちテキストファイルにしなければならないので
これをPythonのモジュールにしようと思い,
テキストを受取るようクラスにしてみましたが,なぜかずっと"音声合成の完了待ちです"となってしまい,
処理が終わりません(Python3.5)

少し調査すると,下の""正常に動くコード""はPython2.7ならばうまくいくようで,python3.5だと音声合成の完了待ちです,がずっと続き同じようになります
おそらく互換性がないのか,それ以上はわたしの知識ではわかりませんでした

""ずっと"音声合成の完了待ちです"""のコードはpython2.7,python3.5でもどちらも動きませんでした

該当のソースコード

######################ずっと"音声合成の完了待ちです"となる(Python2.7,Python3.5どちらも音声合成中になる)
class OutSpeak():
    # デバッグフラグ
    DEBUG = True

    # 音声合成の同時処理数
    MAX_PROCESS = 3

    # open_jtalkコマンドの場所
    JTALK = '/usr/bin/open_jtalk'

    # aplayコマンドの場所
    APLAY = '/usr/bin/aplay'

    # 辞書ディレクトリ
    DICDIR = "/var/lib/mecab/dic/open-jtalk/naist-jdic"

    # 音声ファイル
    # VOICE = '/home/pi/openjtalk/hts_voice/nitech_jp_atr503_m001.htsvoice'
    # VOICE = '/home/pi/openjtalk/hts_voice/omoine_ikuru.htsvoice'
    # VOICE = '/home/pi/openjtalk/hts_voice/syane_homu.htsvoice'
    # VOICE = '/home/pi/openjtalk/hts_voice/suranki.htsvoice'
    VOICE = '/home/pi/OpenJtalk/mei_normal.htsvoice'
    # VOICE = '/home/pi/openjtalk/hts_voice/mei_happy.htsvoice'

    # 話す速度(標準 1.0。0.0以上の値を指定)
    SPEED = 1.0

    # additional half-tone
    TONE = 2.0

    # ボリューム
    VOLUME = 10.0

    alltext=""

    # 作業ディレクトリ
    WORKDIR = "/home/pi/"

    def _print(self,message):
        if self.DEBUG:
            print(message)

    # 音声合成を実行する
    #
    def create_wav(self,t):
        import subprocess
        self._print("DEBUG: 音声作成開始[%d:%s]" % (t[0], t[1]))
        # サブプロセス呼び出し
        outfile = self.WORKDIR + "talk%02d.wav" % t[0]
        # -g という引数はエラーが出るので削除
        c = subprocess.Popen(
            [self.JTALK, '-x', self.DICDIR, '-m', self.VOICE, '-ow', outfile, '-r', str(self.SPEED), '-fm', str(self.TONE)], stdin=subprocess.PIPE)
        # 音声合成するテキストを入力
        c.stdin.write(t[1])
        # 終了を待つ
        c.stdin.close()
        c.wait()
        self._print("DEBUG: 音声作成終了[%d:%s]" % (t[0], t[1]))
        t[2].put(t[0])
        return c.returncode

    def play_wav(self,listindex):


        import subprocess
        command = list()
        command.append(self.APLAY)
        command.append('-q')
        for index in listindex:
            command.append(self.WORKDIR + "talk%02d.wav" % index)
        return subprocess.Popen(command)

    def Speak(self,text):


        self.alltext=text
        import re,time
        from multiprocessing import Pool, Manager
        queue = Manager().Queue()

        # テキストを短文に分割。テキストに連番を振ってリストにしておく。
        index = 0
        arg = list()
        #alltextに "." ","が含まれていたらそれを日本語の句読点に変換
        self.alltext.replace(".","。")
        self.alltext.replace(",","、")
        shorttext = re.split(r'、|。', self.alltext)
        for s in shorttext:
            if s != "":
                arg.append((index, s, queue))
                index += 1
        self._print("DEBUG: %d個に分割しました。" % len(arg))
        # プロセスプールを作成
        p = Pool(self.MAX_PROCESS)

        # 音声合成を開始
        r = p.map_async(self.create_wav, arg)

        # 音声合成の進捗リスト。0は未完了、1は音声合成済み。
        l = [0 for i in range(len(arg))]

        # 終端の判断のため-1を付加。
        l.append(-1)

        nowplaying = -1

        # 現在再生中のaplayコマンドのProcess
        playing = None

        # 進捗を確認しつつ音声を読み上げる
        while (not r.ready()) or (nowplaying != len(arg)) or (playing is not None):
            time.sleep(0.5)
            # 音声合成の終了報告があるかキューを確認する。
            for _ in range(queue.qsize()):
                compiled_index = queue.get()
                l[compiled_index] = 1
            # 再生できるならしてみる?
            if nowplaying < len(arg):
                if playing is None:
                    if l[nowplaying + 1] == 1:
                        # まとめてWAVファイルを指定できるときはする
                        listindex = list()
                        while l[nowplaying + 1] == 1:
                            nowplaying += 1
                            listindex.append(nowplaying)
                        self._print("DEBUG: しゃべるよ![%s]" % str(listindex))
                        playing = self.play_wav(listindex)
                    elif l[nowplaying + 1] == 0:
                        self._print("DEBUG: 音声合成の完了待ちです!")
                    else:
                        exit()
                else:
                    if playing.poll() is not None:
                        playing = None
#######################正常に動くコード(Python3.5ではずっと音声合成中になる)
# coding: UTF-8
import sys
import subprocess
import re
import time
from multiprocessing import Pool, Manager

# デバッグフラグ
DEBUG = True

# 音声合成の同時処理数
MAX_PROCESS = 3

# open_jtalkコマンドの場所
JTALK = '/usr/bin/open_jtalk'

# aplayコマンドの場所
APLAY = '/usr/bin/aplay'

# 辞書ディレクトリ
DICDIR = "/var/lib/mecab/dic/open-jtalk/naist-jdic"

# 音声ファイル
# VOICE = '/home/pi/openjtalk/hts_voice/nitech_jp_atr503_m001.htsvoice'
# VOICE = '/home/pi/openjtalk/hts_voice/omoine_ikuru.htsvoice'
# VOICE = '/home/pi/openjtalk/hts_voice/syane_homu.htsvoice'
# VOICE = '/home/pi/openjtalk/hts_voice/suranki.htsvoice'
VOICE = '/home/pi/OpenJtalk/mei_normal.htsvoice'
# VOICE = '/home/pi/openjtalk/hts_voice/mei_happy.htsvoice'

# 話す速度(標準 1.0。0.0以上の値を指定)
SPEED = 1.0

# additional half-tone
TONE = 2.0

# ボリューム
VOLUME = 10.0

# 作業ディレクトリ
WORKDIR = "/home/pi/"


def _print(message):
        if DEBUG:
               print(message)


#
# 音声合成を実行する
#
def create_wav(t):
        _print("DEBUG: 音声作成開始[%d:%s]" % (t[0], t[1]))
        # サブプロセス呼び出し
        outfile = WORKDIR + "talk%02d.wav" % t[0]
        c = subprocess.Popen(
                [JTALK, '-x', DICDIR, '-m', VOICE, '-ow', outfile, '-r', str(SPEED), '-fm', str(TONE)], stdin=subprocess.PIPE)
        # 音声合成するテキストを入力
        c.stdin.write(t[1])
        # 終了を待つ
        c.stdin.close()
        c.wait()
        _print("DEBUG: 音声作成終了[%d:%s]" % (t[0], t[1]))
        t[2].put(t[0])
        return c.returncode


#
# 音声を(複数まとめて)再生する
#
def play_wav(listindex):
        command = list()
        command.append(APLAY)
        command.append('-q')
        for index in listindex:
                command.append(WORKDIR + "talk%02d.wav" % index)
        return subprocess.Popen(command)


#######################################
# 入力
#######################################
# 引数を取り込み
argvs = sys.argv

# 簡単な引数チェック
if (len(argvs) != 2):
        print
        'Usage: # %s textfile' % argvs[0]
        exit(1)

# 指定されたファイルを読み込み
alltext = ""
for line in open(argvs[1]):
        alltext += line.rstrip()

# 音声合成の進捗を確認するためのキューを作成
queue = Manager().Queue()

# テキストを短文に分割。テキストに連番を振ってリストにしておく。
index = 0
arg = list()
shorttext = re.split(r'、|。', alltext)
for s in shorttext:
        if s != "":
                arg.append((index, s, queue))
                index += 1
_print("DEBUG: %d個に分割しました。" % len(arg))

#######################################
# 合成
#######################################
# プロセスプールを作成
p = Pool(MAX_PROCESS)

# 音声合成を開始
r = p.map_async(create_wav, arg)

# 音声合成の進捗リスト。0は未完了、1は音声合成済み。
l = [0 for i in range(len(arg))]

# 終端の判断のため-1を付加。
l.append(-1)

#######################################
# 再生
#######################################
# 現在再生中の音声のインデックス
nowplaying = -1

# 現在再生中のaplayコマンドのProcess
playing = None

# 進捗を確認しつつ音声を読み上げる
while (not r.ready()) or (nowplaying != len(arg)) or (playing is not None):
        time.sleep(0.5)
        # 音声合成の終了報告があるかキューを確認する。
        for _ in range(queue.qsize()):
                compiled_index = queue.get()
                l[compiled_index] = 1
        # 再生できるならしてみる?
        if nowplaying < len(arg):
                if playing is None:
                        if l[nowplaying + 1] == 1:
                                # まとめてWAVファイルを指定できるときはする
                                listindex = list()
                                while l[nowplaying + 1] == 1:
                                        nowplaying += 1
                                        listindex.append(nowplaying)
                                _print("DEBUG: しゃべるよ![%s]" % str(listindex))
                                playing = play_wav(listindex)
                        elif l[nowplaying + 1] == 0:
                                _print("DEBUG: 音声合成の完了待ちです!")
                        else:
                                exit()
                else:
                        if playing.poll() is not None:
                                playing = None

補足情報(言語/FW/ツール等のバージョンなど)

参考サイト:
http://windvoice.hatenablog.jp/entry/2015/02/22/165457
Raspberry Pi 2 stretch 

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

check解決した方法

0

引数に文字列を入れることで"擬似的に"(システムコールによって)
呼び出すことにしました
IOアクセスによるオーバヘッドは少なくなると思います

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

ただいまの回答率

91.25%

関連した質問

同じタグがついた質問を見る

  • Python

    4189questions

    Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

  • Python 3.x

    2745questions

    Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

  • Python 2.7

    974questions

    Python 2.7は2.xシリーズでは最後のメジャーバージョンです。Python3.1にある機能の多くが含まれています。