summaryrefslogtreecommitdiff
path: root/utils/rbutilqt/base/ttssapi.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'utils/rbutilqt/base/ttssapi.cpp')
-rw-r--r--utils/rbutilqt/base/ttssapi.cpp274
1 files changed, 274 insertions, 0 deletions
diff --git a/utils/rbutilqt/base/ttssapi.cpp b/utils/rbutilqt/base/ttssapi.cpp
new file mode 100644
index 0000000000..1b326b301e
--- /dev/null
+++ b/utils/rbutilqt/base/ttssapi.cpp
@@ -0,0 +1,274 @@
1/***************************************************************************
2* __________ __ ___.
3* Open \______ \ ____ ____ | | _\_ |__ _______ ___
4* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7* \/ \/ \/ \/ \/
8*
9* Copyright (C) 2007 by Dominik Wenger
10*
11* All files in this archive are subject to the GNU General Public License.
12* See the file COPYING in the source tree root for full license agreement.
13*
14* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
15* KIND, either express or implied.
16*
17****************************************************************************/
18
19#include "ttssapi.h"
20#include "utils.h"
21#include "rbsettings.h"
22#include "playerbuildinfo.h"
23#include "Logger.h"
24
25TTSSapi::TTSSapi(QObject* parent) : TTSBase(parent)
26{
27 m_TTSTemplate = "cscript //nologo \"%exe\" /language:%lang "
28 "/voice:\"%voice\" /speed:%speed \"%options\"";
29 m_TTSVoiceTemplate = "cscript //nologo \"%exe\" /language:%lang /listvoices";
30 m_TTSType = "sapi";
31 defaultLanguage = "english";
32 m_started = false;
33}
34
35TTSBase::Capabilities TTSSapi::capabilities()
36{
37 return None;
38}
39
40void TTSSapi::generateSettings()
41{
42 // language
43 QMap<QString, QVariant> langmap = PlayerBuildInfo::instance()->value(
44 PlayerBuildInfo::LanguageList).toMap();
45 EncTtsSetting* setting = new EncTtsSetting(this,
46 EncTtsSetting::eSTRINGLIST, tr("Language:"),
47 RbSettings::subValue(m_TTSType, RbSettings::TtsLanguage),
48 langmap.keys());
49 connect(setting, &EncTtsSetting::dataChanged, this, &TTSSapi::updateVoiceList);
50 insertSetting(eLANGUAGE,setting);
51 // voice
52 setting = new EncTtsSetting(this,
53 EncTtsSetting::eSTRINGLIST, tr("Voice:"),
54 RbSettings::subValue(m_TTSType, RbSettings::TtsVoice),
55 getVoiceList(RbSettings::subValue(m_TTSType,
56 RbSettings::TtsLanguage).toString()),
57 EncTtsSetting::eREFRESHBTN);
58 connect(setting, &EncTtsSetting::refresh, this, &TTSSapi::updateVoiceList);
59 insertSetting(eVOICE,setting);
60 //speed
61 int speed = RbSettings::subValue(m_TTSType, RbSettings::TtsSpeed).toInt();
62 if(speed > 10 || speed < -10)
63 speed = 0;
64 insertSetting(eSPEED, new EncTtsSetting(this,
65 EncTtsSetting::eINT, tr("Speed:"), speed, -10, 10));
66 // options
67 insertSetting(eOPTIONS, new EncTtsSetting(this,
68 EncTtsSetting::eSTRING, tr("Options:"),
69 RbSettings::subValue(m_TTSType, RbSettings::TtsOptions)));
70
71}
72
73void TTSSapi::saveSettings()
74{
75 //save settings in user config
76 RbSettings::setSubValue(m_TTSType, RbSettings::TtsLanguage,
77 getSetting(eLANGUAGE)->current().toString());
78 RbSettings::setSubValue(m_TTSType, RbSettings::TtsVoice,
79 getSetting(eVOICE)->current().toString());
80 RbSettings::setSubValue(m_TTSType, RbSettings::TtsSpeed,
81 getSetting(eSPEED)->current().toInt());
82 RbSettings::setSubValue(m_TTSType, RbSettings::TtsOptions,
83 getSetting(eOPTIONS)->current().toString());
84
85 RbSettings::sync();
86}
87
88void TTSSapi::updateVoiceList()
89{
90 LOG_INFO() << "updating voicelist";
91 QStringList voiceList = getVoiceList(getSetting(eLANGUAGE)->current().toString());
92 getSetting(eVOICE)->setList(voiceList);
93 if(voiceList.size() > 0) getSetting(eVOICE)->setCurrent(voiceList.at(0));
94 else getSetting(eVOICE)->setCurrent("");
95}
96
97bool TTSSapi::start(QString *errStr)
98{
99
100 m_TTSOpts = RbSettings::subValue(m_TTSType, RbSettings::TtsOptions).toString();
101 m_TTSLanguage =RbSettings::subValue(m_TTSType, RbSettings::TtsLanguage).toString();
102 m_TTSVoice=RbSettings::subValue(m_TTSType, RbSettings::TtsVoice).toString();
103 m_TTSSpeed=RbSettings::subValue(m_TTSType, RbSettings::TtsSpeed).toString();
104
105 QFile::remove(QDir::tempPath() +"/sapi_voice.vbs");
106 QFile::copy(":/builtin/sapi_voice.vbs",QDir::tempPath() + "/sapi_voice.vbs");
107 m_TTSexec = QDir::tempPath() +"/sapi_voice.vbs";
108
109 QFileInfo tts(m_TTSexec);
110 if(!tts.exists())
111 {
112 *errStr = tr("Could not copy the SAPI script");
113 return false;
114 }
115 // create the voice process
116 QString execstring = m_TTSTemplate;
117 execstring.replace("%exe",m_TTSexec);
118 execstring.replace("%options",m_TTSOpts);
119 execstring.replace("%lang",m_TTSLanguage);
120 execstring.replace("%voice",m_TTSVoice);
121 execstring.replace("%speed",m_TTSSpeed);
122
123 LOG_INFO() << "Start:" << execstring;
124 voicescript = new QProcess(nullptr);
125 //connect(voicescript,SIGNAL(readyReadStandardError()),this,SLOT(error()));
126 voicescript->start(execstring);
127 LOG_INFO() << "wait for process";
128 if(!voicescript->waitForStarted())
129 {
130 *errStr = tr("Could not start SAPI process");
131 LOG_ERROR() << "starting process timed out!";
132 return false;
133 }
134
135 if(!voicescript->waitForReadyRead(300))
136 {
137 *errStr = voicescript->readAllStandardError();
138 if(*errStr != "")
139 return false;
140 }
141
142 voicestream = new QTextStream(voicescript);
143#if QT_VERSION < 0x060000
144 voicestream->setCodec("UTF16-LE");
145#else
146 voicestream->setEncoding(QStringConverter::Utf16LE);
147#endif
148
149 m_started = true;
150 return true;
151}
152
153QString TTSSapi::voiceVendor(void)
154{
155 bool keeprunning = m_started;
156 QString vendor;
157 if(!m_started) {
158 QString error;
159 start(&error);
160 }
161 *voicestream << "QUERY\tVENDOR\r\n";
162 voicestream->flush();
163 while((vendor = voicestream->readLine()).isEmpty())
164 QCoreApplication::processEvents();
165
166 LOG_INFO() << "TTS vendor:" << vendor;
167 if(!keeprunning) {
168 stop();
169 }
170 return vendor;
171}
172
173QStringList TTSSapi::getVoiceList(QString language)
174{
175 QStringList result;
176
177 QFile::copy(":/builtin/sapi_voice.vbs",QDir::tempPath() + "/sapi_voice.vbs");
178 m_TTSexec = QDir::tempPath() +"/sapi_voice.vbs";
179
180 QFileInfo tts(m_TTSexec);
181 if(!tts.exists())
182 return result;
183
184 // create the voice process
185 QString execstring = m_TTSVoiceTemplate;
186 execstring.replace("%exe",m_TTSexec);
187 execstring.replace("%lang",language);
188
189 LOG_INFO() << "Start:" << execstring;
190 voicescript = new QProcess(nullptr);
191 voicescript->start(execstring);
192 LOG_INFO() << "wait for process";
193 if(!voicescript->waitForStarted()) {
194 LOG_INFO() << "process startup timed out!";
195 return result;
196 }
197 voicescript->closeWriteChannel();
198 voicescript->waitForReadyRead();
199
200 QString dataRaw = voicescript->readAllStandardError().data();
201 if(dataRaw.startsWith("Error")) {
202 LOG_INFO() << "Error:" << dataRaw;
203 }
204#if QT_VERSION >= 0x050e00
205 result = dataRaw.split(";", Qt::SkipEmptyParts);
206#else
207 result = dataRaw.split(";", QString::SkipEmptyParts);
208#endif
209 if(result.size() > 0)
210 {
211 result.sort();
212 result.removeFirst();
213 for(int i = 0; i< result.size();i++)
214 {
215 result[i] = result.at(i).simplified();
216 }
217 }
218
219 delete voicescript;
220 QFile::setPermissions(QDir::tempPath() +"/sapi_voice.vbs",
221 QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOwner
222 | QFile::ReadUser | QFile::WriteUser | QFile::ExeUser
223 | QFile::ReadGroup | QFile::WriteGroup | QFile::ExeGroup
224 | QFile::ReadOther | QFile::WriteOther | QFile::ExeOther );
225 QFile::remove(QDir::tempPath() +"/sapi_voice.vbs");
226 return result;
227}
228
229
230
231TTSStatus TTSSapi::voice(QString text,QString wavfile, QString *errStr)
232{
233 (void) errStr;
234 QString query = "SPEAK\t"+wavfile+"\t"+text;
235 LOG_INFO() << "voicing" << query;
236 // append newline to query. Done now to keep debug output more readable.
237 query.append("\r\n");
238 *voicestream << query;
239 *voicestream << "SYNC\tbla\r\n";
240 voicestream->flush();
241 // do NOT poll the output with readLine(), this causes sync issues!
242 voicescript->waitForReadyRead();
243
244 if(!QFileInfo(wavfile).isFile()) {
245 LOG_ERROR() << "output file does not exist:" << wavfile;
246 return FatalError;
247 }
248 return NoError;
249}
250
251bool TTSSapi::stop()
252{
253 *voicestream << "QUIT\r\n";
254 voicestream->flush();
255 voicescript->waitForFinished();
256 delete voicestream;
257 delete voicescript;
258 QFile::setPermissions(QDir::tempPath() +"/sapi_voice.vbs",
259 QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOwner
260 | QFile::ReadUser | QFile::WriteUser | QFile::ExeUser
261 | QFile::ReadGroup | QFile::WriteGroup | QFile::ExeGroup
262 | QFile::ReadOther | QFile::WriteOther | QFile::ExeOther );
263 QFile::remove(QDir::tempPath() +"/sapi_voice.vbs");
264 m_started = false;
265 return true;
266}
267
268bool TTSSapi::configOk()
269{
270 if(RbSettings::subValue(m_TTSType, RbSettings::TtsVoice).toString().isEmpty())
271 return false;
272 return true;
273}
274