diff options
Diffstat (limited to 'rbutil/rbutilqt/base')
-rw-r--r-- | rbutil/rbutilqt/base/talkgenerator.cpp | 247 | ||||
-rw-r--r-- | rbutil/rbutilqt/base/talkgenerator.h | 31 |
2 files changed, 94 insertions, 184 deletions
diff --git a/rbutil/rbutilqt/base/talkgenerator.cpp b/rbutil/rbutilqt/base/talkgenerator.cpp index 4e78872240..6dc0cebc19 100644 --- a/rbutil/rbutilqt/base/talkgenerator.cpp +++ b/rbutil/rbutilqt/base/talkgenerator.cpp | |||
@@ -21,16 +21,16 @@ | |||
21 | #include "systeminfo.h" | 21 | #include "systeminfo.h" |
22 | #include "wavtrim.h" | 22 | #include "wavtrim.h" |
23 | 23 | ||
24 | TalkGenerator::TalkGenerator(QObject* parent): QObject(parent), encFutureWatcher(this), ttsFutureWatcher(this) | 24 | TalkGenerator::TalkGenerator(QObject* parent): QObject(parent) |
25 | { | 25 | { |
26 | m_userAborted = false; | 26 | |
27 | m_lang = ""; | ||
28 | } | 27 | } |
29 | 28 | ||
30 | //! \brief Creates Talkfiles. | 29 | //! \brief Creates Talkfiles. |
31 | //! | 30 | //! |
32 | TalkGenerator::Status TalkGenerator::process(QList<TalkEntry>* list,int wavtrimth) | 31 | TalkGenerator::Status TalkGenerator::process(QList<TalkEntry>* list,int wavtrimth) |
33 | { | 32 | { |
33 | m_abort = false; | ||
34 | QString errStr; | 34 | QString errStr; |
35 | bool warnings = false; | 35 | bool warnings = false; |
36 | 36 | ||
@@ -103,122 +103,81 @@ TalkGenerator::Status TalkGenerator::process(QList<TalkEntry>* list,int wavtrimt | |||
103 | //! | 103 | //! |
104 | TalkGenerator::Status TalkGenerator::voiceList(QList<TalkEntry>* list,int wavtrimth) | 104 | TalkGenerator::Status TalkGenerator::voiceList(QList<TalkEntry>* list,int wavtrimth) |
105 | { | 105 | { |
106 | emit logProgress(0, list->size()); | 106 | int progressMax = list->size(); |
107 | int m_progress = 0; | ||
108 | emit logProgress(m_progress,progressMax); | ||
107 | 109 | ||
110 | QStringList errors; | ||
108 | QStringList duplicates; | 111 | QStringList duplicates; |
109 | 112 | ||
110 | m_ttsWarnings = false; | 113 | bool warnings = false; |
111 | for(int i=0; i < list->size(); i++) | 114 | for(int i=0; i < list->size(); i++) |
112 | { | 115 | { |
113 | (*list)[i].refs.tts = m_tts; | 116 | if(m_abort) |
114 | (*list)[i].refs.wavtrim = wavtrimth; | 117 | { |
115 | (*list)[i].refs.generator = this; | 118 | emit logItem(tr("Voicing aborted"), LOGERROR); |
116 | // enable voice corrections only if a language is set. | 119 | return eERROR; |
117 | if(!m_lang.isEmpty()) { | ||
118 | QString s = (*list)[i].toSpeak; | ||
119 | (*list)[i].toSpeak = correctString(s); | ||
120 | } | 120 | } |
121 | 121 | ||
122 | // skip duplicated wav entries | 122 | // skip duplicated wav entrys |
123 | if(!duplicates.contains(list->at(i).wavfilename)) | 123 | if(!duplicates.contains(list->at(i).wavfilename)) |
124 | duplicates.append(list->at(i).wavfilename); | 124 | duplicates.append(list->at(i).wavfilename); |
125 | else | 125 | else |
126 | { | 126 | { |
127 | qDebug() << "[TalkGen] duplicate skipped"; | 127 | qDebug() << "[TalkGenerator] duplicate skipped"; |
128 | (*list)[i].voiced = true; | 128 | (*list)[i].voiced = true; |
129 | emit logProgress(++m_progress,progressMax); | ||
129 | continue; | 130 | continue; |
130 | } | 131 | } |
131 | } | ||
132 | |||
133 | /* If the engine can't be parallelized, we use only 1 thread */ | ||
134 | // NOTE: setting the number of maximum threads to use to 1 doesn't seem to | ||
135 | // work as expected -- it causes sporadically output files missing (see | ||
136 | // FS#11994). As a stop-gap solution use a separate implementation in that | ||
137 | // case for running the TTS. | ||
138 | if((m_tts->capabilities() & TTSBase::RunInParallel) != 0) | ||
139 | { | ||
140 | int maxThreadCount = QThreadPool::globalInstance()->maxThreadCount(); | ||
141 | qDebug() << "[TalkGenerator] Maximum number of threads used:" | ||
142 | << QThreadPool::globalInstance()->maxThreadCount(); | ||
143 | |||
144 | connect(&ttsFutureWatcher, SIGNAL(progressValueChanged(int)), | ||
145 | this, SLOT(ttsProgress(int))); | ||
146 | ttsFutureWatcher.setFuture(QtConcurrent::map(*list, &TalkGenerator::ttsEntryPoint)); | ||
147 | |||
148 | /* We use this loop as an equivalent to ttsFutureWatcher.waitForFinished() | ||
149 | * since the latter blocks all events */ | ||
150 | while(ttsFutureWatcher.isRunning()) | ||
151 | QCoreApplication::processEvents(); | ||
152 | |||
153 | /* Restore global settings, if we changed them */ | ||
154 | if ((m_tts->capabilities() & TTSBase::RunInParallel) == 0) | ||
155 | QThreadPool::globalInstance()->setMaxThreadCount(maxThreadCount); | ||
156 | 132 | ||
157 | if(ttsFutureWatcher.isCanceled()) | 133 | // skip already voiced entrys |
158 | return eERROR; | 134 | if(list->at(i).voiced == true) |
159 | else if(m_ttsWarnings) | 135 | { |
160 | return eWARNING; | 136 | emit logProgress(++m_progress,progressMax); |
161 | else | 137 | continue; |
162 | return eOK; | 138 | } |
163 | } | 139 | // skip entry whith empty text |
164 | else { | 140 | if(list->at(i).toSpeak == "") |
165 | qDebug() << "[TalkGenerator] Using single thread TTS workaround"; | 141 | { |
166 | int items = list->size(); | 142 | emit logProgress(++m_progress,progressMax); |
167 | for(int i = 0; i < items; i++) { | 143 | continue; |
168 | if(m_userAborted) { | ||
169 | emit logItem(tr("Voicing aborted"), LOGERROR); | ||
170 | return eERROR; | ||
171 | } | ||
172 | TalkEntry entry = list->at(i); | ||
173 | TalkGenerator::ttsEntryPoint(entry); | ||
174 | (*list)[i] = entry; | ||
175 | emit logProgress(i, items); | ||
176 | } | 144 | } |
177 | return m_ttsWarnings ? eWARNING : eOK; | ||
178 | } | ||
179 | } | ||
180 | 145 | ||
181 | void TalkGenerator::ttsEntryPoint(TalkEntry& entry) | 146 | // voice entry |
182 | { | ||
183 | if (!entry.voiced && !entry.toSpeak.isEmpty()) | ||
184 | { | ||
185 | QString error; | 147 | QString error; |
186 | qDebug() << "[TalkGen] voicing: " << entry.toSpeak << "to" << entry.wavfilename; | 148 | qDebug() << "[TalkGenerator] voicing: " << list->at(i).toSpeak << "to" << list->at(i).wavfilename; |
187 | TTSStatus status = entry.refs.tts->voice(entry.toSpeak,entry.wavfilename, &error); | 149 | TTSStatus status = m_tts->voice(list->at(i).toSpeak,list->at(i).wavfilename, &error); |
188 | if (status == Warning || status == FatalError) | 150 | if(status == Warning) |
189 | { | 151 | { |
190 | entry.refs.generator->ttsFailEntry(entry, status, error); | 152 | warnings = true; |
191 | return; | 153 | emit logItem(tr("Voicing of %1 failed: %2").arg(list->at(i).toSpeak).arg(error), |
154 | LOGWARNING); | ||
192 | } | 155 | } |
193 | if (entry.refs.wavtrim != -1) | 156 | else if (status == FatalError) |
157 | { | ||
158 | emit logItem(tr("Voicing of %1 failed: %2").arg(list->at(i).toSpeak).arg(error), | ||
159 | LOGERROR); | ||
160 | return eERROR; | ||
161 | } | ||
162 | else | ||
163 | (*list)[i].voiced = true; | ||
164 | |||
165 | //wavetrim if needed | ||
166 | if(wavtrimth != -1) | ||
194 | { | 167 | { |
195 | char buffer[255]; | 168 | char buffer[255]; |
196 | wavtrim(entry.wavfilename.toLocal8Bit().data(), entry.refs.wavtrim, buffer, 255); | 169 | wavtrim(list->at(i).wavfilename.toLocal8Bit().data(),wavtrimth,buffer,255); |
197 | } | 170 | } |
198 | entry.voiced = true; | ||
199 | } | ||
200 | } | ||
201 | 171 | ||
202 | void TalkGenerator::ttsFailEntry(const TalkEntry& entry, TTSStatus status, QString error) | 172 | emit logProgress(++m_progress,progressMax); |
203 | { | 173 | QCoreApplication::processEvents(); |
204 | if(status == Warning) | ||
205 | { | ||
206 | m_ttsWarnings = true; | ||
207 | emit logItem(tr("Voicing of %1 failed: %2").arg(entry.toSpeak).arg(error), | ||
208 | LOGWARNING); | ||
209 | } | ||
210 | else if (status == FatalError) | ||
211 | { | ||
212 | emit logItem(tr("Voicing of %1 failed: %2").arg(entry.toSpeak).arg(error), | ||
213 | LOGERROR); | ||
214 | abort(); | ||
215 | } | 174 | } |
175 | if(warnings) | ||
176 | return eWARNING; | ||
177 | else | ||
178 | return eOK; | ||
216 | } | 179 | } |
217 | 180 | ||
218 | void TalkGenerator::ttsProgress(int value) | ||
219 | { | ||
220 | emit logProgress(value,ttsFutureWatcher.progressMaximum()); | ||
221 | } | ||
222 | 181 | ||
223 | //! \brief Encodes a List of strings | 182 | //! \brief Encodes a List of strings |
224 | //! | 183 | //! |
@@ -226,86 +185,58 @@ TalkGenerator::Status TalkGenerator::encodeList(QList<TalkEntry>* list) | |||
226 | { | 185 | { |
227 | QStringList duplicates; | 186 | QStringList duplicates; |
228 | 187 | ||
229 | int itemsCount = list->size(); | 188 | int progressMax = list->size(); |
230 | emit logProgress(0, itemsCount); | 189 | int m_progress = 0; |
190 | emit logProgress(m_progress,progressMax); | ||
231 | 191 | ||
232 | /* Do some preprocessing and remove entries that have not been voiced. */ | 192 | for(int i=0; i < list->size(); i++) |
233 | for (int idx=0; idx < itemsCount; idx++) | ||
234 | { | 193 | { |
235 | if(list->at(idx).voiced == false) | 194 | if(m_abort) |
236 | { | 195 | { |
237 | qDebug() << "[TalkGen] unvoiced entry" << list->at(idx).toSpeak <<"detected"; | 196 | emit logItem(tr("Encoding aborted"), LOGERROR); |
238 | list->removeAt(idx); | 197 | return eERROR; |
239 | itemsCount--; | 198 | } |
240 | idx--; | 199 | |
200 | //skip non-voiced entrys | ||
201 | if(list->at(i).voiced == false) | ||
202 | { | ||
203 | qDebug() << "non voiced entry" << list->at(i).toSpeak <<"detected"; | ||
204 | emit logProgress(++m_progress,progressMax); | ||
241 | continue; | 205 | continue; |
242 | } | 206 | } |
243 | if(duplicates.contains(list->at(idx).talkfilename)) | 207 | //skip duplicates |
208 | if(!duplicates.contains(list->at(i).talkfilename)) | ||
209 | duplicates.append(list->at(i).talkfilename); | ||
210 | else | ||
244 | { | 211 | { |
245 | (*list)[idx].encoded = true; /* make sure we skip this entry */ | 212 | qDebug() << "[TalkGenerator] duplicate skipped"; |
213 | (*list)[i].encoded = true; | ||
214 | emit logProgress(++m_progress,progressMax); | ||
246 | continue; | 215 | continue; |
247 | } | 216 | } |
248 | duplicates.append(list->at(idx).talkfilename); | ||
249 | (*list)[idx].refs.encoder = m_enc; | ||
250 | (*list)[idx].refs.generator = this; /* not really needed, unless we end up | ||
251 | voicing and encoding with two different | ||
252 | TalkGenerators.*/ | ||
253 | } | ||
254 | |||
255 | connect(&encFutureWatcher, SIGNAL(progressValueChanged(int)), | ||
256 | this, SLOT(encProgress(int))); | ||
257 | encFutureWatcher.setFuture(QtConcurrent::map(*list, &TalkGenerator::encEntryPoint)); | ||
258 | |||
259 | /* We use this loop as an equivalent to encFutureWatcher.waitForFinished() | ||
260 | * since the latter blocks all events */ | ||
261 | while (encFutureWatcher.isRunning()) | ||
262 | QCoreApplication::processEvents(QEventLoop::AllEvents); | ||
263 | 217 | ||
264 | if (encFutureWatcher.isCanceled()) | 218 | //encode entry |
265 | return eERROR; | 219 | qDebug() << "[TalkGenerator] encoding " << list->at(i).wavfilename |
266 | else | 220 | << "to" << list->at(i).talkfilename; |
267 | return eOK; | 221 | if(!m_enc->encode(list->at(i).wavfilename,list->at(i).talkfilename)) |
268 | } | 222 | { |
269 | 223 | emit logItem(tr("Encoding of %1 failed").arg( | |
270 | void TalkGenerator::encEntryPoint(TalkEntry& entry) | 224 | QFileInfo(list->at(i).wavfilename).baseName()), LOGERROR); |
271 | { | 225 | return eERROR; |
272 | if(!entry.encoded) | ||
273 | { | ||
274 | bool res = entry.refs.encoder->encode(entry.wavfilename, entry.talkfilename); | ||
275 | entry.encoded = res; | ||
276 | if (!entry.encoded) | ||
277 | entry.refs.generator->encFailEntry(entry); | ||
278 | } | 226 | } |
279 | return; | 227 | (*list)[i].encoded = true; |
280 | } | 228 | emit logProgress(++m_progress,progressMax); |
281 | 229 | QCoreApplication::processEvents(); | |
282 | void TalkGenerator::encProgress(int value) | 230 | } |
283 | { | 231 | return eOK; |
284 | emit logProgress(value, encFutureWatcher.progressMaximum()); | ||
285 | } | ||
286 | |||
287 | void TalkGenerator::encFailEntry(const TalkEntry& entry) | ||
288 | { | ||
289 | emit logItem(tr("Encoding of %1 failed").arg( | ||
290 | QFileInfo(entry.wavfilename).baseName()), LOGERROR); | ||
291 | abort(); | ||
292 | } | 232 | } |
293 | 233 | ||
294 | //! \brief slot, which is connected to the abort of the Logger. Sets a flag, so Creating Talkfiles ends at the next possible position | 234 | //! \brief slot, which is connected to the abort of the Logger. |
235 | //Sets a flag, so Creating Talkfiles ends at the next possible position | ||
295 | //! | 236 | //! |
296 | void TalkGenerator::abort() | 237 | void TalkGenerator::abort() |
297 | { | 238 | { |
298 | if (ttsFutureWatcher.isRunning()) | 239 | m_abort = true; |
299 | { | ||
300 | ttsFutureWatcher.cancel(); | ||
301 | emit logItem(tr("Voicing aborted"), LOGERROR); | ||
302 | } | ||
303 | if (encFutureWatcher.isRunning()) | ||
304 | { | ||
305 | encFutureWatcher.cancel(); | ||
306 | emit logItem(tr("Encoding aborted"), LOGERROR); | ||
307 | } | ||
308 | m_userAborted = true; | ||
309 | } | 240 | } |
310 | 241 | ||
311 | QString TalkGenerator::correctString(QString s) | 242 | QString TalkGenerator::correctString(QString s) |
@@ -325,9 +256,9 @@ QString TalkGenerator::correctString(QString s) | |||
325 | qDebug() << "[VoiceFileCreator] corrected string" << s << "to" << corrected; | 256 | qDebug() << "[VoiceFileCreator] corrected string" << s << "to" << corrected; |
326 | 257 | ||
327 | return corrected; | 258 | return corrected; |
259 | m_abort = true; | ||
328 | } | 260 | } |
329 | 261 | ||
330 | |||
331 | void TalkGenerator::setLang(QString name) | 262 | void TalkGenerator::setLang(QString name) |
332 | { | 263 | { |
333 | m_lang = name; | 264 | m_lang = name; |
diff --git a/rbutil/rbutilqt/base/talkgenerator.h b/rbutil/rbutilqt/base/talkgenerator.h index 5fe036e2f1..3e2f9394fb 100644 --- a/rbutil/rbutilqt/base/talkgenerator.h +++ b/rbutil/rbutilqt/base/talkgenerator.h | |||
@@ -48,30 +48,15 @@ public: | |||
48 | QString target; | 48 | QString target; |
49 | bool voiced; | 49 | bool voiced; |
50 | bool encoded; | 50 | bool encoded; |
51 | |||
52 | /* We need the following members because | ||
53 | * 1) the QtConcurrent entry points are all static methods (and we | ||
54 | * need to communicate with the TalkGenerator) | ||
55 | * 2) we are not guaranteed to go through the list in any | ||
56 | * particular order, so we can't use the progress slot | ||
57 | * for error checking */ | ||
58 | struct | ||
59 | { | ||
60 | EncoderBase* encoder; | ||
61 | TTSBase* tts; | ||
62 | TalkGenerator* generator; | ||
63 | int wavtrim; | ||
64 | } refs; | ||
65 | }; | 51 | }; |
66 | 52 | ||
67 | TalkGenerator(QObject* parent); | 53 | TalkGenerator(QObject* parent); |
54 | |||
68 | Status process(QList<TalkEntry>* list,int wavtrimth = -1); | 55 | Status process(QList<TalkEntry>* list,int wavtrimth = -1); |
69 | QString correctString(QString s); | 56 | QString correctString(QString s); |
70 | 57 | ||
71 | public slots: | 58 | public slots: |
72 | void abort(); | 59 | void abort(); |
73 | void encProgress(int value); | ||
74 | void ttsProgress(int value); | ||
75 | void setLang(QString name); | 60 | void setLang(QString name); |
76 | 61 | ||
77 | signals: | 62 | signals: |
@@ -80,22 +65,12 @@ signals: | |||
80 | void logProgress(int, int); //! set progress bar. | 65 | void logProgress(int, int); //! set progress bar. |
81 | 66 | ||
82 | private: | 67 | private: |
83 | QFutureWatcher<void> encFutureWatcher; | ||
84 | QFutureWatcher<void> ttsFutureWatcher; | ||
85 | void encFailEntry(const TalkEntry& entry); | ||
86 | void ttsFailEntry(const TalkEntry& entry, TTSStatus status, QString error); | ||
87 | |||
88 | Status voiceList(QList<TalkEntry>* list,int wavetrimth); | 68 | Status voiceList(QList<TalkEntry>* list,int wavetrimth); |
89 | Status encodeList(QList<TalkEntry>* list); | 69 | Status encodeList(QList<TalkEntry>* list); |
90 | 70 | ||
91 | static void encEntryPoint(TalkEntry& entry); | ||
92 | static void ttsEntryPoint(TalkEntry& entry); | ||
93 | |||
94 | TTSBase* m_tts; | 71 | TTSBase* m_tts; |
95 | EncoderBase* m_enc; | 72 | EncoderBase* m_enc; |
96 | 73 | ||
97 | bool m_ttsWarnings; | ||
98 | bool m_userAborted; | ||
99 | QString m_lang; | 74 | QString m_lang; |
100 | 75 | ||
101 | struct CorrectionItems | 76 | struct CorrectionItems |
@@ -105,6 +80,10 @@ private: | |||
105 | QString modifier; | 80 | QString modifier; |
106 | }; | 81 | }; |
107 | QList<struct CorrectionItems> m_corrections; | 82 | QList<struct CorrectionItems> m_corrections; |
83 | |||
84 | bool m_abort; | ||
85 | |||
86 | |||
108 | }; | 87 | }; |
109 | 88 | ||
110 | 89 | ||