Fix include
[kdeaccessibility.git] / kttsd / plugins / flite / fliteproc.cpp
blob05f6e5f01798b9fcf5b0cc44c05ad3599c4ee4af
1 /***************************************************** vim:set ts=4 sw=4 sts=4:
2 Main speaking functions for the Festival Lite (Flite) Plug in
3 -------------------
4 Copyright:
5 (C) 2004 by Gary Cramblitt <garycramblitt@comcast.net>
6 -------------------
7 Original author: Gary Cramblitt <garycramblitt@comcast.net>
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 ******************************************************************************/
24 // Qt includes.
27 // KDE includes.
28 #include <kdebug.h>
29 #include <kconfig.h>
30 #include <kstandarddirs.h>
31 #include <k3process.h>
33 // Flite Plugin includes.
34 #include "fliteproc.h"
35 #include "fliteproc.moc"
37 /** Constructor */
38 FliteProc::FliteProc( QObject* parent, const QStringList& ) :
39 PlugInProc( parent, "fliteproc" ){
40 kDebug() << "FliteProc::FliteProc: Running" << endl;
41 m_state = psIdle;
42 m_waitingStop = false;
43 m_fliteProc = 0;
46 /** Destructor */
47 FliteProc::~FliteProc(){
48 kDebug() << "FliteProc::~FliteProc:: Running" << endl;
49 if (m_fliteProc)
51 stopText();
52 delete m_fliteProc;
56 /** Initialize the speech */
57 bool FliteProc::init(KConfig* c, const QString& configGroup){
58 // kDebug() << "Running: FliteProc::init(const QString &lang)" << endl;
59 // kDebug() << "Initializing plug in: Flite" << endl;
60 // Retrieve path to flite executable.
61 KConfigGroup config(c, configGroup);
62 m_fliteExePath = config.readEntry("FliteExePath", "flite");
63 kDebug() << "FliteProc::init: path to flite: " << m_fliteExePath << endl;
64 return true;
67 /**
68 * Say a text. Synthesize and audibilize it.
69 * @param text The text to be spoken.
71 * If the plugin supports asynchronous operation, it should return immediately.
73 void FliteProc::sayText(const QString &text)
75 synth(text, QString(), m_fliteExePath);
78 /**
79 * Synthesize text into an audio file, but do not send to the audio device.
80 * @param text The text to be synthesized.
81 * @param suggestedFilename Full pathname of file to create. The plugin
82 * may ignore this parameter and choose its own
83 * filename. KTTSD will query the generated
84 * filename using getFilename().
86 * If the plugin supports asynchronous operation, it should return immediately.
88 void FliteProc::synthText(const QString& text, const QString& suggestedFilename)
90 synth(text, suggestedFilename, m_fliteExePath);
93 /**
94 * Say or Synthesize text.
95 * @param text The text to be synthesized.
96 * @param suggestedFilename If not Null, synthesize only to this filename, otherwise
97 * synthesize and audibilize the text.
99 void FliteProc::synth(
100 const QString &text,
101 const QString &synthFilename,
102 const QString& fliteExePath)
104 // kDebug() << "Running: FliteProc::synth(const QString &text)" << endl;
106 if (m_fliteProc)
108 if (m_fliteProc->isRunning()) m_fliteProc->kill();
109 delete m_fliteProc;
110 m_fliteProc = 0;
112 // kDebug()<< "FliteProc::synth: Creating Flite object" << endl;
113 m_fliteProc = new K3Process;
114 connect(m_fliteProc, SIGNAL(processExited(K3Process*)),
115 this, SLOT(slotProcessExited(K3Process*)));
116 connect(m_fliteProc, SIGNAL(receivedStdout(K3Process*, char*, int)),
117 this, SLOT(slotReceivedStdout(K3Process*, char*, int)));
118 connect(m_fliteProc, SIGNAL(receivedStderr(K3Process*, char*, int)),
119 this, SLOT(slotReceivedStderr(K3Process*, char*, int)));
120 connect(m_fliteProc, SIGNAL(wroteStdin(K3Process*)),
121 this, SLOT(slotWroteStdin(K3Process* )));
122 if (synthFilename.isNull())
123 m_state = psSaying;
124 else
125 m_state = psSynthing;
127 // Encode quotation characters.
128 QString saidText = text;
130 saidText.replace("\\\"", "#!#!");
131 saidText.replace("\"", "\\\"");
132 saidText.replace("#!#!", "\\\"");
133 // Remove certain comment characters.
134 saidText.replace("--", "");
135 saidText = "\"" + saidText + "\"";
137 saidText += '\n';
139 *m_fliteProc << fliteExePath;
140 // *m_fliteProc << "-t" << saidText;
141 if (!synthFilename.isNull()) *m_fliteProc << "-o" << synthFilename;
143 // Ok, let's rock.
144 m_synthFilename = synthFilename;
145 kDebug() << "FliteProc::synth: Synthing text: '" << saidText << "' using Flite plug in" << endl;
146 if (!m_fliteProc->start(K3Process::NotifyOnExit, K3Process::All))
148 kDebug() << "FliteProc::synth: Error starting Flite process. Is flite in the PATH?" << endl;
149 m_state = psIdle;
150 return;
152 kDebug()<< "FliteProc:synth: Flite initialized" << endl;
153 m_fliteProc->writeStdin(saidText.toLatin1(), saidText.length());
157 * Get the generated audio filename from synthText.
158 * @return Name of the audio file the plugin generated.
159 * Null if no such file.
161 * The plugin must not re-use the filename.
163 QString FliteProc::getFilename()
165 kDebug() << "FliteProc::getFilename: returning " << m_synthFilename << endl;
166 return m_synthFilename;
170 * Stop current operation (saying or synthesizing text).
171 * Important: This function may be called from a thread different from the
172 * one that called sayText or synthText.
173 * If the plugin cannot stop an in-progress @ref sayText or
174 * @ref synthText operation, it must not block waiting for it to complete.
175 * Instead, return immediately.
177 * If a plugin returns before the operation has actually been stopped,
178 * the plugin must emit the @ref stopped signal when the operation has
179 * actually stopped.
181 * The plugin should change to the psIdle state after stopping the
182 * operation.
184 void FliteProc::stopText(){
185 kDebug() << "FliteProc::stopText:: Running" << endl;
186 if (m_fliteProc)
188 if (m_fliteProc->isRunning())
190 kDebug() << "FliteProc::stopText: killing Flite." << endl;
191 m_waitingStop = true;
192 m_fliteProc->kill();
193 } else m_state = psIdle;
194 }else m_state = psIdle;
195 kDebug() << "FliteProc::stopText: Flite stopped." << endl;
198 void FliteProc::slotProcessExited(K3Process*)
200 kDebug() << "FliteProc:slotProcessExited: Flite process has exited." << endl;
201 pluginState prevState = m_state;
202 if (m_waitingStop)
204 m_waitingStop = false;
205 m_state = psIdle;
206 emit stopped();
207 } else {
208 m_state = psFinished;
209 if (prevState == psSaying)
210 emit sayFinished();
211 else
212 if (prevState == psSynthing)
213 emit synthFinished();
217 void FliteProc::slotReceivedStdout(K3Process*, char* buffer, int buflen)
219 QString buf = QString::fromLatin1(buffer, buflen);
220 kDebug() << "FliteProc::slotReceivedStdout: Received output from Flite: " << buf << endl;
223 void FliteProc::slotReceivedStderr(K3Process*, char* buffer, int buflen)
225 QString buf = QString::fromLatin1(buffer, buflen);
226 kDebug() << "FliteProc::slotReceivedStderr: Received error from Flite: " << buf << endl;
229 void FliteProc::slotWroteStdin(K3Process*)
231 kDebug() << "FliteProc::slotWroteStdin: closing Stdin" << endl;
232 m_fliteProc->closeStdin();
236 * Return the current state of the plugin.
237 * This function only makes sense in asynchronous mode.
238 * @return The pluginState of the plugin.
240 * @see pluginState
242 pluginState FliteProc::getState() { return m_state; }
245 * Acknowledges a finished state and resets the plugin state to psIdle.
247 * If the plugin is not in state psFinished, nothing happens.
248 * The plugin may use this call to do any post-processing cleanup,
249 * for example, blanking the stored filename (but do not delete the file).
250 * Calling program should call getFilename prior to ackFinished.
252 void FliteProc::ackFinished()
254 if (m_state == psFinished)
256 m_state = psIdle;
257 m_synthFilename.clear();
262 * Returns True if the plugin supports asynchronous processing,
263 * i.e., returns immediately from sayText or synthText.
264 * @return True if this plugin supports asynchronous processing.
266 * If the plugin returns True, it must also implement @ref getState .
267 * It must also emit @ref sayFinished or @ref synthFinished signals when
268 * saying or synthesis is completed.
270 bool FliteProc::supportsAsync() { return true; }
273 * Returns True if the plugin supports synthText method,
274 * i.e., is able to synthesize text to a sound file without
275 * audibilizing the text.
276 * @return True if this plugin supports synthText method.
278 bool FliteProc::supportsSynth() { return true; }