codec.link must be created with -DCODEC
[kugel-rb.git] / rbutil / rbutilqt / tts.cpp
blob76eacd54caf69fecc3be273a2448a5d3cdc0ff1d
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
9 * Copyright (C) 2007 by Dominik Wenger
10 * $Id$
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
20 #include "tts.h"
23 // static variables
24 QMap<QString,QString> TTSBase::ttsList;
25 QMap<QString,TTSBase*> TTSBase::ttsCache;
27 // static functions
28 void TTSBase::initTTSList()
30 ttsList["espeak"] = "Espeak TTS Engine";
31 ttsList["flite"] = "Flite TTS Engine";
32 ttsList["swift"] = "Swift TTS Engine";
33 #if defined(Q_OS_WIN)
34 ttsList["sapi"] = "Sapi TTS Engine";
35 #endif
39 // function to get a specific encoder
40 TTSBase* TTSBase::getTTS(QString ttsName)
42 // check cache
43 if(ttsCache.contains(ttsName))
44 return ttsCache.value(ttsName);
46 TTSBase* tts;
47 if(ttsName == "sapi")
49 tts = new TTSSapi();
50 ttsCache[ttsName] = tts;
51 return tts;
53 else
55 tts = new TTSExes(ttsName);
56 ttsCache[ttsName] = tts;
57 return tts;
61 // get the list of encoders, nice names
62 QStringList TTSBase::getTTSList()
64 // init list if its empty
65 if(ttsList.count() == 0)
66 initTTSList();
68 return ttsList.keys();
71 // get nice name of a specific tts
72 QString TTSBase::getTTSName(QString tts)
74 if(ttsList.isEmpty())
75 initTTSList();
76 return ttsList.value(tts);
79 /*********************************************************************
80 * TTS Base
81 **********************************************************************/
82 TTSBase::TTSBase(): QObject()
87 /*********************************************************************
88 * General TTS Exes
89 **********************************************************************/
90 TTSExes::TTSExes(QString name) : TTSBase()
92 m_name = name;
94 m_TemplateMap["espeak"] = "\"%exe\" %options -w \"%wavfile\" \"%text\"";
95 m_TemplateMap["flite"] = "\"%exe\" %options -o \"%wavfile\" \"%text\"";
96 m_TemplateMap["swift"] = "\"%exe\" %options -o \"%wavfile\" \"%text\"";
100 void TTSExes::setCfg(RbSettings* sett)
102 // call function of base class
103 TTSBase::setCfg(sett);
105 // if the config isnt OK, try to autodetect
106 if(!configOk())
108 QString exepath;
109 //try autodetect tts
110 #if defined(Q_OS_LINUX) || defined(Q_OS_MACX)
111 QStringList path = QString(getenv("PATH")).split(":", QString::SkipEmptyParts);
112 #elif defined(Q_OS_WIN)
113 QStringList path = QString(getenv("PATH")).split(";", QString::SkipEmptyParts);
114 #endif
115 qDebug() << path;
116 for(int i = 0; i < path.size(); i++)
118 QString executable = QDir::fromNativeSeparators(path.at(i)) + "/" + m_name;
119 #if defined(Q_OS_WIN)
120 executable += ".exe";
121 QStringList ex = executable.split("\"", QString::SkipEmptyParts);
122 executable = ex.join("");
123 #endif
124 qDebug() << executable;
125 if(QFileInfo(executable).isExecutable())
127 exepath= QDir::toNativeSeparators(executable);
128 break;
131 settings->setTTSPath(m_name,exepath);
132 settings->sync();
137 bool TTSExes::start(QString *errStr)
139 m_TTSexec = settings->ttsPath(m_name);
140 m_TTSOpts = settings->ttsOptions(m_name);
142 m_TTSTemplate = m_TemplateMap.value(m_name);
144 QFileInfo tts(m_TTSexec);
145 if(tts.exists())
147 return true;
149 else
151 *errStr = tr("TTS executable not found");
152 return false;
156 bool TTSExes::voice(QString text,QString wavfile)
158 QString execstring = m_TTSTemplate;
160 execstring.replace("%exe",m_TTSexec);
161 execstring.replace("%options",m_TTSOpts);
162 execstring.replace("%wavfile",wavfile);
163 execstring.replace("%text",text);
164 //qDebug() << "voicing" << execstring;
165 QProcess::execute(execstring);
166 return true;
170 void TTSExes::showCfg()
172 #ifndef CONSOLE
173 TTSExesGui gui;
174 #else
175 TTSExesGuiCli gui;
176 #endif
177 gui.setCfg(settings);
178 gui.showCfg(m_name);
181 bool TTSExes::configOk()
183 QString path = settings->ttsPath(m_name);
185 if (QFileInfo(path).exists())
186 return true;
188 return false;
191 /*********************************************************************
192 * TTS Sapi
193 **********************************************************************/
194 TTSSapi::TTSSapi() : TTSBase()
196 m_TTSTemplate = "cscript //nologo \"%exe\" /language:%lang /voice:\"%voice\" /speed:%speed \"%options\"";
197 defaultLanguage ="english";
198 m_sapi4 =false;
202 bool TTSSapi::start(QString *errStr)
205 m_TTSOpts = settings->ttsOptions("sapi");
206 m_TTSLanguage =settings->ttsLang("sapi");
207 m_TTSVoice=settings->ttsVoice("sapi");
208 m_TTSSpeed=QString("%1").arg(settings->ttsSpeed("sapi"));
209 m_sapi4 = settings->ttsUseSapi4();
211 QFile::remove(QDir::tempPath() +"/sapi_voice.vbs");
212 QFile::copy(":/builtin/sapi_voice.vbs",QDir::tempPath() + "/sapi_voice.vbs");
213 m_TTSexec = QDir::tempPath() +"/sapi_voice.vbs";
215 QFileInfo tts(m_TTSexec);
216 if(!tts.exists())
218 *errStr = tr("Could not copy the Sapi-script");
219 return false;
221 // create the voice process
222 QString execstring = m_TTSTemplate;
223 execstring.replace("%exe",m_TTSexec);
224 execstring.replace("%options",m_TTSOpts);
225 execstring.replace("%lang",m_TTSLanguage);
226 execstring.replace("%voice",m_TTSVoice);
227 execstring.replace("%speed",m_TTSSpeed);
229 if(m_sapi4)
230 execstring.append(" /sapi4 ");
232 qDebug() << "init" << execstring;
233 voicescript = new QProcess(NULL);
234 //connect(voicescript,SIGNAL(readyReadStandardError()),this,SLOT(error()));
236 voicescript->start(execstring);
237 if(!voicescript->waitForStarted())
239 *errStr = tr("Could not start the Sapi-script");
240 return false;
243 if(!voicescript->waitForReadyRead(300))
245 *errStr = voicescript->readAllStandardError();
246 if(*errStr != "")
247 return false;
250 voicestream = new QTextStream(voicescript);
251 voicestream->setCodec("UTF16-LE");
253 return true;
257 QStringList TTSSapi::getVoiceList(QString language)
259 QStringList result;
261 QFile::copy(":/builtin/sapi_voice.vbs",QDir::tempPath() + "/sapi_voice.vbs");
262 m_TTSexec = QDir::tempPath() +"/sapi_voice.vbs";
264 QFileInfo tts(m_TTSexec);
265 if(!tts.exists())
266 return result;
268 // create the voice process
269 QString execstring = "cscript //nologo \"%exe\" /language:%lang /listvoices";
270 execstring.replace("%exe",m_TTSexec);
271 execstring.replace("%lang",language);
273 if(settings->ttsUseSapi4())
274 execstring.append(" /sapi4 ");
276 qDebug() << "init" << execstring;
277 voicescript = new QProcess(NULL);
278 voicescript->start(execstring);
279 qDebug() << "wait for started";
280 if(!voicescript->waitForStarted())
281 return result;
282 voicescript->closeWriteChannel();
283 voicescript->waitForReadyRead();
285 QString dataRaw = voicescript->readAllStandardError().data();
286 result = dataRaw.split(",",QString::SkipEmptyParts);
287 result.sort();
288 result.removeFirst();
289 for(int i = 0; i< result.size();i++)
291 result[i] = result.at(i).simplified();
295 delete voicescript;
296 QFile::setPermissions(QDir::tempPath() +"/sapi_voice.vbs",QFile::ReadOwner |QFile::WriteOwner|QFile::ExeOwner
297 |QFile::ReadUser| QFile::WriteUser| QFile::ExeUser
298 |QFile::ReadGroup |QFile::WriteGroup |QFile::ExeGroup
299 |QFile::ReadOther |QFile::WriteOther |QFile::ExeOther );
300 QFile::remove(QDir::tempPath() +"/sapi_voice.vbs");
302 return result;
307 bool TTSSapi::voice(QString text,QString wavfile)
309 QString query = "SPEAK\t"+wavfile+"\t"+text+"\r\n";
310 qDebug() << "voicing" << query;
311 *voicestream << query;
312 *voicestream << "SYNC\tbla\r\n";
313 voicestream->flush();
314 voicescript->waitForReadyRead();
315 return true;
318 bool TTSSapi::stop()
321 *voicestream << "QUIT\r\n";
322 voicestream->flush();
323 voicescript->waitForFinished();
324 delete voicestream;
325 delete voicescript;
326 QFile::setPermissions(QDir::tempPath() +"/sapi_voice.vbs",QFile::ReadOwner |QFile::WriteOwner|QFile::ExeOwner
327 |QFile::ReadUser| QFile::WriteUser| QFile::ExeUser
328 |QFile::ReadGroup |QFile::WriteGroup |QFile::ExeGroup
329 |QFile::ReadOther |QFile::WriteOther |QFile::ExeOther );
330 QFile::remove(QDir::tempPath() +"/sapi_voice.vbs");
331 return true;
335 void TTSSapi::showCfg()
337 #ifndef CONSOLE
338 TTSSapiGui gui(this);
339 #else
340 TTSSapiGuiCli gui(this);
341 #endif
342 gui.setCfg(settings);
343 gui.showCfg();
346 bool TTSSapi::configOk()
348 if(settings->ttsVoice("sapi").isEmpty())
349 return false;
350 return true;