成果物

概要
- テキストボックスに任意テキストを入力する
Enterキーを押す- 任意テキストが音声合成される
QML
import QtQuick 2.0
import QtQuick.Window 2.0
import QtQuick.Controls 2.0
ApplicationWindow {
id: mainWindow
width: 500
height: 50
title: qsTr("Qt + PySide2 + PyOpenJTalk")
visible: true
locale: locale
Rectangle {
color: "#FFCCDD"
anchors.fill: parent
TextInput {
id: _talkText
text: "発話したいテキストを入力してからEnterキーを押してください。"
focus: true
font.pixelSize: Math.max(16, parent.width / 40)
anchors.fill: parent
onAccepted: Connect.talk(_talkText.text)
}
}
}
ポイントはイベント処理。QMLのイベントをPythonで実装する。このとき、どのようにしてQMLとPythonを連携するか。
QMLの以下がイベント処理する箇所である。Connectという名前はPython側でユーザが任意に定義している。詳細は後述。
onAccepted: Connect.talk(_talkText.text)
ソースコード
#!/usr/bin/env python3 # -*- coding: utf-8 -*- import os, sys, numpy, pyopenjtalk from PySide2.QtQml import QQmlApplicationEngine from PySide2.QtWidgets import QApplication from PySide2.QtQuick import QQuickView from PySide2.QtCore import QUrl, QObject, Slot import simpleaudio as sa class Connect(QObject): def __init__(self, parent=None): super().__init__(parent) @Slot(str) def talk(self, text): x, sr = pyopenjtalk.tts(text) ply = sa.play_buffer(x.astype(numpy.int16), 1, 2, sr) ply.wait_done() def Main(): app = QApplication(sys.argv) connect = Connect() engine = QQmlApplicationEngine() ctx = engine.rootContext() ctx.setContextProperty("Connect", connect) HERE = os.path.dirname(os.path.abspath(__file__)) UI = os.path.join(HERE, 'talker.qml') engine.load(UI) if not engine.rootObjects(): sys.exit(-1) sys.exit(app.exec_()) if __name__ == '__main__': Main()
ポイントとなるイベント処理はQQmlApplicationEngineで設定する。以下でConnectという名前をQML内で使えるようにしている。
ctx.setContextProperty("Connect", connect)
Connectという名前に紐づけたオブジェクトconnectは、クラスConnectのインスタンスである。
class Connect(QObject): def __init__(self, parent=None): super().__init__(parent) @Slot(str) def talk(self, text): ...
PySide2.QtCore.Slotでデコレートしたtalkメソッドがある。これがQMLで呼び出されている。
もう一度QMLをみてみる。テキストボックスの入力値をtalkメソッドの引数に渡している。つまり、テキストボックスに入力したテキストを発話する。
onAccepted: Connect.talk(_talkText.text)
所感
環境構築からここまで、非常に大変だった。
おそらくOSが変わったらまた環境構築コードを書き直さねばならない。
対象環境
- Raspbierry pi 4 Model B
- Raspberry Pi OS buster 10.0 2020-08-20 ※
- bash 5.0.3(1)-release
$ uname -a Linux raspberrypi 5.4.83-v7l+ #1379 SMP Mon Dec 14 13:11:54 GMT 2020 armv7l GNU/Linux