diff options
Diffstat (limited to 'kttsd/plugins/flite')
-rw-r--r-- | kttsd/plugins/flite/Makefile.am | 20 | ||||
-rw-r--r-- | kttsd/plugins/flite/README | 3 | ||||
-rw-r--r-- | kttsd/plugins/flite/configure.in.bot | 15 | ||||
-rw-r--r-- | kttsd/plugins/flite/configure.in.in | 22 | ||||
-rw-r--r-- | kttsd/plugins/flite/fliteconf.cpp | 199 | ||||
-rw-r--r-- | kttsd/plugins/flite/fliteconf.h | 124 | ||||
-rw-r--r-- | kttsd/plugins/flite/fliteconfwidget.ui | 186 | ||||
-rw-r--r-- | kttsd/plugins/flite/fliteplugin.cpp | 31 | ||||
-rw-r--r-- | kttsd/plugins/flite/fliteproc.cpp | 281 | ||||
-rw-r--r-- | kttsd/plugins/flite/fliteproc.h | 187 | ||||
-rw-r--r-- | kttsd/plugins/flite/kttsd_fliteplugin.desktop | 59 |
11 files changed, 1127 insertions, 0 deletions
diff --git a/kttsd/plugins/flite/Makefile.am b/kttsd/plugins/flite/Makefile.am new file mode 100644 index 0000000..c451be3 --- /dev/null +++ b/kttsd/plugins/flite/Makefile.am @@ -0,0 +1,20 @@ +INCLUDES = \ + -I$(top_srcdir)/kttsd/libkttsd -I$(top_builddir)/kttsd/libkttsd \ + $(all_includes) + +METASOURCES = AUTO + +kde_module_LTLIBRARIES = libkttsd_fliteplugin.la + +libkttsd_fliteplugin_la_SOURCES = \ + fliteconfwidget.ui \ + fliteconf.cpp \ + fliteproc.cpp \ + fliteplugin.cpp +libkttsd_fliteplugin_la_LDFLAGS = $(KDE_PLUGIN) $(all_libraries) +libkttsd_fliteplugin_la_LIBADD = $(top_builddir)/kttsd/libkttsd/libkttsd.la + +services_DATA = kttsd_fliteplugin.desktop +servicesdir = $(kde_servicesdir) + +noinst_HEADERS = fliteproc.h fliteconf.h fliteconfwidget.h diff --git a/kttsd/plugins/flite/README b/kttsd/plugins/flite/README new file mode 100644 index 0000000..1bff55b --- /dev/null +++ b/kttsd/plugins/flite/README @@ -0,0 +1,3 @@ +This is the directory containing the Festival Lite plug in. +This plug in is developed and maintained by Gary Cramblitt. +<garycramblitt@comcast.net> diff --git a/kttsd/plugins/flite/configure.in.bot b/kttsd/plugins/flite/configure.in.bot new file mode 100644 index 0000000..54bd84e --- /dev/null +++ b/kttsd/plugins/flite/configure.in.bot @@ -0,0 +1,15 @@ +if test "x$flite_bindir" = "xno"; then + if test "$compile_flite_plugin" = "yes"; then + echo "" + echo "=======================================================" + echo "The Festival Lite (flite) program does not appear to be" + echo "installed on this system. The Flite plugin will" + echo "be built, but you need to install Flite before you" + echo "can use it. You can get it at" + echo " http://www.speech.cs.cmu.edu/flite/index.html" + echo "Debian users: apt-get install flite" + echo "======================================================" + all_tests=bad + fi +fi + diff --git a/kttsd/plugins/flite/configure.in.in b/kttsd/plugins/flite/configure.in.in new file mode 100644 index 0000000..f9b222f --- /dev/null +++ b/kttsd/plugins/flite/configure.in.in @@ -0,0 +1,22 @@ +dnl ========================================= +dnl checks for Festival Lite (Flite) Plug In +dnl ========================================= + +AC_ARG_ENABLE(kttsd-flite, + AC_HELP_STRING([--enable-kttsd-flite], + [build KTTSD Festival Lite (flite) [default=yes]]), + flite_plugin=$enableval, + flite_plugin=yes) + +compile_flite_plugin="yes" + +if test "x$flite_plugin" = "xno"; then + compile_flite_plugin="no" +fi + +dnl Check for flite executable. +dnl Note that flite plugin is always built, unless +dnl user overrides on configure command line. +AC_PATH_PROG(flite_bindir, "flite", "no") + +AM_CONDITIONAL(include_kttsd_flite, test "x$compile_flite_plugin" != "xno") diff --git a/kttsd/plugins/flite/fliteconf.cpp b/kttsd/plugins/flite/fliteconf.cpp new file mode 100644 index 0000000..cbc4b2d --- /dev/null +++ b/kttsd/plugins/flite/fliteconf.cpp @@ -0,0 +1,199 @@ +/***************************************************** vim:set ts=4 sw=4 sts=4: + Configuration widget and functions for Festival (Interactive) plug in + ------------------- + Copyright: + (C) 2004 by Gary Cramblitt <garycramblitt@comcast.net> + ------------------- + Original author: Gary Cramblitt <garycramblitt@comcast.net> + + 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + ******************************************************************************/ + +// Qt includes. +#include <qlayout.h> +#include <qfile.h> +#include <qapplication.h> + +// KDE includes. +#include <klocale.h> +#include <kdialog.h> +#include <ktempfile.h> +#include <kstandarddirs.h> +#include <kprogress.h> + +// KTTS includes. +#include <testplayer.h> + +// Flite Plugin includes. +#include "fliteproc.h" +#include "fliteconf.h" +#include "fliteconf.moc" + +/** Constructor */ +FliteConf::FliteConf( QWidget* parent, const char* name, const QStringList& /*args*/) : + PlugInConf(parent, name) +{ + // kdDebug() << "FliteConf::FliteConf: Running" << endl; + m_fliteProc = 0; + m_progressDlg = 0; + + QVBoxLayout *layout = new QVBoxLayout(this, KDialog::marginHint(), + KDialog::spacingHint(), "FliteConfigWidgetLayout"); + layout->setAlignment (Qt::AlignTop); + m_widget = new FliteConfWidget(this, "FliteConfigWidget"); + layout->addWidget(m_widget); + + defaults(); + + connect(m_widget->flitePath, SIGNAL(textChanged(const QString&)), + this, SLOT(configChanged())); + connect(m_widget->fliteTest, SIGNAL(clicked()), this, SLOT(slotFliteTest_clicked())); +} + +/** Destructor */ +FliteConf::~FliteConf(){ + // kdDebug() << "Running: FliteConf::~FliteConf()" << endl; + if (!m_waveFile.isNull()) QFile::remove(m_waveFile); + delete m_fliteProc; + delete m_progressDlg; +} + +void FliteConf::load(KConfig *config, const QString &configGroup){ + // kdDebug() << "FliteConf::load: Loading configuration for language " << langGroup << " with plug in " << "Festival Lite (flite)" << endl; + + config->setGroup(configGroup); + QString fliteExe = config->readEntry("FliteExePath", QString::null); + if (fliteExe.isEmpty()) + { + config->setGroup("Flite"); + fliteExe = config->readEntry("FliteExePath", "flite"); + } + m_widget->flitePath->setURL(fliteExe); +} + +void FliteConf::save(KConfig *config, const QString &configGroup){ + // kdDebug() << "FliteConf::save: Saving configuration for language " << langGroup << " with plug in " << "Festival Lite (flite)" << endl; + + config->setGroup("Flite"); + config->writeEntry("FliteExePath", + realFilePath(m_widget->flitePath->url())); + config->setGroup(configGroup); + config->writeEntry("FliteExePath", + realFilePath(m_widget->flitePath->url())); +} + +void FliteConf::defaults(){ + // kdDebug() << "FliteConf::defaults: Running" << endl; + m_widget->flitePath->setURL("flite"); +} + +void FliteConf::setDesiredLanguage(const QString &lang) +{ + m_languageCode = lang; +} + +QString FliteConf::getTalkerCode() +{ + QString fliteExe = realFilePath(m_widget->flitePath->url()); + if (!fliteExe.isEmpty()) + { + if (!getLocation(fliteExe).isEmpty()) + { + return QString( + "<voice lang=\"%1\" name=\"%2\" gender=\"%3\" />" + "<prosody volume=\"%4\" rate=\"%5\" />" + "<kttsd synthesizer=\"%6\" />") + .arg(m_languageCode) + .arg("fixed") + .arg("neutral") + .arg("medium") + .arg("medium") + .arg("Festival Lite (flite)"); + } + } + return QString::null; +} + +void FliteConf::slotFliteTest_clicked() +{ + // kdDebug() << "FliteConf::slotFliteTest_clicked(): Running" << endl; + // If currently synthesizing, stop it. + if (m_fliteProc) + m_fliteProc->stopText(); + else + { + m_fliteProc = new FliteProc(); + connect (m_fliteProc, SIGNAL(stopped()), this, SLOT(slotSynthStopped())); + } + // Create a temp file name for the wave file. + KTempFile tempFile (locateLocal("tmp", "fliteplugin-"), ".wav"); + QString tmpWaveFile = tempFile.file()->name(); + tempFile.close(); + + // Get test message in the language of the voice. + QString testMsg = testMessage(m_languageCode); + + // Tell user to wait. + m_progressDlg = new KProgressDialog(m_widget, "kttsmgr_flite_testdlg", + i18n("Testing"), + i18n("Testing."), + true); + m_progressDlg->progressBar()->hide(); + m_progressDlg->setAllowCancel(true); + + // Play an English test. Flite only supports English. + connect (m_fliteProc, SIGNAL(synthFinished()), this, SLOT(slotSynthFinished())); + m_fliteProc->synth( + testMsg, + tmpWaveFile, + realFilePath(m_widget->flitePath->url())); + + // Display progress dialog modally. Processing continues when plugin signals synthFinished, + // or if user clicks Cancel button. + m_progressDlg->exec(); + disconnect (m_fliteProc, SIGNAL(synthFinished()), this, SLOT(slotSynthFinished())); + if (m_progressDlg->wasCancelled()) m_fliteProc->stopText(); + delete m_progressDlg; + m_progressDlg = 0; +} + +void FliteConf::slotSynthFinished() +{ + // If user canceled, progress dialog is gone, so exit. + if (!m_progressDlg) + { + m_fliteProc->ackFinished(); + return; + } + // Hide the Cancel button so user can't cancel in the middle of playback. + m_progressDlg->showCancelButton(false); + // Get new wavefile name. + m_waveFile = m_fliteProc->getFilename(); + // Tell synth we're done. + m_fliteProc->ackFinished(); + // Play the wave file (possibly adjusting its Speed). + // Player object deletes the wave file when done. + if (m_player) m_player->play(m_waveFile); + QFile::remove(m_waveFile); + m_waveFile = QString::null; + if (m_progressDlg) m_progressDlg->close(); +} + +void FliteConf::slotSynthStopped() +{ + // Clean up after canceling test. + QString filename = m_fliteProc->getFilename(); + if (!filename.isNull()) QFile::remove(filename); +} diff --git a/kttsd/plugins/flite/fliteconf.h b/kttsd/plugins/flite/fliteconf.h new file mode 100644 index 0000000..aa26c7b --- /dev/null +++ b/kttsd/plugins/flite/fliteconf.h @@ -0,0 +1,124 @@ +/***************************************************** vim:set ts=4 sw=4 sts=4: + Configuration widget and functions for Festival (Interactive) plug in + ------------------- + Copyright: + (C) 2004 by Gary Cramblitt <garycramblitt@comcast.net> + ------------------- + Original author: Gary Cramblitt <garycramblitt@comcast.net> + + 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + ******************************************************************************/ + +#ifndef _FLITECONF_H_ +#define _FLITECONF_H_ + +// Qt includes. +#include <qstring.h> + +// KDE includes. +#include <kconfig.h> +#include <kdebug.h> + +// KTTS includes. +#include <pluginconf.h> + +// Flite plugin includes. +#include "fliteconfwidget.h" + +class FliteProc; +class KProgressDialog; + +class FliteConf : public PlugInConf { + Q_OBJECT + + public: + /** Constructor */ + FliteConf( QWidget* parent = 0, const char* name = 0, const QStringList &args = QStringList()); + + /** Destructor */ + ~FliteConf(); + + /** This method is invoked whenever the module should read its + * configuration (most of the times from a config file) and update the + * user interface. This happens when the user clicks the "Reset" button in + * the control center, to undo all of his changes and restore the currently + * valid settings. NOTE that this is not called after the modules is loaded, + * so you probably want to call this method in the constructor. + */ + void load(KConfig *config, const QString &configGroup); + + /** This function gets called when the user wants to save the settings in + * the user interface, updating the config files or wherever the + * configuration is stored. The method is called when the user clicks "Apply" + * or "Ok". + */ + void save(KConfig *config, const QString &configGroup); + + /** This function is called to set the settings in the module to sensible + * default values. It gets called when hitting the "Default" button. The + * default values should probably be the same as the ones the application + * uses when started without a config file. + */ + void defaults(); + + /** + * This function informs the plugin of the desired language to be spoken + * by the plugin. The plugin should attempt to adapt itself to the + * specified language code, choosing sensible defaults if necessary. + * If the passed-in code is QString::null, no specific language has + * been chosen. + * @param lang The desired language code or Null if none. + * + * If the plugin is unable to support the desired language, that is OK. + * Language codes are given by ISO 639-1 and are in lowercase. + * The code may also include an ISO 3166 country code in uppercase + * separated from the language code by underscore (_). For + * example, en_GB. If your plugin supports the given language, but + * not the given country, treat it as though the country + * code were not specified, i.e., adapt to the given language. + */ + void setDesiredLanguage(const QString &lang); + + /** + * Return fully-specified talker code for the configured plugin. This code + * uniquely identifies the configured instance of the plugin and distinquishes + * one instance from another. If the plugin has not been fully configured, + * i.e., cannot yet synthesize, return QString::null. + * @return Fully-specified talker code. + */ + QString getTalkerCode(); + + private slots: + void configChanged(){ + // kdDebug() << "FliteConf::configChanged: Running" << endl; + emit changed(true); + }; + void slotFliteTest_clicked(); + void slotSynthFinished(); + void slotSynthStopped(); + + private: + // Language code. + QString m_languageCode; + // Configuration Widget. + FliteConfWidget* m_widget; + // Flite synthesizer. + FliteProc* m_fliteProc; + // Synthesized wave file name. + QString m_waveFile; + // Progress dialog. + KProgressDialog* m_progressDlg; +}; +#endif // _FLITECONF_H_ diff --git a/kttsd/plugins/flite/fliteconfwidget.ui b/kttsd/plugins/flite/fliteconfwidget.ui new file mode 100644 index 0000000..839970e --- /dev/null +++ b/kttsd/plugins/flite/fliteconfwidget.ui @@ -0,0 +1,186 @@ +<!DOCTYPE UI><UI version="3.2" stdsetdef="1"> +<class>FliteConfWidget</class> +<author>Gary Cramblitt</author> +<widget class="QWidget"> + <property name="name"> + <cstring>FliteConfWidget</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>559</width> + <height>233</height> + </rect> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>7</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="caption"> + <string>Flite Config UI</string> + </property> + <property name="whatsThis" stdset="0"> + <string>This is the configuration dialog for the Festival Lite (Flite) speech synthesis engine.</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <spacer row="1" column="0"> + <property name="name"> + <cstring>spacer1</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>100</height> + </size> + </property> + </spacer> + <widget class="QGroupBox" row="0" column="0"> + <property name="name"> + <cstring>fliteConfigurationBox</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="frameShape"> + <enum>GroupBoxPanel</enum> + </property> + <property name="frameShadow"> + <enum>Sunken</enum> + </property> + <property name="title"> + <string>Festival &Lite (flite) Configuration</string> + </property> + <property name="whatsThis" stdset="0"> + <string>This is the configuration dialog for the Festival Lite (Flite) speech synthesis engine.</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>11</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <widget class="QLayoutWidget" row="0" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>flitePathBox</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>flitePathLabel</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>1</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>&Flite executable path:</string> + </property> + <property name="alignment"> + <set>AlignVCenter|AlignRight</set> + </property> + <property name="buddy" stdset="0"> + <cstring>flitePath</cstring> + </property> + <property name="whatsThis" stdset="0"> + <string>If Flite is in your PATH environment variable, simply enter "flite", otherwise specify the complete path to the Flite executable program.</string> + </property> + </widget> + <widget class="KURLRequester"> + <property name="name"> + <cstring>flitePath</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>1</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="url" stdset="0"> + <string>flite</string> + </property> + <property name="whatsThis" stdset="0"> + <string>If Flite is in your PATH environment variable, simply enter "flite", otherwise specify the complete path to the Flite executable program.</string> + </property> + </widget> + </hbox> + </widget> + <widget class="QPushButton" row="1" column="1"> + <property name="name"> + <cstring>fliteTest</cstring> + </property> + <property name="text"> + <string>&Test</string> + </property> + </widget> + <spacer row="1" column="0"> + <property name="name"> + <cstring>spacer2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>221</width> + <height>20</height> + </size> + </property> + </spacer> + </grid> + </widget> + </grid> +</widget> +<customwidgets> +</customwidgets> +<includes> + <include location="global" impldecl="in declaration">kurlrequester.h</include> + <include location="global" impldecl="in implementation">kurlrequester.h</include> +</includes> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>kurlrequester.h</includehint> + <includehint>klineedit.h</includehint> + <includehint>kpushbutton.h</includehint> +</includehints> +</UI> diff --git a/kttsd/plugins/flite/fliteplugin.cpp b/kttsd/plugins/flite/fliteplugin.cpp new file mode 100644 index 0000000..602b5bb --- /dev/null +++ b/kttsd/plugins/flite/fliteplugin.cpp @@ -0,0 +1,31 @@ +/***************************************************** vim:set ts=4 sw=4 sts=4: + Generating the factories so festival lite (flite) can be used as plug in. + ------------------- + Copyright: + (C) 2004 by Gary Cramblitt <garycramblitt@comcast.net> + ------------------- + Original author: Gary Cramblitt <garycramblitt@comcast.net> + + 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + ******************************************************************************/ + +#include <kgenericfactory.h> + +#include "fliteconf.h" +#include "fliteproc.h" + +typedef K_TYPELIST_2( FliteProc, FliteConf ) Flite; +K_EXPORT_COMPONENT_FACTORY( libkttsd_fliteplugin, KGenericFactory<Flite>("kttsd_flite") ) + diff --git a/kttsd/plugins/flite/fliteproc.cpp b/kttsd/plugins/flite/fliteproc.cpp new file mode 100644 index 0000000..54b15e3 --- /dev/null +++ b/kttsd/plugins/flite/fliteproc.cpp @@ -0,0 +1,281 @@ +/***************************************************** vim:set ts=4 sw=4 sts=4: + Main speaking functions for the Festival Lite (Flite) Plug in + ------------------- + Copyright: + (C) 2004 by Gary Cramblitt <garycramblitt@comcast.net> + ------------------- + Original author: Gary Cramblitt <garycramblitt@comcast.net> + + 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + ******************************************************************************/ + +// Qt includes. +#include <qstring.h> +#include <qstringlist.h> + +// KDE includes. +#include <kdebug.h> +#include <kconfig.h> +#include <kstandarddirs.h> +#include <kprocess.h> + +// Flite Plugin includes. +#include "fliteproc.h" +#include "fliteproc.moc" + +/** Constructor */ +FliteProc::FliteProc( QObject* parent, const char* name, const QStringList& ) : + PlugInProc( parent, name ){ + kdDebug() << "FliteProc::FliteProc: Running" << endl; + m_state = psIdle; + m_waitingStop = false; + m_fliteProc = 0; +} + +/** Destructor */ +FliteProc::~FliteProc(){ + kdDebug() << "FliteProc::~FliteProc:: Running" << endl; + if (m_fliteProc) + { + stopText(); + delete m_fliteProc; + } +} + +/** Initialize the speech */ +bool FliteProc::init(KConfig* config, const QString& configGroup){ + // kdDebug() << "Running: FliteProc::init(const QString &lang)" << endl; + // kdDebug() << "Initializing plug in: Flite" << endl; + // Retrieve path to flite executable. + config->setGroup(configGroup); + m_fliteExePath = config->readEntry("FliteExePath", "flite"); + kdDebug() << "FliteProc::init: path to flite: " << m_fliteExePath << endl; + return true; +} + +/** +* Say a text. Synthesize and audibilize it. +* @param text The text to be spoken. +* +* If the plugin supports asynchronous operation, it should return immediately. +*/ +void FliteProc::sayText(const QString &text) +{ + synth(text, QString::null, m_fliteExePath); +} + +/** +* Synthesize text into an audio file, but do not send to the audio device. +* @param text The text to be synthesized. +* @param suggestedFilename Full pathname of file to create. The plugin +* may ignore this parameter and choose its own +* filename. KTTSD will query the generated +* filename using getFilename(). +* +* If the plugin supports asynchronous operation, it should return immediately. +*/ +void FliteProc::synthText(const QString& text, const QString& suggestedFilename) +{ + synth(text, suggestedFilename, m_fliteExePath); +} + +/** +* Say or Synthesize text. +* @param text The text to be synthesized. +* @param suggestedFilename If not Null, synthesize only to this filename, otherwise +* synthesize and audibilize the text. +*/ +void FliteProc::synth( + const QString &text, + const QString &synthFilename, + const QString& fliteExePath) +{ + // kdDebug() << "Running: FliteProc::synth(const QString &text)" << endl; + + if (m_fliteProc) + { + if (m_fliteProc->isRunning()) m_fliteProc->kill(); + delete m_fliteProc; + m_fliteProc = 0; + } + // kdDebug()<< "FliteProc::synth: Creating Flite object" << endl; + m_fliteProc = new KProcess; + connect(m_fliteProc, SIGNAL(processExited(KProcess*)), + this, SLOT(slotProcessExited(KProcess*))); + connect(m_fliteProc, SIGNAL(receivedStdout(KProcess*, char*, int)), + this, SLOT(slotReceivedStdout(KProcess*, char*, int))); + connect(m_fliteProc, SIGNAL(receivedStderr(KProcess*, char*, int)), + this, SLOT(slotReceivedStderr(KProcess*, char*, int))); + connect(m_fliteProc, SIGNAL(wroteStdin(KProcess*)), + this, SLOT(slotWroteStdin(KProcess* ))); + if (synthFilename.isNull()) + m_state = psSaying; + else + m_state = psSynthing; + + + // Encode quotation characters. + QString saidText = text; +/* + saidText.replace("\\\"", "#!#!"); + saidText.replace("\"", "\\\""); + saidText.replace("#!#!", "\\\""); + // Remove certain comment characters. + saidText.replace("--", ""); + saidText = "\"" + saidText + "\""; +*/ + saidText += "\n"; + + *m_fliteProc << fliteExePath; +// *m_fliteProc << "-t" << saidText; + if (!synthFilename.isNull()) *m_fliteProc << "-o" << synthFilename; + + // Ok, let's rock. + m_synthFilename = synthFilename; + kdDebug() << "FliteProc::synth: Synthing text: '" << saidText << "' using Flite plug in" << endl; + if (!m_fliteProc->start(KProcess::NotifyOnExit, KProcess::All)) + { + kdDebug() << "FliteProc::synth: Error starting Flite process. Is flite in the PATH?" << endl; + m_state = psIdle; + return; + } + kdDebug()<< "FliteProc:synth: Flite initialized" << endl; + m_fliteProc->writeStdin(saidText.latin1(), saidText.length()); +} + +/** +* Get the generated audio filename from synthText. +* @return Name of the audio file the plugin generated. +* Null if no such file. +* +* The plugin must not re-use the filename. +*/ +QString FliteProc::getFilename() +{ + kdDebug() << "FliteProc::getFilename: returning " << m_synthFilename << endl; + return m_synthFilename; +} + +/** +* Stop current operation (saying or synthesizing text). +* Important: This function may be called from a thread different from the +* one that called sayText or synthText. +* If the plugin cannot stop an in-progress @ref sayText or +* @ref synthText operation, it must not block waiting for it to complete. +* Instead, return immediately. +* +* If a plugin returns before the operation has actually been stopped, +* the plugin must emit the @ref stopped signal when the operation has +* actually stopped. +* +* The plugin should change to the psIdle state after stopping the +* operation. +*/ +void FliteProc::stopText(){ + kdDebug() << "FliteProc::stopText:: Running" << endl; + if (m_fliteProc) + { + if (m_fliteProc->isRunning()) + { + kdDebug() << "FliteProc::stopText: killing Flite." << endl; + m_waitingStop = true; + m_fliteProc->kill(); + } else m_state = psIdle; + }else m_state = psIdle; + kdDebug() << "FliteProc::stopText: Flite stopped." << endl; +} + +void FliteProc::slotProcessExited(KProcess*) +{ + kdDebug() << "FliteProc:slotProcessExited: Flite process has exited." << endl; + pluginState prevState = m_state; + if (m_waitingStop) + { + m_waitingStop = false; + m_state = psIdle; + emit stopped(); + } else { + m_state = psFinished; + if (prevState == psSaying) + emit sayFinished(); + else + if (prevState == psSynthing) + emit synthFinished(); + } +} + +void FliteProc::slotReceivedStdout(KProcess*, char* buffer, int buflen) +{ + QString buf = QString::fromLatin1(buffer, buflen); + kdDebug() << "FliteProc::slotReceivedStdout: Received output from Flite: " << buf << endl; +} + +void FliteProc::slotReceivedStderr(KProcess*, char* buffer, int buflen) +{ + QString buf = QString::fromLatin1(buffer, buflen); + kdDebug() << "FliteProc::slotReceivedStderr: Received error from Flite: " << buf << endl; +} + +void FliteProc::slotWroteStdin(KProcess*) +{ + kdDebug() << "FliteProc::slotWroteStdin: closing Stdin" << endl; + m_fliteProc->closeStdin(); +} + +/** +* Return the current state of the plugin. +* This function only makes sense in asynchronous mode. +* @return The pluginState of the plugin. +* +* @see pluginState +*/ +pluginState FliteProc::getState() { return m_state; } + +/** +* Acknowledges a finished state and resets the plugin state to psIdle. +* +* If the plugin is not in state psFinished, nothing happens. +* The plugin may use this call to do any post-processing cleanup, +* for example, blanking the stored filename (but do not delete the file). +* Calling program should call getFilename prior to ackFinished. +*/ +void FliteProc::ackFinished() +{ + if (m_state == psFinished) + { + m_state = psIdle; + m_synthFilename = QString::null; + } +} + +/** +* Returns True if the plugin supports asynchronous processing, +* i.e., returns immediately from sayText or synthText. +* @return True if this plugin supports asynchronous processing. +* +* If the plugin returns True, it must also implement @ref getState . +* It must also emit @ref sayFinished or @ref synthFinished signals when +* saying or synthesis is completed. +*/ +bool FliteProc::supportsAsync() { return true; } + +/** +* Returns True if the plugin supports synthText method, +* i.e., is able to synthesize text to a sound file without +* audibilizing the text. +* @return True if this plugin supports synthText method. +*/ +bool FliteProc::supportsSynth() { return true; } + diff --git a/kttsd/plugins/flite/fliteproc.h b/kttsd/plugins/flite/fliteproc.h new file mode 100644 index 0000000..7737b3a --- /dev/null +++ b/kttsd/plugins/flite/fliteproc.h @@ -0,0 +1,187 @@ +/***************************************************** vim:set ts=4 sw=4 sts=4: + Main speaking functions for the Festival Lite (Flite) Plug in + ------------------- + Copyright: + (C) 2004 by Gary Cramblitt <garycramblitt@comcast.net> + ------------------- + Original author: Gary Cramblitt <garycramblitt@comcast.net> + + 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + ******************************************************************************/ + +#ifndef _FLITEPROC_H_ +#define _FLITEPROC_H_ + +// Qt includes. +#include <qstringlist.h> +#include <qmutex.h> + +// KTTS includes. +#include <pluginproc.h> + +class KProcess; + +class FliteProc : public PlugInProc{ + Q_OBJECT + + public: + /** + * Constructor + */ + FliteProc( QObject* parent = 0, const char* name = 0, const QStringList &args = QStringList()); + + /** + * Destructor + */ + virtual ~FliteProc(); + + /** + * Initializate the speech engine. + * @param config Settings object. + * @param configGroup Settings Group. + */ + virtual bool init(KConfig *config, const QString &configGroup); + + /** + * Say a text string. + * @param text The text to speak. + */ + virtual void sayText(const QString &text); + + /** + * Synthesize text into an audio file, but do not send to the audio device. + * @param text The text to be synthesized. + * @param suggestedFilename Full pathname of file to create. The plugin + * may ignore this parameter and choose its own + * filename. KTTSD will query the generated + * filename using getFilename(). + * + * If the plugin supports asynchronous operation, it should return immediately. + */ + virtual void synthText(const QString& text, const QString& suggestedFilename); + + /** + * Get the generated audio filename from synthText. + * @return Name of the audio file the plugin generated. + * Null if no such file. + * + * The plugin must not re-use the filename. + */ + virtual QString getFilename(); + + /** + * Stop current operation (saying or synthesizing text). + * Important: This function may be called from a thread different from the + * one that called sayText or synthText. + * If the plugin cannot stop an in-progress @ref sayText or + * @ref synthText operation, it must not block waiting for it to complete. + * Instead, return immediately. + * + * If a plugin returns before the operation has actually been stopped, + * the plugin must emit the @ref stopped signal when the operation has + * actually stopped. + * + * The plugin should change to the psIdle state after stopping the + * operation. + */ + virtual void stopText(); + + /** + * Return the current state of the plugin. + * This function only makes sense in asynchronous mode. + * @return The pluginState of the plugin. + * + * @see pluginState + */ + virtual pluginState getState(); + + /** + * Acknowledges a finished state and resets the plugin state to psIdle. + * + * If the plugin is not in state psFinished, nothing happens. + * The plugin may use this call to do any post-processing cleanup, + * for example, blanking the stored filename (but do not delete the file). + * Calling program should call getFilename prior to ackFinished. + */ + virtual void ackFinished(); + + /** + * Returns True if the plugin supports asynchronous processing, + * i.e., returns immediately from sayText or synthText. + * @return True if this plugin supports asynchronous processing. + * + * If the plugin returns True, it must also implement @ref getState . + * It must also emit @ref sayFinished or @ref synthFinished signals when + * saying or synthesis is completed. + */ + virtual bool supportsAsync(); + + /** + * Returns True if the plugin supports synthText method, + * i.e., is able to synthesize text to a sound file without + * audibilizing the text. + * @return True if this plugin supports synthText method. + */ + virtual bool supportsSynth(); + + /** + * Say or Synthesize text. + * @param text The text to be synthesized. + * @param synthFilename If not Null, synthesize only to this filename, otherwise + * synthesize and audibilize the text. + * @param fliteExePath Path to the flite executable. + */ + void synth( + const QString &text, + const QString &synthFilename, + const QString &fliteExePath); + + private slots: + void slotProcessExited(KProcess* proc); + void slotReceivedStdout(KProcess* proc, char* buffer, int buflen); + void slotReceivedStderr(KProcess* proc, char* buffer, int buflen); + void slotWroteStdin(KProcess* proc); + + private: + + /** + * Path to flite executable (from config). + */ + QString m_fliteExePath; + + /** + * Flite process + */ + KProcess* m_fliteProc; + + /** + * Synthesis filename. + */ + QString m_synthFilename; + + /** + * Plugin state. + */ + pluginState m_state; + + /** + * True when stopText has been called. Used to force transition to psIdle when + * Flite exits. + */ + bool m_waitingStop; + +}; + +#endif // _FLITEPROC_H_ diff --git a/kttsd/plugins/flite/kttsd_fliteplugin.desktop b/kttsd/plugins/flite/kttsd_fliteplugin.desktop new file mode 100644 index 0000000..2105253 --- /dev/null +++ b/kttsd/plugins/flite/kttsd_fliteplugin.desktop @@ -0,0 +1,59 @@ +[Desktop Entry] +Name=Festival Lite (flite) +Name[el]=Festival ελαφρύ (flite) +Name[fi]=Festival Lite (kevytversio) +Name[ka]=Festival მსუბუქი (flite) +Name[km]=មុខងារ Lite (flite) +Name[nds]=Festival Lite (FLite) +Name[ne]=फेस्टिभल लाइट (एफ लाईट) +Name[pt_BR]=Festival Lite +Name[ta]=பெஸ்டிவல் லைட் (flite) +Name[tr]=Festival Lite(flite) +Name[zh_TW]=Festival Lite (flite)4 +Comment=Festival Lite (flite) speech synthesizer +Comment[bg]=Олекотен синтезатор на глас Festival Lite +Comment[ca]=Sintetitzador de veu Festival Lite (flite) +Comment[cs]=Hlasový syntetizér Festival Lite (flite) +Comment[da]=Festival Lite (flite) tale-synthesizer +Comment[de]=Festival Lite (flite) Sprachsynthesizer +Comment[el]=Συνθέτης ομιλίας Festival ελαφρύ (flite) +Comment[es]=Sintetizador de texto a voz Festival (flite) +Comment[et]=Kõnesüntesaator Festival lite (flite) +Comment[eu]=Festival Lite (flite) hizketa-sintetizadorea +Comment[fa]=ترکیبدهندۀ گفتار Festival Lite (flite) +Comment[fi]=Festival Lite (kevytversio) puhesyntetisaattori +Comment[fr]=Synthèse vocale Festival Lite (flite) +Comment[ga]=Sintéiseoir cainte Festival Lite (flite) +Comment[gl]=Sintetizador de voces Festival Lite (flite) +Comment[hu]=Festival Lite (flite) beszédszintetizátor +Comment[is]=Festival Lite (flite) talgerfill +Comment[it]=Sintetizzatore vocale Festival Lite (flite) +Comment[ja]=Festival Lite (flite) スピーチシンセサイザ +Comment[ka]=Festival მარტივი (flite) ხმის სინთეზატორი +Comment[km]=មុខងារកម្មវិធីសង្គ្រោះការនិយាយ Lite (flite) +Comment[mk]=Festival Lite (flite) синтетизатор на говор +Comment[ms]=Pensintesis tutur Festival Lite (flite) +Comment[nb]=Festival Lite (flite) talesyntetisering +Comment[nds]=Blicksnuut Festival lite (FLite) +Comment[ne]=फेस्टिभल लाइट (एफ लाइट) संवाद सिन्थेसाइजर +Comment[nl]=Festival Lite (flite) spraaksynthesizer +Comment[pa]=Festival Lite (flite) ਬੋਲੀ ਸੰਸਲੇਸ਼ਕ +Comment[pl]=Syntezator mowy Festival Lite (flite) +Comment[pt]=O sintetizador de fala Festival Lite (flite) +Comment[pt_BR]=Sintetizador de fala Festival Lite (leve) +Comment[ru]=Синтезатор речи Festival Lite (flite) +Comment[sk]=Syntetizátor reči Festival Lite (flite) +Comment[sl]=Sintetizator govora Festival Lite (flite) +Comment[sr]=Синтетизатор говора Festival Lite (flite) +Comment[sr@Latn]=Sintetizator govora Festival Lite (flite) +Comment[sv]=Festival Lite (flite) talsyntes +Comment[ta]=பெஸ்டிவல் லைட் (flite) பேச்சு கூட்டிணைப்பான் +Comment[tg]=Таҳлилгари овози Festival Lite (flite) +Comment[tr]=Festival Lite(flite) konuşma bireştirici +Comment[uk]=Синтезатор мовлення Festival Lite (flite) +Comment[vi]=Trình tổng hợp tiếng nói Festival Lite (flite) +Comment[zh_TW]=Festival Lite (flite) 語音合成器 +Type=Service +ServiceTypes=KTTSD/SynthPlugin +X-KDE-Library=libkttsd_fliteplugin +X-KDE-Languages=en,en_US,en_GB |