Commit b1034ab5 authored by Jeremy Whiting's avatar Jeremy Whiting
Browse files

Add engine and voice selection to KMouth default system.

Also separate QtSpeech options from run command directly options.
parent 0db0b84c
Pipeline #150583 passed with stage
in 39 seconds
......@@ -6,17 +6,14 @@
<rect>
<x>0</x>
<y>0</y>
<width>391</width>
<width>466</width>
<height>222</height>
</rect>
</property>
<property name="windowTitle">
<string>Text-to-Speech</string>
</property>
<layout class="QVBoxLayout">
<property name="spacing">
<number>6</number>
</property>
<layout class="QGridLayout" name="gridLayout">
<property name="leftMargin">
<number>11</number>
</property>
......@@ -29,143 +26,197 @@
<property name="bottomMargin">
<number>11</number>
</property>
<item>
<widget class="QCheckBox" name="useQtSpeech">
<property name="whatsThis">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;This check box specifies KMouth tries to use the system speech service prior to calling the speech synthesizer directly. The system speech service is a Qt library which wraps speech-dispatcher on linux, and native speech systems on other platforms.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<item row="0" column="0" rowspan="4">
<widget class="QGroupBox" name="qtspeechGroupBox">
<property name="title">
<string>&amp;Use default speech system</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>&amp;Engine:</string>
</property>
<property name="buddy">
<cstring>engineComboBox</cstring>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="engineComboBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>&amp;Voice:</string>
</property>
<property name="buddy">
<cstring>voiceComboBox</cstring>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="voiceComboBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<layout class="QVBoxLayout">
<property name="spacing">
<number>6</number>
</property>
<property name="leftMargin">
<number>0</number>
<item row="0" column="1" rowspan="4">
<widget class="QGroupBox" name="alternativeGroupBox">
<property name="enabled">
<bool>false</bool>
</property>
<property name="topMargin">
<number>0</number>
<property name="title">
<string>Alternative</string>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="urlLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="whatsThis">
<string>This field specifies both the command used for speaking texts and its parameters. KMouth knows the following placeholders:
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QVBoxLayout">
<property name="spacing">
<number>6</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="urlLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="whatsThis">
<string>This field specifies both the command used for speaking texts and its parameters. KMouth knows the following placeholders:
%t -- the text that should be spoken
%f -- the name of a file containing the text
%l -- the language code
%% -- a percent sign</string>
</property>
<property name="text">
<string>Alternative command for speaking &amp;texts:</string>
</property>
<property name="buddy">
<cstring>urlReq</cstring>
</property>
</widget>
</item>
<item>
<widget class="KUrlRequester" name="urlReq">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="whatsThis">
<string>This field specifies both the command used for speaking texts and its parameters. KMouth knows the following placeholders:
</property>
<property name="text">
<string>Command for speaking &amp;texts:</string>
</property>
<property name="buddy">
<cstring>urlReq</cstring>
</property>
</widget>
</item>
<item>
<widget class="KUrlRequester" name="urlReq" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="whatsThis">
<string>This field specifies both the command used for speaking texts and its parameters. KMouth knows the following placeholders:
%t -- the text that should be spoken
%f -- the name of a file containing the text
%l -- the language code
%% -- a percent sign</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout">
<property name="spacing">
<number>6</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="characterCodingLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="whatsThis">
<string>This combo box specifies which character encoding is used for passing the text.</string>
</property>
<property name="text">
<string>Character encodin&amp;g:</string>
</property>
<property name="buddy">
<cstring>characterCodingBox</cstring>
</property>
</widget>
</item>
<item>
<widget class="KComboBox" name="characterCodingBox">
<property name="whatsThis">
<string>This combo box specifies which character encoding is used for passing the text.</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QCheckBox" name="stdInButton">
<property name="whatsThis">
<string>This check box specifies whether the text is sent as standard input to the speech synthesizer.</string>
</property>
<property name="text">
<string>Send the data as standard &amp;input</string>
</property>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QCheckBox" name="stdInButton">
<property name="whatsThis">
<string>This check box specifies whether the text is sent as standard input to the speech synthesizer.</string>
</property>
<property name="text">
<string>Send the data as standard &amp;input</string>
</property>
</widget>
</item>
<item>
<layout class="QVBoxLayout">
<property name="spacing">
<number>6</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="characterCodingLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="whatsThis">
<string>This combo box specifies which character encoding is used for passing the text.</string>
</property>
<property name="text">
<string>Character encodin&amp;g:</string>
</property>
<property name="buddy">
<cstring>characterCodingBox</cstring>
</property>
</widget>
</item>
<item>
<widget class="KComboBox" name="characterCodingBox">
<property name="whatsThis">
<string>This combo box specifies which character encoding is used for passing the text.</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>KUrlRequester</class>
<extends>QWidget</extends>
<header>kurlrequester.h</header>
</customwidget>
<customwidget>
<class>KComboBox</class>
<extends>QComboBox</extends>
<header>kcombobox.h</header>
</customwidget>
<customwidget>
<class>KUrlRequester</class>
<extends>QWidget</extends>
<header>kurlrequester.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
......
......@@ -27,6 +27,8 @@
#include "speech.h"
#include "texttospeechsystem.h"
#include <QtTextToSpeech>
TextToSpeechConfigurationWidget::TextToSpeechConfigurationWidget(QWidget *parent, const QString &name)
: QWizardPage(parent)
{
......@@ -34,7 +36,24 @@ TextToSpeechConfigurationWidget::TextToSpeechConfigurationWidget(QWidget *parent
setupUi(this);
ttsSystem = new TextToSpeechSystem(this);
connect(qtspeechGroupBox, &QGroupBox::toggled,
this, &TextToSpeechConfigurationWidget::useQtspeechChanged);
buildCodecList();
// BEGIN Text-to-speech section
// Populate tts engines and use their names directly as key and item text:
const QStringList engines = QTextToSpeech::availableEngines();
for (const QString &engine : engines) {
engineComboBox->addItem(engine);
}
connect(engineComboBox, qOverload<int>(&QComboBox::currentIndexChanged),
this, &TextToSpeechConfigurationWidget::slotTTSEngineChanged);
connect(voiceComboBox, &QComboBox::currentTextChanged,
this, &TextToSpeechConfigurationWidget::slotTTSVoiceChanged);
// Preload voice list
slotTTSEngineChanged();
}
TextToSpeechConfigurationWidget::~TextToSpeechConfigurationWidget()
......@@ -57,7 +76,39 @@ void TextToSpeechConfigurationWidget::cancel()
urlReq->setUrl(QUrl::fromLocalFile(ttsSystem->ttsCommand));
stdInButton->setChecked(ttsSystem->stdIn);
characterCodingBox->setCurrentIndex(ttsSystem->codec);
useQtSpeech->setChecked(ttsSystem->useQtSpeech);
qtspeechGroupBox->setChecked(ttsSystem->useQtSpeech);
}
void TextToSpeechConfigurationWidget::useQtspeechChanged(bool enabled)
{
alternativeGroupBox->setEnabled(!enabled);
}
void TextToSpeechConfigurationWidget::slotTTSEngineChanged()
{
QString engine = engineComboBox->currentText();
ttsSystem->ttsEngine = engine;
// Get list of voices and repopulate voice tts combobox
QTextToSpeech *ttsEngine = new QTextToSpeech(engine);
const QVector<QVoice> voices = ttsEngine->availableVoices();
voiceComboBox->blockSignals(true);
voiceComboBox->clear();
for (const QVoice &voice : voices) {
voiceComboBox->addItem(voice.name());
}
delete ttsEngine;
// If there's a voice set, try to load it
if (!ttsSystem->ttsVoice.isEmpty()) {
voiceComboBox->setCurrentText(ttsSystem->ttsVoice);
}
voiceComboBox->blockSignals(false);
}
void TextToSpeechConfigurationWidget::slotTTSVoiceChanged(QString voice)
{
ttsSystem->ttsVoice = voice;
}
void TextToSpeechConfigurationWidget::ok()
......@@ -65,7 +116,7 @@ void TextToSpeechConfigurationWidget::ok()
ttsSystem->ttsCommand = urlReq->url().toLocalFile();
ttsSystem->stdIn = stdInButton->isChecked();
ttsSystem->codec = characterCodingBox->currentIndex();
ttsSystem->useQtSpeech = useQtSpeech->isChecked();
ttsSystem->useQtSpeech = qtspeechGroupBox->isChecked();
}
TextToSpeechSystem *TextToSpeechConfigurationWidget::getTTSSystem() const
......@@ -79,7 +130,12 @@ void TextToSpeechConfigurationWidget::readOptions(const QString &langGroup)
urlReq->setUrl(QUrl::fromLocalFile(ttsSystem->ttsCommand));
stdInButton->setChecked(ttsSystem->stdIn);
characterCodingBox->setCurrentIndex(ttsSystem->codec);
useQtSpeech->setChecked(ttsSystem->useQtSpeech);
qtspeechGroupBox->setChecked(ttsSystem->useQtSpeech);
engineComboBox->setCurrentText(ttsSystem->ttsEngine);
if (!ttsSystem->ttsVoice.isEmpty()) {
voiceComboBox->setCurrentText(ttsSystem->ttsVoice);
}
}
void TextToSpeechConfigurationWidget::saveOptions(const QString &langGroup)
......
/***************************************************************************
* Copyright (C) 2002 by Gunnar Schmi Dt <kmouth@schmi-dt.de *
* (C) 2015 by Jeremy Whiting <jpwhiting@kde.org> *
* (C) 2015, 2022 by Jeremy Whiting <jpwhiting@kde.org> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
......@@ -46,6 +46,13 @@ public:
void ok();
void cancel();
private Q_SLOTS:
void useQtspeechChanged(bool enabled);
void slotTTSEngineChanged();
void slotTTSVoiceChanged(QString voice);
private:
void buildCodecList();
......
/***************************************************************************
* Copyright (C) 2002 by Gunnar Schmi Dt <kmouth@schmi-dt.de *
* (C) 2015 by Jeremy Whiting <jpwhiting@kde.org> *
* (C) 2015, 2022 by Jeremy Whiting <jpwhiting@kde.org> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
......@@ -33,9 +33,11 @@ TextToSpeechSystem::TextToSpeechSystem(QObject *parent)
{
stdIn = true;
useQtSpeech = true;
// Default to speechd
ttsEngine = QLatin1String("speechd");
codec = Speech::Local; // local encoding;
buildCodecList();
m_speech = new QTextToSpeech();
m_speech = new QTextToSpeech(ttsEngine);
}
TextToSpeechSystem::~TextToSpeechSystem()
......@@ -66,6 +68,10 @@ void TextToSpeechSystem::readOptions(const QString &langGroup)
ttsCommand = cg.readPathEntry("Command", QString());
stdIn = cg.readEntry("StdIn", true);
useQtSpeech = cg.readEntry("useQtSpeech", true);
ttsEngine = cg.readEntry("ttsEngine", "speechd");
// No default, depends on current locale, etc. so just naturally
// select first voice if none set by user.
ttsVoice = cg.readEntry("ttsVoice", "");
QString codecString = cg.readEntry("Codec", "Local");
if (codecString == QLatin1String("Local"))
......@@ -88,6 +94,8 @@ void TextToSpeechSystem::saveOptions(const QString &langGroup)
cg.writePathEntry("Command", ttsCommand);
cg.writeEntry("StdIn", stdIn);
cg.writeEntry("useQtSpeech", useQtSpeech);
cg.writeEntry("ttsEngine", ttsEngine);
cg.writeEntry("ttsVoice", ttsVoice);
if (codec == Speech::Local)
cg.writeEntry("Codec", "Local");
else if (codec == Speech::Latin1)
......@@ -98,6 +106,15 @@ void TextToSpeechSystem::saveOptions(const QString &langGroup)
QString codeName = QLatin1String(codecList->at(codec - Speech::UseCodec)->name());
cg.writeEntry("Codec", codeName);
}
delete m_speech;
m_speech = new QTextToSpeech(ttsEngine);
const QVector<QVoice> voices = m_speech->availableVoices();
for (const QVoice &voice: voices) {
if (voice.name() == ttsVoice) {
m_speech->setVoice(voice);
}
}
}
void TextToSpeechSystem::buildCodecList()
......
/***************************************************************************
* Copyright (C) 2002 by Gunnar Schmi Dt <kmouth@schmi-dt.de *
* (C) 2015 by Jeremy Whiting <jpwhiting@kde.org> *
* (C) 2015, 2022 by Jeremy Whiting <jpwhiting@kde.org> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
......@@ -51,6 +51,8 @@ private:
QString ttsCommand;
bool stdIn;
bool useQtSpeech;
QString ttsEngine;
QString ttsVoice;
/** Text to Speech API */
QTextToSpeech *m_speech;
};
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment