成果物
概要
- テキストボックスに任意テキストを入力する
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