FS#10925 by myself: add touchscreen support for virtual keyboard.
[kugel-rb.git] / rbutil / rbutilqt / base / talkgenerator.cpp
blobbc7e5f18b0a8a36feecd9efa1a611a1be43f0e46
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 "talkgenerator.h"
21 #include "rbsettings.h"
22 #include "systeminfo.h"
23 #include "wavtrim.h"
25 TalkGenerator::TalkGenerator(QObject* parent): QObject(parent), encFutureWatcher(this), ttsFutureWatcher(this)
30 //! \brief Creates Talkfiles.
31 //!
32 TalkGenerator::Status TalkGenerator::process(QList<TalkEntry>* list,int wavtrimth)
34 QString errStr;
35 bool warnings = false;
37 //tts
38 emit logItem(tr("Starting TTS Engine"),LOGINFO);
39 m_tts = TTSBase::getTTS(this,RbSettings::value(RbSettings::Tts).toString());
40 if(!m_tts->start(&errStr))
42 emit logItem(errStr.trimmed(),LOGERROR);
43 emit logItem(tr("Init of TTS engine failed"),LOGERROR);
44 emit done(true);
45 return eERROR;
47 QCoreApplication::processEvents();
49 // Encoder
50 emit logItem(tr("Starting Encoder Engine"),LOGINFO);
51 m_enc = EncBase::getEncoder(this,SystemInfo::value(SystemInfo::CurEncoder).toString());
52 if(!m_enc->start())
54 emit logItem(tr("Init of Encoder engine failed"),LOGERROR);
55 emit done(true);
56 m_tts->stop();
57 return eERROR;
59 QCoreApplication::processEvents();
61 emit logProgress(0,0);
63 // Voice entries
64 emit logItem(tr("Voicing entries..."),LOGINFO);
65 Status voiceStatus= voiceList(list,wavtrimth);
66 if(voiceStatus == eERROR)
68 m_tts->stop();
69 m_enc->stop();
70 emit done(true);
71 return eERROR;
73 else if( voiceStatus == eWARNING)
74 warnings = true;
76 QCoreApplication::processEvents();
78 // Encoding Entries
79 emit logItem(tr("Encoding files..."),LOGINFO);
80 Status encoderStatus = encodeList(list);
81 if( encoderStatus == eERROR)
83 m_tts->stop();
84 m_enc->stop();
85 emit done(true);
86 return eERROR;
88 else if( voiceStatus == eWARNING)
89 warnings = true;
91 QCoreApplication::processEvents();
93 m_tts->stop();
94 m_enc->stop();
95 emit logProgress(1,1);
97 if(warnings)
98 return eWARNING;
99 return eOK;
102 //! \brief Voices a List of string
104 TalkGenerator::Status TalkGenerator::voiceList(QList<TalkEntry>* list,int wavtrimth)
106 emit logProgress(0, list->size());
108 QStringList duplicates;
110 m_ttsWarnings = false;
111 for(int i=0; i < list->size(); i++)
113 (*list)[i].refs.tts = m_tts;
114 (*list)[i].refs.wavtrim = wavtrimth;
115 (*list)[i].refs.generator = this;
117 // skip duplicated wav entries
118 if(!duplicates.contains(list->at(i).wavfilename))
119 duplicates.append(list->at(i).wavfilename);
120 else
122 qDebug() << "[TalkGen] duplicate skipped";
123 (*list)[i].voiced = true;
124 continue;
128 /* If the engine can't be parallelized, we use only 1 thread */
129 int maxThreadCount = QThreadPool::globalInstance()->maxThreadCount();
130 if ((m_tts->capabilities() & TTSBase::RunInParallel) == 0)
131 QThreadPool::globalInstance()->setMaxThreadCount(1);
133 connect(&ttsFutureWatcher, SIGNAL(progressValueChanged(int)),
134 this, SLOT(ttsProgress(int)));
135 ttsFutureWatcher.setFuture(QtConcurrent::map(*list, &TalkGenerator::ttsEntryPoint));
137 /* We use this loop as an equivalent to ttsFutureWatcher.waitForFinished()
138 * since the latter blocks all events */
139 while(ttsFutureWatcher.isRunning())
140 QCoreApplication::processEvents();
142 /* Restore global settings, if we changed them */
143 if ((m_tts->capabilities() & TTSBase::RunInParallel) == 0)
144 QThreadPool::globalInstance()->setMaxThreadCount(maxThreadCount);
146 if(ttsFutureWatcher.isCanceled())
147 return eERROR;
148 else if(m_ttsWarnings)
149 return eWARNING;
150 else
151 return eOK;
154 void TalkGenerator::ttsEntryPoint(TalkEntry& entry)
156 if (!entry.voiced && !entry.toSpeak.isEmpty())
158 QString error;
159 qDebug() << "[TalkGen] voicing: " << entry.toSpeak << "to" << entry.wavfilename;
160 TTSStatus status = entry.refs.tts->voice(entry.toSpeak,entry.wavfilename, &error);
161 if (status == Warning || status == FatalError)
163 entry.refs.generator->ttsFailEntry(entry, status, error);
164 return;
166 if (entry.refs.wavtrim != -1)
168 char buffer[255];
169 wavtrim(entry.wavfilename.toLocal8Bit().data(), entry.refs.wavtrim, buffer, 255);
171 entry.voiced = true;
175 void TalkGenerator::ttsFailEntry(const TalkEntry& entry, TTSStatus status, QString error)
177 if(status == Warning)
179 m_ttsWarnings = true;
180 emit logItem(tr("Voicing of %1 failed: %2").arg(entry.toSpeak).arg(error),
181 LOGWARNING);
183 else if (status == FatalError)
185 emit logItem(tr("Voicing of %1 failed: %2").arg(entry.toSpeak).arg(error),
186 LOGERROR);
187 abort();
191 void TalkGenerator::ttsProgress(int value)
193 emit logProgress(value,ttsFutureWatcher.progressMaximum());
196 //! \brief Encodes a List of strings
198 TalkGenerator::Status TalkGenerator::encodeList(QList<TalkEntry>* list)
200 QStringList duplicates;
202 int itemsCount = list->size();
203 emit logProgress(0, itemsCount);
205 /* Do some preprocessing and remove entries that have not been voiced. */
206 for (int idx=0; idx < itemsCount; idx++)
208 if(list->at(idx).voiced == false)
210 qDebug() << "[TalkGen] unvoiced entry" << list->at(idx).toSpeak <<"detected";
211 list->removeAt(idx);
212 itemsCount--;
213 idx--;
214 continue;
216 if(duplicates.contains(list->at(idx).talkfilename))
218 (*list)[idx].encoded = true; /* make sure we skip this entry */
219 continue;
221 duplicates.append(list->at(idx).talkfilename);
222 (*list)[idx].refs.encoder = m_enc;
223 (*list)[idx].refs.generator = this; /* not really needed, unless we end up
224 voicing and encoding with two different
225 TalkGenerators.*/
228 connect(&encFutureWatcher, SIGNAL(progressValueChanged(int)),
229 this, SLOT(encProgress(int)));
230 encFutureWatcher.setFuture(QtConcurrent::map(*list, &TalkGenerator::encEntryPoint));
232 /* We use this loop as an equivalent to encFutureWatcher.waitForFinished()
233 * since the latter blocks all events */
234 while (encFutureWatcher.isRunning())
235 QCoreApplication::processEvents(QEventLoop::AllEvents);
237 if (encFutureWatcher.isCanceled())
238 return eERROR;
239 else
240 return eOK;
243 void TalkGenerator::encEntryPoint(TalkEntry& entry)
245 if(!entry.encoded)
247 bool res = entry.refs.encoder->encode(entry.wavfilename, entry.talkfilename);
248 entry.encoded = res;
249 if (!entry.encoded)
250 entry.refs.generator->encFailEntry(entry);
252 return;
255 void TalkGenerator::encProgress(int value)
257 emit logProgress(value, encFutureWatcher.progressMaximum());
260 void TalkGenerator::encFailEntry(const TalkEntry& entry)
262 emit logItem(tr("Encoding of %1 failed").arg(entry.wavfilename), LOGERROR);
263 abort();
266 //! \brief slot, which is connected to the abort of the Logger. Sets a flag, so Creating Talkfiles ends at the next possible position
268 void TalkGenerator::abort()
270 if (ttsFutureWatcher.isRunning())
272 ttsFutureWatcher.cancel();
273 emit logItem(tr("Voicing aborted"), LOGERROR);
275 if (encFutureWatcher.isRunning())
277 encFutureWatcher.cancel();
278 emit logItem(tr("Encoding aborted"), LOGERROR);