summaryrefslogtreecommitdiffstats
path: root/kttsd/plugins/flite/fliteproc.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kttsd/plugins/flite/fliteproc.cpp')
-rw-r--r--kttsd/plugins/flite/fliteproc.cpp281
1 files changed, 281 insertions, 0 deletions
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; }
+