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);
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())
148 else if(m_ttsWarnings
)
154 void TalkGenerator::ttsEntryPoint(TalkEntry
& entry
)
156 if (!entry
.voiced
&& !entry
.toSpeak
.isEmpty())
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
);
166 if (entry
.refs
.wavtrim
!= -1)
169 wavtrim(entry
.wavfilename
.toLocal8Bit().data(), entry
.refs
.wavtrim
, buffer
, 255);
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
),
183 else if (status
== FatalError
)
185 emit
logItem(tr("Voicing of %1 failed: %2").arg(entry
.toSpeak
).arg(error
),
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";
216 if(duplicates
.contains(list
->at(idx
).talkfilename
))
218 (*list
)[idx
].encoded
= true; /* make sure we skip this entry */
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
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())
243 void TalkGenerator::encEntryPoint(TalkEntry
& entry
)
247 bool res
= entry
.refs
.encoder
->encode(entry
.wavfilename
, entry
.talkfilename
);
250 entry
.refs
.generator
->encFailEntry(entry
);
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
);
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
);