MPEGPlayer: Skip to next file when there is a problem with a video file in all-play...
[kugel-rb.git] / rbutil / rbutilqt / base / talkgenerator.cpp
blobf1aa7832810bde41449db7a78cc5d29af906a9c5
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);
132 qDebug() << "[TalkGenerator] Maximum number of threads used:"
133 << QThreadPool::globalInstance()->maxThreadCount();
135 connect(&ttsFutureWatcher, SIGNAL(progressValueChanged(int)),
136 this, SLOT(ttsProgress(int)));
137 ttsFutureWatcher.setFuture(QtConcurrent::map(*list, &TalkGenerator::ttsEntryPoint));
139 /* We use this loop as an equivalent to ttsFutureWatcher.waitForFinished()
140 * since the latter blocks all events */
141 while(ttsFutureWatcher.isRunning())
142 QCoreApplication::processEvents();
144 /* Restore global settings, if we changed them */
145 if ((m_tts->capabilities() & TTSBase::RunInParallel) == 0)
146 QThreadPool::globalInstance()->setMaxThreadCount(maxThreadCount);
148 if(ttsFutureWatcher.isCanceled())
149 return eERROR;
150 else if(m_ttsWarnings)
151 return eWARNING;
152 else
153 return eOK;
156 void TalkGenerator::ttsEntryPoint(TalkEntry& entry)
158 if (!entry.voiced && !entry.toSpeak.isEmpty())
160 QString error;
161 qDebug() << "[TalkGen] voicing: " << entry.toSpeak << "to" << entry.wavfilename;
162 TTSStatus status = entry.refs.tts->voice(entry.toSpeak,entry.wavfilename, &error);
163 if (status == Warning || status == FatalError)
165 entry.refs.generator->ttsFailEntry(entry, status, error);
166 return;
168 if (entry.refs.wavtrim != -1)
170 char buffer[255];
171 wavtrim(entry.wavfilename.toLocal8Bit().data(), entry.refs.wavtrim, buffer, 255);
173 entry.voiced = true;
177 void TalkGenerator::ttsFailEntry(const TalkEntry& entry, TTSStatus status, QString error)
179 if(status == Warning)
181 m_ttsWarnings = true;
182 emit logItem(tr("Voicing of %1 failed: %2").arg(entry.toSpeak).arg(error),
183 LOGWARNING);
185 else if (status == FatalError)
187 emit logItem(tr("Voicing of %1 failed: %2").arg(entry.toSpeak).arg(error),
188 LOGERROR);
189 abort();
193 void TalkGenerator::ttsProgress(int value)
195 emit logProgress(value,ttsFutureWatcher.progressMaximum());
198 //! \brief Encodes a List of strings
200 TalkGenerator::Status TalkGenerator::encodeList(QList<TalkEntry>* list)
202 QStringList duplicates;
204 int itemsCount = list->size();
205 emit logProgress(0, itemsCount);
207 /* Do some preprocessing and remove entries that have not been voiced. */
208 for (int idx=0; idx < itemsCount; idx++)
210 if(list->at(idx).voiced == false)
212 qDebug() << "[TalkGen] unvoiced entry" << list->at(idx).toSpeak <<"detected";
213 list->removeAt(idx);
214 itemsCount--;
215 idx--;
216 continue;
218 if(duplicates.contains(list->at(idx).talkfilename))
220 (*list)[idx].encoded = true; /* make sure we skip this entry */
221 continue;
223 duplicates.append(list->at(idx).talkfilename);
224 (*list)[idx].refs.encoder = m_enc;
225 (*list)[idx].refs.generator = this; /* not really needed, unless we end up
226 voicing and encoding with two different
227 TalkGenerators.*/
230 connect(&encFutureWatcher, SIGNAL(progressValueChanged(int)),
231 this, SLOT(encProgress(int)));
232 encFutureWatcher.setFuture(QtConcurrent::map(*list, &TalkGenerator::encEntryPoint));
234 /* We use this loop as an equivalent to encFutureWatcher.waitForFinished()
235 * since the latter blocks all events */
236 while (encFutureWatcher.isRunning())
237 QCoreApplication::processEvents(QEventLoop::AllEvents);
239 if (encFutureWatcher.isCanceled())
240 return eERROR;
241 else
242 return eOK;
245 void TalkGenerator::encEntryPoint(TalkEntry& entry)
247 if(!entry.encoded)
249 bool res = entry.refs.encoder->encode(entry.wavfilename, entry.talkfilename);
250 entry.encoded = res;
251 if (!entry.encoded)
252 entry.refs.generator->encFailEntry(entry);
254 return;
257 void TalkGenerator::encProgress(int value)
259 emit logProgress(value, encFutureWatcher.progressMaximum());
262 void TalkGenerator::encFailEntry(const TalkEntry& entry)
264 emit logItem(tr("Encoding of %1 failed").arg(entry.wavfilename), LOGERROR);
265 abort();
268 //! \brief slot, which is connected to the abort of the Logger. Sets a flag, so Creating Talkfiles ends at the next possible position
270 void TalkGenerator::abort()
272 if (ttsFutureWatcher.isRunning())
274 ttsFutureWatcher.cancel();
275 emit logItem(tr("Voicing aborted"), LOGERROR);
277 if (encFutureWatcher.isRunning())
279 encFutureWatcher.cancel();
280 emit logItem(tr("Encoding aborted"), LOGERROR);