1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
9 * Copyright (C) 2007 by Dominik Wenger
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"
25 TalkGenerator::TalkGenerator(QObject
* parent
): QObject(parent
), encFutureWatcher(this), ttsFutureWatcher(this)
30 //! \brief Creates Talkfiles.
32 TalkGenerator::Status
TalkGenerator::process(QList
<TalkEntry
>* list
,int wavtrimth
)
35 bool warnings
= false;
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
);
47 QCoreApplication::processEvents();
50 emit
logItem(tr("Starting Encoder Engine"),LOGINFO
);
51 m_enc
= EncBase::getEncoder(this,SystemInfo::value(SystemInfo::CurEncoder
).toString());
54 emit
logItem(tr("Init of Encoder engine failed"),LOGERROR
);
59 QCoreApplication::processEvents();
61 emit
logProgress(0,0);
64 emit
logItem(tr("Voicing entries..."),LOGINFO
);
65 Status voiceStatus
= voiceList(list
,wavtrimth
);
66 if(voiceStatus
== eERROR
)
73 else if( voiceStatus
== eWARNING
)
76 QCoreApplication::processEvents();
79 emit
logItem(tr("Encoding files..."),LOGINFO
);
80 Status encoderStatus
= encodeList(list
);
81 if( encoderStatus
== eERROR
)
88 else if( voiceStatus
== eWARNING
)
91 QCoreApplication::processEvents();
95 emit
logProgress(1,1);
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
);
122 qDebug() << "[TalkGen] duplicate skipped";
123 (*list
)[i
].voiced
= true;
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())
150 else if(m_ttsWarnings
)
156 void TalkGenerator::ttsEntryPoint(TalkEntry
& entry
)
158 if (!entry
.voiced
&& !entry
.toSpeak
.isEmpty())
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
);
168 if (entry
.refs
.wavtrim
!= -1)
171 wavtrim(entry
.wavfilename
.toLocal8Bit().data(), entry
.refs
.wavtrim
, buffer
, 255);
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
),
185 else if (status
== FatalError
)
187 emit
logItem(tr("Voicing of %1 failed: %2").arg(entry
.toSpeak
).arg(error
),
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";
218 if(duplicates
.contains(list
->at(idx
).talkfilename
))
220 (*list
)[idx
].encoded
= true; /* make sure we skip this entry */
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
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())
245 void TalkGenerator::encEntryPoint(TalkEntry
& entry
)
249 bool res
= entry
.refs
.encoder
->encode(entry
.wavfilename
, entry
.talkfilename
);
252 entry
.refs
.generator
->encFailEntry(entry
);
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
);
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
);