Fix SAPI default speed being way too fast.
[kugel-rb.git] / rbutil / rbutilqt / base / ttssapi.cpp
blobcd9ced80837398d34cf58b06d277aea857d64290
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 "ttssapi.h"
21 #include "utils.h"
22 #include "rbsettings.h"
23 #include "systeminfo.h"
25 TTSSapi::TTSSapi(QObject* parent) : TTSBase(parent)
27 m_TTSTemplate = "cscript //nologo \"%exe\" /language:%lang /voice:\"%voice\""
28 " /speed:%speed \"%options\"";
29 defaultLanguage ="english";
30 m_sapi4 =false;
33 TTSBase::Capabilities TTSSapi::capabilities()
35 return None;
38 void TTSSapi::generateSettings()
40 // language
41 QMap<QString, QString> languages = SystemInfo::languages();
42 EncTtsSetting* setting =new EncTtsSetting(this,EncTtsSetting::eSTRINGLIST,
43 tr("Language:"),RbSettings::subValue("sapi",RbSettings::TtsLanguage),
44 languages.values());
45 connect(setting,SIGNAL(dataChanged()),this,SLOT(updateVoiceList()));
46 insertSetting(eLANGUAGE,setting);
47 // voice
48 setting = new EncTtsSetting(this,EncTtsSetting::eSTRINGLIST,
49 tr("Voice:"),RbSettings::subValue("sapi",RbSettings::TtsVoice),
50 getVoiceList(RbSettings::subValue("sapi",RbSettings::TtsLanguage).toString()),
51 EncTtsSetting::eREFRESHBTN);
52 connect(setting,SIGNAL(refresh()),this,SLOT(updateVoiceList()));
53 insertSetting(eVOICE,setting);
54 //speed
55 int speed = RbSettings::subValue("sapi", RbSettings::TtsSpeed).toInt();
56 if(speed > 10 || speed < -10)
57 speed = 0;
58 insertSetting(eSPEED, new EncTtsSetting(this, EncTtsSetting::eINT,
59 tr("Speed:"), speed, -10, 10));
60 // options
61 insertSetting(eOPTIONS,new EncTtsSetting(this,EncTtsSetting::eSTRING,
62 tr("Options:"),RbSettings::subValue("sapi",RbSettings::TtsOptions)));
66 void TTSSapi::saveSettings()
68 //save settings in user config
69 RbSettings::setSubValue("sapi",RbSettings::TtsLanguage,
70 getSetting(eLANGUAGE)->current().toString());
71 RbSettings::setSubValue("sapi",RbSettings::TtsVoice,
72 getSetting(eVOICE)->current().toString());
73 RbSettings::setSubValue("sapi",RbSettings::TtsSpeed,
74 getSetting(eSPEED)->current().toInt());
75 RbSettings::setSubValue("sapi",RbSettings::TtsOptions,
76 getSetting(eOPTIONS)->current().toString());
78 RbSettings::sync();
81 void TTSSapi::updateVoiceList()
83 qDebug() << "update voiceList";
84 QStringList voiceList = getVoiceList(getSetting(eLANGUAGE)->current().toString());
85 getSetting(eVOICE)->setList(voiceList);
86 if(voiceList.size() > 0) getSetting(eVOICE)->setCurrent(voiceList.at(0));
87 else getSetting(eVOICE)->setCurrent("");
90 bool TTSSapi::start(QString *errStr)
93 m_TTSOpts = RbSettings::subValue("sapi",RbSettings::TtsOptions).toString();
94 m_TTSLanguage =RbSettings::subValue("sapi",RbSettings::TtsLanguage).toString();
95 m_TTSVoice=RbSettings::subValue("sapi",RbSettings::TtsVoice).toString();
96 m_TTSSpeed=RbSettings::subValue("sapi",RbSettings::TtsSpeed).toString();
97 m_sapi4 = RbSettings::subValue("sapi",RbSettings::TtsUseSapi4).toBool();
99 QFile::remove(QDir::tempPath() +"/sapi_voice.vbs");
100 QFile::copy(":/builtin/sapi_voice.vbs",QDir::tempPath() + "/sapi_voice.vbs");
101 m_TTSexec = QDir::tempPath() +"/sapi_voice.vbs";
103 QFileInfo tts(m_TTSexec);
104 if(!tts.exists())
106 *errStr = tr("Could not copy the Sapi-script");
107 return false;
109 // create the voice process
110 QString execstring = m_TTSTemplate;
111 execstring.replace("%exe",m_TTSexec);
112 execstring.replace("%options",m_TTSOpts);
113 execstring.replace("%lang",m_TTSLanguage);
114 execstring.replace("%voice",m_TTSVoice);
115 execstring.replace("%speed",m_TTSSpeed);
117 if(m_sapi4)
118 execstring.append(" /sapi4 ");
120 qDebug() << "init" << execstring;
121 voicescript = new QProcess(NULL);
122 //connect(voicescript,SIGNAL(readyReadStandardError()),this,SLOT(error()));
124 voicescript->start(execstring);
125 if(!voicescript->waitForStarted())
127 *errStr = tr("Could not start the Sapi-script");
128 return false;
131 if(!voicescript->waitForReadyRead(300))
133 *errStr = voicescript->readAllStandardError();
134 if(*errStr != "")
135 return false;
138 voicestream = new QTextStream(voicescript);
139 voicestream->setCodec("UTF16-LE");
141 return true;
145 QStringList TTSSapi::getVoiceList(QString language)
147 QStringList result;
149 QFile::copy(":/builtin/sapi_voice.vbs",QDir::tempPath() + "/sapi_voice.vbs");
150 m_TTSexec = QDir::tempPath() +"/sapi_voice.vbs";
152 QFileInfo tts(m_TTSexec);
153 if(!tts.exists())
154 return result;
156 // create the voice process
157 QString execstring = "cscript //nologo \"%exe\" /language:%lang /listvoices";
158 execstring.replace("%exe",m_TTSexec);
159 execstring.replace("%lang",language);
161 if(RbSettings::value(RbSettings::TtsUseSapi4).toBool())
162 execstring.append(" /sapi4 ");
164 qDebug() << "init" << execstring;
165 voicescript = new QProcess(NULL);
166 voicescript->start(execstring);
167 qDebug() << "wait for started";
168 if(!voicescript->waitForStarted())
169 return result;
170 voicescript->closeWriteChannel();
171 voicescript->waitForReadyRead();
173 QString dataRaw = voicescript->readAllStandardError().data();
174 result = dataRaw.split(",",QString::SkipEmptyParts);
175 if(result.size() > 0)
177 result.sort();
178 result.removeFirst();
179 for(int i = 0; i< result.size();i++)
181 result[i] = result.at(i).simplified();
185 delete voicescript;
186 QFile::setPermissions(QDir::tempPath() +"/sapi_voice.vbs",
187 QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOwner
188 | QFile::ReadUser | QFile::WriteUser | QFile::ExeUser
189 | QFile::ReadGroup | QFile::WriteGroup | QFile::ExeGroup
190 | QFile::ReadOther | QFile::WriteOther | QFile::ExeOther );
191 QFile::remove(QDir::tempPath() +"/sapi_voice.vbs");
192 return result;
197 TTSStatus TTSSapi::voice(QString text,QString wavfile, QString *errStr)
199 (void) errStr;
200 QString query = "SPEAK\t"+wavfile+"\t"+text;
201 qDebug() << "[TTSSapi] voicing" << query;
202 // append newline to query. Done now to keep debug output more readable.
203 query.append("\r\n");
204 *voicestream << query;
205 *voicestream << "SYNC\tbla\r\n";
206 voicestream->flush();
207 char temp[20];
209 //we use this, because waitForReadyRead doesnt work from a different thread
210 while( voicescript->readLine(temp,20) == 0)
211 QCoreApplication::processEvents();
213 return NoError;
216 bool TTSSapi::stop()
218 *voicestream << "QUIT\r\n";
219 voicestream->flush();
220 voicescript->waitForFinished();
221 delete voicestream;
222 delete voicescript;
223 QFile::setPermissions(QDir::tempPath() +"/sapi_voice.vbs",
224 QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOwner
225 | QFile::ReadUser | QFile::WriteUser | QFile::ExeUser
226 | QFile::ReadGroup | QFile::WriteGroup | QFile::ExeGroup
227 | QFile::ReadOther | QFile::WriteOther | QFile::ExeOther );
228 QFile::remove(QDir::tempPath() +"/sapi_voice.vbs");
229 return true;
232 bool TTSSapi::configOk()
234 if(RbSettings::subValue("sapi",RbSettings::TtsVoice).toString().isEmpty())
235 return false;
236 return true;