1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
9 * Copyright (C) 2007 by Dominik Wenger
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.
14 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
15 * KIND, either express or implied.
17 ****************************************************************************/
21 #include "rbsettings.h"
22 #include "systeminfo.h"
24 TTSSapi::TTSSapi(QObject
* parent
) : TTSBase(parent
)
26 m_TTSTemplate
= "cscript //nologo \"%exe\" /language:%lang /voice:\"%voice\""
27 " /speed:%speed \"%options\"";
28 defaultLanguage
= "english";
33 TTSBase::Capabilities
TTSSapi::capabilities()
38 void TTSSapi::generateSettings()
41 QMap
<QString
, QStringList
> languages
= SystemInfo::languages();
43 for(int i
= 0; i
< languages
.values().size(); ++i
) {
44 langs
.append(languages
.values().at(i
).at(0));
46 EncTtsSetting
* setting
=new EncTtsSetting(this,EncTtsSetting::eSTRINGLIST
,
47 tr("Language:"),RbSettings::subValue("sapi",RbSettings::TtsLanguage
),
49 connect(setting
,SIGNAL(dataChanged()),this,SLOT(updateVoiceList()));
50 insertSetting(eLANGUAGE
,setting
);
52 setting
= new EncTtsSetting(this,EncTtsSetting::eSTRINGLIST
,
53 tr("Voice:"),RbSettings::subValue("sapi",RbSettings::TtsVoice
),
54 getVoiceList(RbSettings::subValue("sapi",RbSettings::TtsLanguage
).toString()),
55 EncTtsSetting::eREFRESHBTN
);
56 connect(setting
,SIGNAL(refresh()),this,SLOT(updateVoiceList()));
57 insertSetting(eVOICE
,setting
);
59 int speed
= RbSettings::subValue("sapi", RbSettings::TtsSpeed
).toInt();
60 if(speed
> 10 || speed
< -10)
62 insertSetting(eSPEED
, new EncTtsSetting(this, EncTtsSetting::eINT
,
63 tr("Speed:"), speed
, -10, 10));
65 insertSetting(eOPTIONS
,new EncTtsSetting(this,EncTtsSetting::eSTRING
,
66 tr("Options:"),RbSettings::subValue("sapi",RbSettings::TtsOptions
)));
70 void TTSSapi::saveSettings()
72 //save settings in user config
73 RbSettings::setSubValue("sapi",RbSettings::TtsLanguage
,
74 getSetting(eLANGUAGE
)->current().toString());
75 RbSettings::setSubValue("sapi",RbSettings::TtsVoice
,
76 getSetting(eVOICE
)->current().toString());
77 RbSettings::setSubValue("sapi",RbSettings::TtsSpeed
,
78 getSetting(eSPEED
)->current().toInt());
79 RbSettings::setSubValue("sapi",RbSettings::TtsOptions
,
80 getSetting(eOPTIONS
)->current().toString());
85 void TTSSapi::updateVoiceList()
87 qDebug() << "[TTSSapi] updating voicelist";
88 QStringList voiceList
= getVoiceList(getSetting(eLANGUAGE
)->current().toString());
89 getSetting(eVOICE
)->setList(voiceList
);
90 if(voiceList
.size() > 0) getSetting(eVOICE
)->setCurrent(voiceList
.at(0));
91 else getSetting(eVOICE
)->setCurrent("");
94 bool TTSSapi::start(QString
*errStr
)
97 m_TTSOpts
= RbSettings::subValue("sapi",RbSettings::TtsOptions
).toString();
98 m_TTSLanguage
=RbSettings::subValue("sapi",RbSettings::TtsLanguage
).toString();
99 m_TTSVoice
=RbSettings::subValue("sapi",RbSettings::TtsVoice
).toString();
100 m_TTSSpeed
=RbSettings::subValue("sapi",RbSettings::TtsSpeed
).toString();
101 m_sapi4
= RbSettings::subValue("sapi",RbSettings::TtsUseSapi4
).toBool();
103 QFile::remove(QDir::tempPath() +"/sapi_voice.vbs");
104 QFile::copy(":/builtin/sapi_voice.vbs",QDir::tempPath() + "/sapi_voice.vbs");
105 m_TTSexec
= QDir::tempPath() +"/sapi_voice.vbs";
107 QFileInfo
tts(m_TTSexec
);
110 *errStr
= tr("Could not copy the SAPI script");
113 // create the voice process
114 QString execstring
= m_TTSTemplate
;
115 execstring
.replace("%exe",m_TTSexec
);
116 execstring
.replace("%options",m_TTSOpts
);
117 execstring
.replace("%lang",m_TTSLanguage
);
118 execstring
.replace("%voice",m_TTSVoice
);
119 execstring
.replace("%speed",m_TTSSpeed
);
122 execstring
.append(" /sapi4 ");
124 qDebug() << "[TTSSapi] Start:" << execstring
;
125 voicescript
= new QProcess(NULL
);
126 //connect(voicescript,SIGNAL(readyReadStandardError()),this,SLOT(error()));
127 voicescript
->start(execstring
);
128 qDebug() << "[TTSSapi] wait for process";
129 if(!voicescript
->waitForStarted())
131 *errStr
= tr("Could not start SAPI process");
132 qDebug() << "[TTSSapi] starting process timed out!";
136 if(!voicescript
->waitForReadyRead(300))
138 *errStr
= voicescript
->readAllStandardError();
143 voicestream
= new QTextStream(voicescript
);
144 voicestream
->setCodec("UTF16-LE");
150 QString
TTSSapi::voiceVendor(void)
152 bool keeprunning
= m_started
;
158 *voicestream
<< "QUERY\tVENDOR\r\n";
159 voicestream
->flush();
160 while((vendor
= voicestream
->readLine()).isEmpty())
161 QCoreApplication::processEvents();
163 qDebug() << "[TTSSAPI] TTS vendor:" << vendor
;
170 QStringList
TTSSapi::getVoiceList(QString language
)
174 QFile::copy(":/builtin/sapi_voice.vbs",QDir::tempPath() + "/sapi_voice.vbs");
175 m_TTSexec
= QDir::tempPath() +"/sapi_voice.vbs";
177 QFileInfo
tts(m_TTSexec
);
181 // create the voice process
182 QString execstring
= "cscript //nologo \"%exe\" /language:%lang /listvoices";
183 execstring
.replace("%exe",m_TTSexec
);
184 execstring
.replace("%lang",language
);
186 if(RbSettings::value(RbSettings::TtsUseSapi4
).toBool())
187 execstring
.append(" /sapi4 ");
189 qDebug() << "[TTSSapi] Start:" << execstring
;
190 voicescript
= new QProcess(NULL
);
191 voicescript
->start(execstring
);
192 qDebug() << "[TTSSapi] wait for process";
193 if(!voicescript
->waitForStarted()) {
194 qDebug() << "[TTSSapi] process startup timed out!";
197 voicescript
->closeWriteChannel();
198 voicescript
->waitForReadyRead();
200 QString dataRaw
= voicescript
->readAllStandardError().data();
201 result
= dataRaw
.split(",",QString::SkipEmptyParts
);
202 if(result
.size() > 0)
205 result
.removeFirst();
206 for(int i
= 0; i
< result
.size();i
++)
208 result
[i
] = result
.at(i
).simplified();
213 QFile::setPermissions(QDir::tempPath() +"/sapi_voice.vbs",
214 QFile::ReadOwner
| QFile::WriteOwner
| QFile::ExeOwner
215 | QFile::ReadUser
| QFile::WriteUser
| QFile::ExeUser
216 | QFile::ReadGroup
| QFile::WriteGroup
| QFile::ExeGroup
217 | QFile::ReadOther
| QFile::WriteOther
| QFile::ExeOther
);
218 QFile::remove(QDir::tempPath() +"/sapi_voice.vbs");
224 TTSStatus
TTSSapi::voice(QString text
,QString wavfile
, QString
*errStr
)
227 QString query
= "SPEAK\t"+wavfile
+"\t"+text
;
228 qDebug() << "[TTSSapi] voicing" << query
;
229 // append newline to query. Done now to keep debug output more readable.
230 query
.append("\r\n");
231 *voicestream
<< query
;
232 *voicestream
<< "SYNC\tbla\r\n";
233 voicestream
->flush();
234 // do NOT poll the output with readLine(), this causes sync issues!
235 voicescript
->waitForReadyRead();
237 if(!QFileInfo(wavfile
).isFile()) {
238 qDebug() << "[TTSSapi] output file does not exist:" << wavfile
;
246 *voicestream
<< "QUIT\r\n";
247 voicestream
->flush();
248 voicescript
->waitForFinished();
251 QFile::setPermissions(QDir::tempPath() +"/sapi_voice.vbs",
252 QFile::ReadOwner
| QFile::WriteOwner
| QFile::ExeOwner
253 | QFile::ReadUser
| QFile::WriteUser
| QFile::ExeUser
254 | QFile::ReadGroup
| QFile::WriteGroup
| QFile::ExeGroup
255 | QFile::ReadOther
| QFile::WriteOther
| QFile::ExeOther
);
256 QFile::remove(QDir::tempPath() +"/sapi_voice.vbs");
261 bool TTSSapi::configOk()
263 if(RbSettings::subValue("sapi",RbSettings::TtsVoice
).toString().isEmpty())