1 /***************************************************** vim:set ts=4 sw=4 sts=4:
2 Main speaking functions for the Festival Lite (Flite) Plug in
5 (C) 2004 by Gary Cramblitt <garycramblitt@comcast.net>
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 ******************************************************************************/
30 #include <kstandarddirs.h>
31 #include <k3process.h>
33 // Flite Plugin includes.
34 #include "fliteproc.h"
35 #include "fliteproc.moc"
38 FliteProc::FliteProc( QObject
* parent
, const QStringList
& ) :
39 PlugInProc( parent
, "fliteproc" ){
40 kDebug() << "FliteProc::FliteProc: Running" << endl
;
42 m_waitingStop
= false;
47 FliteProc::~FliteProc(){
48 kDebug() << "FliteProc::~FliteProc:: Running" << endl
;
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
;
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
);
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
);
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(
101 const QString
&synthFilename
,
102 const QString
& fliteExePath
)
104 // kDebug() << "Running: FliteProc::synth(const QString &text)" << endl;
108 if (m_fliteProc
->isRunning()) m_fliteProc
->kill();
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())
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 + "\"";
139 *m_fliteProc
<< fliteExePath
;
140 // *m_fliteProc << "-t" << saidText;
141 if (!synthFilename
.isNull()) *m_fliteProc
<< "-o" << synthFilename
;
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
;
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
181 * The plugin should change to the psIdle state after stopping the
184 void FliteProc::stopText(){
185 kDebug() << "FliteProc::stopText:: Running" << endl
;
188 if (m_fliteProc
->isRunning())
190 kDebug() << "FliteProc::stopText: killing Flite." << endl
;
191 m_waitingStop
= true;
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
;
204 m_waitingStop
= false;
208 m_state
= psFinished
;
209 if (prevState
== psSaying
)
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.
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
)
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; }